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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop_todo/gitlab/namespaced_class.yml1
-rw-r--r--app/assets/javascripts/clusters_list/components/install_agent_modal.vue17
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/jobs_app.vue2
-rw-r--r--app/graphql/types/merge_request_sort_enum.rb2
-rw-r--r--app/models/ci/instance_variable.rb11
-rw-r--r--app/views/shared/hook_logs/_content.html.haml2
-rw-r--r--app/views/shared/issuable/_sort_dropdown.html.haml2
-rw-r--r--app/views/users/_overview.html.haml3
-rw-r--r--app/workers/all_queues.yml9
-rw-r--r--app/workers/pages_update_configuration_worker.rb17
-rw-r--r--config/feature_flags/experiment/redirect_trial_user_to_feature.yml8
-rw-r--r--config/sidekiq_queues.yml2
-rw-r--r--data/deprecations/templates/example.yml1
-rw-r--r--data/removals/14_0/14_0-ds-deprecations.yml1
-rw-r--r--data/removals/14_0/14_0-lc-deprecations.yml1
-rw-r--r--data/removals/14_0/change_default_branch_name_to_main.yml1
-rw-r--r--data/removals/14_0/create-code-review-draft-wip.yml1
-rw-r--r--data/removals/14_0/create-code-review-w-parameter-removal.yml1
-rw-r--r--data/removals/14_0/deprecate_ci_project_config_path_variable.yml1
-rw-r--r--data/removals/14_0/deprecation_bump_terraform_template_version.yml1
-rw-r--r--data/removals/14_0/deprecation_manage_access_14_0.yml2
-rw-r--r--data/removals/14_0/deprecation_update_cicd_templates_to_stop_using_hardcode_master.yml1
-rw-r--r--data/removals/14_0/deuley_servicetemplates_removal.yml1
-rw-r--r--data/removals/14_0/release_announce_deprecation_of_release_notes_api.yml1
-rw-r--r--data/removals/14_0/release_deprecation_auto-deploy-image.yml1
-rw-r--r--data/removals/14_0/release_domainsource_configuration_for_gitlab_pages_deprecation.yml1
-rw-r--r--data/removals/14_0/release_legacy_feature_flags_deprecation.yml1
-rw-r--r--data/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml1
-rw-r--r--data/removals/14_0/removal-geo-fdw-settings.yml1
-rw-r--r--data/removals/14_0/removal-graphql-fields.yml1
-rw-r--r--data/removals/14_0/removal-legacy-storage.yml1
-rw-r--r--data/removals/14_0/removal-protect-features.yml2
-rw-r--r--data/removals/14_0/removal-sidekiq_experimental_queue_selector.yml1
-rw-r--r--data/removals/14_0/removal-unicorn.yml1
-rw-r--r--data/removals/14_0/removal_ci_project_config_path.yml1
-rw-r--r--data/removals/14_0/removal_enablement_helm2.yml1
-rw-r--r--data/removals/14_0/removal_enablement_opensuse_15_1.yml1
-rw-r--r--data/removals/14_0/removal_enablement_pg11.yml1
-rw-r--r--data/removals/14_0/removal_enablement_ubuntu_16.yml1
-rw-r--r--data/removals/14_0/removal_repost_static_analysis_notices.yml4
-rw-r--r--data/removals/14_0/removal_runner_25555.yml1
-rw-r--r--data/removals/14_0/removal_runner_26036.yml1
-rw-r--r--data/removals/14_0/removal_runner_26419.yml1
-rw-r--r--data/removals/14_0/removal_runner_4845.yml1
-rw-r--r--data/removals/14_0/removal_runner_6413.yml1
-rw-r--r--data/removals/14_0/removals-14-testing-team.yml3
-rw-r--r--data/removals/14_0/removals_runner_26651.yml1
-rw-r--r--data/removals/14_0/removals_runner_26679.yml1
-rw-r--r--data/removals/14_0/removals_runner_26900.yml1
-rw-r--r--data/removals/14_0/removals_runner_27175.yml1
-rw-r--r--data/removals/14_0/removals_runner_27218.yml1
-rw-r--r--data/removals/14_0/removals_runner_27551.yml1
-rw-r--r--data/removals/14_0/removals_runner_27899.yml1
-rw-r--r--data/removals/14_0/remove-sql-elector.yml1
-rw-r--r--data/removals/14_0/remove_dast_env_variables.yml1
-rw-r--r--data/removals/14_0/remove_dast_legacy_domain_validation.yml1
-rw-r--r--data/removals/14_0/remove_dast_legacy_report_fields.yml1
-rw-r--r--data/removals/14_0/remove_dast_spider_host_reset.yml1
-rw-r--r--data/removals/14_0/remove_dast_template_stages.yml1
-rw-r--r--data/removals/14_0/remove_optimize_api.yml1
-rw-r--r--data/removals/14_0/remove_terraform_template.yml1
-rw-r--r--data/removals/14_0/verify-ci-removal-parametertrace.yml1
-rw-r--r--data/removals/14_0/verify-ci-removalpipelineservice.yml1
-rw-r--r--data/removals/14_1/removal-memory-prometheus-options-source.yml1
-rw-r--r--data/removals/14_1/removal-outdated-browser-support.yml1
-rw-r--r--data/removals/14_2/removal-verify-build-log.yml1
-rw-r--r--data/removals/14_3/removal-limit-tags-to-50.yml3
-rw-r--r--data/removals/14_3/removal-verify-pe-pipelinefindername.yml1
-rw-r--r--data/removals/14_3/removal_legacy_storage_setting.yml1
-rw-r--r--data/removals/templates/_removal_template.md.erb1
-rw-r--r--data/removals/templates/example.yml1
-rw-r--r--doc/api/graphql/reference/index.md2
-rw-r--r--doc/api/merge_requests.md6
-rw-r--r--doc/development/fe_guide/graphql.md70
-rw-r--r--doc/update/removals.md342
-rw-r--r--lib/api/helpers/merge_requests_helpers.rb20
-rw-r--r--lib/bulk_imports/common/extractors/graphql_extractor.rb7
-rw-r--r--lib/bulk_imports/common/graphql/get_members_query.rb (renamed from lib/bulk_imports/groups/graphql/get_members_query.rb)37
-rw-r--r--lib/bulk_imports/common/pipelines/members_pipeline.rb54
-rw-r--r--lib/bulk_imports/groups/graphql/get_group_query.rb10
-rw-r--r--lib/bulk_imports/groups/graphql/get_projects_query.rb10
-rw-r--r--lib/bulk_imports/groups/pipelines/members_pipeline.rb26
-rw-r--r--lib/bulk_imports/groups/stage.rb2
-rw-r--r--lib/bulk_imports/groups/transformers/member_attributes_transformer.rb43
-rw-r--r--lib/bulk_imports/projects/graphql/get_project_query.rb5
-rw-r--r--lib/bulk_imports/projects/graphql/get_repository_query.rb5
-rw-r--r--lib/bulk_imports/projects/graphql/get_snippet_repository_query.rb7
-rw-r--r--lib/bulk_imports/projects/graphql/queryable.rb8
-rw-r--r--lib/bulk_imports/projects/stage.rb4
-rw-r--r--lib/gitlab/ci/build/artifacts/expire_in_parser.rb20
-rw-r--r--lib/gitlab/ci/runner_instructions/templates/linux/install.sh2
-rw-r--r--lib/gitlab/process_memory_cache/helper.rb51
-rw-r--r--locale/gitlab.pot10
-rw-r--r--spec/finders/autocomplete/users_finder_spec.rb9
-rw-r--r--spec/finders/ci/daily_build_group_report_results_finder_spec.rb2
-rw-r--r--spec/finders/merge_request_target_project_finder_spec.rb4
-rw-r--r--spec/frontend/__helpers__/mock_apollo_helper.js6
-rw-r--r--spec/frontend/admin/users/components/users_table_spec.js12
-rw-r--r--spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js17
-rw-r--r--spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js9
-rw-r--r--spec/frontend/boards/board_list_spec.js5
-rw-r--r--spec/frontend/clusters/agents/components/activity_events_list_spec.js7
-rw-r--r--spec/frontend/clusters/agents/components/show_spec.js20
-rw-r--r--spec/frontend/clusters_list/components/agent_options_spec.js7
-rw-r--r--spec/frontend/clusters_list/components/install_agent_modal_spec.js42
-rw-r--r--spec/frontend/clusters_list/mocks/apollo.js5
-rw-r--r--spec/frontend/design_management/pages/index_spec.js18
-rw-r--r--spec/frontend/issues/list/components/issues_list_app_spec.js15
-rw-r--r--spec/frontend/issues/list/components/new_issue_dropdown_spec.js11
-rw-r--r--spec/frontend/jobs/bridge/app_spec.js8
-rw-r--r--spec/frontend/jobs/components/table/job_table_app_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js2
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js9
-rw-r--r--spec/frontend/packages_and_registries/dependency_proxy/app_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/list_spec.js15
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js23
-rw-r--r--spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js4
-rw-r--r--spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js6
-rw-r--r--spec/frontend/pipelines/components/jobs/jobs_app_spec.js6
-rw-r--r--spec/frontend/pipelines/graph/graph_component_wrapper_spec.js58
-rw-r--r--spec/frontend/pipelines/graph/linked_pipelines_column_spec.js14
-rw-r--r--spec/frontend/pipelines/notification/deprecated_type_keyword_notification_spec.js16
-rw-r--r--spec/frontend/projects/new/components/new_project_url_select_spec.js5
-rw-r--r--spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js5
-rw-r--r--spec/frontend/releases/components/app_index_apollo_client_spec.js4
-rw-r--r--spec/frontend/releases/components/app_show_spec.js13
-rw-r--r--spec/frontend/repository/components/blob_content_viewer_spec.js4
-rw-r--r--spec/frontend/runner/admin_runners/admin_runners_app_spec.js4
-rw-r--r--spec/frontend/runner/components/cells/runner_actions_cell_spec.js15
-rw-r--r--spec/frontend/runner/components/registration/registration_dropdown_spec.js4
-rw-r--r--spec/frontend/runner/group_runners/group_runners_app_spec.js4
-rw-r--r--spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js3
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js18
-rw-r--r--spec/graphql/resolvers/merge_requests_resolver_spec.rb60
-rw-r--r--spec/lib/bulk_imports/common/extractors/graphql_extractor_spec.rb15
-rw-r--r--spec/lib/bulk_imports/common/graphql/get_members_query_spec.rb56
-rw-r--r--spec/lib/bulk_imports/common/pipelines/members_pipeline_spec.rb161
-rw-r--r--spec/lib/bulk_imports/groups/graphql/get_group_query_spec.rb27
-rw-r--r--spec/lib/bulk_imports/groups/graphql/get_members_query_spec.rb35
-rw-r--r--spec/lib/bulk_imports/groups/graphql/get_projects_query_spec.rb40
-rw-r--r--spec/lib/bulk_imports/groups/pipelines/members_pipeline_spec.rb119
-rw-r--r--spec/lib/bulk_imports/groups/stage_spec.rb2
-rw-r--r--spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb24
-rw-r--r--spec/lib/bulk_imports/projects/graphql/get_project_query_spec.rb27
-rw-r--r--spec/lib/bulk_imports/projects/graphql/get_repository_query_spec.rb32
-rw-r--r--spec/lib/bulk_imports/projects/graphql/get_snippet_repository_query_spec.rb78
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb2
-rw-r--r--spec/lib/gitlab/process_memory_cache/helper_spec.rb52
-rw-r--r--spec/models/merge_request_spec.rb15
-rw-r--r--spec/requests/api/merge_requests_spec.rb20
-rw-r--r--spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb2
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb1
-rw-r--r--spec/workers/pages_update_configuration_worker_spec.rb12
155 files changed, 1343 insertions, 786 deletions
diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml
index f13325378d3..40afa0d0667 100644
--- a/.rubocop_todo/gitlab/namespaced_class.yml
+++ b/.rubocop_todo/gitlab/namespaced_class.yml
@@ -836,7 +836,6 @@ Gitlab/NamespacedClass:
- app/workers/pages_domain_verification_cron_worker.rb
- app/workers/pages_domain_verification_worker.rb
- app/workers/pages_transfer_worker.rb
- - app/workers/pages_update_configuration_worker.rb
- app/workers/pages_worker.rb
- app/workers/partition_creation_worker.rb
- app/workers/pipeline_hooks_worker.rb
diff --git a/app/assets/javascripts/clusters_list/components/install_agent_modal.vue b/app/assets/javascripts/clusters_list/components/install_agent_modal.vue
index 5eef76252bd..a5a989356dd 100644
--- a/app/assets/javascripts/clusters_list/components/install_agent_modal.vue
+++ b/app/assets/javascripts/clusters_list/components/install_agent_modal.vue
@@ -142,6 +142,9 @@ export default {
isAgentRegistrationModal() {
return this.modalType === MODAL_TYPE_REGISTER;
},
+ isKasEnabledInEmptyStateModal() {
+ return this.isEmptyStateModal && !this.kasDisabled;
+ },
},
methods: {
setAgentName(name) {
@@ -350,18 +353,18 @@ export default {
<img :alt="i18n.altText" :src="emptyStateImage" height="100" />
</div>
- <p>
- <gl-sprintf :message="i18n.modalBody">
+ <p v-if="kasDisabled">
+ <gl-sprintf :message="i18n.enableKasText">
<template #link="{ content }">
- <gl-link :href="$options.installAgentPath"> {{ content }}</gl-link>
+ <gl-link :href="$options.enableKasPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
- <p v-if="kasDisabled">
- <gl-sprintf :message="i18n.enableKasText">
+ <p v-else>
+ <gl-sprintf :message="i18n.modalBody">
<template #link="{ content }">
- <gl-link :href="$options.enableKasPath"> {{ content }}</gl-link>
+ <gl-link :href="$options.installAgentPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
@@ -401,7 +404,7 @@ export default {
</gl-button>
<gl-button
- v-if="isEmptyStateModal"
+ v-if="isKasEnabledInEmptyStateModal"
:href="repositoryPath"
variant="confirm"
category="secondary"
diff --git a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
index e11073aee33..6f35cdac641 100644
--- a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
+++ b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
@@ -39,7 +39,7 @@ export default {
this.jobsPageInfo = data.project?.pipeline?.jobs?.pageInfo || {};
},
error() {
- createFlash({ message: __('An error occured while fetching the pipelines jobs.') });
+ createFlash({ message: __('An error occurred while fetching the pipelines jobs.') });
},
},
},
diff --git a/app/graphql/types/merge_request_sort_enum.rb b/app/graphql/types/merge_request_sort_enum.rb
index d75eae6abc4..a74c5a01769 100644
--- a/app/graphql/types/merge_request_sort_enum.rb
+++ b/app/graphql/types/merge_request_sort_enum.rb
@@ -9,5 +9,7 @@ module Types
value 'MERGED_AT_DESC', 'Merge time by descending order.', value: :merged_at_desc
value 'CLOSED_AT_ASC', 'Closed time by ascending order.', value: :closed_at_asc
value 'CLOSED_AT_DESC', 'Closed time by descending order.', value: :closed_at_desc
+ value 'TITLE_ASC', 'Title by ascending order.', value: :title_asc
+ value 'TITLE_DESC', 'Title by descending order.', value: :title_desc
end
end
diff --git a/app/models/ci/instance_variable.rb b/app/models/ci/instance_variable.rb
index da9d4dea537..da077d31519 100644
--- a/app/models/ci/instance_variable.rb
+++ b/app/models/ci/instance_variable.rb
@@ -2,7 +2,6 @@
module Ci
class InstanceVariable < Ci::ApplicationRecord
- extend Gitlab::ProcessMemoryCache::Helper
include Ci::NewHasVariable
include Ci::Maskable
include Limitable
@@ -36,15 +35,23 @@ module Ci
cached_data[:unprotected]
end
+ def invalidate_memory_cache(key)
+ cache_backend.delete(key)
+ end
+
private
def cached_data
- fetch_memory_cache(:ci_instance_variable_data) do
+ cache_backend.fetch(:ci_instance_variable_data, expires_in: 30.seconds) do
all_records = unscoped.all.to_a
{ all: all_records, unprotected: all_records.reject(&:protected?) }
end
end
+
+ def cache_backend
+ Gitlab::ProcessMemoryCache.cache_backend
+ end
end
end
end
diff --git a/app/views/shared/hook_logs/_content.html.haml b/app/views/shared/hook_logs/_content.html.haml
index d358340814c..95590d6e515 100644
--- a/app/views/shared/hook_logs/_content.html.haml
+++ b/app/views/shared/hook_logs/_content.html.haml
@@ -15,7 +15,7 @@
.gl-alert-container
= sprite_icon('error', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
.gl-alert-content
- %h4.gl-alert-title= _('Internal error occured while delivering this webhook.')
+ %h4.gl-alert-title= _('Internal error occurred while delivering this webhook.')
.gl-alert-body
= _('Error: %{error}') % { error: hook_log.internal_error_message }
diff --git a/app/views/shared/issuable/_sort_dropdown.html.haml b/app/views/shared/issuable/_sort_dropdown.html.haml
index 5742f22ce05..f6d7ed6764d 100644
--- a/app/views/shared/issuable/_sort_dropdown.html.haml
+++ b/app/views/shared/issuable/_sort_dropdown.html.haml
@@ -21,6 +21,6 @@
= sortable_item(sort_title_merged_date, page_filter_path(sort: sort_value_merged_date), sort_title) if viewing_merge_requests
= sortable_item(sort_title_closed_date, page_filter_path(sort: sort_value_closed_date), sort_title) if viewing_merge_requests
= sortable_item(sort_title_relative_position, page_filter_path(sort: sort_value_relative_position), sort_title) if viewing_issues
- = sortable_item(sort_title_title, page_filter_path(sort: sort_value_title), sort_title) if viewing_issues
+ = sortable_item(sort_title_title, page_filter_path(sort: sort_value_title), sort_title)
= render_if_exists('shared/ee/issuable/sort_dropdown', viewing_issues: viewing_issues, sort_title: sort_title)
= issuable_sort_direction_button(sort_value)
diff --git a/app/views/users/_overview.html.haml b/app/views/users/_overview.html.haml
index 7e745efd069..c0a6ab44a26 100644
--- a/app/views/users/_overview.html.haml
+++ b/app/views/users/_overview.html.haml
@@ -8,7 +8,6 @@
= _('There was an error loading users activity calendar.')
%a.js-retry-load{ href: '#' }
= s_('UserProfile|Retry')
- .user-calendar-activities
- if @user.user_readme&.rich_viewer
.row.justify-content-center
.col-12.col-md-10.col-lg-8.gl-my-6
@@ -25,6 +24,8 @@
= link_to _('Edit'), edit_blob_path(@user.user_project, @user.user_project.default_branch, @user.user_readme.path)
= render 'projects/blob/viewer', viewer: @user.user_readme.rich_viewer, load_async: false
.row
+ .col-12.user-calendar-activities
+.row
%div{ class: activity_pane_class }
- if can?(current_user, :read_cross_project)
.activities-block
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 8f5bcfcd20f..e07a2a6ef1d 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -2623,15 +2623,6 @@
:weight: 1
:idempotent:
:tags: []
-- :name: pages_update_configuration
- :worker_name: PagesUpdateConfigurationWorker
- :feature_category: :pages
- :has_external_dependencies:
- :urgency: :low
- :resource_boundary: :unknown
- :weight: 1
- :idempotent: true
- :tags: []
- :name: phabricator_import_import_tasks
:worker_name: Gitlab::PhabricatorImport::ImportTasksWorker
:feature_category: :importers
diff --git a/app/workers/pages_update_configuration_worker.rb b/app/workers/pages_update_configuration_worker.rb
deleted file mode 100644
index 9c58b40e098..00000000000
--- a/app/workers/pages_update_configuration_worker.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-# TODO: remove this in 14.7 https://gitlab.com/gitlab-org/gitlab/-/issues/348582
-class PagesUpdateConfigurationWorker
- include ApplicationWorker
-
- data_consistency :always
-
- sidekiq_options retry: 1
-
- idempotent!
- feature_category :pages
-
- def perform(_project_id)
- # Do nothing
- end
-end
diff --git a/config/feature_flags/experiment/redirect_trial_user_to_feature.yml b/config/feature_flags/experiment/redirect_trial_user_to_feature.yml
deleted file mode 100644
index c653b886a04..00000000000
--- a/config/feature_flags/experiment/redirect_trial_user_to_feature.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: redirect_trial_user_to_feature
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65450
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/335824
-milestone: '14.1'
-type: experiment
-group: group::conversion
-default_enabled: false
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index bf84527bc5f..28ebdb9c021 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -311,8 +311,6 @@
- 1
- - pages_transfer
- 1
-- - pages_update_configuration
- - 1
- - personal_access_tokens
- 1
- - phabricator_import_import_tasks
diff --git a/data/deprecations/templates/example.yml b/data/deprecations/templates/example.yml
index 3097db557b8..a1fdd15612c 100644
--- a/data/deprecations/templates/example.yml
+++ b/data/deprecations/templates/example.yml
@@ -16,6 +16,7 @@
removal_milestone: "XX.YY" # The milestone when this feature is planned to be removed
removal_date: # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
breaking_change: false # If this deprecation is a breaking change, set this value to true
+ reporter: exampleuser # GitLab username of the person reporting the deprecation
body: | # Do not modify this line, instead modify the lines below.
<!-- START OF BODY COMMENT
diff --git a/data/removals/14_0/14_0-ds-deprecations.yml b/data/removals/14_0/14_0-ds-deprecations.yml
index c9eefe65c91..3d143863db5 100644
--- a/data/removals/14_0/14_0-ds-deprecations.yml
+++ b/data/removals/14_0/14_0-ds-deprecations.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: nicoleschwartz
+ breaking_change: true
body: |
As mentioned in [13.9](https://about.gitlab.com/releases/2021/02/22/gitlab-13-9-released/#deprecations-for-dependency-scanning) and [this blog post](https://about.gitlab.com/blog/2021/02/08/composition-analysis-14-deprecations-and-removals/) several removals for Dependency Scanning take effect.
diff --git a/data/removals/14_0/14_0-lc-deprecations.yml b/data/removals/14_0/14_0-lc-deprecations.yml
index 8f59fdbb557..5ca4836038d 100644
--- a/data/removals/14_0/14_0-lc-deprecations.yml
+++ b/data/removals/14_0/14_0-lc-deprecations.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: nicoleschwartz
+ breaking_change: true
body: |
In 13.0, we deprecated the License-Management CI template and renamed it License-Scanning. We have been providing backward compatibility by warning users of the old template to switch. Now in 14.0, we are completely removing the License-Management CI template. Read about it in [issue #216261](https://gitlab.com/gitlab-org/gitlab/-/issues/216261) or [this blog post](https://about.gitlab.com/blog/2021/02/08/composition-analysis-14-deprecations-and-removals/).
diff --git a/data/removals/14_0/change_default_branch_name_to_main.yml b/data/removals/14_0/change_default_branch_name_to_main.yml
index d2c0128daa5..1c47f99870b 100644
--- a/data/removals/14_0/change_default_branch_name_to_main.yml
+++ b/data/removals/14_0/change_default_branch_name_to_main.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: sarahwaldner
+ breaking_change: true
body: |
Every Git repository has an initial branch, which is named `master` by default. It's the first branch to be created automatically when you create a new repository. Future [Git versions](https://lore.kernel.org/git/pull.656.v4.git.1593009996.gitgitgadget@gmail.com/) will change the default branch name in Git from `master` to `main`. In coordination with the Git project and the broader community, [GitLab has changed the default branch name](https://gitlab.com/gitlab-org/gitlab/-/issues/223789) for new projects on both our SaaS (GitLab.com) and self-managed offerings starting with GitLab 14.0. This will not affect existing projects.
diff --git a/data/removals/14_0/create-code-review-draft-wip.yml b/data/removals/14_0/create-code-review-draft-wip.yml
index addd6c400a6..20eaaf3cd02 100644
--- a/data/removals/14_0/create-code-review-draft-wip.yml
+++ b/data/removals/14_0/create-code-review-draft-wip.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: phikai
+ breaking_change: true
body: |
The WIP (work in progress) status for merge requests signaled to reviewers that the merge request in question wasn't ready to merge. We've renamed the WIP feature to **Draft**, a more inclusive and self-explanatory term. **Draft** clearly communicates the merge request in question isn't ready for review, and makes no assumptions about the progress being made toward it. **Draft** also reduces the cognitive load for new users, non-English speakers, and anyone unfamiliar with the WIP acronym.
diff --git a/data/removals/14_0/create-code-review-w-parameter-removal.yml b/data/removals/14_0/create-code-review-w-parameter-removal.yml
index 471df85b540..051849a8335 100644
--- a/data/removals/14_0/create-code-review-w-parameter-removal.yml
+++ b/data/removals/14_0/create-code-review-w-parameter-removal.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: phikai
+ breaking_change: true
body: |
To create a consistent experience for users based on their preferences, support for toggling whitespace changes via URL parameter has been removed in GitLab 14.0.
diff --git a/data/removals/14_0/deprecate_ci_project_config_path_variable.yml b/data/removals/14_0/deprecate_ci_project_config_path_variable.yml
index c262a641bd1..32d7368a211 100644
--- a/data/removals/14_0/deprecate_ci_project_config_path_variable.yml
+++ b/data/removals/14_0/deprecate_ci_project_config_path_variable.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: stkerr
+ breaking_change: true
body: |
GitLab 14.0 removes the `CI_PROJECT_CONFIG_PATH` pre-defined project variable in favor of `CI_CONFIG_PATH`, which is functionally the same. If you are using `CI_PROJECT_CONFIG_PATH` in your pipeline configurations, update them to use `CI_CONFIG_PATH` instead.
diff --git a/data/removals/14_0/deprecation_bump_terraform_template_version.yml b/data/removals/14_0/deprecation_bump_terraform_template_version.yml
index a2e4bad9913..1ea463e0df8 100644
--- a/data/removals/14_0/deprecation_bump_terraform_template_version.yml
+++ b/data/removals/14_0/deprecation_bump_terraform_template_version.yml
@@ -3,6 +3,7 @@
removal_milestone: "14.0" # example
issue_url: ""
reporter: nagyv-gitlab
+ breaking_change: true
body: |
As we continuously [develop GitLab's Terraform integrations](https://gitlab.com/gitlab-org/gitlab/-/issues/325312), to minimize customer disruption, we maintain two GitLab CI/CD templates for Terraform:
diff --git a/data/removals/14_0/deprecation_manage_access_14_0.yml b/data/removals/14_0/deprecation_manage_access_14_0.yml
index bc82067821f..224a709085a 100644
--- a/data/removals/14_0/deprecation_manage_access_14_0.yml
+++ b/data/removals/14_0/deprecation_manage_access_14_0.yml
@@ -3,6 +3,7 @@
removal_milestone: "14.0"
reporter: ogolowisnki
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/257829
+ breaking_change: true
body: |
To improve performance, we are limiting the number of projects returned from the `GET /groups/:id/` API call to 100. A complete list of projects can still be retrieved with the `GET /groups/:id/projects` API call.
@@ -11,6 +12,7 @@
removal_milestone: "14.0"
reporter: ogolowinski
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/288516'
+ breaking_change: true
body: |
GitLab is deprecating the [OAuth 2 implicit grant flow](https://docs.gitlab.com/ee/api/oauth2.html#implicit-grant-flow) as it has been removed for [OAuth 2.1](https://oauth.net/2.1/).
diff --git a/data/removals/14_0/deprecation_update_cicd_templates_to_stop_using_hardcode_master.yml b/data/removals/14_0/deprecation_update_cicd_templates_to_stop_using_hardcode_master.yml
index 97adc4bb050..b54c135a035 100644
--- a/data/removals/14_0/deprecation_update_cicd_templates_to_stop_using_hardcode_master.yml
+++ b/data/removals/14_0/deprecation_update_cicd_templates_to_stop_using_hardcode_master.yml
@@ -2,5 +2,6 @@
reporter: dhershkovitch
removal_date: "2021-06-22"
removal_milestone: "14.0"
+ breaking_change: true
body: |
Our CI/CD templates have been updated to no longer use hard-coded references to a `master` branch. In 14.0, they all use a variable that points to your project's configured default branch instead. If your CI/CD pipeline relies on our built-in templates, verify that this change works with your current configuration. For example, if you have a `master` branch and a different default branch, the updates to the templates may cause changes to your pipeline behavior. For more information, [read the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/324131).
diff --git a/data/removals/14_0/deuley_servicetemplates_removal.yml b/data/removals/14_0/deuley_servicetemplates_removal.yml
index 94816bbee4a..3728b6b9e66 100644
--- a/data/removals/14_0/deuley_servicetemplates_removal.yml
+++ b/data/removals/14_0/deuley_servicetemplates_removal.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deuley
+ breaking_change: true
body: |
Service Templates are [removed in GitLab 14.0](https://gitlab.com/groups/gitlab-org/-/epics/5672). They were used to apply identical settings to a large number of projects, but they only did so at the time of project creation.
diff --git a/data/removals/14_0/release_announce_deprecation_of_release_notes_api.yml b/data/removals/14_0/release_announce_deprecation_of_release_notes_api.yml
index 066022dae87..6a04a49afa1 100644
--- a/data/removals/14_0/release_announce_deprecation_of_release_notes_api.yml
+++ b/data/removals/14_0/release_announce_deprecation_of_release_notes_api.yml
@@ -3,5 +3,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/300887'
+ breaking_change: true
body: |
GitLab 14.0 removes support for the release description in the Tags API. You can no longer add a release description when [creating a new tag](https://docs.gitlab.com/ee/api/tags.html#create-a-new-tag). You also can no longer [create](https://docs.gitlab.com/ee/api/tags.html#create-a-new-release) or [update](https://docs.gitlab.com/ee/api/tags.html#update-a-release) a release through the Tags API. Please migrate to use the [Releases API](https://docs.gitlab.com/ee/api/releases/#create-a-release) instead.
diff --git a/data/removals/14_0/release_deprecation_auto-deploy-image.yml b/data/removals/14_0/release_deprecation_auto-deploy-image.yml
index 7a8f0e598c4..65a402f013d 100644
--- a/data/removals/14_0/release_deprecation_auto-deploy-image.yml
+++ b/data/removals/14_0/release_deprecation_auto-deploy-image.yml
@@ -3,6 +3,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/300862'
+ breaking_change: true
body: |
In GitLab 14.0, we will update the [Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/stages.html#auto-deploy) CI template to the latest version. This includes new features, bug fixes, and performance improvements with a dependency on the v2 [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image). Auto Deploy CI tempalte v1 will is deprecated going forward.
diff --git a/data/removals/14_0/release_domainsource_configuration_for_gitlab_pages_deprecation.yml b/data/removals/14_0/release_domainsource_configuration_for_gitlab_pages_deprecation.yml
index 694c168fb93..766373e6b81 100644
--- a/data/removals/14_0/release_domainsource_configuration_for_gitlab_pages_deprecation.yml
+++ b/data/removals/14_0/release_domainsource_configuration_for_gitlab_pages_deprecation.yml
@@ -3,5 +3,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5993'
+ breaking_change: true
body: |
GitLab Pages [API-based configuration](https://docs.gitlab.com/ee/administration/pages/#gitlab-api-based-configuration) has been available since GitLab 13.0. It replaces the unsupported `disk` source configuration removed in GitLab 14.0, which can no longer be chosen. You should stop using `disk` source configuration, and move to `gitlab` for an API-based configuration. To migrate away from the 'disk' source configuration, set `gitlab_pages['domain_config_source'] = "gitlab"` in your `/etc/gitlab/gitlab.rb` file. We recommend you migrate before updating to GitLab 14.0, to identify and troubleshoot any potential problems before upgrading.
diff --git a/data/removals/14_0/release_legacy_feature_flags_deprecation.yml b/data/removals/14_0/release_legacy_feature_flags_deprecation.yml
index aa62be7eb1d..08813b98435 100644
--- a/data/removals/14_0/release_legacy_feature_flags_deprecation.yml
+++ b/data/removals/14_0/release_legacy_feature_flags_deprecation.yml
@@ -3,5 +3,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/254324'
+ breaking_change: true
body: |
Legacy feature flags became read-only in GitLab 13.4. GitLab 14.0 removes support for legacy feature flags, so you must migrate them to the [new version](https://docs.gitlab.com/ee/operations/feature_flags.html). You can do this by first taking a note (screenshot) of the legacy flag, then deleting the flag through the API or UI (you don't need to alter the code), and finally create a new Feature Flag with the same name as the legacy flag you deleted. Also, make sure the strategies and environments match the deleted flag. We created a [video tutorial](https://www.youtube.com/watch?v=CAJY2IGep7Y) to help with this migration.
diff --git a/data/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml b/data/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml
index 48e79230297..acd8bb34f77 100644
--- a/data/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml
+++ b/data/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml
@@ -3,5 +3,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/325931'
+ breaking_change: true
body: |
The [deployment frequency project-level API](https://docs.gitlab.com/ee/api/dora4_project_analytics.html#list-project-deployment-frequencies) endpoint has been deprecated in favor of the [DORA 4 API](https://docs.gitlab.com/ee/api/dora/metrics.html), which consolidates all the metrics under one API with the specific metric as a required field. As a result, the timestamp field, which doesn't allow adding future extensions and causes performance issues, will be removed. With the old API, an example response would be `{ "2021-03-01": 3, "date": "2021-03-01", "value": 3 }`. The first key/value (`"2021-03-01": 3`) will be removed and replaced by the last two (`"date": "2021-03-01", "value": 3`).
diff --git a/data/removals/14_0/removal-geo-fdw-settings.yml b/data/removals/14_0/removal-geo-fdw-settings.yml
index c2066269cb8..4d950ae59bd 100644
--- a/data/removals/14_0/removal-geo-fdw-settings.yml
+++ b/data/removals/14_0/removal-geo-fdw-settings.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: fzimmer
+ breaking_change: true
body: |
As [announced in GitLab 13.3](https://about.gitlab.com/releases/2020/08/22/gitlab-13-3-released/#geo-foreign-data-wrapper-settings-deprecated), the following configuration settings in `/etc/gitlab/gitlab.rb` have been removed in 14.0:
diff --git a/data/removals/14_0/removal-graphql-fields.yml b/data/removals/14_0/removal-graphql-fields.yml
index 24d2bb4a4eb..67d911b24bf 100644
--- a/data/removals/14_0/removal-graphql-fields.yml
+++ b/data/removals/14_0/removal-graphql-fields.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: gweaver
+ breaking_change: true
body: |
In accordance with our [GraphQL deprecation and removal process](https://docs.gitlab.com/ee/api/graphql/#deprecation-process), the following fields that were deprecated prior to 13.7 are [fully removed in 14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/267966):
diff --git a/data/removals/14_0/removal-legacy-storage.yml b/data/removals/14_0/removal-legacy-storage.yml
index 677ec7b8512..5fabf8e268e 100644
--- a/data/removals/14_0/removal-legacy-storage.yml
+++ b/data/removals/14_0/removal-legacy-storage.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: fzimmer
+ breaking_change: true
body: |
As [announced in GitLab 13.0](https://about.gitlab.com/releases/2020/05/22/gitlab-13-0-released/#planned-removal-of-legacy-storage-in-14.0), [legacy storage](https://docs.gitlab.com/ee/administration/repository_storage_types.html#legacy-storage) has been removed in GitLab 14.0.
diff --git a/data/removals/14_0/removal-protect-features.yml b/data/removals/14_0/removal-protect-features.yml
index 8e50925f6db..e8e71f7bbcd 100644
--- a/data/removals/14_0/removal-protect-features.yml
+++ b/data/removals/14_0/removal-protect-features.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: sam.white
+ breaking_change: true
body: |
Clair, the default container scanning engine, was deprecated in GitLab 13.9 and is removed from GitLab 14.0 and replaced by Trivy. We advise customers who are customizing variables for their container scanning job to [follow these instructions](https://docs.gitlab.com/ee/user/application_security/container_scanning/#change-scanners) to ensure that their container scanning jobs continue to work.
@@ -9,5 +10,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: sam.white
+ breaking_change: true
body: |
The Web Application Firewall (WAF) was deprecated in GitLab 13.6 and is removed from GitLab 14.0. The WAF had limitations inherent in the architectural design that made it difficult to meet the requirements traditionally expected of a WAF. By removing the WAF, GitLab is able to focus on improving other areas in the product where more value can be provided to users. Users who currently rely on the WAF can continue to use the free and open source [ModSecurity](https://github.com/SpiderLabs/ModSecurity) project, which is independent from GitLab. Additional details are available in the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/271276).
diff --git a/data/removals/14_0/removal-sidekiq_experimental_queue_selector.yml b/data/removals/14_0/removal-sidekiq_experimental_queue_selector.yml
index 442c0e97cde..000646c050a 100644
--- a/data/removals/14_0/removal-sidekiq_experimental_queue_selector.yml
+++ b/data/removals/14_0/removal-sidekiq_experimental_queue_selector.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: smcgivern
+ breaking_change: true
body: |
GitLab supports a [queue selector](https://docs.gitlab.com/ee/administration/operations/extra_sidekiq_processes.html#queue-selector) to run only a subset of background jobs for a given process. When it was introduced, this option had an 'experimental' prefix (`experimental_queue_selector` in Omnibus, `experimentalQueueSelector` in Helm charts).
diff --git a/data/removals/14_0/removal-unicorn.yml b/data/removals/14_0/removal-unicorn.yml
index af0bed0f3ec..8b8574b65e8 100644
--- a/data/removals/14_0/removal-unicorn.yml
+++ b/data/removals/14_0/removal-unicorn.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: fzimmer
+ breaking_change: true
body: |
[Support for Unicorn](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6078) has been removed in GitLab 14.0 in favor of Puma. [Puma has a multi-threaded architecture](https://docs.gitlab.com/ee/administration/operations/puma.html) which uses less memory than a multi-process application server like Unicorn. On GitLab.com, we saw a 40% reduction in memory consumption by using Puma.
diff --git a/data/removals/14_0/removal_ci_project_config_path.yml b/data/removals/14_0/removal_ci_project_config_path.yml
index 8e90c83c7c4..ad40aa74bd6 100644
--- a/data/removals/14_0/removal_ci_project_config_path.yml
+++ b/data/removals/14_0/removal_ci_project_config_path.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: stkerr
+ breaking_change: true
body: |
The `CI_PROJECT_CONFIG_PATH` [predefined project variable](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)
has been removed in favor of `CI_CONFIG_PATH`, which is functionally the same.
diff --git a/data/removals/14_0/removal_enablement_helm2.yml b/data/removals/14_0/removal_enablement_helm2.yml
index 323b22fd3b4..09136bead3e 100644
--- a/data/removals/14_0/removal_enablement_helm2.yml
+++ b/data/removals/14_0/removal_enablement_helm2.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: joshlambert
+ breaking_change: true
body: |
Helm v2 was [officially deprecated](https://helm.sh/blog/helm-v2-deprecation-timeline/) in November of 2020, with the `stable` repository being [de-listed from the Helm Hub](https://about.gitlab.com/blog/2020/11/09/ensure-auto-devops-work-after-helm-stable-repo/) shortly thereafter. With the release of GitLab 14.0, which will include the 5.0 release of the [GitLab Helm chart](https://docs.gitlab.com/charts/), Helm v2 will no longer be supported.
diff --git a/data/removals/14_0/removal_enablement_opensuse_15_1.yml b/data/removals/14_0/removal_enablement_opensuse_15_1.yml
index cff442d7b92..2e0333c3b88 100644
--- a/data/removals/14_0/removal_enablement_opensuse_15_1.yml
+++ b/data/removals/14_0/removal_enablement_opensuse_15_1.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: dorrino
+ breaking_change: true
body: |
Support for [OpenSUSE Leap 15.1 is being deprecated](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5135). Support for 15.1 will be dropped in 14.0. We are now providing support for openSUSE Leap 15.2 packages.
diff --git a/data/removals/14_0/removal_enablement_pg11.yml b/data/removals/14_0/removal_enablement_pg11.yml
index c7b9f8b528b..7c5738b7ff9 100644
--- a/data/removals/14_0/removal_enablement_pg11.yml
+++ b/data/removals/14_0/removal_enablement_pg11.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: joshlambert
+ breaking_change: true
body: |
PostgreSQL 12 will be the minimum required version in GitLab 14.0. It offers [significant improvements](https://www.postgresql.org/about/news/postgresql-12-released-1976/) to indexing, partitioning, and general performance benefits.
diff --git a/data/removals/14_0/removal_enablement_ubuntu_16.yml b/data/removals/14_0/removal_enablement_ubuntu_16.yml
index 65457db8c68..593bac720c1 100644
--- a/data/removals/14_0/removal_enablement_ubuntu_16.yml
+++ b/data/removals/14_0/removal_enablement_ubuntu_16.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: joshlambert
+ breaking_change: true
body: |
Ubuntu 16.04 [reached end-of-life in April 2021](https://ubuntu.com/about/release-cycle), and no longer receives maintenance updates. We strongly recommend users to upgrade to a newer release, such as 20.04.
diff --git a/data/removals/14_0/removal_repost_static_analysis_notices.yml b/data/removals/14_0/removal_repost_static_analysis_notices.yml
index 1105f21e3fd..87611a1ae72 100644
--- a/data/removals/14_0/removal_repost_static_analysis_notices.yml
+++ b/data/removals/14_0/removal_repost_static_analysis_notices.yml
@@ -3,6 +3,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/229974'
+ breaking_change: true
body: |
Until GitLab 13.9, if you wanted to avoid running one particular GitLab SAST analyzer, you needed to remove it from the [long string of analyzers in the `SAST.gitlab-ci.yml` file](https://gitlab.com/gitlab-org/gitlab/-/blob/390afc431e7ce1ac253b35beb39f19e49c746bff/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml#L12) and use that to set the [`SAST_DEFAULT_ANALYZERS`](https://docs.gitlab.com/ee/user/application_security/sast/#docker-images) variable in your project's CI file. If you did this, it would exclude you from future new analyzers because this string hard codes the list of analyzers to execute. We avoid this problem by inverting this variable's logic to exclude, rather than choose default analyzers.
Beginning with 13.9, [we migrated](https://gitlab.com/gitlab-org/gitlab/-/blob/14fed7a33bfdbd4663d8928e46002a5ef3e3282c/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml#L13) to `SAST_EXCLUDED_ANALYZERS` in our `SAST.gitlab-ci.yml` file. We encourage anyone who uses a [customized SAST configuration](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) in their project CI file to migrate to this new variable. If you have not overridden `SAST_DEFAULT_ANALYZERS`, no action is needed. The CI/CD variable `SAST_DEFAULT_ANALYZERS` has been removed in GitLab 14.0, which released on June 22, 2021.
@@ -12,6 +13,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/297269'
+ breaking_change: true
body: |
To ensure Secret Detection was scanning both default branches and feature branches, we introduced two separate secret detection CI jobs (`secret_detection_default_branch` and `secret_detection`) in our managed [`Secret-Detection.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml) template. These two CI jobs created confusion and complexity in the CI rules logic. This deprecation moves the `rule` logic into the `script` section, which then determines how the `secret_detection` job is run (historic, on a branch, commits, etc).
If you override or maintain custom versions of `SAST.gitlab-ci.yml` or `Secret-Detection.gitlab-ci.yml`, you must update your CI templates. We strongly encourage [inheriting and overriding our managed CI templates](https://docs.gitlab.com/ee/user/application_security/secret_detection/#custom-settings-example) to future-proof your CI templates. GitLab 14.0 no longer supports the old `secret_detection_default_branch` job.
@@ -22,6 +24,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/301215'
+ breaking_change: true
body: |
With the release of [SAST Custom Rulesets](https://docs.gitlab.com/ee/user/application_security/sast/#customize-rulesets) in GitLab 13.5 we allow greater flexibility in configuration options for our Go analyzer (GoSec). As a result we no longer plan to support our less flexible [`SAST_GOSEC_CONFIG`](https://docs.gitlab.com/ee/user/application_security/sast/#analyzer-settings) analyzer setting. This variable was deprecated in GitLab 13.10.
GitLab 14.0 removes the old `SAST_GOSEC_CONFIG variable`. If you use or override `SAST_GOSEC_CONFIG` in your CI file, update your SAST CI configuration or pin to an older version of the GoSec analyzer. We strongly encourage [inheriting and overriding our managed CI templates](https://docs.gitlab.com/ee/user/application_security/sast/#overriding-sast-jobs) to future-proof your CI templates.
@@ -31,6 +34,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/301216'
+ breaking_change: true
body: |
With the maturity of GitLab Secure scanning tools, we've needed to add more granularity to our release process. Previously, GitLab shared a major version number for [all analyzers and tools](https://docs.gitlab.com/ee/user/application_security/sast/#supported-languages-and-frameworks). This requires all tools to share a major version, and prevents the use of [semantic version numbering](https://semver.org/). In GitLab 14.0, SAST removes the `SAST_ANALYZER_IMAGE_TAG` global variable in our [managed `SAST.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml) CI template, in favor of the analyzer job variable setting the `major.minor` tag in the SAST vendored template.
diff --git a/data/removals/14_0/removal_runner_25555.yml b/data/removals/14_0/removal_runner_25555.yml
index f317eaab846..0007aa59b03 100644
--- a/data/removals/14_0/removal_runner_25555.yml
+++ b/data/removals/14_0/removal_runner_25555.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In GitLab Runner 13.0, [issue #5069](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/5069), we introduced new timing options for the GitLab Docker Machine executor. In GitLab Runner 14.0, we have removed the old configuration option, [off peak time mode](https://docs.gitlab.com/runner/configuration/autoscale.html#off-peak-time-mode-configuration-deprecated).
diff --git a/data/removals/14_0/removal_runner_26036.yml b/data/removals/14_0/removal_runner_26036.yml
index 564143fda82..13260812492 100644
--- a/data/removals/14_0/removal_runner_26036.yml
+++ b/data/removals/14_0/removal_runner_26036.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
Ubuntu 19.10 (Eoan Ermine) reached end of life on Friday, July 17, 2020. In GitLab Runner 14.0, Ubuntu 19.10 (Eoan Ermine) is no longer available from our package distribution. Refer to [issue #26036](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26036) for details.
diff --git a/data/removals/14_0/removal_runner_26419.yml b/data/removals/14_0/removal_runner_26419.yml
index 8b0f3846c7a..85d57de763e 100644
--- a/data/removals/14_0/removal_runner_26419.yml
+++ b/data/removals/14_0/removal_runner_26419.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In GitLab Runner 13.2, PowerShell Core support was added to the Shell executor. In 14.0, PowerShell Core, `pwsh` is now the default shell for newly-registered Windows runners. Windows `CMD` will still be available as a shell option for Windows runners. Refer to [issue #26419](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26419) for details.
diff --git a/data/removals/14_0/removal_runner_4845.yml b/data/removals/14_0/removal_runner_4845.yml
index 92e4e0172f2..db25c0741cb 100644
--- a/data/removals/14_0/removal_runner_4845.yml
+++ b/data/removals/14_0/removal_runner_4845.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In GitLab Runner 14.0, the installation process will ignore the `skel` directory by default when creating the user home directory. Refer to [issue #4845](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4845) for details.
diff --git a/data/removals/14_0/removal_runner_6413.yml b/data/removals/14_0/removal_runner_6413.yml
index f08b1091cca..c990b262c87 100644
--- a/data/removals/14_0/removal_runner_6413.yml
+++ b/data/removals/14_0/removal_runner_6413.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In [GitLab Runner 13.1](https://docs.gitlab.com/runner/executors/shell.html#gitlab-131-and-later), [issue #3376](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/3376), we introduced `sigterm` and then `sigkill` to a process in the Shell executor. We also introduced a new feature flag, `FF_SHELL_EXECUTOR_USE_LEGACY_PROCESS_KILL`, so you can use the previous process termination sequence. In GitLab Runner 14.0, [issue #6413](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6413), the feature flag has been removed.
diff --git a/data/removals/14_0/removals-14-testing-team.yml b/data/removals/14_0/removals-14-testing-team.yml
index d76de564cdd..2012f8738b8 100644
--- a/data/removals/14_0/removals-14-testing-team.yml
+++ b/data/removals/14_0/removals-14-testing-team.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: jheimbuck_gl
+ breaking_change: true
body: |
Browser Performance Testing has run in a job named `performance` by default. With the introduction of [Load Performance Testing](https://docs.gitlab.com/ee/user/project/merge_requests/load_performance_testing.html) in GitLab 13.2, this naming could be confusing. To make it clear which job is running [Browser Performance Testing](https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html), the default job name is changed from `performance` to `browser_performance` in the template in GitLab 14.0.
@@ -10,6 +11,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: jheimbuck_gl
+ breaking_change: true
body: |
By default, the Code Quality feature has not provided support for Ruby 2.6+ if you're using the Code Quality template. To better support the latest versions of Ruby, the default RuboCop version is updated to add support for Ruby 2.4 through 3.0. As a result, support for Ruby 2.1, 2.2, and 2.3 is removed. You can re-enable support for older versions by [customizing your configuration](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html#rubocop-errors).
@@ -18,6 +20,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: jheimbuck_gl
+ breaking_change: true
body: |
By default, the `Ruby.gitlab-ci.yml` file has included Ruby 2.5.
diff --git a/data/removals/14_0/removals_runner_26651.yml b/data/removals/14_0/removals_runner_26651.yml
index a22f8dfc9ac..19d3ac3bde6 100644
--- a/data/removals/14_0/removals_runner_26651.yml
+++ b/data/removals/14_0/removals_runner_26651.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In GitLab Runner 13.3, a symlink was added from `/user/lib/gitlab-runner/gitlab-runner` to `/usr/bin/gitlab-runner`. In 14.0, the symlink has been removed and the runner is now installed in `/usr/bin/gitlab-runner`. Refer to [issue #26651](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26651) for details.
diff --git a/data/removals/14_0/removals_runner_26679.yml b/data/removals/14_0/removals_runner_26679.yml
index 816bd8f37d5..9c8ea23e750 100644
--- a/data/removals/14_0/removals_runner_26679.yml
+++ b/data/removals/14_0/removals_runner_26679.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In 14.0, we have deactivated the `FF_RESET_HELPER_IMAGE_ENTRYPOINT` feature flag. Refer to issue [#26679](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26679) for details.
diff --git a/data/removals/14_0/removals_runner_26900.yml b/data/removals/14_0/removals_runner_26900.yml
index bdba368eee8..4dc984be64a 100644
--- a/data/removals/14_0/removals_runner_26900.yml
+++ b/data/removals/14_0/removals_runner_26900.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In GitLab Runner 13.5, we introduced `failed` and `success` states for a job. To support Prometheus rules, we chose to convert `success/failure` to `finished` for the metric. In 14.0, the conversion has now been removed. Refer to [issue #26900](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26900) for details.
diff --git a/data/removals/14_0/removals_runner_27175.yml b/data/removals/14_0/removals_runner_27175.yml
index 33629084073..758ea7fdd57 100644
--- a/data/removals/14_0/removals_runner_27175.yml
+++ b/data/removals/14_0/removals_runner_27175.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
GitLab Runner 14.0 removes the `FF_USE_GO_CLOUD_WITH_CACHE_ARCHIVER` feature flag. Refer to [issue #27175](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27175) for details.
diff --git a/data/removals/14_0/removals_runner_27218.yml b/data/removals/14_0/removals_runner_27218.yml
index fb1e27c3f91..8fb7e800b0b 100644
--- a/data/removals/14_0/removals_runner_27218.yml
+++ b/data/removals/14_0/removals_runner_27218.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In 14.0, we are now pulling the GitLab Runner [helper image](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#helper-image) from the GitLab Container Registry instead of Docker Hub. Refer to [issue #27218](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27218) for details.
diff --git a/data/removals/14_0/removals_runner_27551.yml b/data/removals/14_0/removals_runner_27551.yml
index 6f4ee52749c..a99b7eb0c73 100644
--- a/data/removals/14_0/removals_runner_27551.yml
+++ b/data/removals/14_0/removals_runner_27551.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In 14.0, we have removed Windows Server 1903. Microsoft ended support for this version on 2020-08-12. Refer to [issue #27551](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27551) for details.
diff --git a/data/removals/14_0/removals_runner_27899.yml b/data/removals/14_0/removals_runner_27899.yml
index 226520abda4..d4b01298e6b 100644
--- a/data/removals/14_0/removals_runner_27899.yml
+++ b/data/removals/14_0/removals_runner_27899.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: deastman
+ breaking_change: true
body: |
In 14.0, we have removed Windows Server 1909. Microsoft ended support for this version on 2021-05-11. Refer to [issue #27899](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27899) for details.
diff --git a/data/removals/14_0/remove-sql-elector.yml b/data/removals/14_0/remove-sql-elector.yml
index d35fac0786c..c32a2d65728 100644
--- a/data/removals/14_0/remove-sql-elector.yml
+++ b/data/removals/14_0/remove-sql-elector.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: mjwood
+ breaking_change: true
body: |
Now that Praefect supports a [primary election strategy](https://docs.gitlab.com/ee/administration/gitaly/praefect.html#repository-specific-primary-nodes) for each repository, we have removed the `sql` election strategy.
The `per_repository` election strategy is the new default, which is automatically used if no election strategy was specified.
diff --git a/data/removals/14_0/remove_dast_env_variables.yml b/data/removals/14_0/remove_dast_env_variables.yml
index f2bbe748af5..3a40c6518e0 100644
--- a/data/removals/14_0/remove_dast_env_variables.yml
+++ b/data/removals/14_0/remove_dast_env_variables.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: derekferguson
+ breaking_change: true
body: |
GitLab 13.8 renamed multiple environment variables to support their broader usage in different workflows. In GitLab 14.0, the old variables have been permanently removed and will no longer work. Any configurations using these variables must be updated to the new variable names. Any scans using these variables in GitLab 14.0 and later will fail to be configured correctly. These variables are:
diff --git a/data/removals/14_0/remove_dast_legacy_domain_validation.yml b/data/removals/14_0/remove_dast_legacy_domain_validation.yml
index 61fb9002880..665433a75f6 100644
--- a/data/removals/14_0/remove_dast_legacy_domain_validation.yml
+++ b/data/removals/14_0/remove_dast_legacy_domain_validation.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: derekferguson
+ breaking_change: true
body: |
The legacy method of DAST Domain Validation for CI/CD scans was deprecated in GitLab 13.8, and is removed in GitLab 14.0. This method of domain validation only disallows scans if the `DAST_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` environment variable is set to `true` in the `gitlab-ci.yml` file, and a `Gitlab-DAST-Permission` header on the site is not set to `allow`. This two-step method required users to opt in to using the variable before they could opt out from using the header.
diff --git a/data/removals/14_0/remove_dast_legacy_report_fields.yml b/data/removals/14_0/remove_dast_legacy_report_fields.yml
index ec98b173a24..e5353abf7c5 100644
--- a/data/removals/14_0/remove_dast_legacy_report_fields.yml
+++ b/data/removals/14_0/remove_dast_legacy_report_fields.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: derekferguson
+ breaking_change: true
body: |
As a part of the migration to a common report format for all of the Secure scanners in GitLab, DAST is making changes to the DAST JSON report. Certain legacy fields were deprecated in 13.8 and have been completely removed in 14.0. These fields are `@generated`, `@version`, `site`, and `spider`. This should not affect any normal DAST operation, but does affect users who consume the JSON report in an automated way and use these fields. Anyone affected by these changes, and needs these fields for business reasons, is encouraged to open a new GitLab issue and explain the need.
diff --git a/data/removals/14_0/remove_dast_spider_host_reset.yml b/data/removals/14_0/remove_dast_spider_host_reset.yml
index de334618b88..53122f6071f 100644
--- a/data/removals/14_0/remove_dast_spider_host_reset.yml
+++ b/data/removals/14_0/remove_dast_spider_host_reset.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: derekferguson
+ breaking_change: true
body: |
In GitLab 14.0, DAST has removed the current method of resetting the scan to the hostname when starting to spider. Prior to GitLab 14.0, the spider would not begin at the specified target path for the URL but would instead reset the URL to begin crawling at the host root. GitLab 14.0 changes the default for the new variable `DAST_SPIDER_START_AT_HOST` to `false` to better support users' intention of beginning spidering and scanning at the specified target URL, rather than the host root URL. This change has an added benefit: scans can take less time, if the specified path does not contain links to the entire site. This enables easier scanning of smaller sections of an application, rather than crawling the entire app during every scan.
diff --git a/data/removals/14_0/remove_dast_template_stages.yml b/data/removals/14_0/remove_dast_template_stages.yml
index 0f72091735d..bdbbac6f029 100644
--- a/data/removals/14_0/remove_dast_template_stages.yml
+++ b/data/removals/14_0/remove_dast_template_stages.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: derekferguson
+ breaking_change: true
body: |
In GitLab 14.0, we've removed the stages defined in the current `DAST.gitlab-ci.yml` template to avoid the situation where the template overrides manual changes made by DAST users. We're making this change in response to customer issues where the stages in the template cause problems when used with customized DAST configurations. Because of this removal, `gitlab-ci.yml` configurations that do not specify a `dast` stage must be updated to include this stage.
diff --git a/data/removals/14_0/remove_optimize_api.yml b/data/removals/14_0/remove_optimize_api.yml
index 5df120858c6..1ab8e748f0c 100644
--- a/data/removals/14_0/remove_optimize_api.yml
+++ b/data/removals/14_0/remove_optimize_api.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: ljlane
+ breaking_change: true
body: |
The first release of the DevOps Adoption report had a concept of **Segments**. Segments were [quickly removed from the report](https://gitlab.com/groups/gitlab-org/-/epics/5251) because they introduced an additional layer of complexity on top of **Groups** and **Projects**. Subsequent iterations of the DevOps Adoption report focus on comparing adoption across groups rather than segments. GitLab 14.0 removes all references to **Segments** [from the GraphQL API](https://gitlab.com/gitlab-org/gitlab/-/issues/324414) and replaces them with **Enabled groups**.
diff --git a/data/removals/14_0/remove_terraform_template.yml b/data/removals/14_0/remove_terraform_template.yml
index bc3b529f630..2d78eb1f59c 100644
--- a/data/removals/14_0/remove_terraform_template.yml
+++ b/data/removals/14_0/remove_terraform_template.yml
@@ -3,6 +3,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/328500'
+ breaking_change: true
body: |
GitLab 14.0 renews the Terraform CI template to the latest version. The new template is set up for the GitLab Managed Terraform state, with a dependency on the GitLab `terraform-images` image, to provide a good user experience around GitLab's Infrastructure-as-Code features.
diff --git a/data/removals/14_0/verify-ci-removal-parametertrace.yml b/data/removals/14_0/verify-ci-removal-parametertrace.yml
index c37497c1a35..4fd1fa3d459 100644
--- a/data/removals/14_0/verify-ci-removal-parametertrace.yml
+++ b/data/removals/14_0/verify-ci-removal-parametertrace.yml
@@ -2,6 +2,7 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: jreporter
+ breaking_change: true
body: |
GitLab Runner was updated in GitLab 13.4 to internally stop passing the `trace` parameter to the `/api/jobs/:id` endpoint. GitLab 14.0 deprecates the `trace` parameter entirely for all other requests of this endpoint. Make sure your [GitLab Runner version matches your GitLab version](https://docs.gitlab.com/runner/#gitlab-runner-versions) to ensure consistent behavior.
diff --git a/data/removals/14_0/verify-ci-removalpipelineservice.yml b/data/removals/14_0/verify-ci-removalpipelineservice.yml
index f3583bd0498..fe3d3f224d1 100644
--- a/data/removals/14_0/verify-ci-removalpipelineservice.yml
+++ b/data/removals/14_0/verify-ci-removalpipelineservice.yml
@@ -2,5 +2,6 @@
removal_date: "2021-06-22"
removal_milestone: "14.0"
reporter: jreporter
+ breaking_change: true
body: |
For self-managed instances using the experimental [external pipeline validation service](https://docs.gitlab.com/ee/administration/external_pipeline_validation.html), the range of error codes GitLab accepts will be reduced. Currently, pipelines are invalidated when the validation service returns a response code from `400` to `499`. In GitLab 14.0 and later, pipelines will be invalidated for the `406: Not Accepted` response code only.
diff --git a/data/removals/14_1/removal-memory-prometheus-options-source.yml b/data/removals/14_1/removal-memory-prometheus-options-source.yml
index afef081c348..57a5dfa5d69 100644
--- a/data/removals/14_1/removal-memory-prometheus-options-source.yml
+++ b/data/removals/14_1/removal-memory-prometheus-options-source.yml
@@ -2,6 +2,7 @@
removal_date: July 22, 2021
removal_milestone: "14.1"
reporter: fzimmer
+ breaking_change: false
body: |
The support for `prometheus.listen_address` and `prometheus.enable` has been removed from `gitlab.yml`. Use `prometheus.enabled` and `prometheus.server_address` to set up Prometheus server that GitLab instance connects to. Refer to [our documentation](https://docs.gitlab.com/ee/install/installation.html#prometheus-server-setup) for details.
diff --git a/data/removals/14_1/removal-outdated-browser-support.yml b/data/removals/14_1/removal-outdated-browser-support.yml
index 1019b8fe2f3..281b8d65686 100644
--- a/data/removals/14_1/removal-outdated-browser-support.yml
+++ b/data/removals/14_1/removal-outdated-browser-support.yml
@@ -2,6 +2,7 @@
removal_date: July 22, 2021
removal_milestone: "14.1"
reporter: leipert
+ breaking_change: false
body: |
In GitLab 14.1, we are cleaning up and [removing old code](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63994) that was specific for browsers that we no longer support. This has no impact on users when one of our [supported web browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers) is used.
diff --git a/data/removals/14_2/removal-verify-build-log.yml b/data/removals/14_2/removal-verify-build-log.yml
index 6b4e37c7c6e..10ffe8b7242 100644
--- a/data/removals/14_2/removal-verify-build-log.yml
+++ b/data/removals/14_2/removal-verify-build-log.yml
@@ -2,6 +2,7 @@
removal_date: August 22, 2021 # day the removal was released
removal_milestone: "14.2"
reporter: jreporter # GitLab username of the person reporting the removal
+ breaking_change: false
body: |
GitLab values efficiency for all users in our wider community of contributors, so we're always working hard to make sure the application performs at a high level with a lovable UX.
In GitLab 14.2, we have introduced a [job log file size limit](https://docs.gitlab.com/ee/administration/instance_limits.html#maximum-file-size-for-job-logs), set to 100 megabytes by default. Administrators of self-managed GitLab instances can customize this to any value. All jobs that exceed this limit are dropped and marked as failed, helping prevent performance impacts or over-use of resources. This ensures that everyone using GitLab has the best possible experience.
diff --git a/data/removals/14_3/removal-limit-tags-to-50.yml b/data/removals/14_3/removal-limit-tags-to-50.yml
index db624656e6e..3395fc9b6ce 100644
--- a/data/removals/14_3/removal-limit-tags-to-50.yml
+++ b/data/removals/14_3/removal-limit-tags-to-50.yml
@@ -1,6 +1,7 @@
- name: "Introduced limit of 50 tags for jobs"
removal_date: September 22nd, 2021
removal_milestone: "14.3"
- reporter: jreporter
+ reporter: jreporter
+ breaking_change: false
body: |
GitLab values efficiency and is prioritizing reliability for [GitLab.com in FY22](https://about.gitlab.com/direction/#gitlab-hosted-first). In 14.3, GitLab CI/CD jobs must have less than 50 [tags](https://docs.gitlab.com/ee/ci/yaml/index.html#tags). If a pipeline contains a job with 50 or more tags, you will receive an error and the pipeline will not be created.
diff --git a/data/removals/14_3/removal-verify-pe-pipelinefindername.yml b/data/removals/14_3/removal-verify-pe-pipelinefindername.yml
index 979317f99df..df39a6cec38 100644
--- a/data/removals/14_3/removal-verify-pe-pipelinefindername.yml
+++ b/data/removals/14_3/removal-verify-pe-pipelinefindername.yml
@@ -2,5 +2,6 @@
removal_date: September 22, 2021 # day the removal was released
removal_milestone: "14.3"
reporter: jreporter # GitLab username of the person reporting the removal
+ breaking_change: false
body: |
In GitLab 14.3, we will remove the ability to filter by `name` in the [list project pipelines API endpoint](https://docs.gitlab.com/ee/api/pipelines.html#list-project-pipelines) to improve performance. If you currently use this parameter with this endpoint, you must switch to `username`.
diff --git a/data/removals/14_3/removal_legacy_storage_setting.yml b/data/removals/14_3/removal_legacy_storage_setting.yml
index b1f98e47554..5241861bf5a 100644
--- a/data/removals/14_3/removal_legacy_storage_setting.yml
+++ b/data/removals/14_3/removal_legacy_storage_setting.yml
@@ -2,6 +2,7 @@
removal_date: September 22nd, 2021 # day the removal was released
removal_milestone: "14.3"
reporter: dorrino # GitLab username of the person reporting the removal
+ breaking_change: false
body: | # example (supports markdown)
The support for [`gitlab_pages['use_legacy_storage']` setting](https://docs.gitlab.com/ee/administration/pages/index.html#domain-source-configuration-before-140) in Omnibus installations has been removed.
diff --git a/data/removals/templates/_removal_template.md.erb b/data/removals/templates/_removal_template.md.erb
index e227c6aa6e6..5243f4fdcd8 100644
--- a/data/removals/templates/_removal_template.md.erb
+++ b/data/removals/templates/_removal_template.md.erb
@@ -33,6 +33,7 @@ For removal reviewers (Technical Writers only):
<%- entries.select{|entry| entry["removal_milestone"] == milestone}.each do |removal| %>
### <%= removal["name"]%>
<% if removal["breaking_change"] -%>
+
WARNING:
This feature was changed or removed in <%= removal["removal_milestone"]%>
as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
diff --git a/data/removals/templates/example.yml b/data/removals/templates/example.yml
index 78cbec2be28..51f55a4505a 100644
--- a/data/removals/templates/example.yml
+++ b/data/removals/templates/example.yml
@@ -15,6 +15,7 @@
removal_milestone: "XX.YY" # The milestone when this feature is being removed.
removal_date: "YYYY-MM-DD" # This should almost always be the 22nd of a month (YYYY-MM-DD), the date of the milestone release when this feature will be removed.
breaking_change: false # Change to true if this removal is a breaking change.
+ reporter: exampleuser # GitLab username of the person reporting the removal
body: | # Do not modify this line, instead modify the lines below.
<!-- START OF BODY COMMENT
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index a66503a9cff..1b1adff7993 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -17116,6 +17116,8 @@ Values for sorting merge requests.
| <a id="mergerequestsortmilestone_due_desc"></a>`MILESTONE_DUE_DESC` | Milestone due date by descending order. |
| <a id="mergerequestsortpriority_asc"></a>`PRIORITY_ASC` | Priority by ascending order. |
| <a id="mergerequestsortpriority_desc"></a>`PRIORITY_DESC` | Priority by descending order. |
+| <a id="mergerequestsorttitle_asc"></a>`TITLE_ASC` | Title by ascending order. |
+| <a id="mergerequestsorttitle_desc"></a>`TITLE_DESC` | Title by descending order. |
| <a id="mergerequestsortupdated_asc"></a>`UPDATED_ASC` | Updated at ascending order. |
| <a id="mergerequestsortupdated_desc"></a>`UPDATED_DESC` | Updated at descending order. |
| <a id="mergerequestsortcreated_asc"></a>`created_asc` **{warning-solid}** | **Deprecated** in 13.5. This was renamed. Use: `CREATED_ASC`. |
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 905ecd05d52..82db3b0a2fd 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -78,7 +78,7 @@ Parameters:
| Attribute | Type | Required | Description |
| ------------------------------- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged`. |
-| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`. |
+| `order_by` | string | no | Return requests ordered by `created_at`, `title`, or `updated_at` fields. Default is `created_at`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/331625) in GitLab 14.8.|
| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc`. |
| `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. |
| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request. |
@@ -273,7 +273,7 @@ Parameters:
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `iids[]` | integer array | no | Return the request having the given `iid`. |
| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged`. |
-| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`. |
+| `order_by` | string | no | Return requests ordered by `created_at`, `title` or `updated_at` fields. Default is `created_at`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/331625) in GitLab 14.8. |
| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc`. |
| `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. |
| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request. |
@@ -468,7 +468,7 @@ Parameters:
| ------------------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged`. |
-| `order_by` | string | no | Return merge requests ordered by `created_at` or `updated_at` fields. Default is `created_at`. |
+| `order_by` | string | no | Return merge requests ordered by `created_at`, `title` or `updated_at` fields. Default is `created_at`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/331625) in GitLab 14.8. |
| `sort` | string | no | Return merge requests sorted in `asc` or `desc` order. Default is `desc`. |
| `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. |
| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request. |
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index ed71f612061..aea71f4b376 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -1081,55 +1081,6 @@ If you use the RubyMine IDE, and have marked the `tmp` directory as
`gitlab/tmp/tests/graphql`. This will allow the **JS GraphQL** plugin to
automatically find and index the schema.
-#### Mocking response as component data
-
-<!-- vale gitlab.Spelling = NO -->
-
-With [Vue Test Utils](https://vue-test-utils.vuejs.org/) one can quickly test components that
-fetch GraphQL queries. The simplest way is to use `shallowMount` and then set
-the data on the component:
-
-<!-- vale gitlab.Spelling = YES -->
-
-```javascript
-it('tests apollo component', () => {
- const vm = shallowMount(App);
-
- vm.setData({
- ...mockData
- });
-});
-```
-
-#### Testing loading state
-
-To test how a component renders when results from the GraphQL API are still loading, mock a loading state into respective Apollo queries/mutations:
-
-```javascript
- function createComponent({
- loading = false,
- } = {}) {
- const $apollo = {
- queries: {
- designs: {
- loading,
- },
- },
- };
-
- wrapper = shallowMount(Index, {
- sync: false,
- mocks: { $apollo }
- });
- }
-
- it('renders loading icon', () => {
- createComponent({ loading: true });
-
- expect(wrapper.element).toMatchSnapshot();
-})
-```
-
#### Testing Apollo components
If we use `ApolloQuery` or `ApolloMutation` in our components, in order to test their functionality we need to add a stub first:
@@ -1197,11 +1148,9 @@ it('calls mutation on submitting form ', () => {
});
```
-### Testing with mocked Apollo Client
-
-To test the logic of Apollo cache updates, we might want to mock an Apollo Client in our unit tests. We use [`mock-apollo-client`](https://www.npmjs.com/package/mock-apollo-client) library to mock Apollo client and [`createMockApollo` helper](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/frontend/__helpers__/mock_apollo_helper.js) we created on top of it.
+#### Mocking Apollo Client
-To separate tests with mocked client from 'usual' unit tests, create an additional factory and pass the created `mockApollo` as an option to the `createComponent`-factory. This way we only create Apollo Client instance when it's necessary.
+To test the components with Apollo operations, we need to mock an Apollo Client in our unit tests. We use [`mock-apollo-client`](https://www.npmjs.com/package/mock-apollo-client) library to mock Apollo client and [`createMockApollo` helper](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/frontend/__helpers__/mock_apollo_helper.js) we created on top of it.
We need to inject `VueApollo` into the Vue instance by calling `Vue.use(VueApollo)`. This will install `VueApollo` globally for all the tests in the file. It is recommended to call `Vue.use(VueApollo)` just after the imports.
@@ -1320,8 +1269,7 @@ it('renders designs list', async () => {
const mockApollo = createMockApolloProvider();
const wrapper = createComponent({ mockApollo });
- jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
+ await waitForPromises()
expect(findDesigns()).toHaveLength(3);
});
@@ -1342,8 +1290,7 @@ function createMockApolloProvider() {
it('renders error if query fails', async () => {
const wrapper = createComponent();
- jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
+ await waitForPromises()
expect(wrapper.find('.test-error').exists()).toBe(true)
})
@@ -1351,7 +1298,7 @@ it('renders error if query fails', async () => {
Request handlers can also be passed to component factory as a parameter.
-Mutations could be tested the same way with a few additional `nextTick`s to get the updated result:
+Mutations could be tested the same way:
```javascript
function createMockApolloProvider({
@@ -1391,7 +1338,7 @@ it('calls a mutation with correct parameters and reorders designs', async () =>
expect(moveDesignHandler).toHaveBeenCalled();
- await wrapper.vm.$nextTick();
+ await waitForPromises();
expect(
findDesigns()
@@ -1407,8 +1354,7 @@ To mock multiple query response states, success and failure, Apollo Client's nat
describe('when query times out', () => {
const advanceApolloTimers = async () => {
jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
- await wrapper.vm.$nextTick();
+ await waitForPromises()
};
beforeEach(async () => {
@@ -1419,7 +1365,7 @@ describe('when query times out', () => {
.mockResolvedValueOnce({ errors: [{ message: 'timeout' }] });
createComponentWithApollo(failSucceedFail);
- await wrapper.vm.$nextTick();
+ await waitForPromises();
});
it('shows correct errors and does not overwrite populated data when data is empty', async () => {
diff --git a/doc/update/removals.md b/doc/update/removals.md
index ef5fcd76f80..cad89e5ed6e 100644
--- a/doc/update/removals.md
+++ b/doc/update/removals.md
@@ -32,22 +32,46 @@ For removal reviewers (Technical Writers only):
### Breaking changes to Terraform CI template
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
GitLab 14.0 renews the Terraform CI template to the latest version. The new template is set up for the GitLab Managed Terraform state, with a dependency on the GitLab `terraform-images` image, to provide a good user experience around GitLab's Infrastructure-as-Code features.
The current stable and latest templates are not compatible, and the current latest template becomes the stable template beginning with GitLab 14.0, your Terraform pipeline might encounter an unexpected failure if you run a custom `init` job.
### Code Quality RuboCop support changed
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
By default, the Code Quality feature has not provided support for Ruby 2.6+ if you're using the Code Quality template. To better support the latest versions of Ruby, the default RuboCop version is updated to add support for Ruby 2.4 through 3.0. As a result, support for Ruby 2.1, 2.2, and 2.3 is removed. You can re-enable support for older versions by [customizing your configuration](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html#rubocop-errors).
Relevant Issue: [Default `codeclimate-rubocop` engine does not support Ruby 2.6+](https://gitlab.com/gitlab-org/ci-cd/codequality/-/issues/28)
### Container Scanning Engine Clair
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Clair, the default container scanning engine, was deprecated in GitLab 13.9 and is removed from GitLab 14.0 and replaced by Trivy. We advise customers who are customizing variables for their container scanning job to [follow these instructions](https://docs.gitlab.com/ee/user/application_security/container_scanning/#change-scanners) to ensure that their container scanning jobs continue to work.
### DAST environment variable renaming and removal
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
GitLab 13.8 renamed multiple environment variables to support their broader usage in different workflows. In GitLab 14.0, the old variables have been permanently removed and will no longer work. Any configurations using these variables must be updated to the new variable names. Any scans using these variables in GitLab 14.0 and later will fail to be configured correctly. These variables are:
- `DAST_AUTH_EXCLUDE_URLS` becomes `DAST_EXCLUDE_URLS`.
@@ -61,16 +85,34 @@ GitLab 13.8 renamed multiple environment variables to support their broader usag
### Default Browser Performance testing job renamed in GitLab 14.0
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Browser Performance Testing has run in a job named `performance` by default. With the introduction of [Load Performance Testing](https://docs.gitlab.com/ee/user/project/merge_requests/load_performance_testing.html) in GitLab 13.2, this naming could be confusing. To make it clear which job is running [Browser Performance Testing](https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html), the default job name is changed from `performance` to `browser_performance` in the template in GitLab 14.0.
Relevant Issue: [Rename default Browser Performance Testing job](https://gitlab.com/gitlab-org/gitlab/-/issues/225914)
### Default DAST spider begins crawling at target URL
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In GitLab 14.0, DAST has removed the current method of resetting the scan to the hostname when starting to spider. Prior to GitLab 14.0, the spider would not begin at the specified target path for the URL but would instead reset the URL to begin crawling at the host root. GitLab 14.0 changes the default for the new variable `DAST_SPIDER_START_AT_HOST` to `false` to better support users' intention of beginning spidering and scanning at the specified target URL, rather than the host root URL. This change has an added benefit: scans can take less time, if the specified path does not contain links to the entire site. This enables easier scanning of smaller sections of an application, rather than crawling the entire app during every scan.
### Default branch name for new repositories now `main`
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Every Git repository has an initial branch, which is named `master` by default. It's the first branch to be created automatically when you create a new repository. Future [Git versions](https://lore.kernel.org/git/pull.656.v4.git.1593009996.gitgitgadget@gmail.com/) will change the default branch name in Git from `master` to `main`. In coordination with the Git project and the broader community, [GitLab has changed the default branch name](https://gitlab.com/gitlab-org/gitlab/-/issues/223789) for new projects on both our SaaS (GitLab.com) and self-managed offerings starting with GitLab 14.0. This will not affect existing projects.
GitLab has already introduced changes that allow you to change the default branch name both at the [instance level](https://docs.gitlab.com/ee/user/project/repository/branches/default.html#instance-level-custom-initial-branch-name) (for self-managed users) and at the [group level](https://docs.gitlab.com/ee/user/group/#use-a-custom-name-for-the-initial-branch) (for both SaaS and self-managed users). We encourage you to make use of these features to set default branch names on new projects.
@@ -79,6 +121,12 @@ For more information, check out our [blog post](https://about.gitlab.com/blog/20
### Deprecated GraphQL fields have been removed
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In accordance with our [GraphQL deprecation and removal process](https://docs.gitlab.com/ee/api/graphql/#deprecation-process), the following fields that were deprecated prior to 13.7 are [fully removed in 14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/267966):
- `Mutations::Todos::MarkAllDone`, `Mutations::Todos::RestoreMany` - `:updated_ids`
@@ -90,6 +138,12 @@ In accordance with our [GraphQL deprecation and removal process](https://docs.gi
### Deprecations for Dependency Scanning
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
As mentioned in [13.9](https://about.gitlab.com/releases/2021/02/22/gitlab-13-9-released/#deprecations-for-dependency-scanning) and [this blog post](https://about.gitlab.com/blog/2021/02/08/composition-analysis-14-deprecations-and-removals/) several removals for Dependency Scanning take effect.
Previously, to exclude a DS analyzer, you needed to remove it from the default list of analyzers, and use that to set the `DS_DEFAULT_ANALYZERS` variable in your project’s CI template. We determined it should be easier to avoid running a particular analyzer without losing the benefit of newly added analyzers. As a result, we ask you to migrate from `DS_DEFAULT_ANALYZERS` to `DS_EXCLUDED_ANALYZERS` when it is available. Read about it in [issue #287691](https://gitlab.com/gitlab-org/gitlab/-/issues/287691).
@@ -98,10 +152,22 @@ Previously, to prevent the Gemnasium analyzers to fetch the advisory database at
### External Pipeline Validation Service Code Changes
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
For self-managed instances using the experimental [external pipeline validation service](https://docs.gitlab.com/ee/administration/external_pipeline_validation.html), the range of error codes GitLab accepts will be reduced. Currently, pipelines are invalidated when the validation service returns a response code from `400` to `499`. In GitLab 14.0 and later, pipelines will be invalidated for the `406: Not Accepted` response code only.
### Geo Foreign Data Wrapper settings removed
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
As [announced in GitLab 13.3](https://about.gitlab.com/releases/2020/08/22/gitlab-13-3-released/#geo-foreign-data-wrapper-settings-deprecated), the following configuration settings in `/etc/gitlab/gitlab.rb` have been removed in 14.0:
- `geo_secondary['db_fdw']`
@@ -111,20 +177,44 @@ As [announced in GitLab 13.3](https://about.gitlab.com/releases/2020/08/22/gitla
### GitLab OAuth implicit grant deprecation
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
GitLab is deprecating the [OAuth 2 implicit grant flow](https://docs.gitlab.com/ee/api/oauth2.html#implicit-grant-flow) as it has been removed for [OAuth 2.1](https://oauth.net/2.1/).
Beginning in 14.0, new applications can't be created with the OAuth 2 implicit grant flow. Existing OAuth implicit grant flows are no longer supported in 14.4. Migrate your existing applications to other supported [OAuth2 flows](https://docs.gitlab.com/ee/api/oauth2.html#supported-oauth2-flows) before release 14.4.
### GitLab Runner helper image in GitLab.com Container Registry
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In 14.0, we are now pulling the GitLab Runner [helper image](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#helper-image) from the GitLab Container Registry instead of Docker Hub. Refer to [issue #27218](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27218) for details.
### GitLab Runner installation to ignore the `skel` directory
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In GitLab Runner 14.0, the installation process will ignore the `skel` directory by default when creating the user home directory. Refer to [issue #4845](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4845) for details.
### Gitaly Cluster SQL primary elector has been removed
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Now that Praefect supports a [primary election strategy](https://docs.gitlab.com/ee/administration/gitaly/praefect.html#repository-specific-primary-nodes) for each repository, we have removed the `sql` election strategy.
The `per_repository` election strategy is the new default, which is automatically used if no election strategy was specified.
@@ -132,33 +222,75 @@ If you had configured the `sql` election strategy, you must follow the [migratio
### Helm v2 support
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Helm v2 was [officially deprecated](https://helm.sh/blog/helm-v2-deprecation-timeline/) in November of 2020, with the `stable` repository being [de-listed from the Helm Hub](https://about.gitlab.com/blog/2020/11/09/ensure-auto-devops-work-after-helm-stable-repo/) shortly thereafter. With the release of GitLab 14.0, which will include the 5.0 release of the [GitLab Helm chart](https://docs.gitlab.com/charts/), Helm v2 will no longer be supported.
Users of the chart should [upgrade to Helm v3](https://helm.sh/docs/topics/v2_v3_migration/) to deploy GitLab 14.0 and later.
### Legacy feature flags removed
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Legacy feature flags became read-only in GitLab 13.4. GitLab 14.0 removes support for legacy feature flags, so you must migrate them to the [new version](https://docs.gitlab.com/ee/operations/feature_flags.html). You can do this by first taking a note (screenshot) of the legacy flag, then deleting the flag through the API or UI (you don't need to alter the code), and finally create a new Feature Flag with the same name as the legacy flag you deleted. Also, make sure the strategies and environments match the deleted flag. We created a [video tutorial](https://www.youtube.com/watch?v=CAJY2IGep7Y) to help with this migration.
### Legacy storage removed
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
As [announced in GitLab 13.0](https://about.gitlab.com/releases/2020/05/22/gitlab-13-0-released/#planned-removal-of-legacy-storage-in-14.0), [legacy storage](https://docs.gitlab.com/ee/administration/repository_storage_types.html#legacy-storage) has been removed in GitLab 14.0.
### Limit projects returned in `GET /groups/:id/`
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
To improve performance, we are limiting the number of projects returned from the `GET /groups/:id/` API call to 100. A complete list of projects can still be retrieved with the `GET /groups/:id/projects` API call.
### Make `pwsh` the default shell for newly-registered Windows Runners
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In GitLab Runner 13.2, PowerShell Core support was added to the Shell executor. In 14.0, PowerShell Core, `pwsh` is now the default shell for newly-registered Windows runners. Windows `CMD` will still be available as a shell option for Windows runners. Refer to [issue #26419](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26419) for details.
### Migrate from `SAST_DEFAULT_ANALYZERS` to `SAST_EXCLUDED_ANALYZERS`
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Until GitLab 13.9, if you wanted to avoid running one particular GitLab SAST analyzer, you needed to remove it from the [long string of analyzers in the `SAST.gitlab-ci.yml` file](https://gitlab.com/gitlab-org/gitlab/-/blob/390afc431e7ce1ac253b35beb39f19e49c746bff/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml#L12) and use that to set the [`SAST_DEFAULT_ANALYZERS`](https://docs.gitlab.com/ee/user/application_security/sast/#docker-images) variable in your project's CI file. If you did this, it would exclude you from future new analyzers because this string hard codes the list of analyzers to execute. We avoid this problem by inverting this variable's logic to exclude, rather than choose default analyzers.
Beginning with 13.9, [we migrated](https://gitlab.com/gitlab-org/gitlab/-/blob/14fed7a33bfdbd4663d8928e46002a5ef3e3282c/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml#L13) to `SAST_EXCLUDED_ANALYZERS` in our `SAST.gitlab-ci.yml` file. We encourage anyone who uses a [customized SAST configuration](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) in their project CI file to migrate to this new variable. If you have not overridden `SAST_DEFAULT_ANALYZERS`, no action is needed. The CI/CD variable `SAST_DEFAULT_ANALYZERS` has been removed in GitLab 14.0, which released on June 22, 2021.
### New Terraform template version
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
As we continuously [develop GitLab's Terraform integrations](https://gitlab.com/gitlab-org/gitlab/-/issues/325312), to minimize customer disruption, we maintain two GitLab CI/CD templates for Terraform:
- The ["latest version" template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml), which is updated frequently between minor releases of GitLab (such as 13.10, 13.11, etc).
@@ -174,102 +306,240 @@ To check the new changes, see the [new "major version" template](https://gitlab.
### OpenSUSE Leap 15.1
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Support for [OpenSUSE Leap 15.1 is being deprecated](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5135). Support for 15.1 will be dropped in 14.0. We are now providing support for openSUSE Leap 15.2 packages.
### PostgreSQL 11 support
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
PostgreSQL 12 will be the minimum required version in GitLab 14.0. It offers [significant improvements](https://www.postgresql.org/about/news/postgresql-12-released-1976/) to indexing, partitioning, and general performance benefits.
Starting in GitLab 13.7, all new installations default to version 12. From GitLab 13.8, single-node instances are automatically upgraded as well. If you aren't ready to upgrade, you can [opt out of automatic upgrades](https://docs.gitlab.com/omnibus/settings/database.html#opt-out-of-automatic-postgresql-upgrades).
### Removal of deprecated `trace` parameter from `jobs` API endpoint
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
GitLab Runner was updated in GitLab 13.4 to internally stop passing the `trace` parameter to the `/api/jobs/:id` endpoint. GitLab 14.0 deprecates the `trace` parameter entirely for all other requests of this endpoint. Make sure your [GitLab Runner version matches your GitLab version](https://docs.gitlab.com/runner/#gitlab-runner-versions) to ensure consistent behavior.
### Removal of legacy fields from DAST report
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
As a part of the migration to a common report format for all of the Secure scanners in GitLab, DAST is making changes to the DAST JSON report. Certain legacy fields were deprecated in 13.8 and have been completely removed in 14.0. These fields are `@generated`, `@version`, `site`, and `spider`. This should not affect any normal DAST operation, but does affect users who consume the JSON report in an automated way and use these fields. Anyone affected by these changes, and needs these fields for business reasons, is encouraged to open a new GitLab issue and explain the need.
For more information, see [the removal issue](https://gitlab.com/gitlab-org/gitlab/-/issues/33915).
### Removal of release description in the Tags API
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
GitLab 14.0 removes support for the release description in the Tags API. You can no longer add a release description when [creating a new tag](https://docs.gitlab.com/ee/api/tags.html#create-a-new-tag). You also can no longer [create](https://docs.gitlab.com/ee/api/tags.html#create-a-new-release) or [update](https://docs.gitlab.com/ee/api/tags.html#update-a-release) a release through the Tags API. Please migrate to use the [Releases API](https://docs.gitlab.com/ee/api/releases/#create-a-release) instead.
### Removals for License Compliance
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In 13.0, we deprecated the License-Management CI template and renamed it License-Scanning. We have been providing backward compatibility by warning users of the old template to switch. Now in 14.0, we are completely removing the License-Management CI template. Read about it in [issue #216261](https://gitlab.com/gitlab-org/gitlab/-/issues/216261) or [this blog post](https://about.gitlab.com/blog/2021/02/08/composition-analysis-14-deprecations-and-removals/).
### Remove DAST default template stages
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In GitLab 14.0, we've removed the stages defined in the current `DAST.gitlab-ci.yml` template to avoid the situation where the template overrides manual changes made by DAST users. We're making this change in response to customer issues where the stages in the template cause problems when used with customized DAST configurations. Because of this removal, `gitlab-ci.yml` configurations that do not specify a `dast` stage must be updated to include this stage.
### Remove SAST analyzer `SAST_GOSEC_CONFIG` variable in favor of custom rulesets
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
With the release of [SAST Custom Rulesets](https://docs.gitlab.com/ee/user/application_security/sast/#customize-rulesets) in GitLab 13.5 we allow greater flexibility in configuration options for our Go analyzer (GoSec). As a result we no longer plan to support our less flexible [`SAST_GOSEC_CONFIG`](https://docs.gitlab.com/ee/user/application_security/sast/#analyzer-settings) analyzer setting. This variable was deprecated in GitLab 13.10.
GitLab 14.0 removes the old `SAST_GOSEC_CONFIG variable`. If you use or override `SAST_GOSEC_CONFIG` in your CI file, update your SAST CI configuration or pin to an older version of the GoSec analyzer. We strongly encourage [inheriting and overriding our managed CI templates](https://docs.gitlab.com/ee/user/application_security/sast/#overriding-sast-jobs) to future-proof your CI templates.
### Remove Ubuntu 19.10 (Eoan Ermine) package
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Ubuntu 19.10 (Eoan Ermine) reached end of life on Friday, July 17, 2020. In GitLab Runner 14.0, Ubuntu 19.10 (Eoan Ermine) is no longer available from our package distribution. Refer to [issue #26036](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26036) for details.
### Remove `/usr/lib/gitlab-runner` symlink from package
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In GitLab Runner 13.3, a symlink was added from `/user/lib/gitlab-runner/gitlab-runner` to `/usr/bin/gitlab-runner`. In 14.0, the symlink has been removed and the runner is now installed in `/usr/bin/gitlab-runner`. Refer to [issue #26651](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26651) for details.
### Remove `?w=1` URL parameter to ignore whitespace changes
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
To create a consistent experience for users based on their preferences, support for toggling whitespace changes via URL parameter has been removed in GitLab 14.0.
### Remove `FF_RESET_HELPER_IMAGE_ENTRYPOINT` feature flag
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In 14.0, we have deactivated the `FF_RESET_HELPER_IMAGE_ENTRYPOINT` feature flag. Refer to issue [#26679](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26679) for details.
### Remove `FF_SHELL_EXECUTOR_USE_LEGACY_PROCESS_KILL` feature flag
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In [GitLab Runner 13.1](https://docs.gitlab.com/runner/executors/shell.html#gitlab-131-and-later), [issue #3376](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/3376), we introduced `sigterm` and then `sigkill` to a process in the Shell executor. We also introduced a new feature flag, `FF_SHELL_EXECUTOR_USE_LEGACY_PROCESS_KILL`, so you can use the previous process termination sequence. In GitLab Runner 14.0, [issue #6413](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6413), the feature flag has been removed.
### Remove `FF_USE_GO_CLOUD_WITH_CACHE_ARCHIVER` feature flag
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
GitLab Runner 14.0 removes the `FF_USE_GO_CLOUD_WITH_CACHE_ARCHIVER` feature flag. Refer to [issue #27175](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27175) for details.
### Remove `secret_detection_default_branch` job
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
To ensure Secret Detection was scanning both default branches and feature branches, we introduced two separate secret detection CI jobs (`secret_detection_default_branch` and `secret_detection`) in our managed [`Secret-Detection.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml) template. These two CI jobs created confusion and complexity in the CI rules logic. This deprecation moves the `rule` logic into the `script` section, which then determines how the `secret_detection` job is run (historic, on a branch, commits, etc).
If you override or maintain custom versions of `SAST.gitlab-ci.yml` or `Secret-Detection.gitlab-ci.yml`, you must update your CI templates. We strongly encourage [inheriting and overriding our managed CI templates](https://docs.gitlab.com/ee/user/application_security/secret_detection/#custom-settings-example) to future-proof your CI templates. GitLab 14.0 no longer supports the old `secret_detection_default_branch` job.
### Remove disk source configuration for GitLab Pages
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
GitLab Pages [API-based configuration](https://docs.gitlab.com/ee/administration/pages/#gitlab-api-based-configuration) has been available since GitLab 13.0. It replaces the unsupported `disk` source configuration removed in GitLab 14.0, which can no longer be chosen. You should stop using `disk` source configuration, and move to `gitlab` for an API-based configuration. To migrate away from the 'disk' source configuration, set `gitlab_pages['domain_config_source'] = "gitlab"` in your `/etc/gitlab/gitlab.rb` file. We recommend you migrate before updating to GitLab 14.0, to identify and troubleshoot any potential problems before upgrading.
### Remove legacy DAST domain validation
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
The legacy method of DAST Domain Validation for CI/CD scans was deprecated in GitLab 13.8, and is removed in GitLab 14.0. This method of domain validation only disallows scans if the `DAST_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` environment variable is set to `true` in the `gitlab-ci.yml` file, and a `Gitlab-DAST-Permission` header on the site is not set to `allow`. This two-step method required users to opt in to using the variable before they could opt out from using the header.
For more information, see the [removal issue](https://gitlab.com/gitlab-org/gitlab/-/issues/293595).
### Remove off peak time mode configuration for Docker Machine autoscaling
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In GitLab Runner 13.0, [issue #5069](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/5069), we introduced new timing options for the GitLab Docker Machine executor. In GitLab Runner 14.0, we have removed the old configuration option, [off peak time mode](https://docs.gitlab.com/runner/configuration/autoscale.html#off-peak-time-mode-configuration-deprecated).
### Remove redundant timestamp field from DORA metrics API payload
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
The [deployment frequency project-level API](https://docs.gitlab.com/ee/api/dora4_project_analytics.html#list-project-deployment-frequencies) endpoint has been deprecated in favor of the [DORA 4 API](https://docs.gitlab.com/ee/api/dora/metrics.html), which consolidates all the metrics under one API with the specific metric as a required field. As a result, the timestamp field, which doesn't allow adding future extensions and causes performance issues, will be removed. With the old API, an example response would be `{ "2021-03-01": 3, "date": "2021-03-01", "value": 3 }`. The first key/value (`"2021-03-01": 3`) will be removed and replaced by the last two (`"date": "2021-03-01", "value": 3`).
### Remove success and failure for finished build metric conversion
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In GitLab Runner 13.5, we introduced `failed` and `success` states for a job. To support Prometheus rules, we chose to convert `success/failure` to `finished` for the metric. In 14.0, the conversion has now been removed. Refer to [issue #26900](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26900) for details.
### Remove support for Windows Server 1903 image
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In 14.0, we have removed Windows Server 1903. Microsoft ended support for this version on 2020-08-12. Refer to [issue #27551](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27551) for details.
### Remove support for Windows Server 1909 image
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In 14.0, we have removed Windows Server 1909. Microsoft ended support for this version on 2021-05-11. Refer to [issue #27899](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27899) for details.
### Removed Global `SAST_ANALYZER_IMAGE_TAG` in SAST CI template
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
With the maturity of GitLab Secure scanning tools, we've needed to add more granularity to our release process. Previously, GitLab shared a major version number for [all analyzers and tools](https://docs.gitlab.com/ee/user/application_security/sast/#supported-languages-and-frameworks). This requires all tools to share a major version, and prevents the use of [semantic version numbering](https://semver.org/). In GitLab 14.0, SAST removes the `SAST_ANALYZER_IMAGE_TAG` global variable in our [managed `SAST.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml) CI template, in favor of the analyzer job variable setting the `major.minor` tag in the SAST vendored template.
Each analyzer job now has a scoped `SAST_ANALYZER_IMAGE_TAG` variable, which will be actively managed by GitLab and set to the `major` tag for the respective analyzer. To pin to a specific version, [change the variable value to the specific version tag](https://docs.gitlab.com/ee/user/application_security/sast/#pinning-to-minor-image-version).
@@ -278,6 +548,12 @@ This deprecation and removal changes our [previously announced plan](https://abo
### Ruby version changed in `Ruby.gitlab-ci.yml`
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
By default, the `Ruby.gitlab-ci.yml` file has included Ruby 2.5.
To better support the latest versions of Ruby, the template is changed to use `ruby:latest`, which is currently 3.0. To better understand the changes in Ruby 3.0, please reference the [Ruby-lang.org release announcement](https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/).
@@ -286,54 +562,120 @@ Relevant Issue: [Updates Ruby version 2.5 to 3.0](https://gitlab.com/gitlab-org/
### Segments removed from DevOps Adoption API
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
The first release of the DevOps Adoption report had a concept of **Segments**. Segments were [quickly removed from the report](https://gitlab.com/groups/gitlab-org/-/epics/5251) because they introduced an additional layer of complexity on top of **Groups** and **Projects**. Subsequent iterations of the DevOps Adoption report focus on comparing adoption across groups rather than segments. GitLab 14.0 removes all references to **Segments** [from the GraphQL API](https://gitlab.com/gitlab-org/gitlab/-/issues/324414) and replaces them with **Enabled groups**.
### Service Templates removed
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Service Templates are [removed in GitLab 14.0](https://gitlab.com/groups/gitlab-org/-/epics/5672). They were used to apply identical settings to a large number of projects, but they only did so at the time of project creation.
While they solved part of the problem, _updating_ those values later proved to be a major pain point. [Project Integration Management](https://docs.gitlab.com/ee/user/admin_area/settings/project_integration_management.html) solves this problem by enabling you to create settings at the Group or Instance level, and projects within that namespace inheriting those settings.
### Sidekiq queue selector options no longer accept the 'experimental' prefix
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
GitLab supports a [queue selector](https://docs.gitlab.com/ee/administration/operations/extra_sidekiq_processes.html#queue-selector) to run only a subset of background jobs for a given process. When it was introduced, this option had an 'experimental' prefix (`experimental_queue_selector` in Omnibus, `experimentalQueueSelector` in Helm charts).
As announced in the [13.6 release post](https://about.gitlab.com/releases/2020/11/22/gitlab-13-6-released/#sidekiq-cluster-queue-selector-configuration-option-has-been-renamed), the 'experimental' prefix is no longer supported. Instead, `queue_selector` for Omnibus and `queueSelector` in Helm charts should be used.
### Ubuntu 16.04 support
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Ubuntu 16.04 [reached end-of-life in April 2021](https://ubuntu.com/about/release-cycle), and no longer receives maintenance updates. We strongly recommend users to upgrade to a newer release, such as 20.04.
GitLab 13.12 will be the last release with Ubuntu 16.04 support.
### Unicorn removed in favor of Puma for GitLab self-managed
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
[Support for Unicorn](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6078) has been removed in GitLab 14.0 in favor of Puma. [Puma has a multi-threaded architecture](https://docs.gitlab.com/ee/administration/operations/puma.html) which uses less memory than a multi-process application server like Unicorn. On GitLab.com, we saw a 40% reduction in memory consumption by using Puma.
### Update Auto Deploy template version
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
In GitLab 14.0, we will update the [Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/stages.html#auto-deploy) CI template to the latest version. This includes new features, bug fixes, and performance improvements with a dependency on the v2 [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image). Auto Deploy CI tempalte v1 will is deprecated going forward.
Since the v1 and v2 versions are not backward-compatible, your project might encounter an unexpected failure if you already have a deployed application. Follow the [upgrade guide](https://docs.gitlab.com/ee/topics/autodevops/upgrading_auto_deploy_dependencies.html#upgrade-guide) to upgrade your environments. You can also start using the latest template today by following the [early adoption guide](https://docs.gitlab.com/ee/topics/autodevops/upgrading_auto_deploy_dependencies.html#early-adopters).
### Update CI/CD templates to stop using hardcoded `master`
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
Our CI/CD templates have been updated to no longer use hard-coded references to a `master` branch. In 14.0, they all use a variable that points to your project's configured default branch instead. If your CI/CD pipeline relies on our built-in templates, verify that this change works with your current configuration. For example, if you have a `master` branch and a different default branch, the updates to the templates may cause changes to your pipeline behavior. For more information, [read the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/324131).
### WIP merge requests renamed 'draft merge requests'
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
The WIP (work in progress) status for merge requests signaled to reviewers that the merge request in question wasn't ready to merge. We've renamed the WIP feature to **Draft**, a more inclusive and self-explanatory term. **Draft** clearly communicates the merge request in question isn't ready for review, and makes no assumptions about the progress being made toward it. **Draft** also reduces the cognitive load for new users, non-English speakers, and anyone unfamiliar with the WIP acronym.
### Web Application Firewall (WAF)
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
The Web Application Firewall (WAF) was deprecated in GitLab 13.6 and is removed from GitLab 14.0. The WAF had limitations inherent in the architectural design that made it difficult to meet the requirements traditionally expected of a WAF. By removing the WAF, GitLab is able to focus on improving other areas in the product where more value can be provided to users. Users who currently rely on the WAF can continue to use the free and open source [ModSecurity](https://github.com/SpiderLabs/ModSecurity) project, which is independent from GitLab. Additional details are available in the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/271276).
### `CI_PROJECT_CONFIG_PATH` removed in GitLab 14.0
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
GitLab 14.0 removes the `CI_PROJECT_CONFIG_PATH` pre-defined project variable in favor of `CI_CONFIG_PATH`, which is functionally the same. If you are using `CI_PROJECT_CONFIG_PATH` in your pipeline configurations, update them to use `CI_CONFIG_PATH` instead.
### `CI_PROJECT_CONFIG_PATH` variable has been removed
+WARNING:
+This feature was changed or removed in 14.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
The `CI_PROJECT_CONFIG_PATH` [predefined project variable](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)
has been removed in favor of `CI_CONFIG_PATH`, which is functionally the same.
diff --git a/lib/api/helpers/merge_requests_helpers.rb b/lib/api/helpers/merge_requests_helpers.rb
index f8fe40f7135..00d9f49adf0 100644
--- a/lib/api/helpers/merge_requests_helpers.rb
+++ b/lib/api/helpers/merge_requests_helpers.rb
@@ -47,9 +47,9 @@ module API
desc: 'Return opened, closed, locked, merged, or all merge requests'
optional :order_by,
type: String,
- values: %w[created_at updated_at],
+ values: Helpers::MergeRequestsHelpers.sort_options,
default: 'created_at',
- desc: 'Return merge requests ordered by `created_at` or `updated_at` fields.'
+ desc: "Return merge requests ordered by #{Helpers::MergeRequestsHelpers.sort_options_help} fields."
optional :sort,
type: String,
values: %w[asc desc],
@@ -115,6 +115,22 @@ module API
render_validation_error!(merge_request)
end
+
+ def self.sort_options
+ %w[
+ created_at
+ label_priority
+ milestone_due
+ popularity
+ priority
+ title
+ updated_at
+ ]
+ end
+
+ def self.sort_options_help
+ sort_options.map {|y| "`#{y}`" }.to_sentence(last_word_connector: ' or ')
+ end
end
end
end
diff --git a/lib/bulk_imports/common/extractors/graphql_extractor.rb b/lib/bulk_imports/common/extractors/graphql_extractor.rb
index cde3d1cad5b..bfdc0b13603 100644
--- a/lib/bulk_imports/common/extractors/graphql_extractor.rb
+++ b/lib/bulk_imports/common/extractors/graphql_extractor.rb
@@ -5,15 +5,16 @@ module BulkImports
module Extractors
class GraphqlExtractor
def initialize(options = {})
- @query = options[:query]
+ @query_klass = options[:query]
end
def extract(context)
client = graphql_client(context)
+ query = query_klass.new(context: context)
response = client.execute(
client.parse(query.to_s),
- query.variables(context)
+ query.variables
).original_hash.deep_dup
BulkImports::Pipeline::ExtractedData.new(
@@ -24,7 +25,7 @@ module BulkImports
private
- attr_reader :query
+ attr_reader :query_klass
def graphql_client(context)
@graphql_client ||= BulkImports::Clients::Graphql.new(
diff --git a/lib/bulk_imports/groups/graphql/get_members_query.rb b/lib/bulk_imports/common/graphql/get_members_query.rb
index e76c87cc521..00977f694d7 100644
--- a/lib/bulk_imports/groups/graphql/get_members_query.rb
+++ b/lib/bulk_imports/common/graphql/get_members_query.rb
@@ -1,15 +1,20 @@
# frozen_string_literal: true
module BulkImports
- module Groups
+ module Common
module Graphql
- module GetMembersQuery
- extend self
+ class GetMembersQuery
+ attr_reader :context
+
+ def initialize(context:)
+ @context = context
+ end
+
def to_s
- <<-'GRAPHQL'
+ <<-GRAPHQL
query($full_path: ID!, $cursor: String, $per_page: Int) {
- group(fullPath: $full_path) {
- group_members: groupMembers(relations: DIRECT, first: $per_page, after: $cursor) {
+ portable: #{context.entity.entity_type}(fullPath: $full_path) {
+ members: #{members_type}(relations: [DIRECT, INHERITED], first: $per_page, after: $cursor) {
page_info: pageInfo {
next_page: endCursor
has_next_page: hasNextPage
@@ -32,7 +37,7 @@ module BulkImports
GRAPHQL
end
- def variables(context)
+ def variables
{
full_path: context.entity.source_full_path,
cursor: context.tracker.next_page,
@@ -40,10 +45,6 @@ module BulkImports
}
end
- def base_path
- %w[data group group_members]
- end
-
def data_path
base_path << 'nodes'
end
@@ -51,6 +52,20 @@ module BulkImports
def page_info_path
base_path << 'page_info'
end
+
+ private
+
+ def base_path
+ %w[data portable members]
+ end
+
+ def members_type
+ if context.entity.group?
+ 'groupMembers'
+ else
+ 'projectMembers'
+ end
+ end
end
end
end
diff --git a/lib/bulk_imports/common/pipelines/members_pipeline.rb b/lib/bulk_imports/common/pipelines/members_pipeline.rb
new file mode 100644
index 00000000000..f35eb5ccf5e
--- /dev/null
+++ b/lib/bulk_imports/common/pipelines/members_pipeline.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module BulkImports
+ module Common
+ module Pipelines
+ class MembersPipeline
+ include Pipeline
+
+ transformer Common::Transformers::ProhibitedAttributesTransformer
+ transformer BulkImports::Groups::Transformers::MemberAttributesTransformer
+
+ def extract(context)
+ graphql_extractor.extract(context)
+ end
+
+ def load(_context, data)
+ return unless data
+
+ user_id = data[:user_id]
+
+ # Current user is already a member
+ return if user_id == current_user.id
+
+ user_membership = existing_user_membership(user_id)
+
+ # User is already a member with higher existing (inherited) membership
+ return if user_membership && user_membership[:access_level] >= data[:access_level]
+
+ # Create new membership for any other access level
+ portable.members.create!(data)
+ end
+
+ private
+
+ def graphql_extractor
+ @graphql_extractor ||= BulkImports::Common::Extractors::GraphqlExtractor
+ .new(query: BulkImports::Common::Graphql::GetMembersQuery)
+ end
+
+ def existing_user_membership(user_id)
+ members_finder.execute.find_by_user_id(user_id)
+ end
+
+ def members_finder
+ @members_finder ||= if context.entity.group?
+ ::GroupMembersFinder.new(portable, current_user)
+ else
+ ::MembersFinder.new(portable, current_user)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bulk_imports/groups/graphql/get_group_query.rb b/lib/bulk_imports/groups/graphql/get_group_query.rb
index 6852e25c87f..911b2b67d8c 100644
--- a/lib/bulk_imports/groups/graphql/get_group_query.rb
+++ b/lib/bulk_imports/groups/graphql/get_group_query.rb
@@ -3,8 +3,12 @@
module BulkImports
module Groups
module Graphql
- module GetGroupQuery
- extend self
+ class GetGroupQuery
+ attr_reader :context
+
+ def initialize(context:)
+ @context = context
+ end
def to_s
<<-'GRAPHQL'
@@ -29,7 +33,7 @@ module BulkImports
GRAPHQL
end
- def variables(context)
+ def variables
{ full_path: context.entity.source_full_path }
end
diff --git a/lib/bulk_imports/groups/graphql/get_projects_query.rb b/lib/bulk_imports/groups/graphql/get_projects_query.rb
index 4cec1ad1462..3f74bbb8cce 100644
--- a/lib/bulk_imports/groups/graphql/get_projects_query.rb
+++ b/lib/bulk_imports/groups/graphql/get_projects_query.rb
@@ -3,8 +3,12 @@
module BulkImports
module Groups
module Graphql
- module GetProjectsQuery
- extend self
+ class GetProjectsQuery
+ attr_reader :context
+
+ def initialize(context:)
+ @context = context
+ end
def to_s
<<-'GRAPHQL'
@@ -25,7 +29,7 @@ module BulkImports
GRAPHQL
end
- def variables(context)
+ def variables
{
full_path: context.entity.source_full_path,
cursor: context.tracker.next_page,
diff --git a/lib/bulk_imports/groups/pipelines/members_pipeline.rb b/lib/bulk_imports/groups/pipelines/members_pipeline.rb
deleted file mode 100644
index 265abd5e3a7..00000000000
--- a/lib/bulk_imports/groups/pipelines/members_pipeline.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-module BulkImports
- module Groups
- module Pipelines
- class MembersPipeline
- include Pipeline
-
- extractor BulkImports::Common::Extractors::GraphqlExtractor,
- query: BulkImports::Groups::Graphql::GetMembersQuery
-
- transformer Common::Transformers::ProhibitedAttributesTransformer
- transformer BulkImports::Groups::Transformers::MemberAttributesTransformer
-
- def load(context, data)
- return unless data
-
- # Current user is already a member
- return if data['user_id'].to_i == context.current_user.id
-
- context.group.members.create!(data)
- end
- end
- end
- end
-end
diff --git a/lib/bulk_imports/groups/stage.rb b/lib/bulk_imports/groups/stage.rb
index 1a3babe1679..bc27220391d 100644
--- a/lib/bulk_imports/groups/stage.rb
+++ b/lib/bulk_imports/groups/stage.rb
@@ -16,7 +16,7 @@ module BulkImports
stage: 1
},
members: {
- pipeline: BulkImports::Groups::Pipelines::MembersPipeline,
+ pipeline: BulkImports::Common::Pipelines::MembersPipeline,
stage: 1
},
labels: {
diff --git a/lib/bulk_imports/groups/transformers/member_attributes_transformer.rb b/lib/bulk_imports/groups/transformers/member_attributes_transformer.rb
index b9de375d0e9..da50a19ee62 100644
--- a/lib/bulk_imports/groups/transformers/member_attributes_transformer.rb
+++ b/lib/bulk_imports/groups/transformers/member_attributes_transformer.rb
@@ -5,50 +5,35 @@ module BulkImports
module Transformers
class MemberAttributesTransformer
def transform(context, data)
- data
- .then { |data| add_user(data, context) }
- .then { |data| add_access_level(data) }
- .then { |data| add_author(data, context) }
- end
-
- private
-
- def add_user(data, context)
user = find_user(data&.dig('user', 'public_email'))
+ access_level = data&.dig('access_level', 'integer_value')
+ return unless data
return unless user
+ return unless valid_access_level?(access_level)
cache_source_user_id(data, user, context)
- data
- .except('user')
- .merge('user_id' => user.id)
+ {
+ user_id: user.id,
+ access_level: access_level,
+ created_at: data['created_at'],
+ updated_at: data['updated_at'],
+ expires_at: data['expires_at'],
+ created_by_id: context.current_user.id
+ }
end
+ private
+
def find_user(email)
return unless email
User.find_by_any_email(email, confirmed: true)
end
- def add_access_level(data)
- access_level = data&.dig('access_level', 'integer_value')
-
- return unless valid_access_level?(access_level)
-
- data.merge('access_level' => access_level)
- end
-
def valid_access_level?(access_level)
- Gitlab::Access
- .options_with_owner
- .value?(access_level)
- end
-
- def add_author(data, context)
- return unless data
-
- data.merge('created_by_id' => context.current_user.id)
+ Gitlab::Access.options_with_owner.value?(access_level)
end
def cache_source_user_id(data, user, context)
diff --git a/lib/bulk_imports/projects/graphql/get_project_query.rb b/lib/bulk_imports/projects/graphql/get_project_query.rb
index 04ac0916bbc..b3d7f3f4683 100644
--- a/lib/bulk_imports/projects/graphql/get_project_query.rb
+++ b/lib/bulk_imports/projects/graphql/get_project_query.rb
@@ -3,9 +3,8 @@
module BulkImports
module Projects
module Graphql
- module GetProjectQuery
- extend Queryable
- extend self
+ class GetProjectQuery
+ include Queryable
def to_s
<<-'GRAPHQL'
diff --git a/lib/bulk_imports/projects/graphql/get_repository_query.rb b/lib/bulk_imports/projects/graphql/get_repository_query.rb
index 24efce9e276..ca777c1a7e0 100644
--- a/lib/bulk_imports/projects/graphql/get_repository_query.rb
+++ b/lib/bulk_imports/projects/graphql/get_repository_query.rb
@@ -3,9 +3,8 @@
module BulkImports
module Projects
module Graphql
- module GetRepositoryQuery
- extend Queryable
- extend self
+ class GetRepositoryQuery
+ include Queryable
def to_s
<<-'GRAPHQL'
diff --git a/lib/bulk_imports/projects/graphql/get_snippet_repository_query.rb b/lib/bulk_imports/projects/graphql/get_snippet_repository_query.rb
index 1ba57789612..c105b04c731 100644
--- a/lib/bulk_imports/projects/graphql/get_snippet_repository_query.rb
+++ b/lib/bulk_imports/projects/graphql/get_snippet_repository_query.rb
@@ -3,9 +3,8 @@
module BulkImports
module Projects
module Graphql
- module GetSnippetRepositoryQuery
- extend Queryable
- extend self
+ class GetSnippetRepositoryQuery
+ include Queryable
def to_s
<<-'GRAPHQL'
@@ -27,7 +26,7 @@ module BulkImports
GRAPHQL
end
- def variables(context)
+ def variables
{
full_path: context.entity.source_full_path,
cursor: context.tracker.next_page,
diff --git a/lib/bulk_imports/projects/graphql/queryable.rb b/lib/bulk_imports/projects/graphql/queryable.rb
index a897632dff3..bd3116cb838 100644
--- a/lib/bulk_imports/projects/graphql/queryable.rb
+++ b/lib/bulk_imports/projects/graphql/queryable.rb
@@ -4,7 +4,13 @@ module BulkImports
module Projects
module Graphql
module Queryable
- def variables(context)
+ attr_reader :context
+
+ def initialize(context:)
+ @context = context
+ end
+
+ def variables
{ full_path: context.entity.source_full_path }
end
diff --git a/lib/bulk_imports/projects/stage.rb b/lib/bulk_imports/projects/stage.rb
index 0556395ca66..b55151855c9 100644
--- a/lib/bulk_imports/projects/stage.rb
+++ b/lib/bulk_imports/projects/stage.rb
@@ -19,6 +19,10 @@ module BulkImports
pipeline: BulkImports::Projects::Pipelines::ProjectAttributesPipeline,
stage: 1
},
+ members: {
+ pipeline: BulkImports::Common::Pipelines::MembersPipeline,
+ stage: 1
+ },
labels: {
pipeline: BulkImports::Common::Pipelines::LabelsPipeline,
stage: 2
diff --git a/lib/gitlab/ci/build/artifacts/expire_in_parser.rb b/lib/gitlab/ci/build/artifacts/expire_in_parser.rb
index 3e8a1fb86fc..848208c5cdd 100644
--- a/lib/gitlab/ci/build/artifacts/expire_in_parser.rb
+++ b/lib/gitlab/ci/build/artifacts/expire_in_parser.rb
@@ -16,9 +16,7 @@ module Gitlab
def validate_duration
return true if never?
- parse
- rescue ChronicDuration::DurationParseError
- false
+ cached_parse
end
def seconds_from_now
@@ -29,12 +27,28 @@ module Gitlab
attr_reader :value
+ def cached_parse
+ return validation_cache[value] if validation_cache.key?(value)
+
+ validation_cache[value] = safe_parse
+ end
+
+ def safe_parse
+ parse
+ rescue ChronicDuration::DurationParseError
+ false
+ end
+
def parse
return if never?
ChronicDuration.parse(value)
end
+ def validation_cache
+ Gitlab::SafeRequestStore[:ci_expire_in_parser_cache] ||= {}
+ end
+
def never?
value.to_s.casecmp('never') == 0
end
diff --git a/lib/gitlab/ci/runner_instructions/templates/linux/install.sh b/lib/gitlab/ci/runner_instructions/templates/linux/install.sh
index 2c55144e82d..a8ba2592128 100644
--- a/lib/gitlab/ci/runner_instructions/templates/linux/install.sh
+++ b/lib/gitlab/ci/runner_instructions/templates/linux/install.sh
@@ -4,7 +4,7 @@ sudo curl -L --output /usr/local/bin/gitlab-runner ${GITLAB_CI_RUNNER_DOWNLOAD_L
# Give it permission to execute
sudo chmod +x /usr/local/bin/gitlab-runner
-# Create a GitLab user
+# Create a GitLab Runner user
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
# Install and run as a service
diff --git a/lib/gitlab/process_memory_cache/helper.rb b/lib/gitlab/process_memory_cache/helper.rb
deleted file mode 100644
index ee4b81a9a19..00000000000
--- a/lib/gitlab/process_memory_cache/helper.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- class ProcessMemoryCache
- module Helper
- def fetch_memory_cache(key, &payload)
- cache = cache_backend.read(key)
-
- if cache && !stale_cache?(key, cache)
- cache[:data]
- else
- store_cache(key, &payload)
- end
- end
-
- def invalidate_memory_cache(key)
- touch_cache_timestamp(key)
- end
-
- private
-
- def touch_cache_timestamp(key, time = Time.current.to_f)
- shared_backend.write(key, time)
- end
-
- def stale_cache?(key, cache_info)
- shared_timestamp = shared_backend.read(key)
- return true unless shared_timestamp
-
- shared_timestamp.to_f > cache_info[:cached_at].to_f
- end
-
- def store_cache(key)
- data = yield
- time = Time.current.to_f
-
- cache_backend.write(key, data: data, cached_at: time)
- touch_cache_timestamp(key, time)
- data
- end
-
- def shared_backend
- Rails.cache
- end
-
- def cache_backend
- ::Gitlab::ProcessMemoryCache.cache_backend
- end
- end
- end
-end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 14d75dbeff1..fa8754e8328 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3659,9 +3659,6 @@ msgstr ""
msgid "An error in reporting in which a test result incorrectly indicates the presence of a vulnerability in a system when the vulnerability is not present."
msgstr ""
-msgid "An error occured while fetching the pipelines jobs."
-msgstr ""
-
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -3809,6 +3806,9 @@ msgstr ""
msgid "An error occurred while fetching the latest pipeline."
msgstr ""
+msgid "An error occurred while fetching the pipelines jobs."
+msgstr ""
+
msgid "An error occurred while fetching the releases. Please try again."
msgstr ""
@@ -19358,7 +19358,7 @@ msgstr ""
msgid "Internal URL (optional)"
msgstr ""
-msgid "Internal error occured while delivering this webhook."
+msgid "Internal error occurred while delivering this webhook."
msgstr ""
msgid "Internal users"
@@ -29068,7 +29068,7 @@ msgstr ""
msgid "Purchase more storage"
msgstr ""
-msgid "PurchaseStep|An error occured in the purchase step. If the problem persists please contact support@gitlab.com."
+msgid "PurchaseStep|An error occurred in the purchase step. If the problem persists please contact support@gitlab.com."
msgstr ""
msgid "Push"
diff --git a/spec/finders/autocomplete/users_finder_spec.rb b/spec/finders/autocomplete/users_finder_spec.rb
index 28bd7e12916..df7a14d440e 100644
--- a/spec/finders/autocomplete/users_finder_spec.rb
+++ b/spec/finders/autocomplete/users_finder_spec.rb
@@ -3,6 +3,9 @@
require 'spec_helper'
RSpec.describe Autocomplete::UsersFinder do
+ # TODO update when multiple owners are possible in projects
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/21432
+
describe '#execute' do
let!(:user1) { create(:user, username: 'johndoe') }
let!(:user2) { create(:user, :blocked, username: 'notsorandom') }
@@ -25,19 +28,19 @@ RSpec.describe Autocomplete::UsersFinder do
context 'when project passed' do
let(:project) { create(:project) }
- it { is_expected.to match_array([project.owner]) }
+ it { is_expected.to match_array([project.first_owner]) }
context 'when author_id passed' do
context 'and author is active' do
let(:params) { { author_id: user1.id } }
- it { is_expected.to match_array([project.owner, user1]) }
+ it { is_expected.to match_array([project.first_owner, user1]) }
end
context 'and author is blocked' do
let(:params) { { author_id: user2.id } }
- it { is_expected.to match_array([project.owner]) }
+ it { is_expected.to match_array([project.first_owner]) }
end
end
end
diff --git a/spec/finders/ci/daily_build_group_report_results_finder_spec.rb b/spec/finders/ci/daily_build_group_report_results_finder_spec.rb
index cf15a00323b..5352cfe5238 100644
--- a/spec/finders/ci/daily_build_group_report_results_finder_spec.rb
+++ b/spec/finders/ci/daily_build_group_report_results_finder_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Ci::DailyBuildGroupReportResultsFinder do
describe '#execute' do
let_it_be(:project) { create(:project, :private) }
let(:user_without_permission) { create(:user) }
- let_it_be(:user_with_permission) { project.owner }
+ let_it_be(:user_with_permission) { project.first_owner }
let_it_be(:ref_path) { 'refs/heads/master' }
let(:limit) { nil }
let_it_be(:default_branch) { false }
diff --git a/spec/finders/merge_request_target_project_finder_spec.rb b/spec/finders/merge_request_target_project_finder_spec.rb
index 08fbfd7229a..bf735152d99 100644
--- a/spec/finders/merge_request_target_project_finder_spec.rb
+++ b/spec/finders/merge_request_target_project_finder_spec.rb
@@ -65,8 +65,8 @@ RSpec.describe MergeRequestTargetProjectFinder do
context 'private projects' do
let(:base_project) { create(:project, :private, path: 'base') }
- let(:forked_project) { fork_project(base_project, base_project.owner) }
- let(:other_fork) { fork_project(base_project, base_project.owner) }
+ let(:forked_project) { fork_project(base_project, base_project.first_owner) }
+ let(:other_fork) { fork_project(base_project, base_project.first_owner) }
context 'when the user is a member of all projects' do
before do
diff --git a/spec/frontend/__helpers__/mock_apollo_helper.js b/spec/frontend/__helpers__/mock_apollo_helper.js
index ee4bbd42b1e..2dff9acbc76 100644
--- a/spec/frontend/__helpers__/mock_apollo_helper.js
+++ b/spec/frontend/__helpers__/mock_apollo_helper.js
@@ -16,7 +16,11 @@ export function createMockClient(handlers = [], resolvers = {}, cacheOptions = {
const mockClient = createMockApolloClient({ cache, resolvers });
if (Array.isArray(handlers)) {
- handlers.forEach(([query, value]) => mockClient.setRequestHandler(query, value));
+ handlers.forEach(([query, value]) =>
+ mockClient.setRequestHandler(query, (...args) =>
+ Promise.resolve(value(...args)).then((r) => ({ ...r })),
+ ),
+ );
} else {
throw new Error('You should pass an array of handlers to mock Apollo client');
}
diff --git a/spec/frontend/admin/users/components/users_table_spec.js b/spec/frontend/admin/users/components/users_table_spec.js
index 9ff5961c7ec..dffe8d6893b 100644
--- a/spec/frontend/admin/users/components/users_table_spec.js
+++ b/spec/frontend/admin/users/components/users_table_spec.js
@@ -3,6 +3,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import AdminUserActions from '~/admin/users/components/user_actions.vue';
@@ -106,8 +107,9 @@ describe('AdminUsersTable component', () => {
});
describe('when the data has been fetched', () => {
- beforeEach(() => {
+ beforeEach(async () => {
initComponent();
+ await waitForPromises();
});
it("renders the user's group count", () => {
@@ -115,8 +117,9 @@ describe('AdminUsersTable component', () => {
});
describe("and a user's group count is null", () => {
- beforeEach(() => {
+ beforeEach(async () => {
initComponent({}, createFetchGroupCount([{ id: user.id, groupCount: null }]));
+ await waitForPromises();
});
it("renders the user's group count as 0", () => {
@@ -126,12 +129,13 @@ describe('AdminUsersTable component', () => {
});
describe('when there is an error while fetching the data', () => {
- beforeEach(() => {
+ beforeEach(async () => {
initComponent({}, fetchGroupCountsError);
+ await waitForPromises();
});
it('creates a flash message and captures the error', () => {
- expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledTimes(2);
expect(createFlash).toHaveBeenCalledWith({
message: 'Could not load user group counts. Please refresh the page to try again.',
captureError: true,
diff --git a/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js b/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
index e6a6e01c41c..12fc08c303c 100644
--- a/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
+++ b/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
@@ -1,7 +1,6 @@
import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
import { mount, createLocalVue } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import createHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql';
import updateHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql';
@@ -79,12 +78,6 @@ describe('AlertsSettingsWrapper', () => {
.vm.$emit('delete-integration', { id: integrationToDestroy.id });
}
- async function awaitApolloDomMock() {
- await nextTick(); // kick off the DOM update
- await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
- await nextTick(); // kick off the DOM update for flash
- }
-
const createComponent = ({ data = {}, provide = {}, loading = false } = {}) => {
wrapper = extendedWrapper(
mount(AlertsSettingsWrapper, {
@@ -476,9 +469,7 @@ describe('AlertsSettingsWrapper', () => {
describe('with mocked Apollo client', () => {
it('has a selection of integrations loaded via the getIntegrationsQuery', async () => {
createComponentWithApollo();
-
- await jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
expect(findIntegrations()).toHaveLength(4);
});
@@ -490,7 +481,7 @@ describe('AlertsSettingsWrapper', () => {
expect(destroyIntegrationHandler).toHaveBeenCalled();
- await nextTick();
+ await waitForPromises();
expect(findIntegrations()).toHaveLength(3);
});
@@ -501,7 +492,7 @@ describe('AlertsSettingsWrapper', () => {
});
await destroyHttpIntegration(wrapper);
- await awaitApolloDomMock();
+ await waitForPromises();
expect(createFlash).toHaveBeenCalledWith({ message: 'Houston, we have a problem' });
});
@@ -512,7 +503,7 @@ describe('AlertsSettingsWrapper', () => {
});
await destroyHttpIntegration(wrapper);
- await awaitApolloDomMock();
+ await waitForPromises();
expect(createFlash).toHaveBeenCalledWith({
message: DELETE_INTEGRATION_ERROR,
diff --git a/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js b/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js
index 1a331100bb8..f86f2eacf50 100644
--- a/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js
+++ b/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js
@@ -4,6 +4,7 @@ import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import UsageTrendsCountChart from '~/analytics/usage_trends/components/usage_trends_count_chart.vue';
import statsQuery from '~/analytics/usage_trends/graphql/queries/usage_count.query.graphql';
import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
@@ -77,9 +78,10 @@ describe('UsageTrendsCountChart', () => {
});
describe('without data', () => {
- beforeEach(() => {
+ beforeEach(async () => {
queryHandler = mockQueryResponse({ key: queryResponseDataKey, data: [] });
wrapper = createComponent({ responseHandler: queryHandler });
+ await waitForPromises();
});
it('renders an no data message', () => {
@@ -96,9 +98,10 @@ describe('UsageTrendsCountChart', () => {
});
describe('with data', () => {
- beforeEach(() => {
+ beforeEach(async () => {
queryHandler = mockQueryResponse({ key: queryResponseDataKey, data: mockCountsData1 });
wrapper = createComponent({ responseHandler: queryHandler });
+ await waitForPromises();
});
it('requests data', () => {
@@ -134,7 +137,7 @@ describe('UsageTrendsCountChart', () => {
});
wrapper = createComponent({ responseHandler: queryHandler });
- await wrapper.vm.$nextTick();
+ await waitForPromises();
});
it('requests data twice', () => {
diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js
index 1981ed5ab7f..e29c19d6e97 100644
--- a/spec/frontend/boards/board_list_spec.js
+++ b/spec/frontend/boards/board_list_spec.js
@@ -1,6 +1,7 @@
import Draggable from 'vuedraggable';
import { DraggableItemTypes } from 'ee_else_ce/boards/constants';
import { useFakeRequestAnimationFrame } from 'helpers/fake_request_animation_frame';
+import waitForPromises from 'helpers/wait_for_promises';
import createComponent from 'jest/boards/board_list_helper';
import BoardCard from '~/boards/components/board_card.vue';
import eventHub from '~/boards/eventhub';
@@ -132,7 +133,6 @@ describe('Board list component', () => {
});
it('shows how many more issues to load', async () => {
- // wrapper.vm.showCount = true;
wrapper = createComponent({
data: {
showCount: true,
@@ -140,6 +140,9 @@ describe('Board list component', () => {
});
await wrapper.vm.$nextTick();
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
+
expect(wrapper.find('.board-list-count').text()).toBe('Showing 1 of 20 issues');
});
});
diff --git a/spec/frontend/clusters/agents/components/activity_events_list_spec.js b/spec/frontend/clusters/agents/components/activity_events_list_spec.js
index 4abbd77dfb7..6b374b6620d 100644
--- a/spec/frontend/clusters/agents/components/activity_events_list_spec.js
+++ b/spec/frontend/clusters/agents/components/activity_events_list_spec.js
@@ -70,8 +70,9 @@ describe('ActivityEvents', () => {
});
describe('when there are no agentEvents', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createWrapper({ queryResponse: jest.fn().mockResolvedValue(mockEmptyResponse) });
+ await waitForPromises();
});
it('displays an empty state with the correct illustration', () => {
@@ -83,9 +84,11 @@ describe('ActivityEvents', () => {
describe('when the agentEvents are present', () => {
const length = mockResponse.data?.project?.clusterAgent?.activityEvents?.nodes?.length;
- beforeEach(() => {
+ beforeEach(async () => {
createWrapper();
+ await waitForPromises();
});
+
it('renders an activity-history-item components for every event', () => {
expect(findAllActivityHistoryItems()).toHaveLength(length);
});
diff --git a/spec/frontend/clusters/agents/components/show_spec.js b/spec/frontend/clusters/agents/components/show_spec.js
index 4b40f9e7223..c92bf634a92 100644
--- a/spec/frontend/clusters/agents/components/show_spec.js
+++ b/spec/frontend/clusters/agents/components/show_spec.js
@@ -82,8 +82,9 @@ describe('ClusterAgentShow', () => {
});
describe('default behaviour', () => {
- beforeEach(() => {
- return createWrapper({ clusterAgent: defaultClusterAgent });
+ beforeEach(async () => {
+ createWrapper({ clusterAgent: defaultClusterAgent });
+ await waitForPromises();
});
it('sends expected params', () => {
@@ -131,8 +132,9 @@ describe('ClusterAgentShow', () => {
createdByUser: null,
};
- beforeEach(() => {
- return createWrapper({ clusterAgent: missingUser });
+ beforeEach(async () => {
+ createWrapper({ clusterAgent: missingUser });
+ await waitForPromises();
});
it('displays agent create information with unknown user', () => {
@@ -146,8 +148,9 @@ describe('ClusterAgentShow', () => {
tokens: null,
};
- beforeEach(() => {
- return createWrapper({ clusterAgent: missingTokens });
+ beforeEach(async () => {
+ createWrapper({ clusterAgent: missingTokens });
+ await waitForPromises();
});
it('displays token header with no count', () => {
@@ -171,8 +174,9 @@ describe('ClusterAgentShow', () => {
},
};
- beforeEach(() => {
- return createWrapper({ clusterAgent: tokenPagination });
+ beforeEach(async () => {
+ createWrapper({ clusterAgent: tokenPagination });
+ await waitForPromises();
});
it('should render pagination buttons', () => {
diff --git a/spec/frontend/clusters_list/components/agent_options_spec.js b/spec/frontend/clusters_list/components/agent_options_spec.js
index 05bab247816..f20a7b39a97 100644
--- a/spec/frontend/clusters_list/components/agent_options_spec.js
+++ b/spec/frontend/clusters_list/components/agent_options_spec.js
@@ -6,6 +6,7 @@ import { ENTER_KEY } from '~/lib/utils/keys';
import getAgentsQuery from '~/clusters_list/graphql/queries/get_agents.query.graphql';
import deleteAgentMutation from '~/clusters_list/graphql/mutations/delete_agent.mutation.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import AgentOptions from '~/clusters_list/components/agent_options.vue';
import { MAX_LIST_COUNT } from '~/clusters_list/constants';
import { getAgentResponse, mockDeleteResponse, mockErrorDeleteResponse } from '../mocks/apollo';
@@ -83,6 +84,7 @@ describe('AgentOptions', () => {
findDeleteBtn().vm.$emit('click');
findInput().vm.$emit('input', agent.name);
await findModal().vm.$emit('primary');
+ await waitForPromises();
};
beforeEach(() => {
@@ -173,8 +175,7 @@ describe('AgentOptions', () => {
describe('when getting an error deleting agent', () => {
beforeEach(async () => {
await createWrapper({ mutationResponse: mockErrorDeleteResponse });
-
- submitAgentToDelete();
+ await submitAgentToDelete();
});
it('displays the error message', () => {
@@ -187,7 +188,7 @@ describe('AgentOptions', () => {
const loadingResponse = new Promise(() => {});
await createWrapper({ mutationResponse: loadingResponse });
- submitAgentToDelete();
+ await submitAgentToDelete();
});
it('reenables the options dropdown', async () => {
diff --git a/spec/frontend/clusters_list/components/install_agent_modal_spec.js b/spec/frontend/clusters_list/components/install_agent_modal_spec.js
index 4d1429c9e50..5edc504aecb 100644
--- a/spec/frontend/clusters_list/components/install_agent_modal_spec.js
+++ b/spec/frontend/clusters_list/components/install_agent_modal_spec.js
@@ -1,6 +1,7 @@
-import { GlAlert, GlButton, GlFormInputGroup } from '@gitlab/ui';
+import { GlAlert, GlButton, GlFormInputGroup, GlSprintf } from '@gitlab/ui';
import { createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
+import { sprintf } from '~/locale';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { mockTracking } from 'helpers/tracking_helper';
import AvailableAgentsDropdown from '~/clusters_list/components/available_agents_dropdown.vue';
@@ -27,6 +28,7 @@ import {
createAgentTokenResponse,
createAgentTokenErrorResponse,
getAgentResponse,
+ kasDisabledErrorResponse,
} from '../mocks/apollo';
import ModalStub from '../stubs';
@@ -35,7 +37,6 @@ localVue.use(VueApollo);
const projectPath = 'path/to/project';
const kasAddress = 'kas.example.com';
-const kasEnabled = true;
const emptyStateImage = 'path/to/image';
const defaultBranchName = 'default';
const maxAgents = MAX_LIST_COUNT;
@@ -80,7 +81,6 @@ describe('InstallAgentModal', () => {
const provide = {
projectPath,
kasAddress,
- kasEnabled,
emptyStateImage,
};
@@ -92,6 +92,7 @@ describe('InstallAgentModal', () => {
wrapper = shallowMountExtended(InstallAgentModal, {
attachTo: document.body,
stubs: {
+ GlSprintf,
GlModal: ModalStub,
},
localVue,
@@ -118,7 +119,7 @@ describe('InstallAgentModal', () => {
createWrapper();
writeQuery();
- await wrapper.vm.$nextTick();
+ await waitForPromises();
wrapper.vm.setAgentName('agent-name');
findActionButton().vm.$emit('click');
@@ -126,11 +127,12 @@ describe('InstallAgentModal', () => {
return waitForPromises();
};
- beforeEach(() => {
+ beforeEach(async () => {
apolloProvider = createMockApollo([
[getAgentConfigurations, jest.fn().mockResolvedValue(apolloQueryResponse)],
]);
createWrapper();
+ await waitForPromises();
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
});
@@ -306,4 +308,34 @@ describe('InstallAgentModal', () => {
});
});
});
+
+ describe('when KAS is disabled', () => {
+ const i18n = I18N_AGENT_MODAL.empty_state;
+ beforeEach(() => {
+ apolloProvider = createMockApollo([
+ [getAgentConfigurations, jest.fn().mockResolvedValue(kasDisabledErrorResponse)],
+ ]);
+
+ return mockSelectedAgentResponse();
+ });
+
+ it('renders empty state image', () => {
+ expect(findImage().attributes('src')).toBe(emptyStateImage);
+ });
+
+ it('renders an instruction to enable the KAS', () => {
+ expect(findModal().text()).toContain(
+ sprintf(i18n.enableKasText, { linkStart: '', linkEnd: '' }),
+ );
+ });
+
+ it('renders a cancel button', () => {
+ expect(findActionButton().isVisible()).toBe(true);
+ expect(findActionButton().text()).toBe(i18n.done);
+ });
+
+ it("doesn't render a secondary button", () => {
+ expect(findSecondaryButton().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/clusters_list/mocks/apollo.js b/spec/frontend/clusters_list/mocks/apollo.js
index c4a31ed4394..4e863e1c1e9 100644
--- a/spec/frontend/clusters_list/mocks/apollo.js
+++ b/spec/frontend/clusters_list/mocks/apollo.js
@@ -76,6 +76,11 @@ export const getAgentResponse = {
},
};
+export const kasDisabledErrorResponse = {
+ data: {},
+ errors: [{ message: 'Gitlab::Kas::Client::ConfigurationError' }],
+};
+
export const mockDeleteResponse = {
data: { clusterAgentDelete: { errors: [] } },
};
diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js
index dd0f7972553..ce74569f219 100644
--- a/spec/frontend/design_management/pages/index_spec.js
+++ b/spec/frontend/design_management/pages/index_spec.js
@@ -5,6 +5,7 @@ import VueApollo, { ApolloMutation } from 'vue-apollo';
import VueRouter from 'vue-router';
import VueDraggable from 'vuedraggable';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import permissionsQuery from 'shared_queries/design_management/design_permissions.query.graphql';
import getDesignListQuery from 'shared_queries/design_management/get_design_list.query.graphql';
@@ -115,8 +116,7 @@ describe('Design management index page', () => {
const findDesignToolbarWrapper = () => wrapper.find('[data-testid="design-toolbar-wrapper"]');
async function moveDesigns(localWrapper) {
- await jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
localWrapper.find(VueDraggable).vm.$emit('input', reorderedDesigns);
localWrapper.find(VueDraggable).vm.$emit('change', {
@@ -746,9 +746,7 @@ describe('Design management index page', () => {
describe('with mocked Apollo client', () => {
it('has a design with id 1 as a first one', async () => {
createComponentWithApollo({});
-
- await jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
expect(findDesigns()).toHaveLength(3);
expect(findDesigns().at(0).props('id')).toBe('1');
@@ -773,9 +771,7 @@ describe('Design management index page', () => {
expect(draggableAttributes().disabled).toBe(true);
- await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
- await nextTick(); // kick off the DOM update
- await nextTick(); // kick off the DOM update for finally block
+ await waitForPromises();
expect(draggableAttributes().disabled).toBe(false);
});
@@ -787,7 +783,7 @@ describe('Design management index page', () => {
await moveDesigns(wrapper);
- await nextTick();
+ await waitForPromises();
expect(createFlash).toHaveBeenCalledWith({ message: 'Houston, we have a problem' });
});
@@ -799,9 +795,7 @@ describe('Design management index page', () => {
await moveDesigns(wrapper);
- await nextTick(); // kick off the DOM update
- await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
- await nextTick(); // kick off the DOM update for flash
+ await waitForPromises();
expect(createFlash).toHaveBeenCalledWith({
message: 'Something went wrong when reordering designs. Please try again',
diff --git a/spec/frontend/issues/list/components/issues_list_app_spec.js b/spec/frontend/issues/list/components/issues_list_app_spec.js
index 66428ee0492..7730c69641e 100644
--- a/spec/frontend/issues/list/components/issues_list_app_spec.js
+++ b/spec/frontend/issues/list/components/issues_list_app_spec.js
@@ -131,9 +131,10 @@ describe('CE IssuesListApp component', () => {
});
describe('IssuableList', () => {
- beforeEach(() => {
+ beforeEach(async () => {
wrapper = mountComponent();
jest.runOnlyPendingTimers();
+ await waitForPromises();
});
it('renders', () => {
@@ -167,8 +168,9 @@ describe('CE IssuesListApp component', () => {
});
describe('header action buttons', () => {
- it('renders rss button', () => {
+ it('renders rss button', async () => {
wrapper = mountComponent({ mountFn: mount });
+ await waitForPromises();
expect(findGlButtonAt(0).props('icon')).toBe('rss');
expect(findGlButtonAt(0).attributes()).toMatchObject({
@@ -177,8 +179,9 @@ describe('CE IssuesListApp component', () => {
});
});
- it('renders calendar button', () => {
+ it('renders calendar button', async () => {
wrapper = mountComponent({ mountFn: mount });
+ await waitForPromises();
expect(findGlButtonAt(1).props('icon')).toBe('calendar');
expect(findGlButtonAt(1).attributes()).toMatchObject({
@@ -191,12 +194,13 @@ describe('CE IssuesListApp component', () => {
describe('when user is signed in', () => {
const search = '?search=refactor&sort=created_date&state=opened';
- beforeEach(() => {
+ beforeEach(async () => {
setWindowLocation(search);
wrapper = mountComponent({ provide: { isSignedIn: true }, mountFn: mount });
jest.runOnlyPendingTimers();
+ await waitForPromises();
});
it('renders', () => {
@@ -585,11 +589,12 @@ describe('CE IssuesListApp component', () => {
${'fetching issues'} | ${'issuesQueryResponse'} | ${IssuesListApp.i18n.errorFetchingIssues}
${'fetching issue counts'} | ${'issuesCountsQueryResponse'} | ${IssuesListApp.i18n.errorFetchingCounts}
`('when there is an error $error', ({ mountOption, message }) => {
- beforeEach(() => {
+ beforeEach(async () => {
wrapper = mountComponent({
[mountOption]: jest.fn().mockRejectedValue(new Error('ERROR')),
});
jest.runOnlyPendingTimers();
+ await waitForPromises();
});
it('shows an error message', () => {
diff --git a/spec/frontend/issues/list/components/new_issue_dropdown_spec.js b/spec/frontend/issues/list/components/new_issue_dropdown_spec.js
index 0c52e66ff14..7bec3d13d44 100644
--- a/spec/frontend/issues/list/components/new_issue_dropdown_spec.js
+++ b/spec/frontend/issues/list/components/new_issue_dropdown_spec.js
@@ -2,9 +2,11 @@ import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import NewIssueDropdown from '~/issues/list/components/new_issue_dropdown.vue';
import searchProjectsQuery from '~/issues/list/queries/search_projects.query.graphql';
import { DASH_SCOPE, joinPaths } from '~/lib/utils/url_utility';
+import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
import {
emptySearchProjectsQueryResponse,
project1,
@@ -42,8 +44,9 @@ describe('NewIssueDropdown component', () => {
const findInput = () => wrapper.findComponent(GlSearchBoxByType);
const showDropdown = async () => {
findDropdown().vm.$emit('shown');
- await wrapper.vm.$apollo.queries.projects.refetch();
- jest.runOnlyPendingTimers();
+ await waitForPromises();
+ jest.advanceTimersByTime(DEBOUNCE_DELAY);
+ await waitForPromises();
};
afterEach(() => {
@@ -74,7 +77,6 @@ describe('NewIssueDropdown component', () => {
it('renders projects with issues enabled', async () => {
wrapper = mountComponent({ mountFn: mount });
-
await showDropdown();
const listItems = wrapper.findAll('li');
@@ -112,10 +114,11 @@ describe('NewIssueDropdown component', () => {
describe('when a project is selected', () => {
beforeEach(async () => {
wrapper = mountComponent({ mountFn: mount });
-
+ await waitForPromises();
await showDropdown();
wrapper.findComponent(GlDropdownItem).vm.$emit('click', project1);
+ await waitForPromises();
});
it('dropdown button is a link', () => {
diff --git a/spec/frontend/jobs/bridge/app_spec.js b/spec/frontend/jobs/bridge/app_spec.js
index c0faab90552..cd7c2fd5322 100644
--- a/spec/frontend/jobs/bridge/app_spec.js
+++ b/spec/frontend/jobs/bridge/app_spec.js
@@ -81,10 +81,10 @@ describe('Bridge Show Page', () => {
});
describe('after pipeline query is loaded', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockPipelineQuery.mockResolvedValue(mockPipelineQueryResponse);
createComponentWithApollo();
- waitForPromises();
+ await waitForPromises();
});
it('query is called with correct variables', async () => {
@@ -109,10 +109,10 @@ describe('Bridge Show Page', () => {
});
describe('sidebar expansion', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockPipelineQuery.mockResolvedValue(mockPipelineQueryResponse);
createComponentWithApollo();
- waitForPromises();
+ await waitForPromises();
});
describe('on resize', () => {
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 05988eecb10..389bcf670c9 100644
--- a/spec/frontend/jobs/components/table/job_table_app_spec.js
+++ b/spec/frontend/jobs/components/table/job_table_app_spec.js
@@ -112,7 +112,7 @@ describe('Job table app', () => {
},
});
- await wrapper.vm.$nextTick();
+ await waitForPromises();
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
@@ -150,7 +150,7 @@ describe('Job table app', () => {
},
});
- await wrapper.vm.$nextTick();
+ await waitForPromises();
expect(findPrevious().exists()).toBe(true);
expect(findPrevious().classes('disabled')).toBe(true);
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js
index 917d0fccf3f..7d9f89518d5 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js
@@ -108,6 +108,7 @@ describe('Tags List', () => {
describe('events', () => {
it('prev-page fetch the previous page', async () => {
findRegistryList().vm.$emit('prev-page');
+ await waitForPromises();
expect(resolver).toHaveBeenCalledWith({
first: null,
@@ -119,8 +120,9 @@ describe('Tags List', () => {
});
});
- it('next-page fetch the previous page', () => {
+ it('next-page fetch the previous page', async () => {
findRegistryList().vm.$emit('next-page');
+ await waitForPromises();
expect(resolver).toHaveBeenCalledWith({
after: tagsPageInfo.endCursor,
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js
index 9e9d61a1241..1f8cda55f39 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js
@@ -522,7 +522,7 @@ describe('Details Page', () => {
findDeleteImage().vm.$emit('start');
- await nextTick();
+ await waitForPromises();
expect(findTagsLoader().exists()).toBe(true);
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
index ec00e7f9319..c4984d1b6ae 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
@@ -361,7 +361,7 @@ describe('List Page', () => {
findRegistrySearch().vm.$emit('filter:submit');
- await nextTick();
+ await waitForPromises();
};
it('has a search box element', async () => {
@@ -429,7 +429,7 @@ describe('List Page', () => {
await waitForApolloRequestRender();
findImageList().vm.$emit('prev-page');
- await nextTick();
+ await waitForPromises();
expect(resolver).toHaveBeenCalledWith(
expect.objectContaining({ before: pageInfo.startCursor }),
@@ -449,7 +449,7 @@ describe('List Page', () => {
await waitForApolloRequestRender();
findImageList().vm.$emit('next-page');
- await nextTick();
+ await waitForPromises();
expect(resolver).toHaveBeenCalledWith(
expect.objectContaining({ after: pageInfo.endCursor }),
@@ -471,8 +471,9 @@ describe('List Page', () => {
});
it('contains a description with the path of the item to delete', async () => {
+ await waitForPromises();
findImageList().vm.$emit('delete', { path: 'foo' });
- await nextTick();
+ await waitForPromises();
expect(findDeleteModal().html()).toContain('foo');
});
});
diff --git a/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js b/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
index 44a7186904d..842b63ac0d5 100644
--- a/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
+++ b/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
@@ -195,8 +195,9 @@ describe('DependencyProxyApp', () => {
});
});
- it('prev-page event on list fetches the previous page', () => {
+ it('prev-page event on list fetches the previous page', async () => {
findManifestList().vm.$emit('prev-page');
+ await waitForPromises();
expect(resolver).toHaveBeenCalledWith({
before: pagination().startCursor,
@@ -206,8 +207,9 @@ describe('DependencyProxyApp', () => {
});
});
- it('next-page event on list fetches the next page', () => {
+ it('next-page event on list fetches the next page', async () => {
findManifestList().vm.$emit('next-page');
+ await waitForPromises();
expect(resolver).toHaveBeenCalledWith({
after: pagination().endCursor,
diff --git a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
index 2ac2a6455ef..8121d9c7dbd 100644
--- a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
@@ -85,7 +85,7 @@ describe('PackagesListApp', () => {
wrapper.destroy();
});
- const waitForFirstRequest = () => {
+ const waitForFirstRequest = async () => {
// emit a search update so the query is executed
findSearch().vm.$emit('update', { sort: 'NAME_DESC', filters: [] });
return waitForPromises();
@@ -149,11 +149,10 @@ describe('PackagesListApp', () => {
beforeEach(() => {
resolver = jest.fn().mockResolvedValue(packagesListQuery());
mountComponent({ resolver });
-
- return waitForFirstRequest();
});
- it('exists and has the right props', () => {
+ it('exists and has the right props', async () => {
+ await waitForFirstRequest();
expect(findListComponent().props()).toMatchObject({
list: expect.arrayContaining([expect.objectContaining({ id: packageData().id })]),
isLoading: false,
@@ -161,16 +160,20 @@ describe('PackagesListApp', () => {
});
});
- it('when list emits next-page fetches the next set of records', () => {
+ it('when list emits next-page fetches the next set of records', async () => {
+ await waitForFirstRequest();
findListComponent().vm.$emit('next-page');
+ await waitForPromises();
expect(resolver).toHaveBeenCalledWith(
expect.objectContaining({ after: pagination().endCursor, first: GRAPHQL_PAGE_SIZE }),
);
});
- it('when list emits prev-page fetches the prev set of records', () => {
+ it('when list emits prev-page fetches the prev set of records', async () => {
+ await waitForFirstRequest();
findListComponent().vm.$emit('prev-page');
+ await waitForPromises();
expect(resolver).toHaveBeenCalledWith(
expect.objectContaining({ before: pagination().startCursor, last: GRAPHQL_PAGE_SIZE }),
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js
index 8266f9bee89..cad5d4db033 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js
@@ -2,6 +2,7 @@ import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import component from '~/packages_and_registries/settings/project/components/registry_settings_app.vue';
import SettingsForm from '~/packages_and_registries/settings/project/components/settings_form.vue';
import {
@@ -64,8 +65,6 @@ describe('Registry Settings App', () => {
localVue,
apolloProvider: fakeApollo,
});
-
- return requestHandlers.map((request) => request[1]);
};
afterEach(() => {
@@ -101,25 +100,25 @@ describe('Registry Settings App', () => {
${'response and changes'} | ${expirationPolicyPayload()} | ${{ ...containerExpirationPolicyData(), nameRegex: '12345' }} | ${true}
${'response and empty'} | ${expirationPolicyPayload()} | ${{}} | ${true}
`('$description', async ({ apiResponse, workingCopy, result }) => {
- const requests = mountComponentWithApollo({
+ mountComponentWithApollo({
provide: { ...defaultProvidedValues, enableHistoricEntries: true },
resolver: jest.fn().mockResolvedValue(apiResponse),
});
- await Promise.all(requests);
+ await waitForPromises();
findSettingsComponent().vm.$emit('input', workingCopy);
- await wrapper.vm.$nextTick();
+ await waitForPromises();
expect(findSettingsComponent().props('isEdited')).toBe(result);
});
});
it('renders the setting form', async () => {
- const requests = mountComponentWithApollo({
+ mountComponentWithApollo({
resolver: jest.fn().mockResolvedValue(expirationPolicyPayload()),
});
- await Promise.all(requests);
+ await waitForPromises();
expect(findSettingsComponent().exists()).toBe(true);
});
@@ -153,11 +152,11 @@ describe('Registry Settings App', () => {
});
describe('fetchSettingsError', () => {
- beforeEach(() => {
- const requests = mountComponentWithApollo({
+ beforeEach(async () => {
+ mountComponentWithApollo({
resolver: jest.fn().mockRejectedValue(new Error('GraphQL error')),
});
- return Promise.all(requests);
+ await waitForPromises();
});
it('the form is hidden', () => {
@@ -175,14 +174,14 @@ describe('Registry Settings App', () => {
${true} | ${true}
${false} | ${false}
`('is $isShown that the form is shown', async ({ enableHistoricEntries, isShown }) => {
- const requests = mountComponentWithApollo({
+ mountComponentWithApollo({
provide: {
...defaultProvidedValues,
enableHistoricEntries,
},
resolver: jest.fn().mockResolvedValue(emptyExpirationPolicyPayload()),
});
- await Promise.all(requests);
+ await waitForPromises();
expect(findSettingsComponent().exists()).toBe(isShown);
});
diff --git a/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js b/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js
index c101b1d21c7..d813d67b94b 100644
--- a/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js
+++ b/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js
@@ -70,13 +70,13 @@ describe('Pipeline Status', () => {
describe('when querying data', () => {
describe('when data is set', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockPipelineQuery.mockResolvedValue({
data: { project: mockProjectPipeline() },
});
createComponentWithApollo();
- waitForPromises();
+ await waitForPromises();
});
it('query is called with correct variables', async () => {
diff --git a/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js b/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js
index 6b9f576917f..2f26b4d145c 100644
--- a/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js
+++ b/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js
@@ -1,6 +1,7 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
@@ -89,13 +90,14 @@ describe('Pipeline Status', () => {
});
describe('when query fails', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockLinkedPipelinesQuery.mockRejectedValue(new Error());
createComponentWithApollo();
+ await waitForPromises();
});
it('should emit an error event when query fails', async () => {
- expect(wrapper.emitted('showError')).toHaveLength(1);
+ expect(wrapper.emitted('showError')).toHaveLength(2);
expect(wrapper.emitted('showError')[0]).toEqual([
{
type: PIPELINE_FAILURE,
diff --git a/spec/frontend/pipelines/components/jobs/jobs_app_spec.js b/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
index 1ea6096c922..547c0cdda5e 100644
--- a/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
+++ b/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
@@ -74,16 +74,16 @@ describe('Jobs app', () => {
await waitForPromises();
expect(createFlash).toHaveBeenCalledWith({
- message: 'An error occured while fetching the pipelines jobs.',
+ message: 'An error occurred while fetching the pipelines jobs.',
});
});
it('handles infinite scrolling by calling fetchMore', async () => {
createComponent(resolverSpy);
-
await waitForPromises();
triggerInfiniteScroll();
+ await waitForPromises();
expect(resolverSpy).toHaveBeenCalledWith({
after: 'eyJpZCI6Ijg0NyJ9',
@@ -96,10 +96,10 @@ describe('Jobs app', () => {
createComponent(resolverSpy);
expect(findSkeletonLoader().exists()).toBe(true);
-
await waitForPromises();
triggerInfiniteScroll();
+ await waitForPromises();
expect(findSkeletonLoader().exists()).toBe(false);
});
diff --git a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
index 04e004dc6c1..8bc6c086b9d 100644
--- a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
@@ -1,10 +1,11 @@
import { GlAlert, GlButton, GlButtonGroup, GlLoadingIcon } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
-import Vue, { nextTick } from 'vue';
+import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
import getUserCallouts from '~/graphql_shared/queries/get_user_callouts.query.graphql';
import axios from '~/lib/utils/axios_utils';
@@ -100,15 +101,6 @@ describe('Pipeline graph wrapper', () => {
wrapper.destroy();
});
- beforeAll(() => {
- jest.useFakeTimers();
- });
-
- afterAll(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
- });
-
describe('when data is loading', () => {
it('displays the loading icon', () => {
createComponentWithApollo();
@@ -134,8 +126,7 @@ describe('Pipeline graph wrapper', () => {
describe('when data has loaded', () => {
beforeEach(async () => {
createComponentWithApollo();
- jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('does not display the loading icon', () => {
@@ -163,8 +154,7 @@ describe('Pipeline graph wrapper', () => {
createComponentWithApollo({
getPipelineDetailsHandler: jest.fn().mockRejectedValue(new Error('GraphQL error')),
});
- jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('does not display the loading icon', () => {
@@ -187,8 +177,7 @@ describe('Pipeline graph wrapper', () => {
pipelineIid: '',
},
});
- jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('does not display the loading icon', () => {
@@ -210,7 +199,7 @@ describe('Pipeline graph wrapper', () => {
createComponentWithApollo();
jest.spyOn(wrapper.vm.$apollo.queries.headerPipeline, 'refetch');
jest.spyOn(wrapper.vm.$apollo.queries.pipeline, 'refetch');
- await nextTick();
+ await waitForPromises();
getGraph().vm.$emit('refreshPipelineGraph');
});
@@ -224,8 +213,7 @@ describe('Pipeline graph wrapper', () => {
describe('when query times out', () => {
const advanceApolloTimers = async () => {
jest.runOnlyPendingTimers();
- await nextTick();
- await nextTick();
+ await waitForPromises();
};
beforeEach(async () => {
@@ -245,7 +233,7 @@ describe('Pipeline graph wrapper', () => {
.mockResolvedValueOnce(errorData);
createComponentWithApollo({ getPipelineDetailsHandler: failSucceedFail });
- await nextTick();
+ await waitForPromises();
});
it('shows correct errors and does not overwrite populated data when data is empty', async () => {
@@ -274,8 +262,7 @@ describe('Pipeline graph wrapper', () => {
mountFn: mount,
});
- jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('appears when pipeline uses needs', () => {
@@ -318,7 +305,7 @@ describe('Pipeline graph wrapper', () => {
});
jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('sets showLinks to true', async () => {
@@ -327,8 +314,9 @@ describe('Pipeline graph wrapper', () => {
expect(getLinksLayer().props('showLinks')).toBe(false);
expect(getViewSelector().props('type')).toBe(LAYER_VIEW);
await getDependenciesToggle().vm.$emit('change', true);
+
jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
expect(wrapper.findComponent(LinksLayer).props('showLinks')).toBe(true);
});
});
@@ -343,8 +331,7 @@ describe('Pipeline graph wrapper', () => {
mountFn: mount,
});
- jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('shows the hover tip in the view selector', async () => {
@@ -365,7 +352,7 @@ describe('Pipeline graph wrapper', () => {
});
jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('does not show the hover tip', async () => {
@@ -382,8 +369,7 @@ describe('Pipeline graph wrapper', () => {
mountFn: mount,
});
- jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
afterEach(() => {
@@ -411,8 +397,7 @@ describe('Pipeline graph wrapper', () => {
getPipelineDetailsHandler: jest.fn().mockResolvedValue(nonNeedsResponse),
});
- jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
afterEach(() => {
@@ -435,7 +420,7 @@ describe('Pipeline graph wrapper', () => {
});
jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('does not appear when pipeline does not use needs', () => {
@@ -461,8 +446,7 @@ describe('Pipeline graph wrapper', () => {
describe('with no metrics path', () => {
beforeEach(async () => {
createComponentWithApollo();
- jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('is not called', () => {
@@ -505,8 +489,7 @@ describe('Pipeline graph wrapper', () => {
},
});
- jest.runOnlyPendingTimers();
- await nextTick();
+ await waitForPromises();
});
it('attempts to collect metrics', () => {
@@ -517,7 +500,7 @@ describe('Pipeline graph wrapper', () => {
});
describe('with duration and no error', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mock = new MockAdapter(axios);
mock.onPost(metricsPath).reply(200, {});
@@ -536,6 +519,7 @@ describe('Pipeline graph wrapper', () => {
currentViewType: LAYER_VIEW,
},
});
+ await waitForPromises();
});
afterEach(() => {
diff --git a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
index 2f03b846525..5897da4b8c2 100644
--- a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
@@ -1,6 +1,7 @@
import { mount, shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
import {
DOWNSTREAM,
@@ -87,13 +88,12 @@ describe('Linked Pipelines Column', () => {
describe('click action', () => {
const clickExpandButton = async () => {
await findExpandButton().trigger('click');
- await wrapper.vm.$nextTick();
+ await waitForPromises();
};
const clickExpandButtonAndAwaitTimers = async () => {
await clickExpandButton();
jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
};
describe('layer type rendering', () => {
@@ -162,7 +162,10 @@ describe('Linked Pipelines Column', () => {
it('emits the error', async () => {
await clickExpandButton();
- expect(wrapper.emitted().error).toEqual([[{ type: LOAD_FAILURE, skipSentry: true }]]);
+ expect(wrapper.emitted().error).toEqual([
+ [{ type: LOAD_FAILURE, skipSentry: true }],
+ [{ type: LOAD_FAILURE, skipSentry: true }],
+ ]);
});
it('does not show the pipeline', async () => {
@@ -213,7 +216,10 @@ describe('Linked Pipelines Column', () => {
it('emits the error', async () => {
await clickExpandButton();
- expect(wrapper.emitted().error).toEqual([[{ type: LOAD_FAILURE, skipSentry: true }]]);
+ expect(wrapper.emitted().error).toEqual([
+ [{ type: LOAD_FAILURE, skipSentry: true }],
+ [{ type: LOAD_FAILURE, skipSentry: true }],
+ ]);
});
it('does not show the pipeline', async () => {
diff --git a/spec/frontend/pipelines/notification/deprecated_type_keyword_notification_spec.js b/spec/frontend/pipelines/notification/deprecated_type_keyword_notification_spec.js
index 10ee55818ac..f626652a944 100644
--- a/spec/frontend/pipelines/notification/deprecated_type_keyword_notification_spec.js
+++ b/spec/frontend/pipelines/notification/deprecated_type_keyword_notification_spec.js
@@ -2,6 +2,7 @@ import VueApollo from 'vue-apollo';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { GlAlert, GlSprintf } from '@gitlab/ui';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import DeprecatedTypeKeywordNotification from '~/pipelines/components/notification/deprecated_type_keyword_notification.vue';
import getPipelineWarnings from '~/pipelines/graphql/queries/get_pipeline_warnings.query.graphql';
import {
@@ -77,9 +78,10 @@ describe('Deprecated keyword notification', () => {
});
describe('if there is an error in the query', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockWarnings.mockResolvedValue({ errors: ['It didnt work'] });
wrapper = createComponentWithApollo();
+ await waitForPromises();
});
it('does not display the notification', () => {
@@ -89,9 +91,10 @@ describe('Deprecated keyword notification', () => {
describe('with a valid query result', () => {
describe('if there are no deprecation warnings', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockWarnings.mockResolvedValue(mockWarningsWithoutDeprecation);
wrapper = createComponentWithApollo();
+ await waitForPromises();
});
it('does not show the notification', () => {
expect(findAlert().exists()).toBe(false);
@@ -99,9 +102,10 @@ describe('Deprecated keyword notification', () => {
});
describe('with a root type deprecation message', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockWarnings.mockResolvedValue(mockWarningsRootType);
wrapper = createComponentWithApollo();
+ await waitForPromises();
});
it('shows the notification with one item', () => {
expect(findAlert().exists()).toBe(true);
@@ -111,9 +115,10 @@ describe('Deprecated keyword notification', () => {
});
describe('with a job type deprecation message', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockWarnings.mockResolvedValue(mockWarningsType);
wrapper = createComponentWithApollo();
+ await waitForPromises();
});
it('shows the notification with one item', () => {
expect(findAlert().exists()).toBe(true);
@@ -124,9 +129,10 @@ describe('Deprecated keyword notification', () => {
});
describe('with both the root types and job type deprecation message', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockWarnings.mockResolvedValue(mockWarningsTypesAll);
wrapper = createComponentWithApollo();
+ await waitForPromises();
});
it('shows the notification with two items', () => {
expect(findAlert().exists()).toBe(true);
diff --git a/spec/frontend/projects/new/components/new_project_url_select_spec.js b/spec/frontend/projects/new/components/new_project_url_select_spec.js
index 258fa7636d4..be6592530fc 100644
--- a/spec/frontend/projects/new/components/new_project_url_select_spec.js
+++ b/spec/frontend/projects/new/components/new_project_url_select_spec.js
@@ -9,6 +9,7 @@ import { mount, shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import eventHub from '~/projects/new/event_hub';
@@ -101,6 +102,7 @@ describe('NewProjectUrlSelect component', () => {
findDropdown().vm.$emit('shown');
await wrapper.vm.$apollo.queries.currentUser.refetch();
jest.runOnlyPendingTimers();
+ await waitForPromises();
};
afterEach(() => {
@@ -235,8 +237,7 @@ describe('NewProjectUrlSelect component', () => {
};
wrapper = mountComponent({ search: 'no matches', queryResponse, mountFn: mount });
- jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
+ await waitForPromises();
expect(wrapper.find('li').text()).toBe('No matches found');
});
diff --git a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js
index 6ef49390c47..2ee2ffdb96b 100644
--- a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js
@@ -2,6 +2,7 @@ import { GlColumnChart } from '@gitlab/ui/dist/charts';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import PipelineCharts from '~/projects/pipelines/charts/components/pipeline_charts.vue';
import StatisticsList from '~/projects/pipelines/charts/components/statistics_list.vue';
import getPipelineCountByStatus from '~/projects/pipelines/charts/graphql/queries/get_pipeline_count_by_status.query.graphql';
@@ -25,7 +26,7 @@ describe('~/projects/pipelines/charts/components/pipeline_charts.vue', () => {
return createMockApollo(requestHandlers);
}
- beforeEach(() => {
+ beforeEach(async () => {
wrapper = shallowMount(PipelineCharts, {
provide: {
projectPath,
@@ -33,6 +34,8 @@ describe('~/projects/pipelines/charts/components/pipeline_charts.vue', () => {
localVue,
apolloProvider: createMockApolloProvider(),
});
+
+ await waitForPromises();
});
afterEach(() => {
diff --git a/spec/frontend/releases/components/app_index_apollo_client_spec.js b/spec/frontend/releases/components/app_index_apollo_client_spec.js
index 32bbfd386f5..53ee5b223ad 100644
--- a/spec/frontend/releases/components/app_index_apollo_client_spec.js
+++ b/spec/frontend/releases/components/app_index_apollo_client_spec.js
@@ -4,6 +4,7 @@ import VueApollo from 'vue-apollo';
import originalAllReleasesQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/all_releases.query.graphql.json';
import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import allReleasesQuery from 'shared_queries/releases/all_releases.query.graphql';
import createFlash from '~/flash';
import { historyPushState } from '~/lib/utils/common_utils';
@@ -141,7 +142,8 @@ describe('app_index_apollo_client.vue', () => {
});
});
- it(`${toDescription(loadingIndicator)} render a loading indicator`, () => {
+ it(`${toDescription(loadingIndicator)} render a loading indicator`, async () => {
+ await waitForPromises();
expect(findLoadingIndicator().exists()).toBe(loadingIndicator);
});
diff --git a/spec/frontend/releases/components/app_show_spec.js b/spec/frontend/releases/components/app_show_spec.js
index a60b9bda66a..41c9746a363 100644
--- a/spec/frontend/releases/components/app_show_spec.js
+++ b/spec/frontend/releases/components/app_show_spec.js
@@ -3,6 +3,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import oneReleaseQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release.query.graphql.json';
import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import ReleaseShowApp from '~/releases/components/app_show.vue';
import ReleaseBlock from '~/releases/components/release_block.vue';
@@ -111,12 +112,13 @@ describe('Release show component', () => {
});
describe('when the component has successfully loaded the release', () => {
- beforeEach(() => {
+ beforeEach(async () => {
const apolloProvider = createMockApollo([
[oneReleaseQuery, jest.fn().mockResolvedValueOnce(oneReleaseQueryResponse)],
]);
createComponent({ apolloProvider });
+ await waitForPromises();
});
expectNoLoadingIndicator();
@@ -125,12 +127,13 @@ describe('Release show component', () => {
});
describe('when the request succeeded, but the returned "project" key was null', () => {
- beforeEach(() => {
+ beforeEach(async () => {
const apolloProvider = createMockApollo([
[oneReleaseQuery, jest.fn().mockResolvedValueOnce({ data: { project: null } })],
]);
createComponent({ apolloProvider });
+ await waitForPromises();
});
expectNoLoadingIndicator();
@@ -139,7 +142,7 @@ describe('Release show component', () => {
});
describe('when the request succeeded, but the returned "project.release" key was null', () => {
- beforeEach(() => {
+ beforeEach(async () => {
const apolloProvider = createMockApollo([
[
oneReleaseQuery,
@@ -148,6 +151,7 @@ describe('Release show component', () => {
]);
createComponent({ apolloProvider });
+ await waitForPromises();
});
expectNoLoadingIndicator();
@@ -156,12 +160,13 @@ describe('Release show component', () => {
});
describe('when an error occurs while loading the release', () => {
- beforeEach(() => {
+ beforeEach(async () => {
const apolloProvider = createMockApollo([
[oneReleaseQuery, jest.fn().mockRejectedValueOnce('An error occurred!')],
]);
createComponent({ apolloProvider });
+ await waitForPromises();
});
expectNoLoadingIndicator();
diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js
index d3b60ec3768..3384fd599b4 100644
--- a/spec/frontend/repository/components/blob_content_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_content_viewer_spec.js
@@ -209,7 +209,7 @@ describe('Blob content viewer component', () => {
it('does not render a BlobContent component if a Blob viewer is available', async () => {
loadViewer.mockReturnValue(() => true);
await createComponent({ blob: richViewerMock });
-
+ await waitForPromises();
expect(findBlobContent().exists()).toBe(false);
});
@@ -235,7 +235,7 @@ describe('Blob content viewer component', () => {
},
});
- await nextTick();
+ await waitForPromises();
expect(loadViewer).toHaveBeenCalledWith(viewer);
expect(wrapper.findComponent(loadViewerReturnValue).exists()).toBe(true);
diff --git a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
index ac7ecf32938..35df27e02ea 100644
--- a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
+++ b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
@@ -281,6 +281,7 @@ describe('AdminRunnersApp', () => {
},
});
createComponent();
+ await waitForPromises();
});
it('shows a message for no results', async () => {
@@ -289,9 +290,10 @@ describe('AdminRunnersApp', () => {
});
describe('when runners query fails', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockRunnersQuery = jest.fn().mockRejectedValue(new Error('Error!'));
createComponent();
+ await waitForPromises();
});
it('error is shown to the user', async () => {
diff --git a/spec/frontend/runner/components/cells/runner_actions_cell_spec.js b/spec/frontend/runner/components/cells/runner_actions_cell_spec.js
index 89961fdb162..69838ab95fa 100644
--- a/spec/frontend/runner/components/cells/runner_actions_cell_spec.js
+++ b/spec/frontend/runner/components/cells/runner_actions_cell_spec.js
@@ -186,7 +186,8 @@ describe('RunnerTypeCell', () => {
beforeEach(async () => {
runnerActionsUpdateMutationHandler.mockRejectedValueOnce(new Error(mockErrorMsg));
- await findToggleActiveBtn().vm.$emit('click');
+ findToggleActiveBtn().vm.$emit('click');
+ await waitForPromises();
});
it('error is reported to sentry', () => {
@@ -215,7 +216,8 @@ describe('RunnerTypeCell', () => {
},
});
- await findToggleActiveBtn().vm.$emit('click');
+ findToggleActiveBtn().vm.$emit('click');
+ await waitForPromises();
});
it('error is reported to sentry', () => {
@@ -305,8 +307,9 @@ describe('RunnerTypeCell', () => {
});
describe('When delete is clicked', () => {
- beforeEach(() => {
+ beforeEach(async () => {
findRunnerDeleteModal().vm.$emit('primary');
+ await waitForPromises();
});
it('The delete mutation is called correctly', () => {
@@ -333,10 +336,11 @@ describe('RunnerTypeCell', () => {
describe('On a network error', () => {
const mockErrorMsg = 'Delete error!';
- beforeEach(() => {
+ beforeEach(async () => {
runnerDeleteMutationHandler.mockRejectedValueOnce(new Error(mockErrorMsg));
findRunnerDeleteModal().vm.$emit('primary');
+ await waitForPromises();
});
it('error is reported to sentry', () => {
@@ -359,7 +363,7 @@ describe('RunnerTypeCell', () => {
const mockErrorMsg = 'Runner not found!';
const mockErrorMsg2 = 'User not allowed!';
- beforeEach(() => {
+ beforeEach(async () => {
runnerDeleteMutationHandler.mockResolvedValue({
data: {
runnerDelete: {
@@ -369,6 +373,7 @@ describe('RunnerTypeCell', () => {
});
findRunnerDeleteModal().vm.$emit('primary');
+ await waitForPromises();
});
it('error is reported to sentry', () => {
diff --git a/spec/frontend/runner/components/registration/registration_dropdown_spec.js b/spec/frontend/runner/components/registration/registration_dropdown_spec.js
index 8c08f3560f8..2685d387ef2 100644
--- a/spec/frontend/runner/components/registration/registration_dropdown_spec.js
+++ b/spec/frontend/runner/components/registration/registration_dropdown_spec.js
@@ -82,7 +82,7 @@ describe('RegistrationDropdown', () => {
const findModalInBody = () =>
createWrapper(document.body).find('[data-testid="runner-instructions-modal"]');
- beforeEach(() => {
+ beforeEach(async () => {
createComponent(
{
localVue,
@@ -94,7 +94,7 @@ describe('RegistrationDropdown', () => {
mountExtended,
);
- findRegistrationInstructionsDropdownItem().trigger('click');
+ await findRegistrationInstructionsDropdownItem().trigger('click');
});
afterEach(() => {
diff --git a/spec/frontend/runner/group_runners/group_runners_app_spec.js b/spec/frontend/runner/group_runners/group_runners_app_spec.js
index 71706767092..6becc1ba743 100644
--- a/spec/frontend/runner/group_runners/group_runners_app_spec.js
+++ b/spec/frontend/runner/group_runners/group_runners_app_spec.js
@@ -218,6 +218,7 @@ describe('GroupRunnersApp', () => {
},
});
createComponent();
+ await waitForPromises();
});
it('shows a message for no results', async () => {
@@ -226,9 +227,10 @@ describe('GroupRunnersApp', () => {
});
describe('when runners query fails', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockGroupRunnersQuery = jest.fn().mockRejectedValue(new Error('Error!'));
createComponent();
+ await waitForPromises();
});
it('error is shown to the user', async () => {
diff --git a/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
index 07da4acef8c..76a00f5a826 100644
--- a/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
+++ b/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
@@ -322,9 +322,10 @@ describe('Sidebar assignees widget', () => {
});
describe('when user is not signed in', () => {
- beforeEach(() => {
+ beforeEach(async () => {
gon.current_username = undefined;
createComponent();
+ await waitForPromises();
});
it('passes signedIn prop as false to IssuableAssignees', () => {
diff --git a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js
index e74a867ec97..7808bdb8db3 100644
--- a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js
+++ b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js
@@ -77,8 +77,6 @@ describe('RunnerInstructionsModal component', () => {
runnerSetupInstructionsHandler = jest.fn().mockResolvedValue(mockGraphqlInstructions);
createComponent();
-
- await nextTick();
});
afterEach(() => {
@@ -113,13 +111,15 @@ describe('RunnerInstructionsModal component', () => {
});
});
- it('binary instructions are shown', () => {
+ it('binary instructions are shown', async () => {
+ await waitForPromises();
const instructions = findBinaryInstructions().text();
expect(instructions).toBe(installInstructions);
});
- it('register command is shown with a replaced token', () => {
+ it('register command is shown with a replaced token', async () => {
+ await waitForPromises();
const instructions = findRegisterCommand().text();
expect(instructions).toBe(
@@ -130,7 +130,7 @@ describe('RunnerInstructionsModal component', () => {
describe('when a register token is not shown', () => {
beforeEach(async () => {
createComponent({ props: { registrationToken: undefined } });
- await nextTick();
+ await waitForPromises();
});
it('register command is shown without a defined registration token', () => {
@@ -198,16 +198,16 @@ describe('RunnerInstructionsModal component', () => {
expect(findSkeletonLoader().exists()).toBe(true);
expect(findGlLoadingIcon().exists()).toBe(false);
- await nextTick(); // wait for platforms
+ await nextTick();
+ await jest.runOnlyPendingTimers();
+ await nextTick();
expect(findGlLoadingIcon().exists()).toBe(true);
});
it('once loaded, should not show a loading state', async () => {
createComponent();
-
- await nextTick(); // wait for platforms
- await nextTick(); // wait for architectures
+ await waitForPromises();
expect(findSkeletonLoader().exists()).toBe(false);
expect(findGlLoadingIcon().exists()).toBe(false);
diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
index 1d0eac30a23..e4eaeb9bc3c 100644
--- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
@@ -321,7 +321,7 @@ RSpec.describe Resolvers::MergeRequestsResolver do
end
describe 'sorting' do
- let(:mrs) do
+ let_it_be(:mrs) do
[
merge_request_with_milestone, merge_request_6, merge_request_5, merge_request_4,
merge_request_3, merge_request_2, merge_request_1
@@ -363,28 +363,44 @@ RSpec.describe Resolvers::MergeRequestsResolver do
def merged_at(mr)
nils_last(mr.metrics.merged_at)
end
+ end
+
+ context 'when sorting by closed at' do
+ before do
+ merge_request_1.metrics.update!(latest_closed_at: 10.days.ago)
+ merge_request_3.metrics.update!(latest_closed_at: 5.days.ago)
+ end
+
+ it 'sorts merge requests ascending' do
+ expect(resolve_mr(project, sort: :closed_at_asc))
+ .to match_array(mrs)
+ .and be_sorted(->(mr) { [closed_at(mr), -mr.id] })
+ end
+
+ it 'sorts merge requests descending' do
+ expect(resolve_mr(project, sort: :closed_at_desc))
+ .to match_array(mrs)
+ .and be_sorted(->(mr) { [-closed_at(mr), -mr.id] })
+ end
+
+ def closed_at(mr)
+ nils_last(mr.metrics.latest_closed_at)
+ end
+ end
+
+ context 'when sorting by title' do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:mr1) { create(:merge_request, :unique_branches, title: 'foo', source_project: project) }
+ let_it_be(:mr2) { create(:merge_request, :unique_branches, title: 'bar', source_project: project) }
+ let_it_be(:mr3) { create(:merge_request, :unique_branches, title: 'baz', source_project: project) }
+ let_it_be(:mr4) { create(:merge_request, :unique_branches, title: 'Baz 2', source_project: project) }
+
+ it 'sorts issues ascending' do
+ expect(resolve_mr(project, sort: :title_asc).to_a).to eq [mr2, mr3, mr4, mr1]
+ end
- context 'when sorting by closed at' do
- before do
- merge_request_1.metrics.update!(latest_closed_at: 10.days.ago)
- merge_request_3.metrics.update!(latest_closed_at: 5.days.ago)
- end
-
- it 'sorts merge requests ascending' do
- expect(resolve_mr(project, sort: :closed_at_asc))
- .to match_array(mrs)
- .and be_sorted(->(mr) { [closed_at(mr), -mr.id] })
- end
-
- it 'sorts merge requests descending' do
- expect(resolve_mr(project, sort: :closed_at_desc))
- .to match_array(mrs)
- .and be_sorted(->(mr) { [-closed_at(mr), -mr.id] })
- end
-
- def closed_at(mr)
- nils_last(mr.metrics.latest_closed_at)
- end
+ it 'sorts issues descending' do
+ expect(resolve_mr(project, sort: :title_desc).to_a).to eq [mr1, mr4, mr3, mr2]
end
end
end
diff --git a/spec/lib/bulk_imports/common/extractors/graphql_extractor_spec.rb b/spec/lib/bulk_imports/common/extractors/graphql_extractor_spec.rb
index 80607485b6e..50c54a7b47f 100644
--- a/spec/lib/bulk_imports/common/extractors/graphql_extractor_spec.rb
+++ b/spec/lib/bulk_imports/common/extractors/graphql_extractor_spec.rb
@@ -8,12 +8,15 @@ RSpec.describe BulkImports::Common::Extractors::GraphqlExtractor do
let(:response) { double(original_hash: { 'data' => { 'foo' => 'bar' }, 'page_info' => {} }) }
let(:options) do
{
- query: double(
- to_s: 'test',
- variables: {},
- data_path: %w[data foo],
- page_info_path: %w[data page_info]
- )
+ query:
+ double(
+ new: double(
+ to_s: 'test',
+ variables: {},
+ data_path: %w[data foo],
+ page_info_path: %w[data page_info]
+ )
+ )
}
end
diff --git a/spec/lib/bulk_imports/common/graphql/get_members_query_spec.rb b/spec/lib/bulk_imports/common/graphql/get_members_query_spec.rb
new file mode 100644
index 00000000000..e3a7335a238
--- /dev/null
+++ b/spec/lib/bulk_imports/common/graphql/get_members_query_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::Common::Graphql::GetMembersQuery do
+ let(:entity) { create(:bulk_import_entity, :group_entity) }
+ let(:tracker) { create(:bulk_import_tracker, entity: entity) }
+ let(:context) { BulkImports::Pipeline::Context.new(tracker) }
+
+ subject(:query) { described_class.new(context: context) }
+
+ it 'has a valid query' do
+ parsed_query = GraphQL::Query.new(
+ GitlabSchema,
+ query.to_s,
+ variables: query.variables
+ )
+ result = GitlabSchema.static_validator.validate(parsed_query)
+
+ expect(result[:errors]).to be_empty
+ end
+
+ describe '#data_path' do
+ it 'returns data path' do
+ expected = %w[data portable members nodes]
+
+ expect(query.data_path).to eq(expected)
+ end
+ end
+
+ describe '#page_info_path' do
+ it 'returns pagination information path' do
+ expected = %w[data portable members page_info]
+
+ expect(query.page_info_path).to eq(expected)
+ end
+ end
+
+ describe '#to_s' do
+ context 'when entity is group' do
+ it 'queries group & group members' do
+ expect(query.to_s).to include('group')
+ expect(query.to_s).to include('groupMembers')
+ end
+ end
+
+ context 'when entity is project' do
+ let(:entity) { create(:bulk_import_entity, :project_entity) }
+
+ it 'queries project & project members' do
+ expect(query.to_s).to include('project')
+ expect(query.to_s).to include('projectMembers')
+ end
+ end
+ end
+end
diff --git a/spec/lib/bulk_imports/common/pipelines/members_pipeline_spec.rb b/spec/lib/bulk_imports/common/pipelines/members_pipeline_spec.rb
new file mode 100644
index 00000000000..f9b95f79104
--- /dev/null
+++ b/spec/lib/bulk_imports/common/pipelines/members_pipeline_spec.rb
@@ -0,0 +1,161 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::Common::Pipelines::MembersPipeline do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:bulk_import) { create(:bulk_import, user: user) }
+ let_it_be(:member_user1) { create(:user, email: 'email1@email.com') }
+ let_it_be(:member_user2) { create(:user, email: 'email2@email.com') }
+ let_it_be(:member_data) do
+ {
+ user_id: member_user1.id,
+ created_by_id: member_user2.id,
+ access_level: 30,
+ created_at: '2020-01-01T00:00:00Z',
+ updated_at: '2020-01-01T00:00:00Z',
+ expires_at: nil
+ }
+ end
+
+ let(:parent) { create(:group) }
+ let(:tracker) { create(:bulk_import_tracker, entity: entity) }
+ let(:context) { BulkImports::Pipeline::Context.new(tracker) }
+ let(:members) { portable.members.map { |m| m.slice(:user_id, :access_level) } }
+
+ subject(:pipeline) { described_class.new(context) }
+
+ def extracted_data(email:, has_next_page: false)
+ data = {
+ 'created_at' => '2020-01-01T00:00:00Z',
+ 'updated_at' => '2020-01-02T00:00:00Z',
+ 'expires_at' => nil,
+ 'access_level' => {
+ 'integer_value' => 30
+ },
+ 'user' => {
+ 'public_email' => email
+ }
+ }
+
+ page_info = {
+ 'has_next_page' => has_next_page,
+ 'next_page' => has_next_page ? 'cursor' : nil
+ }
+
+ BulkImports::Pipeline::ExtractedData.new(data: data, page_info: page_info)
+ end
+
+ shared_examples 'members import' do
+ before do
+ portable.members.delete_all
+ end
+
+ describe '#run' do
+ it 'creates memberships for existing users' do
+ first_page = extracted_data(email: member_user1.email, has_next_page: true)
+ last_page = extracted_data(email: member_user2.email)
+
+ allow_next_instance_of(BulkImports::Common::Extractors::GraphqlExtractor) do |extractor|
+ allow(extractor).to receive(:extract).and_return(first_page, last_page)
+ end
+
+ expect { pipeline.run }.to change(portable.members, :count).by(2)
+
+ expect(members).to contain_exactly(
+ { user_id: member_user1.id, access_level: 30 },
+ { user_id: member_user2.id, access_level: 30 }
+ )
+ end
+ end
+
+ describe '#load' do
+ it 'creates new membership' do
+ expect { subject.load(context, member_data) }.to change(portable.members, :count).by(1)
+
+ member = portable.members.find_by_user_id(member_user1.id)
+
+ expect(member.user).to eq(member_user1)
+ expect(member.created_by).to eq(member_user2)
+ expect(member.access_level).to eq(30)
+ expect(member.created_at).to eq('2020-01-01T00:00:00Z')
+ expect(member.updated_at).to eq('2020-01-01T00:00:00Z')
+ expect(member.expires_at).to eq(nil)
+ end
+
+ context 'when user_id is current user id' do
+ it 'does not create new membership' do
+ data = { user_id: user.id }
+
+ expect { pipeline.load(context, data) }.not_to change(portable.members, :count)
+ end
+ end
+
+ context 'when data is nil' do
+ it 'does not create new membership' do
+ expect { pipeline.load(context, nil) }.not_to change(portable.members, :count)
+ end
+ end
+
+ context 'when user membership already exists with the same access level' do
+ it 'does not create new membership' do
+ portable.members.create!(member_data)
+
+ expect { pipeline.load(context, member_data) }.not_to change(portable.members, :count)
+ end
+ end
+
+ context 'when portable is in a parent group' do
+ let(:tracker) { create(:bulk_import_tracker, entity: entity_with_parent) }
+
+ before do
+ parent.members.create!(member_data)
+ end
+
+ context 'when the same membership exists in parent group' do
+ it 'does not create new membership' do
+ expect { pipeline.load(context, member_data) }.not_to change(portable_with_parent.members, :count)
+ end
+ end
+
+ context 'when membership with higher access level exists in parent group' do
+ it 'creates new direct membership' do
+ data = member_data.merge(access_level: Gitlab::Access::MAINTAINER)
+
+ expect { pipeline.load(context, data) }.to change(portable_with_parent.members, :count)
+
+ member = portable_with_parent.members.find_by_user_id(member_user1.id)
+
+ expect(member.access_level).to eq(Gitlab::Access::MAINTAINER)
+ end
+ end
+
+ context 'when membership with lower access level exists in parent group' do
+ it 'does not create new membership' do
+ data = member_data.merge(access_level: Gitlab::Access::GUEST)
+
+ expect { pipeline.load(context, data) }.not_to change(portable_with_parent.members, :count)
+ end
+ end
+ end
+ end
+ end
+
+ context 'when importing to group' do
+ let(:portable) { create(:group) }
+ let(:portable_with_parent) { create(:group, parent: parent) }
+ let(:entity) { create(:bulk_import_entity, :group_entity, group: portable, bulk_import: bulk_import) }
+ let(:entity_with_parent) { create(:bulk_import_entity, :group_entity, group: portable_with_parent, bulk_import: bulk_import) }
+
+ include_examples 'members import'
+ end
+
+ context 'when importing to project' do
+ let(:portable) { create(:project) }
+ let(:portable_with_parent) { create(:project, namespace: parent) }
+ let(:entity) { create(:bulk_import_entity, :project_entity, project: portable, bulk_import: bulk_import) }
+ let(:entity_with_parent) { create(:bulk_import_entity, :project_entity, project: portable_with_parent, bulk_import: bulk_import) }
+
+ include_examples 'members import'
+ end
+end
diff --git a/spec/lib/bulk_imports/groups/graphql/get_group_query_spec.rb b/spec/lib/bulk_imports/groups/graphql/get_group_query_spec.rb
index b0f8f74783b..d03b8d8b5b2 100644
--- a/spec/lib/bulk_imports/groups/graphql/get_group_query_spec.rb
+++ b/spec/lib/bulk_imports/groups/graphql/get_group_query_spec.rb
@@ -3,14 +3,27 @@
require 'spec_helper'
RSpec.describe BulkImports::Groups::Graphql::GetGroupQuery do
+ let_it_be(:tracker) { create(:bulk_import_tracker) }
+ let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
+
+ subject(:query) { described_class.new(context: context) }
+
+ it 'has a valid query' do
+ parsed_query = GraphQL::Query.new(
+ GitlabSchema,
+ query.to_s,
+ variables: query.variables
+ )
+ result = GitlabSchema.static_validator.validate(parsed_query)
+
+ expect(result[:errors]).to be_empty
+ end
+
describe '#variables' do
it 'returns query variables based on entity information' do
- entity = double(source_full_path: 'test', bulk_import: nil)
- tracker = double(entity: entity)
- context = BulkImports::Pipeline::Context.new(tracker)
- expected = { full_path: entity.source_full_path }
+ expected = { full_path: tracker.entity.source_full_path }
- expect(described_class.variables(context)).to eq(expected)
+ expect(subject.variables).to eq(expected)
end
end
@@ -18,7 +31,7 @@ RSpec.describe BulkImports::Groups::Graphql::GetGroupQuery do
it 'returns data path' do
expected = %w[data group]
- expect(described_class.data_path).to eq(expected)
+ expect(subject.data_path).to eq(expected)
end
end
@@ -26,7 +39,7 @@ RSpec.describe BulkImports::Groups::Graphql::GetGroupQuery do
it 'returns pagination information path' do
expected = %w[data group page_info]
- expect(described_class.page_info_path).to eq(expected)
+ expect(subject.page_info_path).to eq(expected)
end
end
end
diff --git a/spec/lib/bulk_imports/groups/graphql/get_members_query_spec.rb b/spec/lib/bulk_imports/groups/graphql/get_members_query_spec.rb
deleted file mode 100644
index d0c4bb817b2..00000000000
--- a/spec/lib/bulk_imports/groups/graphql/get_members_query_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe BulkImports::Groups::Graphql::GetMembersQuery do
- it 'has a valid query' do
- tracker = create(:bulk_import_tracker)
- context = BulkImports::Pipeline::Context.new(tracker)
-
- query = GraphQL::Query.new(
- GitlabSchema,
- described_class.to_s,
- variables: described_class.variables(context)
- )
- result = GitlabSchema.static_validator.validate(query)
-
- expect(result[:errors]).to be_empty
- end
-
- describe '#data_path' do
- it 'returns data path' do
- expected = %w[data group group_members nodes]
-
- expect(described_class.data_path).to eq(expected)
- end
- end
-
- describe '#page_info_path' do
- it 'returns pagination information path' do
- expected = %w[data group group_members page_info]
-
- expect(described_class.page_info_path).to eq(expected)
- end
- end
-end
diff --git a/spec/lib/bulk_imports/groups/graphql/get_projects_query_spec.rb b/spec/lib/bulk_imports/groups/graphql/get_projects_query_spec.rb
index 1a7c5a4993c..fe28e3959a0 100644
--- a/spec/lib/bulk_imports/groups/graphql/get_projects_query_spec.rb
+++ b/spec/lib/bulk_imports/groups/graphql/get_projects_query_spec.rb
@@ -3,25 +3,25 @@
require 'spec_helper'
RSpec.describe BulkImports::Groups::Graphql::GetProjectsQuery do
- describe '#variables' do
- it 'returns valid variables based on entity information' do
- tracker = create(:bulk_import_tracker)
- context = BulkImports::Pipeline::Context.new(tracker)
-
- query = GraphQL::Query.new(
- GitlabSchema,
- described_class.to_s,
- variables: described_class.variables(context)
- )
- result = GitlabSchema.static_validator.validate(query)
-
- expect(result[:errors]).to be_empty
- end
+ let_it_be(:tracker) { create(:bulk_import_tracker) }
+ let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
+
+ subject(:query) { described_class.new(context: context) }
+
+ it 'has a valid query' do
+ parsed_query = GraphQL::Query.new(
+ GitlabSchema,
+ query.to_s,
+ variables: query.variables
+ )
+ result = GitlabSchema.static_validator.validate(parsed_query)
+
+ expect(result[:errors]).to be_empty
+ end
- context 'with invalid variables' do
- it 'raises an error' do
- expect { GraphQL::Query.new(GitlabSchema, described_class.to_s, variables: 'invalid') }.to raise_error(ArgumentError)
- end
+ context 'with invalid variables' do
+ it 'raises an error' do
+ expect { GraphQL::Query.new(GitlabSchema, subject.to_s, variables: 'invalid') }.to raise_error(ArgumentError)
end
end
@@ -29,7 +29,7 @@ RSpec.describe BulkImports::Groups::Graphql::GetProjectsQuery do
it 'returns data path' do
expected = %w[data group projects nodes]
- expect(described_class.data_path).to eq(expected)
+ expect(subject.data_path).to eq(expected)
end
end
@@ -37,7 +37,7 @@ RSpec.describe BulkImports::Groups::Graphql::GetProjectsQuery do
it 'returns pagination information path' do
expected = %w[data group projects page_info]
- expect(described_class.page_info_path).to eq(expected)
+ expect(subject.page_info_path).to eq(expected)
end
end
end
diff --git a/spec/lib/bulk_imports/groups/pipelines/members_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/members_pipeline_spec.rb
deleted file mode 100644
index 0126acb320b..00000000000
--- a/spec/lib/bulk_imports/groups/pipelines/members_pipeline_spec.rb
+++ /dev/null
@@ -1,119 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe BulkImports::Groups::Pipelines::MembersPipeline do
- let_it_be(:member_user1) { create(:user, email: 'email1@email.com') }
- let_it_be(:member_user2) { create(:user, email: 'email2@email.com') }
-
- let_it_be(:user) { create(:user) }
- let_it_be(:group) { create(:group) }
- let_it_be(:bulk_import) { create(:bulk_import, user: user) }
- let_it_be(:entity) { create(:bulk_import_entity, bulk_import: bulk_import, group: group) }
- let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) }
- let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
-
- subject { described_class.new(context) }
-
- describe '#run' do
- it 'maps existing users to the imported group' do
- first_page = extracted_data(email: member_user1.email, has_next_page: true)
- last_page = extracted_data(email: member_user2.email)
-
- allow_next_instance_of(BulkImports::Common::Extractors::GraphqlExtractor) do |extractor|
- allow(extractor)
- .to receive(:extract)
- .and_return(first_page, last_page)
- end
-
- expect { subject.run }.to change(GroupMember, :count).by(2)
-
- members = group.members.map { |m| m.slice(:user_id, :access_level) }
-
- expect(members).to contain_exactly(
- { user_id: member_user1.id, access_level: 30 },
- { user_id: member_user2.id, access_level: 30 }
- )
- end
- end
-
- describe '#load' do
- it 'does nothing when there is no data' do
- expect { subject.load(context, nil) }.not_to change(GroupMember, :count)
- end
-
- it 'creates the member' do
- data = {
- 'user_id' => member_user1.id,
- 'created_by_id' => member_user2.id,
- 'access_level' => 30,
- 'created_at' => '2020-01-01T00:00:00Z',
- 'updated_at' => '2020-01-01T00:00:00Z',
- 'expires_at' => nil
- }
-
- expect { subject.load(context, data) }.to change(GroupMember, :count).by(1)
-
- member = group.members.last
-
- expect(member.user).to eq(member_user1)
- expect(member.created_by).to eq(member_user2)
- expect(member.access_level).to eq(30)
- expect(member.created_at).to eq('2020-01-01T00:00:00Z')
- expect(member.updated_at).to eq('2020-01-01T00:00:00Z')
- expect(member.expires_at).to eq(nil)
- end
-
- context 'when user_id is current user id' do
- it 'does not create new member' do
- data = { 'user_id' => user.id }
-
- expect { subject.load(context, data) }.not_to change(GroupMember, :count)
- end
- end
- end
-
- describe 'pipeline parts' do
- it { expect(described_class).to include_module(BulkImports::Pipeline) }
- it { expect(described_class).to include_module(BulkImports::Pipeline::Runner) }
-
- it 'has extractors' do
- expect(described_class.get_extractor)
- .to eq(
- klass: BulkImports::Common::Extractors::GraphqlExtractor,
- options: {
- query: BulkImports::Groups::Graphql::GetMembersQuery
- }
- )
- end
-
- it 'has transformers' do
- expect(described_class.transformers)
- .to contain_exactly(
- { klass: BulkImports::Common::Transformers::ProhibitedAttributesTransformer, options: nil },
- { klass: BulkImports::Groups::Transformers::MemberAttributesTransformer, options: nil }
- )
- end
- end
-
- def extracted_data(email:, has_next_page: false)
- data = {
- 'created_at' => '2020-01-01T00:00:00Z',
- 'updated_at' => '2020-01-01T00:00:00Z',
- 'expires_at' => nil,
- 'access_level' => {
- 'integer_value' => 30
- },
- 'user' => {
- 'public_email' => email
- }
- }
-
- page_info = {
- 'has_next_page' => has_next_page,
- 'next_page' => has_next_page ? 'cursor' : nil
- }
-
- BulkImports::Pipeline::ExtractedData.new(data: data, page_info: page_info)
- end
-end
diff --git a/spec/lib/bulk_imports/groups/stage_spec.rb b/spec/lib/bulk_imports/groups/stage_spec.rb
index 55a8e40f480..b6bb8a7d195 100644
--- a/spec/lib/bulk_imports/groups/stage_spec.rb
+++ b/spec/lib/bulk_imports/groups/stage_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe BulkImports::Groups::Stage do
[
[0, BulkImports::Groups::Pipelines::GroupPipeline],
[1, BulkImports::Groups::Pipelines::SubgroupEntitiesPipeline],
- [1, BulkImports::Groups::Pipelines::MembersPipeline],
+ [1, BulkImports::Common::Pipelines::MembersPipeline],
[1, BulkImports::Common::Pipelines::LabelsPipeline],
[1, BulkImports::Common::Pipelines::MilestonesPipeline],
[1, BulkImports::Common::Pipelines::BadgesPipeline],
diff --git a/spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb b/spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb
index af99428e0c1..c8935f71f10 100644
--- a/spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb
+++ b/spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb
@@ -48,12 +48,12 @@ RSpec.describe BulkImports::Groups::Transformers::MemberAttributesTransformer do
data = member_data(email: user.email)
expect(subject.transform(context, data)).to eq(
- 'access_level' => 30,
- 'user_id' => user.id,
- 'created_by_id' => user.id,
- 'created_at' => '2020-01-01T00:00:00Z',
- 'updated_at' => '2020-01-01T00:00:00Z',
- 'expires_at' => nil
+ access_level: 30,
+ user_id: user.id,
+ created_by_id: user.id,
+ created_at: '2020-01-01T00:00:00Z',
+ updated_at: '2020-01-01T00:00:00Z',
+ expires_at: nil
)
end
@@ -62,12 +62,12 @@ RSpec.describe BulkImports::Groups::Transformers::MemberAttributesTransformer do
data = member_data(email: secondary_email)
expect(subject.transform(context, data)).to eq(
- 'access_level' => 30,
- 'user_id' => user.id,
- 'created_by_id' => user.id,
- 'created_at' => '2020-01-01T00:00:00Z',
- 'updated_at' => '2020-01-01T00:00:00Z',
- 'expires_at' => nil
+ access_level: 30,
+ user_id: user.id,
+ created_by_id: user.id,
+ created_at: '2020-01-01T00:00:00Z',
+ updated_at: '2020-01-01T00:00:00Z',
+ expires_at: nil
)
end
diff --git a/spec/lib/bulk_imports/projects/graphql/get_project_query_spec.rb b/spec/lib/bulk_imports/projects/graphql/get_project_query_spec.rb
new file mode 100644
index 00000000000..6593aa56506
--- /dev/null
+++ b/spec/lib/bulk_imports/projects/graphql/get_project_query_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::Projects::Graphql::GetProjectQuery do
+ let_it_be(:tracker) { create(:bulk_import_tracker) }
+ let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
+
+ subject(:query) { described_class.new(context: context) }
+
+ it 'has a valid query' do
+ parsed_query = GraphQL::Query.new(
+ GitlabSchema,
+ query.to_s,
+ variables: query.variables
+ )
+ result = GitlabSchema.static_validator.validate(parsed_query)
+
+ expect(result[:errors]).to be_empty
+ end
+
+ it 'queries project based on source_full_path' do
+ expected = { full_path: tracker.entity.source_full_path }
+
+ expect(subject.variables).to eq(expected)
+ end
+end
diff --git a/spec/lib/bulk_imports/projects/graphql/get_repository_query_spec.rb b/spec/lib/bulk_imports/projects/graphql/get_repository_query_spec.rb
index 4dba81dc0d2..8ed105bc0c9 100644
--- a/spec/lib/bulk_imports/projects/graphql/get_repository_query_spec.rb
+++ b/spec/lib/bulk_imports/projects/graphql/get_repository_query_spec.rb
@@ -3,19 +3,29 @@
require 'spec_helper'
RSpec.describe BulkImports::Projects::Graphql::GetRepositoryQuery do
- describe 'query repository based on full_path' do
- let(:entity) { double(source_full_path: 'test', bulk_import: nil) }
- let(:tracker) { double(entity: entity) }
- let(:context) { BulkImports::Pipeline::Context.new(tracker) }
+ let_it_be(:tracker) { create(:bulk_import_tracker) }
+ let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
- it 'returns project repository url' do
- expect(described_class.to_s).to include('httpUrlToRepo')
- end
+ subject(:query) { described_class.new(context: context) }
- it 'queries project based on source_full_path' do
- expected = { full_path: entity.source_full_path }
+ it 'has a valid query' do
+ parsed_query = GraphQL::Query.new(
+ GitlabSchema,
+ query.to_s,
+ variables: query.variables
+ )
+ result = GitlabSchema.static_validator.validate(parsed_query)
- expect(described_class.variables(context)).to eq(expected)
- end
+ expect(result[:errors]).to be_empty
+ end
+
+ it 'returns project repository url' do
+ expect(subject.to_s).to include('httpUrlToRepo')
+ end
+
+ it 'queries project based on source_full_path' do
+ expected = { full_path: tracker.entity.source_full_path }
+
+ expect(subject.variables).to eq(expected)
end
end
diff --git a/spec/lib/bulk_imports/projects/graphql/get_snippet_repository_query_spec.rb b/spec/lib/bulk_imports/projects/graphql/get_snippet_repository_query_spec.rb
index b680fa5cbfc..1bd4106297d 100644
--- a/spec/lib/bulk_imports/projects/graphql/get_snippet_repository_query_spec.rb
+++ b/spec/lib/bulk_imports/projects/graphql/get_snippet_repository_query_spec.rb
@@ -3,56 +3,56 @@
require 'spec_helper'
RSpec.describe BulkImports::Projects::Graphql::GetSnippetRepositoryQuery do
- describe 'query repository based on full_path' do
- let_it_be(:entity) { create(:bulk_import_entity) }
- let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) }
- let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
-
- it 'has a valid query' do
- query = GraphQL::Query.new(
- GitlabSchema,
- described_class.to_s,
- variables: described_class.variables(context)
- )
- result = GitlabSchema.static_validator.validate(query)
-
- expect(result[:errors]).to be_empty
- end
+ let_it_be(:entity) { create(:bulk_import_entity) }
+ let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) }
+ let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
- it 'returns snippet httpUrlToRepo' do
- expect(described_class.to_s).to include('httpUrlToRepo')
- end
+ subject(:query) { described_class.new(context: context) }
- it 'returns snippet createdAt' do
- expect(described_class.to_s).to include('createdAt')
- end
+ it 'has a valid query' do
+ parsed_query = GraphQL::Query.new(
+ GitlabSchema,
+ query.to_s,
+ variables: query.variables
+ )
+ result = GitlabSchema.static_validator.validate(parsed_query)
- it 'returns snippet title' do
- expect(described_class.to_s).to include('title')
- end
+ expect(result[:errors]).to be_empty
+ end
- describe '.variables' do
- it 'queries project based on source_full_path and pagination' do
- expected = { full_path: entity.source_full_path, cursor: nil, per_page: 500 }
+ it 'returns snippet httpUrlToRepo' do
+ expect(subject.to_s).to include('httpUrlToRepo')
+ end
- expect(described_class.variables(context)).to eq(expected)
- end
+ it 'returns snippet createdAt' do
+ expect(subject.to_s).to include('createdAt')
+ end
+
+ it 'returns snippet title' do
+ expect(subject.to_s).to include('title')
+ end
+
+ describe '.variables' do
+ it 'queries project based on source_full_path and pagination' do
+ expected = { full_path: entity.source_full_path, cursor: nil, per_page: 500 }
+
+ expect(subject.variables).to eq(expected)
end
+ end
- describe '.data_path' do
- it '.data_path returns data path' do
- expected = %w[data project snippets nodes]
+ describe '.data_path' do
+ it '.data_path returns data path' do
+ expected = %w[data project snippets nodes]
- expect(described_class.data_path).to eq(expected)
- end
+ expect(subject.data_path).to eq(expected)
end
+ end
- describe '.page_info_path' do
- it '.page_info_path returns pagination information path' do
- expected = %w[data project snippets page_info]
+ describe '.page_info_path' do
+ it '.page_info_path returns pagination information path' do
+ expected = %w[data project snippets page_info]
- expect(described_class.page_info_path).to eq(expected)
- end
+ expect(subject.page_info_path).to eq(expected)
end
end
end
diff --git a/spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb b/spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb
index 0e26a9fa571..889878cf3ef 100644
--- a/spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Build::Artifacts::ExpireInParser do
- describe '.validate_duration' do
+ describe '.validate_duration', :request_store do
subject { described_class.validate_duration(value) }
context 'with never' do
@@ -20,14 +20,33 @@ RSpec.describe Gitlab::Ci::Build::Artifacts::ExpireInParser do
context 'with a duration' do
let(:value) { '1 Day' }
+ let(:other_value) { '30 seconds' }
it { is_expected.to be_truthy }
+
+ it 'caches data' do
+ expect(ChronicDuration).to receive(:parse).with(value).once.and_call_original
+ expect(ChronicDuration).to receive(:parse).with(other_value).once.and_call_original
+
+ 2.times do
+ expect(described_class.validate_duration(value)).to eq(86400)
+ expect(described_class.validate_duration(other_value)).to eq(30)
+ end
+ end
end
context 'without a duration' do
let(:value) { 'something' }
it { is_expected.to be_falsy }
+
+ it 'caches data' do
+ expect(ChronicDuration).to receive(:parse).with(value).once.and_call_original
+
+ 2.times do
+ expect(described_class.validate_duration(value)).to be_falsey
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
index 687bb82a8ef..7b69d23ce90 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
@@ -252,7 +252,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
extra_jobs = 2
non_handled_sql_queries = 2
- # 1. Ci::InstanceVariable Load => `Ci::InstanceVariable#cached_data` => already cached with `fetch_memory_cache`
+ # 1. Ci::InstanceVariable Load => `Ci::InstanceVariable#cached_data` => already cached with `ProcessMemoryCache`
# 2. Ci::Variable Load => `Project#ci_variables_for` => already cached with `Gitlab::SafeRequestStore`
extra_jobs * non_handled_sql_queries
diff --git a/spec/lib/gitlab/process_memory_cache/helper_spec.rb b/spec/lib/gitlab/process_memory_cache/helper_spec.rb
deleted file mode 100644
index 27d7fd0bdcf..00000000000
--- a/spec/lib/gitlab/process_memory_cache/helper_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::ProcessMemoryCache::Helper, :use_clean_rails_memory_store_caching do
- let(:minimal_test_class) do
- Class.new do
- include Gitlab::ProcessMemoryCache::Helper
-
- def cached_content
- fetch_memory_cache(:cached_content_instance_key) { expensive_computation }
- end
-
- def clear_cached_content
- invalidate_memory_cache(:cached_content_instance_key)
- end
- end
- end
-
- before do
- stub_const("MinimalTestClass", minimal_test_class)
- end
-
- subject { MinimalTestClass.new }
-
- describe '.fetch_memory_cache' do
- it 'memoizes the result' do
- is_expected.to receive(:expensive_computation).once.and_return(1)
-
- 2.times do
- expect(subject.cached_content).to eq(1)
- end
- end
-
- it 'resets the cache when the shared key is missing', :aggregate_failures do
- expect(Rails.cache).to receive(:read).with(:cached_content_instance_key).twice.and_return(nil)
- is_expected.to receive(:expensive_computation).thrice.and_return(1, 2, 3)
-
- 3.times do |index|
- expect(subject.cached_content).to eq(index + 1)
- end
- end
- end
-
- describe '.invalidate_memory_cache' do
- it 'invalidates the cache' do
- is_expected.to receive(:expensive_computation).twice.and_return(1, 2)
-
- expect { subject.clear_cached_content }.to change { subject.cached_content }
- end
- end
-end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 5839bc414cc..0b3fb80f97f 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -585,6 +585,21 @@ RSpec.describe MergeRequest, factory_default: :keep do
expect(merge_requests).to eq([older_mr, newer_mr])
end
end
+
+ context 'title' do
+ let_it_be(:first_mr) { create(:merge_request, :closed, title: 'One') }
+ let_it_be(:second_mr) { create(:merge_request, :closed, title: 'Two') }
+
+ it 'sorts asc' do
+ merge_requests = described_class.sort_by_attribute(:title_asc)
+ expect(merge_requests).to eq([first_mr, second_mr])
+ end
+
+ it 'sorts desc' do
+ merge_requests = described_class.sort_by_attribute(:title_desc)
+ expect(merge_requests).to eq([second_mr, first_mr])
+ end
+ end
end
describe 'time to merge calculations' do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index a751f785913..0a90be4a068 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -436,6 +436,26 @@ RSpec.describe API::MergeRequests do
response_dates = json_response.map { |merge_request| merge_request['created_at'] }
expect(response_dates).to eq(response_dates.sort)
end
+
+ context 'returns an array of merge_requests ordered by title' do
+ it 'asc when requested' do
+ path = endpoint_path + '?order_by=title&sort=asc'
+
+ get api(path, user)
+
+ response_titles = json_response.map { |merge_request| merge_request['title'] }
+ expect(response_titles).to eq(response_titles.sort)
+ end
+
+ it 'desc when requested' do
+ path = endpoint_path + '?order_by=title&sort=desc'
+
+ get api(path, user)
+
+ response_titles = json_response.map { |merge_request| merge_request['title'] }
+ expect(response_titles).to eq(response_titles.sort.reverse)
+ end
+ end
end
context 'NOT params' do
diff --git a/spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb
index 2bb3d807aa7..14b2663a72c 100644
--- a/spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb
@@ -18,7 +18,7 @@ RSpec.shared_examples_for 'graphql mutations security ci configuration' do
ServiceResponse.success(payload: { branch: branch, success_path: success_path })
end
- let(:error) { "An error occured!" }
+ let(:error) { "An error occurred!" }
let(:service_error_response) do
ServiceResponse.error(message: error)
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index bb4e2981070..18ce853dbef 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -370,7 +370,6 @@ RSpec.describe 'Every Sidekiq worker' do
'PagesDomainSslRenewalWorker' => 3,
'PagesDomainVerificationWorker' => 3,
'PagesTransferWorker' => 3,
- 'PagesUpdateConfigurationWorker' => 1,
'PagesWorker' => 3,
'PersonalAccessTokens::Groups::PolicyWorker' => 3,
'PersonalAccessTokens::Instance::PolicyWorker' => 3,
diff --git a/spec/workers/pages_update_configuration_worker_spec.rb b/spec/workers/pages_update_configuration_worker_spec.rb
deleted file mode 100644
index af71f6b3cca..00000000000
--- a/spec/workers/pages_update_configuration_worker_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-require "spec_helper"
-
-RSpec.describe PagesUpdateConfigurationWorker do
- let_it_be(:project) { create(:project) }
-
- describe "#perform" do
- it "does not break" do
- expect { subject.perform(-1) }.not_to raise_error
- end
- end
-end