Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/diffs/components/tree_list.vue106
-rw-r--r--app/assets/javascripts/editor/schema/ci.json10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row_header.vue2
-rw-r--r--app/assets/stylesheets/framework/diffs.scss2
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss11
-rw-r--r--app/assets/stylesheets/page_bundles/project_quality.scss15
-rw-r--r--app/controllers/concerns/observability/content_security_policy.rb2
-rw-r--r--app/controllers/concerns/product_analytics_tracking.rb45
-rw-r--r--app/controllers/groups/observability_controller.rb2
-rw-r--r--app/controllers/ide_controller.rb5
-rw-r--r--app/controllers/search_controller.rb5
-rw-r--r--app/graphql/mutations/alert_management/base.rb2
-rw-r--r--app/mailers/emails/profile.rb2
-rw-r--r--app/models/integrations/base_slack_notification.rb2
-rw-r--r--app/models/integrations/jira.rb2
-rw-r--r--app/policies/group_policy.rb8
-rw-r--r--app/services/concerns/incident_management/usage_data.rb2
-rw-r--r--app/services/event_create_service.rb2
-rw-r--r--app/services/import_csv/base_service.rb3
-rw-r--r--app/services/incident_management/timeline_events/base_service.rb2
-rw-r--r--app/services/issuable/import_csv/base_service.rb2
-rw-r--r--app/services/todo_service.rb2
-rw-r--r--app/services/work_items/import_csv_service.rb50
-rw-r--r--app/views/admin/sessions/_two_factor_otp.html.haml6
-rw-r--r--app/views/devise/sessions/two_factor.html.haml6
-rw-r--r--app/views/notify/two_factor_otp_attempt_failed_email.html.haml4
-rw-r--r--app/views/notify/two_factor_otp_attempt_failed_email.text.haml4
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml4
-rw-r--r--app/views/projects/pipelines/charts.html.haml1
-rw-r--r--app/views/projects/settings/integrations/index.html.haml2
-rw-r--r--app/views/shared/integrations/_slack_notifications_deprecation_alert.html.haml10
-rw-r--r--app/workers/post_receive.rb2
-rw-r--r--config/application.rb1
-rw-r--r--config/feature_flags/development/route_hll_to_snowplow_phase2.yml8
-rw-r--r--danger/roulette/Dangerfile2
-rw-r--r--db/post_migrate/20230216222956_add_sync_index_on_lfs_objects_file.rb15
-rw-r--r--db/schema_migrations/202302162229561
-rw-r--r--db/structure.sql2
-rw-r--r--doc/administration/integration/kroki.md8
-rw-r--r--doc/administration/integration/plantuml.md7
-rw-r--r--doc/administration/packages/container_registry.md2
-rw-r--r--doc/administration/postgresql/pgbouncer.md21
-rw-r--r--doc/api/commits.md5
-rw-r--r--doc/api/discussions.md4
-rw-r--r--doc/api/merge_request_approvals.md2
-rw-r--r--doc/api/notes.md9
-rw-r--r--doc/api/suggestions.md16
-rw-r--r--doc/architecture/blueprints/ci_pipeline_components/index.md5
-rw-r--r--doc/architecture/blueprints/gitlab_agent_deployments/index.md2
-rw-r--r--doc/ci/services/index.md2
-rw-r--r--doc/ci/testing/code_quality.md7
-rw-r--r--doc/ci/testing/img/code_quality_summary_15_9.pngbin0 -> 369601 bytes
-rw-r--r--doc/integration/datadog.md2
-rw-r--r--doc/integration/gmail_action_buttons_for_gitlab.md3
-rw-r--r--doc/integration/jira/index.md4
-rw-r--r--doc/integration/jira/issues.md4
-rw-r--r--doc/integration/trello_power_up.md8
-rw-r--r--doc/operations/metrics/index.md2
-rw-r--r--doc/raketasks/generate_sample_prometheus_data.md12
-rw-r--r--doc/user/admin_area/settings/external_authorization.md23
-rw-r--r--doc/user/clusters/agent/gitops/flux.md36
-rw-r--r--doc/user/profile/index.md2
-rw-r--r--doc/user/profile/notifications.md2
-rw-r--r--doc/user/project/integrations/apple_app_store.md2
-rw-r--r--doc/user/project/integrations/asana.md2
-rw-r--r--doc/user/project/integrations/ewm.md2
-rw-r--r--doc/user/project/integrations/github.md2
-rw-r--r--doc/user/project/integrations/hangouts_chat.md4
-rw-r--r--doc/user/project/integrations/harbor.md6
-rw-r--r--doc/user/project/integrations/irker.md4
-rw-r--r--doc/user/project/integrations/mock_ci.md10
-rw-r--r--doc/user/project/integrations/pivotal_tracker.md2
-rw-r--r--doc/user/project/integrations/prometheus.md2
-rw-r--r--doc/user/project/integrations/redmine.md3
-rw-r--r--doc/user/project/integrations/slack_slash_commands.md2
-rw-r--r--doc/user/project/integrations/unify_circuit.md2
-rw-r--r--lib/api/terraform/state.rb22
-rw-r--r--lib/gitlab/database/schema_validation/database.rb4
-rw-r--r--lib/gitlab/database/schema_validation/runner.rb24
-rw-r--r--lib/gitlab/database/schema_validation/structure_sql.rb4
-rw-r--r--lib/gitlab/database/schema_validation/validators/base_validator.rb38
-rw-r--r--lib/gitlab/database/schema_validation/validators/extra_indexes.rb19
-rw-r--r--lib/gitlab/database/schema_validation/validators/missing_indexes.rb19
-rw-r--r--lib/gitlab/database/schema_validation/validators/wrong_indexes.rb22
-rw-r--r--lib/gitlab/observability.rb39
-rw-r--r--lib/gitlab/usage_data_counters/editor_unique_counter.rb22
-rw-r--r--lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb1
-rw-r--r--lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb4
-rw-r--r--lib/sidebars/groups/menus/observability_menu.rb9
-rw-r--r--locale/gitlab.pot54
-rw-r--r--package.json4
-rw-r--r--rubocop/cop/gitlab/feature_available_usage.rb2
-rw-r--r--rubocop/cop/graphql/id_type.rb2
-rw-r--r--rubocop/cop/migration/add_reference.rb2
-rw-r--r--rubocop/cop/rspec/factory_bot/inline_association.rb2
-rw-r--r--spec/controllers/admin/cohorts_controller_spec.rb1
-rw-r--r--spec/controllers/admin/dev_ops_report_controller_spec.rb1
-rw-r--r--spec/controllers/admin/usage_trends_controller_spec.rb1
-rw-r--r--spec/controllers/projects/cycle_analytics_controller_spec.rb1
-rw-r--r--spec/controllers/projects/graphs_controller_spec.rb1
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb1
-rw-r--r--spec/controllers/search_controller_spec.rb10
-rw-r--r--spec/features/admin/admin_mode/login_spec.rb20
-rw-r--r--spec/features/users/login_spec.rb6
-rw-r--r--spec/fixtures/work_items_missing_header.csv3
-rw-r--r--spec/fixtures/work_items_valid.csv3
-rw-r--r--spec/frontend/diffs/components/tree_list_spec.js79
-rw-r--r--spec/frontend/editor/schema/ci/ci_schema_spec.js8
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml38
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml31
-rw-r--r--spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap40
-rw-r--r--spec/frontend/vue_shared/components/file_row_header_spec.js26
-rw-r--r--spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb1
-rw-r--r--spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb1
-rw-r--r--spec/graphql/mutations/alert_management/create_alert_issue_spec.rb2
-rw-r--r--spec/graphql/mutations/alert_management/update_alert_status_spec.rb1
-rw-r--r--spec/lib/gitlab/database/schema_validation/database_spec.rb18
-rw-r--r--spec/lib/gitlab/database/schema_validation/runner_spec.rb19
-rw-r--r--spec/lib/gitlab/database/schema_validation/structure_sql_spec.rb47
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb28
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/extra_indexes_spec.rb7
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/missing_indexes_spec.rb14
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/wrong_indexes_spec.rb7
-rw-r--r--spec/lib/gitlab/observability_spec.rb105
-rw-r--r--spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb2
-rw-r--r--spec/lib/sidebars/groups/menus/observability_menu_spec.rb60
-rw-r--r--spec/mailers/emails/profile_spec.rb2
-rw-r--r--spec/models/integrations/jira_spec.rb2
-rw-r--r--spec/policies/group_policy_spec.rb7
-rw-r--r--spec/requests/api/commits_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/snippets/update_spec.rb3
-rw-r--r--spec/requests/api/terraform/state_spec.rb1
-rw-r--r--spec/requests/groups/observability_controller_spec.rb18
-rw-r--r--spec/requests/ide_controller_spec.rb12
-rw-r--r--spec/requests/verifies_with_email_spec.rb2
-rw-r--r--spec/services/event_create_service_spec.rb6
-rw-r--r--spec/services/import_csv/base_service_spec.rb39
-rw-r--r--spec/services/incident_management/timeline_events/create_service_spec.rb2
-rw-r--r--spec/services/incident_management/timeline_events/destroy_service_spec.rb1
-rw-r--r--spec/services/incident_management/timeline_events/update_service_spec.rb1
-rw-r--r--spec/services/issue_links/create_service_spec.rb1
-rw-r--r--spec/services/issue_links/destroy_service_spec.rb1
-rw-r--r--spec/services/issues/close_service_spec.rb1
-rw-r--r--spec/services/issues/import_csv_service_spec.rb3
-rw-r--r--spec/services/issues/reopen_service_spec.rb1
-rw-r--r--spec/services/issues/update_service_spec.rb2
-rw-r--r--spec/services/issues/zoom_link_service_spec.rb1
-rw-r--r--spec/services/notes/create_service_spec.rb1
-rw-r--r--spec/services/todo_service_spec.rb1
-rw-r--r--spec/services/work_items/import_csv_service_spec.rb99
-rw-r--r--spec/support/services/import_csv_service_shared_examples.rb38
-rw-r--r--spec/support/services/issuable_import_csv_service_shared_examples.rb37
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb (renamed from spec/lib/gitlab/database/schema_validation/indexes_spec.rb)29
-rw-r--r--spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/observability/csp_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb1
-rw-r--r--spec/workers/post_receive_spec.rb1
-rw-r--r--tooling/danger/sidekiq_queues.rb2
-rw-r--r--yarn.lock16
167 files changed, 1323 insertions, 521 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 5f8d751e840..f61490fab6e 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-24b98424df69e1de124662844a7e6df6dccb3768
+d4c721263cf338984810e84d1af4039364954b5f
diff --git a/Gemfile b/Gemfile
index 0f64f3c9b04..f837c9b7025 100644
--- a/Gemfile
+++ b/Gemfile
@@ -416,7 +416,7 @@ group :development, :test do
gem 'bundler-audit', '~> 0.7.0.1', require: false
# Benchmarking & profiling
- gem 'benchmark-ips', '~> 2.3.0', require: false
+ gem 'benchmark-ips', '~> 2.11.0', require: false
gem 'benchmark-memory', '~> 0.1', require: false
gem 'knapsack', '~> 1.21.1'
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 338358973e2..cfd4b470b8f 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -50,7 +50,7 @@
{"name":"bcrypt","version":"3.1.16","platform":"java","checksum":"2925a1546fa8e85bdb1b10f1fc95c4e1ea15992ada16adea4af82b0978ed662c"},
{"name":"bcrypt","version":"3.1.16","platform":"ruby","checksum":"0b8bf031ba81aa76c0f10c5a8dac779b6035d84b09af1dbb2b1a32a7e360210b"},
{"name":"benchmark","version":"0.2.0","platform":"ruby","checksum":"5f7087b794613abdd3ac9c13f4351f65b164bcb15ced2ad29508e365f9b28c77"},
-{"name":"benchmark-ips","version":"2.3.0","platform":"ruby","checksum":"12443aa327d3129aa965244f79d7d5cb0f692f0f92ba7db76fba61526a40062e"},
+{"name":"benchmark-ips","version":"2.11.0","platform":"ruby","checksum":"1eaa89841073895af0ee7ff72eb069e5c7dda01c6d6a8b3e79e363bace596dec"},
{"name":"benchmark-malloc","version":"0.2.0","platform":"ruby","checksum":"37c68f0435261634026f584d79956a35325a3027e3e6b4cc8d7575aa10537e6b"},
{"name":"benchmark-memory","version":"0.2.0","platform":"ruby","checksum":"ca1e436433b09535ee8f64f80600a5edb407cff1f6ac70e089ca238118e6ab5c"},
{"name":"benchmark-perf","version":"0.6.0","platform":"ruby","checksum":"fe2b01959f3de0f9dd34820d54ef881eb4f3589fccb7d17b63068ac92d7f9621"},
diff --git a/Gemfile.lock b/Gemfile.lock
index ca37508841b..95307b80a14 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -232,7 +232,7 @@ GEM
batch-loader (2.0.1)
bcrypt (3.1.16)
benchmark (0.2.0)
- benchmark-ips (2.3.0)
+ benchmark-ips (2.11.0)
benchmark-malloc (0.2.0)
benchmark-memory (0.2.0)
memory_profiler (~> 1)
@@ -1613,7 +1613,7 @@ DEPENDENCIES
base32 (~> 0.3.0)
batch-loader (~> 2.0.1)
bcrypt (~> 3.1, >= 3.1.14)
- benchmark-ips (~> 2.3.0)
+ benchmark-ips (~> 2.11.0)
benchmark-memory (~> 0.1)
better_errors (~> 2.9.1)
bootsnap (~> 1.16.0)
diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue
index 8bb1872567c..4748c587b8e 100644
--- a/app/assets/javascripts/diffs/components/tree_list.vue
+++ b/app/assets/javascripts/diffs/components/tree_list.vue
@@ -2,9 +2,10 @@
import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import micromatch from 'micromatch';
+import { debounce } from 'lodash';
import { getModifierKey } from '~/constants';
import { s__, sprintf } from '~/locale';
-import FileTree from '~/vue_shared/components/file_tree.vue';
+import { RecycleScroller } from 'vendor/vue-virtual-scroller';
import DiffFileRow from './diff_file_row.vue';
const MODIFIER_KEY = getModifierKey();
@@ -15,7 +16,8 @@ export default {
},
components: {
GlIcon,
- FileTree,
+ DiffFileRow,
+ RecycleScroller,
},
props: {
hideFileStats: {
@@ -26,6 +28,10 @@ export default {
data() {
return {
search: '',
+ scrollerHeight: 0,
+ resizeObserver: null,
+ rowHeight: 0,
+ debouncedHeightCalc: null,
};
},
computed: {
@@ -61,12 +67,51 @@ export default {
return acc;
}, []);
},
+ // Flatten the treeList so there's no nested trees
+ // This gives us fixed row height for virtual scrolling
+ // in: [{ path: 'a', tree: [{ path: 'b' }] }, { path: 'c' }]
+ // out: [{ path: 'a', tree: [{ path: 'b' }] }, { path: 'b' }, { path: 'c' }]
+ flatFilteredTreeList() {
+ const result = [];
+ const createFlatten = (level) => (item) => {
+ result.push({
+ ...item,
+ level: item.isHeader ? 0 : level,
+ key: item.key || item.path,
+ });
+ if (item.opened || item.isHeader) {
+ item.tree.forEach(createFlatten(level + 1));
+ }
+ };
+
+ this.filteredTreeList.forEach(createFlatten(0));
+
+ return result;
+ },
+ },
+ created() {
+ this.debouncedHeightCalc = debounce(this.calculateScrollerHeight, 50);
+ },
+ mounted() {
+ const heightProp = getComputedStyle(this.$refs.wrapper).getPropertyValue('--file-row-height');
+ this.rowHeight = parseInt(heightProp, 10);
+ this.calculateScrollerHeight();
+ this.resizeObserver = new ResizeObserver(() => {
+ this.debouncedHeightCalc();
+ });
+ this.resizeObserver.observe(this.$refs.scrollRoot);
+ },
+ beforeDestroy() {
+ this.resizeObserver.disconnect();
},
methods: {
...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile']),
clearSearch() {
this.search = '';
},
+ calculateScrollerHeight() {
+ this.scrollerHeight = this.$refs.scrollRoot.clientHeight;
+ },
},
searchPlaceholder: sprintf(s__('MergeRequest|Search (e.g. *.vue) (%{MODIFIER_KEY}P)'), {
MODIFIER_KEY,
@@ -76,8 +121,12 @@ export default {
</script>
<template>
- <div class="tree-list-holder d-flex flex-column" data-qa-selector="file_tree_container">
- <div class="gl-mb-3 position-relative tree-list-search d-flex">
+ <div
+ ref="wrapper"
+ class="tree-list-holder d-flex flex-column"
+ data-qa-selector="file_tree_container"
+ >
+ <div class="gl-pb-3 position-relative tree-list-search d-flex">
<div class="flex-fill d-flex">
<gl-icon name="search" class="position-absolute tree-list-icon" />
<label for="diff-tree-search" class="sr-only">{{ $options.searchPlaceholder }}</label>
@@ -101,24 +150,37 @@ export default {
</button>
</div>
</div>
- <div :class="{ 'pt-0 tree-list-blobs': !renderTreeList || search }" class="tree-list-scroll">
- <template v-if="filteredTreeList.length">
- <file-tree
- v-for="file in filteredTreeList"
- :key="file.key"
- :file="file"
- :level="0"
- :viewed-files="viewedDiffFileIds"
- :hide-file-stats="hideFileStats"
- :file-row-component="$options.DiffFileRow"
- :current-diff-file-id="currentDiffFileId"
- :style="{ '--level': 0 }"
- :class="{ 'tree-list-parent': file.tree.length }"
- class="gl-relative"
- @toggleTreeOpen="toggleTreeOpen"
- @clickFile="(path) => scrollToFile({ path })"
- />
- </template>
+ <div
+ ref="scrollRoot"
+ :class="{ 'tree-list-blobs': !renderTreeList || search }"
+ class="gl-flex-grow-1"
+ >
+ <recycle-scroller
+ v-if="flatFilteredTreeList.length"
+ :style="{ height: `${scrollerHeight}px` }"
+ :items="flatFilteredTreeList"
+ :item-size="rowHeight"
+ :buffer="100"
+ key-field="key"
+ >
+ <template #default="{ item }">
+ <diff-file-row
+ :file="item"
+ :level="item.level"
+ :viewed-files="viewedDiffFileIds"
+ :hide-file-stats="hideFileStats"
+ :current-diff-file-id="currentDiffFileId"
+ :style="{ '--level': item.level }"
+ :class="{ 'tree-list-parent': item.tree.length }"
+ class="gl-relative"
+ @toggleTreeOpen="toggleTreeOpen"
+ @clickFile="(path) => scrollToFile({ path })"
+ />
+ </template>
+ <template #after>
+ <div class="tree-list-gutter"></div>
+ </template>
+ </recycle-scroller>
<p v-else class="prepend-top-20 append-bottom-20 text-center">
{{ s__('MergeRequest|No files found') }}
</p>
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index 57477a993c5..701b40b1021 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -537,7 +537,7 @@
},
"entrypoint": {
"type": "array",
- "description": "Command or script that should be executed as the container's entrypoint. It will be translated to Docker's --entrypoint option while creating the container. The syntax is similar to Dockerfile's ENTRYPOINT directive, where each shell token is a separate string in the array.",
+ "markdownDescription": "Command or script that should be executed as the container's entrypoint. It will be translated to Docker's --entrypoint option while creating the container. The syntax is similar to Dockerfile's ENTRYPOINT directive, where each shell token is a separate string in the array. [Learn More](https://docs.gitlab.com/ee/ci/services/index.html#available-settings-for-services)",
"minItems": 1,
"items": {
"type": "string"
@@ -572,7 +572,7 @@
},
"command": {
"type": "array",
- "description": "Command or script that should be used as the container's command. It will be translated to arguments passed to Docker after the image's name. The syntax is similar to Dockerfile's CMD directive, where each shell token is a separate string in the array.",
+ "markdownDescription": "Command or script that should be used as the container's command. It will be translated to arguments passed to Docker after the image's name. The syntax is similar to Dockerfile's CMD directive, where each shell token is a separate string in the array. [Learn More](https://docs.gitlab.com/ee/ci/services/index.html#available-settings-for-services)",
"minItems": 1,
"items": {
"type": "string"
@@ -580,8 +580,12 @@
},
"alias": {
"type": "string",
- "description": "Additional alias that can be used to access the service from the job's container. Read Accessing the services for more information.",
+ "markdownDescription": "Additional alias that can be used to access the service from the job's container. Read Accessing the services for more information. [Learn More](https://docs.gitlab.com/ee/ci/services/index.html#available-settings-for-services)",
"minLength": 1
+ },
+ "variables": {
+ "$ref": "#/definitions/jobVariables",
+ "markdownDescription": "Additional environment variables that are passed exclusively to the service. Service variables cannot reference themselves. [Learn More](https://docs.gitlab.com/ee/ci/services/index.html#available-settings-for-services)"
}
},
"required": [
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
index 81cb20475cc..cead42b12ae 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
@@ -32,5 +32,5 @@ export default function deviseState() {
) {
return stateKey.readyToMerge;
}
- return null;
+ return stateKey.checking;
}
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index dfeb12d5cf5..721f87ff4d6 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -168,7 +168,7 @@ export default {
.file-row {
display: flex;
align-items: center;
- height: 32px;
+ height: var(--file-row-height, 32px);
padding: 4px 8px;
margin-left: -8px;
margin-right: -8px;
diff --git a/app/assets/javascripts/vue_shared/components/file_row_header.vue b/app/assets/javascripts/vue_shared/components/file_row_header.vue
index 5afb2408c7e..b436872e463 100644
--- a/app/assets/javascripts/vue_shared/components/file_row_header.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row_header.vue
@@ -15,7 +15,7 @@ export default {
</script>
<template>
- <div class="file-row-header bg-white sticky-top p-2 js-file-row-header" :title="path">
+ <div class="file-row-header bg-white sticky-top gl-px-2 js-file-row-header" :title="path">
<gl-truncate :text="path" position="middle" class="bold" />
</div>
</template>
diff --git a/app/assets/stylesheets/framework/diffs.scss b/app/assets/stylesheets/framework/diffs.scss
index 4eb26d533c2..742d0e39dda 100644
--- a/app/assets/stylesheets/framework/diffs.scss
+++ b/app/assets/stylesheets/framework/diffs.scss
@@ -999,7 +999,7 @@ table.code {
}
// Note: Prevents tall files from appearing above sticky tabs
-.diffs .vue-recycle-scroller__item-view > div:not(.active) {
+.diff-files-holder .vue-recycle-scroller__item-view > div:not(.active) {
position: absolute;
bottom: 100vh;
}
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index fe64e4f2fe8..4caaeeb647e 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -282,6 +282,7 @@ $tabs-holder-z-index: 250;
}
.tree-list-holder {
+ --file-row-height: 32px;
height: 100%;
.file-row {
@@ -297,6 +298,10 @@ $tabs-holder-z-index: 250;
overflow-x: auto;
}
+.tree-list-gutter {
+ height: $grid-size;
+}
+
.tree-list-search {
flex: 0 0 34px;
@@ -322,6 +327,12 @@ $tabs-holder-z-index: 250;
line-height: 0;
}
+.file-row-header {
+ display: flex;
+ align-items: center;
+ height: var(--file-row-height);
+}
+
@media (max-width: map-get($grid-breakpoints, lg)-1) {
.diffs .files {
.diff-tree-list {
diff --git a/app/assets/stylesheets/page_bundles/project_quality.scss b/app/assets/stylesheets/page_bundles/project_quality.scss
new file mode 100644
index 00000000000..425b9544235
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/project_quality.scss
@@ -0,0 +1,15 @@
+@import 'page_bundles/mixins_and_variables_and_functions';
+
+/*
+When the single-stat component of gitlab UI adds the props of the title icon color,
+remove this file and use the props of gitlab UI to set the color
+Gitlab UI issue: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2157
+*/
+
+.code-quality-blocker .gl-icon {
+ @include gl-text-red-800;
+}
+
+.code-quality-critical .gl-icon {
+ @include gl-text-red-600;
+}
diff --git a/app/controllers/concerns/observability/content_security_policy.rb b/app/controllers/concerns/observability/content_security_policy.rb
index 14e9217fe02..1e25dc492a0 100644
--- a/app/controllers/concerns/observability/content_security_policy.rb
+++ b/app/controllers/concerns/observability/content_security_policy.rb
@@ -12,7 +12,7 @@ module Observability
defined?(project) ? project&.group : nil
end
- next if p.directives.blank? || !Gitlab::Observability.observability_enabled?(current_user, current_group)
+ next if p.directives.blank? || !Feature.enabled?(:observability_group_tab, current_group)
default_frame_src = p.directives['frame-src'] || p.directives['default-src']
diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb
index 5696e441ad0..223b200f3b5 100644
--- a/app/controllers/concerns/product_analytics_tracking.rb
+++ b/app/controllers/concerns/product_analytics_tracking.rb
@@ -5,7 +5,29 @@ module ProductAnalyticsTracking
include RedisTracking
extend ActiveSupport::Concern
- MIGRATED_EVENTS = ['g_analytics_valuestream'].freeze
+ MIGRATED_EVENTS = %w[
+ g_analytics_valuestream
+ i_search_paid
+ i_search_total
+ i_search_advanced
+ i_ecosystem_jira_service_list_issues
+ users_viewing_analytics_group_devops_adoption
+ i_analytics_dev_ops_adoption
+ i_analytics_dev_ops_score
+ p_analytics_merge_request
+ i_analytics_instance_statistics
+ g_analytics_contribution
+ p_analytics_pipelines
+ p_analytics_code_reviews
+ p_analytics_valuestream
+ p_analytics_insights
+ p_analytics_issues
+ p_analytics_repo
+ g_analytics_insights
+ g_analytics_issues
+ g_analytics_productivity
+ i_analytics_cohorts
+ ].freeze
class_methods do
# TODO: Remove once all the events are migrated to #track_custom_event
@@ -68,27 +90,6 @@ module ProductAnalyticsTracking
return true if MIGRATED_EVENTS.include?(event)
events_to_ff = {
- i_search_paid: :_phase2,
- i_search_total: :_phase2,
- i_search_advanced: :_phase2,
- i_ecosystem_jira_service_list_issues: :_phase2,
- users_viewing_analytics_group_devops_adoption: :_phase2,
- i_analytics_dev_ops_adoption: :_phase2,
- i_analytics_dev_ops_score: :_phase2,
- p_analytics_merge_request: :_phase2,
- i_analytics_instance_statistics: :_phase2,
- g_analytics_contribution: :_phase2,
- p_analytics_pipelines: :_phase2,
- p_analytics_code_reviews: :_phase2,
- p_analytics_valuestream: :_phase2,
- p_analytics_insights: :_phase2,
- p_analytics_issues: :_phase2,
- p_analytics_repo: :_phase2,
- g_analytics_insights: :_phase2,
- g_analytics_issues: :_phase2,
- g_analytics_productivity: :_phase2,
- i_analytics_cohorts: :_phase2,
-
g_compliance_dashboard: :_phase4
}
diff --git a/app/controllers/groups/observability_controller.rb b/app/controllers/groups/observability_controller.rb
index 726af00a10e..525407f5849 100644
--- a/app/controllers/groups/observability_controller.rb
+++ b/app/controllers/groups/observability_controller.rb
@@ -30,7 +30,7 @@ module Groups
end
def check_observability_allowed
- render_404 unless Gitlab::Observability.observability_enabled?(current_user, group)
+ render_404 unless Gitlab::Observability.allowed_for_action?(current_user, group, params[:action])
end
end
end
diff --git a/app/controllers/ide_controller.rb b/app/controllers/ide_controller.rb
index d0e14000d8e..b61e2318cea 100644
--- a/app/controllers/ide_controller.rb
+++ b/app/controllers/ide_controller.rb
@@ -20,9 +20,8 @@ class IdeController < ApplicationController
def index
Gitlab::UsageDataCounters::WebIdeCounter.increment_views_count
- if project && Feature.enabled?(:route_hll_to_snowplow_phase2, project&.namespace)
- Gitlab::Tracking.event(self.class.to_s, 'web_ide_views',
- namespace: project&.namespace, user: current_user)
+ if project
+ Gitlab::Tracking.event(self.class.to_s, 'web_ide_views', namespace: project.namespace, user: current_user)
end
render layout: 'fullscreen', locals: { minimal: helpers.use_new_web_ide? }
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 8796fda572f..9df86e2c702 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -24,7 +24,7 @@ class SearchController < ApplicationController
before_action :block_anonymous_global_searches, :check_scope_global_search_enabled, except: :opensearch
skip_before_action :authenticate_user!
- skip_before_action :default_cache_headers, only: :count
+ skip_before_action :default_cache_headers, only: [:count, :autocomplete]
requires_cross_project_access if: -> do
search_term_present = params[:search].present? || params[:term].present?
@@ -116,6 +116,9 @@ class SearchController < ApplicationController
@ref = params[:project_ref] if params[:project_ref].present?
@filter = params[:filter]
+ # Cache the response on the frontend
+ expires_in 1.minute
+
render json: Gitlab::Json.dump(search_autocomplete_opts(term, filter: @filter))
end
diff --git a/app/graphql/mutations/alert_management/base.rb b/app/graphql/mutations/alert_management/base.rb
index 2eef6bb9db7..771ace5510f 100644
--- a/app/graphql/mutations/alert_management/base.rb
+++ b/app/graphql/mutations/alert_management/base.rb
@@ -45,8 +45,6 @@ module Mutations
namespace = project.namespace
track_usage_event(event, current_user.id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, namespace)
-
Gitlab::Tracking.event(
self.class.to_s,
event,
diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb
index 5b1750400d8..a191bd4a8f6 100644
--- a/app/mailers/emails/profile.rb
+++ b/app/mailers/emails/profile.rb
@@ -153,7 +153,7 @@ module Emails
Gitlab::I18n.with_locale(@user.preferred_language) do
email_with_layout(
to: @user.notification_email_or_default,
- subject: subject(_("Attempted sign in to %{host} using a wrong two-factor authentication code") % { host: Gitlab.config.gitlab.host }))
+ subject: subject(_("Attempted sign in to %{host} using an incorrect verification code") % { host: Gitlab.config.gitlab.host }))
end
end
diff --git a/app/models/integrations/base_slack_notification.rb b/app/models/integrations/base_slack_notification.rb
index 7a2a91aa0d2..c83a559e0da 100644
--- a/app/models/integrations/base_slack_notification.rb
+++ b/app/models/integrations/base_slack_notification.rb
@@ -44,8 +44,6 @@ module Integrations
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(key, values: user_id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2)
-
optional_arguments = {
project: project,
namespace: group || project&.namespace
diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb
index d96a848c72e..a1cdd55ceae 100644
--- a/app/models/integrations/jira.rb
+++ b/app/models/integrations/jira.rb
@@ -391,8 +391,6 @@ module Integrations
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(key, values: user.id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2)
-
optional_arguments = {
project: project,
namespace: group || project&.namespace
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index 6cc65248914..b560a5d914a 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -246,7 +246,9 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
rule { ~can?(:view_globally) }.prevent :request_access
rule { has_access }.prevent :request_access
- rule { owner & (~share_with_group_locked | ~has_parent | ~parent_share_with_group_locked | can_change_parent_share_with_group_lock) }.enable :change_share_with_group_lock
+ rule do
+ owner & (~share_with_group_locked | ~has_parent | ~parent_share_with_group_locked | can_change_parent_share_with_group_lock)
+ end.enable :change_share_with_group_lock
rule { developer & developer_maintainer_access }.enable :create_projects
rule { create_projects_disabled }.prevent :create_projects
@@ -325,6 +327,10 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :read_observability
end
+ rule { can?(:maintainer_access) & observability_enabled }.policy do
+ enable :admin_observability
+ end
+
rule { ~create_runner_workflow_enabled }.policy do
prevent :create_group_runners
end
diff --git a/app/services/concerns/incident_management/usage_data.rb b/app/services/concerns/incident_management/usage_data.rb
index 40183085344..775dea9b949 100644
--- a/app/services/concerns/incident_management/usage_data.rb
+++ b/app/services/concerns/incident_management/usage_data.rb
@@ -13,8 +13,6 @@ module IncidentManagement
namespace = target.try(:namespace)
project = target.try(:project)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, target.try(:namespace))
-
Gitlab::Tracking.event(
self.class.to_s,
event,
diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb
index d848f694598..c941febad57 100644
--- a/app/services/event_create_service.rb
+++ b/app/services/event_create_service.rb
@@ -278,8 +278,6 @@ class EventCreateService
end
def track_snowplow_event(action:, project:, user:, label:, property:)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2)
-
Gitlab::Tracking.event(
self.class.to_s,
action.to_s,
diff --git a/app/services/import_csv/base_service.rb b/app/services/import_csv/base_service.rb
index feb76425fb4..628c322db13 100644
--- a/app/services/import_csv/base_service.rb
+++ b/app/services/import_csv/base_service.rb
@@ -46,8 +46,9 @@ module ImportCsv
results[:error_lines].push(line_no)
end
end
- rescue ArgumentError, CSV::MalformedCSVError
+ rescue ArgumentError, CSV::MalformedCSVError => e
results[:parse_error] = true
+ results[:error_lines].push(e.line_number) if e.respond_to?(:line_number)
end
def with_csv_lines
diff --git a/app/services/incident_management/timeline_events/base_service.rb b/app/services/incident_management/timeline_events/base_service.rb
index e997d940ed4..75a3811af2d 100644
--- a/app/services/incident_management/timeline_events/base_service.rb
+++ b/app/services/incident_management/timeline_events/base_service.rb
@@ -29,8 +29,6 @@ module IncidentManagement
namespace = project.namespace
track_usage_event(event, user.id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, namespace)
-
Gitlab::Tracking.event(
self.class.to_s,
event,
diff --git a/app/services/issuable/import_csv/base_service.rb b/app/services/issuable/import_csv/base_service.rb
index 83cf5a67453..9ef9fb76e3c 100644
--- a/app/services/issuable/import_csv/base_service.rb
+++ b/app/services/issuable/import_csv/base_service.rb
@@ -21,7 +21,7 @@ module Issuable
headers.downcase! if headers
return if headers && headers.include?('title') && headers.include?('description')
- raise CSV::MalformedCSVError
+ raise CSV::MalformedCSVError.new('Invalid CSV format - missing required headers.', 1)
end
end
end
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index 42a8aca17d3..2025d438ae7 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -428,8 +428,6 @@ class TodoService
event = "incident_management_incident_todo"
track_usage_event(event, user.id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, namespace)
-
Gitlab::Tracking.event(
self.class.to_s,
event,
diff --git a/app/services/work_items/import_csv_service.rb b/app/services/work_items/import_csv_service.rb
new file mode 100644
index 00000000000..e93905b8ca5
--- /dev/null
+++ b/app/services/work_items/import_csv_service.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module WorkItems
+ class ImportCsvService < ImportCsv::BaseService
+ extend ::Gitlab::Utils::Override
+
+ NotAvailableError = StandardError.new('This feature is currently behind a feature flag and it is not available.')
+
+ def execute
+ raise NotAvailableError if ::Feature.disabled?(:import_export_work_items_csv, project)
+
+ super
+ end
+
+ def email_results_to_user
+ # todo as part of https://gitlab.com/gitlab-org/gitlab/-/issues/379153
+ end
+
+ private
+
+ def create_object(attributes)
+ super[:work_item]
+ end
+
+ def create_object_class
+ ::WorkItems::CreateService
+ end
+
+ override :attributes_for
+ def attributes_for(row)
+ {
+ title: row[:title],
+ work_item_type: WorkItems::Type.default_issue_type
+ }
+ end
+
+ override :validate_headers_presence!
+ def validate_headers_presence!(headers)
+ headers.downcase! if headers
+ return if headers && required_headers.all? { |rh| headers.include?(rh) }
+
+ required_headers_message = "Required headers are missing. Required headers are #{required_headers.join(', ')}"
+ raise CSV::MalformedCSVError.new(required_headers_message, 1)
+ end
+
+ def required_headers
+ %w[title].freeze
+ end
+ end
+end
diff --git a/app/views/admin/sessions/_two_factor_otp.html.haml b/app/views/admin/sessions/_two_factor_otp.html.haml
index 40ba79d1a65..037f0d5ecb1 100644
--- a/app/views/admin/sessions/_two_factor_otp.html.haml
+++ b/app/views/admin/sessions/_two_factor_otp.html.haml
@@ -1,9 +1,9 @@
= form_tag(admin_session_path, { method: :post, class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if current_user.two_factor_webauthn_u2f_enabled?}" }) do
.form-group
- = label_tag :user_otp_attempt, _('Two-Factor Authentication code')
- = text_field_tag 'user[otp_attempt]', nil, class: 'form-control', required: true, autofocus: true, autocomplete: 'off', title: _('This field is required.')
+ = label_tag :user_otp_attempt, _('Enter verification code')
+ = text_field_tag 'user[otp_attempt]', nil, class: 'form-control', required: true, autofocus: true, autocomplete: 'off', inputmode: 'numeric', title: _('This field is required.')
%p.form-text.text-muted.hint
- = _("Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.")
+ = _("Enter the code from your two-factor authenticator app. If you've lost your device, you can enter one of your recovery codes.")
.submit-container.move-submit-down
= submit_tag 'Verify code', class: 'gl-button btn btn-confirm'
diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml
index f63f1aa9197..25aeb25994e 100644
--- a/app/views/devise/sessions/two_factor.html.haml
+++ b/app/views/devise/sessions/two_factor.html.haml
@@ -7,9 +7,9 @@
- resource_params = params[resource_name].presence || params
= f.hidden_field :remember_me, value: resource_params.fetch(:remember_me, 0)
%div
- = f.label _('Two-Factor Authentication code'), name: :otp_attempt, class: Feature.enabled?(:restyle_login_page, @project) ? 'gl-mb-1' : ''
- = f.text_field :otp_attempt, class: 'form-control gl-form-input', required: true, autofocus: true, autocomplete: 'off', title: _('This field is required.'), data: { qa_selector: 'two_fa_code_field' }
- %p.form-text.text-muted.hint= _("Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.")
+ = f.label _('Enter verification code'), name: :otp_attempt, class: Feature.enabled?(:restyle_login_page, @project) ? 'gl-mb-1' : ''
+ = f.text_field :otp_attempt, class: 'form-control gl-form-input', required: true, autofocus: true, autocomplete: 'off', inputmode: 'numeric', title: _('This field is required.'), data: { qa_selector: 'two_fa_code_field' }
+ %p.form-text.text-muted.hint= _("Enter the code from your two-factor authenticator app. If you've lost your device, you can enter one of your recovery codes.")
.prepend-top-20
= f.submit _("Verify code"), pajamas_button: true, data: { qa_selector: 'verify_code_button' }
- if @user.two_factor_webauthn_u2f_enabled?
diff --git a/app/views/notify/two_factor_otp_attempt_failed_email.html.haml b/app/views/notify/two_factor_otp_attempt_failed_email.html.haml
index 83f028af500..968d84f700d 100644
--- a/app/views/notify/two_factor_otp_attempt_failed_email.html.haml
+++ b/app/views/notify/two_factor_otp_attempt_failed_email.html.haml
@@ -9,7 +9,7 @@
%tr
%td{ style: "#{default_font}vertical-align:middle;color:#ffffff;text-align:center;" }
%span
- = _("We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code") % { host: Gitlab.config.gitlab.host }
+ = _("GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code") % { host: Gitlab.config.gitlab.host }
%tr.spacer
%td{ style: spacer_style }
&nbsp;
@@ -43,7 +43,7 @@
%tr{ style: 'width:100%;' }
%td{ style: "#{default_style}text-align:center;" }
- password_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_url('user/profile/user_passwords', anchor: 'change-your-password') }
- = _('If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email.')
+ = _('If you recently tried to sign in, but mistakenly entered an incorrect verification code, you can ignore this email.')
- if password_authentication_enabled_for_web?
%p
diff --git a/app/views/notify/two_factor_otp_attempt_failed_email.text.haml b/app/views/notify/two_factor_otp_attempt_failed_email.text.haml
index 8718ab034ff..9760dd3d985 100644
--- a/app/views/notify/two_factor_otp_attempt_failed_email.text.haml
+++ b/app/views/notify/two_factor_otp_attempt_failed_email.text.haml
@@ -1,7 +1,7 @@
= _('Hi %{username}!') % { username: sanitize_name(@user.name) }
-= _('We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}') % { host: Gitlab.config.gitlab.host, ip: @ip, time: @time }
+= _('GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code from the following IP address: %{ip}, at %{time}') % { host: Gitlab.config.gitlab.host, ip: @ip, time: @time }
-= _('If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email.')
+= _('If you recently tried to sign in, but mistakenly entered an incorrect verification code, you can ignore this email.')
= _('If you did not recently try to sign in, you should immediately change your password: %{password_link}.') % { password_link: help_page_url('user/profile/user_passwords', anchor: 'change-your-password') }
= _('Make sure you choose a strong, unique password.')
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index 3add3af3c65..2d40a566608 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -59,8 +59,8 @@
= link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication.md', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer'
.form-group
- = label_tag :pin_code, _('Pin code'), class: "label-bold"
- = text_field_tag :pin_code, nil, class: "form-control gl-form-input", required: true, data: { qa_selector: 'pin_code_field' }
+ = label_tag :pin_code, _('Enter verification code'), class: "label-bold"
+ = text_field_tag :pin_code, nil, autocomplete: 'off', inputmode: 'numeric', class: "form-control gl-form-input", required: true, data: { qa_selector: 'pin_code_field' }
- if current_password_required?
.form-group
= label_tag :current_password, _('Current password'), class: 'label-bold'
diff --git a/app/views/projects/pipelines/charts.html.haml b/app/views/projects/pipelines/charts.html.haml
index e16a2235e53..968189ab310 100644
--- a/app/views/projects/pipelines/charts.html.haml
+++ b/app/views/projects/pipelines/charts.html.haml
@@ -1,4 +1,5 @@
- page_title _('CI/CD Analytics')
+- add_page_specific_style 'page_bundles/project_quality'
#js-project-pipelines-charts-app{ data: { project_path: @project.full_path,
should_render_dora_charts: should_render_dora_charts.to_s,
diff --git a/app/views/projects/settings/integrations/index.html.haml b/app/views/projects/settings/integrations/index.html.haml
index 2077d244b24..c316b4e9cac 100644
--- a/app/views/projects/settings/integrations/index.html.haml
+++ b/app/views/projects/settings/integrations/index.html.haml
@@ -2,6 +2,8 @@
- breadcrumb_title _('Integration Settings')
- page_title _('Integrations')
+= render 'shared/integrations/slack_notifications_deprecation_alert'
+
%section.js-search-settings-section
%h3= _('Integrations')
- integrations_link_start = '<a href="%{url}">'.html_safe % { url: help_page_url('user/project/integrations/index') }
diff --git a/app/views/shared/integrations/_slack_notifications_deprecation_alert.html.haml b/app/views/shared/integrations/_slack_notifications_deprecation_alert.html.haml
new file mode 100644
index 00000000000..1e19d74df4c
--- /dev/null
+++ b/app/views/shared/integrations/_slack_notifications_deprecation_alert.html.haml
@@ -0,0 +1,10 @@
+- if Gitlab.com? && Feature.enabled?(:integration_slack_app_notifications)
+ = render Pajamas::AlertComponent.new(title: _('Slack notifications integration is deprecated'),
+ variant: :warning,
+ dismissible: false,
+ alert_options: { class: 'gl-mt-5', data: { testid: "slack-notifications-deprecation" } }) do |c|
+ = c.body do
+ - help_page_link = help_page_url('user/project/integrations/gitlab_slack_application')
+ - learn_more_link = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_link }
+
+ = html_escape(s_('The Slack notifications integration is deprecated and will be removed in a future release. To continue to receive notifications from Slack, use the GitLab for Slack app instead. %{learn_more_link_start}Learn more%{link_end}.')) % { learn_more_link_start: learn_more_link, link_end: '</a>'.html_safe }
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index f95176da252..676a834d79d 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -140,8 +140,6 @@ class PostReceive
end
def emit_snowplow_event(project, user)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, project.namespace)
-
metric_path = 'counts.source_code_pushes'
Gitlab::Tracking.event(
'PostReceive',
diff --git a/config/application.rb b/config/application.rb
index c6ecfcc0cb1..a1ed5fbd58a 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -311,6 +311,7 @@ module Gitlab
config.assets.precompile << "page_bundles/pipeline_editor.css"
config.assets.precompile << "page_bundles/productivity_analytics.css"
config.assets.precompile << "page_bundles/profile.css"
+ config.assets.precompile << "page_bundles/project_quality.css"
config.assets.precompile << "page_bundles/profile_two_factor_auth.css"
config.assets.precompile << "page_bundles/profiles/preferences.css"
config.assets.precompile << "page_bundles/project.css"
diff --git a/config/feature_flags/development/route_hll_to_snowplow_phase2.yml b/config/feature_flags/development/route_hll_to_snowplow_phase2.yml
deleted file mode 100644
index 2a3a820afd2..00000000000
--- a/config/feature_flags/development/route_hll_to_snowplow_phase2.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: route_hll_to_snowplow_phase2
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88482
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/363562
-milestone: '15.1'
-type: development
-group: group::product intelligence
-default_enabled: true
diff --git a/danger/roulette/Dangerfile b/danger/roulette/Dangerfile
index ca5a671ef29..32899c4d74f 100644
--- a/danger/roulette/Dangerfile
+++ b/danger/roulette/Dangerfile
@@ -96,7 +96,7 @@ categories = Set.new(changes.keys - [:unknown])
categories << :database if helper.mr_labels.include?('database')
# Ensure to spin for UX reviewer when ~UX is applied (e.g. to review changes to the UI) except when it's from wider community contribution where we want to assign from the corresponding group
-categories << :ux if helper.mr_labels.include?('UX') && !helper.mr_labels.include?('Community contribution')
+categories << :ux if helper.mr_labels.include?('UX') && !helper.mr_labels.include?('Community contribution') # rubocop:disable Rails/NegateInclude
# Ensure to spin for Product Intelligence reviewer when ~"product intelligence::review pending" is applied
categories << :product_intelligence if helper.mr_labels.include?("product intelligence::review pending")
diff --git a/db/post_migrate/20230216222956_add_sync_index_on_lfs_objects_file.rb b/db/post_migrate/20230216222956_add_sync_index_on_lfs_objects_file.rb
new file mode 100644
index 00000000000..8eda3345713
--- /dev/null
+++ b/db/post_migrate/20230216222956_add_sync_index_on_lfs_objects_file.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddSyncIndexOnLfsObjectsFile < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_lfs_objects_on_file'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :lfs_objects, :file, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :lfs_objects, INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20230216222956 b/db/schema_migrations/20230216222956
new file mode 100644
index 00000000000..a93e0602cd6
--- /dev/null
+++ b/db/schema_migrations/20230216222956
@@ -0,0 +1 @@
+6ebeadf8259911352813166646645320c3a238a68c1e8a4a97baa51b2bd182dd \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index c277291e823..e1d3e46161f 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -30537,6 +30537,8 @@ CREATE INDEX index_lfs_object_states_on_verification_state ON lfs_object_states
CREATE INDEX index_lfs_object_states_pending_verification ON lfs_object_states USING btree (verified_at NULLS FIRST) WHERE (verification_state = 0);
+CREATE INDEX index_lfs_objects_on_file ON lfs_objects USING btree (file);
+
CREATE INDEX index_lfs_objects_on_file_store ON lfs_objects USING btree (file_store);
CREATE UNIQUE INDEX index_lfs_objects_on_oid ON lfs_objects USING btree (oid);
diff --git a/doc/administration/integration/kroki.md b/doc/administration/integration/kroki.md
index 081c4d8a08c..6655657adcb 100644
--- a/doc/administration/integration/kroki.md
+++ b/doc/administration/integration/kroki.md
@@ -9,12 +9,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241744) in GitLab 13.7.
> - Support for reStructuredText and Textile documents [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/324766) in GitLab 13.12.
-When [Kroki](https://kroki.io) integration is enabled and configured in
-GitLab, you can use it to create diagrams in AsciiDoc, Markdown, reStructuredText, and Textile documents.
+With the [Kroki](https://kroki.io) integration,
+you can create diagrams in AsciiDoc, Markdown, reStructuredText, and Textile.
-## Kroki Server
+## Kroki server
-When Kroki is enabled, GitLab sends diagrams to an instance of Kroki to display them as images.
+When you enable Kroki, GitLab sends diagrams to an instance of Kroki to display them as images.
You can use the free public cloud instance `https://kroki.io` or you can [install Kroki](https://docs.kroki.io/kroki/setup/install/)
on your own infrastructure.
After you've installed Kroki, make sure to update the server URL to point to your instance.
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 33434e15c4e..41ec8cfca1d 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -7,9 +7,8 @@ type: reference, howto
# PlantUML **(FREE)**
-When the [PlantUML](https://plantuml.com) integration is enabled and configured in
-GitLab, you can create diagrams in snippets, wikis, and repositories. This integration
-is enabled on GitLab.com for all SaaS users and does not require any additional configuration.
+With the [PlantUML](https://plantuml.com) integration, you can create diagrams in snippets, wikis, and repositories.
+This integration is enabled on GitLab.com for all SaaS users and does not require any additional configuration.
To set up the integration on a self-managed instance, you must:
@@ -148,7 +147,7 @@ using Tomcat:
```
The Tomcat service should restart. After the restart is complete, the
-PlantUML service is ready and listening for requests on port 8080:
+PlantUML integration is ready and listening for requests on port 8080:
`http://localhost:8080/plantuml`
To change these defaults, edit the `/etc/tomcat8/server.xml` file.
diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md
index 34acf57ce70..f96b2c7e490 100644
--- a/doc/administration/packages/container_registry.md
+++ b/doc/administration/packages/container_registry.md
@@ -607,7 +607,7 @@ Without this configuration, the Azure storage driver uses `//` instead of `/` as
registry['storage'] = {
'azure' => {
'accountname' => 'accountname',
- 'accesskey' => 'base64encodedaccountkey',
+ 'accountkey' => 'base64encodedaccountkey',
'container' => 'containername',
'rootdirectory' => '/azure/virtual/container',
'trimlegacyrootprefix' => 'true'
diff --git a/doc/administration/postgresql/pgbouncer.md b/doc/administration/postgresql/pgbouncer.md
index 5dd0aad7162..59aac9141a4 100644
--- a/doc/administration/postgresql/pgbouncer.md
+++ b/doc/administration/postgresql/pgbouncer.md
@@ -174,10 +174,12 @@ ote_pid | tls
## Procedure for bypassing PgBouncer
+### Omnibus installations
+
Some database changes have to be done directly, and not through PgBouncer.
-Read more about the affected tasks: [database restores](../../raketasks/backup_restore.md#back-up-and-restore-for-installations-using-pgbouncer)
-and [GitLab upgrades](../../update/zero_downtime.md#postgresql).
+The main affected tasks are [database restores](../../raketasks/backup_restore.md#back-up-and-restore-for-installations-using-pgbouncer)
+and [GitLab upgrades with database migrations](../../update/zero_downtime.md#postgresql).
1. To find the primary node, run the following on a database node:
@@ -195,7 +197,7 @@ and [GitLab upgrades](../../update/zero_downtime.md#postgresql).
sudo gitlab-ctl reconfigure
```
-Once you've performed the tasks or procedure, switch back to using PgBouncer:
+After you've performed the tasks or procedure, switch back to using PgBouncer:
1. Change back `/etc/gitlab/gitlab.rb` to point to PgBouncer.
1. Run reconfigure:
@@ -204,6 +206,19 @@ Once you've performed the tasks or procedure, switch back to using PgBouncer:
sudo gitlab-ctl reconfigure
```
+### Helm chart installations
+
+High-availability deployments also need to bypass PgBouncer for the same reasons as Omnibus-based ones.
+For this type of installation:
+
+- Database backup and restore tasks are performed by the toolbox container.
+- Migration tasks are performed by the migrations container.
+
+You should override the PostgreSQL port on each subchart, so these tasks can execute and connect to PostgreSQL directly:
+
+- [Toolbox](https://gitlab.com/gitlab-org/charts/gitlab/-/blob/master/charts/gitlab/charts/toolbox/values.yaml#L40)
+- [Migrations](https://gitlab.com/gitlab-org/charts/gitlab/-/blob/master/charts/gitlab/charts/migrations/values.yaml#L46)
+
## Fine tuning
PgBouncer's default settings suit the majority of installations.
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 5a3481ee086..0859143a542 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -525,6 +525,11 @@ cases below is valid:
In any of the above cases, the response of `line`, `line_type` and `path` is
set to `null`.
+For other approaches to commenting on a merge request, see
+[Create new merge request note](notes.md#create-new-merge-request-note) in the Notes API,
+and [Create a new thread in the merge request diff](discussions.md#create-a-new-thread-in-the-merge-request-diff)
+in the Discussions API.
+
```plaintext
POST /projects/:id/repository/commits/:sha/comments
```
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
index ccef57dab7f..262064befaa 100644
--- a/doc/api/discussions.md
+++ b/doc/api/discussions.md
@@ -856,7 +856,9 @@ curl --header "PRIVATE-TOKEN: <your_access_token>"\
> The `commit id` entry was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47130) in GitLab 13.7.
Creates a new thread to a single project merge request. This is similar to creating
-a note but other comments (replies) can be added to it later.
+a note but other comments (replies) can be added to it later. For other approaches,
+see [Post comment to commit](commits.md#post-comment-to-commit) in the Commits API,
+and [Create new merge request note](notes.md#create-new-merge-request-note) in the Notes API.
```plaintext
POST /projects/:id/merge_requests/:merge_request_iid/discussions
diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md
index 0df2b90e64d..79a70bddfee 100644
--- a/doc/api/merge_request_approvals.md
+++ b/doc/api/merge_request_approvals.md
@@ -312,7 +312,7 @@ Supported attributes:
| `applies_to_all_protected_branches` | boolean | **{dotted-circle}** No | Whether the rule is applied to all protected branches. If set to `true`, the value of `protected_branch_ids` is ignored. Default is `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335316) in GitLab 15.3. |
| `group_ids` | Array | **{dotted-circle}** No | The IDs of groups as approvers. |
| `protected_branch_ids` | Array | **{dotted-circle}** No | The IDs of protected branches to scope the rule by. To identify the ID, [use the API](protected_branches.md#list-protected-branches). |
-| `report_type` | string | **{dotted-circle}** No | The report type required when the rule type is `report_approver`. The supported report types are `license_scanning` and `code_coverage`. |
+| `report_type` | string | **{dotted-circle}** No | The report type required when the rule type is `report_approver`. The supported report types are `license_scanning` [(Deprecated in GitLab 15.9)](../update/deprecations.md#license-check-and-the-policies-tab-on-the-license-compliance-page) and `code_coverage`. |
| `rule_type` | string | **{dotted-circle}** No | The type of rule. `any_approver` is a pre-configured default rule with `approvals_required` at `0`. Other rules are `regular`. |
| `user_ids` | Array | **{dotted-circle}** No | The IDs of users as approvers. |
| `usernames` | string array | **{dotted-circle}** No | The usernames for this rule. |
diff --git a/doc/api/notes.md b/doc/api/notes.md
index 9c453c6390f..66ed6b52387 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -392,8 +392,13 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
### Create new merge request note
-Creates a new note for a single merge request.
-If you create a note where the body only contains an Award Emoji, GitLab returns this object.
+Creates a new note for a single merge request. Notes are not attached to specific
+lines in a merge request. For other approaches with more granular control, see
+[Post comment to commit](commits.md#post-comment-to-commit) in the Commits API,
+and [Create a new thread in the merge request diff](discussions.md#create-a-new-thread-in-the-merge-request-diff)
+in the Discussions API.
+
+If you create a note where the body only contains an award emoji, GitLab returns this object.
```plaintext
POST /projects/:id/merge_requests/:merge_request_iid/notes
diff --git a/doc/api/suggestions.md b/doc/api/suggestions.md
index 1e1f226481c..bb1f3968cf3 100644
--- a/doc/api/suggestions.md
+++ b/doc/api/suggestions.md
@@ -11,7 +11,19 @@ This page describes the API for [suggesting changes](../user/project/merge_reque
Every API call to suggestions must be authenticated.
-## Applying a suggestion
+## Create a suggestion
+
+To create a suggestion through the API, use the Discussions API to
+[create a new thread in the merge request diff](discussions.md#create-new-merge-request-thread).
+The format for suggestions is:
+
+````markdown
+```suggestion:-3+0
+example text
+```
+````
+
+## Apply a suggestion
Applies a suggested patch in a merge request. Users must have
at least the Developer role to perform such action.
@@ -43,7 +55,7 @@ Example response:
}
```
-## Applying multiple suggestions
+## Apply multiple suggestions
```plaintext
PUT /suggestions/batch_apply
diff --git a/doc/architecture/blueprints/ci_pipeline_components/index.md b/doc/architecture/blueprints/ci_pipeline_components/index.md
index b1aee7c4217..f78cf59fca5 100644
--- a/doc/architecture/blueprints/ci_pipeline_components/index.md
+++ b/doc/architecture/blueprints/ci_pipeline_components/index.md
@@ -202,7 +202,6 @@ A component YAML file:
- Should be **validated statically** (for example: using JSON schema validators).
```yaml
----
spec:
inputs:
website:
@@ -319,7 +318,6 @@ This limitation encourages cohesion at project level and keeps complexity low.
If the component takes any input parameters they must be specified according to the following schema:
```yaml
----
spec:
inputs:
website: # by default all declared inputs are mandatory.
@@ -363,7 +361,6 @@ Input parameters are validated as soon as possible:
1. Interpolate input parameters inside the component's content.
```yaml
----
spec:
inputs:
environment:
@@ -452,7 +449,6 @@ include:
Then the configuration being included must specify the inputs by defining a specification section in the YAML:
```yaml
----
spec:
inputs:
foo:
@@ -496,7 +492,6 @@ deploy-app:
To solve the problem of `Run Pipeline` UI form we could fully leverage the `inputs` specifications:
```yaml
----
spec:
inputs:
concurrency:
diff --git a/doc/architecture/blueprints/gitlab_agent_deployments/index.md b/doc/architecture/blueprints/gitlab_agent_deployments/index.md
index 96e361d7531..0e5b5f0b248 100644
--- a/doc/architecture/blueprints/gitlab_agent_deployments/index.md
+++ b/doc/architecture/blueprints/gitlab_agent_deployments/index.md
@@ -374,6 +374,8 @@ Here is an example of GraphQL query:
lastDeployment(status: SUCCESS) {
agent {
id
+ name
+ project
kubernetesNamespace
}
}
diff --git a/doc/ci/services/index.md b/doc/ci/services/index.md
index f26751c56e7..eca4c62deb2 100644
--- a/doc/ci/services/index.md
+++ b/doc/ci/services/index.md
@@ -269,7 +269,7 @@ test:
| `entrypoint` | no | 9.4 |Command or script to execute as the container's entrypoint. It's translated to the Docker `--entrypoint` option while creating the container. The syntax is similar to [`Dockerfile`'s `ENTRYPOINT`](https://docs.docker.com/engine/reference/builder/#entrypoint) directive, where each shell token is a separate string in the array. |
| `command` | no | 9.4 |Command or script that should be used as the container's command. It's translated to arguments passed to Docker after the image's name. The syntax is similar to [`Dockerfile`'s `CMD`](https://docs.docker.com/engine/reference/builder/#cmd) directive, where each shell token is a separate string in the array. |
| `alias` (1) | no | 9.4 | Additional alias that can be used to access the service from the job's container. Read [Accessing the services](#accessing-the-services) for more information. |
-| `variables` (2) | no | 14.5 | Additional environment variables that are passed exclusively to the service. The syntax is the same as [Job Variables](../variables/index.md). |
+| `variables` (2) | no | 14.5 | Additional environment variables that are passed exclusively to the service. The syntax is the same as [Job Variables](../variables/index.md). Service variables cannot reference themselves. |
(1) Alias support for the Kubernetes executor was [introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2229) in GitLab Runner 12.8, and is only available for Kubernetes version 1.7 or later.
diff --git a/doc/ci/testing/code_quality.md b/doc/ci/testing/code_quality.md
index 4b826991bb5..ff7e11e9c71 100644
--- a/doc/ci/testing/code_quality.md
+++ b/doc/ci/testing/code_quality.md
@@ -44,6 +44,7 @@ Code Quality results are shown in the:
- Merge request widget
- Merge request changes view
- Pipeline details view
+- Project quality view
### Merge request widget
@@ -73,6 +74,12 @@ tab of the pipeline's details page.
![Code Quality Report](img/code_quality_report_13_11.png)
+### Project quality view
+
+The project quality view displays an overview of the code quality findings.
+
+![Code Quality Summary](img/code_quality_summary_15_9.png)
+
## Enable Code Quality
Prerequisites:
diff --git a/doc/ci/testing/img/code_quality_summary_15_9.png b/doc/ci/testing/img/code_quality_summary_15_9.png
new file mode 100644
index 00000000000..0586f24b22b
--- /dev/null
+++ b/doc/ci/testing/img/code_quality_summary_15_9.png
Binary files differ
diff --git a/doc/integration/datadog.md b/doc/integration/datadog.md
index 8b64e3898f9..2c86b7a8ed3 100644
--- a/doc/integration/datadog.md
+++ b/doc/integration/datadog.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/270123) in GitLab 14.1
-This integration enables you to send CI/CD pipeline and job information to
+The Datadog integration enables you to send CI/CD pipeline and job information to
[Datadog](https://www.datadoghq.com/). The [Datadog CI Visibility](https://app.datadoghq.com/ci)
product helps you monitor for job failures and performance issues, then troubleshoot them.
It's based on [Webhooks](../user/project/integrations/webhooks.md),
diff --git a/doc/integration/gmail_action_buttons_for_gitlab.md b/doc/integration/gmail_action_buttons_for_gitlab.md
index 4a233df3899..6de7e7ab17c 100644
--- a/doc/integration/gmail_action_buttons_for_gitlab.md
+++ b/doc/integration/gmail_action_buttons_for_gitlab.md
@@ -7,8 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Gmail actions **(FREE)**
GitLab supports [Google actions in email](https://developers.google.com/gmail/markup/actions/actions-overview).
-
-If correctly set up, emails that require an action are marked in Gmail.
+When you configure this integration, emails that require an action are marked in Gmail.
![Gmail actions button](img/gmail_action_buttons_for_gitlab.png)
diff --git a/doc/integration/jira/index.md b/doc/integration/jira/index.md
index 2ad71a19cf7..53c6dfe9c07 100644
--- a/doc/integration/jira/index.md
+++ b/doc/integration/jira/index.md
@@ -63,8 +63,8 @@ The authentication method in Jira depends on whether you host Jira on your own s
required. Connecting to Jira Server using the Central Authentication Service (CAS) is not possible. For more information, read
how to [set up a user in Jira Server](jira_server_configuration.md).
- **Jira on Atlassian cloud** supports authentication through an API token. When connecting to Jira on
- Atlassian cloud, an email and API token are required. For more information, read
- [create an API token for Jira in Atlassian cloud](jira_cloud_configuration.md).
+ Atlassian cloud, an email and API token are required. For more information, see
+ [Create a Jira Cloud API token](jira_cloud_configuration.md).
## Privacy considerations
diff --git a/doc/integration/jira/issues.md b/doc/integration/jira/issues.md
index 3a5d8e66b2d..4e76cc4e606 100644
--- a/doc/integration/jira/issues.md
+++ b/doc/integration/jira/issues.md
@@ -6,8 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Jira integration issue management **(FREE)**
-Integrating issue management with Jira requires you to [configure Jira](index.md#jira-integration)
-and [enable the Jira integration](configure.md) in GitLab.
+To integrate issue management with Jira, [configure Jira](index.md#jira-integration)
+and [enable the integration](configure.md) in GitLab.
After you configure and enable the integration, you can reference and close Jira
issues by mentioning the Jira ID in GitLab commits and merge requests.
diff --git a/doc/integration/trello_power_up.md b/doc/integration/trello_power_up.md
index 9cca8e5485d..908fc623d0e 100644
--- a/doc/integration/trello_power_up.md
+++ b/doc/integration/trello_power_up.md
@@ -6,14 +6,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Trello Power-Ups **(FREE)**
-You can use the Trello Power-Up for GitLab to attach
+You can use Trello Power-Ups for GitLab to attach
GitLab merge requests to Trello cards.
-![GitLab Trello PowerUp - Trello card](img/trello_card_with_gitlab_powerup.png)
+![GitLab Trello Power-Ups - Trello card](img/trello_card_with_gitlab_powerup.png)
-## Configure the Power-Up
+## Configure Power-Ups
-To configure a Power-Up for a Trello board:
+To configure Power-Ups for a Trello board:
1. Go to your Trello board.
1. Select **Power-Ups** and find the **GitLab** row.
diff --git a/doc/operations/metrics/index.md b/doc/operations/metrics/index.md
index 11350d65237..08cea94c189 100644
--- a/doc/operations/metrics/index.md
+++ b/doc/operations/metrics/index.md
@@ -124,7 +124,7 @@ After saving them, they display on the environment metrics dashboard provided th
- A [connected Kubernetes cluster](../../user/clusters/agent/index.md)
with the matching [environment scope](../../ci/environments/index.md#limit-the-environment-scope-of-a-cicd-variable) is used and
- [Prometheus installed on the cluster](../../user/project/integrations/prometheus.md#enabling-prometheus-integration).
+ [Prometheus installed on the cluster](../../user/project/integrations/prometheus.md#enabling-the-prometheus-integration).
- Prometheus is [manually configured](../../user/project/integrations/prometheus.md#manual-configuration-of-prometheus).
![Add New Metric](img/prometheus_add_metric.png)
diff --git a/doc/raketasks/generate_sample_prometheus_data.md b/doc/raketasks/generate_sample_prometheus_data.md
index 7445065c77e..73c49bd2599 100644
--- a/doc/raketasks/generate_sample_prometheus_data.md
+++ b/doc/raketasks/generate_sample_prometheus_data.md
@@ -4,9 +4,9 @@ group: Respond
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Generate sample Prometheus data Rake task **(FREE SELF)**
+# Sample Prometheus data Rake task **(FREE SELF)**
-This command runs Prometheus queries for each of the metrics of a specific environment
+The Rake task runs Prometheus queries for each of the metrics of a specific environment
for a series of time intervals to now:
- 30 minutes
@@ -16,12 +16,12 @@ for a series of time intervals to now:
- 72 hours
- 7 days
-The results of each of query are stored under a `sample_metrics` directory as a YAML
+The results of each query are stored under a `sample_metrics` directory as a YAML
file named by the metric's `identifier`. When the environmental variable `USE_SAMPLE_METRICS`
-is set, the Prometheus API query is re-routed to `Projects::Environments::SampleMetricsController`
-which loads the appropriate data set if it is present within the `sample_metrics` directory.
+is set, the Prometheus API query is re-routed to `Projects::Environments::SampleMetricsController`,
+which loads the appropriate data set if it's present in the `sample_metrics` directory.
-This command requires an ID from an environment with an available Prometheus installation.
+The Rake task requires an ID from an environment with an available Prometheus installation.
## Example
diff --git a/doc/user/admin_area/settings/external_authorization.md b/doc/user/admin_area/settings/external_authorization.md
index 94d9ec73640..ab6c5ee4096 100644
--- a/doc/user/admin_area/settings/external_authorization.md
+++ b/doc/user/admin_area/settings/external_authorization.md
@@ -43,9 +43,6 @@ using Omnibus, learn to install a custom CA in the
Alternatively, learn where to install custom certificates by using
`openssl version -d`.
-When external authorization is enabled, [deploy tokens](../../project/deploy_tokens/index.md)
- and [deploy keys](../../project/deploy_keys/index.md) can't be used for Git operations.
-
## Configuration
The external authorization service can be enabled by an administrator:
@@ -56,6 +53,26 @@ The external authorization service can be enabled by an administrator:
1. Complete the fields.
1. Select **Save changes**.
+### Allow external authorization with deploy tokens and deploy keys
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386656) in GitLab 15.9.
+
+You can set your instance to allow external authorization for Git operations with
+[deploy tokens](../../project/deploy_tokens/index.md) or [deploy keys](../../project/deploy_keys/index.md).
+
+Prerequisites:
+
+- You must be using classification labels without a service URL for external authorization.
+
+To allow authorization with deploy tokens and keys:
+
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **External authorization**, and:
+ - Leave the service URL field empty.
+ - Select **Allow deploy tokens and deploy keys to be used with external authorization**.
+1. Select **Save changes**.
+
## How it works
When GitLab requests access, it sends a JSON POST request to the external
diff --git a/doc/user/clusters/agent/gitops/flux.md b/doc/user/clusters/agent/gitops/flux.md
new file mode 100644
index 00000000000..9a3537aacbf
--- /dev/null
+++ b/doc/user/clusters/agent/gitops/flux.md
@@ -0,0 +1,36 @@
+---
+stage: Configure
+group: Configure
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Flux (Beta) **(FREE)**
+
+Flux is a GitOps tool that helps you manage your Kubernetes clusters.
+You can use Flux to:
+
+- Keep your clusters in sync with your Git repositories.
+- Reconcile code changes with your deployments.
+- Manage your Flux installation itself with a bootstrap.
+
+To get started, see the [Flux installation documentation](https://fluxcd.io/flux/installation).
+
+Support for Flux is in [Open Beta](../../../../policy/alpha-beta-support.md#beta-features).
+
+## Bootstrap installation
+
+Use the Flux command [`bootstrap gitlab`](https://fluxcd.io/flux/installation/#gitlab-and-gitlab-enterprise)
+to configure a Kubernetes cluster to manage itself from a Git repository.
+
+You must authenticate your installation with either:
+
+- Recommended. [A project access token](../../../project/settings/project_access_tokens.md).
+- A [group access token](../../../group/settings/group_access_tokens.md).
+- A [personal access token](../../../profile/personal_access_tokens.md).
+
+Some Flux features like [automated image updates](https://fluxcd.io/flux/guides/image-update/) require
+write access to the source repositories.
+
+## GitOps repository structure
+
+You should organize your repositories to meet the needs of your team. For detailed recommendations, see the Flux [repository structure documentation](https://fluxcd.io/flux/guides/repository-structure/).
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index a84d16e6d0c..90a45d85c49 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -389,7 +389,7 @@ Without the `config.extend_remember_period` flag, you would be forced to sign in
- [Change your password](user_passwords.md)
- Receive emails for:
- [Sign-ins from unknown IP addresses or devices](notifications.md#notifications-for-unknown-sign-ins)
- - [Attempted sign-ins using wrong two-factor authentication codes](notifications.md#notifications-for-attempted-sign-in-using-wrong-two-factor-authentication-codes)
+ - [Attempted sign-ins using incorrect verification codes](notifications.md#notifications-for-attempted-sign-ins-using-incorrect-verification-codes)
- Manage applications that can [use GitLab as an OAuth provider](../../integration/oauth_provider.md)
- Manage [personal access tokens](personal_access_tokens.md) to access your account via API and authorized applications
- Manage [SSH keys](../ssh.md) to access your account via SSH
diff --git a/doc/user/profile/notifications.md b/doc/user/profile/notifications.md
index dcc78dac05b..9e6e9984c15 100644
--- a/doc/user/profile/notifications.md
+++ b/doc/user/profile/notifications.md
@@ -306,7 +306,7 @@ GitLab uses several methods to identify a known sign-in. All methods must fail f
- Cookie: After successful sign in, an encrypted cookie is stored in the browser.
This cookie is set to expire 14 days after the last successful sign in.
-## Notifications for attempted sign-in using wrong two-factor authentication codes
+## Notifications for attempted sign-ins using incorrect verification codes
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/374740) in GitLab 15.5.
diff --git a/doc/user/project/integrations/apple_app_store.md b/doc/user/project/integrations/apple_app_store.md
index 1b41dd0b669..97ecffee434 100644
--- a/doc/user/project/integrations/apple_app_store.md
+++ b/doc/user/project/integrations/apple_app_store.md
@@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `apple_app_store_integration`. On GitLab.com, this feature is not available.
-The Apple App Store integration makes it easy to configure your CI/CD pipelines to connect to [App Store Connect](https://appstoreconnect.apple.com) to build and release apps for iOS, iPadOS, macOS, tvOS, and watchOS.
+With the Apple App Store integration, you can configure your CI/CD pipelines to connect to [App Store Connect](https://appstoreconnect.apple.com) to build and release apps for iOS, iPadOS, macOS, tvOS, and watchOS.
The integration is designed to be able to work out of the box with [fastlane](http://fastlane.tools/), but can be used with other build tools as well.
diff --git a/doc/user/project/integrations/asana.md b/doc/user/project/integrations/asana.md
index 8bc1a984e3d..fac09e7f071 100644
--- a/doc/user/project/integrations/asana.md
+++ b/doc/user/project/integrations/asana.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Asana **(FREE)**
-This integration adds commit messages as comments to Asana tasks.
+The Asana integration adds commit messages as comments to Asana tasks.
Once enabled, commit messages are checked for Asana task URLs (for example,
`https://app.asana.com/0/123456/987654`) or task IDs starting with `#`
(for example, `#987654`). Every task ID found gets the commit comment added to it.
diff --git a/doc/user/project/integrations/ewm.md b/doc/user/project/integrations/ewm.md
index c2371d32853..42f0ec6b0de 100644
--- a/doc/user/project/integrations/ewm.md
+++ b/doc/user/project/integrations/ewm.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Engineering Workflow Management (EWM) **(FREE)**
-This integration allows you to go from GitLab to EWM work items mentioned in merge request
+The EWM integration allows you to go from GitLab to EWM work items mentioned in merge request
descriptions and commit messages.
Each work item reference is automatically converted to a link to the work item.
diff --git a/doc/user/project/integrations/github.md b/doc/user/project/integrations/github.md
index 990d0839581..3b5e55b48a1 100644
--- a/doc/user/project/integrations/github.md
+++ b/doc/user/project/integrations/github.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitHub **(PREMIUM)**
You can update GitHub with pipeline status updates from GitLab.
-This integration can help you if you use GitLab for CI/CD.
+The GitHub integration can help you if you use GitLab for CI/CD.
![Pipeline status update on GitHub](img/github_status_check_pipeline_update.png)
diff --git a/doc/user/project/integrations/hangouts_chat.md b/doc/user/project/integrations/hangouts_chat.md
index 3537033902d..9aee2684ed4 100644
--- a/doc/user/project/integrations/hangouts_chat.md
+++ b/doc/user/project/integrations/hangouts_chat.md
@@ -6,8 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Google Chat **(FREE)**
-Integrate your project to send notifications from GitLab to a
-room of your choice in [Google Chat](https://chat.google.com/) (former Google
+You can configure your project to send notifications from GitLab to a
+room of your choice in [Google Chat](https://chat.google.com/) (formerly Google
Hangouts).
## Integration workflow
diff --git a/doc/user/project/integrations/harbor.md b/doc/user/project/integrations/harbor.md
index 596821ba12b..e316f6fbd9e 100644
--- a/doc/user/project/integrations/harbor.md
+++ b/doc/user/project/integrations/harbor.md
@@ -8,11 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80999) in GitLab 14.9.
-Use Harbor as the container registry for your GitLab project.
+You can use Harbor as the container registry for your GitLab project.
-[Harbor](https://goharbor.io/) is an open source registry that can help you manage artifacts across cloud-native compute platforms, like Kubernetes and Docker.
+[Harbor](https://goharbor.io/) is an open-source registry that can help you manage artifacts across cloud-native compute platforms like Kubernetes and Docker.
-This integration can help you if you need GitLab CI/CD and a container image repository.
+The Harbor integration can help you if you need GitLab CI/CD and a container image repository.
## Prerequisites
diff --git a/doc/user/project/integrations/irker.md b/doc/user/project/integrations/irker.md
index 23525c33e84..757d15e71b3 100644
--- a/doc/user/project/integrations/irker.md
+++ b/doc/user/project/integrations/irker.md
@@ -6,8 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# irker (IRC gateway) **(FREE)**
-GitLab provides a way to push update messages to an irker server. When
-configured, pushes to a project trigger the integration to send data directly
+GitLab provides a way to push update messages to an irker server. After you configure
+the integration, each push to a project triggers the integration to send data directly
to the irker server.
See also the [irker integration API documentation](../../../api/integrations.md).
diff --git a/doc/user/project/integrations/mock_ci.md b/doc/user/project/integrations/mock_ci.md
index ae1737f8d3f..cbe073485e0 100644
--- a/doc/user/project/integrations/mock_ci.md
+++ b/doc/user/project/integrations/mock_ci.md
@@ -9,12 +9,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
NOTE:
This integration only appears if you're in a [development environment](https://gitlab.com/gitlab-org/gitlab-mock-ci-service#setup-mockci-integration).
-To set up the mock CI service server, respond to the following endpoints
+To set up the mock CI service server, respond to the following endpoints:
- `commit_status`: `#{project.namespace.path}/#{project.path}/status/#{sha}.json`
- - Have your service return `200 { status: ['failed'|'canceled'|'running'|'pending'|'success'|'success-with-warnings'|'skipped'|'not_found'] }`
- - If the service returns a 404, it is interpreted as `pending`
+ - Have your service return `200 { status: ['failed'|'canceled'|'running'|'pending'|'success'|'success-with-warnings'|'skipped'|'not_found'] }`.
+ - If the service returns a 404, the service is interpreted as `pending`.
- `build_page`: `#{project.namespace.path}/#{project.path}/status/#{sha}`
- - Just where the build is linked to, doesn't matter if implemented
+ - Where the build is linked to (whether or not it's implemented).
-For an example of a mock CI server, see [`gitlab-org/gitlab-mock-ci-service`](https://gitlab.com/gitlab-org/gitlab-mock-ci-service)
+For an example of a mock CI server, see [`gitlab-org/gitlab-mock-ci-service`](https://gitlab.com/gitlab-org/gitlab-mock-ci-service).
diff --git a/doc/user/project/integrations/pivotal_tracker.md b/doc/user/project/integrations/pivotal_tracker.md
index 034be8ab3d8..c794001672b 100644
--- a/doc/user/project/integrations/pivotal_tracker.md
+++ b/doc/user/project/integrations/pivotal_tracker.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Pivotal Tracker **(FREE)**
-This integration adds commit messages as comments to Pivotal Tracker stories.
+The Pivotal Tracker integration adds commit messages as comments to Pivotal Tracker stories.
Once enabled, commit messages are checked for square brackets containing a hash mark followed by
the story ID (for example, `[#555]`). Every story ID found gets the commit comment added to it.
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index cd92e49cada..80c6337f934 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -23,7 +23,7 @@ Once enabled, GitLab detects metrics from known services in the
[add your own metrics](../../../operations/metrics/index.md#adding-custom-metrics) and create
[custom dashboards](../../../operations/metrics/dashboards/index.md).
-## Enabling Prometheus Integration
+## Enabling the Prometheus integration
### Prometheus cluster integration
diff --git a/doc/user/project/integrations/redmine.md b/doc/user/project/integrations/redmine.md
index 0a399d3481f..97c3e14dd9d 100644
--- a/doc/user/project/integrations/redmine.md
+++ b/doc/user/project/integrations/redmine.md
@@ -6,8 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Redmine **(FREE)**
-Use [Redmine](https://www.redmine.org/) as the issue tracker.
-
+You can use [Redmine](https://www.redmine.org/) as an external issue tracker.
To enable the Redmine integration in a project:
1. On the top bar, select **Main menu > Projects** and find your project.
diff --git a/doc/user/project/integrations/slack_slash_commands.md b/doc/user/project/integrations/slack_slash_commands.md
index 2563cec2b05..f9b95a0dd0c 100644
--- a/doc/user/project/integrations/slack_slash_commands.md
+++ b/doc/user/project/integrations/slack_slash_commands.md
@@ -15,7 +15,7 @@ working in Slack, you can use Slack slash commands.
To use Slack slash commands, you must configure both Slack and GitLab.
GitLab can also send events (for example, `issue created`) to Slack as notifications.
-The [Slack notifications service](slack.md) is configured separately.
+The [Slack notifications integration](slack.md) is configured separately.
## Configure GitLab and Slack
diff --git a/doc/user/project/integrations/unify_circuit.md b/doc/user/project/integrations/unify_circuit.md
index d465b4e50f0..9c38cec0a01 100644
--- a/doc/user/project/integrations/unify_circuit.md
+++ b/doc/user/project/integrations/unify_circuit.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
The Unify Circuit integration sends notifications from GitLab to a Circuit conversation.
-## Set up Unify Circuit service
+## Set up Unify Circuit
In Unify Circuit, [add a webhook](https://www.circuit.com/unifyportalfaqdetail?articleId=164448) and
copy its URL.
diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb
index bdc9f975970..184690f9979 100644
--- a/lib/api/terraform/state.rb
+++ b/lib/api/terraform/state.rb
@@ -28,18 +28,16 @@ module API
increment_unique_values('p_terraform_state_api_unique_users', current_user.id)
- if Feature.enabled?(:route_hll_to_snowplow_phase2, user_project&.namespace)
- Gitlab::Tracking.event(
- 'API::Terraform::State',
- 'terraform_state_api_request',
- namespace: user_project&.namespace,
- user: current_user,
- project: user_project,
- label: 'redis_hll_counters.terraform.p_terraform_state_api_unique_users_monthly',
- context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
- event: 'p_terraform_state_api_unique_users').to_context]
- )
- end
+ Gitlab::Tracking.event(
+ 'API::Terraform::State',
+ 'terraform_state_api_request',
+ namespace: user_project&.namespace,
+ user: current_user,
+ project: user_project,
+ label: 'redis_hll_counters.terraform.p_terraform_state_api_unique_users_monthly',
+ context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
+ event: 'p_terraform_state_api_unique_users').to_context]
+ )
end
params do
diff --git a/lib/gitlab/database/schema_validation/database.rb b/lib/gitlab/database/schema_validation/database.rb
index dfc845f0b44..15f003a1b0c 100644
--- a/lib/gitlab/database/schema_validation/database.rb
+++ b/lib/gitlab/database/schema_validation/database.rb
@@ -16,6 +16,10 @@ module Gitlab
index_map.values
end
+ def index_exists?(index_name)
+ index_map[index_name].present?
+ end
+
private
def index_map
diff --git a/lib/gitlab/database/schema_validation/runner.rb b/lib/gitlab/database/schema_validation/runner.rb
new file mode 100644
index 00000000000..a96f5a5b4c2
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/runner.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ class Runner
+ def initialize(structure_sql, database)
+ @structure_sql = structure_sql
+ @database = database
+ end
+
+ def execute
+ validator_classes = Validators::BaseValidator.all_validators
+
+ validator_classes.flat_map { |c| c.new(structure_sql, database).execute }
+ end
+
+ private
+
+ attr_reader :structure_sql, :database
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/structure_sql.rb b/lib/gitlab/database/schema_validation/structure_sql.rb
index 32c69a0e5e7..306cc22f9f5 100644
--- a/lib/gitlab/database/schema_validation/structure_sql.rb
+++ b/lib/gitlab/database/schema_validation/structure_sql.rb
@@ -8,6 +8,10 @@ module Gitlab
@structure_file_path = structure_file_path
end
+ def index_exists?(index_name)
+ indexes.find { |index| index.name == index_name }.present?
+ end
+
def indexes
@indexes ||= index_statements.map do |index_statement|
index_statement.relation.schemaname = "public" if index_statement.relation.schemaname == ''
diff --git a/lib/gitlab/database/schema_validation/validators/base_validator.rb b/lib/gitlab/database/schema_validation/validators/base_validator.rb
new file mode 100644
index 00000000000..2478d446e43
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/base_validator.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class BaseValidator
+ Inconsistency = Struct.new(:name, :statement)
+
+ def initialize(structure_sql, database)
+ @structure_sql = structure_sql
+ @database = database
+ end
+
+ def self.all_validators
+ [
+ ExtraIndexes,
+ MissingIndexes,
+ WrongIndexes
+ ]
+ end
+
+ def execute
+ raise NoMethodError, "subclasses of #{self.class.name} must implement #{__method__}"
+ end
+
+ private
+
+ attr_reader :structure_sql, :database
+
+ def build_inconsistency(schema_object)
+ Inconsistency.new(schema_object.name, schema_object.statement)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/extra_indexes.rb b/lib/gitlab/database/schema_validation/validators/extra_indexes.rb
new file mode 100644
index 00000000000..023052459ff
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/extra_indexes.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class ExtraIndexes < BaseValidator
+ def execute
+ database.indexes.filter_map do |index|
+ next if structure_sql.index_exists?(index.name)
+
+ build_inconsistency(index)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/missing_indexes.rb b/lib/gitlab/database/schema_validation/validators/missing_indexes.rb
new file mode 100644
index 00000000000..890c00c58c9
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/missing_indexes.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class MissingIndexes < BaseValidator
+ def execute
+ structure_sql.indexes.filter_map do |index|
+ next if database.index_exists?(index.name)
+
+ build_inconsistency(index)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/wrong_indexes.rb b/lib/gitlab/database/schema_validation/validators/wrong_indexes.rb
new file mode 100644
index 00000000000..a92e7158be7
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/wrong_indexes.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class WrongIndexes < BaseValidator
+ def execute
+ structure_sql.indexes.filter_map do |structure_sql_index|
+ database_index = database.fetch_index_by_name(structure_sql_index.name)
+
+ next if database_index.nil?
+ next if database_index.statement == structure_sql_index.statement
+
+ build_inconsistency(structure_sql_index)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/observability.rb b/lib/gitlab/observability.rb
index 8dbd2f41ccb..853eecc946f 100644
--- a/lib/gitlab/observability.rb
+++ b/lib/gitlab/observability.rb
@@ -4,6 +4,13 @@ module Gitlab
module Observability
module_function
+ ACTION_TO_PERMISSION = {
+ explore: :read_observability,
+ datasources: :admin_observability,
+ manage: :admin_observability,
+ dashboards: :read_observability
+ }.freeze
+
def observability_url
return ENV['OVERRIDE_OBSERVABILITY_URL'] if ENV['OVERRIDE_OBSERVABILITY_URL']
# TODO Make observability URL configurable https://gitlab.com/gitlab-org/opstrace/opstrace-ui/-/issues/80
@@ -12,8 +19,36 @@ module Gitlab
'https://observe.gitlab.com'
end
- def observability_enabled?(user, group)
- Gitlab::Observability.observability_url.present? && Ability.allowed?(user, :read_observability, group)
+ def valid_observability_url?(url)
+ uri = URI.parse(url)
+ observability_uri = URI.parse(Gitlab::Observability.observability_url)
+
+ uri.scheme == observability_uri.scheme &&
+ uri.port == observability_uri.port &&
+ uri.host.casecmp?(observability_uri.host)
+
+ rescue URI::InvalidURIError
+ false
+ end
+
+ def group_id_from_url(url)
+ return unless valid_observability_url?(url)
+
+ group_id = URI.parse(url).path.split('/')[1]
+ group_id.to_i unless group_id.to_i <= 0
+ end
+
+ def allowed_for_action?(user, group, action)
+ return false if action.nil?
+
+ permission = ACTION_TO_PERMISSION.fetch(action.to_sym, :admin_observability)
+ allowed?(user, group, permission)
+ end
+
+ def allowed?(user, group, permission = :admin_observability)
+ return false unless group && user
+
+ Gitlab::Observability.observability_url.present? && Ability.allowed?(user, permission, group)
end
end
end
diff --git a/lib/gitlab/usage_data_counters/editor_unique_counter.rb b/lib/gitlab/usage_data_counters/editor_unique_counter.rb
index 2aebc1b8813..4e4a01ed301 100644
--- a/lib/gitlab/usage_data_counters/editor_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/editor_unique_counter.rb
@@ -38,18 +38,16 @@ module Gitlab
def track_unique_action(event_name, author, time, project = nil)
return unless author
- if Feature.enabled?(:route_hll_to_snowplow_phase2)
- Gitlab::Tracking.event(
- name,
- 'ide_edit',
- property: event_name.to_s,
- project: project,
- namespace: project&.namespace,
- user: author,
- label: 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit',
- context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context]
- )
- end
+ Gitlab::Tracking.event(
+ name,
+ 'ide_edit',
+ property: event_name.to_s,
+ project: project,
+ namespace: project&.namespace,
+ user: author,
+ label: 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit',
+ context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context]
+ )
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: author.id, time: time)
end
diff --git a/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
index a59ea36961d..c0d1af8a43a 100644
--- a/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
@@ -180,7 +180,6 @@ module Gitlab
private
def track_snowplow_action(event_name, author, project)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, project.namespace)
return unless author
Gitlab::Tracking.event(
diff --git a/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
index c8768164710..fceeacb60ca 100644
--- a/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
@@ -68,8 +68,6 @@ module Gitlab
track_unique_action_by_merge_request(MR_CREATE_ACTION, merge_request)
project = merge_request.target_project
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, project.namespace)
-
Gitlab::Tracking.event(
name,
:create,
@@ -99,8 +97,6 @@ module Gitlab
track_unique_action_by_user(MR_APPROVE_ACTION, user)
project = merge_request.target_project
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, project.namespace)
-
Gitlab::Tracking.event(
name,
:approve,
diff --git a/lib/sidebars/groups/menus/observability_menu.rb b/lib/sidebars/groups/menus/observability_menu.rb
index d85efb1a002..0a5171eccfe 100644
--- a/lib/sidebars/groups/menus/observability_menu.rb
+++ b/lib/sidebars/groups/menus/observability_menu.rb
@@ -6,8 +6,11 @@ module Sidebars
class ObservabilityMenu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
- add_item(explore_menu_item)
- add_item(datasources_menu_item)
+ add_item(explore_menu_item) if Gitlab::Observability.allowed_for_action?(context.current_user, context.group,
+ :explore)
+
+ add_item(datasources_menu_item) if Gitlab::Observability.allowed_for_action?(context.current_user,
+ context.group, :datasources)
end
override :title
@@ -22,7 +25,7 @@ module Sidebars
override :render?
def render?
- Gitlab::Observability.observability_enabled?(context.current_user, context.group)
+ Gitlab::Observability.allowed_for_action?(context.current_user, context.group, :explore)
end
private
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 8dfbd84bb2c..8391c00bc60 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -5679,7 +5679,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -15805,7 +15805,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+msgid "Enter the code from your two-factor authenticator app. If you've lost your device, you can enter one of your recovery codes."
msgstr ""
msgid "Enter the following to confirm:"
@@ -15823,6 +15823,9 @@ msgstr ""
msgid "Enter the username for password-protected Elasticsearch servers."
msgstr ""
+msgid "Enter verification code"
+msgstr ""
+
msgid "Enter your Packagist server. Defaults to https://packagist.org."
msgstr ""
@@ -18939,6 +18942,12 @@ msgstr ""
msgid "GitLab commit"
msgstr ""
+msgid "GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code"
+msgstr ""
+
+msgid "GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code from the following IP address: %{ip}, at %{time}"
+msgstr ""
+
msgid "GitLab documentation"
msgstr ""
@@ -21343,7 +21352,7 @@ msgstr ""
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr ""
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email."
+msgid "If you recently tried to sign in, but mistakenly entered an incorrect verification code, you can ignore this email."
msgstr ""
msgid "If you want to re-enable two-factor authentication, visit %{two_factor_link}"
@@ -30844,9 +30853,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -33322,9 +33328,21 @@ msgstr ""
msgid "ProjectQualitySummary|An error occurred while trying to fetch project quality statistics"
msgstr ""
+msgid "ProjectQualitySummary|Analysis of your source code's quality and complexity."
+msgstr ""
+
+msgid "ProjectQualitySummary|Blocker"
+msgstr ""
+
+msgid "ProjectQualitySummary|Code quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Coverage"
msgstr ""
+msgid "ProjectQualitySummary|Critical"
+msgstr ""
+
msgid "ProjectQualitySummary|Failure"
msgstr ""
@@ -33337,6 +33355,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33379,6 +33400,12 @@ msgstr ""
msgid "ProjectQualitySummary|This page helps you understand the code testing trends for your project. Let us know how we can improve it!"
msgstr ""
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
+
msgid "ProjectSelect|No matching results"
msgstr ""
@@ -40112,6 +40139,9 @@ msgstr ""
msgid "Slack logo"
msgstr ""
+msgid "Slack notifications integration is deprecated"
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
@@ -42614,6 +42644,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr ""
+msgid "The Slack notifications integration is deprecated and will be removed in a future release. To continue to receive notifications from Slack, use the GitLab for Slack app instead. %{learn_more_link_start}Learn more%{link_end}."
+msgstr ""
+
msgid "The Snowplow cookie domain."
msgstr ""
@@ -45259,9 +45292,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -47625,12 +47655,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
diff --git a/package.json b/package.json
index 7b4eb71fe99..d6d25b018d4 100644
--- a/package.json
+++ b/package.json
@@ -121,7 +121,7 @@
"dateformat": "^5.0.1",
"deckar01-task_list": "^2.3.1",
"diff": "^3.4.0",
- "dompurify": "^2.4.3",
+ "dompurify": "^2.4.4",
"dropzone": "^4.2.0",
"editorconfig": "^0.15.3",
"emoji-regex": "^10.0.0",
@@ -225,7 +225,7 @@
"cheerio": "^1.0.0-rc.9",
"commander": "^2.20.3",
"custom-jquery-matchers": "^2.1.0",
- "eslint": "8.32.0",
+ "eslint": "8.34.0",
"eslint-import-resolver-jest": "3.0.2",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-import": "^2.27.5",
diff --git a/rubocop/cop/gitlab/feature_available_usage.rb b/rubocop/cop/gitlab/feature_available_usage.rb
index fcf4992a19d..df4409c27e0 100644
--- a/rubocop/cop/gitlab/feature_available_usage.rb
+++ b/rubocop/cop/gitlab/feature_available_usage.rb
@@ -39,7 +39,7 @@ module RuboCop
return if feature_name(node).nil?
return if ALL_FEATURES.include?(feature_name(node)) && args_count(node) == 2
- if !ALL_FEATURES.include?(feature_name(node))
+ if !ALL_FEATURES.include?(feature_name(node)) # rubocop:disable Rails/NegateInclude
add_offense(node, message: licensed_feature_message(node))
elsif args_count(node) < 2
add_offense(node, message: NOT_ENOUGH_ARGS_MSG)
diff --git a/rubocop/cop/graphql/id_type.rb b/rubocop/cop/graphql/id_type.rb
index eb677aa4507..c9d9b4ea6eb 100644
--- a/rubocop/cop/graphql/id_type.rb
+++ b/rubocop/cop/graphql/id_type.rb
@@ -21,7 +21,7 @@ module RuboCop
private
def does_not_match?(arg)
- !WHITELISTED_ARGUMENTS.include?(arg)
+ !WHITELISTED_ARGUMENTS.include?(arg) # rubocop:disable Rails/NegateInclude
end
end
end
diff --git a/rubocop/cop/migration/add_reference.rb b/rubocop/cop/migration/add_reference.rb
index 02a0ef899b4..8daa85749fd 100644
--- a/rubocop/cop/migration/add_reference.rb
+++ b/rubocop/cop/migration/add_reference.rb
@@ -41,7 +41,7 @@ module RuboCop
private
def existing_table?(new_tables, table)
- !new_tables.include?(table)
+ !new_tables.include?(table) # rubocop:disable Rails/NegateInclude
end
def create_table?(node)
diff --git a/rubocop/cop/rspec/factory_bot/inline_association.rb b/rubocop/cop/rspec/factory_bot/inline_association.rb
index 8d7c73b99a0..acd2c10a63d 100644
--- a/rubocop/cop/rspec/factory_bot/inline_association.rb
+++ b/rubocop/cop/rspec/factory_bot/inline_association.rb
@@ -99,7 +99,7 @@ module RuboCop
def inside_assocation_definition?(node)
node.each_ancestor(:block).any? do |parent|
name = association_definition(parent)
- name && !SKIP_NAMES.include?(name)
+ name && !SKIP_NAMES.include?(name) # rubocop:disable Rails/NegateInclude
end
end
end
diff --git a/spec/controllers/admin/cohorts_controller_spec.rb b/spec/controllers/admin/cohorts_controller_spec.rb
index 50626a5da91..26f6540258e 100644
--- a/spec/controllers/admin/cohorts_controller_spec.rb
+++ b/spec/controllers/admin/cohorts_controller_spec.rb
@@ -17,7 +17,6 @@ RSpec.describe Admin::CohortsController do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject { get :index }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' }
diff --git a/spec/controllers/admin/dev_ops_report_controller_spec.rb b/spec/controllers/admin/dev_ops_report_controller_spec.rb
index 52a46b5e99a..d8166380760 100644
--- a/spec/controllers/admin/dev_ops_report_controller_spec.rb
+++ b/spec/controllers/admin/dev_ops_report_controller_spec.rb
@@ -32,7 +32,6 @@ RSpec.describe Admin::DevOpsReportController do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject { get :show, format: :html }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' }
diff --git a/spec/controllers/admin/usage_trends_controller_spec.rb b/spec/controllers/admin/usage_trends_controller_spec.rb
index 87cf8988b4e..7b801d53f14 100644
--- a/spec/controllers/admin/usage_trends_controller_spec.rb
+++ b/spec/controllers/admin/usage_trends_controller_spec.rb
@@ -17,7 +17,6 @@ RSpec.describe Admin::UsageTrendsController do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject { get :index }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' }
diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb
index 2ad2189c020..4ff8c21706b 100644
--- a/spec/controllers/projects/cycle_analytics_controller_spec.rb
+++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb
@@ -31,7 +31,6 @@ RSpec.describe Projects::CycleAnalyticsController do
subject { get :show, params: request_params, format: :html }
let(:request_params) { { namespace_id: project.namespace, project_id: project } }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:namespace) { project.namespace }
diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb
index 1e9d999311a..3e5bcbbc9ba 100644
--- a/spec/controllers/projects/graphs_controller_spec.rb
+++ b/spec/controllers/projects/graphs_controller_spec.rb
@@ -141,7 +141,6 @@ RSpec.describe Projects::GraphsController do
end
let(:request_params) { { namespace_id: project.namespace.path, project_id: project.path, id: 'master' } }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:namespace) { project.namespace }
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index d41848c1231..5ff4d37e2f4 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -819,7 +819,6 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
subject { get :charts, params: request_params, format: :html }
let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:namespace) { project.namespace }
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 6f8d059780c..ff24b754d7a 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -231,7 +231,6 @@ RSpec.describe SearchController, feature_category: :global_search do
end
let(:namespace) { create(:group) }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
context 'on restricted projects' do
@@ -427,6 +426,15 @@ RSpec.describe SearchController, feature_category: :global_search do
get :autocomplete, params: { term: 'setting', filter: 'generic' }
end
+
+ it 'sets correct cache control headers' do
+ get :autocomplete, params: { term: 'setting', filter: 'generic' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(response.headers['Cache-Control']).to eq('max-age=60, private')
+ expect(response.headers['Pragma']).to be_nil
+ end
end
describe '#append_info_to_payload' do
diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb
index 393721fe451..533fcb9ba46 100644
--- a/spec/features/admin/admin_mode/login_spec.rb
+++ b/spec/features/admin/admin_mode/login_spec.rb
@@ -25,13 +25,13 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
it 'blocks login if we reuse the same code immediately' do
gitlab_sign_in(user, remember: true)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
repeated_otp = user.current_otp
enter_code(repeated_otp)
gitlab_enable_admin_mode_sign_in(user)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
enter_code(repeated_otp)
@@ -43,12 +43,12 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
before do
gitlab_sign_in(user, remember: true)
- expect(page).to have_content('Two-factor authentication code')
+ expect(page).to have_content('Enter verification code')
enter_code(user.current_otp)
gitlab_enable_admin_mode_sign_in(user)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
end
it 'allows login with valid code' do
@@ -145,11 +145,11 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
it 'signs user in without prompting for second factor' do
sign_in_using_saml!
- expect(page).not_to have_content('Two-Factor Authentication')
+ expect(page).not_to have_content(_('Enter verification code'))
enable_admin_mode_using_saml!
- expect(page).not_to have_content('Two-Factor Authentication')
+ expect(page).not_to have_content(_('Enter verification code'))
expect(page).to have_current_path admin_root_path, ignore_query: true
expect(page).to have_content('Admin mode enabled')
end
@@ -159,12 +159,12 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
it 'shows 2FA prompt after omniauth login' do
sign_in_using_saml!
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
enter_code(user.current_otp)
enable_admin_mode_using_saml!
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
# Cannot reuse the TOTP
travel_to(30.seconds.from_now) do
@@ -210,12 +210,12 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
context 'when two factor authentication is required' do
it 'shows 2FA prompt after ldap login' do
sign_in_using_ldap!(user, provider_label)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
enter_code(user.current_otp)
enable_admin_mode_using_ldap!(user)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
# Cannot reuse the TOTP
travel_to(30.seconds.from_now) do
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 5e683befeec..f8c06a85f71 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -217,7 +217,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
before do
gitlab_sign_in(user, remember: true)
- expect(page).to have_content('Two-factor authentication code')
+ expect(page).to have_content('Enter verification code')
end
it 'does not show a "You are already signed in." error message' do
@@ -394,7 +394,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
sign_in_using_saml!
expect_single_session_with_authenticated_ttl
- expect(page).not_to have_content('Two-Factor Authentication')
+ expect(page).not_to have_content(_('Enter verification code'))
expect(page).to have_current_path root_path, ignore_query: true
end
end
@@ -408,7 +408,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
sign_in_using_saml!
- expect(page).to have_content('Two-factor authentication code')
+ expect(page).to have_content('Enter verification code')
enter_code(user.current_otp)
diff --git a/spec/fixtures/work_items_missing_header.csv b/spec/fixtures/work_items_missing_header.csv
new file mode 100644
index 00000000000..c1f21947469
--- /dev/null
+++ b/spec/fixtures/work_items_missing_header.csv
@@ -0,0 +1,3 @@
+type,created_at
+issue,2021-01-01
+task,2023-02-02
diff --git a/spec/fixtures/work_items_valid.csv b/spec/fixtures/work_items_valid.csv
new file mode 100644
index 00000000000..c8d646fd17b
--- /dev/null
+++ b/spec/fixtures/work_items_valid.csv
@@ -0,0 +1,3 @@
+title,type
+馬のスモモモモモモモモ,issue
+Do this task,task
diff --git a/spec/frontend/diffs/components/tree_list_spec.js b/spec/frontend/diffs/components/tree_list_spec.js
index 1656eaf8ba0..7e6274d7778 100644
--- a/spec/frontend/diffs/components/tree_list_spec.js
+++ b/spec/frontend/diffs/components/tree_list_spec.js
@@ -1,20 +1,36 @@
-import { shallowMount, mount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import TreeList from '~/diffs/components/tree_list.vue';
import createStore from '~/diffs/store/modules';
-import FileTree from '~/vue_shared/components/file_tree.vue';
+import DiffFileRow from '~/diffs/components//diff_file_row.vue';
+import { stubComponent } from 'helpers/stub_component';
describe('Diffs tree list component', () => {
let wrapper;
let store;
- const getFileRows = () => wrapper.findAll('.file-row');
+ const getScroller = () => wrapper.findComponent({ name: 'RecycleScroller' });
+ const getFileRow = () => wrapper.findComponent(DiffFileRow);
Vue.use(Vuex);
- const createComponent = (mountFn = mount) => {
- wrapper = mountFn(TreeList, {
+ const createComponent = () => {
+ wrapper = shallowMount(TreeList, {
store,
propsData: { hideFileStats: false },
+ stubs: {
+ // eslint will fail if we import the real component
+ RecycleScroller: stubComponent(
+ {
+ name: 'RecycleScroller',
+ props: {
+ items: null,
+ },
+ },
+ {
+ template: '<div><slot :item="{ tree: [] }"></slot></div>',
+ },
+ ),
+ },
});
};
@@ -101,26 +117,32 @@ describe('Diffs tree list component', () => {
});
describe('search by file extension', () => {
+ it('hides scroller for no matches', async () => {
+ wrapper.find('[data-testid="diff-tree-search"]').setValue('*.md');
+
+ await nextTick();
+
+ expect(getScroller().exists()).toBe(false);
+ expect(wrapper.text()).toContain('No files found');
+ });
+
it.each`
extension | itemSize
- ${'*.md'} | ${0}
- ${'*.js'} | ${1}
- ${'index.js'} | ${1}
- ${'app/*.js'} | ${1}
- ${'*.js, *.rb'} | ${2}
+ ${'*.js'} | ${2}
+ ${'index.js'} | ${2}
+ ${'app/*.js'} | ${2}
+ ${'*.js, *.rb'} | ${3}
`('returns $itemSize item for $extension', async ({ extension, itemSize }) => {
wrapper.find('[data-testid="diff-tree-search"]').setValue(extension);
await nextTick();
- expect(getFileRows()).toHaveLength(itemSize);
+ expect(getScroller().props('items')).toHaveLength(itemSize);
});
});
it('renders tree', () => {
- expect(getFileRows()).toHaveLength(2);
- expect(getFileRows().at(0).html()).toContain('index.js');
- expect(getFileRows().at(1).html()).toContain('app');
+ expect(getScroller().props('items')).toHaveLength(2);
});
it('hides file stats', async () => {
@@ -133,33 +155,16 @@ describe('Diffs tree list component', () => {
it('calls toggleTreeOpen when clicking folder', () => {
jest.spyOn(wrapper.vm.$store, 'dispatch').mockReturnValue(undefined);
- getFileRows().at(1).trigger('click');
+ getFileRow().vm.$emit('toggleTreeOpen', 'app');
expect(wrapper.vm.$store.dispatch).toHaveBeenCalledWith('diffs/toggleTreeOpen', 'app');
});
- it('calls scrollToFile when clicking blob', () => {
- jest.spyOn(wrapper.vm.$store, 'dispatch').mockReturnValue(undefined);
-
- wrapper.find('.file-row').trigger('click');
-
- expect(wrapper.vm.$store.dispatch).toHaveBeenCalledWith('diffs/scrollToFile', {
- path: 'app/index.js',
- });
- });
-
- it('renders as file list when renderTreeList is false', async () => {
+ it('renders when renderTreeList is false', async () => {
wrapper.vm.$store.state.diffs.renderTreeList = false;
await nextTick();
- expect(getFileRows()).toHaveLength(2);
- });
-
- it('renders file paths when renderTreeList is false', async () => {
- wrapper.vm.$store.state.diffs.renderTreeList = false;
-
- await nextTick();
- expect(wrapper.find('.file-row').html()).toContain('index.js');
+ expect(getScroller().props('items')).toHaveLength(3);
});
});
@@ -172,12 +177,10 @@ describe('Diffs tree list component', () => {
});
it('passes the viewedDiffFileIds to the FileTree', async () => {
- createComponent(shallowMount);
+ createComponent();
await nextTick();
- // Have to use $attrs['viewed-files'] because we are passing down an object
- // and attributes('') stringifies values (e.g. [object])...
- expect(wrapper.findComponent(FileTree).vm.$attrs['viewed-files']).toBe(viewedDiffFileIds);
+ expect(wrapper.findComponent(DiffFileRow).props('viewedFiles')).toBe(viewedDiffFileIds);
});
});
});
diff --git a/spec/frontend/editor/schema/ci/ci_schema_spec.js b/spec/frontend/editor/schema/ci/ci_schema_spec.js
index c822a0bfeaf..87208ec7aa8 100644
--- a/spec/frontend/editor/schema/ci/ci_schema_spec.js
+++ b/spec/frontend/editor/schema/ci/ci_schema_spec.js
@@ -33,6 +33,7 @@ import JobWhenYaml from './yaml_tests/positive_tests/job_when.yml';
import IdTokensYaml from './yaml_tests/positive_tests/id_tokens.yml';
import HooksYaml from './yaml_tests/positive_tests/hooks.yml';
import SecretsYaml from './yaml_tests/positive_tests/secrets.yml';
+import ServicesYaml from './yaml_tests/positive_tests/services.yml';
// YAML NEGATIVE TEST
import ArtifactsNegativeYaml from './yaml_tests/negative_tests/artifacts.yml';
@@ -52,6 +53,7 @@ import VariablesWrongSyntaxUsageExpand from './yaml_tests/negative_tests/variabl
import IdTokensNegativeYaml from './yaml_tests/negative_tests/id_tokens.yml';
import HooksNegative from './yaml_tests/negative_tests/hooks.yml';
import SecretsNegativeYaml from './yaml_tests/negative_tests/secrets.yml';
+import ServicesNegativeYaml from './yaml_tests/negative_tests/services.yml';
const ajv = new Ajv({
strictTypes: false,
@@ -89,6 +91,7 @@ describe('positive tests', () => {
VariablesYaml,
ProjectPathYaml,
IdTokensYaml,
+ ServicesYaml,
SecretsYaml,
}),
)('schema validates %s', (_, input) => {
@@ -113,10 +116,12 @@ describe('negative tests', () => {
// YAML
ArtifactsNegativeYaml,
CacheKeyNeative,
+ HooksNegative,
IdTokensNegativeYaml,
IncludeNegativeYaml,
JobWhenNegativeYaml,
RulesNegativeYaml,
+ TriggerNegative,
VariablesInvalidOptionsYaml,
VariablesInvalidSyntaxDescYaml,
VariablesWrongSyntaxUsageExpand,
@@ -126,8 +131,7 @@ describe('negative tests', () => {
ProjectPathIncludeNoSlashYaml,
ProjectPathIncludeTailSlashYaml,
SecretsNegativeYaml,
- TriggerNegative,
- HooksNegative,
+ ServicesNegativeYaml,
}),
)('schema validates %s', (_, input) => {
// We construct a new "JSON" from each main key that is inside a
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml
new file mode 100644
index 00000000000..6761a603a0a
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml
@@ -0,0 +1,38 @@
+empty_services:
+ services:
+
+without_name:
+ services:
+ - alias: db-postgres
+ entrypoint: ["/usr/local/bin/db-postgres"]
+ command: ["start"]
+
+invalid_entrypoint:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ entrypoint: "/usr/local/bin/db-postgres" # must be array
+
+empty_entrypoint:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ entrypoint: []
+
+invalid_command:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ command: "start" # must be array
+
+empty_command:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ command: []
+
+empty_pull_policy:
+ script: echo "Multiple pull policies."
+ services:
+ - name: postgres:11.6
+ pull_policy: []
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml
new file mode 100644
index 00000000000..8a0f59d1dfd
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml
@@ -0,0 +1,31 @@
+valid_services_list:
+ services:
+ - php:7
+ - node:latest
+ - golang:1.10
+
+valid_services_object:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ entrypoint: ["/usr/local/bin/db-postgres"]
+ command: ["start"]
+
+services_with_variables:
+ services:
+ - name: bitnami/nginx
+ alias: nginx
+ variables:
+ NGINX_HTTP_PORT_NUMBER: ${NGINX_HTTP_PORT_NUMBER}
+
+pull_policy_string:
+ script: echo "A single pull policy."
+ services:
+ - name: postgres:11.6
+ pull_policy: if-not-present
+
+pull_policy_array:
+ script: echo "Multiple pull policies."
+ services:
+ - name: postgres:11.6
+ pull_policy: [always, if-not-present]
diff --git a/spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js b/spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js
index 88d9d0b4cff..a6288b9c725 100644
--- a/spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js
+++ b/spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js
@@ -20,7 +20,7 @@ describe('getStateKey', () => {
};
const bound = getStateKey.bind(context);
- expect(bound()).toEqual(null);
+ expect(bound()).toEqual('checking');
context.detailedMergeStatus = 'MERGEABLE';
diff --git a/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap
deleted file mode 100644
index ca9d4488870..00000000000
--- a/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap
+++ /dev/null
@@ -1,40 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`File row header component adds multiple ellipsises after 40 characters 1`] = `
-<div
- class="file-row-header bg-white sticky-top p-2 js-file-row-header"
- title="app/assets/javascripts/merge_requests/widget/diffs/notes"
->
- <gl-truncate-stub
- class="bold"
- position="middle"
- text="app/assets/javascripts/merge_requests/widget/diffs/notes"
- />
-</div>
-`;
-
-exports[`File row header component renders file path 1`] = `
-<div
- class="file-row-header bg-white sticky-top p-2 js-file-row-header"
- title="app/assets"
->
- <gl-truncate-stub
- class="bold"
- position="middle"
- text="app/assets"
- />
-</div>
-`;
-
-exports[`File row header component trucates path after 40 characters 1`] = `
-<div
- class="file-row-header bg-white sticky-top p-2 js-file-row-header"
- title="app/assets/javascripts/merge_requests"
->
- <gl-truncate-stub
- class="bold"
- position="middle"
- text="app/assets/javascripts/merge_requests"
- />
-</div>
-`;
diff --git a/spec/frontend/vue_shared/components/file_row_header_spec.js b/spec/frontend/vue_shared/components/file_row_header_spec.js
index 80f4c275dcc..7aea581fe51 100644
--- a/spec/frontend/vue_shared/components/file_row_header_spec.js
+++ b/spec/frontend/vue_shared/components/file_row_header_spec.js
@@ -1,11 +1,12 @@
import { shallowMount } from '@vue/test-utils';
+import { GlTruncate } from '@gitlab/ui';
import FileRowHeader from '~/vue_shared/components/file_row_header.vue';
describe('File row header component', () => {
- let vm;
+ let wrapper;
function createComponent(path) {
- vm = shallowMount(FileRowHeader, {
+ wrapper = shallowMount(FileRowHeader, {
propsData: {
path,
},
@@ -13,24 +14,15 @@ describe('File row header component', () => {
}
afterEach(() => {
- vm.destroy();
+ wrapper.destroy();
});
it('renders file path', () => {
- createComponent('app/assets');
+ const path = 'app/assets';
+ createComponent(path);
- expect(vm.element).toMatchSnapshot();
- });
-
- it('trucates path after 40 characters', () => {
- createComponent('app/assets/javascripts/merge_requests');
-
- expect(vm.element).toMatchSnapshot();
- });
-
- it('adds multiple ellipsises after 40 characters', () => {
- createComponent('app/assets/javascripts/merge_requests/widget/diffs/notes');
-
- expect(vm.element).toMatchSnapshot();
+ const truncate = wrapper.findComponent(GlTruncate);
+ expect(truncate.exists()).toBe(true);
+ expect(truncate.props('text')).toBe(path);
});
});
diff --git a/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb b/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
index 125e15b70cf..da5531d2b93 100644
--- a/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
+++ b/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
@@ -58,7 +58,6 @@ RSpec.describe Mutations::AlertManagement::Alerts::SetAssignees do
it_behaves_like 'an incident management tracked event', :incident_management_alert_assigned
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb b/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb
index bcb7c74fa09..8ba1e785b63 100644
--- a/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb
+++ b/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb
@@ -20,7 +20,6 @@ RSpec.describe Mutations::AlertManagement::Alerts::Todo::Create do
it_behaves_like 'an incident management tracked event', :incident_management_alert_todo
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb
index e49596b37c9..f86046bb0d6 100644
--- a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb
+++ b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb
@@ -32,7 +32,6 @@ RSpec.describe Mutations::AlertManagement::CreateAlertIssue do
it_behaves_like 'an incident management tracked event', :incident_management_alert_create_incident
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
@@ -57,7 +56,6 @@ RSpec.describe Mutations::AlertManagement::CreateAlertIssue do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb
index 22ad93df79b..fb11ec7065b 100644
--- a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb
+++ b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb
@@ -36,7 +36,6 @@ RSpec.describe Mutations::AlertManagement::UpdateAlertStatus do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/lib/gitlab/database/schema_validation/database_spec.rb b/spec/lib/gitlab/database/schema_validation/database_spec.rb
index c0026f91b46..68e12c90819 100644
--- a/spec/lib/gitlab/database/schema_validation/database_spec.rb
+++ b/spec/lib/gitlab/database/schema_validation/database_spec.rb
@@ -34,6 +34,24 @@ RSpec.describe Gitlab::Database::SchemaValidation::Database, feature_category: :
end
end
+ describe '#index_exists?' do
+ context 'when index exists' do
+ it 'returns true' do
+ index_exists = database.index_exists?('index')
+
+ expect(index_exists).to be_truthy
+ end
+ end
+
+ context 'when index does not exist' do
+ it 'returns false' do
+ index_exists = database.index_exists?('non_existing_index')
+
+ expect(index_exists).to be_falsey
+ end
+ end
+ end
+
describe '#indexes' do
it 'returns indexes' do
indexes = database.indexes
diff --git a/spec/lib/gitlab/database/schema_validation/runner_spec.rb b/spec/lib/gitlab/database/schema_validation/runner_spec.rb
new file mode 100644
index 00000000000..6c491ae56f7
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/runner_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Runner, feature_category: :database do
+ let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+ let(:connection) { ActiveRecord::Base.connection }
+
+ let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
+ let(:structure_sql) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path) }
+
+ describe '#execute' do
+ subject(:inconsistencies) { described_class.new(structure_sql, database).execute }
+
+ it 'returns inconsistencies' do
+ expect(inconsistencies).not_to be_empty
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/structure_sql_spec.rb b/spec/lib/gitlab/database/schema_validation/structure_sql_spec.rb
new file mode 100644
index 00000000000..00566d884cf
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/structure_sql_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::StructureSql, feature_category: :database do
+ let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+
+ subject(:structure_sql) { described_class.new(structure_file_path) }
+
+ describe '#index_exists?' do
+ subject(:index_exists) { structure_sql.index_exists?(index_name) }
+
+ context 'when the index does not exist' do
+ let(:index_name) { 'non-existent-index' }
+
+ it 'returns false' do
+ expect(index_exists).to be_falsey
+ end
+ end
+
+ context 'when the index exists' do
+ let(:index_name) { 'index' }
+
+ it 'returns true' do
+ expect(index_exists).to be_truthy
+ end
+ end
+ end
+
+ describe '#indexes' do
+ it 'returns indexes' do
+ indexes = structure_sql.indexes
+
+ expected_indexes = %w[
+ missing_index
+ wrong_index
+ index
+ index_namespaces_public_groups_name_id
+ index_on_deploy_keys_id_and_type_and_public
+ index_users_on_public_email_excluding_null_and_empty
+ ]
+
+ expect(indexes).to all(be_a(Gitlab::Database::SchemaValidation::Index))
+ expect(indexes.map(&:name)).to eq(expected_indexes)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb
new file mode 100644
index 00000000000..adac5b4e579
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::BaseValidator, feature_category: :database do
+ describe '.all_validators' do
+ subject(:all_validators) { described_class.all_validators }
+
+ it 'returns an array of all validators' do
+ expect(all_validators).to eq([
+ Gitlab::Database::SchemaValidation::Validators::ExtraIndexes,
+ Gitlab::Database::SchemaValidation::Validators::MissingIndexes,
+ Gitlab::Database::SchemaValidation::Validators::WrongIndexes
+ ])
+ end
+ end
+
+ describe '#execute' do
+ let(:structure_sql) { instance_double(Gitlab::Database::SchemaValidation::StructureSql) }
+ let(:database) { instance_double(Gitlab::Database::SchemaValidation::Database) }
+
+ subject(:inconsistencies) { described_class.new(structure_sql, database).execute }
+
+ it 'raises an exception' do
+ expect { inconsistencies }.to raise_error(NoMethodError)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/extra_indexes_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/extra_indexes_spec.rb
new file mode 100644
index 00000000000..842dbb42120
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/extra_indexes_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::ExtraIndexes, feature_category: :database do
+ include_examples 'index validators', described_class, ['extra_index']
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/missing_indexes_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/missing_indexes_spec.rb
new file mode 100644
index 00000000000..c402c3a2fa7
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/missing_indexes_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::MissingIndexes, feature_category: :database do
+ missing_indexes = %w[
+ missing_index
+ index_namespaces_public_groups_name_id
+ index_on_deploy_keys_id_and_type_and_public
+ index_users_on_public_email_excluding_null_and_empty
+ ]
+
+ include_examples 'index validators', described_class, missing_indexes
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/wrong_indexes_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/wrong_indexes_spec.rb
new file mode 100644
index 00000000000..026f3fb710c
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/wrong_indexes_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::WrongIndexes, feature_category: :database do
+ include_examples 'index validators', described_class, ['wrong_index']
+end
diff --git a/spec/lib/gitlab/observability_spec.rb b/spec/lib/gitlab/observability_spec.rb
index 8068d2f8ec9..e8c79c29830 100644
--- a/spec/lib/gitlab/observability_spec.rb
+++ b/spec/lib/gitlab/observability_spec.rb
@@ -31,29 +31,114 @@ RSpec.describe Gitlab::Observability do
end
end
- describe '.observability_enabled?' do
+ describe '.valid_observability_url?' do
+ it 'returns true if url is a valid observability url' do
+ expect(described_class.valid_observability_url?('https://observe.gitlab.com')).to eq(true)
+ expect(described_class.valid_observability_url?('https://observe.gitlab.com:443')).to eq(true)
+ expect(described_class.valid_observability_url?('https://observe.gitlab.com/foo/bar')).to eq(true)
+ expect(described_class.valid_observability_url?('https://observe.gitlab.com/123/456')).to eq(true)
+ end
+
+ it 'returns false if url is a not valid observability url' do
+ expect(described_class.valid_observability_url?('http://observe.gitlab.com')).to eq(false)
+ expect(described_class.valid_observability_url?('https://observe.gitlab.com:81')).to eq(false)
+ expect(described_class.valid_observability_url?('https://foo.observe.gitlab.com')).to eq(false)
+ expect(described_class.valid_observability_url?('https://www.gitlab.com')).to eq(false)
+ expect(described_class.valid_observability_url?('foo@@@@bar/1/')).to eq(false)
+ expect(described_class.valid_observability_url?('foo bar')).to eq(false)
+ end
+ end
+
+ describe '.group_id_from_url' do
+ it 'returns the group id extracted from the url' do
+ expect(described_class.group_id_from_url('https://observe.gitlab.com/123/explore')).to eq(123)
+ expect(described_class.group_id_from_url('https://observe.gitlab.com/123')).to eq(123)
+ expect(described_class.group_id_from_url('https://observe.gitlab.com/123/')).to eq(123)
+ expect(described_class.group_id_from_url('https://observe.gitlab.com/123/456')).to eq(123)
+ end
+
+ it 'returns nil if the group id is not valid or missing' do
+ expect(described_class.group_id_from_url('https://observe.gitlab.com')).to be_nil
+ expect(described_class.group_id_from_url('https://observe.gitlab.com/')).to be_nil
+ expect(described_class.group_id_from_url('https://observe.gitlab.com/foo')).to be_nil
+ expect(described_class.group_id_from_url('https://observe.gitlab.com/foo/bar')).to be_nil
+ expect(described_class.group_id_from_url('https://observe.gitlab.com/0')).to be_nil
+ expect(described_class.group_id_from_url('https://observe.gitlab.com/-1')).to be_nil
+ end
+
+ it 'returns nil if the url is not a valid' do
+ expect(described_class.group_id_from_url('https://invalid.gitlab.com/123')).to be_nil
+ expect(described_class.group_id_from_url('foo bar')).to be_nil
+ expect(described_class.group_id_from_url('foo@@@@bar/1/')).to be_nil
+ end
+ end
+
+ describe '.allowed_for_action?' do
+ let_it_be(:group) { build(:user) }
+ let_it_be(:user) { build(:group) }
+
+ before do
+ allow(described_class).to receive(:allowed?).and_call_original
+ end
+
+ it 'returns false if action is nil' do
+ expect(described_class.allowed_for_action?(user, group, nil)).to eq(false)
+ end
+
+ describe 'allowed? calls' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:action, :permission) do
+ :foo | :admin_observability
+ :explore | :read_observability
+ :datasources | :admin_observability
+ :manage | :admin_observability
+ :dashboards | :read_observability
+ end
+
+ with_them do
+ it "calls allowed? with #{params[:permission]} when actions is #{params[:action]}" do
+ described_class.allowed_for_action?(user, group, action)
+ expect(described_class).to have_received(:allowed?).with(user, group, permission)
+ end
+ end
+ end
+ end
+
+ describe '.allowed?' do
let_it_be(:group) { build(:user) }
let_it_be(:user) { build(:group) }
+ let_it_be(:test_permission) { :read_observability }
+
+ before do
+ allow(Ability).to receive(:allowed?).and_return(false)
+ end
subject do
- described_class.observability_enabled?(user, group)
+ described_class.allowed?(user, group, test_permission)
end
- it 'checks if read_observability ability is allowed for the given user and group' do
+ it 'checks if ability is allowed for the given user and group' do
allow(Ability).to receive(:allowed?).and_return(true)
subject
- expect(Ability).to have_received(:allowed?).with(user, :read_observability, group)
+ expect(Ability).to have_received(:allowed?).with(user, test_permission, group)
+ end
+
+ it 'checks for admin_observability if permission is missing' do
+ described_class.allowed?(user, group)
+
+ expect(Ability).to have_received(:allowed?).with(user, :admin_observability, group)
end
- it 'returns true if the read_observability ability is allowed' do
+ it 'returns true if the ability is allowed' do
allow(Ability).to receive(:allowed?).and_return(true)
expect(subject).to eq(true)
end
- it 'returns false if the read_observability ability is not allowed' do
+ it 'returns false if the ability is not allowed' do
allow(Ability).to receive(:allowed?).and_return(false)
expect(subject).to eq(false)
@@ -64,5 +149,13 @@ RSpec.describe Gitlab::Observability do
expect(subject).to eq(false)
end
+
+ it 'returns false if group is missing' do
+ expect(described_class.allowed?(user, nil, :read_observability)).to eq(false)
+ end
+
+ it 'returns false if user is missing' do
+ expect(described_class.allowed?(nil, group, :read_observability)).to eq(false)
+ end
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
index 42aa84c2c3e..e41da6d9ea2 100644
--- a/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
@@ -69,7 +69,6 @@ RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :cl
let(:project) { target_project }
let(:namespace) { project.namespace.reload }
let(:user) { project.creator }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:label) { 'redis_hll_counters.code_review.i_code_review_user_create_mr_monthly' }
let(:property) { described_class::MR_USER_CREATE_ACTION }
end
@@ -118,7 +117,6 @@ RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :cl
let(:project) { target_project }
let(:namespace) { project.namespace.reload }
let(:user) { project.creator }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:label) { 'redis_hll_counters.code_review.i_code_review_user_approve_mr_monthly' }
let(:property) { described_class::MR_APPROVE_ACTION }
end
diff --git a/spec/lib/sidebars/groups/menus/observability_menu_spec.rb b/spec/lib/sidebars/groups/menus/observability_menu_spec.rb
index 5b993cd6f28..20af8ea00be 100644
--- a/spec/lib/sidebars/groups/menus/observability_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/observability_menu_spec.rb
@@ -20,26 +20,74 @@ RSpec.describe Sidebars::Groups::Menus::ObservabilityMenu do
allow(menu).to receive(:can?).and_call_original
end
- context 'when observability is enabled' do
+ context 'when observability#explore is allowed' do
before do
- allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(true)
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, :explore).and_return(true)
end
it 'returns true' do
expect(menu.render?).to eq true
- expect(Gitlab::Observability).to have_received(:observability_enabled?).with(user, group)
+ expect(Gitlab::Observability).to have_received(:allowed_for_action?).with(user, group, :explore)
end
end
- context 'when observability is disabled' do
+ context 'when observability#explore is not allowed' do
before do
- allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(false)
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, :explore).and_return(false)
end
it 'returns false' do
expect(menu.render?).to eq false
- expect(Gitlab::Observability).to have_received(:observability_enabled?).with(user, group)
+ expect(Gitlab::Observability).to have_received(:allowed_for_action?).with(user, group, :explore)
end
end
end
+
+ describe "Menu items" do
+ before do
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).and_return(false)
+ end
+
+ subject { find_menu(menu, item_id) }
+
+ shared_examples 'observability menu entry' do
+ context 'when action is allowed' do
+ before do
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, item_id).and_return(true)
+ end
+
+ it 'the menu item is added to list of menu items' do
+ is_expected.not_to be_nil
+ end
+ end
+
+ context 'when action is not allowed' do
+ before do
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, item_id).and_return(false)
+ end
+
+ it 'the menu item is added to list of menu items' do
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ describe 'Explore' do
+ it_behaves_like 'observability menu entry' do
+ let(:item_id) { :explore }
+ end
+ end
+
+ describe 'Datasources' do
+ it_behaves_like 'observability menu entry' do
+ let(:item_id) { :datasources }
+ end
+ end
+ end
+
+ private
+
+ def find_menu(menu, item)
+ menu.renderable_items.find { |i| i.item_id == item }
+ end
end
diff --git a/spec/mailers/emails/profile_spec.rb b/spec/mailers/emails/profile_spec.rb
index f5fce559778..32df477fdfc 100644
--- a/spec/mailers/emails/profile_spec.rb
+++ b/spec/mailers/emails/profile_spec.rb
@@ -476,7 +476,7 @@ RSpec.describe Emails::Profile do
end
it 'has the correct subject' do
- is_expected.to have_subject "Attempted sign in to #{Gitlab.config.gitlab.host} using a wrong two-factor authentication code"
+ is_expected.to have_subject "Attempted sign in to #{Gitlab.config.gitlab.host} using an incorrect verification code"
end
it 'mentions the IP address' do
diff --git a/spec/models/integrations/jira_spec.rb b/spec/models/integrations/jira_spec.rb
index a4ccae459cf..fb7f676e47b 100644
--- a/spec/models/integrations/jira_spec.rb
+++ b/spec/models/integrations/jira_spec.rb
@@ -590,7 +590,6 @@ RSpec.describe Integrations::Jira do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject { close_issue }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { 'Integrations::Jira' }
let(:action) { 'perform_integrations_action' }
let(:namespace) { project.namespace }
@@ -944,7 +943,6 @@ RSpec.describe Integrations::Jira do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { 'Integrations::Jira' }
let(:action) { 'perform_integrations_action' }
let(:namespace) { project.namespace }
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index 451db9eaf9c..f76b5dd8224 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -933,13 +933,14 @@ RSpec.describe GroupPolicy, feature_category: :authentication_and_authorization
describe 'observability' do
using RSpec::Parameterized::TableSyntax
- let(:allowed) { be_allowed(:read_observability) }
- let(:disallowed) { be_disallowed(:read_observability) }
+ let(:allowed_admin) { be_allowed(:read_observability) && be_allowed(:admin_observability) }
+ let(:allowed_read) { be_allowed(:read_observability) && be_disallowed(:admin_observability) }
+ let(:disallowed) { be_disallowed(:read_observability) && be_disallowed(:admin_observability) }
# rubocop:disable Layout/LineLength
where(:feature_enabled, :admin_matcher, :owner_matcher, :maintainer_matcher, :developer_matcher, :reporter_matcher, :guest_matcher, :non_member_matcher, :anonymous_matcher) do
false | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed)
- true | ref(:allowed) | ref(:allowed) | ref(:allowed) | ref(:allowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed)
+ true | ref(:allowed_admin) | ref(:allowed_admin) | ref(:allowed_admin) | ref(:allowed_read) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed)
end
# rubocop:enable Layout/LineLength
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 3932abd20cc..e474070f621 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -499,7 +499,6 @@ RSpec.describe API::Commits, feature_category: :source_code_management do
let(:property) { 'g_edit_by_web_ide' }
let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit' }
let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context] }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
context 'counts.web_ide_commits Snowplow event tracking' do
diff --git a/spec/requests/api/graphql/mutations/snippets/update_spec.rb b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
index fa087e6773c..3b98ee3c2e9 100644
--- a/spec/requests/api/graphql/mutations/snippets/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
@@ -193,7 +193,6 @@ RSpec.describe 'Updating a Snippet', feature_category: :source_code_management d
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:user) { current_user }
let(:property) { 'g_edit_by_snippet_ide' }
let(:namespace) { project.namespace }
@@ -203,8 +202,6 @@ RSpec.describe 'Updating a Snippet', feature_category: :source_code_management d
let(:context) do
[Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context]
end
-
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
end
end
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index fd34345d814..7784985f7f4 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -51,7 +51,6 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject(:api_request) { request }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'terraform_state_api_request' }
let(:label) { 'redis_hll_counters.terraform.p_terraform_state_api_unique_users_monthly' }
diff --git a/spec/requests/groups/observability_controller_spec.rb b/spec/requests/groups/observability_controller_spec.rb
index 471cad40c90..b82cf2b0bad 100644
--- a/spec/requests/groups/observability_controller_spec.rb
+++ b/spec/requests/groups/observability_controller_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Groups::ObservabilityController, feature_category: :tracing do
end
end
- context 'when user is not a developer' do
+ context 'when user is a guest' do
before do
sign_in(user)
end
@@ -36,10 +36,10 @@ RSpec.describe Groups::ObservabilityController, feature_category: :tracing do
end
end
- context 'when user is authenticated and a developer' do
+ context 'when user has the correct permissions' do
before do
sign_in(user)
- group.add_developer(user)
+ set_permissions
end
context 'when observability url is missing' do
@@ -75,13 +75,21 @@ RSpec.describe Groups::ObservabilityController, feature_category: :tracing do
let(:path) { group_observability_explore_path(group) }
let(:expected_observability_path) { "#{observability_url}/-/#{group.id}/explore" }
- it_behaves_like 'observability route request'
+ it_behaves_like 'observability route request' do
+ let(:set_permissions) do
+ group.add_developer(user)
+ end
+ end
end
describe 'GET #datasources' do
let(:path) { group_observability_datasources_path(group) }
let(:expected_observability_path) { "#{observability_url}/-/#{group.id}/datasources" }
- it_behaves_like 'observability route request'
+ it_behaves_like 'observability route request' do
+ let(:set_permissions) do
+ group.add_maintainer(user)
+ end
+ end
end
end
diff --git a/spec/requests/ide_controller_spec.rb b/spec/requests/ide_controller_spec.rb
index b287ded799d..6e79943e83d 100644
--- a/spec/requests/ide_controller_spec.rb
+++ b/spec/requests/ide_controller_spec.rb
@@ -237,18 +237,6 @@ RSpec.describe IdeController, feature_category: :web_ide do
user: user
)
end
-
- context 'when route_hll_to_snowplow_phase2 FF is disabled' do
- before do
- stub_feature_flags(route_hll_to_snowplow_phase2: false)
- end
-
- it 'does not track Snowplow event' do
- subject
-
- expect_no_snowplow_event
- end
- end
end
# This indirectly tests that `minimal: true` was passed to the fullscreen layout
diff --git a/spec/requests/verifies_with_email_spec.rb b/spec/requests/verifies_with_email_spec.rb
index 8a6a7e717ff..3184fe151be 100644
--- a/spec/requests/verifies_with_email_spec.rb
+++ b/spec/requests/verifies_with_email_spec.rb
@@ -42,7 +42,7 @@ feature_category: :user_management do
shared_examples_for 'two factor prompt or successful login' do
it 'shows the 2FA prompt when enabled or redirects to the root path' do
if user.two_factor_enabled?
- expect(response.body).to include('Two-factor authentication code')
+ expect(response.body).to include('Enter verification code')
else
expect(response).to redirect_to(root_path)
end
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index b969bd76053..47f1b7d9b64 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -69,7 +69,6 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'created' }
let(:label) { described_class::MR_EVENT_LABEL }
@@ -99,7 +98,6 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'closed' }
let(:label) { described_class::MR_EVENT_LABEL }
@@ -129,7 +127,6 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'merged' }
let(:label) { described_class::MR_EVENT_LABEL }
@@ -409,7 +406,6 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
let(:category) { described_class.name }
let(:property) { Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s }
let(:label) { ::EventCreateService::DEGIGN_EVENT_LABEL }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
context 'for create event' do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
@@ -461,7 +457,6 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
let(:user) { author }
let(:property) { Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s }
let(:label) { ::EventCreateService::DEGIGN_EVENT_LABEL }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
end
end
@@ -485,7 +480,6 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
it_behaves_like "it records the event in the event counter"
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:note) { create(:diff_note_on_merge_request) }
let(:category) { described_class.name }
let(:action) { 'commented' }
diff --git a/spec/services/import_csv/base_service_spec.rb b/spec/services/import_csv/base_service_spec.rb
index 0c0ed40ff4d..7a4b53832a6 100644
--- a/spec/services/import_csv/base_service_spec.rb
+++ b/spec/services/import_csv/base_service_spec.rb
@@ -24,6 +24,39 @@ RSpec.describe ImportCsv::BaseService, feature_category: :importers do
it_behaves_like 'abstract method', :validate_headers_presence!, "any"
it_behaves_like 'abstract method', :create_object_class
+ context 'when given a class' do
+ let(:importer_klass) do
+ Class.new(described_class) do
+ def attributes_for(row)
+ { title: row[:title] }
+ end
+
+ def validate_headers_presence!(headers)
+ raise CSV::MalformedCSVError.new("Missing required headers", 1) unless headers.present?
+ end
+
+ def create_object_class
+ Class.new
+ end
+
+ def email_results_to_user
+ # no-op
+ end
+ end
+ end
+
+ let(:service) do
+ uploader = FileUploader.new(project)
+ uploader.store!(file)
+
+ importer_klass.new(user, project, uploader)
+ end
+
+ subject { service.execute }
+
+ it_behaves_like 'correctly handles invalid files'
+ end
+
describe '#detect_col_sep' do
context 'when header contains invalid separators' do
it 'raises error' do
@@ -42,19 +75,19 @@ RSpec.describe ImportCsv::BaseService, feature_category: :importers do
end
end
- context 'with ; as separator' do
+ context 'when separator is ;' do
let(:separator) { ';' }
it_behaves_like 'header with valid separators'
end
- context 'with \t as separator' do
+ context 'when separator is \t' do
let(:separator) { "\t" }
it_behaves_like 'header with valid separators'
end
- context 'with , as separator' do
+ context 'when separator is ,' do
let(:separator) { ',' }
it_behaves_like 'header with valid separators'
diff --git a/spec/services/incident_management/timeline_events/create_service_spec.rb b/spec/services/incident_management/timeline_events/create_service_spec.rb
index fa5f4c64a43..b57a93d51b2 100644
--- a/spec/services/incident_management/timeline_events/create_service_spec.rb
+++ b/spec/services/incident_management/timeline_events/create_service_spec.rb
@@ -57,7 +57,6 @@ RSpec.describe IncidentManagement::TimelineEvents::CreateService do
it_behaves_like 'an incident management tracked event', :incident_management_timeline_event_created
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
@@ -286,7 +285,6 @@ RSpec.describe IncidentManagement::TimelineEvents::CreateService do
it_behaves_like 'an incident management tracked event', :incident_management_timeline_event_created
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/services/incident_management/timeline_events/destroy_service_spec.rb b/spec/services/incident_management/timeline_events/destroy_service_spec.rb
index f90ff72a2bf..026e1936761 100644
--- a/spec/services/incident_management/timeline_events/destroy_service_spec.rb
+++ b/spec/services/incident_management/timeline_events/destroy_service_spec.rb
@@ -67,7 +67,6 @@ RSpec.describe IncidentManagement::TimelineEvents::DestroyService do
it_behaves_like 'an incident management tracked event', :incident_management_timeline_event_deleted
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/services/incident_management/timeline_events/update_service_spec.rb b/spec/services/incident_management/timeline_events/update_service_spec.rb
index ebaa4dde7a2..c38126baa65 100644
--- a/spec/services/incident_management/timeline_events/update_service_spec.rb
+++ b/spec/services/incident_management/timeline_events/update_service_spec.rb
@@ -50,7 +50,6 @@ RSpec.describe IncidentManagement::TimelineEvents::UpdateService, feature_catego
it_behaves_like 'an incident management tracked event', :incident_management_timeline_event_edited
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_timeline_event_edited' }
diff --git a/spec/services/issue_links/create_service_spec.rb b/spec/services/issue_links/create_service_spec.rb
index 0629b8b091b..3ff6769d316 100644
--- a/spec/services/issue_links/create_service_spec.rb
+++ b/spec/services/issue_links/create_service_spec.rb
@@ -43,7 +43,6 @@ RSpec.describe IssueLinks::CreateService do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_relate' }
diff --git a/spec/services/issue_links/destroy_service_spec.rb b/spec/services/issue_links/destroy_service_spec.rb
index ecb53b5cd31..e31b5e95eb6 100644
--- a/spec/services/issue_links/destroy_service_spec.rb
+++ b/spec/services/issue_links/destroy_service_spec.rb
@@ -27,7 +27,6 @@ RSpec.describe IssueLinks::DestroyService do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue_b.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_unrelate' }
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index 803808e667c..44597929817 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -100,7 +100,6 @@ RSpec.describe Issues::CloseService do
it_behaves_like 'an incident management tracked event', :incident_management_incident_closed
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_closed' }
diff --git a/spec/services/issues/import_csv_service_spec.rb b/spec/services/issues/import_csv_service_spec.rb
index 90e360f9cf1..6a147782209 100644
--- a/spec/services/issues/import_csv_service_spec.rb
+++ b/spec/services/issues/import_csv_service_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Issues::ImportCsvService, feature_category: :team_planning do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:assignee) { create(:user, username: 'csv_assignee') }
+ let(:file) { fixture_file_upload('spec/fixtures/csv_complex.csv') }
let(:service) do
uploader = FileUploader.new(project)
uploader.store!(file)
@@ -19,8 +20,6 @@ RSpec.describe Issues::ImportCsvService, feature_category: :team_planning do
end
describe '#execute' do
- let(:file) { fixture_file_upload('spec/fixtures/csv_complex.csv') }
-
subject { service.execute }
it 'sets all issueable attributes and executes quick actions' do
diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb
index 68015a2327e..a5cb991e140 100644
--- a/spec/services/issues/reopen_service_spec.rb
+++ b/spec/services/issues/reopen_service_spec.rb
@@ -75,7 +75,6 @@ RSpec.describe Issues::ReopenService do
it_behaves_like 'an incident management tracked event', :incident_management_incident_reopened
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_reopened' }
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 973025bd2e3..cd41b95c95a 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -191,7 +191,6 @@ RSpec.describe Issues::UpdateService, :mailer do
it_behaves_like 'an incident management tracked event', :incident_management_incident_change_confidential
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:label) { 'redis_hll_counters.incident_management.incident_management_total_unique_counts_monthly' }
@@ -696,7 +695,6 @@ RSpec.describe Issues::UpdateService, :mailer do
it_behaves_like 'an incident management tracked event', :incident_management_incident_assigned
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:label) { 'redis_hll_counters.incident_management.incident_management_total_unique_counts_monthly' }
diff --git a/spec/services/issues/zoom_link_service_spec.rb b/spec/services/issues/zoom_link_service_spec.rb
index 230e4c1b5e1..b40cb34c75f 100644
--- a/spec/services/issues/zoom_link_service_spec.rb
+++ b/spec/services/issues/zoom_link_service_spec.rb
@@ -97,7 +97,6 @@ RSpec.describe Issues::ZoomLinkService do
it_behaves_like 'an incident management tracked event', :incident_management_incident_zoom_meeting
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_zoom_meeting' }
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 1ee9e51433e..d099a2ef5ae 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -108,7 +108,6 @@ RSpec.describe Notes::CreateService, feature_category: :team_planning do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_comment' }
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index f73eae70d3c..8afa409b0cf 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -211,7 +211,6 @@ RSpec.describe TodoService do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_todo' }
diff --git a/spec/services/work_items/import_csv_service_spec.rb b/spec/services/work_items/import_csv_service_spec.rb
new file mode 100644
index 00000000000..658062ecdbe
--- /dev/null
+++ b/spec/services/work_items/import_csv_service_spec.rb
@@ -0,0 +1,99 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::ImportCsvService, feature_category: :team_planning do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:author) { create(:user, username: 'csv_author') }
+ let(:file) { fixture_file_upload('spec/fixtures/work_items_valid.csv') }
+ let(:service) do
+ uploader = FileUploader.new(project)
+ uploader.store!(file)
+
+ described_class.new(user, project, uploader)
+ end
+
+ let_it_be(:issue_type) { ::WorkItems::Type.default_issue_type }
+
+ let(:work_items) { ::WorkItems::WorkItemsFinder.new(user, project: project).execute }
+
+ subject { service.execute }
+
+ describe '#execute' do
+ context 'when user has permission' do
+ before do
+ project.add_guest(user)
+ end
+
+ context 'when file is valid' do
+ it 'creates the expected number of work items' do
+ expect { subject }.to change { work_items.count }.by 2
+ end
+
+ describe 'imported work item details' do
+ it 'sets work item attributes' do
+ result = subject
+
+ expect(work_items.reload).to contain_exactly(
+ have_attributes(
+ title: '馬のスモモモモモモモモ',
+ work_item_type_id: issue_type.id
+ ),
+ have_attributes(
+ title: 'Do this task',
+ work_item_type_id: issue_type.id
+ )
+ )
+
+ expect(result[:success]).to eq(2)
+ expect(result[:error_lines]).to eq([])
+ expect(result[:parse_error]).to eq(false)
+ end
+
+ it 'defaults all work items to issue type' do
+ subject
+
+ expect(work_items.reload).to all(have_attributes(work_item_type: issue_type))
+ end
+ end
+ end
+
+ context 'when file is missing necessary headers' do
+ let(:file) { fixture_file_upload('spec/fixtures/work_items_missing_header.csv') }
+
+ it 'creates no records' do
+ result = subject
+
+ expect(result[:success]).to eq(0)
+ expect(result[:error_lines]).to eq([1])
+ expect(result[:parse_error]).to eq(true)
+ end
+
+ it 'creates no work items' do
+ expect { subject }.not_to change { work_items.count }
+ end
+ end
+
+ context 'when import_export_work_items_csv feature flag is off' do
+ before do
+ stub_feature_flags(import_export_work_items_csv: false)
+ end
+
+ it 'returns an error' do
+ expect { subject }.to raise_error(/This feature is currently behind a feature flag and it is not available./)
+ end
+ end
+ end
+
+ context 'when user does not have permission' do
+ it 'errors on those lines', :aggregate_failures do
+ result = subject
+
+ expect(result[:success]).to eq(0)
+ expect(result[:error_lines]).to match_array([2, 3])
+ expect(result[:parse_error]).to eq(false)
+ end
+ end
+ end
+end
diff --git a/spec/support/services/import_csv_service_shared_examples.rb b/spec/support/services/import_csv_service_shared_examples.rb
new file mode 100644
index 00000000000..1555497ae48
--- /dev/null
+++ b/spec/support/services/import_csv_service_shared_examples.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples_for 'importer with email notification' do
+ it 'notifies user of import result' do
+ expect(Notify).to receive_message_chain(email_method, :deliver_later)
+
+ subject
+ end
+end
+
+RSpec.shared_examples 'correctly handles invalid files' do
+ shared_examples_for 'invalid file' do
+ it 'returns invalid file error' do
+ expect(subject[:success]).to eq(0)
+ expect(subject[:parse_error]).to eq(true)
+ end
+ end
+
+ context 'when given file with unsupported extension' do
+ let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
+
+ it_behaves_like 'invalid file'
+ end
+
+ context 'when given empty file' do
+ let(:file) { fixture_file_upload('spec/fixtures/csv_empty.csv') }
+
+ it_behaves_like 'invalid file'
+ end
+
+ context 'when given file without headers' do
+ let(:file) { fixture_file_upload('spec/fixtures/csv_no_headers.csv') }
+
+ it_behaves_like 'invalid file'
+ end
+end
diff --git a/spec/support/services/issuable_import_csv_service_shared_examples.rb b/spec/support/services/issuable_import_csv_service_shared_examples.rb
index 0dea6cfb729..71740ba8ab2 100644
--- a/spec/support/services/issuable_import_csv_service_shared_examples.rb
+++ b/spec/support/services/issuable_import_csv_service_shared_examples.rb
@@ -18,45 +18,14 @@ RSpec.shared_examples 'issuable import csv service' do |issuable_type|
end
end
- shared_examples_for 'importer with email notification' do
- it 'notifies user of import result' do
- expect(Notify).to receive_message_chain(email_method, :deliver_later)
-
- subject
- end
- end
-
- shared_examples_for 'invalid file' do
- it 'returns invalid file error' do
- expect(subject[:success]).to eq(0)
- expect(subject[:parse_error]).to eq(true)
- end
-
- it_behaves_like 'importer with email notification'
- it_behaves_like 'an issuable importer'
- end
-
describe '#execute' do
before do
project.add_developer(user)
end
- context 'invalid file extension' do
- let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
-
- it_behaves_like 'invalid file'
- end
-
- context 'empty file' do
- let(:file) { fixture_file_upload('spec/fixtures/csv_empty.csv') }
-
- it_behaves_like 'invalid file'
- end
-
- context 'file without headers' do
- let(:file) { fixture_file_upload('spec/fixtures/csv_no_headers.csv') }
-
- it_behaves_like 'invalid file'
+ it_behaves_like 'correctly handles invalid files' do
+ it_behaves_like 'importer with email notification'
+ it_behaves_like 'an issuable importer'
end
context 'with a file generated by Gitlab CSV export' do
diff --git a/spec/lib/gitlab/database/schema_validation/indexes_spec.rb b/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb
index 4351031a4b4..0a8fd39bc2c 100644
--- a/spec/lib/gitlab/database/schema_validation/indexes_spec.rb
+++ b/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::SchemaValidation::Indexes, feature_category: :database do
+RSpec.shared_examples "index validators" do |validator, expected_result|
let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
let(:database_indexes) do
[
@@ -23,34 +23,13 @@ RSpec.describe Gitlab::Database::SchemaValidation::Indexes, feature_category: :d
let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path) }
- subject(:schema_validation) { described_class.new(structure_file, database) }
+ subject(:result) { validator.new(structure_file, database).execute }
before do
allow(connection).to receive(:exec_query).and_return(query_result)
end
- describe '#missing_indexes' do
- it 'returns missing indexes' do
- missing_indexes = %w[
- missing_index
- index_namespaces_public_groups_name_id
- index_on_deploy_keys_id_and_type_and_public
- index_users_on_public_email_excluding_null_and_empty
- ]
-
- expect(schema_validation.missing_indexes).to match_array(missing_indexes)
- end
- end
-
- describe '#extra_indexes' do
- it 'returns extra indexes' do
- expect(schema_validation.extra_indexes).to match_array(['extra_index'])
- end
- end
-
- describe '#wrong_indexes' do
- it 'returns wrong indexes' do
- expect(schema_validation.wrong_indexes).to match_array(['wrong_index'])
- end
+ it 'returns extra indexes' do
+ expect(result.map(&:name)).to match_array(expected_result)
end
end
diff --git a/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
index d4802a19202..9873bab1caf 100644
--- a/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
@@ -27,18 +27,6 @@ RSpec.shared_examples 'a daily tracked issuable snowplow and service ping events
expect_snowplow_event(**{ category: category, action: event_action, user: user1 }.merge(event_params))
end
-
- context 'with route_hll_to_snowplow_phase2 disabled' do
- before do
- stub_feature_flags(route_hll_to_snowplow_phase2: false)
- end
-
- it 'does not emit snowplow event' do
- track_action({ author: user1 }.merge(track_params))
-
- expect_no_snowplow_event
- end
- end
end
RSpec.shared_examples 'daily tracked issuable snowplow and service ping events with project' do
diff --git a/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
index 2e528f7996c..2dad35dc46e 100644
--- a/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
@@ -35,7 +35,6 @@ RSpec.shared_examples Integrations::BaseSlackNotification do |factory:|
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.to_s }
let(:action) { 'perform_integrations_action' }
let(:namespace) { project.namespace }
diff --git a/spec/support/shared_examples/observability/csp_shared_examples.rb b/spec/support/shared_examples/observability/csp_shared_examples.rb
index 0cd211f69eb..9d6e7e75f4d 100644
--- a/spec/support/shared_examples/observability/csp_shared_examples.rb
+++ b/spec/support/shared_examples/observability/csp_shared_examples.rb
@@ -31,19 +31,19 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
let(:observability_url) { Gitlab::Observability.observability_url }
let(:signin_url) do
Gitlab::Utils.append_path(Gitlab.config.gitlab.url,
- '/users/sign_in')
+ '/users/sign_in')
end
let(:oauth_url) do
Gitlab::Utils.append_path(Gitlab.config.gitlab.url,
- '/oauth/authorize')
+ '/oauth/authorize')
end
before do
setup_csp_for_controller(controller_class, csp, any_time: true)
group.add_developer(user)
login_as(user)
- allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(true)
+ stub_feature_flags(observability_group_tab: true)
end
subject do
@@ -67,7 +67,7 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
end
before do
- allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(false)
+ stub_feature_flags(observability_group_tab: false)
end
it 'does not add observability urls to the csp header' do
@@ -76,23 +76,6 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
end
end
- context 'when checking if observability is enabled' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.frame_src 'https://something.test'
- end
- end
-
- it 'check access for a given user and group' do
- allow(Gitlab::Observability).to receive(:observability_enabled?)
-
- get tested_path
-
- expect(Gitlab::Observability).to have_received(:observability_enabled?)
- .with(user, group).at_least(:once)
- end
- end
-
context 'when frame-src exists in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
diff --git a/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb b/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb
index e72e8e79411..d3b3434b339 100644
--- a/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb
+++ b/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb
@@ -5,7 +5,6 @@ RSpec.shared_examples 'issue_edit snowplow tracking' do
let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_ACTION }
let(:label) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_LABEL }
let(:namespace) { project.namespace }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
it_behaves_like 'Snowplow event tracking with RedisHLL context'
end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 210987555c9..a7b186049e0 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -280,7 +280,6 @@ RSpec.describe PostReceive do
let(:category) { described_class.name }
let(:namespace) { project.namespace }
let(:user) { project.creator }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:label) { 'counts.source_code_pushes' }
let(:property) { 'source_code_pushes' }
let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: label).to_h] }
diff --git a/tooling/danger/sidekiq_queues.rb b/tooling/danger/sidekiq_queues.rb
index ae32b128682..bd6480fcba6 100644
--- a/tooling/danger/sidekiq_queues.rb
+++ b/tooling/danger/sidekiq_queues.rb
@@ -14,7 +14,7 @@ module Tooling
def changed_queue_names
@changed_queue_names ||=
(new_queues.values_at(*old_queues.keys) - old_queues.values)
- .compact.map { |queue| queue[:name] }
+ .compact.map { |queue| queue[:name] } # rubocop:disable Rails/Pluck
end
private
diff --git a/yarn.lock b/yarn.lock
index 244e5dada65..3942780e769 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5276,10 +5276,10 @@ dompurify@2.3.8:
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.8.tgz#224fe9ae57d7ebd9a1ae1ac18c1c1ca3f532226f"
integrity sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw==
-dompurify@^2.4.3:
- version "2.4.3"
- resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.3.tgz#f4133af0e6a50297fc8874e2eaedc13a3c308c03"
- integrity sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==
+dompurify@^2.4.3, dompurify@^2.4.4:
+ version "2.4.4"
+ resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.4.tgz#c17803931dd524e1b68e0e940a84567f9498f4bd"
+ integrity sha512-1e2SpqHiRx4DPvmRuXU5J0di3iQACwJM+mFGE2HAkkK7Tbnfk9WcghcAmyWc9CRrjyRRUpmuhPUH6LphQQR3EQ==
domutils@^2.5.2, domutils@^2.6.0:
version "2.6.0"
@@ -5801,10 +5801,10 @@ eslint-visitor-keys@^3.3.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
-eslint@8.32.0:
- version "8.32.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.32.0.tgz#d9690056bb6f1a302bd991e7090f5b68fbaea861"
- integrity sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==
+eslint@8.34.0:
+ version "8.34.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.34.0.tgz#fe0ab0ef478104c1f9ebc5537e303d25a8fb22d6"
+ integrity sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==
dependencies:
"@eslint/eslintrc" "^1.4.1"
"@humanwhocodes/config-array" "^0.11.8"