summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/CODEOWNERS3
-rw-r--r--.rubocop_todo/fips/sha1.yml1
-rw-r--r--.rubocop_todo/gitlab/namespaced_class.yml1
-rw-r--r--.rubocop_todo/layout/argument_alignment.yml28
-rw-r--r--.rubocop_todo/layout/line_length.yml1
-rw-r--r--.rubocop_todo/layout/space_in_lambda_literal.yml1
-rw-r--r--.rubocop_todo/rspec/context_wording.yml1
-rw-r--r--.rubocop_todo/rspec/described_class.yml1
-rw-r--r--.rubocop_todo/rspec/hooks_before_examples.yml1
-rw-r--r--.rubocop_todo/rspec/missing_feature_category.yml1
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table_app.vue13
-rw-r--r--app/assets/javascripts/oauth_application/components/oauth_secret.vue106
-rw-r--r--app/assets/javascripts/oauth_application/constants.js20
-rw-r--r--app/assets/javascripts/oauth_application/index.js21
-rw-r--r--app/assets/javascripts/pages/admin/applications/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/settings/applications/index.js3
-rw-r--r--app/assets/javascripts/pages/oauth/applications/index.js3
-rw-r--r--app/controllers/admin/applications_controller.rb5
-rw-r--r--app/controllers/groups/settings/applications_controller.rb5
-rw-r--r--app/controllers/oauth/applications_controller.rb5
-rw-r--r--app/graphql/types/ci/catalog/resource_type.rb27
-rw-r--r--app/models/ci/catalog/resource.rb2
-rw-r--r--app/views/shared/doorkeeper/applications/_show.html.haml11
-rw-r--r--app/views/shared/doorkeeper/applications/_update_form.html.haml3
-rw-r--r--db/docs/merge_trains.yml4
-rw-r--r--db/docs/schema_inconsistencies.yml2
-rw-r--r--db/post_migrate/20230329091107_truncate_p_ci_runner_machine_builds.rb14
-rw-r--r--db/post_migrate/20230329091300_swap_ci_runner_machine_builds_primary_key_v2.rb46
-rw-r--r--db/schema_migrations/202303290911071
-rw-r--r--db/schema_migrations/202303290913001
-rw-r--r--db/structure.sql2
-rw-r--r--doc/api/graphql/reference/index.md55
-rw-r--r--doc/api/visual_review_discussions.md10
-rw-r--r--doc/ci/review_apps/index.md9
-rw-r--r--doc/ci/testing/accessibility_testing.md2
-rw-r--r--doc/ci/testing/browser_performance_testing.md5
-rw-r--r--doc/ci/testing/load_performance_testing.md9
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/subscriptions/bronze_starter.md2
-rw-r--r--doc/subscriptions/quarterly_reconciliation.md2
-rw-r--r--lib/gitlab/database/batch_count.rb2
-rw-r--r--lib/gitlab/database/schema_validation/inconsistency.rb4
-rw-r--r--lib/gitlab/database/schema_validation/index.rb25
-rw-r--r--lib/gitlab/database/schema_validation/schema_inconsistency.rb15
-rw-r--r--lib/gitlab/database/schema_validation/schema_objects/base.rb4
-rw-r--r--lib/gitlab/database/schema_validation/track_inconsistency.rb77
-rw-r--r--lib/tasks/gitlab/db.rake8
-rw-r--r--locale/gitlab.pot8
-rw-r--r--spec/controllers/admin/applications_controller_spec.rb8
-rw-r--r--spec/controllers/groups/settings/applications_controller_spec.rb8
-rw-r--r--spec/controllers/oauth/applications_controller_spec.rb8
-rw-r--r--spec/db/schema_spec.rb5
-rw-r--r--spec/factories/gitlab/database/background_migration/schema_inconsistencies.rb11
-rw-r--r--spec/frontend/jobs/components/table/job_table_app_spec.js37
-rw-r--r--spec/frontend/oauth_application/components/oauth_secret_spec.js116
-rw-r--r--spec/graphql/types/ci/catalog/resource_type_spec.rb18
-rw-r--r--spec/helpers/avatars_helper_spec.rb142
-rw-r--r--spec/helpers/emoji_helper_spec.rb22
-rw-r--r--spec/helpers/feature_flags_helper_spec.rb14
-rw-r--r--spec/helpers/namespaces_helper_spec.rb33
-rw-r--r--spec/helpers/notify_helper_spec.rb17
-rw-r--r--spec/helpers/page_layout_helper_spec.rb14
-rw-r--r--spec/helpers/routing/pseudonymization_helper_spec.rb228
-rw-r--r--spec/helpers/storage_helper_spec.rb28
-rw-r--r--spec/helpers/todos_helper_spec.rb44
-rw-r--r--spec/helpers/users/group_callouts_helper_spec.rb10
-rw-r--r--spec/helpers/visibility_level_helper_spec.rb6
-rw-r--r--spec/lib/gitlab/database/schema_validation/inconsistency_spec.rb10
-rw-r--r--spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb17
-rw-r--r--spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb1
-rw-r--r--spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb1
-rw-r--r--spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb82
-rw-r--r--spec/models/ci/catalog/resource_spec.rb6
-rw-r--r--spec/support/helpers/api_internal_base_helpers.rb14
-rw-r--r--spec/support/helpers/board_helpers.rb16
-rw-r--r--spec/support/helpers/ci/source_pipeline_helpers.rb12
-rw-r--r--spec/support/helpers/feature_flag_helpers.rb22
-rw-r--r--spec/support/helpers/graphql_helpers.rb36
-rw-r--r--spec/support/helpers/stub_object_storage.rb110
-rw-r--r--spec/support/helpers/workhorse_helpers.rb41
-rw-r--r--spec/support/rspec_order_todo.yml1
-rw-r--r--spec/support/shared_examples/features/manage_applications_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb6
84 files changed, 1279 insertions, 443 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index e747e7a4858..ffdd0ef10e3 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -1281,7 +1281,6 @@ lib/gitlab/checks/** @proglottis @toon
/app/workers/stuck_ci_jobs_worker.rb
/app/workers/update_external_pull_requests_worker.rb
/lib/api/commit_statuses.rb
-/ee/app/models/merge_train.rb
/ee/app/finders/merge_trains_finder.rb
/ee/app/services/auto_merge/add_to_merge_train_when_pipeline_succeeds_service.rb
/ee/app/services/auto_merge/merge_train_service.rb
@@ -1290,7 +1289,6 @@ lib/gitlab/checks/** @proglottis @toon
/ee/app/controllers/ee/projects/pipelines_controller.rb
/ee/app/controllers/projects/pipelines/
/ee/app/controllers/projects/subscriptions_controller.rb
-/ee/app/models/merge_train.rb
/ee/app/helpers/ee/projects/pipeline_helper.rb
/ee/app/views/ci_minutes_usage_mailer/
/ee/app/views/projects/pipelines/
@@ -1334,7 +1332,6 @@ lib/gitlab/checks/** @proglottis @toon
/spec/workers/run_pipeline_schedule_worker_spec.rb
/spec/workers/stuck_ci_jobs_worker_spec.rb
/spec/workers/update_external_pull_requests_worker_spec.rb
-/ee/spec/models/merge_train_spec.rb
/ee/spec/finders/merge_trains_finder_spec.rb
/ee/spec/services/auto_merge/add_to_merge_train_when_pipeline_succeeds_service_spec.rb
/ee/spec/services/auto_merge/merge_train_service_spec.rb
diff --git a/.rubocop_todo/fips/sha1.yml b/.rubocop_todo/fips/sha1.yml
index a9637295cab..f39ca78fd81 100644
--- a/.rubocop_todo/fips/sha1.yml
+++ b/.rubocop_todo/fips/sha1.yml
@@ -30,7 +30,6 @@ Fips/SHA1:
- 'ee/spec/lib/gitlab/ci/reports/security/locations/dast_spec.rb'
- 'ee/spec/lib/gitlab/ci/reports/security/locations/dependency_scanning_spec.rb'
- 'ee/spec/migrations/update_vulnerability_occurrences_location_spec.rb'
- - 'ee/spec/models/merge_train_spec.rb'
- 'ee/spec/models/resource_weight_event_spec.rb'
- 'ee/spec/models/vulnerabilities/finding_signature_spec.rb'
- 'ee/spec/models/vulnerabilities/finding_spec.rb'
diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml
index a35783ac898..7de96b82445 100644
--- a/.rubocop_todo/gitlab/namespaced_class.yml
+++ b/.rubocop_todo/gitlab/namespaced_class.yml
@@ -923,7 +923,6 @@ Gitlab/NamespacedClass:
- 'ee/app/models/license.rb'
- 'ee/app/models/merge_request_block.rb'
- 'ee/app/models/merge_request_diff_detail.rb'
- - 'ee/app/models/merge_train.rb'
- 'ee/app/models/namespace_limit.rb'
- 'ee/app/models/path_lock.rb'
- 'ee/app/models/productivity_analytics.rb'
diff --git a/.rubocop_todo/layout/argument_alignment.yml b/.rubocop_todo/layout/argument_alignment.yml
index af8f5a62980..289b732e958 100644
--- a/.rubocop_todo/layout/argument_alignment.yml
+++ b/.rubocop_todo/layout/argument_alignment.yml
@@ -1338,14 +1338,6 @@ Layout/ArgumentAlignment:
- 'ee/spec/graphql/types/pipeline_security_report_finding_type_spec.rb'
- 'ee/spec/graphql/types/project_type_spec.rb'
- 'ee/spec/graphql/types/vulnerability_type_spec.rb'
- - 'ee/spec/helpers/billing_plans_helper_spec.rb'
- - 'ee/spec/helpers/ee/integrations_helper_spec.rb'
- - 'ee/spec/helpers/ee/namespace_user_cap_reached_alert_helper_spec.rb'
- - 'ee/spec/helpers/ee/namespaces_helper_spec.rb'
- - 'ee/spec/helpers/ee/trial_registration_helper_spec.rb'
- - 'ee/spec/helpers/license_monitoring_helper_spec.rb'
- - 'ee/spec/helpers/projects_helper_spec.rb'
- - 'ee/spec/helpers/vulnerabilities_helper_spec.rb'
- 'ee/spec/lib/analytics/group_activity_calculator_spec.rb'
- 'ee/spec/lib/analytics/merge_request_metrics_calculator_spec.rb'
- 'ee/spec/lib/api/entities/protected_environments/approval_rule_for_summary_spec.rb'
@@ -1640,7 +1632,6 @@ Layout/ArgumentAlignment:
- 'ee/spec/services/vulnerabilities/user_notes_count_service_spec.rb'
- 'ee/spec/services/vulnerability_feedback/create_service_spec.rb'
- 'ee/spec/services/vulnerability_merge_request_links/create_service_spec.rb'
- - 'ee/spec/support/helpers/vulnerability_helpers.rb'
- 'ee/spec/support/shared_examples/audit/audit_event_type_stream_shared_examples.rb'
- 'ee/spec/support/shared_examples/controllers/analytics/cycle_analytics/shared_stage_shared_examples.rb'
- 'ee/spec/support/shared_examples/features/credentials_inventory_shared_examples.rb'
@@ -2173,18 +2164,6 @@ Layout/ArgumentAlignment:
- 'spec/graphql/types/project_type_spec.rb'
- 'spec/graphql/types/root_storage_statistics_type_spec.rb'
- 'spec/graphql/types/todo_type_spec.rb'
- - 'spec/helpers/avatars_helper_spec.rb'
- - 'spec/helpers/emoji_helper_spec.rb'
- - 'spec/helpers/feature_flags_helper_spec.rb'
- - 'spec/helpers/namespaces_helper_spec.rb'
- - 'spec/helpers/notify_helper_spec.rb'
- - 'spec/helpers/page_layout_helper_spec.rb'
- - 'spec/helpers/routing/pseudonymization_helper_spec.rb'
- - 'spec/helpers/storage_helper_spec.rb'
- - 'spec/helpers/todos_helper_spec.rb'
- - 'spec/helpers/users/callouts_helper_spec.rb'
- - 'spec/helpers/users/group_callouts_helper_spec.rb'
- - 'spec/helpers/visibility_level_helper_spec.rb'
- 'spec/initializers/00_rails_disable_joins_spec.rb'
- 'spec/initializers/secret_token_spec.rb'
- 'spec/lib/api/every_api_endpoint_spec.rb'
@@ -2756,13 +2735,6 @@ Layout/ArgumentAlignment:
- 'spec/services/work_items/task_list_reference_removal_service_spec.rb'
- 'spec/services/work_items/widgets/description_service/update_service_spec.rb'
- 'spec/sidekiq/cron/job_gem_dependency_spec.rb'
- - 'spec/support/helpers/api_internal_base_helpers.rb'
- - 'spec/support/helpers/board_helpers.rb'
- - 'spec/support/helpers/ci/source_pipeline_helpers.rb'
- - 'spec/support/helpers/feature_flag_helpers.rb'
- - 'spec/support/helpers/graphql_helpers.rb'
- - 'spec/support/helpers/stub_object_storage.rb'
- - 'spec/support/helpers/workhorse_helpers.rb'
- 'spec/support/import_export/export_file_helper.rb'
- 'spec/support/redis/redis_shared_examples.rb'
- 'spec/support/shared_contexts/bulk_imports_requests_shared_context.rb'
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml
index 86faf32e8be..2499b2ee194 100644
--- a/.rubocop_todo/layout/line_length.yml
+++ b/.rubocop_todo/layout/line_length.yml
@@ -2117,7 +2117,6 @@ Layout/LineLength:
- 'ee/spec/models/merge_request_spec.rb'
- 'ee/spec/models/merge_requests/compliance_violation_spec.rb'
- 'ee/spec/models/merge_requests/external_status_check_spec.rb'
- - 'ee/spec/models/merge_train_spec.rb'
- 'ee/spec/models/namespace_setting_spec.rb'
- 'ee/spec/models/note_spec.rb'
- 'ee/spec/models/packages/package_file_spec.rb'
diff --git a/.rubocop_todo/layout/space_in_lambda_literal.yml b/.rubocop_todo/layout/space_in_lambda_literal.yml
index c311f562e93..144b4eb04a7 100644
--- a/.rubocop_todo/layout/space_in_lambda_literal.yml
+++ b/.rubocop_todo/layout/space_in_lambda_literal.yml
@@ -223,7 +223,6 @@ Layout/SpaceInLambdaLiteral:
- 'ee/app/models/iterations/cadence.rb'
- 'ee/app/models/merge_request_block.rb'
- 'ee/app/models/merge_requests/compliance_violation.rb'
- - 'ee/app/models/merge_train.rb'
- 'ee/app/models/namespaces/namespace_ban.rb'
- 'ee/app/models/requirements_management/requirement.rb'
- 'ee/app/models/resource_iteration_event.rb'
diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml
index 9e2061049a5..560c99e3b1d 100644
--- a/.rubocop_todo/rspec/context_wording.yml
+++ b/.rubocop_todo/rspec/context_wording.yml
@@ -499,7 +499,6 @@ RSpec/ContextWording:
- 'ee/spec/models/member_spec.rb'
- 'ee/spec/models/merge_request/blocking_spec.rb'
- 'ee/spec/models/merge_request_spec.rb'
- - 'ee/spec/models/merge_train_spec.rb'
- 'ee/spec/models/namespace_setting_spec.rb'
- 'ee/spec/models/note_spec.rb'
- 'ee/spec/models/packages/package_file_spec.rb'
diff --git a/.rubocop_todo/rspec/described_class.yml b/.rubocop_todo/rspec/described_class.yml
index 94c44a144bf..99800ab8257 100644
--- a/.rubocop_todo/rspec/described_class.yml
+++ b/.rubocop_todo/rspec/described_class.yml
@@ -26,7 +26,6 @@ RSpec/DescribedClass:
- 'ee/spec/models/issue_spec.rb'
- 'ee/spec/models/iteration_spec.rb'
- 'ee/spec/models/license_spec.rb'
- - 'ee/spec/models/merge_train_spec.rb'
- 'ee/spec/models/project_import_state_spec.rb'
- 'ee/spec/models/release_highlight_spec.rb'
- 'ee/spec/models/requirements_management/test_report_spec.rb'
diff --git a/.rubocop_todo/rspec/hooks_before_examples.yml b/.rubocop_todo/rspec/hooks_before_examples.yml
index a6291452db8..e161a2aba33 100644
--- a/.rubocop_todo/rspec/hooks_before_examples.yml
+++ b/.rubocop_todo/rspec/hooks_before_examples.yml
@@ -17,7 +17,6 @@ RSpec/HooksBeforeExamples:
- 'ee/spec/lib/ee/gitlab/usage_data_counters/hll_redis_counter_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/group/stage_summary_spec.rb'
- 'ee/spec/models/ee/merge_request_diff_spec.rb'
- - 'ee/spec/models/merge_train_spec.rb'
- 'ee/spec/requests/api/boards_spec.rb'
- 'ee/spec/requests/ee/projects/deploy_tokens_controller_spec.rb'
- 'ee/spec/services/ee/groups/deploy_tokens/create_service_spec.rb'
diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml
index dfcc1e48ddd..e9ede007d47 100644
--- a/.rubocop_todo/rspec/missing_feature_category.yml
+++ b/.rubocop_todo/rspec/missing_feature_category.yml
@@ -1254,7 +1254,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/models/merge_requests/compliance_violation_spec.rb'
- 'ee/spec/models/merge_requests/external_status_check_spec.rb'
- 'ee/spec/models/merge_requests/status_check_response_spec.rb'
- - 'ee/spec/models/merge_train_spec.rb'
- 'ee/spec/models/milestone_release_spec.rb'
- 'ee/spec/models/milestone_spec.rb'
- 'ee/spec/models/namespace_limit_spec.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 01e42c9eaab..24b9b695c69 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-d7ad67347247776ec267d4f2056e2c4cffcf4ebd
+c31b9fed97bb01a1790496386ceab8e31e76b1d8
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
index 2e386fd786e..ff7982319e7 100644
--- a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
+++ b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
@@ -140,6 +140,19 @@ export default {
this.infiniteScrollingTriggered = false;
this.filterSearchTriggered = true;
+ // all filters have been cleared reset query param
+ // and refetch jobs/count with defaults
+ if (!filters.length) {
+ updateHistory({
+ url: setUrlParams({ statuses: null }, window.location.href, true),
+ });
+
+ this.$apollo.queries.jobs.refetch({ statuses: null });
+ this.$apollo.queries.jobsCount.refetch({ statuses: null });
+
+ return;
+ }
+
// Eventually there will be more tokens available
// this code is written to scale for those tokens
filters.forEach((filter) => {
diff --git a/app/assets/javascripts/oauth_application/components/oauth_secret.vue b/app/assets/javascripts/oauth_application/components/oauth_secret.vue
new file mode 100644
index 00000000000..fabda19c27b
--- /dev/null
+++ b/app/assets/javascripts/oauth_application/components/oauth_secret.vue
@@ -0,0 +1,106 @@
+<script>
+import { GlButton, GlModal } from '@gitlab/ui';
+import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import InputCopyToggleVisibility from '~/vue_shared/components/form/input_copy_toggle_visibility.vue';
+import {
+ CONFIRM_MODAL,
+ CONFIRM_MODAL_TITLE,
+ COPY_SECRET,
+ DESCRIPTION_SECRET,
+ RENEW_SECRET,
+ RENEW_SECRET_FAILURE,
+ RENEW_SECRET_SUCCESS,
+ WARNING_NO_SECRET,
+} from '../constants';
+
+export default {
+ CONFIRM_MODAL,
+ CONFIRM_MODAL_TITLE,
+ COPY_SECRET,
+ DESCRIPTION_SECRET,
+ RENEW_SECRET,
+ name: 'OAuthSecret',
+ components: {
+ GlButton,
+ GlModal,
+ InputCopyToggleVisibility,
+ },
+ inject: ['initialSecret', 'renewPath'],
+ data() {
+ return {
+ secret: this.initialSecret,
+ alert: null,
+ isModalVisible: false,
+ isLoading: false,
+ };
+ },
+ computed: {
+ actionPrimary() {
+ return {
+ text: this.$options.RENEW_SECRET,
+ attributes: {
+ variant: 'confirm',
+ loading: this.isLoading,
+ },
+ };
+ },
+ },
+ created() {
+ if (!this.secret) {
+ this.alert = createAlert({ message: WARNING_NO_SECRET, variant: VARIANT_WARNING });
+ }
+ },
+ methods: {
+ displayModal() {
+ this.isModalVisible = true;
+ },
+ async renewSecret(event) {
+ event.preventDefault();
+ this.isLoading = true;
+ this.alert?.dismiss();
+
+ try {
+ const { data } = await axios.put(this.renewPath);
+ this.alert = createAlert({ message: RENEW_SECRET_SUCCESS, variant: VARIANT_SUCCESS });
+ this.secret = data.secret;
+ } catch {
+ this.alert = createAlert({ message: RENEW_SECRET_FAILURE });
+ } finally {
+ this.isLoading = false;
+ this.isModalVisible = false;
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-flex gl-flex-wrap-wrap gl-gap-5">
+ <input-copy-toggle-visibility
+ v-if="secret"
+ :copy-button-title="$options.COPY_SECRET"
+ :value="secret"
+ class="gl-mt-n3 gl-mb-0"
+ >
+ <template #description>
+ {{ $options.DESCRIPTION_SECRET }}
+ </template>
+ </input-copy-toggle-visibility>
+
+ <gl-button category="secondary" class="gl-align-self-start" @click="displayModal">{{
+ $options.RENEW_SECRET
+ }}</gl-button>
+
+ <gl-modal
+ v-model="isModalVisible"
+ :title="$options.CONFIRM_MODAL_TITLE"
+ size="sm"
+ modal-id="modal-renew-secret"
+ :action-primary="actionPrimary"
+ @primary="renewSecret"
+ >
+ {{ $options.CONFIRM_MODAL }}
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/oauth_application/constants.js b/app/assets/javascripts/oauth_application/constants.js
new file mode 100644
index 00000000000..5eaacadda78
--- /dev/null
+++ b/app/assets/javascripts/oauth_application/constants.js
@@ -0,0 +1,20 @@
+import { __, s__ } from '~/locale';
+
+export const CONFIRM_MODAL = s__(
+ 'AuthorizedApplication|Are you sure you want to renew this secret? Any applications using the old secret will no longer be able to authenticate with GitLab.',
+);
+export const CONFIRM_MODAL_TITLE = s__('AuthorizedApplication|Renew secret?');
+export const COPY_SECRET = __('Copy secret');
+export const DESCRIPTION_SECRET = __(
+ 'This is the only time the secret is accessible. Copy the secret and store it securely.',
+);
+export const RENEW_SECRET = s__('AuthorizedApplication|Renew secret');
+export const RENEW_SECRET_FAILURE = s__(
+ 'AuthorizedApplication|There was an error trying to renew the application secret. Please try again.',
+);
+export const RENEW_SECRET_SUCCESS = s__(
+ 'AuthorizedApplication|Application secret was successfully renewed.',
+);
+export const WARNING_NO_SECRET = __(
+ 'The secret is only available when you create the application or renew the secret.',
+);
diff --git a/app/assets/javascripts/oauth_application/index.js b/app/assets/javascripts/oauth_application/index.js
new file mode 100644
index 00000000000..f8f1f647a15
--- /dev/null
+++ b/app/assets/javascripts/oauth_application/index.js
@@ -0,0 +1,21 @@
+import Vue from 'vue';
+import OAuthSecret from './components/oauth_secret.vue';
+
+export const initOAuthApplicationSecret = () => {
+ const el = document.querySelector('#js-oauth-application-secret');
+
+ if (!el) {
+ return null;
+ }
+
+ const { initialSecret, renewPath } = el.dataset;
+
+ return new Vue({
+ el,
+ name: 'OAuthSecretRoot',
+ provide: { initialSecret, renewPath },
+ render(h) {
+ return h(OAuthSecret);
+ },
+ });
+};
diff --git a/app/assets/javascripts/pages/admin/applications/index.js b/app/assets/javascripts/pages/admin/applications/index.js
index 3397b02aeba..df9e38431b0 100644
--- a/app/assets/javascripts/pages/admin/applications/index.js
+++ b/app/assets/javascripts/pages/admin/applications/index.js
@@ -1,3 +1,5 @@
import initApplicationDeleteButtons from '~/admin/applications';
+import { initOAuthApplicationSecret } from '~/oauth_application';
initApplicationDeleteButtons();
+initOAuthApplicationSecret();
diff --git a/app/assets/javascripts/pages/groups/settings/applications/index.js b/app/assets/javascripts/pages/groups/settings/applications/index.js
new file mode 100644
index 00000000000..4dee5433ec9
--- /dev/null
+++ b/app/assets/javascripts/pages/groups/settings/applications/index.js
@@ -0,0 +1,3 @@
+import { initOAuthApplicationSecret } from '~/oauth_application';
+
+initOAuthApplicationSecret();
diff --git a/app/assets/javascripts/pages/oauth/applications/index.js b/app/assets/javascripts/pages/oauth/applications/index.js
new file mode 100644
index 00000000000..4dee5433ec9
--- /dev/null
+++ b/app/assets/javascripts/pages/oauth/applications/index.js
@@ -0,0 +1,3 @@
+import { initOAuthApplicationSecret } from '~/oauth_application';
+
+initOAuthApplicationSecret();
diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb
index 76564981c9b..d97fcc5df74 100644
--- a/app/controllers/admin/applications_controller.rb
+++ b/app/controllers/admin/applications_controller.rb
@@ -47,10 +47,9 @@ class Admin::ApplicationsController < Admin::ApplicationController
@application.renew_secret
if @application.save
- flash.now[:notice] = s_('AuthorizedApplication|Application secret was successfully updated.')
- render :show
+ render json: { secret: @application.plaintext_secret }
else
- redirect_to admin_application_url(@application)
+ render json: { errors: @application.errors }, status: :unprocessable_entity
end
end
diff --git a/app/controllers/groups/settings/applications_controller.rb b/app/controllers/groups/settings/applications_controller.rb
index 2bf5c95937b..3ae1ae824a0 100644
--- a/app/controllers/groups/settings/applications_controller.rb
+++ b/app/controllers/groups/settings/applications_controller.rb
@@ -46,10 +46,9 @@ module Groups
@application.renew_secret
if @application.save
- flash.now[:notice] = s_('AuthorizedApplication|Application secret was successfully updated.')
- render :show
+ render json: { secret: @application.plaintext_secret }
else
- redirect_to group_settings_application_url(@group, @application)
+ render json: { errors: @application.errors }, status: :unprocessable_entity
end
end
diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb
index 7a31738188a..2d5421f9f74 100644
--- a/app/controllers/oauth/applications_controller.rb
+++ b/app/controllers/oauth/applications_controller.rb
@@ -45,10 +45,9 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
@application.renew_secret
if @application.save
- flash.now[:notice] = s_('AuthorizedApplication|Application secret was successfully updated.')
- render :show
+ render json: { secret: @application.plaintext_secret }
else
- redirect_to oauth_application_url(@application)
+ render json: { errors: @application.errors }, status: :unprocessable_entity
end
end
diff --git a/app/graphql/types/ci/catalog/resource_type.rb b/app/graphql/types/ci/catalog/resource_type.rb
new file mode 100644
index 00000000000..b5947826fa1
--- /dev/null
+++ b/app/graphql/types/ci/catalog/resource_type.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ module Catalog
+ # rubocop: disable Graphql/AuthorizeTypes
+ class ResourceType < BaseObject
+ graphql_name 'CiCatalogResource'
+
+ connection_type_class(Types::CountableConnectionType)
+
+ field :id, GraphQL::Types::ID, null: false, description: 'ID of the catalog resource.',
+ alpha: { milestone: '15.11' }
+
+ field :name, GraphQL::Types::String, null: true, description: 'Name of the catalog resource.',
+ alpha: { milestone: '15.11' }
+
+ field :description, GraphQL::Types::String, null: true, description: 'Description of the catalog resource.',
+ alpha: { milestone: '15.11' }
+
+ field :icon, GraphQL::Types::String, null: true, description: 'Icon for the catalog resource.',
+ method: :avatar_path, alpha: { milestone: '15.11' }
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/models/ci/catalog/resource.rb b/app/models/ci/catalog/resource.rb
index 40ec41de6fe..837f1352b4d 100644
--- a/app/models/ci/catalog/resource.rb
+++ b/app/models/ci/catalog/resource.rb
@@ -13,6 +13,8 @@ module Ci
belongs_to :project
scope :for_projects, ->(project_ids) { where(project_id: project_ids) }
+
+ delegate :avatar_path, :description, :name, to: :project
end
end
end
diff --git a/app/views/shared/doorkeeper/applications/_show.html.haml b/app/views/shared/doorkeeper/applications/_show.html.haml
index 19f4c971c1d..6bebbe94a55 100644
--- a/app/views/shared/doorkeeper/applications/_show.html.haml
+++ b/app/views/shared/doorkeeper/applications/_show.html.haml
@@ -15,16 +15,7 @@
%td
= _('Secret')
%td
- - if @application.plaintext_secret
- = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-5'}) do |c|
- = c.body do
- = _('This is the only time the secret is accessible. Copy the secret and store it securely.')
- = clipboard_button(clipboard_text: @application.plaintext_secret, button_text: _('Copy'), title: _("Copy secret"), class: "btn btn-default btn-md gl-button")
- - else
- = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-5'}) do |c|
- = c.body do
- = _('The secret is only available when you create the application or renew the secret.')
- = render 'shared/doorkeeper/applications/update_form', path: renew_path
+ #js-oauth-application-secret{ data: { initial_secret: @application.plaintext_secret, renew_path: renew_path } }
%tr
%td
diff --git a/app/views/shared/doorkeeper/applications/_update_form.html.haml b/app/views/shared/doorkeeper/applications/_update_form.html.haml
deleted file mode 100644
index 1bee3288639..00000000000
--- a/app/views/shared/doorkeeper/applications/_update_form.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-- path = local_assigns.fetch(:path)
-= form_for(@application, url: path, html: {class: 'gl-display-inline-block', method: "put"}) do |f|
- = submit_tag s_('AuthorizedApplication|Renew secret'), data: { confirm: s_("AuthorizedApplication|Are you sure you want to renew this secret? Any applications using the old secret will no longer be able to authenticate with GitLab."), confirm_btn_variant: "danger" }, aria: { label: s_('AuthorizedApplication|Renew secret') }, class: 'gl-button btn btn-md btn-default'
diff --git a/db/docs/merge_trains.yml b/db/docs/merge_trains.yml
index 3b666322d3b..7d0310236e9 100644
--- a/db/docs/merge_trains.yml
+++ b/db/docs/merge_trains.yml
@@ -1,10 +1,10 @@
---
table_name: merge_trains
classes:
-- MergeTrain
+- MergeTrains::Car
feature_categories:
- continuous_integration
-description: TODO
+description: Each record represents a single merge request which is or was part of a merge train.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/827fc3ccb9335aa29fba0fc532b70015ec4c5186
milestone: '11.11'
gitlab_schema: gitlab_main
diff --git a/db/docs/schema_inconsistencies.yml b/db/docs/schema_inconsistencies.yml
index 85a2681a523..af95f26accb 100644
--- a/db/docs/schema_inconsistencies.yml
+++ b/db/docs/schema_inconsistencies.yml
@@ -5,4 +5,6 @@ feature_categories:
description: The schema_inconsistencies table contains a list of database schema inconsistencies.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114876
milestone: '15.11'
+classes:
+- Gitlab::Database::SchemaValidation::SchemaInconsistency
gitlab_schema: gitlab_main
diff --git a/db/post_migrate/20230329091107_truncate_p_ci_runner_machine_builds.rb b/db/post_migrate/20230329091107_truncate_p_ci_runner_machine_builds.rb
new file mode 100644
index 00000000000..b9efdd8234d
--- /dev/null
+++ b/db/post_migrate/20230329091107_truncate_p_ci_runner_machine_builds.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class TruncatePCiRunnerMachineBuilds < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ return unless Gitlab::Database.gitlab_schemas_for_connection(connection).include?(:gitlab_ci)
+
+ execute('TRUNCATE TABLE p_ci_runner_machine_builds')
+ end
+
+ # no-op
+ def down; end
+end
diff --git a/db/post_migrate/20230329091300_swap_ci_runner_machine_builds_primary_key_v2.rb b/db/post_migrate/20230329091300_swap_ci_runner_machine_builds_primary_key_v2.rb
new file mode 100644
index 00000000000..ad40ed118b1
--- /dev/null
+++ b/db/post_migrate/20230329091300_swap_ci_runner_machine_builds_primary_key_v2.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+class SwapCiRunnerMachineBuildsPrimaryKeyV2 < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = :p_ci_runner_machine_builds
+ BUILDS_TABLE = :ci_builds
+
+ def up
+ reorder_primary_key_columns([:build_id, :partition_id])
+ end
+
+ def down
+ reorder_primary_key_columns([:partition_id, :build_id])
+ end
+
+ private
+
+ def reorder_primary_key_columns(columns)
+ with_lock_retries(raise_on_exhaustion: true) do
+ connection.execute(<<~SQL)
+ LOCK TABLE #{BUILDS_TABLE}, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE;
+ SQL
+
+ partitions = Gitlab::Database::PostgresPartitionedTable.each_partition(TABLE_NAME).to_a
+ partitions.each { |partition| drop_table partition.identifier }
+
+ execute <<~SQL
+ ALTER TABLE #{TABLE_NAME}
+ DROP CONSTRAINT p_ci_runner_machine_builds_pkey CASCADE;
+
+ ALTER TABLE #{TABLE_NAME}
+ ADD PRIMARY KEY (#{columns.join(', ')});
+ SQL
+
+ partitions.each do |partition|
+ connection.execute(<<~SQL)
+ CREATE TABLE IF NOT EXISTS #{partition.identifier}
+ PARTITION OF #{partition.parent_identifier} #{partition.condition};
+ SQL
+ end
+ end
+ end
+end
diff --git a/db/schema_migrations/20230329091107 b/db/schema_migrations/20230329091107
new file mode 100644
index 00000000000..658d90e662f
--- /dev/null
+++ b/db/schema_migrations/20230329091107
@@ -0,0 +1 @@
+4ca98e9c93245a8fc1f4124d00d47d73d12b961affde1d53b7262ffc93582d83 \ No newline at end of file
diff --git a/db/schema_migrations/20230329091300 b/db/schema_migrations/20230329091300
new file mode 100644
index 00000000000..4a4be644126
--- /dev/null
+++ b/db/schema_migrations/20230329091300
@@ -0,0 +1 @@
+a85e3139d843295e666867129575818f61983a8b16eaa73f9b470e394d9c5476 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 06e4541147b..6c71c7d17ce 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -27376,7 +27376,7 @@ ALTER TABLE ONLY operations_user_lists
ADD CONSTRAINT operations_user_lists_pkey PRIMARY KEY (id);
ALTER TABLE ONLY p_ci_runner_machine_builds
- ADD CONSTRAINT p_ci_runner_machine_builds_pkey PRIMARY KEY (partition_id, build_id);
+ ADD CONSTRAINT p_ci_runner_machine_builds_pkey PRIMARY KEY (build_id, partition_id);
ALTER TABLE ONLY packages_build_infos
ADD CONSTRAINT packages_build_infos_pkey PRIMARY KEY (id);
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 916c01958ca..958436b3c8a 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -55,6 +55,26 @@ CI related settings that apply to the entire instance.
Returns [`CiApplicationSettings`](#ciapplicationsettings).
+### `Query.ciCatalogResources`
+
+CI Catalog resources visible to the current user.
+
+WARNING:
+**Introduced** in 15.11.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Returns [`CiCatalogResourceConnection`](#cicatalogresourceconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="querycicatalogresourcesprojectpath"></a>`projectPath` | [`ID`](#id) | Project with the namespace catalog. |
+
### `Query.ciConfig`
Linted and processed contents of a CI config.
@@ -7114,6 +7134,30 @@ The edge type for [`CiBuildNeed`](#cibuildneed).
| <a id="cibuildneededgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="cibuildneededgenode"></a>`node` | [`CiBuildNeed`](#cibuildneed) | The item at the end of the edge. |
+#### `CiCatalogResourceConnection`
+
+The connection type for [`CiCatalogResource`](#cicatalogresource).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cicatalogresourceconnectioncount"></a>`count` | [`Int!`](#int) | Total count of collection. |
+| <a id="cicatalogresourceconnectionedges"></a>`edges` | [`[CiCatalogResourceEdge]`](#cicatalogresourceedge) | A list of edges. |
+| <a id="cicatalogresourceconnectionnodes"></a>`nodes` | [`[CiCatalogResource]`](#cicatalogresource) | A list of nodes. |
+| <a id="cicatalogresourceconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `CiCatalogResourceEdge`
+
+The edge type for [`CiCatalogResource`](#cicatalogresource).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cicatalogresourceedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="cicatalogresourceedgenode"></a>`node` | [`CiCatalogResource`](#cicatalogresource) | The item at the end of the edge. |
+
#### `CiConfigGroupConnection`
The connection type for [`CiConfigGroup`](#ciconfiggroup).
@@ -11678,6 +11722,17 @@ Represents the total number of issues and their weights for a particular day.
| <a id="cibuildneedid"></a>`id` | [`ID!`](#id) | ID of the BuildNeed. |
| <a id="cibuildneedname"></a>`name` | [`String`](#string) | Name of the job we need to complete. |
+### `CiCatalogResource`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cicatalogresourcedescription"></a>`description` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.11. This feature is in Alpha. It can be changed or removed at any time. Description of the catalog resource. |
+| <a id="cicatalogresourceicon"></a>`icon` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.11. This feature is in Alpha. It can be changed or removed at any time. Icon for the catalog resource. |
+| <a id="cicatalogresourceid"></a>`id` **{warning-solid}** | [`ID!`](#id) | **Introduced** in 15.11. This feature is in Alpha. It can be changed or removed at any time. ID of the catalog resource. |
+| <a id="cicatalogresourcename"></a>`name` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.11. This feature is in Alpha. It can be changed or removed at any time. Name of the catalog resource. |
+
### `CiConfig`
#### Fields
diff --git a/doc/api/visual_review_discussions.md b/doc/api/visual_review_discussions.md
index 561dc1a26a5..496c732b337 100644
--- a/doc/api/visual_review_discussions.md
+++ b/doc/api/visual_review_discussions.md
@@ -4,13 +4,18 @@ group: Pipeline Execution
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
---
-# Visual Review discussions API **(PREMIUM)**
+<!--- start_remove The following content will be removed on remove_date: '2024-05-22' -->
+# Visual Review discussions API (deprecated) **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18710) in GitLab 12.5.
> - [Moved](https://about.gitlab.com/blog/2021/01/26/new-gitlab-product-subscription-model/) to GitLab Premium in 13.9.
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387751) in GitLab 15.8
+and is planned for removal in 17.0. This change is a breaking change.
+
Visual Review discussions are notes on merge requests sent as
-feedback from [Visual Reviews](../ci/review_apps/index.md#visual-reviews).
+feedback from [Visual Reviews](../ci/review_apps/index.md#visual-reviews-deprecated).
## Create new merge request thread
@@ -45,3 +50,4 @@ Parameters:
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/merge_requests/11/visual_review_discussions?body=comment"
```
+<!--- end_remove -->
diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md
index fb0bf7b2ae1..1b423f1df70 100644
--- a/doc/ci/review_apps/index.md
+++ b/doc/ci/review_apps/index.md
@@ -193,13 +193,18 @@ After you have the route mapping set up, it takes effect in the following locati
![View on environment button in file view](img/view_on_env_blob.png)
-## Visual Reviews **(PREMIUM)**
+<!--- start_remove The following content will be removed on remove_date: '2024-05-22' -->
+## Visual Reviews (deprecated) **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10761) in GitLab 12.0.
> - [Moved](https://about.gitlab.com/blog/2021/01/26/new-gitlab-product-subscription-model/) to GitLab Premium in 13.9.
> - It's [deployed behind a feature flag](../../user/feature_flags.md), `anonymous_visual_review_feedback`, disabled by default.
> - It's disabled on GitLab.com.
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387751) in GitLab 15.8
+and is planned for removal in 17.0. This change is a breaking change.
+
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 `anonymous_visual_review_feedback`.
@@ -305,3 +310,5 @@ the user must enter a [personal access token](../../user/profile/personal_access
with `api` scope before submitting feedback.
This same method can be used to require authentication for any public projects.
+
+<!--- end_remove -->
diff --git a/doc/ci/testing/accessibility_testing.md b/doc/ci/testing/accessibility_testing.md
index 9d479289e07..b03e4a23153 100644
--- a/doc/ci/testing/accessibility_testing.md
+++ b/doc/ci/testing/accessibility_testing.md
@@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25144) in GitLab 12.8.
WARNING:
-This feature was deprecated in GitLab 15.9
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/390424) in GitLab 15.9
and is planned for removal in 17.0. This change is a breaking change.
If your application offers a web interface, you can use
diff --git a/doc/ci/testing/browser_performance_testing.md b/doc/ci/testing/browser_performance_testing.md
index 175ecef7f09..600b1a2cf4b 100644
--- a/doc/ci/testing/browser_performance_testing.md
+++ b/doc/ci/testing/browser_performance_testing.md
@@ -4,10 +4,15 @@ group: Pipeline Execution
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
---
+<!--- start_remove The following content will be removed on remove_date: '2024-05-22' -->
# Browser Performance Testing **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3507) in GitLab 10.3.
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/388719) in GitLab 15.9
+and is planned for removal in 17.0. This change is a breaking change.
+
If your application offers a web interface and you're using
[GitLab CI/CD](../index.md), you can quickly determine the rendering performance
impact of pending code changes in the browser.
diff --git a/doc/ci/testing/load_performance_testing.md b/doc/ci/testing/load_performance_testing.md
index dac4dd555b0..2897d7fe0ab 100644
--- a/doc/ci/testing/load_performance_testing.md
+++ b/doc/ci/testing/load_performance_testing.md
@@ -4,10 +4,15 @@ group: Pipeline Execution
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
---
-# Load Performance Testing **(PREMIUM)**
+<!--- start_remove The following content will be removed on remove_date: '2024-05-22' -->
+# Load Performance Testing (deprecated) **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10683) in GitLab 13.2.
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/388723) in GitLab 15.9
+and is planned for removal in 17.0. This change is a breaking change.
+
With Load Performance Testing, you can test the impact of any pending code changes
to your application's backend in [GitLab CI/CD](../index.md).
@@ -199,3 +204,5 @@ load_performance:
rules:
- if: $CI_COMMIT_BRANCH # Modify to match your pipeline rules, or use `only/except` if needed.
```
+
+<!--- end_remove -->
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 1cd6a4fc5d2..b14ff89c804 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -224,7 +224,7 @@ Download Ruby and compile it:
mkdir /tmp/ruby && cd /tmp/ruby
curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.5.tar.gz"
echo '9afc6380a027a4fe1ae1a3e2eccb6b497b9c5ac0631c12ca56f9b7beb4848776 ruby-3.0.5.tar.gz' | sha256sum -c - && tar xzf ruby-3.0.5.tar.gz
-cd ruby-2.7.6
+cd ruby-3.0.5
./configure --disable-install-rdoc --enable-shared
make
diff --git a/doc/subscriptions/bronze_starter.md b/doc/subscriptions/bronze_starter.md
index accc0627a41..632177754f4 100644
--- a/doc/subscriptions/bronze_starter.md
+++ b/doc/subscriptions/bronze_starter.md
@@ -71,7 +71,7 @@ the tiers are no longer mentioned in GitLab documentation:
- [Code Owners as eligible approvers](../user/project/merge_requests/approvals/rules.md#code-owners-as-eligible-approvers)
- [Approval rules](../user/project/merge_requests/approvals/rules.md) features
- [Restricting push and merge access to certain users](../user/project/protected_branches.md)
- - [Visual Reviews](../ci/review_apps/index.md#visual-reviews)
+ - [Visual Reviews (deprecated)](../ci/review_apps/index.md#visual-reviews-deprecated)
- Metrics and analytics:
- [Contribution Analytics](../user/group/contribution_analytics/index.md)
- [Merge Request Analytics](../user/analytics/merge_request_analytics.md)
diff --git a/doc/subscriptions/quarterly_reconciliation.md b/doc/subscriptions/quarterly_reconciliation.md
index 126a34334c4..16f1828f2c3 100644
--- a/doc/subscriptions/quarterly_reconciliation.md
+++ b/doc/subscriptions/quarterly_reconciliation.md
@@ -91,7 +91,7 @@ sent and subject to your payment terms.
- You purchased your subscription from a reseller or another channel partner.
- You purchased a multi-year subscription.
- You purchased your subscription with a purchasing order.
-- You are a pubic sector customer.
+- You are a public sector customer.
- You have an offline environment and used a license file to activate your subscription.
- You are enrolled in a program that provides a free tier such as the GitLab for Education, GitLab for Open Source Program, or GitLab for Startups.
diff --git a/lib/gitlab/database/batch_count.rb b/lib/gitlab/database/batch_count.rb
index 7a064fb4005..7249cb3e73b 100644
--- a/lib/gitlab/database/batch_count.rb
+++ b/lib/gitlab/database/batch_count.rb
@@ -27,7 +27,7 @@
# batch_sum(User, :sign_in_count)
# batch_sum(Issue.group(:state_id), :weight))
# batch_average(Ci::Pipeline, :duration)
-# batch_average(MergeTrain.group(:status), :duration)
+# batch_average(MergeTrains::Car.group(:status), :duration)
module Gitlab
module Database
module BatchCount
diff --git a/lib/gitlab/database/schema_validation/inconsistency.rb b/lib/gitlab/database/schema_validation/inconsistency.rb
index ea85429364b..c834a6bd693 100644
--- a/lib/gitlab/database/schema_validation/inconsistency.rb
+++ b/lib/gitlab/database/schema_validation/inconsistency.rb
@@ -18,6 +18,10 @@ module Gitlab
validator_class.name.demodulize.underscore
end
+ def table_name
+ structure_sql_object&.table_name || database_object&.table_name
+ end
+
def object_name
structure_sql_object&.name || database_object&.name
end
diff --git a/lib/gitlab/database/schema_validation/index.rb b/lib/gitlab/database/schema_validation/index.rb
deleted file mode 100644
index af0d5f31f4e..00000000000
--- a/lib/gitlab/database/schema_validation/index.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Database
- module SchemaValidation
- class Index
- def initialize(parsed_stmt)
- @parsed_stmt = parsed_stmt
- end
-
- def name
- parsed_stmt.idxname
- end
-
- def statement
- @statement ||= PgQuery.deparse_stmt(parsed_stmt)
- end
-
- private
-
- attr_reader :parsed_stmt
- end
- end
- end
-end
diff --git a/lib/gitlab/database/schema_validation/schema_inconsistency.rb b/lib/gitlab/database/schema_validation/schema_inconsistency.rb
new file mode 100644
index 00000000000..6f50603e784
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/schema_inconsistency.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ class SchemaInconsistency < ApplicationRecord
+ self.table_name = :schema_inconsistencies
+
+ belongs_to :issue
+
+ validates :object_name, :valitador_name, :table_name, presence: true
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/schema_objects/base.rb b/lib/gitlab/database/schema_validation/schema_objects/base.rb
index b0c8eb087dd..43d30dc54ae 100644
--- a/lib/gitlab/database/schema_validation/schema_objects/base.rb
+++ b/lib/gitlab/database/schema_validation/schema_objects/base.rb
@@ -13,6 +13,10 @@ module Gitlab
raise NoMethodError, "subclasses of #{self.class.name} must implement #{__method__}"
end
+ def table_name
+ parsed_stmt.relation.relname
+ end
+
def statement
@statement ||= PgQuery.deparse_stmt(parsed_stmt)
end
diff --git a/lib/gitlab/database/schema_validation/track_inconsistency.rb b/lib/gitlab/database/schema_validation/track_inconsistency.rb
new file mode 100644
index 00000000000..c7e946be647
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/track_inconsistency.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ class TrackInconsistency
+ def initialize(inconsistency, project, user)
+ @inconsistency = inconsistency
+ @project = project
+ @user = user
+ end
+
+ def execute
+ return unless Gitlab.com?
+ return if inconsistency_record.present?
+
+ result = ::Issues::CreateService.new(container: project, current_user: user, params: params,
+ spam_params: nil).execute
+
+ track_inconsistency(result[:issue]) if result.success?
+ end
+
+ private
+
+ attr_reader :inconsistency, :project, :user
+
+ def track_inconsistency(issue)
+ schema_inconsistency_model.create(
+ issue: issue,
+ object_name: inconsistency.object_name,
+ table_name: inconsistency.table_name,
+ valitador_name: inconsistency.type
+ )
+ end
+
+ def params
+ {
+ title: issue_title,
+ description: issue_description,
+ confidential: true,
+ issue_type: 'issue',
+ labels: %w[database database-inconsistency-report]
+ }
+ end
+
+ def issue_title
+ "New schema inconsistency: #{inconsistency.object_name}"
+ end
+
+ def issue_description
+ <<~MSG
+ We have detected a new schema inconsistency.
+
+ Table_name: #{inconsistency.table_name}
+ Object_name: #{inconsistency.object_name}
+ Validator_name: #{inconsistency.type}
+ Error_message: #{inconsistency.error_message}
+
+ For more information, please contact the database team.
+ MSG
+ end
+
+ def schema_inconsistency_model
+ Gitlab::Database::SchemaValidation::SchemaInconsistency
+ end
+
+ def inconsistency_record
+ schema_inconsistency_model.find_by(
+ object_name: inconsistency.object_name,
+ table_name: inconsistency.table_name,
+ valitador_name: inconsistency.type
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index e7c89d6a728..a58eea0d880 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -455,7 +455,15 @@ namespace :gitlab do
inconsistencies = Gitlab::Database::SchemaValidation::Runner.new(structure_sql, database).execute
+ gitlab_url = 'gitlab-org/gitlab'
+
inconsistencies.each do |inconsistency|
+ Gitlab::Database::SchemaValidation::TrackInconsistency.new(
+ inconsistency,
+ Project.find_by_full_path(gitlab_url),
+ User.support_bot
+ ).execute
+
puts inconsistency.inspect
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 56e0c0cd5f2..fd54b44b16b 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -6180,7 +6180,7 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
-msgid "AuthorizedApplication|Application secret was successfully updated."
+msgid "AuthorizedApplication|Application secret was successfully renewed."
msgstr ""
msgid "AuthorizedApplication|Are you sure you want to renew this secret? Any applications using the old secret will no longer be able to authenticate with GitLab."
@@ -6192,9 +6192,15 @@ msgstr ""
msgid "AuthorizedApplication|Renew secret"
msgstr ""
+msgid "AuthorizedApplication|Renew secret?"
+msgstr ""
+
msgid "AuthorizedApplication|Revoke application"
msgstr ""
+msgid "AuthorizedApplication|There was an error trying to renew the application secret. Please try again."
+msgstr ""
+
msgid "Authors: %{authors}"
msgstr ""
diff --git a/spec/controllers/admin/applications_controller_spec.rb b/spec/controllers/admin/applications_controller_spec.rb
index edb17aefe86..1feda0ed36f 100644
--- a/spec/controllers/admin/applications_controller_spec.rb
+++ b/spec/controllers/admin/applications_controller_spec.rb
@@ -50,6 +50,12 @@ RSpec.describe Admin::ApplicationsController do
it { is_expected.to have_gitlab_http_status(:ok) }
it { expect { subject }.to change { application.reload.secret } }
+ it 'returns the secret in json format' do
+ subject
+
+ expect(json_response['secret']).not_to be_nil
+ end
+
context 'when renew fails' do
before do
allow_next_found_instance_of(Doorkeeper::Application) do |application|
@@ -58,7 +64,7 @@ RSpec.describe Admin::ApplicationsController do
end
it { expect { subject }.not_to change { application.reload.secret } }
- it { is_expected.to redirect_to(admin_application_url(application)) }
+ it { is_expected.to have_gitlab_http_status(:unprocessable_entity) }
end
end
diff --git a/spec/controllers/groups/settings/applications_controller_spec.rb b/spec/controllers/groups/settings/applications_controller_spec.rb
index 2fadac2dc17..c398fd044c2 100644
--- a/spec/controllers/groups/settings/applications_controller_spec.rb
+++ b/spec/controllers/groups/settings/applications_controller_spec.rb
@@ -156,6 +156,12 @@ RSpec.describe Groups::Settings::ApplicationsController do
it { is_expected.to have_gitlab_http_status(:ok) }
it { expect { subject }.to change { application.reload.secret } }
+ it 'returns the secret in json format' do
+ subject
+
+ expect(json_response['secret']).not_to be_nil
+ end
+
context 'when renew fails' do
before do
allow_next_found_instance_of(Doorkeeper::Application) do |application|
@@ -164,7 +170,7 @@ RSpec.describe Groups::Settings::ApplicationsController do
end
it { expect { subject }.not_to change { application.reload.secret } }
- it { is_expected.to redirect_to(group_settings_application_url(group, application)) }
+ it { is_expected.to have_gitlab_http_status(:unprocessable_entity) }
end
end
diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb
index e7ec268a5a2..5b9fd192ad4 100644
--- a/spec/controllers/oauth/applications_controller_spec.rb
+++ b/spec/controllers/oauth/applications_controller_spec.rb
@@ -86,6 +86,12 @@ RSpec.describe Oauth::ApplicationsController do
it_behaves_like 'redirects to login page when the user is not signed in'
it_behaves_like 'redirects to 2fa setup page when the user requires it'
+ it 'returns the secret in json format' do
+ subject
+
+ expect(json_response['secret']).not_to be_nil
+ end
+
context 'when renew fails' do
before do
allow_next_found_instance_of(Doorkeeper::Application) do |application|
@@ -94,7 +100,7 @@ RSpec.describe Oauth::ApplicationsController do
end
it { expect { subject }.not_to change { application.reload.secret } }
- it { is_expected.to redirect_to(oauth_application_url(application)) }
+ it { is_expected.to have_gitlab_http_status(:unprocessable_entity) }
end
end
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index e3e08d3b653..e4a0ccdb57f 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -11,7 +11,8 @@ RSpec.describe 'Database schema', feature_category: :database do
IGNORED_INDEXES_ON_FKS = {
slack_integrations_scopes: %w[slack_api_scope_id],
- p_ci_builds_metadata: %w[partition_id] # composable FK, the columns are reversed in the index definition
+ p_ci_builds_metadata: %w[partition_id], # composable FK, the columns are reversed in the index definition
+ p_ci_runner_machine_builds: %w[partition_id] # composable FK, the columns are reversed in the index definition
}.with_indifferent_access.freeze
TABLE_PARTITIONS = %w[ci_builds_metadata].freeze
@@ -319,7 +320,7 @@ RSpec.describe 'Database schema', feature_category: :database do
# position. Using PARTITIONABLE_MODELS instead of iterating tables since when partitioning existing tables,
# the routing table only gets created after the PK has already been created, which would be too late for a check.
- skip_tables = %w[Ci::RunnerMachineBuild]
+ skip_tables = %w[]
partitionable_models = Ci::Partitionable::Testing::PARTITIONABLE_MODELS
(partitionable_models - skip_tables).each do |klass|
model = klass.safe_constantize
diff --git a/spec/factories/gitlab/database/background_migration/schema_inconsistencies.rb b/spec/factories/gitlab/database/background_migration/schema_inconsistencies.rb
new file mode 100644
index 00000000000..b71b0971417
--- /dev/null
+++ b/spec/factories/gitlab/database/background_migration/schema_inconsistencies.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :schema_inconsistency, class: '::Gitlab::Database::SchemaValidation::SchemaInconsistency' do
+ issue factory: :issue
+
+ object_name { 'name' }
+ table_name { 'table' }
+ valitador_name { 'validator' }
+ end
+end
diff --git a/spec/frontend/jobs/components/table/job_table_app_spec.js b/spec/frontend/jobs/components/table/job_table_app_spec.js
index 6247cfcc640..19033c227d9 100644
--- a/spec/frontend/jobs/components/table/job_table_app_spec.js
+++ b/spec/frontend/jobs/components/table/job_table_app_spec.js
@@ -275,5 +275,42 @@ describe('Job table app', () => {
url: `${TEST_HOST}/?statuses=FAILED`,
});
});
+
+ it('resets query param after clearing tokens', () => {
+ createComponent();
+
+ jest.spyOn(urlUtils, 'updateHistory');
+
+ findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+
+ expect(successHandler).toHaveBeenCalledWith({
+ first: 30,
+ fullPath: 'gitlab-org/gitlab',
+ statuses: 'FAILED',
+ });
+ expect(countSuccessHandler).toHaveBeenCalledWith({
+ fullPath: 'gitlab-org/gitlab',
+ statuses: 'FAILED',
+ });
+ expect(urlUtils.updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/?statuses=FAILED`,
+ });
+
+ findFilteredSearch().vm.$emit('filterJobsBySearch', []);
+
+ expect(urlUtils.updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/`,
+ });
+
+ expect(successHandler).toHaveBeenCalledWith({
+ first: 30,
+ fullPath: 'gitlab-org/gitlab',
+ statuses: null,
+ });
+ expect(countSuccessHandler).toHaveBeenCalledWith({
+ fullPath: 'gitlab-org/gitlab',
+ statuses: null,
+ });
+ });
});
});
diff --git a/spec/frontend/oauth_application/components/oauth_secret_spec.js b/spec/frontend/oauth_application/components/oauth_secret_spec.js
new file mode 100644
index 00000000000..c38bd066da8
--- /dev/null
+++ b/spec/frontend/oauth_application/components/oauth_secret_spec.js
@@ -0,0 +1,116 @@
+import { GlButton, GlModal } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import OAuthSecret from '~/oauth_application/components/oauth_secret.vue';
+import {
+ RENEW_SECRET_FAILURE,
+ RENEW_SECRET_SUCCESS,
+ WARNING_NO_SECRET,
+} from '~/oauth_application/constants';
+import InputCopyToggleVisibility from '~/vue_shared/components/form/input_copy_toggle_visibility.vue';
+
+jest.mock('~/alert');
+const mockEvent = { preventDefault: jest.fn() };
+
+describe('OAuthSecret', () => {
+ let wrapper;
+ const renewPath = '/applications/1/renew';
+
+ const createComponent = (provide = {}) => {
+ wrapper = shallowMount(OAuthSecret, {
+ provide: {
+ initialSecret: undefined,
+ renewPath,
+ ...provide,
+ },
+ });
+ };
+
+ const findInputCopyToggleVisibility = () => wrapper.findComponent(InputCopyToggleVisibility);
+ const findRenewSecretButton = () => wrapper.findComponent(GlButton);
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ describe('when secret is provided', () => {
+ const initialSecret = 'my secret';
+ beforeEach(() => {
+ createComponent({ initialSecret });
+ });
+
+ it('shows the masked secret', () => {
+ expect(findInputCopyToggleVisibility().props('value')).toBe(initialSecret);
+ });
+
+ it('shows the renew secret button', () => {
+ expect(findRenewSecretButton().exists()).toBe(true);
+ });
+ });
+
+ describe('when secret is not provided', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('shows an alert', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: WARNING_NO_SECRET,
+ variant: VARIANT_WARNING,
+ });
+ });
+
+ it('shows the renew secret button', () => {
+ expect(findRenewSecretButton().exists()).toBe(true);
+ });
+
+ describe('when renew secret button is selected', () => {
+ beforeEach(() => {
+ createComponent();
+ findRenewSecretButton().vm.$emit('click');
+ });
+
+ it('shows a modal', () => {
+ expect(findModal().props('visible')).toBe(true);
+ });
+
+ describe('when secret renewal succeeds', () => {
+ const initialSecret = 'my secret';
+
+ beforeEach(async () => {
+ const mockAxios = new MockAdapter(axios);
+ mockAxios.onPut().reply(HTTP_STATUS_OK, { secret: initialSecret });
+ findModal().vm.$emit('primary', mockEvent);
+ await waitForPromises();
+ });
+
+ it('shows an alert', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: RENEW_SECRET_SUCCESS,
+ variant: VARIANT_SUCCESS,
+ });
+ });
+
+ it('shows the new secret', () => {
+ expect(findInputCopyToggleVisibility().props('value')).toBe(initialSecret);
+ });
+ });
+
+ describe('when secret renewal fails', () => {
+ beforeEach(async () => {
+ const mockAxios = new MockAdapter(axios);
+ mockAxios.onPut().reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ findModal().vm.$emit('primary', mockEvent);
+ await waitForPromises();
+ });
+
+ it('creates an alert', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: RENEW_SECRET_FAILURE,
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/spec/graphql/types/ci/catalog/resource_type_spec.rb b/spec/graphql/types/ci/catalog/resource_type_spec.rb
new file mode 100644
index 00000000000..d0bb45a4f1d
--- /dev/null
+++ b/spec/graphql/types/ci/catalog/resource_type_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::Catalog::ResourceType, feature_category: :pipeline_composition do
+ specify { expect(described_class.graphql_name).to eq('CiCatalogResource') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ id
+ name
+ description
+ icon
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index cef72d24c43..6eb97a99264 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -297,22 +297,26 @@ RSpec.describe AvatarsHelper do
subject { helper.user_avatar_without_link(options) }
it 'displays user avatar' do
- is_expected.to eq tag.img(alt: "#{user.name}'s avatar",
- src: avatar_icon_for_user(user, 16),
- data: { container: 'body' },
- class: 'avatar s16 has-tooltip',
- title: user.name)
+ is_expected.to eq tag.img(
+ alt: "#{user.name}'s avatar",
+ src: avatar_icon_for_user(user, 16),
+ data: { container: 'body' },
+ class: 'avatar s16 has-tooltip',
+ title: user.name
+ )
end
context 'with css_class parameter' do
let(:options) { { user: user, css_class: '.cat-pics' } }
it 'uses provided css_class' do
- is_expected.to eq tag.img(alt: "#{user.name}'s avatar",
- src: avatar_icon_for_user(user, 16),
- data: { container: 'body' },
- class: "avatar s16 #{options[:css_class]} has-tooltip",
- title: user.name)
+ is_expected.to eq tag.img(
+ alt: "#{user.name}'s avatar",
+ src: avatar_icon_for_user(user, 16),
+ data: { container: 'body' },
+ class: "avatar s16 #{options[:css_class]} has-tooltip",
+ title: user.name
+ )
end
end
@@ -320,11 +324,13 @@ RSpec.describe AvatarsHelper do
let(:options) { { user: user, size: 99 } }
it 'uses provided size' do
- is_expected.to eq tag.img(alt: "#{user.name}'s avatar",
- src: avatar_icon_for_user(user, options[:size]),
- data: { container: 'body' },
- class: "avatar s#{options[:size]} has-tooltip",
- title: user.name)
+ is_expected.to eq tag.img(
+ alt: "#{user.name}'s avatar",
+ src: avatar_icon_for_user(user, options[:size]),
+ data: { container: 'body' },
+ class: "avatar s#{options[:size]} has-tooltip",
+ title: user.name
+ )
end
end
@@ -332,11 +338,13 @@ RSpec.describe AvatarsHelper do
let(:options) { { user: user, url: '/over/the/rainbow.png' } }
it 'uses provided url' do
- is_expected.to eq tag.img(alt: "#{user.name}'s avatar",
- src: options[:url],
- data: { container: 'body' },
- class: "avatar s16 has-tooltip",
- title: user.name)
+ is_expected.to eq tag.img(
+ alt: "#{user.name}'s avatar",
+ src: options[:url],
+ data: { container: 'body' },
+ class: "avatar s16 has-tooltip",
+ title: user.name
+ )
end
end
@@ -344,11 +352,13 @@ RSpec.describe AvatarsHelper do
let(:options) { { user: user, lazy: true } }
it 'adds `lazy` class to class list, sets `data-src` with avatar URL and `src` with placeholder image' do
- is_expected.to eq tag.img(alt: "#{user.name}'s avatar",
- src: LazyImageTagHelper.placeholder_image,
- data: { container: 'body', src: avatar_icon_for_user(user, 16) },
- class: "avatar s16 has-tooltip lazy",
- title: user.name)
+ is_expected.to eq tag.img(
+ alt: "#{user.name}'s avatar",
+ src: LazyImageTagHelper.placeholder_image,
+ data: { container: 'body', src: avatar_icon_for_user(user, 16) },
+ class: "avatar s16 has-tooltip lazy",
+ title: user.name
+ )
end
end
@@ -357,11 +367,13 @@ RSpec.describe AvatarsHelper do
let(:options) { { user: user, has_tooltip: true } }
it 'adds has-tooltip' do
- is_expected.to eq tag.img(alt: "#{user.name}'s avatar",
- src: avatar_icon_for_user(user, 16),
- data: { container: 'body' },
- class: "avatar s16 has-tooltip",
- title: user.name)
+ is_expected.to eq tag.img(
+ alt: "#{user.name}'s avatar",
+ src: avatar_icon_for_user(user, 16),
+ data: { container: 'body' },
+ class: "avatar s16 has-tooltip",
+ title: user.name
+ )
end
end
@@ -369,10 +381,12 @@ RSpec.describe AvatarsHelper do
let(:options) { { user: user, has_tooltip: false } }
it 'does not add has-tooltip or data container' do
- is_expected.to eq tag.img(alt: "#{user.name}'s avatar",
- src: avatar_icon_for_user(user, 16),
- class: "avatar s16",
- title: user.name)
+ is_expected.to eq tag.img(
+ alt: "#{user.name}'s avatar",
+ src: avatar_icon_for_user(user, 16),
+ class: "avatar s16",
+ title: user.name
+ )
end
end
end
@@ -384,20 +398,24 @@ RSpec.describe AvatarsHelper do
let(:options) { { user: user, user_name: 'Tinky Winky' } }
it 'prefers user parameter' do
- is_expected.to eq tag.img(alt: "#{user.name}'s avatar",
- src: avatar_icon_for_user(user, 16),
- data: { container: 'body' },
- class: "avatar s16 has-tooltip",
- title: user.name)
+ is_expected.to eq tag.img(
+ alt: "#{user.name}'s avatar",
+ src: avatar_icon_for_user(user, 16),
+ data: { container: 'body' },
+ class: "avatar s16 has-tooltip",
+ title: user.name
+ )
end
end
it 'uses user_name and user_email parameter if user is not present' do
- is_expected.to eq tag.img(alt: "#{options[:user_name]}'s avatar",
- src: helper.avatar_icon_for_email(options[:user_email], 16),
- data: { container: 'body' },
- class: "avatar s16 has-tooltip",
- title: options[:user_name])
+ is_expected.to eq tag.img(
+ alt: "#{options[:user_name]}'s avatar",
+ src: helper.avatar_icon_for_email(options[:user_email], 16),
+ data: { container: 'body' },
+ class: "avatar s16 has-tooltip",
+ title: options[:user_name]
+ )
end
end
@@ -408,11 +426,13 @@ RSpec.describe AvatarsHelper do
let(:options) { { user: user_with_avatar, only_path: false } }
it 'will return avatar with a full path' do
- is_expected.to eq tag.img(alt: "#{user_with_avatar.name}'s avatar",
- src: avatar_icon_for_user(user_with_avatar, 16, only_path: false),
- data: { container: 'body' },
- class: "avatar s16 has-tooltip",
- title: user_with_avatar.name)
+ is_expected.to eq tag.img(
+ alt: "#{user_with_avatar.name}'s avatar",
+ src: avatar_icon_for_user(user_with_avatar, 16, only_path: false),
+ data: { container: 'body' },
+ class: "avatar s16 has-tooltip",
+ title: user_with_avatar.name
+ )
end
end
@@ -420,11 +440,13 @@ RSpec.describe AvatarsHelper do
let(:options) { { user_email: user_with_avatar.email, user_name: user_with_avatar.username, only_path: false } }
it 'will return avatar with a full path' do
- is_expected.to eq tag.img(alt: "#{user_with_avatar.username}'s avatar",
- src: helper.avatar_icon_for_email(user_with_avatar.email, 16, only_path: false),
- data: { container: 'body' },
- class: "avatar s16 has-tooltip",
- title: user_with_avatar.username)
+ is_expected.to eq tag.img(
+ alt: "#{user_with_avatar.username}'s avatar",
+ src: helper.avatar_icon_for_email(user_with_avatar.email, 16, only_path: false),
+ data: { container: 'body' },
+ class: "avatar s16 has-tooltip",
+ title: user_with_avatar.username
+ )
end
end
end
@@ -447,11 +469,13 @@ RSpec.describe AvatarsHelper do
let(:resource) { user.namespace }
it 'displays user avatar' do
- is_expected.to eq tag.img(alt: "#{user.name}'s avatar",
- src: avatar_icon_for_user(user, 32),
- data: { container: 'body' },
- class: 'avatar s32 has-tooltip',
- title: user.name)
+ is_expected.to eq tag.img(
+ alt: "#{user.name}'s avatar",
+ src: avatar_icon_for_user(user, 32),
+ data: { container: 'body' },
+ class: 'avatar s32 has-tooltip',
+ title: user.name
+ )
end
end
diff --git a/spec/helpers/emoji_helper_spec.rb b/spec/helpers/emoji_helper_spec.rb
index 6f4c962c0fb..e16c96c86ed 100644
--- a/spec/helpers/emoji_helper_spec.rb
+++ b/spec/helpers/emoji_helper_spec.rb
@@ -12,10 +12,12 @@ RSpec.describe EmojiHelper do
subject { helper.emoji_icon(emoji_text, options) }
it 'has no options' do
- is_expected.to include('<gl-emoji',
- "title=\"#{emoji_text}\"",
- "data-name=\"#{emoji_text}\"",
- "data-unicode-version=\"#{unicode_version}\"")
+ is_expected.to include(
+ '<gl-emoji',
+ "title=\"#{emoji_text}\"",
+ "data-name=\"#{emoji_text}\"",
+ "data-unicode-version=\"#{unicode_version}\""
+ )
is_expected.not_to include(aria_hidden_option)
end
@@ -23,11 +25,13 @@ RSpec.describe EmojiHelper do
let(:options) { { 'aria-hidden': true } }
it 'applies aria-hidden' do
- is_expected.to include('<gl-emoji',
- "title=\"#{emoji_text}\"",
- "data-name=\"#{emoji_text}\"",
- "data-unicode-version=\"#{unicode_version}\"",
- aria_hidden_option)
+ is_expected.to include(
+ '<gl-emoji',
+ "title=\"#{emoji_text}\"",
+ "data-name=\"#{emoji_text}\"",
+ "data-unicode-version=\"#{unicode_version}\"",
+ aria_hidden_option
+ )
end
end
end
diff --git a/spec/helpers/feature_flags_helper_spec.rb b/spec/helpers/feature_flags_helper_spec.rb
index 786454c6c4d..a5e7f8d273e 100644
--- a/spec/helpers/feature_flags_helper_spec.rb
+++ b/spec/helpers/feature_flags_helper_spec.rb
@@ -33,12 +33,14 @@ RSpec.describe FeatureFlagsHelper do
subject { helper.edit_feature_flag_data }
it 'contains all the data needed to edit feature flags' do
- is_expected.to include(endpoint: "/#{project.full_path}/-/feature_flags/#{feature_flag.iid}",
- project_id: project.id,
- feature_flags_path: "/#{project.full_path}/-/feature_flags",
- environments_endpoint: "/#{project.full_path}/-/environments/search.json",
- strategy_type_docs_page_path: "/help/operations/feature_flags#feature-flag-strategies",
- environments_scope_docs_path: "/help/ci/environments/index.md#limit-the-environment-scope-of-a-cicd-variable")
+ is_expected.to include(
+ endpoint: "/#{project.full_path}/-/feature_flags/#{feature_flag.iid}",
+ project_id: project.id,
+ feature_flags_path: "/#{project.full_path}/-/feature_flags",
+ environments_endpoint: "/#{project.full_path}/-/environments/search.json",
+ strategy_type_docs_page_path: "/help/operations/feature_flags#feature-flag-strategies",
+ environments_scope_docs_path: "/help/ci/environments/index.md#limit-the-environment-scope-of-a-cicd-variable"
+ )
end
end
end
diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb
index 3e6780d6831..e288a604be6 100644
--- a/spec/helpers/namespaces_helper_spec.rb
+++ b/spec/helpers/namespaces_helper_spec.rb
@@ -6,38 +6,35 @@ RSpec.describe NamespacesHelper do
let!(:admin) { create(:admin) }
let!(:admin_project_creation_level) { nil }
let!(:admin_group) do
- create(:group,
- :private,
- project_creation_level: admin_project_creation_level)
+ create(:group, :private, project_creation_level: admin_project_creation_level)
end
let!(:user) { create(:user) }
let!(:user_project_creation_level) { nil }
let!(:user_group) do
- create(:group,
- :private,
- project_creation_level: user_project_creation_level)
+ create(:group, :private, project_creation_level: user_project_creation_level)
end
let!(:subgroup1) do
- create(:group,
- :private,
- parent: admin_group,
- project_creation_level: nil)
+ create(:group, :private, parent: admin_group, project_creation_level: nil)
end
let!(:subgroup2) do
- create(:group,
- :private,
- parent: admin_group,
- project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS)
+ create(
+ :group,
+ :private,
+ parent: admin_group,
+ project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS
+ )
end
let!(:subgroup3) do
- create(:group,
- :private,
- parent: admin_group,
- project_creation_level: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
+ create(
+ :group,
+ :private,
+ parent: admin_group,
+ project_creation_level: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS
+ )
end
before do
diff --git a/spec/helpers/notify_helper_spec.rb b/spec/helpers/notify_helper_spec.rb
index 09da2b89dff..bc1b927cc93 100644
--- a/spec/helpers/notify_helper_spec.rb
+++ b/spec/helpers/notify_helper_spec.rb
@@ -64,10 +64,19 @@ RSpec.describe NotifyHelper do
mr_link_style = "font-weight: 600;color:#3777b0;text-decoration:none"
reviewer_avatar_style = "border-radius:12px;margin:-7px 0 -7px 3px;"
mr_link = link_to(merge_request.to_reference, merge_request_url(merge_request), style: mr_link_style).html_safe
- reviewer_avatar = content_tag(:img, nil, height: "24", src: avatar_icon_for_user, style: reviewer_avatar_style, \
- width: "24", alt: "Avatar", class: "avatar").html_safe
- reviewer_link = link_to(reviewer.name, user_url(reviewer), style: "color:#333333;text-decoration:none;", \
- class: "muted").html_safe
+ reviewer_avatar = content_tag(
+ :img,
+ nil,
+ height: "24",
+ src: avatar_icon_for_user,
+ style: reviewer_avatar_style,
+ width: "24",
+ alt: "Avatar",
+ class: "avatar"
+ ).html_safe
+ reviewer_link = link_to(
+ reviewer.name, user_url(reviewer), style: "color:#333333;text-decoration:none;", class: "muted"
+ ).html_safe
result = helper.merge_request_hash_param(merge_request, reviewer)
expect(result[:mr_highlight]).to eq '<span style="font-weight: 600;color:#333333;">'.html_safe
expect(result[:highlight_end]).to eq '</span>'.html_safe
diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb
index eb42ce18da0..9694921e223 100644
--- a/spec/helpers/page_layout_helper_spec.rb
+++ b/spec/helpers/page_layout_helper_spec.rb
@@ -128,12 +128,14 @@ RSpec.describe PageLayoutHelper do
describe 'a bare controller' do
it 'returns an empty context' do
- expect(search_context).to have_attributes(project: nil,
- group: nil,
- snippets: [],
- project_metadata: {},
- group_metadata: {},
- search_url: '/search')
+ expect(search_context).to have_attributes(
+ project: nil,
+ group: nil,
+ snippets: [],
+ project_metadata: {},
+ group_metadata: {},
+ search_url: '/search'
+ )
end
end
end
diff --git a/spec/helpers/routing/pseudonymization_helper_spec.rb b/spec/helpers/routing/pseudonymization_helper_spec.rb
index eb2cb548f35..784579dc895 100644
--- a/spec/helpers/routing/pseudonymization_helper_spec.rb
+++ b/spec/helpers/routing/pseudonymization_helper_spec.rb
@@ -26,17 +26,19 @@ RSpec.describe ::Routing::PseudonymizationHelper do
context 'with controller for MR' do
let(:masked_url) { "http://localhost/namespace#{group.id}/project#{project.id}/-/merge_requests/#{merge_request.id}" }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: "projects/merge_requests",
- action: "show",
- namespace_id: group.name,
- project_id: project.name,
- id: merge_request.id.to_s
- },
- protocol: 'http',
- host: 'localhost',
- query_string: '')
+ double(
+ :Request,
+ path_parameters: {
+ controller: "projects/merge_requests",
+ action: "show",
+ namespace_id: group.name,
+ project_id: project.name,
+ id: merge_request.id.to_s
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: ''
+ )
end
before do
@@ -49,17 +51,19 @@ RSpec.describe ::Routing::PseudonymizationHelper do
context 'with controller for issue' do
let(:masked_url) { "http://localhost/namespace#{group.id}/project#{project.id}/-/issues/#{issue.id}" }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: "projects/issues",
- action: "show",
- namespace_id: group.name,
- project_id: project.name,
- id: issue.id.to_s
- },
- protocol: 'http',
- host: 'localhost',
- query_string: '')
+ double(
+ :Request,
+ path_parameters: {
+ controller: "projects/issues",
+ action: "show",
+ namespace_id: group.name,
+ project_id: project.name,
+ id: issue.id.to_s
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: ''
+ )
end
before do
@@ -74,16 +78,18 @@ RSpec.describe ::Routing::PseudonymizationHelper do
let(:group) { subgroup }
let(:project) { subproject }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: 'projects',
- action: 'show',
- namespace_id: subgroup.name,
- id: subproject.name
- },
- protocol: 'http',
- host: 'localhost',
- query_string: '')
+ double(
+ :Request,
+ path_parameters: {
+ controller: 'projects',
+ action: 'show',
+ namespace_id: subgroup.name,
+ id: subproject.name
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: ''
+ )
end
before do
@@ -97,15 +103,17 @@ RSpec.describe ::Routing::PseudonymizationHelper do
let(:masked_url) { "http://localhost/groups/namespace#{subgroup.id}/-/shared" }
let(:group) { subgroup }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: 'groups',
- action: 'show',
- id: subgroup.name
- },
- protocol: 'http',
- host: 'localhost',
- query_string: '')
+ double(
+ :Request,
+ path_parameters: {
+ controller: 'groups',
+ action: 'show',
+ id: subgroup.name
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: ''
+ )
end
before do
@@ -118,17 +126,19 @@ RSpec.describe ::Routing::PseudonymizationHelper do
context 'with controller for blob with file path' do
let(:masked_url) { "http://localhost/namespace#{group.id}/project#{project.id}/-/blob/:repository_path" }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: 'projects/blob',
- action: 'show',
- namespace_id: group.name,
- project_id: project.name,
- id: 'master/README.md'
- },
- protocol: 'http',
- host: 'localhost',
- query_string: '')
+ double(
+ :Request,
+ path_parameters: {
+ controller: 'projects/blob',
+ action: 'show',
+ namespace_id: group.name,
+ project_id: project.name,
+ id: 'master/README.md'
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: ''
+ )
end
before do
@@ -141,14 +151,16 @@ RSpec.describe ::Routing::PseudonymizationHelper do
context 'when assignee_username is present' do
let(:masked_url) { "http://localhost/dashboard/issues?assignee_username=masked_assignee_username" }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: 'dashboard',
- action: 'issues'
- },
- protocol: 'http',
- host: 'localhost',
- query_string: 'assignee_username=root')
+ double(
+ :Request,
+ path_parameters: {
+ controller: 'dashboard',
+ action: 'issues'
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: 'assignee_username=root'
+ )
end
before do
@@ -161,14 +173,16 @@ RSpec.describe ::Routing::PseudonymizationHelper do
context 'when author_username is present' do
let(:masked_url) { "http://localhost/dashboard/issues?author_username=masked_author_username&scope=all&state=opened" }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: 'dashboard',
- action: 'issues'
- },
- protocol: 'http',
- host: 'localhost',
- query_string: 'author_username=root&scope=all&state=opened')
+ double(
+ :Request,
+ path_parameters: {
+ controller: 'dashboard',
+ action: 'issues'
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: 'author_username=root&scope=all&state=opened'
+ )
end
before do
@@ -181,14 +195,16 @@ RSpec.describe ::Routing::PseudonymizationHelper do
context 'when some query params are not required to be masked' do
let(:masked_url) { "http://localhost/dashboard/issues?author_username=masked_author_username&scope=all&state=masked_state&tab=2" }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: 'dashboard',
- action: 'issues'
- },
- protocol: 'http',
- host: 'localhost',
- query_string: 'author_username=root&scope=all&state=opened&tab=2')
+ double(
+ :Request,
+ path_parameters: {
+ controller: 'dashboard',
+ action: 'issues'
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: 'author_username=root&scope=all&state=opened&tab=2'
+ )
end
before do
@@ -202,14 +218,16 @@ RSpec.describe ::Routing::PseudonymizationHelper do
context 'when query string has keys with the same names as path params' do
let(:masked_url) { "http://localhost/dashboard/issues?action=masked_action&scope=all&state=opened" }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: 'dashboard',
- action: 'issues'
- },
- protocol: 'http',
- host: 'localhost',
- query_string: 'action=foobar&scope=all&state=opened')
+ double(
+ :Request,
+ path_parameters: {
+ controller: 'dashboard',
+ action: 'issues'
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: 'action=foobar&scope=all&state=opened'
+ )
end
before do
@@ -223,16 +241,18 @@ RSpec.describe ::Routing::PseudonymizationHelper do
describe 'when url has no params to mask' do
let(:original_url) { 'http://localhost/-/security/vulnerabilities' }
let(:request) do
- double(:Request,
- path_parameters: {
- controller: 'security/vulnerabilities',
- action: 'index'
- },
- protocol: 'http',
- host: 'localhost',
- query_string: '',
- original_fullpath: '/-/security/vulnerabilities',
- original_url: original_url)
+ double(
+ :Request,
+ path_parameters: {
+ controller: 'security/vulnerabilities',
+ action: 'index'
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: '',
+ original_fullpath: '/-/security/vulnerabilities',
+ original_url: original_url
+ )
end
before do
@@ -247,15 +267,17 @@ RSpec.describe ::Routing::PseudonymizationHelper do
describe 'when it raises exception' do
context 'calls error tracking' do
let(:request) do
- double(:Request,
- path_parameters: {
- controller: 'dashboard',
- action: 'issues'
- },
- protocol: 'http',
- host: 'localhost',
- query_string: 'assignee_username=root',
- original_fullpath: '/dashboard/issues?assignee_username=root')
+ double(
+ :Request,
+ path_parameters: {
+ controller: 'dashboard',
+ action: 'issues'
+ },
+ protocol: 'http',
+ host: 'localhost',
+ query_string: 'assignee_username=root',
+ original_fullpath: '/dashboard/issues?assignee_username=root'
+ )
end
before do
diff --git a/spec/helpers/storage_helper_spec.rb b/spec/helpers/storage_helper_spec.rb
index 6c0f1034d65..d62da2ca714 100644
--- a/spec/helpers/storage_helper_spec.rb
+++ b/spec/helpers/storage_helper_spec.rb
@@ -24,18 +24,22 @@ RSpec.describe StorageHelper do
describe "#storage_counters_details" do
let_it_be(:namespace) { create(:namespace) }
let_it_be(:project) do
- create(:project,
- namespace: namespace,
- statistics: build(:project_statistics,
- namespace: namespace,
- repository_size: 10.kilobytes,
- wiki_size: 10.bytes,
- lfs_objects_size: 20.gigabytes,
- build_artifacts_size: 30.megabytes,
- pipeline_artifacts_size: 11.megabytes,
- snippets_size: 40.megabytes,
- packages_size: 12.megabytes,
- uploads_size: 15.megabytes))
+ create(
+ :project,
+ namespace: namespace,
+ statistics: build(
+ :project_statistics,
+ namespace: namespace,
+ repository_size: 10.kilobytes,
+ wiki_size: 10.bytes,
+ lfs_objects_size: 20.gigabytes,
+ build_artifacts_size: 30.megabytes,
+ pipeline_artifacts_size: 11.megabytes,
+ snippets_size: 40.megabytes,
+ packages_size: 12.megabytes,
+ uploads_size: 15.megabytes
+ )
+ )
end
let(:message) { 'Repository: 10 KB / Wikis: 10 Bytes / Build Artifacts: 30 MB / Pipeline Artifacts: 11 MB / LFS: 20 GB / Snippets: 40 MB / Packages: 12 MB / Uploads: 15 MB' }
diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb
index 8d24e9576e0..54b7c5ce11e 100644
--- a/spec/helpers/todos_helper_spec.rb
+++ b/spec/helpers/todos_helper_spec.rb
@@ -9,20 +9,21 @@ RSpec.describe TodosHelper do
let_it_be(:issue) { create(:issue, title: 'Issue 1', project: project) }
let_it_be(:design) { create(:design, issue: issue) }
let_it_be(:note) do
- create(:note,
- project: issue.project,
- note: 'I am note, hear me roar')
+ create(:note, project: issue.project, note: 'I am note, hear me roar')
end
let_it_be(:group) { create(:group, :public, name: 'Group 1') }
let_it_be(:design_todo) do
- create(:todo, :mentioned,
- user: user,
- project: project,
- target: design,
- author: author,
- note: note)
+ create(
+ :todo,
+ :mentioned,
+ user: user,
+ project: project,
+ target: design,
+ author: author,
+ note: note
+ )
end
let_it_be(:alert_todo) do
@@ -93,11 +94,14 @@ RSpec.describe TodosHelper do
context 'when given a non-design todo' do
let(:todo) do
- build_stubbed(:todo, :assigned,
- user: user,
- project: issue.project,
- target: issue,
- author: author)
+ build_stubbed(
+ :todo,
+ :assigned,
+ user: user,
+ project: issue.project,
+ target: issue,
+ author: author
+ )
end
it 'returns the title' do
@@ -154,11 +158,13 @@ RSpec.describe TodosHelper do
context 'when a user requests access to group' do
let_it_be(:group_access_request_todo) do
- create(:todo,
- target_id: group.id,
- target_type: group.class.polymorphic_name,
- group: group,
- action: Todo::MEMBER_ACCESS_REQUESTED)
+ create(
+ :todo,
+ target_id: group.id,
+ target_type: group.class.polymorphic_name,
+ group: group,
+ action: Todo::MEMBER_ACCESS_REQUESTED
+ )
end
it 'responds with access requests tab' do
diff --git a/spec/helpers/users/group_callouts_helper_spec.rb b/spec/helpers/users/group_callouts_helper_spec.rb
index da67c4921b3..c6679069c49 100644
--- a/spec/helpers/users/group_callouts_helper_spec.rb
+++ b/spec/helpers/users/group_callouts_helper_spec.rb
@@ -70,10 +70,12 @@ RSpec.describe Users::GroupCalloutsHelper do
context 'when the invite_members_banner has been dismissed' do
before do
- create(:group_callout,
- user: user,
- group: group,
- feature_name: described_class::INVITE_MEMBERS_BANNER)
+ create(
+ :group_callout,
+ user: user,
+ group: group,
+ feature_name: described_class::INVITE_MEMBERS_BANNER
+ )
end
it { is_expected.to eq(false) }
diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb
index a0bd629e3e6..8f37bf29a4b 100644
--- a/spec/helpers/visibility_level_helper_spec.rb
+++ b/spec/helpers/visibility_level_helper_spec.rb
@@ -178,8 +178,10 @@ RSpec.describe VisibilityLevelHelper, feature_category: :system_access do
end
before do
- stub_application_setting(restricted_visibility_levels: restricted_levels,
- default_project_visibility: global_default_level)
+ stub_application_setting(
+ restricted_visibility_levels: restricted_levels,
+ default_project_visibility: global_default_level
+ )
end
with_them do
diff --git a/spec/lib/gitlab/database/schema_validation/inconsistency_spec.rb b/spec/lib/gitlab/database/schema_validation/inconsistency_spec.rb
index 890aa38cc7f..cb3df75b3fb 100644
--- a/spec/lib/gitlab/database/schema_validation/inconsistency_spec.rb
+++ b/spec/lib/gitlab/database/schema_validation/inconsistency_spec.rb
@@ -11,8 +11,8 @@ RSpec.describe Gitlab::Database::SchemaValidation::Inconsistency, feature_catego
let(:structure_stmt) { PgQuery.parse(structure_sql_statement).tree.stmts.first.stmt.index_stmt }
let(:database_stmt) { PgQuery.parse(database_statement).tree.stmts.first.stmt.index_stmt }
- let(:structure_sql_object) { Gitlab::Database::SchemaValidation::Index.new(structure_stmt) }
- let(:database_object) { Gitlab::Database::SchemaValidation::Index.new(database_stmt) }
+ let(:structure_sql_object) { Gitlab::Database::SchemaValidation::SchemaObjects::Index.new(structure_stmt) }
+ let(:database_object) { Gitlab::Database::SchemaValidation::SchemaObjects::Index.new(database_stmt) }
subject(:inconsistency) { described_class.new(validator, structure_sql_object, database_object) }
@@ -44,6 +44,12 @@ RSpec.describe Gitlab::Database::SchemaValidation::Inconsistency, feature_catego
end
end
+ describe '#table_name' do
+ it 'returns the table name' do
+ expect(inconsistency.table_name).to eq('achievements')
+ end
+ end
+
describe '#inspect' do
let(:expected_output) do
<<~MSG
diff --git a/spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb b/spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb
new file mode 100644
index 00000000000..7d6a279def9
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::SchemaInconsistency, type: :model, feature_category: :database do
+ it { is_expected.to be_a ApplicationRecord }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:issue) }
+ end
+
+ describe "Validations" do
+ it { is_expected.to validate_presence_of(:object_name) }
+ it { is_expected.to validate_presence_of(:valitador_name) }
+ it { is_expected.to validate_presence_of(:table_name) }
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb b/spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb
index 1aaa994e3bb..43d8fa38ec8 100644
--- a/spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb
+++ b/spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::SchemaValidation::SchemaObjects::Index, feature_category: :database do
let(:statement) { 'CREATE INDEX index_name ON public.achievements USING btree (namespace_id)' }
let(:name) { 'index_name' }
+ let(:table_name) { 'achievements' }
include_examples 'schema objects assertions for', 'index_stmt'
end
diff --git a/spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb b/spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb
index 8000a54ee27..3c2481dfae0 100644
--- a/spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb
+++ b/spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::SchemaValidation::SchemaObjects::Trigger, feature_category: :database do
let(:statement) { 'CREATE TRIGGER my_trigger BEFORE INSERT ON todos FOR EACH ROW EXECUTE FUNCTION trigger()' }
let(:name) { 'my_trigger' }
+ let(:table_name) { 'todos' }
include_examples 'schema objects assertions for', 'create_trig_stmt'
end
diff --git a/spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb b/spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb
new file mode 100644
index 00000000000..84db721fc2d
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::TrackInconsistency, feature_category: :database do
+ describe '#execute' do
+ let(:validator) { Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionIndexes }
+
+ let(:database_statement) { 'CREATE INDEX index_name ON public.achievements USING btree (namespace_id)' }
+ let(:structure_sql_statement) { 'CREATE INDEX index_name ON public.achievements USING btree (id)' }
+
+ let(:structure_stmt) { PgQuery.parse(structure_sql_statement).tree.stmts.first.stmt.index_stmt }
+ let(:database_stmt) { PgQuery.parse(database_statement).tree.stmts.first.stmt.index_stmt }
+
+ let(:structure_sql_object) { Gitlab::Database::SchemaValidation::SchemaObjects::Index.new(structure_stmt) }
+ let(:database_object) { Gitlab::Database::SchemaValidation::SchemaObjects::Index.new(database_stmt) }
+
+ let(:inconsistency) do
+ Gitlab::Database::SchemaValidation::Inconsistency.new(validator, structure_sql_object, database_object)
+ end
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ subject(:execute) { described_class.new(inconsistency, project, user).execute }
+
+ before do
+ stub_spam_services
+ end
+
+ context 'when is not GitLab.com' do
+ it 'does not create a schema inconsistency record' do
+ allow(Gitlab).to receive(:com?).and_return(false)
+
+ expect { execute }.not_to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count }
+ end
+ end
+
+ context 'when the issue creation fails' do
+ let(:issue_creation) { instance_double(Mutations::Issues::Create, resolve: { errors: 'error' }) }
+
+ before do
+ allow(Mutations::Issues::Create).to receive(:new).and_return(issue_creation)
+ end
+
+ it 'does not create a schema inconsistency record' do
+ allow(Gitlab).to receive(:com?).and_return(true)
+
+ expect { execute }.not_to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count }
+ end
+ end
+
+ context 'when a new inconsistency is found' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'creates a new schema inconsistency record' do
+ allow(Gitlab).to receive(:com?).and_return(true)
+
+ expect { execute }.to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count }
+ end
+ end
+
+ context 'when the schema inconsistency already exists' do
+ before do
+ project.add_developer(user)
+ end
+
+ let!(:schema_inconsistency) do
+ create(:schema_inconsistency, object_name: 'index_name', table_name: 'achievements',
+ valitador_name: 'different_definition_indexes')
+ end
+
+ it 'does not create a schema inconsistency record' do
+ allow(Gitlab).to receive(:com?).and_return(true)
+
+ expect { execute }.not_to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count }
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/catalog/resource_spec.rb b/spec/models/ci/catalog/resource_spec.rb
index 78656c743ed..1a699fcd842 100644
--- a/spec/models/ci/catalog/resource_spec.rb
+++ b/spec/models/ci/catalog/resource_spec.rb
@@ -3,6 +3,12 @@
require 'spec_helper'
RSpec.describe Ci::Catalog::Resource, feature_category: :pipeline_composition do
+ it { is_expected.to belong_to(:project) }
+
+ it { is_expected.to delegate_method(:avatar_path).to(:project) }
+ it { is_expected.to delegate_method(:description).to(:project) }
+ it { is_expected.to delegate_method(:name).to(:project) }
+
describe '.for_projects' do
it 'returns catalog resources for the given project IDs' do
project = create(:project)
diff --git a/spec/support/helpers/api_internal_base_helpers.rb b/spec/support/helpers/api_internal_base_helpers.rb
index e89716571f9..8299821a699 100644
--- a/spec/support/helpers/api_internal_base_helpers.rb
+++ b/spec/support/helpers/api_internal_base_helpers.rb
@@ -44,12 +44,14 @@ module APIInternalBaseHelpers
end
def push(key, container, protocol = 'ssh', env: nil, changes: nil)
- push_with_path(key,
- full_path: full_path_for(container),
- gl_repository: gl_repository_for(container),
- protocol: protocol,
- env: env,
- changes: changes)
+ push_with_path(
+ key,
+ full_path: full_path_for(container),
+ gl_repository: gl_repository_for(container),
+ protocol: protocol,
+ env: env,
+ changes: changes
+ )
end
def push_with_path(key, full_path:, gl_repository: nil, protocol: 'ssh', env: nil, changes: nil)
diff --git a/spec/support/helpers/board_helpers.rb b/spec/support/helpers/board_helpers.rb
index d7277ba9a20..c7a7993c52b 100644
--- a/spec/support/helpers/board_helpers.rb
+++ b/spec/support/helpers/board_helpers.rb
@@ -29,13 +29,15 @@ module BoardHelpers
# ensure there is enough horizontal space for four board lists
resize_window(2000, 800)
- drag_to(selector: selector,
- scrollable: '#board-app',
- list_from_index: list_from_index,
- from_index: from_index,
- to_index: to_index,
- list_to_index: list_to_index,
- perform_drop: perform_drop)
+ drag_to(
+ selector: selector,
+ scrollable: '#board-app',
+ list_from_index: list_from_index,
+ from_index: from_index,
+ to_index: to_index,
+ list_to_index: list_to_index,
+ perform_drop: perform_drop
+ )
end
wait_for_requests
diff --git a/spec/support/helpers/ci/source_pipeline_helpers.rb b/spec/support/helpers/ci/source_pipeline_helpers.rb
index b99f499cc16..ef3aea7de52 100644
--- a/spec/support/helpers/ci/source_pipeline_helpers.rb
+++ b/spec/support/helpers/ci/source_pipeline_helpers.rb
@@ -3,11 +3,13 @@
module Ci
module SourcePipelineHelpers
def create_source_pipeline(upstream, downstream)
- create(:ci_sources_pipeline,
- source_job: create(:ci_build, pipeline: upstream),
- source_project: upstream.project,
- pipeline: downstream,
- project: downstream.project)
+ create(
+ :ci_sources_pipeline,
+ source_job: create(:ci_build, pipeline: upstream),
+ source_project: upstream.project,
+ pipeline: downstream,
+ project: downstream.project
+ )
end
end
end
diff --git a/spec/support/helpers/feature_flag_helpers.rb b/spec/support/helpers/feature_flag_helpers.rb
index 5a1c5a6bdab..3cf611c66e6 100644
--- a/spec/support/helpers/feature_flag_helpers.rb
+++ b/spec/support/helpers/feature_flag_helpers.rb
@@ -2,22 +2,32 @@
module FeatureFlagHelpers
def create_flag(project, name, active = true, description: nil, version: Operations::FeatureFlag.versions['new_version_flag'])
- create(:operations_feature_flag, name: name, active: active, version: version,
- description: description, project: project)
+ create(
+ :operations_feature_flag,
+ name: name,
+ active: active,
+ version: version,
+ description: description,
+ project: project
+ )
end
def create_scope(feature_flag, environment_scope, active = true, strategies = [{ name: "default", parameters: {} }])
- create(:operations_feature_flag_scope,
+ create(
+ :operations_feature_flag_scope,
feature_flag: feature_flag,
environment_scope: environment_scope,
active: active,
- strategies: strategies)
+ strategies: strategies
+ )
end
def create_strategy(feature_flag, name = 'default', parameters = {})
- create(:operations_strategy,
+ create(
+ :operations_strategy,
feature_flag: feature_flag,
- name: name)
+ name: name
+ )
end
def within_feature_flag_row(index)
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 191e5192a61..a55027d3976 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -89,13 +89,16 @@ module GraphqlHelpers
# All mutations accept a single `:input` argument. Wrap arguments here.
args = { input: args } if resolver_class <= ::Mutations::BaseMutation && !args.key?(:input)
- resolve_field(field, obj,
- args: args,
- ctx: ctx,
- schema: schema,
- object_type: resolver_parent,
- extras: { parent: parent, lookahead: lookahead },
- arg_style: arg_style)
+ resolve_field(
+ field,
+ obj,
+ args: args,
+ ctx: ctx,
+ schema: schema,
+ object_type: resolver_parent,
+ extras: { parent: parent, lookahead: lookahead },
+ arg_style: arg_style
+ )
end
# Resolve the value of a field on an object.
@@ -513,20 +516,23 @@ module GraphqlHelpers
end
def post_graphql_mutation(mutation, current_user: nil, token: {})
- post_graphql(mutation.query,
- current_user: current_user,
- variables: mutation.variables,
- token: token)
+ post_graphql(
+ mutation.query,
+ current_user: current_user,
+ variables: mutation.variables,
+ token: token
+ )
end
def post_graphql_mutation_with_uploads(mutation, current_user: nil)
file_paths = file_paths_in_mutation(mutation)
params = mutation_to_apollo_uploads_param(mutation, files: file_paths)
- workhorse_post_with_file(api('/', current_user, version: 'graphql'),
- params: params,
- file_key: '1'
- )
+ workhorse_post_with_file(
+ api('/', current_user, version: 'graphql'),
+ params: params,
+ file_key: '1'
+ )
end
def file_paths_in_mutation(mutation)
diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb
index 65c0c32c44c..4efe2a98a45 100644
--- a/spec/support/helpers/stub_object_storage.rb
+++ b/spec/support/helpers/stub_object_storage.rb
@@ -2,9 +2,11 @@
module StubObjectStorage
def stub_dependency_proxy_object_storage(**params)
- stub_object_storage_uploader(config: ::Gitlab.config.dependency_proxy.object_store,
- uploader: ::DependencyProxy::FileUploader,
- **params)
+ stub_object_storage_uploader(
+ config: ::Gitlab.config.dependency_proxy.object_store,
+ uploader: ::DependencyProxy::FileUploader,
+ **params
+ )
end
def stub_object_storage_uploader(
@@ -36,8 +38,10 @@ module StubObjectStorage
return unless enabled
- stub_object_storage(connection_params: uploader.object_store_credentials,
- remote_directory: old_config.remote_directory)
+ stub_object_storage(
+ connection_params: uploader.object_store_credentials,
+ remote_directory: old_config.remote_directory
+ )
end
def stub_object_storage(connection_params:, remote_directory:)
@@ -55,75 +59,99 @@ module StubObjectStorage
end
def stub_artifacts_object_storage(uploader = JobArtifactUploader, **params)
- stub_object_storage_uploader(config: Gitlab.config.artifacts.object_store,
- uploader: uploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.artifacts.object_store,
+ uploader: uploader,
+ **params
+ )
end
def stub_external_diffs_object_storage(uploader = described_class, **params)
- stub_object_storage_uploader(config: Gitlab.config.external_diffs.object_store,
- uploader: uploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.external_diffs.object_store,
+ uploader: uploader,
+ **params
+ )
end
def stub_lfs_object_storage(**params)
- stub_object_storage_uploader(config: Gitlab.config.lfs.object_store,
- uploader: LfsObjectUploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.lfs.object_store,
+ uploader: LfsObjectUploader,
+ **params
+ )
end
def stub_package_file_object_storage(**params)
- stub_object_storage_uploader(config: Gitlab.config.packages.object_store,
- uploader: ::Packages::PackageFileUploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.packages.object_store,
+ uploader: ::Packages::PackageFileUploader,
+ **params
+ )
end
def stub_rpm_repository_file_object_storage(**params)
- stub_object_storage_uploader(config: Gitlab.config.packages.object_store,
- uploader: ::Packages::Rpm::RepositoryFileUploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.packages.object_store,
+ uploader: ::Packages::Rpm::RepositoryFileUploader,
+ **params
+ )
end
def stub_composer_cache_object_storage(**params)
- stub_object_storage_uploader(config: Gitlab.config.packages.object_store,
- uploader: ::Packages::Composer::CacheUploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.packages.object_store,
+ uploader: ::Packages::Composer::CacheUploader,
+ **params
+ )
end
def debian_component_file_object_storage(**params)
- stub_object_storage_uploader(config: Gitlab.config.packages.object_store,
- uploader: ::Packages::Debian::ComponentFileUploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.packages.object_store,
+ uploader: ::Packages::Debian::ComponentFileUploader,
+ **params
+ )
end
def debian_distribution_release_file_object_storage(**params)
- stub_object_storage_uploader(config: Gitlab.config.packages.object_store,
- uploader: ::Packages::Debian::DistributionReleaseFileUploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.packages.object_store,
+ uploader: ::Packages::Debian::DistributionReleaseFileUploader,
+ **params
+ )
end
def stub_uploads_object_storage(uploader = described_class, **params)
- stub_object_storage_uploader(config: Gitlab.config.uploads.object_store,
- uploader: uploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.uploads.object_store,
+ uploader: uploader,
+ **params
+ )
end
def stub_ci_secure_file_object_storage(**params)
- stub_object_storage_uploader(config: Gitlab.config.ci_secure_files.object_store,
- uploader: Ci::SecureFileUploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.ci_secure_files.object_store,
+ uploader: Ci::SecureFileUploader,
+ **params
+ )
end
def stub_terraform_state_object_storage(**params)
- stub_object_storage_uploader(config: Gitlab.config.terraform_state.object_store,
- uploader: Terraform::StateUploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.terraform_state.object_store,
+ uploader: Terraform::StateUploader,
+ **params
+ )
end
def stub_pages_object_storage(uploader = described_class, **params)
- stub_object_storage_uploader(config: Gitlab.config.pages.object_store,
- uploader: uploader,
- **params)
+ stub_object_storage_uploader(
+ config: Gitlab.config.pages.object_store,
+ uploader: uploader,
+ **params
+ )
end
def stub_object_storage_multipart_init(endpoint, upload_id = "upload_id")
diff --git a/spec/support/helpers/workhorse_helpers.rb b/spec/support/helpers/workhorse_helpers.rb
index 1b3741e59f3..f3b1d3af501 100644
--- a/spec/support/helpers/workhorse_helpers.rb
+++ b/spec/support/helpers/workhorse_helpers.rb
@@ -29,31 +29,48 @@ module WorkhorseHelpers
# workhorse_form_with_file will transform file_key inside params as if it was disk accelerated by workhorse
def workhorse_form_with_file(url, file_key:, params:, method: :post)
- workhorse_request_with_file(method, url,
- file_key: file_key,
- params: params,
- env: { 'CONTENT_TYPE' => 'multipart/form-data' },
- send_rewritten_field: true
+ workhorse_request_with_file(
+ method, url,
+ file_key: file_key,
+ params: params,
+ env: { 'CONTENT_TYPE' => 'multipart/form-data' },
+ send_rewritten_field: true
)
end
# workhorse_finalize will transform file_key inside params as if it was the finalize call of an inline object storage upload.
# note that based on the content of the params it can simulate a disc acceleration or an object storage upload
def workhorse_finalize(url, file_key:, params:, method: :post, headers: {}, send_rewritten_field: false)
- workhorse_finalize_with_multiple_files(url, method: method, file_keys: file_key, params: params, headers: headers, send_rewritten_field: send_rewritten_field)
+ workhorse_finalize_with_multiple_files(
+ url,
+ method: method,
+ file_keys: file_key,
+ params: params,
+ headers: headers,
+ send_rewritten_field: send_rewritten_field
+ )
end
def workhorse_finalize_with_multiple_files(url, file_keys:, params:, method: :post, headers: {}, send_rewritten_field: false)
- workhorse_request_with_multiple_files(method, url,
- file_keys: file_keys,
- params: params,
- extra_headers: headers,
- send_rewritten_field: send_rewritten_field
+ workhorse_request_with_multiple_files(
+ method, url,
+ file_keys: file_keys,
+ params: params,
+ extra_headers: headers,
+ send_rewritten_field: send_rewritten_field
)
end
def workhorse_request_with_file(method, url, file_key:, params:, send_rewritten_field:, env: {}, extra_headers: {})
- workhorse_request_with_multiple_files(method, url, file_keys: file_key, params: params, env: env, extra_headers: extra_headers, send_rewritten_field: send_rewritten_field)
+ workhorse_request_with_multiple_files(
+ method,
+ url,
+ file_keys: file_key,
+ params: params,
+ env: env,
+ extra_headers: extra_headers,
+ send_rewritten_field: send_rewritten_field
+ )
end
def workhorse_request_with_multiple_files(method, url, file_keys:, params:, send_rewritten_field:, env: {}, extra_headers: {})
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 2058eeef442..d6824bc2cd4 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -1868,7 +1868,6 @@
- './ee/spec/models/merge_requests/external_status_check_spec.rb'
- './ee/spec/models/merge_request_spec.rb'
- './ee/spec/models/merge_requests/status_check_response_spec.rb'
-- './ee/spec/models/merge_train_spec.rb'
- './ee/spec/models/milestone_release_spec.rb'
- './ee/spec/models/milestone_spec.rb'
- './ee/spec/models/namespace_limit_spec.rb'
diff --git a/spec/support/shared_examples/features/manage_applications_shared_examples.rb b/spec/support/shared_examples/features/manage_applications_shared_examples.rb
index 63ba5832771..b8fd58e7efa 100644
--- a/spec/support/shared_examples/features/manage_applications_shared_examples.rb
+++ b/spec/support/shared_examples/features/manage_applications_shared_examples.rb
@@ -19,7 +19,7 @@ RSpec.shared_examples 'manage applications' do
expect(page).to have_content _('This is the only time the secret is accessible. Copy the secret and store it securely')
expect(page).to have_link('Continue', href: index_path)
- expect(page).to have_css("button[title=\"Copy secret\"]", text: 'Copy')
+ expect(page).to have_button(_('Copy secret'))
click_on 'Edit'
diff --git a/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb
index d5ecab0cb6b..ec7a881f7ce 100644
--- a/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb
@@ -17,4 +17,10 @@ RSpec.shared_examples "schema objects assertions for" do |stmt_name|
expect(schema_object.statement).to eq(statement)
end
end
+
+ describe '#table_name' do
+ it 'returns schema object table_name' do
+ expect(schema_object.table_name).to eq(table_name)
+ end
+ end
end