summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.yml9
-rw-r--r--.gitlab/merge_request_templates/New static analysis check.md2
-rw-r--r--.overcommit.yml.example4
-rw-r--r--Gemfile2
-rw-r--r--app/assets/javascripts/awards_handler.js2
-rw-r--r--app/assets/javascripts/badges/components/badge.vue2
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/playable.js2
-rw-r--r--app/assets/javascripts/boards/components/board.js3
-rw-r--r--app/assets/javascripts/boards/components/board_card.vue7
-rw-r--r--app/assets/javascripts/boards/components/board_delete.js1
-rw-r--r--app/assets/javascripts/boards/components/board_sidebar.js1
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue1
-rw-r--r--app/assets/javascripts/boards/components/modal/header.vue2
-rw-r--r--app/assets/javascripts/boards/components/modal/tabs.vue2
-rw-r--r--app/assets/javascripts/boards/stores/actions.js2
-rw-r--r--app/assets/javascripts/boards/stores/mutations.js2
-rw-r--r--app/assets/javascripts/clusters/components/application_row.vue3
-rw-r--r--app/assets/javascripts/clusters/components/knative_domain_editor.vue1
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_code_component.vue2
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_component.vue2
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_review_component.vue2
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue2
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_test_component.vue2
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue2
-rw-r--r--app/assets/javascripts/diffs/components/hidden_files_warning.vue2
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue4
-rw-r--r--app/assets/javascripts/environments/components/environment_rollback.vue1
-rw-r--r--app/assets/javascripts/environments/components/stop_environment_modal.vue2
-rw-r--r--app/assets/javascripts/error_tracking/utils.js2
-rw-r--r--app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue4
-rw-r--r--app/assets/javascripts/ide/components/branches/item.vue2
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list_item.vue2
-rw-r--r--app/assets/javascripts/ide/components/ide_status_bar.vue2
-rw-r--r--app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue2
-rw-r--r--app/assets/javascripts/issuable_suggestions/components/item.vue2
-rw-r--r--app/assets/javascripts/issue_show/components/edit_actions.vue2
-rw-r--r--app/assets/javascripts/issue_show/components/edited.vue2
-rw-r--r--app/assets/javascripts/issue_show/components/fields/description_template.vue2
-rw-r--r--app/assets/javascripts/jobs/components/commit_block.vue2
-rw-r--r--app/assets/javascripts/lib/utils/autosave.js2
-rw-r--r--app/assets/javascripts/lib/utils/datetime_range.js4
-rw-r--r--app/assets/javascripts/lib/utils/notify.js4
-rw-r--r--app/assets/javascripts/lib/utils/unit_format/formatter_factory.js6
-rw-r--r--app/assets/javascripts/main.js2
-rw-r--r--app/assets/javascripts/monitoring/components/charts/stacked_column.vue2
-rw-r--r--app/assets/javascripts/monitoring/components/charts/time_series.vue2
-rw-r--r--app/assets/javascripts/monitoring/components/panel_type.vue2
-rw-r--r--app/assets/javascripts/monitoring/utils.js2
-rw-r--r--app/assets/javascripts/mr_popover/components/mr_popover.vue8
-rw-r--r--app/assets/javascripts/new_branch_form.js2
-rw-r--r--app/assets/javascripts/notebook/cells/code/index.vue1
-rw-r--r--app/assets/javascripts/notebook/cells/markdown.vue2
-rw-r--r--app/assets/javascripts/notebook/cells/output/image.vue2
-rw-r--r--app/assets/javascripts/notebook/cells/output/index.vue1
-rw-r--r--app/assets/javascripts/notebook/index.vue2
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_edited_text.vue2
-rw-r--r--app/assets/javascripts/operation_settings/components/external_dashboard.vue4
-rw-r--r--app/assets/javascripts/pages/admin/users/index.js2
-rw-r--r--app/assets/javascripts/performance_bar/index.js2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_artifacts.vue2
-rw-r--r--app/assets/javascripts/registry/explorer/components/project_empty_state.vue6
-rw-r--r--app/assets/javascripts/registry/list/components/project_empty_state.vue6
-rw-r--r--app/assets/javascripts/reports/components/report_link.vue2
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue2
-rw-r--r--app/assets/javascripts/repository/graphql.js4
-rw-r--r--app/assets/javascripts/repository/utils/title.js2
-rw-r--r--app/assets/javascripts/search_autocomplete.js4
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignees.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue1
-rw-r--r--app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql5
-rw-r--r--app/assets/javascripts/snippets/components/snippet_header.vue5
-rw-r--r--app/assets/javascripts/tracking.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/changed_file_icon.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/header.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/project_avatar/default.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/select2_select.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/smart_virtual_list.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue2
-rw-r--r--app/controllers/concerns/authenticates_2fa_for_admin_mode.rb (renamed from app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb)0
-rw-r--r--app/graphql/types/group_type.rb1
-rw-r--r--app/graphql/types/project_type.rb1
-rw-r--r--app/models/issue.rb1
-rw-r--r--changelogs/unreleased/208923-enable-batch-counting-for-some-individual-queries-4.yml5
-rw-r--r--changelogs/unreleased/ref-params-validator.yml5
-rw-r--r--config/application.rb2
-rw-r--r--config/environments/development.rb2
-rw-r--r--config/environments/test.rb2
-rw-r--r--config/initializers/2_gitlab.rb1
-rw-r--r--config/initializers_before_autoloader/002_zeitwerk.rb59
-rw-r--r--config/settings.rb6
-rw-r--r--db/migrate/20200312125121_add_index_on_active_and_template_and_type_and_id_to_services.rb18
-rw-r--r--db/schema.rb1
-rw-r--r--doc/administration/gitaly/img/praefect_architecture_v12_10.pngbin0 -> 29067 bytes
-rw-r--r--doc/administration/gitaly/img/praefect_architecture_v12_9.pngbin44098 -> 0 bytes
-rw-r--r--doc/administration/gitaly/praefect.md2
-rw-r--r--doc/administration/index.md1
-rw-r--r--doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md469
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql21
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json48
-rw-r--r--doc/api/graphql/reference/index.md6
-rw-r--r--doc/development/contributing/style_guides.md2
-rw-r--r--lib/api/helpers/custom_validators.rb30
-rw-r--r--lib/gitlab/graphql/docs/helper.rb2
-rw-r--r--lib/gitlab/graphql/docs/renderer.rb2
-rw-r--r--lib/gitlab/import_export/relation_tree_restorer.rb2
-rw-r--r--lib/gitlab/metrics/exporter/base_exporter.rb3
-rw-r--r--lib/gitlab/set_cache.rb3
-rw-r--r--lib/gitlab/usage_data.rb2
-rw-r--r--lib/tasks/gitlab/graphql.rake1
-rw-r--r--locale/gitlab.pot9
-rw-r--r--package.json4
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb2
-rwxr-xr-xscripts/static-analysis1
-rw-r--r--spec/factories/usage_data.rb64
-rw-r--r--spec/fast_spec_helper.rb7
-rw-r--r--spec/frontend/snippets/components/snippet_header_spec.js2
-rw-r--r--spec/lib/api/helpers/custom_validators_spec.rb41
-rw-r--r--spec/lib/gitlab/fogbugz_import/importer_spec.rb1
-rw-r--r--spec/lib/gitlab/graphql/docs/renderer_spec.rb1
-rw-r--r--spec/lib/gitlab/repository_set_cache_spec.rb6
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb394
-rw-r--r--spec/models/issue_spec.rb15
-rw-r--r--spec/services/service_response_spec.rb3
-rw-r--r--spec/support/helpers/usage_data_helpers.rb134
-rw-r--r--tooling/overcommit/Gemfile (renamed from tooling/overcommit/gems.rb)2
-rw-r--r--tooling/overcommit/Gemfile.lock (renamed from tooling/overcommit/gems.locked)0
-rw-r--r--yarn.lock39
137 files changed, 1202 insertions, 454 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml
index 8d34efc9a6b..0639228fe51 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -1,6 +1,6 @@
extends:
- - '@gitlab'
- - plugin:promise/recommended
+ - plugin:@gitlab/default
+ - plugin:@gitlab/i18n
- plugin:no-jquery/slim
- plugin:no-jquery/deprecated-3.4
globals:
@@ -16,9 +16,6 @@ settings:
webpack:
config: './config/webpack.config.js'
rules:
- "@gitlab/i18n/no-non-i18n-strings": error
- "@gitlab/vue-i18n/no-bare-strings": error
- "@gitlab/vue-i18n/no-bare-attribute-strings": error
import/no-commonjs: error
no-underscore-dangle:
- error
@@ -54,4 +51,4 @@ overrides:
- files:
- '**/spec/**/*'
rules:
- "@gitlab/i18n/no-non-i18n-strings": off
+ "@gitlab/require-i18n-strings": off
diff --git a/.gitlab/merge_request_templates/New static analysis check.md b/.gitlab/merge_request_templates/New static analysis check.md
index b89b6f7dbc4..8bbb3effb1c 100644
--- a/.gitlab/merge_request_templates/New static analysis check.md
+++ b/.gitlab/merge_request_templates/New static analysis check.md
@@ -8,7 +8,6 @@ Please describe the proposal and add a link to the source (for example, http://w
- [ ] Make sure this MR enables a static analysis check rule for new usage but
ignores current offenses
-- [ ] Create a follow-up issue to fix the current offenses as a separate iteration: ISSUE_LINK
- [ ] Mention this proposal in the relevant Slack channels (e.g. `#development`, `#backend`, `#frontend`)
- [ ] If there is a choice to make between two potential styles, set up an emoji vote in the MR:
- CHOICE_A: :a:
@@ -17,6 +16,7 @@ Please describe the proposal and add a link to the source (for example, http://w
- [ ] The MR doesn't have significant objections, and is getting a majority of :+1: vs :-1: (remember that [we don't need to reach a consensus](https://about.gitlab.com/handbook/values/#collaboration-is-not-consensus))
- [ ] (If applicable) One style is getting a majority of vote (compared to the other choice)
- [ ] (If applicable) Update the MR with the chosen style
+- [ ] Create a follow-up issue to fix the current offenses as a separate iteration: ISSUE_LINK
- [ ] Follow the [review process](https://docs.gitlab.com/ee/development/code_review.html) as usual
- [ ] Once approved and merged by a maintainer, mention it again:
- [ ] In the relevant Slack channels (e.g. `#development`, `#backend`, `#frontend`)
diff --git a/.overcommit.yml.example b/.overcommit.yml.example
index b957a8bbd2a..4e6d084a95d 100644
--- a/.overcommit.yml.example
+++ b/.overcommit.yml.example
@@ -15,8 +15,8 @@
#
# Uncomment the following lines to make the configuration take effect.
-# Make sure to run `cd tooling/overcommit && make && cd -`
-gemfile: 'tooling/overcommit/gems.rb'
+# Make sure to run `make -C tooling/overcommit`
+gemfile: 'tooling/overcommit/Gemfile'
PostCheckout:
BundleInstall:
diff --git a/Gemfile b/Gemfile
index 51350401807..8c8802e4435 100644
--- a/Gemfile
+++ b/Gemfile
@@ -475,7 +475,7 @@ gem 'lograge', '~> 0.5'
gem 'grape_logging', '~> 1.7'
# DNS Lookup
-gem 'gitlab-net-dns', '~> 0.9.1'
+gem 'gitlab-net-dns', '~> 0.9.1', require: 'net/dns'
# Countries list
gem 'countries', '~> 3.0'
diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js
index 0e403d023df..67164997bd8 100644
--- a/app/assets/javascripts/awards_handler.js
+++ b/app/assets/javascripts/awards_handler.js
@@ -1,4 +1,4 @@
-/* eslint-disable class-methods-use-this, @gitlab/i18n/no-non-i18n-strings */
+/* eslint-disable class-methods-use-this, @gitlab/require-i18n-strings */
import $ from 'jquery';
import _ from 'underscore';
diff --git a/app/assets/javascripts/badges/components/badge.vue b/app/assets/javascripts/badges/components/badge.vue
index 00c0334db77..f9dd153eba0 100644
--- a/app/assets/javascripts/badges/components/badge.vue
+++ b/app/assets/javascripts/badges/components/badge.vue
@@ -4,7 +4,7 @@ import Icon from '~/vue_shared/components/icon.vue';
export default {
// name: 'Badge' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/25
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
name: 'Badge',
components: {
Icon,
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/playable.js b/app/assets/javascripts/behaviors/markdown/nodes/playable.js
index 9209c69d04a..9a2c9c3c9b0 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/playable.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/playable.js
@@ -1,5 +1,5 @@
/* eslint-disable class-methods-use-this */
-/* eslint-disable @gitlab/i18n/no-non-i18n-strings */
+/* eslint-disable @gitlab/require-i18n-strings */
import { Node } from 'tiptap';
import { defaultMarkdownSerializer } from 'prosemirror-markdown';
diff --git a/app/assets/javascripts/boards/components/board.js b/app/assets/javascripts/boards/components/board.js
index 67046715e9b..b68a6ad0ef5 100644
--- a/app/assets/javascripts/boards/components/board.js
+++ b/app/assets/javascripts/boards/components/board.js
@@ -36,6 +36,7 @@ export default Vue.extend({
list: {
type: Object,
default: () => ({}),
+ required: false,
},
disabled: {
type: Boolean,
@@ -94,7 +95,7 @@ export default Vue.extend({
return this.list.type !== ListType.blank && this.list.type !== ListType.promotion;
},
uniqueKey() {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return `boards.${this.boardId}.${this.list.type}.${this.list.id}`;
},
helpLink() {
diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue
index 0fc60528eb6..5735c8ded3d 100644
--- a/app/assets/javascripts/boards/components/board_card.vue
+++ b/app/assets/javascripts/boards/components/board_card.vue
@@ -13,29 +13,36 @@ export default {
list: {
type: Object,
default: () => ({}),
+ required: false,
},
issue: {
type: Object,
default: () => ({}),
+ required: false,
},
issueLinkBase: {
type: String,
default: '',
+ required: false,
},
disabled: {
type: Boolean,
default: false,
+ required: false,
},
index: {
type: Number,
default: 0,
+ required: false,
},
rootPath: {
type: String,
default: '',
+ required: false,
},
groupId: {
type: Number,
+ required: false,
},
},
data() {
diff --git a/app/assets/javascripts/boards/components/board_delete.js b/app/assets/javascripts/boards/components/board_delete.js
index a06db359c94..cc15dc82db9 100644
--- a/app/assets/javascripts/boards/components/board_delete.js
+++ b/app/assets/javascripts/boards/components/board_delete.js
@@ -7,6 +7,7 @@ export default Vue.extend({
list: {
type: Object,
default: () => ({}),
+ required: false,
},
},
methods: {
diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js
index 9b67126bee2..a3a9753f1b5 100644
--- a/app/assets/javascripts/boards/components/board_sidebar.js
+++ b/app/assets/javascripts/boards/components/board_sidebar.js
@@ -34,6 +34,7 @@ export default Vue.extend({
currentUser: {
type: Object,
default: () => ({}),
+ required: false,
},
},
data() {
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index fbf487357a5..f2c976be7ae 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -43,6 +43,7 @@ export default {
throttleDuration: {
type: Number,
default: 200,
+ required: false,
},
boardBaseUrl: {
type: String,
diff --git a/app/assets/javascripts/boards/components/modal/header.vue b/app/assets/javascripts/boards/components/modal/header.vue
index 8cd4840d3d6..a42e691dcf3 100644
--- a/app/assets/javascripts/boards/components/modal/header.vue
+++ b/app/assets/javascripts/boards/components/modal/header.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { __ } from '~/locale';
import ModalFilters from './filters';
import ModalTabs from './tabs.vue';
diff --git a/app/assets/javascripts/boards/components/modal/tabs.vue b/app/assets/javascripts/boards/components/modal/tabs.vue
index 7430fc96654..ed67206218e 100644
--- a/app/assets/javascripts/boards/components/modal/tabs.vue
+++ b/app/assets/javascripts/boards/components/modal/tabs.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import ModalStore from '../../stores/modal_store';
import modalMixin from '../../mixins/modal_mixins';
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index d4f4df3ad75..34598d66f45 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -1,5 +1,5 @@
const notImplemented = () => {
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
throw new Error('Not implemented!');
};
diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js
index 09eb8bb9b98..7a287400265 100644
--- a/app/assets/javascripts/boards/stores/mutations.js
+++ b/app/assets/javascripts/boards/stores/mutations.js
@@ -1,7 +1,7 @@
import * as mutationTypes from './mutation_types';
const notImplemented = () => {
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
throw new Error('Not implemented!');
};
diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue
index f8bf778b9e7..53bc079a4e1 100644
--- a/app/assets/javascripts/clusters/components/application_row.vue
+++ b/app/assets/javascripts/clusters/components/application_row.vue
@@ -1,6 +1,6 @@
<script>
/* eslint-disable vue/require-default-prop */
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlLink, GlModalDirective } from '@gitlab/ui';
import { s__, __, sprintf } from '~/locale';
import eventHub from '../event_hub';
@@ -95,6 +95,7 @@ export default {
updateable: {
type: Boolean,
default: true,
+ required: false,
},
updateSuccessful: {
type: Boolean,
diff --git a/app/assets/javascripts/clusters/components/knative_domain_editor.vue b/app/assets/javascripts/clusters/components/knative_domain_editor.vue
index 66c8297cb75..30efbe2e0f7 100644
--- a/app/assets/javascripts/clusters/components/knative_domain_editor.vue
+++ b/app/assets/javascripts/clusters/components/knative_domain_editor.vue
@@ -22,6 +22,7 @@ export default {
ingressDnsHelpPath: {
type: String,
default: '',
+ required: false,
},
},
computed: {
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
index 55e5f4ffad2..6b757c6972a 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
@@ -13,10 +13,12 @@ export default {
items: {
type: Array,
default: () => [],
+ required: false,
},
stage: {
type: Object,
default: () => ({}),
+ required: false,
},
},
};
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
index c4f5172df3b..cc7ae74dd3a 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
@@ -13,10 +13,12 @@ export default {
items: {
type: Array,
default: () => [],
+ required: false,
},
stage: {
type: Object,
default: () => ({}),
+ required: false,
},
},
};
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
index a295c8b496b..d61e6995551 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
@@ -15,10 +15,12 @@ export default {
items: {
type: Array,
default: () => [],
+ required: false,
},
stage: {
type: Object,
default: () => ({}),
+ required: false,
},
},
};
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
index c5146c3bf88..2a507b7e601 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
@@ -16,10 +16,12 @@ export default {
items: {
type: Array,
default: () => [],
+ required: false,
},
stage: {
type: Object,
default: () => ({}),
+ required: false,
},
},
computed: {
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
index 35721384210..caff6f9c349 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
@@ -15,10 +15,12 @@ export default {
items: {
type: Array,
default: () => [],
+ required: false,
},
stage: {
type: Object,
default: () => ({}),
+ required: false,
},
},
computed: {
diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
index cfffccd54eb..9d4edd84f25 100644
--- a/app/assets/javascripts/diffs/components/commit_item.vue
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -48,7 +48,7 @@ export default {
},
authorUrl() {
// name: 'mailto:' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return this.author.web_url || `mailto:${this.commit.author_email}`;
},
authorAvatar() {
diff --git a/app/assets/javascripts/diffs/components/hidden_files_warning.vue b/app/assets/javascripts/diffs/components/hidden_files_warning.vue
index 035c2b3b11e..ad0ca4fa402 100644
--- a/app/assets/javascripts/diffs/components/hidden_files_warning.vue
+++ b/app/assets/javascripts/diffs/components/hidden_files_warning.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
export default {
props: {
total: {
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index 3096ccad0aa..dc489c804e9 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import _ from 'underscore';
import { GlTooltipDirective } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
@@ -342,7 +342,7 @@ export default {
isLastDeployment() {
// name: 'last?' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
// Vue i18n ESLint rules issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/63560
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return this.model && this.model.last_deployment && this.model.last_deployment['last?'];
},
diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue
index 6279bbc83ee..577e480d210 100644
--- a/app/assets/javascripts/environments/components/environment_rollback.vue
+++ b/app/assets/javascripts/environments/components/environment_rollback.vue
@@ -24,6 +24,7 @@ export default {
isLastDeployment: {
type: Boolean,
default: true,
+ required: false,
},
environment: {
diff --git a/app/assets/javascripts/environments/components/stop_environment_modal.vue b/app/assets/javascripts/environments/components/stop_environment_modal.vue
index 43ebd7b2824..3caf723442e 100644
--- a/app/assets/javascripts/environments/components/stop_environment_modal.vue
+++ b/app/assets/javascripts/environments/components/stop_environment_modal.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlTooltipDirective } from '@gitlab/ui';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import { s__, sprintf } from '~/locale';
diff --git a/app/assets/javascripts/error_tracking/utils.js b/app/assets/javascripts/error_tracking/utils.js
index 3c382ccd1aa..d1cd70a72fa 100644
--- a/app/assets/javascripts/error_tracking/utils.js
+++ b/app/assets/javascripts/error_tracking/utils.js
@@ -1,4 +1,4 @@
-/* eslint-disable @gitlab/i18n/no-non-i18n-strings, import/prefer-default-export */
+/* eslint-disable @gitlab/require-i18n-strings, import/prefer-default-export */
/**
* Tracks snowplow event when User clicks on error link to Sentry
diff --git a/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue b/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue
index 9f77fe8cd59..0be42519092 100644
--- a/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue
+++ b/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue
@@ -24,7 +24,7 @@ export default {
<label class="label-bold" for="error-tracking-api-host">{{ __('Sentry API URL') }}</label>
<div class="row">
<div class="col-8 col-md-9 gl-pr-0">
- <!-- eslint-disable @gitlab/vue-i18n/no-bare-attribute-strings -->
+ <!-- eslint-disable @gitlab/vue-require-i18n-attribute-strings -->
<gl-form-input
id="error-tracking-api-host"
:value="apiHost"
@@ -39,7 +39,7 @@ export default {
)
}}
</p>
- <!-- eslint-enable @gitlab/vue-i18n/no-bare-attribute-strings -->
+ <!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings -->
</div>
</div>
</div>
diff --git a/app/assets/javascripts/ide/components/branches/item.vue b/app/assets/javascripts/ide/components/branches/item.vue
index 5c048749060..58a0631ee0d 100644
--- a/app/assets/javascripts/ide/components/branches/item.vue
+++ b/app/assets/javascripts/ide/components/branches/item.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import Icon from '~/vue_shared/components/icon.vue';
import Timeago from '~/vue_shared/components/time_ago_tooltip.vue';
import router from '../../ide_router';
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
index e49d96efe50..e70e251c117 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
@@ -38,7 +38,7 @@ export default {
computed: {
iconName() {
// name: '-solid' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
const suffix = this.stagedList ? '-solid' : '';
return `${getCommitIconMap(this.file).icon}${suffix}`;
diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue
index 7ce33fd2278..5585343f367 100644
--- a/app/assets/javascripts/ide/components/ide_status_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_status_bar.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { mapActions, mapState, mapGetters } from 'vuex';
import IdeStatusList from 'ee_else_ce/ide/components/ide_status_list.vue';
import IdeStatusMr from './ide_status_mr.vue';
diff --git a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue
index d5a123edb80..7f65d089148 100644
--- a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue
+++ b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue
@@ -48,7 +48,7 @@ export default {
},
}),
namespace() {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return `${this.side}Pane`;
},
tabs() {
diff --git a/app/assets/javascripts/issuable_suggestions/components/item.vue b/app/assets/javascripts/issuable_suggestions/components/item.vue
index 9f3508fb937..76e4fac5107 100644
--- a/app/assets/javascripts/issuable_suggestions/components/item.vue
+++ b/app/assets/javascripts/issuable_suggestions/components/item.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { uniqueId } from 'lodash';
import { GlLink, GlTooltip, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/issue_show/components/edit_actions.vue b/app/assets/javascripts/issue_show/components/edit_actions.vue
index ce867f16acf..588ae655de4 100644
--- a/app/assets/javascripts/issue_show/components/edit_actions.vue
+++ b/app/assets/javascripts/issue_show/components/edit_actions.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { __, sprintf } from '~/locale';
import updateMixin from '../mixins/update';
import eventHub from '../event_hub';
diff --git a/app/assets/javascripts/issue_show/components/edited.vue b/app/assets/javascripts/issue_show/components/edited.vue
index 2c92324d292..64f61a1b88e 100644
--- a/app/assets/javascripts/issue_show/components/edited.vue
+++ b/app/assets/javascripts/issue_show/components/edited.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
export default {
diff --git a/app/assets/javascripts/issue_show/components/fields/description_template.vue b/app/assets/javascripts/issue_show/components/fields/description_template.vue
index bc3c81d479e..6d8a9950b6d 100644
--- a/app/assets/javascripts/issue_show/components/fields/description_template.vue
+++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import $ from 'jquery';
import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors';
diff --git a/app/assets/javascripts/jobs/components/commit_block.vue b/app/assets/javascripts/jobs/components/commit_block.vue
index 8156f26ffb1..88649ddbdb7 100644
--- a/app/assets/javascripts/jobs/components/commit_block.vue
+++ b/app/assets/javascripts/jobs/components/commit_block.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlLink } from '@gitlab/ui';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
diff --git a/app/assets/javascripts/lib/utils/autosave.js b/app/assets/javascripts/lib/utils/autosave.js
index 37896626053..56df2532528 100644
--- a/app/assets/javascripts/lib/utils/autosave.js
+++ b/app/assets/javascripts/lib/utils/autosave.js
@@ -29,5 +29,5 @@ export const updateDraft = (autosaveKey, text) => {
};
export const getDiscussionReplyKey = (noteableType, discussionId) =>
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
['Note', capitalizeFirstCharacter(noteableType), discussionId, 'Reply'].join('/');
diff --git a/app/assets/javascripts/lib/utils/datetime_range.js b/app/assets/javascripts/lib/utils/datetime_range.js
index 6d4e21cf386..9275b9e74e1 100644
--- a/app/assets/javascripts/lib/utils/datetime_range.js
+++ b/app/assets/javascripts/lib/utils/datetime_range.js
@@ -10,7 +10,7 @@ const durationToMillis = duration => {
if (Object.entries(duration).length === 1 && Number.isFinite(duration.seconds)) {
return secondsToMilliseconds(duration.seconds);
}
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
throw new Error('Invalid duration: only `seconds` is supported');
};
@@ -131,7 +131,7 @@ const convertOpenToFixed = ({ anchor, direction }) => {
* Handles invalid date ranges
*/
const handleInvalidRange = () => {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
throw new Error('The input range does not have the right format.');
};
diff --git a/app/assets/javascripts/lib/utils/notify.js b/app/assets/javascripts/lib/utils/notify.js
index 8db08099b3f..aa7884846a3 100644
--- a/app/assets/javascripts/lib/utils/notify.js
+++ b/app/assets/javascripts/lib/utils/notify.js
@@ -13,7 +13,7 @@ function notificationGranted(message, opts, onclick) {
}
function notifyPermissions() {
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
if ('Notification' in window) {
return Notification.requestPermission();
}
@@ -25,7 +25,7 @@ function notifyMe(message, body, icon, onclick) {
icon,
};
// Let's check if the browser supports notifications
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
if (!('Notification' in window)) {
// do nothing
} else if (Notification.permission === 'granted') {
diff --git a/app/assets/javascripts/lib/utils/unit_format/formatter_factory.js b/app/assets/javascripts/lib/utils/unit_format/formatter_factory.js
index 98bcb8348e2..5d3dd79850e 100644
--- a/app/assets/javascripts/lib/utils/unit_format/formatter_factory.js
+++ b/app/assets/javascripts/lib/utils/unit_format/formatter_factory.js
@@ -111,7 +111,7 @@ export const scaledSIFormatter = (unit = '', prefixOffset = 0) => {
});
if (!units.length) {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
throw new RangeError('The unit cannot be converted, please try a different scale');
}
@@ -122,7 +122,7 @@ export const scaledSIFormatter = (unit = '', prefixOffset = 0) => {
* Returns a function that formats a number scaled using SI units notation.
*/
export const scaledBinaryFormatter = (unit = '', prefixOffset = 0) => {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
const multiplicative = ['Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
const symbols = ['', ...multiplicative];
@@ -131,7 +131,7 @@ export const scaledBinaryFormatter = (unit = '', prefixOffset = 0) => {
});
if (!units.length) {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
throw new RangeError('The unit cannot be converted, please try a different scale');
}
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 4d3a61a7627..81b2e9f13a5 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -49,7 +49,7 @@ window.$ = jQuery;
// Add nonce to jQuery script handler
jQuery.ajaxSetup({
converters: {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings, func-names
+ // eslint-disable-next-line @gitlab/require-i18n-strings, func-names
'text script': function(text) {
jQuery.globalEval(text, { nonce: getCspNonceValue() });
return text;
diff --git a/app/assets/javascripts/monitoring/components/charts/stacked_column.vue b/app/assets/javascripts/monitoring/components/charts/stacked_column.vue
index 56a747b9d1f..66ba20c125f 100644
--- a/app/assets/javascripts/monitoring/components/charts/stacked_column.vue
+++ b/app/assets/javascripts/monitoring/components/charts/stacked_column.vue
@@ -68,7 +68,7 @@ export default {
}
})
.catch(e => {
- // eslint-disable-next-line no-console, @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line no-console, @gitlab/require-i18n-strings
console.error('SVG could not be rendered correctly: ', e);
});
},
diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue
index cba0a6da6a9..f3cbdffec64 100644
--- a/app/assets/javascripts/monitoring/components/charts/time_series.vue
+++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue
@@ -327,7 +327,7 @@ export default {
}
})
.catch(e => {
- // eslint-disable-next-line no-console, @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line no-console, @gitlab/require-i18n-strings
console.error('SVG could not be rendered correctly: ', e);
});
},
diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue
index 4573ec58ab8..ba92b72a71d 100644
--- a/app/assets/javascripts/monitoring/components/panel_type.vue
+++ b/app/assets/javascripts/monitoring/components/panel_type.vue
@@ -95,7 +95,7 @@ export default {
csvText() {
const chartData = this.graphData.metrics[0].result[0].values;
const yLabel = this.graphData.y_label;
- const header = `timestamp,${yLabel}\r\n`; // eslint-disable-line @gitlab/i18n/no-non-i18n-strings
+ const header = `timestamp,${yLabel}\r\n`; // eslint-disable-line @gitlab/require-i18n-strings
return chartData.reduce((csv, data) => {
const row = data.join(',');
return `${csv}${row}\r\n`;
diff --git a/app/assets/javascripts/monitoring/utils.js b/app/assets/javascripts/monitoring/utils.js
index 6694ae2f157..6a46c7e67e4 100644
--- a/app/assets/javascripts/monitoring/utils.js
+++ b/app/assets/javascripts/monitoring/utils.js
@@ -28,7 +28,7 @@ export const graphDataValidatorForValues = (isValues, graphData) => {
);
};
-/* eslint-disable @gitlab/i18n/no-non-i18n-strings */
+/* eslint-disable @gitlab/require-i18n-strings */
/**
* Checks that element that triggered event is located on cluster health check dashboard
* @param {HTMLElement} element to check against
diff --git a/app/assets/javascripts/mr_popover/components/mr_popover.vue b/app/assets/javascripts/mr_popover/components/mr_popover.vue
index bbc2feae812..e6bf7a6ec02 100644
--- a/app/assets/javascripts/mr_popover/components/mr_popover.vue
+++ b/app/assets/javascripts/mr_popover/components/mr_popover.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlPopover, GlSkeletonLoading } from '@gitlab/ui';
import CiIcon from '../../vue_shared/components/ci_icon.vue';
import timeagoMixin from '../../vue_shared/mixins/timeago';
@@ -8,7 +8,7 @@ import { mrStates, humanMRStates } from '../constants';
export default {
// name: 'MRPopover' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/25
- name: 'MRPopover', // eslint-disable-line @gitlab/i18n/no-non-i18n-strings
+ name: 'MRPopover', // eslint-disable-line @gitlab/require-i18n-strings
components: {
GlPopover,
GlSkeletonLoading,
@@ -102,11 +102,11 @@ export default {
<ci-icon v-if="detailedStatus" :status="detailedStatus" />
</div>
<h5 class="my-2">{{ mergeRequestTitle }}</h5>
- <!-- eslint-disable @gitlab/vue-i18n/no-bare-strings -->
+ <!-- eslint-disable @gitlab/vue-require-i18n-strings -->
<div class="text-secondary">
{{ `${projectPath}!${mergeRequestIID}` }}
</div>
- <!-- eslint-enable @gitlab/vue-i18n/no-bare-strings -->
+ <!-- eslint-enable @gitlab/vue-require-i18n-strings -->
</div>
</gl-popover>
</template>
diff --git a/app/assets/javascripts/new_branch_form.js b/app/assets/javascripts/new_branch_form.js
index 918c6e408a2..be3ea4e680c 100644
--- a/app/assets/javascripts/new_branch_form.js
+++ b/app/assets/javascripts/new_branch_form.js
@@ -1,4 +1,4 @@
-/* eslint-disable func-names, consistent-return, no-return-assign, no-else-return, @gitlab/i18n/no-non-i18n-strings */
+/* eslint-disable func-names, consistent-return, no-return-assign, no-else-return, @gitlab/require-i18n-strings */
import $ from 'jquery';
import RefSelectDropdown from './ref_select_dropdown';
diff --git a/app/assets/javascripts/notebook/cells/code/index.vue b/app/assets/javascripts/notebook/cells/code/index.vue
index 470d8c87d59..e1ef9aa6d79 100644
--- a/app/assets/javascripts/notebook/cells/code/index.vue
+++ b/app/assets/javascripts/notebook/cells/code/index.vue
@@ -29,6 +29,7 @@ export default {
metadata: {
type: Object,
default: () => ({}),
+ required: false,
},
},
computed: {
diff --git a/app/assets/javascripts/notebook/cells/markdown.vue b/app/assets/javascripts/notebook/cells/markdown.vue
index 753aa96bb55..dab27cf8269 100644
--- a/app/assets/javascripts/notebook/cells/markdown.vue
+++ b/app/assets/javascripts/notebook/cells/markdown.vue
@@ -43,7 +43,7 @@ renderer.paragraph = t => {
if (typeof katex !== 'undefined') {
const katexString = text
.replace(/&amp;/g, '&')
- .replace(/&=&/g, '\\space=\\space') // eslint-disable-line @gitlab/i18n/no-non-i18n-strings
+ .replace(/&=&/g, '\\space=\\space') // eslint-disable-line @gitlab/require-i18n-strings
.replace(/<(\/?)em>/g, '_');
const regex = new RegExp(katexRegexString, 'gi');
const matchLocation = katexString.search(regex);
diff --git a/app/assets/javascripts/notebook/cells/output/image.vue b/app/assets/javascripts/notebook/cells/output/image.vue
index 842d9e8da0d..065f5def83c 100644
--- a/app/assets/javascripts/notebook/cells/output/image.vue
+++ b/app/assets/javascripts/notebook/cells/output/image.vue
@@ -25,7 +25,7 @@ export default {
},
computed: {
imgSrc() {
- return `data:${this.outputType};base64,${this.rawCode}`; // eslint-disable-line @gitlab/i18n/no-non-i18n-strings
+ return `data:${this.outputType};base64,${this.rawCode}`; // eslint-disable-line @gitlab/require-i18n-strings
},
showOutput() {
return this.index === 0;
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
index d8b0e099bc4..61626f7aaf5 100644
--- a/app/assets/javascripts/notebook/cells/output/index.vue
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -22,6 +22,7 @@ export default {
metadata: {
type: Object,
default: () => ({}),
+ required: false,
},
},
methods: {
diff --git a/app/assets/javascripts/notebook/index.vue b/app/assets/javascripts/notebook/index.vue
index 4a3c1a28279..44dc1856e49 100644
--- a/app/assets/javascripts/notebook/index.vue
+++ b/app/assets/javascripts/notebook/index.vue
@@ -39,7 +39,7 @@ export default {
},
methods: {
cellType(type) {
- return `${type}-cell`; // eslint-disable-line @gitlab/i18n/no-non-i18n-strings
+ return `${type}-cell`; // eslint-disable-line @gitlab/require-i18n-strings
},
},
};
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index fe22737c7fc..c3915ef299b 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { mapState, mapActions } from 'vuex';
import { GlSkeletonLoading } from '@gitlab/ui';
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
diff --git a/app/assets/javascripts/notes/components/note_edited_text.vue b/app/assets/javascripts/notes/components/note_edited_text.vue
index 1af5af5c470..7c052320c98 100644
--- a/app/assets/javascripts/notes/components/note_edited_text.vue
+++ b/app/assets/javascripts/notes/components/note_edited_text.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
export default {
diff --git a/app/assets/javascripts/operation_settings/components/external_dashboard.vue b/app/assets/javascripts/operation_settings/components/external_dashboard.vue
index 8b6467bc0f6..3594e30bd69 100644
--- a/app/assets/javascripts/operation_settings/components/external_dashboard.vue
+++ b/app/assets/javascripts/operation_settings/components/external_dashboard.vue
@@ -54,14 +54,14 @@ export default {
:description="s__('ExternalMetrics|Enter the URL of the dashboard you want to link to')"
>
<!-- placeholder with a url is a false positive -->
- <!-- eslint-disable @gitlab/vue-i18n/no-bare-attribute-strings -->
+ <!-- eslint-disable @gitlab/vue-require-i18n-attribute-strings -->
<gl-form-input
id="full-dashboard-url"
v-model="userDashboardUrl"
placeholder="https://my-org.gitlab.io/my-dashboards"
@keydown.enter.native.prevent="updateExternalDashboardUrl"
/>
- <!-- eslint-enable @gitlab/vue-i18n/no-bare-attribute-strings -->
+ <!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings -->
</gl-form-group>
<gl-button variant="success" @click="updateExternalDashboardUrl">
{{ __('Save Changes') }}
diff --git a/app/assets/javascripts/pages/admin/users/index.js b/app/assets/javascripts/pages/admin/users/index.js
index bc96e88351b..86c4b4f4f48 100644
--- a/app/assets/javascripts/pages/admin/users/index.js
+++ b/app/assets/javascripts/pages/admin/users/index.js
@@ -19,7 +19,7 @@ function loadModalsConfigurationFromHtml(modalsElement) {
const modalsConfiguration = {};
if (!modalsElement) {
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
throw new Error('Modals content element not found!');
}
diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js
index 7b373a8ce22..a294f3f36a6 100644
--- a/app/assets/javascripts/performance_bar/index.js
+++ b/app/assets/javascripts/performance_bar/index.js
@@ -1,4 +1,4 @@
-/* eslint-disable @gitlab/i18n/no-non-i18n-strings */
+/* eslint-disable @gitlab/require-i18n-strings */
import Vue from 'vue';
import axios from '~/lib/utils/axios_utils';
diff --git a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue
index 3f07b77ed32..2212428ced5 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlLink, GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
diff --git a/app/assets/javascripts/registry/explorer/components/project_empty_state.vue b/app/assets/javascripts/registry/explorer/components/project_empty_state.vue
index 53853b4b9fb..556df10ea5b 100644
--- a/app/assets/javascripts/registry/explorer/components/project_empty_state.vue
+++ b/app/assets/javascripts/registry/explorer/components/project_empty_state.vue
@@ -14,15 +14,15 @@ export default {
computed: {
...mapState(['config']),
dockerBuildCommand() {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return `docker build -t ${this.config.repositoryUrl} .`;
},
dockerPushCommand() {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return `docker push ${this.config.repositoryUrl}`;
},
dockerLoginCommand() {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return `docker login ${this.config.registryHostUrlWithPort}`;
},
},
diff --git a/app/assets/javascripts/registry/list/components/project_empty_state.vue b/app/assets/javascripts/registry/list/components/project_empty_state.vue
index 80ef31004c8..900498ed03d 100644
--- a/app/assets/javascripts/registry/list/components/project_empty_state.vue
+++ b/app/assets/javascripts/registry/list/components/project_empty_state.vue
@@ -37,15 +37,15 @@ export default {
},
computed: {
dockerBuildCommand() {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return `docker build -t ${this.repositoryUrl} .`;
},
dockerPushCommand() {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return `docker push ${this.repositoryUrl}`;
},
dockerLoginCommand() {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return `docker login ${this.registryHostUrlWithPort}`;
},
noContainerImagesText() {
diff --git a/app/assets/javascripts/reports/components/report_link.vue b/app/assets/javascripts/reports/components/report_link.vue
index e32e1ac49ca..f285b526a54 100644
--- a/app/assets/javascripts/reports/components/report_link.vue
+++ b/app/assets/javascripts/reports/components/report_link.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
export default {
name: 'ReportIssueLink',
props: {
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index f3e6e3686a3..88a7e3e3a68 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -151,7 +151,7 @@ export default {
>
{{ fullPath }}
</component>
- <!-- eslint-disable-next-line @gitlab/vue-i18n/no-bare-strings -->
+ <!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings -->
<gl-badge v-if="lfsOid" variant="default" class="label-lfs ml-1">LFS</gl-badge>
<template v-if="isSubmodule">
@ <gl-link :href="submoduleTreeUrl" class="commit-sha">{{ shortSha }}</gl-link>
diff --git a/app/assets/javascripts/repository/graphql.js b/app/assets/javascripts/repository/graphql.js
index 265df20636b..0c68b5a599b 100644
--- a/app/assets/javascripts/repository/graphql.js
+++ b/app/assets/javascripts/repository/graphql.js
@@ -39,7 +39,7 @@ const defaultClient = createDefaultClient(
cacheConfig: {
fragmentMatcher,
dataIdFromObject: obj => {
- /* eslint-disable @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-disable @gitlab/require-i18n-strings */
// eslint-disable-next-line no-underscore-dangle
switch (obj.__typename) {
// We need to create a dynamic ID for each entry
@@ -55,7 +55,7 @@ const defaultClient = createDefaultClient(
// eslint-disable-next-line no-underscore-dangle
return obj.id || obj._id;
}
- /* eslint-enable @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-enable @gitlab/require-i18n-strings */
},
},
},
diff --git a/app/assets/javascripts/repository/utils/title.js b/app/assets/javascripts/repository/utils/title.js
index 9c4b334a1ce..442f6c5d741 100644
--- a/app/assets/javascripts/repository/utils/title.js
+++ b/app/assets/javascripts/repository/utils/title.js
@@ -9,7 +9,7 @@ export const setTitle = (pathMatch, ref, project) => {
const path = pathMatch.replace(/^\//, '');
const isEmpty = path === '';
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
document.title = `${isEmpty ? 'Files' : path} · ${ref} · ${project} ${DEFAULT_TITLE}`;
};
diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js
index 8d888a574d8..3eaa34c8a93 100644
--- a/app/assets/javascripts/search_autocomplete.js
+++ b/app/assets/javascripts/search_autocomplete.js
@@ -420,11 +420,11 @@ export class SearchAutocomplete {
onClick(item, $el, e) {
if (window.location.pathname.indexOf(item.url) !== -1) {
if (!e.metaKey) e.preventDefault();
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
if (item.category === 'Projects') {
this.projectInputEl.val(item.id);
}
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
+ // eslint-disable-next-line @gitlab/require-i18n-strings
if (item.category === 'Groups') {
this.groupInputEl.val(item.id);
}
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees.vue b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
index d9739e8d197..f16b16a6837 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
@@ -4,7 +4,7 @@ import UncollapsedAssigneeList from '../assignees/uncollapsed_assignee_list.vue'
export default {
// name: 'Assignees' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
name: 'Assignees',
components: {
CollapsedAssigneeList,
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
index 682ca600b6a..1e8a31fff81 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
@@ -40,6 +40,7 @@ export default {
limitToHours: {
type: Boolean,
default: false,
+ required: false,
},
rootPath: {
type: String,
diff --git a/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql b/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql
index 27a5cff12c7..b45b6b46c8f 100644
--- a/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql
@@ -1,7 +1,8 @@
-mutation ($projectPath: ID!, $iid: String!, $healthStatus: HealthStatus) {
- updateIssue(input: { projectPath: $projectPath, iid: $iid, healthStatus: $healthStatus}) {
+mutation($projectPath: ID!, $iid: String!, $healthStatus: HealthStatus) {
+ updateIssue(input: { projectPath: $projectPath, iid: $iid, healthStatus: $healthStatus }) {
issue {
healthStatus
}
+ errors
}
}
diff --git a/app/assets/javascripts/snippets/components/snippet_header.vue b/app/assets/javascripts/snippets/components/snippet_header.vue
index 36ba6eeecbd..bbe4c33fa43 100644
--- a/app/assets/javascripts/snippets/components/snippet_header.vue
+++ b/app/assets/javascripts/snippets/components/snippet_header.vue
@@ -137,7 +137,10 @@ export default {
mutation: DeleteSnippetMutation,
variables: { id: this.snippet.id },
})
- .then(() => {
+ .then(({ data }) => {
+ if (data?.destroySnippet?.errors) {
+ throw new Error(data?.destroySnippet?.errors[0]);
+ }
this.isDeleting = false;
this.errorMessage = undefined;
this.closeDeleteModal();
diff --git a/app/assets/javascripts/tracking.js b/app/assets/javascripts/tracking.js
index ab5acd83b01..09fe952e5f0 100644
--- a/app/assets/javascripts/tracking.js
+++ b/app/assets/javascripts/tracking.js
@@ -54,7 +54,7 @@ export default class Tracking {
static event(category = document.body.dataset.page, action = 'generic', data = {}) {
if (!this.enabled()) return false;
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
if (!category) throw new Error('Tracking: no category provided for tracking.');
const { label, property, value, context } = data;
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment.vue
index 9c476d5b2e0..f497936e299 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment.vue
@@ -5,7 +5,7 @@ import { MANUAL_DEPLOY, WILL_DEPLOY, CREATED } from './constants';
export default {
// name: 'Deployment' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
name: 'Deployment',
components: {
DeploymentActions,
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
index c8e652a1305..7279aaf0809 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlLoadingIcon } from '@gitlab/ui';
import Flash from '~/flash';
import tooltip from '~/vue_shared/directives/tooltip';
@@ -86,7 +86,7 @@ export default {
.then(res => res.data)
.then(data => {
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
if (data.message === 'Branch was deleted') {
eventHub.$emit('MRWidgetUpdateRequested', () => {
this.isMakingRequest = false;
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 8b12e8ffb73..084deee042b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -42,7 +42,7 @@ import { setFaviconOverlay } from '../lib/utils/common_utils';
export default {
el: '#js-vue-mr-widget',
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/25
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
name: 'MRWidget',
components: {
Loading,
diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
index 1bd320d81e8..60e41a16854 100644
--- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
@@ -40,7 +40,7 @@ export default {
computed: {
changedIcon() {
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
const suffix = this.file.staged && this.showStagedIcon ? '-solid' : '';
return `${getCommitIconMap(this.file).icon}${suffix}`;
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue
index 66155ddcdd9..2f5e5f35064 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue
@@ -8,6 +8,7 @@ export default {
content: {
type: String,
default: '',
+ required: false,
},
path: {
type: String,
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
index 6a4a834337a..9f98943f6b4 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
@@ -16,6 +16,7 @@ export default {
renderInfo: {
type: Boolean,
default: true,
+ required: false,
},
innerCssClasses: {
type: [Array, Object, String],
diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue
index 36cbb230d30..bf25ed96f35 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue
@@ -39,10 +39,10 @@ export default {
mdTable() {
return [
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
- '| header | header |', // eslint-disable-line @gitlab/i18n/no-non-i18n-strings
+ '| header | header |', // eslint-disable-line @gitlab/require-i18n-strings
'| ------ | ------ |',
- '| cell | cell |', // eslint-disable-line @gitlab/i18n/no-non-i18n-strings
- '| cell | cell |', // eslint-disable-line @gitlab/i18n/no-non-i18n-strings
+ '| cell | cell |', // eslint-disable-line @gitlab/require-i18n-strings
+ '| cell | cell |', // eslint-disable-line @gitlab/require-i18n-strings
].join('\n');
},
mdSuggestion() {
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
index 4da99e00165..486d4f6b609 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
+/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlLink, GlLoadingIcon } from '@gitlab/ui';
export default {
diff --git a/app/assets/javascripts/vue_shared/components/project_avatar/default.vue b/app/assets/javascripts/vue_shared/components/project_avatar/default.vue
index 881b5059d2a..4bc70870767 100644
--- a/app/assets/javascripts/vue_shared/components/project_avatar/default.vue
+++ b/app/assets/javascripts/vue_shared/components/project_avatar/default.vue
@@ -15,6 +15,7 @@ export default {
size: {
type: Number,
default: 40,
+ required: false,
},
},
computed: {
diff --git a/app/assets/javascripts/vue_shared/components/select2_select.vue b/app/assets/javascripts/vue_shared/components/select2_select.vue
index eb741d238b5..c90bd4da6c2 100644
--- a/app/assets/javascripts/vue_shared/components/select2_select.vue
+++ b/app/assets/javascripts/vue_shared/components/select2_select.vue
@@ -4,7 +4,7 @@ import 'select2';
export default {
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
name: 'Select2Select',
props: {
options: {
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue
index 0e401a9f7aa..44cc11a6aaa 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue
@@ -77,12 +77,12 @@ export default {
},
enableScopedLabels: {
type: Boolean,
- require: false,
+ required: false,
default: false,
},
scopedLabelsDocumentationLink: {
type: String,
- require: false,
+ required: false,
default: '#',
},
},
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue
index 1eed8907bb7..c3bc61d0053 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue
@@ -33,12 +33,12 @@ export default {
},
enableScopedLabels: {
type: Boolean,
- require: false,
+ required: false,
default: false,
},
scopedLabelsDocumentationLink: {
type: String,
- require: false,
+ required: false,
default: '#',
},
},
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js
index 145ec7dc566..e6053628eca 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js
@@ -45,7 +45,7 @@ export const createLabel = ({ state, dispatch }, label) => {
dispatch('receiveCreateLabelSuccess');
dispatch('toggleDropdownContentsCreateView');
} else {
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
throw new Error('Error Creating Label');
}
})
diff --git a/app/assets/javascripts/vue_shared/components/smart_virtual_list.vue b/app/assets/javascripts/vue_shared/components/smart_virtual_list.vue
index 49f987bb619..0fb7fd6cd38 100644
--- a/app/assets/javascripts/vue_shared/components/smart_virtual_list.vue
+++ b/app/assets/javascripts/vue_shared/components/smart_virtual_list.vue
@@ -8,9 +8,9 @@ export default {
size: { type: Number, required: true },
length: { type: Number, required: true },
remain: { type: Number, required: true },
- rtag: { type: String, default: 'div' },
- wtag: { type: String, default: 'div' },
- wclass: { type: String, default: null },
+ rtag: { type: String, default: 'div', required: false },
+ wtag: { type: String, default: 'div', required: false },
+ wclass: { type: String, default: null, required: false },
},
};
</script>
diff --git a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
index ea564d1b2f2..ec077197c9c 100644
--- a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
+++ b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
@@ -83,7 +83,7 @@ export default {
},
barStyle(percent) {
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ // eslint-disable-next-line @gitlab/require-i18n-strings
return `width: ${percent}%;`;
},
getTooltip(label, count) {
diff --git a/app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb b/app/controllers/concerns/authenticates_2fa_for_admin_mode.rb
index c6fd1d55e51..c6fd1d55e51 100644
--- a/app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb
+++ b/app/controllers/concerns/authenticates_2fa_for_admin_mode.rb
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index 699aa51e6c8..bd9efef94f8 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -51,6 +51,7 @@ module Types
Types::BoardType.connection_type,
null: true,
description: 'Boards of the group',
+ max_page_size: 2000,
resolver: Resolvers::BoardsResolver
field :board,
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 1142459f6eb..5c0b9182ac5 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -184,6 +184,7 @@ module Types
Types::BoardType.connection_type,
null: true,
description: 'Boards of the project',
+ max_page_size: 2000,
resolver: Resolvers::BoardsResolver
field :board,
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 145807457a1..3d389013985 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -68,6 +68,7 @@ class Issue < ApplicationRecord
scope :order_closest_future_date, -> { reorder(Arel.sql('CASE WHEN issues.due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - issues.due_date) ASC')) }
scope :order_relative_position_asc, -> { reorder(::Gitlab::Database.nulls_last_order('relative_position', 'ASC')) }
scope :order_closed_date_desc, -> { reorder(closed_at: :desc) }
+ scope :order_created_at_desc, -> { reorder(created_at: :desc) }
scope :preload_associated_models, -> { preload(:labels, project: :namespace) }
scope :with_api_entity_associations, -> { preload(:timelogs, :assignees, :author, :notes, :labels, project: [:route, { namespace: :route }] ) }
diff --git a/changelogs/unreleased/208923-enable-batch-counting-for-some-individual-queries-4.yml b/changelogs/unreleased/208923-enable-batch-counting-for-some-individual-queries-4.yml
new file mode 100644
index 00000000000..07e7b71a787
--- /dev/null
+++ b/changelogs/unreleased/208923-enable-batch-counting-for-some-individual-queries-4.yml
@@ -0,0 +1,5 @@
+---
+title: Optimize projects_service_active queries performance in usage data
+merge_request: 27093
+author:
+type: performance
diff --git a/changelogs/unreleased/ref-params-validator.yml b/changelogs/unreleased/ref-params-validator.yml
new file mode 100644
index 00000000000..a4ac8e30e19
--- /dev/null
+++ b/changelogs/unreleased/ref-params-validator.yml
@@ -0,0 +1,5 @@
+---
+title: Add grape custom validator for git reference params
+merge_request: 26102
+author: Rajendra Kadam
+type: added
diff --git a/config/application.rb b/config/application.rb
index 14e92bf5905..e1be913b5c3 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -32,6 +32,8 @@ module Gitlab
config.active_record.sqlite3.represent_boolean_as_integer = true
+ config.autoloader = :zeitwerk
+
# Sidekiq uses eager loading, but directories not in the standard Rails
# directories must be added to the eager load paths:
# https://github.com/mperham/sidekiq/wiki/FAQ#why-doesnt-sidekiq-autoload-my-rails-application-code
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 25d57467060..c42d7127a22 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -42,7 +42,7 @@ Rails.application.configure do
config.action_mailer.raise_delivery_errors = true
# Don't make a mess when bootstrapping a development environment
config.action_mailer.perform_deliveries = (ENV['BOOTSTRAP'] != '1')
- config.action_mailer.preview_path = 'app/mailers/previews'
+ config.action_mailer.preview_path = Rails.root.join('app', 'mailers', 'previews')
config.eager_load = false
diff --git a/config/environments/test.rb b/config/environments/test.rb
index 71cd5200415..f8fb7f60f0d 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -43,7 +43,7 @@ Rails.application.configure do
# Print deprecation notices to the stderr
config.active_support.deprecation = :stderr
- config.eager_load = true
+ config.eager_load = false
config.cache_store = :null_store
diff --git a/config/initializers/2_gitlab.rb b/config/initializers/2_gitlab.rb
deleted file mode 100644
index 8b7f245b7b0..00000000000
--- a/config/initializers/2_gitlab.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_dependency 'gitlab'
diff --git a/config/initializers_before_autoloader/002_zeitwerk.rb b/config/initializers_before_autoloader/002_zeitwerk.rb
new file mode 100644
index 00000000000..df0c16b0bc0
--- /dev/null
+++ b/config/initializers_before_autoloader/002_zeitwerk.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+Rails.autoloaders.each do |autoloader|
+ # We need to ignore these since these are non-Ruby files
+ # that do not define Ruby classes / modules
+ autoloader.ignore(Rails.root.join('lib/support'))
+ # Ignore generators since these are loaded manually by Rails
+ autoloader.ignore(Rails.root.join('lib/generators'))
+ autoloader.ignore(Rails.root.join('ee/lib/generators')) if Gitlab.ee?
+ # Mailer previews are also loaded manually by Rails
+ autoloader.ignore(Rails.root.join('app/mailers/previews'))
+ autoloader.ignore(Rails.root.join('ee/app/mailers/previews')) if Gitlab.ee?
+ # Ignore these files because these are only used in Rake tasks
+ # and are not available in production
+ autoloader.ignore(Rails.root.join('lib/gitlab/graphql/docs'))
+
+ autoloader.inflector.inflect(
+ 'authenticates_2fa_for_admin_mode' => 'Authenticates2FAForAdminMode',
+ 'api' => 'API',
+ 'api_guard' => 'APIGuard',
+ 'group_api_compatibility' => 'GroupAPICompatibility',
+ 'project_api_compatibility' => 'ProjectAPICompatibility',
+ 'cte' => 'CTE',
+ 'recursive_cte' => 'RecursiveCTE',
+ 'cidr' => 'CIDR',
+ 'cli' => 'CLI',
+ 'dn' => 'DN',
+ 'hmac_token' => 'HMACToken',
+ 'html' => 'HTML',
+ 'html_parser' => 'HTMLParser',
+ 'html_gitlab' => 'HTMLGitlab',
+ 'http' => 'HTTP',
+ 'http_connection_adapter' => 'HTTPConnectionAdapter',
+ 'http_clone_enabled_check' => 'HTTPCloneEnabledCheck',
+ 'chunked_io' => 'ChunkedIO',
+ 'http_io' => 'HttpIO',
+ 'json' => 'JSON',
+ 'json_formatter' => 'JSONFormatter',
+ 'json_web_token' => 'JSONWebToken',
+ 'as_json' => 'AsJSON',
+ 'ldap_key' => 'LDAPKey',
+ 'mr_note' => 'MRNote',
+ 'pdf' => 'PDF',
+ 'rsa_token' => 'RSAToken',
+ 'san_extension' => 'SANExtension',
+ 'sca' => 'SCA',
+ 'spdx' => 'SPDX',
+ 'sql' => 'SQL',
+ 'ssh_key' => 'SSHKey',
+ 'ssh_key_with_user' => 'SSHKeyWithUser',
+ 'ssh_public_key' => 'SSHPublicKey',
+ 'git_push_ssh_proxy' => 'GitPushSSHProxy',
+ 'git_user_default_ssh_config_check' => 'GitUserDefaultSSHConfigCheck',
+ 'binary_stl' => 'BinarySTL',
+ 'text_stl' => 'TextSTL',
+ 'svg' => 'SVG',
+ 'function_uri' => 'FunctionURI'
+ )
+end
diff --git a/config/settings.rb b/config/settings.rb
index 144a068ef2a..a9e91ce22d7 100644
--- a/config/settings.rb
+++ b/config/settings.rb
@@ -3,12 +3,6 @@
require 'settingslogic'
require 'digest/md5'
-# We can not use `Rails.root` here, as this file might be loaded without the
-# full Rails environment being loaded. We can not use `require_relative` either,
-# as Rails uses `load` for `require_dependency` (used when loading the Rails
-# environment). This could then lead to this file being loaded twice.
-require_dependency File.expand_path('../lib/gitlab', __dir__)
-
class Settings < Settingslogic
source ENV.fetch('GITLAB_CONFIG') { Pathname.new(File.expand_path('..', __dir__)).join('config/gitlab.yml') }
namespace ENV.fetch('GITLAB_ENV') { Rails.env }
diff --git a/db/migrate/20200312125121_add_index_on_active_and_template_and_type_and_id_to_services.rb b/db/migrate/20200312125121_add_index_on_active_and_template_and_type_and_id_to_services.rb
new file mode 100644
index 00000000000..3a2390bb6a1
--- /dev/null
+++ b/db/migrate/20200312125121_add_index_on_active_and_template_and_type_and_id_to_services.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddIndexOnActiveAndTemplateAndTypeAndIdToServices < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_services_on_type_and_id_and_template_when_active'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :services, [:type, :id, :template], where: 'active = TRUE', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index :services, INDEX_NAME
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 9edc1d9853c..db9ba2ce8f5 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -3977,6 +3977,7 @@ ActiveRecord::Schema.define(version: 2020_03_13_123934) do
t.boolean "instance", default: false, null: false
t.index ["project_id", "type"], name: "index_services_on_project_id_and_type"
t.index ["template"], name: "index_services_on_template"
+ t.index ["type", "id", "template"], name: "index_services_on_type_and_id_and_template_when_active", where: "(active = true)"
t.index ["type", "instance"], name: "index_services_on_type_and_instance", unique: true, where: "(instance IS TRUE)"
t.index ["type", "template"], name: "index_services_on_type_and_template", unique: true, where: "(template IS TRUE)"
t.index ["type"], name: "index_services_on_type"
diff --git a/doc/administration/gitaly/img/praefect_architecture_v12_10.png b/doc/administration/gitaly/img/praefect_architecture_v12_10.png
new file mode 100644
index 00000000000..7b8f1138b23
--- /dev/null
+++ b/doc/administration/gitaly/img/praefect_architecture_v12_10.png
Binary files differ
diff --git a/doc/administration/gitaly/img/praefect_architecture_v12_9.png b/doc/administration/gitaly/img/praefect_architecture_v12_9.png
deleted file mode 100644
index b68e495cb17..00000000000
--- a/doc/administration/gitaly/img/praefect_architecture_v12_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index 4e8dc533f44..9fb61d93f73 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -28,7 +28,7 @@ reference architecture additionally requires:
- 1 PostgreSQL server (PostgreSQL 9.6 or newer)
- 3 Gitaly nodes (1 primary, 2 secondary)
-![Alpha architecture diagram](img/praefect_architecture_v12_9.png)
+![Alpha architecture diagram](img/praefect_architecture_v12_10.png)
See the [design
document](https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/design_ha.md)
diff --git a/doc/administration/index.md b/doc/administration/index.md
index 4ca03fa2669..2ab4b3f710e 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -200,6 +200,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Log system](logs.md): Where to look for logs.
- [Sidekiq Troubleshooting](troubleshooting/sidekiq.md): Debug when Sidekiq appears hung and is not processing jobs.
- [Troubleshooting Elasticsearch](troubleshooting/elasticsearch.md)
+- [Navigating GitLab via Rails console](troubleshooting/navigating_gitlab_via_rails_console.md)
- [GitLab application limits](instance_limits.md)
### Support Team Docs
diff --git a/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md b/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
new file mode 100644
index 00000000000..01c3da80481
--- /dev/null
+++ b/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
@@ -0,0 +1,469 @@
+# Navigating GitLab via Rails console
+
+At the heart of GitLab is a web application [built using the Ruby on Rails
+framework](https://about.gitlab.com/blog/2018/10/29/why-we-use-rails-to-build-gitlab/).
+Thanks to this, we also get access to the amazing tools built right into Rails.
+In this guide, we'll introduce the [Rails console](https://docs.gitlab.com/omnibus/maintenance/#starting-a-rails-console-session)
+and the basics of interacting with your GitLab instance from the command line.
+
+CAUTION: **CAUTION:**
+The Rails console interacts directly with your GitLab instance. In many cases,
+there are no handrails to prevent you from permanently modifying, corrupting
+or destroying production data. If you would like to explore the Rails console
+with no consequences, you are strongly advised to do so in a test environment.
+
+This guide is targeted at GitLab system administrators who are troubleshooting
+a problem or need to retrieve some data that can only be done through direct
+access of the GitLab application. Basic knowledge of Ruby is needed (try [this
+30-minute tutorial](https://try.ruby-lang.org/) for a quick introduction).
+Rails experience is helpful to have but not a must.
+
+## Starting a Rails console session
+
+Omnibus GitLab comes with a convenient wrapper command which automatically loads
+the production GitLab environment:
+
+```shell
+sudo gitlab-rails console
+```
+
+For source installations, you'll have to instead run:
+
+```shell
+sudo -u git -H bundle exec rails console RAILS_ENV=production
+```
+
+Further code examples will all take place inside the Rails console and also
+assume an Omnibus GitLab installation.
+
+## Active Record objects
+
+### Looking up database-persisted objects
+
+Under the hood, Rails uses [Active Record](https://guides.rubyonrails.org/active_record_basics.html),
+an object-relational mapping system, to read, write and map application objects
+to the PostgreSQL database. These mappings are handled by Active Record models,
+which are Ruby classes defined in a Rails app. For GitLab, the model classes
+can be found at `/opt/gitlab/embedded/service/gitlab-rails/app/models`.
+
+Let's enable debug logging for Active Record so we can see the underlying
+database queries made:
+
+```ruby
+ActiveRecord::Base.logger = Logger.new(STDOUT)
+```
+
+Now, let's try retrieving a user from the database:
+
+```ruby
+user = User.find(1)
+```
+
+Which would return:
+
+```ruby
+D, [2020-03-05T16:46:25.571238 #910] DEBUG -- : User Load (1.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
+=> #<User id:1 @root>
+```
+
+We can see that we've queried the `users` table in the database for a row whose
+`id` column has the value `1`, and Active Record has translated that database
+record into a Ruby object that we can interact with. Try some of the following:
+
+- `user.username`
+- `user.created_at`
+- `user.admin`
+
+By convention, column names are directly translated into Ruby object attributes,
+so you should be able to do `user.<column_name>` to view the attribute's value.
+
+Also by convention, Active Record class names (singular and in camel case) map
+directly onto table names (plural and in snake case) and vice versa. For example,
+the `users` table maps to the `User` class, while the `application_settings`
+table maps to the `ApplicationSetting` class.
+
+You can find a list of tables and column names in the Rails database schema,
+available at `/opt/gitlab/embedded/service/gitlab-rails/db/schema.rb`.
+
+You can also look up an object from the database by attribute name:
+
+```ruby
+user = User.find_by(username: 'root')
+```
+
+Which would return:
+
+```ruby
+D, [2020-03-05T17:03:24.696493 #910] DEBUG -- : User Load (2.1ms) SELECT "users".* FROM "users" WHERE "users"."username" = 'root' LIMIT 1
+=> #<User id:1 @root>
+```
+
+Give the following a try:
+
+- `User.find_by(email: 'admin@example.com')`
+- `User.where.not(admin: true)`
+- `User.where('created_at < ?', 7.days.ago)`
+
+Did you notice that the last two commands returned an `ActiveRecord::Relation`
+object that appeared to contain multiple `User` objects?
+
+Up to now, we've been using `.find` or `.find_by`, which are designed to return
+only a single object (notice the `LIMIT 1` in the generated SQL query?).
+`.where` is used when it is desirable to get a collection of objects.
+
+Let's get a collection of non-admin users and see what we can do with it:
+
+```ruby
+users = User.where.not(admin: true)
+```
+
+Which would return:
+
+```ruby
+D, [2020-03-05T17:11:16.845387 #910] DEBUG -- : User Load (2.8ms) SELECT "users".* FROM "users" WHERE "users"."admin" != TRUE LIMIT 11
+=> #<ActiveRecord::Relation [#<User id:3 @support-bot>, #<User id:7 @alert-bot>, #<User id:5 @carrie>, #<User id:4 @bernice>, #<User id:2 @anne>]>
+```
+
+Now, try the following:
+
+- `users.count`
+- `users.order(created_at: :desc)`
+- `users.where(username: 'support-bot')`
+
+In the last command, we see that we can chain `.where` statements to generate
+more complex queries. Notice also that while the collection returned contains
+only a single object, we cannot directly interact with it:
+
+```ruby
+users.where(username: 'support-bot').username
+```
+
+Which would return:
+
+```ruby
+Traceback (most recent call last):
+ 1: from (irb):37
+D, [2020-03-05T17:18:25.637607 #910] DEBUG -- : User Load (1.6ms) SELECT "users".* FROM "users" WHERE "users"."admin" != TRUE AND "users"."username" = 'support-bot' LIMIT 11
+NoMethodError (undefined method `username' for #<ActiveRecord::Relation [#<User id:3 @support-bot>]>)
+Did you mean? by_username
+```
+
+We need to retrieve the single object from the collection by using the `.first`
+method to get the first item in the collection:
+
+```ruby
+users.where(username: 'support-bot').first.username
+```
+
+We now get the result we wanted:
+
+```ruby
+D, [2020-03-05T17:18:30.406047 #910] DEBUG -- : User Load (2.6ms) SELECT "users".* FROM "users" WHERE "users"."admin" != TRUE AND "users"."username" = 'support-bot' ORDER BY "users"."id" ASC LIMIT 1
+=> "support-bot"
+```
+
+For more on different ways to retrieve data from the database using Active
+Record, please see the [Active Record Query Interface documentation](https://guides.rubyonrails.org/active_record_querying.html).
+
+### Modifying Active Record objects
+
+In the previous section, we learned about retrieving database records using
+Active Record. Now, we'll learn how to write changes to the database.
+
+First, let's retrieve the `root` user:
+
+```ruby
+user = User.find_by(username: 'root')
+```
+
+Next, let's try updating the user's password:
+
+```ruby
+user.password = 'password'
+user.save
+```
+
+Which would return:
+
+```ruby
+Enqueued ActionMailer::DeliveryJob (Job ID: 05915c4e-c849-4e14-80bb-696d5ae22065) to Sidekiq(mailers) with arguments: "DeviseMailer", "password_change", "deliver_now", #<GlobalID:0x00007f42d8ccebe8 @uri=#<URI::GID gid://gitlab/User/1>>
+=> true
+```
+
+Here, we see that the `.save` command returned `true`, indicating that the
+password change was successfully saved to the database.
+
+We also see that the save operation triggered some other action -- in this case
+a background job to deliver an email notification. This is an example of an
+[Active Record callback](https://guides.rubyonrails.org/active_record_callbacks.html)
+-- code which is designated to run in response to events in the Active Record
+object life cycle. This is also why using the Rails console is preferred when
+direct changes to data is necessary as changes made via direct database queries
+will not trigger these callbacks.
+
+It's also possible to update attributes in a single line:
+
+```ruby
+user.update(password: 'password')
+```
+
+Or update multiple attributes at once:
+
+```ruby
+user.update(password: 'password', email: 'hunter2@example.com')
+```
+
+Now, let's try something different:
+
+```ruby
+# Retrieve the object again so we get its latest state
+user = User.find_by(username: 'root')
+user.password = 'password'
+user.password_confirmation = 'hunter2'
+user.save
+```
+
+This returns `false`, indicating that the changes we made were not saved to the
+database. You can probably guess why, but let's find out for sure:
+
+```ruby
+user.save!
+```
+
+This should return:
+
+```ruby
+Traceback (most recent call last):
+ 1: from (irb):64
+ActiveRecord::RecordInvalid (Validation failed: Password confirmation doesn't match Password)
+```
+
+Aha! We've tripped an [Active Record Validation](https://guides.rubyonrails.org/active_record_validations.html).
+Validations are business logic put in place at the application-level to prevent
+unwanted data from being saved to the database and in most cases come with
+helpful messages letting you know how to fix the problem inputs.
+
+We can also add the bang (Ruby speak for `!`) to `.update`:
+
+```ruby
+user.update!(password: 'password', password_confirmation: 'hunter2')
+```
+
+In Ruby, method names ending with `!` are commonly known as "bang methods". By
+convention, the bang indicates that the method directly modifies the object it
+is acting on, as opposed to returning the transformed result and leaving the
+underlying object untouched. For Active Record methods that write to the
+database, bang methods also serve an additional function: they raise an
+explicit exception whenever an error occurs, instead of just returning `false`.
+
+We can also skip validations entirely:
+
+```ruby
+# Retrieve the object again so we get its latest state
+user = User.find_by(username: 'root')
+user.password = 'password'
+user.password_confirmation = 'hunter2'
+user.save!(validate: false)
+```
+
+This is not recommended, as validations are usually put in place to ensure the
+integrity and consistency of user-provided data.
+
+Note that a validation error will prevent the entire object from being saved to
+the database. We'll see a little of this in the next section. If you're getting
+a mysterious red banner in the GitLab UI when submitting a form, this can often
+be the fastest way to get to the root of the problem.
+
+### Interacting with Active Record objects
+
+At the end of the day, Active Record objects are just normal Ruby objects. As
+such, we can define methods on them which perform arbitrary actions.
+
+For example, GitLab developers have added some methods which help with
+two-factor authentication:
+
+```ruby
+def disable_two_factor!
+ transaction do
+ update(
+ otp_required_for_login: false,
+ encrypted_otp_secret: nil,
+ encrypted_otp_secret_iv: nil,
+ encrypted_otp_secret_salt: nil,
+ otp_grace_period_started_at: nil,
+ otp_backup_codes: nil
+ )
+ self.u2f_registrations.destroy_all # rubocop: disable DestroyAll
+ end
+end
+
+def two_factor_enabled?
+ two_factor_otp_enabled? || two_factor_u2f_enabled?
+end
+```
+
+(See: `/opt/gitlab/embedded/service/gitlab-rails/app/models/user.rb`)
+
+We can then use these methods on any user object:
+
+```ruby
+user = User.find_by(username: 'root')
+user.two_factor_enabled?
+user.disable_two_factor!
+```
+
+Some methods are defined by gems, or Ruby software packages, which GitLab uses.
+For example, the [StateMachines](https://github.com/state-machines/state_machines-activerecord)
+gem which GitLab uses to manage user state:
+
+```ruby
+state_machine :state, initial: :active do
+ event :block do
+
+ ...
+
+ event :activate do
+
+ ...
+
+end
+```
+
+Give it a try:
+
+```ruby
+user = User.find_by(username: 'root')
+user.state
+user.block
+user.state
+user.activate
+user.state
+```
+
+Earlier, we mentioned that a validation error will prevent the entire object
+from being saved to the database. Let's see how this can have unexpected
+interactions:
+
+```ruby
+user.password = 'password'
+user.password_confirmation = 'hunter2'
+user.block
+```
+
+We get `false` returned! Let's find out what happened by adding a bang as we did
+earlier:
+
+```ruby
+user.block!
+```
+
+Which would return:
+
+```ruby
+Traceback (most recent call last):
+ 1: from (irb):87
+StateMachines::InvalidTransition (Cannot transition state via :block from :active (Reason(s): Password confirmation doesn't match Password))
+```
+
+We see that a validation error from what feels like a completely separate
+attribute comes back to haunt us when we try to update the user in any way.
+
+In practical terms, we sometimes see this happen with GitLab admin settings --
+validations are sometimes added or changed in a GitLab update, resulting in
+previously saved settings now failing validation. Because you can only update
+a subset of settings at once through the UI, in this case the only way to get
+back to a good state is direct manipulation via Rails console.
+
+### Commonly used Active Record models and how to look up objects
+
+**Get a user by primary email address or username:**
+
+```ruby
+User.find_by(email: 'admin@example.com')
+User.find_by(username: 'root')
+```
+
+**Get a user by primary OR secondary email address:**
+
+```ruby
+User.find_by_any_email('user@example.com')
+```
+
+Note: `find_by_any_email` is a custom method added by GitLab developers rather
+than a Rails-provided default method.
+
+**Get a collection of admin users:**
+
+```ruby
+User.admins
+```
+
+Note: `admins` is a [scope convenience method](https://guides.rubyonrails.org/active_record_querying.html#scopes)
+which does `where(admin: true)` under the hood.
+
+**Get a project by its path:**
+
+```ruby
+Project.find_by_full_path('group/subgroup/project')
+```
+
+Note: `find_by_full_path` is a custom method added by GitLab developers rather
+than a Rails-provided default method.
+
+**Get a project's issue or merge request by its numeric ID:**
+
+```ruby
+project = Project.find_by_full_path('group/subgroup/project')
+project.issues.find_by(iid: 42)
+project.merge_requests.find_by(iid: 42)
+```
+
+Note: `iid` means "internal ID" and is how we keep issue and merge request IDs
+scoped to each GitLab project.
+
+**Get a group by its path:**
+
+```ruby
+Group.find_by_full_path('group/subgroup')
+```
+
+**Get a group's related groups:**
+
+```ruby
+group = Group.find_by_full_path('group/subgroup')
+
+# Get a group's parent group
+group.parent
+
+# Get a group's child groups
+group.children
+```
+
+**Get a group's projects:**
+
+```ruby
+group = Group.find_by_full_path('group/subgroup')
+
+# Get group's immediate child projects
+group.projects
+
+# Get group's child projects, including those in sub-groups
+group.all_projects
+```
+
+**Get CI pipeline or builds:**
+
+```ruby
+Ci::Pipeline.find(4151)
+Ci::Build.find(66124)
+```
+
+Note: The pipeline and job #ID numbers increment globally across your GitLab
+instance, so there's no need to use an internal ID attribute to look them up,
+unlike with issues or merge requests.
+
+**Get the current application settings object:**
+
+```ruby
+ApplicationSetting.current
+```
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index e3f988016fe..4c5bce005d5 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -776,11 +776,16 @@ type Design implements DesignFields & Noteable {
id: ID!
"""
- The URL of the image
+ The URL of the full-sized image
"""
image: String!
"""
+ The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated
+ """
+ imageV432x230: String
+
+ """
The issue the design belongs to
"""
issue: Issue!
@@ -891,11 +896,16 @@ type DesignAtVersion implements DesignFields {
id: ID!
"""
- The URL of the image
+ The URL of the full-sized image
"""
image: String!
"""
+ The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated
+ """
+ imageV432x230: String
+
+ """
The issue the design belongs to
"""
issue: Issue!
@@ -1144,11 +1154,16 @@ interface DesignFields {
id: ID!
"""
- The URL of the image
+ The URL of the full-sized image
"""
image: String!
"""
+ The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated
+ """
+ imageV432x230: String
+
+ """
The issue the design belongs to
"""
issue: Issue!
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 3d941d9cc69..94c0c17d218 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -2247,7 +2247,7 @@
},
{
"name": "image",
- "description": "The URL of the image",
+ "description": "The URL of the full-sized image",
"args": [
],
@@ -2264,6 +2264,20 @@
"deprecationReason": null
},
{
+ "name": "imageV432x230",
+ "description": "The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "issue",
"description": "The issue the design belongs to",
"args": [
@@ -2583,7 +2597,7 @@
},
{
"name": "image",
- "description": "The URL of the image",
+ "description": "The URL of the full-sized image",
"args": [
],
@@ -2600,6 +2614,20 @@
"deprecationReason": null
},
{
+ "name": "imageV432x230",
+ "description": "The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "issue",
"description": "The issue the design belongs to",
"args": [
@@ -3326,7 +3354,7 @@
},
{
"name": "image",
- "description": "The URL of the image",
+ "description": "The URL of the full-sized image",
"args": [
],
@@ -3343,6 +3371,20 @@
"deprecationReason": null
},
{
+ "name": "imageV432x230",
+ "description": "The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "issue",
"description": "The issue the design belongs to",
"args": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 38067b275d5..a5eeab127d0 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -170,7 +170,8 @@ A single design
| `filename` | String! | The filename of the design |
| `fullPath` | String! | The full path to the design file |
| `id` | ID! | The ID of this design |
-| `image` | String! | The URL of the image |
+| `image` | String! | The URL of the full-sized image |
+| `imageV432x230` | String | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated |
| `issue` | Issue! | The issue the design belongs to |
| `notesCount` | Int! | The total count of user-created notes for this design |
| `project` | Project! | The project the design belongs to |
@@ -187,7 +188,8 @@ A design pinned to a specific version. The image field reflects the design as of
| `filename` | String! | The filename of the design |
| `fullPath` | String! | The full path to the design file |
| `id` | ID! | The ID of this design |
-| `image` | String! | The URL of the image |
+| `image` | String! | The URL of the full-sized image |
+| `imageV432x230` | String | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated |
| `issue` | Issue! | The issue the design belongs to |
| `notesCount` | Int! | The total count of user-created notes for this design |
| `project` | Project! | The project the design belongs to |
diff --git a/doc/development/contributing/style_guides.md b/doc/development/contributing/style_guides.md
index 770726f4563..9a0b654f47f 100644
--- a/doc/development/contributing/style_guides.md
+++ b/doc/development/contributing/style_guides.md
@@ -17,7 +17,7 @@ static analysis offenses before committing locally.
In your GitLab source directory run:
```shell
-cd tooling/overcommit && make && cd -
+make -C tooling/overcommit
```
Then before a commit is created, Overcommit will automatically check for
diff --git a/lib/api/helpers/custom_validators.rb b/lib/api/helpers/custom_validators.rb
index 4c15c1d01cd..b4523d7b436 100644
--- a/lib/api/helpers/custom_validators.rb
+++ b/lib/api/helpers/custom_validators.rb
@@ -56,6 +56,35 @@ module API
message: "should be an array, 'None' or 'Any'"
end
end
+
+ class GitRef < Grape::Validations::Base
+ # There are few checks that a Git reference should pass through to be valid reference.
+ # The link contains some rules that have been added to this validator.
+ # https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
+ # We have skipped some checks that are optional and can be skipped for exception.
+ # We also check for control characters, More info on ctrl chars - https://ruby-doc.org/core-2.7.0/Regexp.html#class-Regexp-label-Character+Classes
+ INVALID_CHARS = Regexp.union('..', '\\', '@', '@{', ' ', '~', '^', ':', '*', '?', '[', /[[:cntrl:]]/).freeze
+ GIT_REF_LENGTH = (1..1024).freeze
+
+ def validate_param!(attr_name, params)
+ revision = params[attr_name]
+
+ return unless invalid_character?(revision)
+
+ raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)],
+ message: 'should be a valid reference path'
+ end
+
+ private
+
+ def invalid_character?(revision)
+ revision.nil? ||
+ revision.start_with?('-') ||
+ revision.end_with?('.') ||
+ GIT_REF_LENGTH.exclude?(revision.length) ||
+ INVALID_CHARS.match?(revision)
+ end
+ end
end
end
end
@@ -65,3 +94,4 @@ Grape::Validations.register_validator(:git_sha, ::API::Helpers::CustomValidators
Grape::Validations.register_validator(:absence, ::API::Helpers::CustomValidators::Absence)
Grape::Validations.register_validator(:integer_none_any, ::API::Helpers::CustomValidators::IntegerNoneAny)
Grape::Validations.register_validator(:array_none_any, ::API::Helpers::CustomValidators::ArrayNoneAny)
+Grape::Validations.register_validator(:git_ref, ::API::Helpers::CustomValidators::GitRef)
diff --git a/lib/gitlab/graphql/docs/helper.rb b/lib/gitlab/graphql/docs/helper.rb
index 0dd28b32511..46f253e08e8 100644
--- a/lib/gitlab/graphql/docs/helper.rb
+++ b/lib/gitlab/graphql/docs/helper.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-return if Rails.env.production?
-
module Gitlab
module Graphql
module Docs
diff --git a/lib/gitlab/graphql/docs/renderer.rb b/lib/gitlab/graphql/docs/renderer.rb
index 6abd56c89c6..fe950de7d13 100644
--- a/lib/gitlab/graphql/docs/renderer.rb
+++ b/lib/gitlab/graphql/docs/renderer.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-return if Rails.env.production?
+require 'gitlab/graphql/docs/helper'
module Gitlab
module Graphql
diff --git a/lib/gitlab/import_export/relation_tree_restorer.rb b/lib/gitlab/import_export/relation_tree_restorer.rb
index 466cb03862e..88cf346d8ec 100644
--- a/lib/gitlab/import_export/relation_tree_restorer.rb
+++ b/lib/gitlab/import_export/relation_tree_restorer.rb
@@ -28,7 +28,7 @@ module Gitlab
update_params!
bulk_inserts_enabled = @importable.class == ::Project &&
- Feature.enabled?(:import_bulk_inserts, @importable.group)
+ Feature.enabled?(:import_bulk_inserts, @importable.group, default_enabled: true)
BulkInsertableAssociations.with_bulk_insert(enabled: bulk_inserts_enabled) do
fix_ci_pipelines_not_sorted_on_legacy_project_json!
create_relations!
diff --git a/lib/gitlab/metrics/exporter/base_exporter.rb b/lib/gitlab/metrics/exporter/base_exporter.rb
index 7111835c85a..ff8b8bf2237 100644
--- a/lib/gitlab/metrics/exporter/base_exporter.rb
+++ b/lib/gitlab/metrics/exporter/base_exporter.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+require 'webrick'
+require 'prometheus/client/rack/exporter'
+
module Gitlab
module Metrics
module Exporter
diff --git a/lib/gitlab/set_cache.rb b/lib/gitlab/set_cache.rb
index 2e72855824a..d1151a431bb 100644
--- a/lib/gitlab/set_cache.rb
+++ b/lib/gitlab/set_cache.rb
@@ -14,7 +14,10 @@ module Gitlab
"#{key}:set"
end
+ # Returns the number of keys deleted by Redis
def expire(*keys)
+ return 0 if keys.empty?
+
with do |redis|
keys = keys.map { |key| cache_key(key) }
unlink_or_delete(redis, keys)
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index b9cd4d74914..4457dffd603 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -98,7 +98,7 @@ module Gitlab
projects_imported_from_github: count(Project.where(import_type: 'github')),
projects_with_repositories_enabled: count(ProjectFeature.where('repository_access_level > ?', ProjectFeature::DISABLED)),
projects_with_error_tracking_enabled: count(::ErrorTracking::ProjectErrorTrackingSetting.where(enabled: true)),
- projects_with_alerts_service_enabled: count(AlertsService.active, batch: false),
+ projects_with_alerts_service_enabled: count(AlertsService.active),
protected_branches: count(ProtectedBranch),
releases: count(Release),
remote_mirrors: count(RemoteMirror),
diff --git a/lib/tasks/gitlab/graphql.rake b/lib/tasks/gitlab/graphql.rake
index 5a583183924..4e7d462e850 100644
--- a/lib/tasks/gitlab/graphql.rake
+++ b/lib/tasks/gitlab/graphql.rake
@@ -3,6 +3,7 @@
return if Rails.env.production?
require 'graphql/rake_task'
+require 'gitlab/graphql/docs/renderer'
namespace :gitlab do
OUTPUT_DIR = Rails.root.join("doc/api/graphql/reference")
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 16a07a52d62..97cbe7faeb4 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2247,6 +2247,9 @@ msgstr ""
msgid "Archive project"
msgstr ""
+msgid "Archived"
+msgstr ""
+
msgid "Archived project! Repository and other project resources are read only"
msgstr ""
@@ -8776,6 +8779,9 @@ msgstr ""
msgid "Filter"
msgstr ""
+msgid "Filter by %{issuable_type} that are currently archived."
+msgstr ""
+
msgid "Filter by %{issuable_type} that are currently closed."
msgstr ""
@@ -13112,6 +13118,9 @@ msgstr ""
msgid "New release"
msgstr ""
+msgid "New requirement"
+msgstr ""
+
msgid "New runners registration token has been generated!"
msgstr ""
diff --git a/package.json b/package.json
index c699da02441..11e5da73c23 100644
--- a/package.json
+++ b/package.json
@@ -146,7 +146,7 @@
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.8.3",
- "@gitlab/eslint-config": "^3.0.0",
+ "@gitlab/eslint-plugin": "^2.0.0",
"@vue/test-utils": "^1.0.0-beta.30",
"axios-mock-adapter": "^1.15.0",
"babel-jest": "^24.1.0",
@@ -215,4 +215,4 @@
"node": ">=10.13.0",
"yarn": "^1.10.0"
}
-} \ No newline at end of file
+}
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
index 9c99f3ee377..2cb6a76b6b3 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
@@ -17,7 +17,7 @@ module QA
end
end
- context 'when using attachments in comments', :object_storage, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/issues/205408', type: :flaky } do
+ context 'when using attachments in comments', :object_storage, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/issues/205408', type: :bug } do
let(:gif_file_name) { 'banana_sample.gif' }
let(:file_to_attach) do
File.absolute_path(File.join('spec', 'fixtures', gif_file_name))
diff --git a/scripts/static-analysis b/scripts/static-analysis
index ede29b85b8d..c07923cd837 100755
--- a/scripts/static-analysis
+++ b/scripts/static-analysis
@@ -1,7 +1,6 @@
#!/usr/bin/env ruby
# We don't have auto-loading here
-require_relative '../lib/gitlab'
require_relative '../lib/gitlab/popen'
require_relative '../lib/gitlab/popen/runner'
diff --git a/spec/factories/usage_data.rb b/spec/factories/usage_data.rb
new file mode 100644
index 00000000000..9560e076ae4
--- /dev/null
+++ b/spec/factories/usage_data.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :usage_data, class: 'Gitlab::UsageData' do
+ skip_create # non-model factories (i.e. without #save)
+
+ initialize_with do
+ projects = create_list(:project, 4)
+ create(:board, project: projects[0])
+ create(:jira_service, project: projects[0])
+ create(:jira_service, :without_properties_callback, project: projects[1])
+ create(:jira_service, :jira_cloud_service, project: projects[2])
+ create(:jira_service, :without_properties_callback, project: projects[3],
+ properties: { url: 'https://mysite.atlassian.net' })
+ create(:prometheus_service, project: projects[1])
+ create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true)
+ create(:service, project: projects[1], type: 'SlackService', active: true)
+ create(:service, project: projects[2], type: 'SlackService', active: true)
+ create(:service, project: projects[2], type: 'MattermostService', active: false)
+ create(:service, :template, type: 'MattermostService', active: true)
+ create(:service, project: projects[2], type: 'CustomIssueTrackerService', active: true)
+ create(:project_error_tracking_setting, project: projects[0])
+ create(:project_error_tracking_setting, project: projects[1], enabled: false)
+ create(:alerts_service, project: projects[0])
+ create(:alerts_service, :inactive, project: projects[1])
+ create_list(:issue, 2, project: projects[0], author: User.alert_bot)
+ create_list(:issue, 2, project: projects[1], author: User.alert_bot)
+ create_list(:issue, 4, project: projects[0])
+ create(:zoom_meeting, project: projects[0], issue: projects[0].issues[0], issue_status: :added)
+ create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[1], issue_status: :removed)
+ create(:zoom_meeting, project: projects[0], issue: projects[0].issues[2], issue_status: :added)
+ create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[2], issue_status: :removed)
+ create(:sentry_issue, issue: projects[0].issues[0])
+
+ # Enabled clusters
+ gcp_cluster = create(:cluster_provider_gcp, :created).cluster
+ create(:cluster_provider_aws, :created)
+ create(:cluster_platform_kubernetes)
+ create(:cluster, :group)
+
+ # Disabled clusters
+ create(:cluster, :disabled)
+ create(:cluster, :group, :disabled)
+ create(:cluster, :group, :disabled)
+
+ # Applications
+ create(:clusters_applications_helm, :installed, cluster: gcp_cluster)
+ create(:clusters_applications_ingress, :installed, cluster: gcp_cluster)
+ create(:clusters_applications_cert_manager, :installed, cluster: gcp_cluster)
+ create(:clusters_applications_prometheus, :installed, cluster: gcp_cluster)
+ create(:clusters_applications_crossplane, :installed, cluster: gcp_cluster)
+ create(:clusters_applications_runner, :installed, cluster: gcp_cluster)
+ create(:clusters_applications_knative, :installed, cluster: gcp_cluster)
+ create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster)
+ create(:clusters_applications_jupyter, :installed, cluster: gcp_cluster)
+
+ create(:grafana_integration, project: projects[0], enabled: true)
+ create(:grafana_integration, project: projects[1], enabled: true)
+ create(:grafana_integration, project: projects[2], enabled: false)
+
+ ProjectFeature.first.update_attribute('repository_access_level', 0)
+ end
+ end
+end
diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb
index 1a8af335244..366c201bfe3 100644
--- a/spec/fast_spec_helper.rb
+++ b/spec/fast_spec_helper.rb
@@ -11,6 +11,9 @@ require_relative '../config/settings'
require_relative 'support/rspec'
require 'active_support/all'
-ActiveSupport::Dependencies.autoload_paths << 'lib'
-ActiveSupport::Dependencies.autoload_paths << 'ee/lib'
+unless ActiveSupport::Dependencies.autoload_paths.frozen?
+ ActiveSupport::Dependencies.autoload_paths << 'lib'
+ ActiveSupport::Dependencies.autoload_paths << 'ee/lib'
+end
+
ActiveSupport::XmlMini.backend = 'Nokogiri'
diff --git a/spec/frontend/snippets/components/snippet_header_spec.js b/spec/frontend/snippets/components/snippet_header_spec.js
index 5cf20119189..c74f7615538 100644
--- a/spec/frontend/snippets/components/snippet_header_spec.js
+++ b/spec/frontend/snippets/components/snippet_header_spec.js
@@ -32,7 +32,7 @@ describe('Snippet header component', () => {
const errorMsg = 'Foo bar';
const err = { message: errorMsg };
- const resolveMutate = jest.fn(() => Promise.resolve());
+ const resolveMutate = jest.fn(() => Promise.resolve({ data: {} }));
const rejectMutation = jest.fn(() => Promise.reject(err));
const mutationTypes = {
diff --git a/spec/lib/api/helpers/custom_validators_spec.rb b/spec/lib/api/helpers/custom_validators_spec.rb
index 66b86d0a055..a4f2cd3452c 100644
--- a/spec/lib/api/helpers/custom_validators_spec.rb
+++ b/spec/lib/api/helpers/custom_validators_spec.rb
@@ -61,6 +61,47 @@ describe API::Helpers::CustomValidators do
end
end
+ describe API::Helpers::CustomValidators::GitRef do
+ subject do
+ described_class.new(['test'], {}, false, scope.new)
+ end
+
+ context 'valid revision param' do
+ it 'does not raise a validation error' do
+ expect_no_validation_error('test' => '4e963fe')
+ expect_no_validation_error('test' => 'foo/bar/baz')
+ expect_no_validation_error('test' => "heads/fu\303\237")
+ expect_no_validation_error('test' => 'a' * 1024)
+ end
+ end
+
+ context "revision param contains invalid chars" do
+ it 'raises a validation error' do
+ expect_validation_error('test' => '-4e963fe')
+ expect_validation_error('test' => '4e963fe..ed4ef')
+ expect_validation_error('test' => '4e96\3fe')
+ expect_validation_error('test' => '4e96@3fe')
+ expect_validation_error('test' => '4e9@{63fe')
+ expect_validation_error('test' => '4e963 fe')
+ expect_validation_error('test' => '4e96~3fe')
+ expect_validation_error('test' => '^4e963fe')
+ expect_validation_error('test' => '4:e963fe')
+ expect_validation_error('test' => '4e963fe.')
+ expect_validation_error('test' => 'heads/foo..bar')
+ expect_validation_error('test' => 'foo/bar/.')
+ expect_validation_error('test' => 'heads/v@{ation')
+ expect_validation_error('test' => 'refs/heads/foo.')
+ expect_validation_error('test' => 'heads/foo\bar')
+ expect_validation_error('test' => 'heads/f[/bar')
+ expect_validation_error('test' => "heads/foo\t")
+ expect_validation_error('test' => "heads/foo\177")
+ expect_validation_error('test' => "#{'a' * 1025}")
+ expect_validation_error('test' => nil)
+ expect_validation_error('test' => '')
+ end
+ end
+ end
+
describe API::Helpers::CustomValidators::FilePath do
subject do
described_class.new(['test'], {}, false, scope.new)
diff --git a/spec/lib/gitlab/fogbugz_import/importer_spec.rb b/spec/lib/gitlab/fogbugz_import/importer_spec.rb
index 9e67047eeda..c78659ff49b 100644
--- a/spec/lib/gitlab/fogbugz_import/importer_spec.rb
+++ b/spec/lib/gitlab/fogbugz_import/importer_spec.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
+require 'fogbugz'
describe Gitlab::FogbugzImport::Importer do
let(:project) { create(:project_empty_repo) }
diff --git a/spec/lib/gitlab/graphql/docs/renderer_spec.rb b/spec/lib/gitlab/graphql/docs/renderer_spec.rb
index 5ba70bb8f0a..c94fe059b92 100644
--- a/spec/lib/gitlab/graphql/docs/renderer_spec.rb
+++ b/spec/lib/gitlab/graphql/docs/renderer_spec.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
+require 'gitlab/graphql/docs/renderer'
describe Gitlab::Graphql::Docs::Renderer do
describe '#contents' do
diff --git a/spec/lib/gitlab/repository_set_cache_spec.rb b/spec/lib/gitlab/repository_set_cache_spec.rb
index c5d95e53120..6221d6fb45f 100644
--- a/spec/lib/gitlab/repository_set_cache_spec.rb
+++ b/spec/lib/gitlab/repository_set_cache_spec.rb
@@ -88,6 +88,12 @@ describe Gitlab::RepositorySetCache, :clean_gitlab_redis_cache do
end
end
+ context 'no keys' do
+ let(:keys) { [] }
+
+ it { is_expected.to eq(0) }
+ end
+
context "unlink isn't supported" do
before do
allow_any_instance_of(Redis).to receive(:unlink) { raise ::Redis::CommandError }
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 21117f11f63..fb60ac955de 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -2,299 +2,127 @@
require 'spec_helper'
-describe Gitlab::UsageData do
- let(:projects) { create_list(:project, 4) }
- let!(:board) { create(:board, project: projects[0]) }
+describe Gitlab::UsageData, :aggregate_failures do
+ include UsageDataHelpers
before do
allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
end
- [true, false].each do |usage_ping_batch_counter_on|
- describe "when the feature flag usage_ping_batch_counter is set to #{usage_ping_batch_counter_on}" do
+
+ shared_examples "usage data execution" do
+ describe '#data' do
+ let!(:ud) { build(:usage_data) }
+
before do
- stub_feature_flags(usage_ping_batch_counter: usage_ping_batch_counter_on)
+ allow(Gitlab::GrafanaEmbedUsageData).to receive(:issue_count).and_return(2)
end
- describe '#data' do
- before do
- create(:jira_service, project: projects[0])
- create(:jira_service, :without_properties_callback, project: projects[1])
- create(:jira_service, :jira_cloud_service, project: projects[2])
- create(:jira_service, :without_properties_callback, project: projects[3],
- properties: { url: 'https://mysite.atlassian.net' })
- create(:prometheus_service, project: projects[1])
- create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true)
- create(:service, project: projects[1], type: 'SlackService', active: true)
- create(:service, project: projects[2], type: 'SlackService', active: true)
- create(:service, project: projects[2], type: 'MattermostService', active: false)
- create(:service, :template, type: 'MattermostService', active: true)
- create(:service, project: projects[2], type: 'CustomIssueTrackerService', active: true)
- create(:project_error_tracking_setting, project: projects[0])
- create(:project_error_tracking_setting, project: projects[1], enabled: false)
- create(:alerts_service, project: projects[0])
- create(:alerts_service, :inactive, project: projects[1])
- create_list(:issue, 2, project: projects[0], author: User.alert_bot)
- create_list(:issue, 2, project: projects[1], author: User.alert_bot)
- create_list(:issue, 4, project: projects[0])
- create(:zoom_meeting, project: projects[0], issue: projects[0].issues[0], issue_status: :added)
- create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[1], issue_status: :removed)
- create(:zoom_meeting, project: projects[0], issue: projects[0].issues[2], issue_status: :added)
- create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[2], issue_status: :removed)
- create(:sentry_issue, issue: projects[0].issues[0])
-
- # Enabled clusters
- gcp_cluster = create(:cluster_provider_gcp, :created).cluster
- create(:cluster_provider_aws, :created)
- create(:cluster_platform_kubernetes)
- create(:cluster, :group)
-
- # Disabled clusters
- create(:cluster, :disabled)
- create(:cluster, :group, :disabled)
- create(:cluster, :group, :disabled)
-
- # Applications
- create(:clusters_applications_helm, :installed, cluster: gcp_cluster)
- create(:clusters_applications_ingress, :installed, cluster: gcp_cluster)
- create(:clusters_applications_cert_manager, :installed, cluster: gcp_cluster)
- create(:clusters_applications_prometheus, :installed, cluster: gcp_cluster)
- create(:clusters_applications_crossplane, :installed, cluster: gcp_cluster)
- create(:clusters_applications_runner, :installed, cluster: gcp_cluster)
- create(:clusters_applications_knative, :installed, cluster: gcp_cluster)
- create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster)
- create(:clusters_applications_jupyter, :installed, cluster: gcp_cluster)
-
- create(:grafana_integration, project: projects[0], enabled: true)
- create(:grafana_integration, project: projects[1], enabled: true)
- create(:grafana_integration, project: projects[2], enabled: false)
-
- allow(Gitlab::GrafanaEmbedUsageData).to receive(:issue_count).and_return(2)
-
- ProjectFeature.first.update_attribute('repository_access_level', 0)
- end
+ subject { described_class.data }
- subject { described_class.data }
-
- it 'gathers usage data', :aggregate_failures do
- expect(subject.keys).to include(*%i(
- active_user_count
- counts
- recorded_at
- edition
- version
- installation_type
- uuid
- hostname
- mattermost_enabled
- signup_enabled
- ldap_enabled
- gravatar_enabled
- omniauth_enabled
- reply_by_email_enabled
- container_registry_enabled
- dependency_proxy_enabled
- gitlab_shared_runners_enabled
- gitlab_pages
- git
- gitaly
- database
- avg_cycle_analytics
- influxdb_metrics_enabled
- prometheus_metrics_enabled
- web_ide_clientside_preview_enabled
- ingress_modsecurity_enabled
- ))
- end
+ it 'gathers usage data' do
+ expect(subject.keys).to include(*UsageDataHelpers::USAGE_DATA_KEYS)
+ end
- it 'gathers usage counts' do
- smau_keys = %i(
- snippet_create
- snippet_update
- snippet_comment
- merge_request_comment
- merge_request_create
- commit_comment
- wiki_pages_create
- wiki_pages_update
- wiki_pages_delete
- web_ide_views
- web_ide_commits
- web_ide_merge_requests
- web_ide_previews
- navbar_searches
- cycle_analytics_views
- productivity_analytics_views
- source_code_pushes
- )
+ it 'gathers usage counts' do
+ count_data = subject[:counts]
- expected_keys = %i(
- assignee_lists
- boards
- ci_builds
- ci_internal_pipelines
- ci_external_pipelines
- ci_pipeline_config_auto_devops
- ci_pipeline_config_repository
- ci_runners
- ci_triggers
- ci_pipeline_schedules
- auto_devops_enabled
- auto_devops_disabled
- deploy_keys
- deployments
- successful_deployments
- failed_deployments
- environments
- clusters
- clusters_enabled
- project_clusters_enabled
- group_clusters_enabled
- clusters_disabled
- project_clusters_disabled
- group_clusters_disabled
- clusters_platforms_eks
- clusters_platforms_gke
- clusters_platforms_user
- clusters_applications_helm
- clusters_applications_ingress
- clusters_applications_cert_managers
- clusters_applications_prometheus
- clusters_applications_crossplane
- clusters_applications_runner
- clusters_applications_knative
- clusters_applications_elastic_stack
- clusters_applications_jupyter
- in_review_folder
- grafana_integrated_projects
- groups
- issues
- issues_created_from_gitlab_error_tracking_ui
- issues_with_associated_zoom_link
- issues_using_zoom_quick_actions
- issues_with_embedded_grafana_charts_approx
- incident_issues
- keys
- label_lists
- labels
- lfs_objects
- merge_requests
- milestone_lists
- milestones
- notes
- pool_repositories
- projects
- projects_imported_from_github
- projects_asana_active
- projects_jira_active
- projects_jira_server_active
- projects_jira_cloud_active
- projects_slack_notifications_active
- projects_slack_slash_active
- projects_slack_active
- projects_slack_slash_commands_active
- projects_custom_issue_tracker_active
- projects_mattermost_active
- projects_prometheus_active
- projects_with_repositories_enabled
- projects_with_error_tracking_enabled
- projects_with_alerts_service_enabled
- pages_domains
- protected_branches
- releases
- remote_mirrors
- snippets
- suggestions
- todos
- uploads
- web_hooks
- ).push(*smau_keys)
-
- count_data = subject[:counts]
-
- expect(count_data[:boards]).to eq(1)
- expect(count_data[:projects]).to eq(4)
- expect(count_data.values_at(*smau_keys)).to all(be_an(Integer))
- expect(count_data.keys).to include(*expected_keys)
- expect(expected_keys - count_data.keys).to be_empty
- end
+ expect(count_data[:boards]).to eq(1)
+ expect(count_data[:projects]).to eq(4)
+ expect(count_data.values_at(*UsageDataHelpers::SMAU_KEYS)).to all(be_an(Integer))
+ expect(count_data.keys).to include(*UsageDataHelpers::COUNTS_KEYS)
+ expect(UsageDataHelpers::COUNTS_KEYS - count_data.keys).to be_empty
+ end
- it 'gathers projects data correctly', :aggregate_failures do
- count_data = subject[:counts]
-
- expect(count_data[:projects]).to eq(4)
- expect(count_data[:projects_asana_active]).to eq(0)
- expect(count_data[:projects_prometheus_active]).to eq(1)
- expect(count_data[:projects_jira_active]).to eq(4)
- expect(count_data[:projects_jira_server_active]).to eq(2)
- expect(count_data[:projects_jira_cloud_active]).to eq(2)
- expect(count_data[:projects_slack_notifications_active]).to eq(2)
- expect(count_data[:projects_slack_slash_active]).to eq(1)
- expect(count_data[:projects_slack_active]).to eq(2)
- expect(count_data[:projects_slack_slash_commands_active]).to eq(1)
- expect(count_data[:projects_custom_issue_tracker_active]).to eq(1)
- expect(count_data[:projects_mattermost_active]).to eq(0)
- expect(count_data[:projects_with_repositories_enabled]).to eq(3)
- expect(count_data[:projects_with_error_tracking_enabled]).to eq(1)
- expect(count_data[:projects_with_alerts_service_enabled]).to eq(1)
- expect(count_data[:issues_created_from_gitlab_error_tracking_ui]).to eq(1)
- expect(count_data[:issues_with_associated_zoom_link]).to eq(2)
- expect(count_data[:issues_using_zoom_quick_actions]).to eq(3)
- expect(count_data[:issues_with_embedded_grafana_charts_approx]).to eq(2)
- expect(count_data[:incident_issues]).to eq(4)
-
- expect(count_data[:clusters_enabled]).to eq(4)
- expect(count_data[:project_clusters_enabled]).to eq(3)
- expect(count_data[:group_clusters_enabled]).to eq(1)
- expect(count_data[:clusters_disabled]).to eq(3)
- expect(count_data[:project_clusters_disabled]).to eq(1)
- expect(count_data[:group_clusters_disabled]).to eq(2)
- expect(count_data[:group_clusters_enabled]).to eq(1)
- expect(count_data[:clusters_platforms_eks]).to eq(1)
- expect(count_data[:clusters_platforms_gke]).to eq(1)
- expect(count_data[:clusters_platforms_user]).to eq(1)
- expect(count_data[:clusters_applications_helm]).to eq(1)
- expect(count_data[:clusters_applications_ingress]).to eq(1)
- expect(count_data[:clusters_applications_cert_managers]).to eq(1)
- expect(count_data[:clusters_applications_crossplane]).to eq(1)
- expect(count_data[:clusters_applications_prometheus]).to eq(1)
- expect(count_data[:clusters_applications_runner]).to eq(1)
- expect(count_data[:clusters_applications_knative]).to eq(1)
- expect(count_data[:clusters_applications_elastic_stack]).to eq(1)
- expect(count_data[:grafana_integrated_projects]).to eq(2)
- expect(count_data[:clusters_applications_jupyter]).to eq(1)
- end
+ it 'gathers projects data correctly' do
+ count_data = subject[:counts]
+
+ expect(count_data[:projects]).to eq(4)
+ expect(count_data[:projects_asana_active]).to eq(0)
+ expect(count_data[:projects_prometheus_active]).to eq(1)
+ expect(count_data[:projects_jira_active]).to eq(4)
+ expect(count_data[:projects_jira_server_active]).to eq(2)
+ expect(count_data[:projects_jira_cloud_active]).to eq(2)
+ expect(count_data[:projects_slack_notifications_active]).to eq(2)
+ expect(count_data[:projects_slack_slash_active]).to eq(1)
+ expect(count_data[:projects_slack_active]).to eq(2)
+ expect(count_data[:projects_slack_slash_commands_active]).to eq(1)
+ expect(count_data[:projects_custom_issue_tracker_active]).to eq(1)
+ expect(count_data[:projects_mattermost_active]).to eq(0)
+ expect(count_data[:projects_with_repositories_enabled]).to eq(3)
+ expect(count_data[:projects_with_error_tracking_enabled]).to eq(1)
+ expect(count_data[:projects_with_alerts_service_enabled]).to eq(1)
+ expect(count_data[:issues_created_from_gitlab_error_tracking_ui]).to eq(1)
+ expect(count_data[:issues_with_associated_zoom_link]).to eq(2)
+ expect(count_data[:issues_using_zoom_quick_actions]).to eq(3)
+ expect(count_data[:issues_with_embedded_grafana_charts_approx]).to eq(2)
+ expect(count_data[:incident_issues]).to eq(4)
+
+ expect(count_data[:clusters_enabled]).to eq(4)
+ expect(count_data[:project_clusters_enabled]).to eq(3)
+ expect(count_data[:group_clusters_enabled]).to eq(1)
+ expect(count_data[:clusters_disabled]).to eq(3)
+ expect(count_data[:project_clusters_disabled]).to eq(1)
+ expect(count_data[:group_clusters_disabled]).to eq(2)
+ expect(count_data[:group_clusters_enabled]).to eq(1)
+ expect(count_data[:clusters_platforms_eks]).to eq(1)
+ expect(count_data[:clusters_platforms_gke]).to eq(1)
+ expect(count_data[:clusters_platforms_user]).to eq(1)
+ expect(count_data[:clusters_applications_helm]).to eq(1)
+ expect(count_data[:clusters_applications_ingress]).to eq(1)
+ expect(count_data[:clusters_applications_cert_managers]).to eq(1)
+ expect(count_data[:clusters_applications_crossplane]).to eq(1)
+ expect(count_data[:clusters_applications_prometheus]).to eq(1)
+ expect(count_data[:clusters_applications_runner]).to eq(1)
+ expect(count_data[:clusters_applications_knative]).to eq(1)
+ expect(count_data[:clusters_applications_elastic_stack]).to eq(1)
+ expect(count_data[:grafana_integrated_projects]).to eq(2)
+ expect(count_data[:clusters_applications_jupyter]).to eq(1)
+ end
- it 'works when queries time out' do
- allow_any_instance_of(ActiveRecord::Relation)
- .to receive(:count).and_raise(ActiveRecord::StatementInvalid.new(''))
+ it 'works when queries time out' do
+ allow_any_instance_of(ActiveRecord::Relation)
+ .to receive(:count).and_raise(ActiveRecord::StatementInvalid.new(''))
- expect { subject }.not_to raise_error
- end
+ expect { subject }.not_to raise_error
end
+ end
- describe '#usage_data_counters' do
- subject { described_class.usage_data_counters }
+ describe '#usage_data_counters' do
+ subject { described_class.usage_data_counters }
- it { is_expected.to all(respond_to :totals) }
+ it { is_expected.to all(respond_to :totals) }
- describe 'the results of calling #totals on all objects in the array' do
- subject { described_class.usage_data_counters.map(&:totals) }
+ describe 'the results of calling #totals on all objects in the array' do
+ subject { described_class.usage_data_counters.map(&:totals) }
- it { is_expected.to all(be_a Hash) }
- it { is_expected.to all(have_attributes(keys: all(be_a Symbol), values: all(be_a Integer))) }
- end
+ it { is_expected.to all(be_a Hash) }
+ it { is_expected.to all(have_attributes(keys: all(be_a Symbol), values: all(be_a Integer))) }
+ end
- it 'does not have any conflicts' do
- all_keys = subject.flat_map { |counter| counter.totals.keys }
+ it 'does not have any conflicts' do
+ all_keys = subject.flat_map { |counter| counter.totals.keys }
- expect(all_keys.size).to eq all_keys.to_set.size
- end
+ expect(all_keys.size).to eq all_keys.to_set.size
end
+ end
+ describe '#license_usage_data' do
+ subject { described_class.license_usage_data }
+
+ it 'gathers license data' do
+ expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid)
+ expect(subject[:version]).to eq(Gitlab::VERSION)
+ expect(subject[:installation_type]).to eq('gitlab-development-kit')
+ expect(subject[:active_user_count]).to eq(User.active.size)
+ expect(subject[:recorded_at]).to be_a(Time)
+ end
+ end
+
+ context 'when not relying on database records' do
describe '#features_usage_data_ce' do
subject { described_class.features_usage_data_ce }
- it 'gathers feature usage data', :aggregate_failures do
+ it 'gathers feature usage data' do
expect(subject[:mattermost_enabled]).to eq(Gitlab.config.mattermost.enabled)
expect(subject[:signup_enabled]).to eq(Gitlab::CurrentSettings.allow_signup?)
expect(subject[:ldap_enabled]).to eq(Gitlab.config.ldap.enabled)
@@ -311,7 +139,7 @@ describe Gitlab::UsageData do
describe '#components_usage_data' do
subject { described_class.components_usage_data }
- it 'gathers components usage data', :aggregate_failures do
+ it 'gathers components usage data' do
expect(subject[:gitlab_pages][:enabled]).to eq(Gitlab.config.pages.enabled)
expect(subject[:gitlab_pages][:version]).to eq(Gitlab::Pages::VERSION)
expect(subject[:git][:version]).to eq(Gitlab::Git.version)
@@ -360,18 +188,6 @@ describe Gitlab::UsageData do
end
end
- describe '#license_usage_data' do
- subject { described_class.license_usage_data }
-
- it 'gathers license data', :aggregate_failures do
- expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid)
- expect(subject[:version]).to eq(Gitlab::VERSION)
- expect(subject[:installation_type]).to eq('gitlab-development-kit')
- expect(subject[:active_user_count]).to eq(User.active.count)
- expect(subject[:recorded_at]).to be_a(Time)
- end
- end
-
describe '#count' do
let(:relation) { double(:relation) }
@@ -405,4 +221,20 @@ describe Gitlab::UsageData do
end
end
end
+
+ context 'when usage usage_ping_batch_counter is true' do
+ before do
+ stub_feature_flags(usage_ping_batch_counter: true)
+ end
+
+ it_behaves_like 'usage data execution'
+ end
+
+ context 'when usage usage_ping_batch_counter is false' do
+ before do
+ stub_feature_flags(usage_ping_batch_counter: false)
+ end
+
+ it_behaves_like 'usage data execution'
+ end
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 66b298bb36f..6f12d72c723 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -313,19 +313,16 @@ describe Issue do
end
describe '#moved?' do
- let(:issue) { create(:issue) }
-
- subject { issue.moved? }
+ context 'when issue has not been moved' do
+ subject { build_stubbed(:issue) }
- context 'issue not moved' do
- it { is_expected.to eq false }
+ it { is_expected.not_to be_moved }
end
- context 'issue already moved' do
- let(:moved_to_issue) { create(:issue) }
- let(:issue) { create(:issue, moved_to: moved_to_issue) }
+ context 'when issue has already been moved' do
+ subject { build_stubbed(:issue, moved_to: build_stubbed(:issue)) }
- it { is_expected.to eq true }
+ it { is_expected.to be_moved }
end
end
diff --git a/spec/services/service_response_spec.rb b/spec/services/service_response_spec.rb
index a6567f52c6f..d477a99b609 100644
--- a/spec/services/service_response_spec.rb
+++ b/spec/services/service_response_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
-
-ActiveSupport::Dependencies.autoload_paths << 'app/services'
+require_relative '../../app/services/service_response'
describe ServiceResponse do
describe '.success' do
diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb
new file mode 100644
index 00000000000..0fa1c40bd67
--- /dev/null
+++ b/spec/support/helpers/usage_data_helpers.rb
@@ -0,0 +1,134 @@
+# frozen_string_literal: true
+
+module UsageDataHelpers
+ SMAU_KEYS = %i(
+ snippet_create
+ snippet_update
+ snippet_comment
+ merge_request_comment
+ merge_request_create
+ commit_comment
+ wiki_pages_create
+ wiki_pages_update
+ wiki_pages_delete
+ web_ide_views
+ web_ide_commits
+ web_ide_merge_requests
+ web_ide_previews
+ navbar_searches
+ cycle_analytics_views
+ productivity_analytics_views
+ source_code_pushes
+ ).freeze
+
+ COUNTS_KEYS = %i(
+ assignee_lists
+ boards
+ ci_builds
+ ci_internal_pipelines
+ ci_external_pipelines
+ ci_pipeline_config_auto_devops
+ ci_pipeline_config_repository
+ ci_runners
+ ci_triggers
+ ci_pipeline_schedules
+ auto_devops_enabled
+ auto_devops_disabled
+ deploy_keys
+ deployments
+ successful_deployments
+ failed_deployments
+ environments
+ clusters
+ clusters_enabled
+ project_clusters_enabled
+ group_clusters_enabled
+ clusters_disabled
+ project_clusters_disabled
+ group_clusters_disabled
+ clusters_platforms_eks
+ clusters_platforms_gke
+ clusters_platforms_user
+ clusters_applications_helm
+ clusters_applications_ingress
+ clusters_applications_cert_managers
+ clusters_applications_prometheus
+ clusters_applications_crossplane
+ clusters_applications_runner
+ clusters_applications_knative
+ clusters_applications_elastic_stack
+ clusters_applications_jupyter
+ in_review_folder
+ grafana_integrated_projects
+ groups
+ issues
+ issues_created_from_gitlab_error_tracking_ui
+ issues_with_associated_zoom_link
+ issues_using_zoom_quick_actions
+ issues_with_embedded_grafana_charts_approx
+ incident_issues
+ keys
+ label_lists
+ labels
+ lfs_objects
+ merge_requests
+ milestone_lists
+ milestones
+ notes
+ pool_repositories
+ projects
+ projects_imported_from_github
+ projects_asana_active
+ projects_jira_active
+ projects_jira_server_active
+ projects_jira_cloud_active
+ projects_slack_notifications_active
+ projects_slack_slash_active
+ projects_slack_active
+ projects_slack_slash_commands_active
+ projects_custom_issue_tracker_active
+ projects_mattermost_active
+ projects_prometheus_active
+ projects_with_repositories_enabled
+ projects_with_error_tracking_enabled
+ projects_with_alerts_service_enabled
+ pages_domains
+ protected_branches
+ releases
+ remote_mirrors
+ snippets
+ suggestions
+ todos
+ uploads
+ web_hooks
+ ).push(*SMAU_KEYS)
+
+ USAGE_DATA_KEYS = %i(
+ active_user_count
+ counts
+ recorded_at
+ edition
+ version
+ installation_type
+ uuid
+ hostname
+ mattermost_enabled
+ signup_enabled
+ ldap_enabled
+ gravatar_enabled
+ omniauth_enabled
+ reply_by_email_enabled
+ container_registry_enabled
+ dependency_proxy_enabled
+ gitlab_shared_runners_enabled
+ gitlab_pages
+ git
+ gitaly
+ database
+ avg_cycle_analytics
+ influxdb_metrics_enabled
+ prometheus_metrics_enabled
+ web_ide_clientside_preview_enabled
+ ingress_modsecurity_enabled
+ ).freeze
+end
diff --git a/tooling/overcommit/gems.rb b/tooling/overcommit/Gemfile
index c563a23275a..5525662e43e 100644
--- a/tooling/overcommit/gems.rb
+++ b/tooling/overcommit/Gemfile
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# Make sure to run `bundle install --gemfile=tooling/overcommit/gems.rb` when you update this file.
+# Make sure to run `make` (in this directory) when you update this file.
source 'https://rubygems.org'
gem 'overcommit'
diff --git a/tooling/overcommit/gems.locked b/tooling/overcommit/Gemfile.lock
index 15b80426c03..15b80426c03 100644
--- a/tooling/overcommit/gems.locked
+++ b/tooling/overcommit/Gemfile.lock
diff --git a/yarn.lock b/yarn.lock
index a443fb11287..7342879af10 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -766,13 +766,11 @@
resolved "https://registry.yarnpkg.com/@gitlab/at.js/-/at.js-1.5.5.tgz#5f6bfe6baaef360daa9b038fa78798d7a6a916b4"
integrity sha512-282Dn3SPVsUHVDhMsXgfnv+Rzog0uxecjttxGRQvxh25es1+xvkGQFsvJfkSKJ3X1kHVkSjKf+Tt5Rra+Jhp9g==
-"@gitlab/eslint-config@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@gitlab/eslint-config/-/eslint-config-3.0.0.tgz#9a93662ffefb7792d5d0d96d876c316f2c393315"
- integrity sha512-wlMpcl4q4hTnvmdPB9yuD+ZIi39P2ZCSfp3LQYSvbSXCF3POfyjRRe4tK7cerKrawjmJmII8YvNnIg2Ip9eKnQ==
+"@gitlab/eslint-plugin@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-2.0.0.tgz#4eedd16cf95cf82dc359c1b220d4f5a08361df9c"
+ integrity sha512-ctmsGnCuokhfh/5goLdz3NdBIUpwTMkx/17QxxutxkWW7yOGMPIY8Na+WhjnUSdst8Wjwzexc+snbh5NMs8H/A==
dependencies:
- "@gitlab/eslint-plugin-i18n" "^1.1.0"
- "@gitlab/eslint-plugin-vue-i18n" "^2.0.0"
babel-eslint "^10.0.3"
eslint-config-airbnb-base "^14.0.0"
eslint-config-prettier "^6.10.0"
@@ -780,20 +778,7 @@
eslint-plugin-filenames "^1.3.2"
eslint-plugin-import "^2.20.1"
eslint-plugin-promise "^4.2.1"
- eslint-plugin-vue "^6.0.1"
-
-"@gitlab/eslint-plugin-i18n@^1.1.0":
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin-i18n/-/eslint-plugin-i18n-1.1.0.tgz#e494d599e644ce3a094ea85f87dbbda41a924c5e"
- integrity sha512-Cwm7sLtQnUDqvxE9Ez8UMslyosPCpMVLxBnFb+2n6QcBZmXRao4aNSVRkmlsDZYgYegWhOGn3Qq3MLy4BSqauQ==
- dependencies:
- requireindex "~1.1.0"
-
-"@gitlab/eslint-plugin-vue-i18n@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin-vue-i18n/-/eslint-plugin-vue-i18n-2.0.0.tgz#5a01912d9d5a7524539d678f09cac6fa57d6d838"
- integrity sha512-z72ysu5AgjL/oWPckvNrMWUnkcFJhtZT0oqeSgN97NyktrvYMMpAOjSSeu2Nv+HLTD5vk9w/fG3zskp/qgT+lw==
- dependencies:
+ eslint-plugin-vue "^6.2.1"
vue-eslint-parser "^7.0.0"
"@gitlab/svgs@^1.113.0":
@@ -4408,11 +4393,12 @@ eslint-plugin-promise@^4.2.1:
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==
-eslint-plugin-vue@^6.0.1:
- version "6.1.2"
- resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-6.1.2.tgz#4b05c28c83c0ec912669b64dbd998bb8bf692ef6"
- integrity sha512-M75oAB+2a/LNkLKRbeEaS07EjzjIUaV7/hYoHAfRFeeF8ZMmCbahUn8nQLsLP85mkar24+zDU3QW2iT1JRsACw==
+eslint-plugin-vue@^6.2.1:
+ version "6.2.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-6.2.2.tgz#27fecd9a3a24789b0f111ecdd540a9e56198e0fe"
+ integrity sha512-Nhc+oVAHm0uz/PkJAWscwIT4ijTrK5fqNqz9QB1D35SbbuMG1uB6Yr5AJpvPSWg+WOw7nYNswerYh0kOk64gqQ==
dependencies:
+ natural-compare "^1.4.0"
semver "^5.6.0"
vue-eslint-parser "^7.0.0"
@@ -9872,11 +9858,6 @@ require-package-name@^2.0.1:
resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9"
integrity sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk=
-requireindex@~1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162"
- integrity sha1-5UBLgVV+91225JxacgBIk/4D4WI=
-
requires-port@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"