diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-26 15:09:27 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-26 15:09:27 +0000 |
commit | 5169b4a63b1e592e159b5451f81bc3c11602275f (patch) | |
tree | 2cfb5e8f0a4c2343579a2f56c8a60233bb6059b1 | |
parent | 0594381ba711725d7d676db202902dfcbe9ec4a0 (diff) | |
download | gitlab-ce-5169b4a63b1e592e159b5451f81bc3c11602275f.tar.gz |
Add latest changes from gitlab-org/gitlab@master
47 files changed, 487 insertions, 93 deletions
diff --git a/.gitlab/issue_templates/Productivity Improvement.md b/.gitlab/issue_templates/Productivity Improvement.md index 06692d3ede8..040d8ea2f89 100644 --- a/.gitlab/issue_templates/Productivity Improvement.md +++ b/.gitlab/issue_templates/Productivity Improvement.md @@ -2,7 +2,7 @@ <!-- Please describe the engineering productivity problem that needs to be solved backed by charts from -https://about.gitlab.com/handbook/engineering/quality/engineering-productivity-team/#engineering-productivity-team-metrics. +https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/#engineering-productivity-metrics. --> ### Problem identification checklist diff --git a/.gitlab/merge_request_templates/Pipeline Configuration.md b/.gitlab/merge_request_templates/Pipeline Configuration.md index 920abf086cb..083992bff92 100644 --- a/.gitlab/merge_request_templates/Pipeline Configuration.md +++ b/.gitlab/merge_request_templates/Pipeline Configuration.md @@ -33,6 +33,6 @@ This will help keep track of expected cost increases to the [GitLab project aver ### Post-merge -- [ ] Consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity-team/#pipeline-changes) +- [ ] Consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/#pipeline-changes) /label ~tooling ~"tooling::pipelines" ~"Engineering Productivity" diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 05f9d7573ba..243f3a70c19 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -ee4b20cc318876c4b237e277fefd9d75186a085c +156e65d1de93e779091a0915cf77b2aefa85fadf diff --git a/app/assets/javascripts/blob/components/blob_content.vue b/app/assets/javascripts/blob/components/blob_content.vue index 213e026c41f..e3e43ea3a0e 100644 --- a/app/assets/javascripts/blob/components/blob_content.vue +++ b/app/assets/javascripts/blob/components/blob_content.vue @@ -65,7 +65,7 @@ export default { }; </script> <template> - <div class="blob-viewer" :data-type="activeViewer.type"> + <div class="blob-viewer" :data-type="activeViewer.type" :data-loaded="!loading"> <gl-loading-icon v-if="loading" size="md" color="dark" class="my-4 mx-auto" /> <template v-else> diff --git a/app/assets/javascripts/blob/components/blob_header.vue b/app/assets/javascripts/blob/components/blob_header.vue index 4742b4ae4b4..933ad448c77 100644 --- a/app/assets/javascripts/blob/components/blob_header.vue +++ b/app/assets/javascripts/blob/components/blob_header.vue @@ -3,12 +3,14 @@ import DefaultActions from './blob_header_default_actions.vue'; import BlobFilepath from './blob_header_filepath.vue'; import ViewerSwitcher from './blob_header_viewer_switcher.vue'; import { SIMPLE_BLOB_VIEWER } from './constants'; +import TableOfContents from './table_contents.vue'; export default { components: { ViewerSwitcher, DefaultActions, BlobFilepath, + TableOfContents, }, props: { blob: { @@ -70,11 +72,14 @@ export default { </script> <template> <div class="js-file-title file-title-flex-parent"> - <blob-filepath :blob="blob"> - <template #filepath-prepend> - <slot name="prepend"></slot> - </template> - </blob-filepath> + <div class="gl-display-flex"> + <table-of-contents class="gl-pr-2" /> + <blob-filepath :blob="blob"> + <template #filepath-prepend> + <slot name="prepend"></slot> + </template> + </blob-filepath> + </div> <div class="gl-display-none gl-sm-display-flex"> <viewer-switcher v-if="showViewerSwitcher" v-model="viewer" /> diff --git a/app/assets/javascripts/blob/components/table_contents.vue b/app/assets/javascripts/blob/components/table_contents.vue index 78ecb82f2cd..07da262ec9a 100644 --- a/app/assets/javascripts/blob/components/table_contents.vue +++ b/app/assets/javascripts/blob/components/table_contents.vue @@ -18,11 +18,12 @@ export default { }, mounted() { this.blobViewer = document.querySelector('.blob-viewer[data-type="rich"]'); + const blobViewerAttr = (attr) => this.blobViewer.getAttribute(attr); this.observer = new MutationObserver(() => { - if (this.blobViewer.classList.contains('hidden')) { + if (this.blobViewer.classList.contains('hidden') || blobViewerAttr('data-type') !== 'rich') { this.isHidden = true; - } else if (this.blobViewer.getAttribute('data-loaded') === 'true') { + } else if (blobViewerAttr('data-loaded') === 'true') { this.isHidden = false; this.generateHeaders(); } diff --git a/app/assets/javascripts/groups/components/item_caret.vue b/app/assets/javascripts/groups/components/item_caret.vue index 9c379d7bf9b..a51edd385dd 100644 --- a/app/assets/javascripts/groups/components/item_caret.vue +++ b/app/assets/javascripts/groups/components/item_caret.vue @@ -22,6 +22,6 @@ export default { <template> <span class="folder-caret gl-mr-2"> - <gl-icon :size="10" :name="iconClass" use-deprecated-sizes /> + <gl-icon :size="12" :name="iconClass" /> </span> </template> diff --git a/app/assets/javascripts/issue_show/components/header_actions.vue b/app/assets/javascripts/issue_show/components/header_actions.vue index 2bddbe4faa0..2c314ce1c3f 100644 --- a/app/assets/javascripts/issue_show/components/header_actions.vue +++ b/app/assets/javascripts/issue_show/components/header_actions.vue @@ -192,9 +192,14 @@ export default { class="gl-sm-display-none! w-100" block :text="dropdownText" + data-qa-selector="issue_actions_dropdown" :loading="isToggleStateButtonLoading" > - <gl-dropdown-item v-if="showToggleIssueStateButton" @click="toggleIssueState"> + <gl-dropdown-item + v-if="showToggleIssueStateButton" + :data-qa-selector="`mobile_${qaSelector}`" + @click="toggleIssueState" + > {{ buttonText }} </gl-dropdown-item> <gl-dropdown-item v-if="canCreateIssue" :href="newIssuePath"> diff --git a/app/assets/javascripts/nav/components/responsive_home.vue b/app/assets/javascripts/nav/components/responsive_home.vue index c8f2f0bfb10..a80fda96363 100644 --- a/app/assets/javascripts/nav/components/responsive_home.vue +++ b/app/assets/javascripts/nav/components/responsive_home.vue @@ -55,6 +55,7 @@ export default { v-gl-tooltip="{ title: newDropdownViewModel.title }" :view-model="newDropdownViewModel" class="gl-ml-3" + data-qa-selector="mobile_new_dropdown" /> </header> <top-nav-menu-sections class="gl-h-full" :sections="menuSections" v-on="$listeners" /> diff --git a/app/assets/javascripts/nav/components/top_nav_new_dropdown.vue b/app/assets/javascripts/nav/components/top_nav_new_dropdown.vue index 154bed81854..bfcdcfc7292 100644 --- a/app/assets/javascripts/nav/components/top_nav_new_dropdown.vue +++ b/app/assets/javascripts/nav/components/top_nav_new_dropdown.vue @@ -46,6 +46,7 @@ export default { link-class="top-nav-menu-item" :href="menuItem.href" data-testid="item" + :data-qa-selector="`${menuItem.title.toLowerCase().replace(' ', '_')}_mobile_button`" > {{ menuItem.title }} </gl-dropdown-item> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue index 8dafdec0e92..ceed2249f3d 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue @@ -197,7 +197,7 @@ export default { class="gl-display-flex gl-align-items-center gl-py-3 gl-pl-7" data-testid="extension-list-item" > - <status-icon v-if="data.icon" :icon-name="data.icon.name" :size="12" /> + <status-icon v-if="data.icon" :icon-name="data.icon.name" :size="12" class="gl-pl-0" /> <gl-intersection-observer :options="{ rootMargin: '100px', thresholds: 0.1 }" class="gl-flex-wrap gl-align-self-center gl-display-flex" diff --git a/app/assets/javascripts/vue_shared/components/file_icon.vue b/app/assets/javascripts/vue_shared/components/file_icon.vue index 276fb35b51f..adf34f822ed 100644 --- a/app/assets/javascripts/vue_shared/components/file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/file_icon.vue @@ -86,7 +86,7 @@ export default { <template> <span> <gl-loading-icon v-if="loading" size="sm" :inline="true" /> - <gl-icon v-else-if="isSymlink" name="symlink" :size="size" use-deprecated-sizes /> + <gl-icon v-else-if="isSymlink" name="symlink" :size="size" /> <svg v-else-if="!folder" :key="spriteHref" :class="[iconSizeClass, cssClasses]"> <use v-bind="{ 'xlink:href': spriteHref }" /> </svg> diff --git a/app/graphql/mutations/issues/create.rb b/app/graphql/mutations/issues/create.rb index 70a8f539ccf..72b03cc27c2 100644 --- a/app/graphql/mutations/issues/create.rb +++ b/app/graphql/mutations/issues/create.rb @@ -3,13 +3,14 @@ module Mutations module Issues class Create < BaseMutation + include Mutations::SpamProtection include FindsProject + include CommonMutationArguments + graphql_name 'CreateIssue' authorize :create_issue - include CommonMutationArguments - argument :project_path, GraphQL::Types::ID, required: true, description: 'Project full path the issue is associated with.' @@ -76,9 +77,7 @@ module Mutations spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) issue = ::Issues::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute - if issue.spam? - issue.errors.add(:base, 'Spam detected.') - end + check_spam_action_response!(issue) { issue: issue.valid? ? issue : nil, diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index df2d62f4a99..fffc06ecb29 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -684,7 +684,9 @@ module Ci end def freeze_period? - Ci::FreezePeriodStatus.new(project: project).execute + strong_memoize(:freeze_period) do + Ci::FreezePeriodStatus.new(project: project).execute + end end def has_warnings? @@ -800,20 +802,7 @@ module Ci variables.append(key: 'CI_PIPELINE_CREATED_AT', value: created_at&.iso8601) variables.concat(predefined_commit_variables) - - if merge_request? - variables.append(key: 'CI_MERGE_REQUEST_EVENT_TYPE', value: merge_request_event_type.to_s) - variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', value: source_sha.to_s) - variables.append(key: 'CI_MERGE_REQUEST_TARGET_BRANCH_SHA', value: target_sha.to_s) - - diff = self.merge_request_diff - if diff.present? - variables.append(key: 'CI_MERGE_REQUEST_DIFF_ID', value: diff.id.to_s) - variables.append(key: 'CI_MERGE_REQUEST_DIFF_BASE_SHA', value: diff.base_commit_sha) - end - - variables.concat(merge_request.predefined_variables) - end + variables.concat(predefined_merge_request_variables) if open_merge_requests_refs.any? variables.append(key: 'CI_OPEN_MERGE_REQUESTS', value: open_merge_requests_refs.join(',')) @@ -829,27 +818,49 @@ module Ci end def predefined_commit_variables - Gitlab::Ci::Variables::Collection.new.tap do |variables| - variables.append(key: 'CI_COMMIT_SHA', value: sha) - variables.append(key: 'CI_COMMIT_SHORT_SHA', value: short_sha) - variables.append(key: 'CI_COMMIT_BEFORE_SHA', value: before_sha) - variables.append(key: 'CI_COMMIT_REF_NAME', value: source_ref) - variables.append(key: 'CI_COMMIT_REF_SLUG', value: source_ref_slug) - variables.append(key: 'CI_COMMIT_BRANCH', value: ref) if branch? - variables.append(key: 'CI_COMMIT_TAG', value: ref) if tag? - variables.append(key: 'CI_COMMIT_MESSAGE', value: git_commit_message.to_s) - variables.append(key: 'CI_COMMIT_TITLE', value: git_commit_full_title.to_s) - variables.append(key: 'CI_COMMIT_DESCRIPTION', value: git_commit_description.to_s) - variables.append(key: 'CI_COMMIT_REF_PROTECTED', value: (!!protected_ref?).to_s) - variables.append(key: 'CI_COMMIT_TIMESTAMP', value: git_commit_timestamp.to_s) - variables.append(key: 'CI_COMMIT_AUTHOR', value: git_author_full_text.to_s) - - # legacy variables - variables.append(key: 'CI_BUILD_REF', value: sha) - variables.append(key: 'CI_BUILD_BEFORE_SHA', value: before_sha) - variables.append(key: 'CI_BUILD_REF_NAME', value: source_ref) - variables.append(key: 'CI_BUILD_REF_SLUG', value: source_ref_slug) - variables.append(key: 'CI_BUILD_TAG', value: ref) if tag? + strong_memoize(:predefined_commit_variables) do + Gitlab::Ci::Variables::Collection.new.tap do |variables| + variables.append(key: 'CI_COMMIT_SHA', value: sha) + variables.append(key: 'CI_COMMIT_SHORT_SHA', value: short_sha) + variables.append(key: 'CI_COMMIT_BEFORE_SHA', value: before_sha) + variables.append(key: 'CI_COMMIT_REF_NAME', value: source_ref) + variables.append(key: 'CI_COMMIT_REF_SLUG', value: source_ref_slug) + variables.append(key: 'CI_COMMIT_BRANCH', value: ref) if branch? + variables.append(key: 'CI_COMMIT_TAG', value: ref) if tag? + variables.append(key: 'CI_COMMIT_MESSAGE', value: git_commit_message.to_s) + variables.append(key: 'CI_COMMIT_TITLE', value: git_commit_full_title.to_s) + variables.append(key: 'CI_COMMIT_DESCRIPTION', value: git_commit_description.to_s) + variables.append(key: 'CI_COMMIT_REF_PROTECTED', value: (!!protected_ref?).to_s) + variables.append(key: 'CI_COMMIT_TIMESTAMP', value: git_commit_timestamp.to_s) + variables.append(key: 'CI_COMMIT_AUTHOR', value: git_author_full_text.to_s) + + # legacy variables + variables.append(key: 'CI_BUILD_REF', value: sha) + variables.append(key: 'CI_BUILD_BEFORE_SHA', value: before_sha) + variables.append(key: 'CI_BUILD_REF_NAME', value: source_ref) + variables.append(key: 'CI_BUILD_REF_SLUG', value: source_ref_slug) + variables.append(key: 'CI_BUILD_TAG', value: ref) if tag? + end + end + end + + def predefined_merge_request_variables + strong_memoize(:predefined_merge_request_variables) do + Gitlab::Ci::Variables::Collection.new.tap do |variables| + next variables unless merge_request? + + variables.append(key: 'CI_MERGE_REQUEST_EVENT_TYPE', value: merge_request_event_type.to_s) + variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', value: source_sha.to_s) + variables.append(key: 'CI_MERGE_REQUEST_TARGET_BRANCH_SHA', value: target_sha.to_s) + + diff = self.merge_request_diff + if diff.present? + variables.append(key: 'CI_MERGE_REQUEST_DIFF_ID', value: diff.id.to_s) + variables.append(key: 'CI_MERGE_REQUEST_DIFF_BASE_SHA', value: diff.base_commit_sha) + end + + variables.concat(merge_request.predefined_variables) + end end end diff --git a/app/models/project.rb b/app/models/project.rb index 7bc0efa1d3f..490e0e15af4 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2056,14 +2056,16 @@ class Project < ApplicationRecord end def predefined_variables - Gitlab::Ci::Variables::Collection.new - .concat(predefined_ci_server_variables) - .concat(predefined_project_variables) - .concat(pages_variables) - .concat(container_registry_variables) - .concat(dependency_proxy_variables) - .concat(auto_devops_variables) - .concat(api_variables) + strong_memoize(:predefined_variables) do + Gitlab::Ci::Variables::Collection.new + .concat(predefined_ci_server_variables) + .concat(predefined_project_variables) + .concat(pages_variables) + .concat(container_registry_variables) + .concat(dependency_proxy_variables) + .concat(auto_devops_variables) + .concat(api_variables) + end end def predefined_project_variables diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 8d28823bfa4..83e8ff79aec 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -120,7 +120,7 @@ - sign_in_text = allow_signup? ? _('Sign in / Register') : _('Sign in') = link_to sign_in_text, new_session_path(:user, redirect_to_referer: 'yes'), class: 'gl-button btn btn-default btn-sign-in' - %button.navbar-toggler.d-block.d-sm-none{ type: 'button', class: 'gl-border-none!', data: { testid: 'top-nav-responsive-toggle' } } + %button.navbar-toggler.d-block.d-sm-none{ type: 'button', class: 'gl-border-none!', data: { testid: 'top-nav-responsive-toggle', qa_selector: 'mobile_navbar_button' } } %span.sr-only= _('Toggle navigation') %span.more-icon.gl-px-3.gl-font-sm.gl-font-weight-bold %span.gl-pr-2= _('Menu') diff --git a/app/views/layouts/nav/_breadcrumbs.html.haml b/app/views/layouts/nav/_breadcrumbs.html.haml index 02a37dac158..ab4c0989eab 100644 --- a/app/views/layouts/nav/_breadcrumbs.html.haml +++ b/app/views/layouts/nav/_breadcrumbs.html.haml @@ -6,7 +6,7 @@ %nav.breadcrumbs{ class: [container, @content_class], 'aria-label': _('Breadcrumbs') } .breadcrumbs-container{ class: ("border-bottom-0" if @no_breadcrumb_border) } - if defined?(@left_sidebar) - = button_tag class: 'toggle-mobile-nav', type: 'button' do + = button_tag class: 'toggle-mobile-nav', data: { qa_selector: 'toggle_mobile_nav_button' }, type: 'button' do %span.sr-only= _("Open sidebar") = sprite_icon('hamburger', size: 18) .breadcrumbs-links{ data: { testid: 'breadcrumb-links', qa_selector: 'breadcrumb_links_content' } } diff --git a/app/views/projects/blob/_header.html.haml b/app/views/projects/blob/_header.html.haml index d7668dd1c91..dad4ea205b4 100644 --- a/app/views/projects/blob/_header.html.haml +++ b/app/views/projects/blob/_header.html.haml @@ -10,7 +10,7 @@ = edit_blob_button(@project, @ref, @path, blob: blob) = ide_edit_button(@project, @ref, @path, blob: blob) - if can_view_pipeline_editor?(@project) && @path == @project.ci_config_path_or_default - = link_to "Pipeline Editor", project_ci_pipeline_editor_path(@project), class: "btn gl-button btn-confirm-secondary gl-ml-3" + = link_to "Pipeline Editor", project_ci_pipeline_editor_path(@project, branch_name: @ref), class: "btn gl-button btn-confirm-secondary gl-ml-3" .btn-group{ role: "group", class: ("gl-ml-3" if current_user) }> = render_if_exists 'projects/blob/header_file_locks_link' - if current_user diff --git a/danger/pipeline/Dangerfile b/danger/pipeline/Dangerfile index 5503094ba50..861d031915e 100644 --- a/danger/pipeline/Dangerfile +++ b/danger/pipeline/Dangerfile @@ -14,7 +14,7 @@ Please consider the effect of the changes in this merge request on the following - personal forks - Effects on [pipeline performance](https://about.gitlab.com/handbook/engineering/quality/performance-indicators/#average-merge-request-pipeline-duration-for-gitlab) -Please consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity-team/#pipeline-changes) +Please consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/#pipeline-changes) MESSAGE if helper.has_ci_changes? diff --git a/doc/development/index.md b/doc/development/index.md index 17d7eaf9779..fa49d43d46c 100644 --- a/doc/development/index.md +++ b/doc/development/index.md @@ -122,7 +122,7 @@ In these cases, use the following workflow: - [User Experience (UX)](https://about.gitlab.com/handbook/engineering/ux/) - [Security](https://about.gitlab.com/handbook/engineering/security/) - [Quality](https://about.gitlab.com/handbook/engineering/quality/) - - [Engineering Productivity](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity-team/) + - [Engineering Productivity](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/) - [Infrastructure](https://about.gitlab.com/handbook/engineering/infrastructure/) - [Technical Writing](https://about.gitlab.com/handbook/engineering/ux/technical-writing/) diff --git a/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md b/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md index eadd0ef49a0..1990b04e155 100644 --- a/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md +++ b/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md @@ -485,3 +485,109 @@ To run the LDAP tests on your local with TLS disabled, follow these steps: ```shell GITLAB_LDAP_USERNAME="tanuki" GITLAB_LDAP_PASSWORD="password" QA_DEBUG=true WEBDRIVER_HEADLESS=false bin/qa Test::Instance::All http://localhost qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb ``` + +## Guide to the mobile suite + +### What are mobile tests + +Tests that are tagged with `:mobile` can be run against specified mobile devices using cloud emulator/simulator services. + +### How to run mobile tests with Sauce Labs + +Running directly against an environment like staging is not recommended because Sauce Labs test logs expose credentials. Therefore, it is best practice and the default to use a tunnel. + +Tunnel installation instructions are here [https://docs.saucelabs.com/secure-connections/sauce-connect/installation]. To start the tunnel, after following the installation above, copy the run command in Sauce Labs > Tunnels (must be logged in to Sauce Labs with the credentials found in 1Password) and run in terminal. + +NOTE: +It is highly recommended to use `GITLAB_QA_ACCESS_TOKEN` to speed up tests and reduce flakiness. + +`QA_REMOTE_MOBILE_DEVICE_NAME` can be any device name listed in [https://saucelabs.com/platform/supported-browsers-devices] under Emulators/simulators and the latest versions of Android or iOS. `QA_BROWSER` must be set to `safari` for iOS devices and `chrome` for Android devices. + +1. To test against a local instance with a tunnel running, in `gitlab/qa` run: + +```shell +$ QA_BROWSER="safari" \ + QA_REMOTE_MOBILE_DEVICE_NAME="iPhone 12 Simulator" \ + QA_REMOTE_GRID="ondemand.saucelabs.com:80" \ + QA_REMOTE_GRID_USERNAME="gitlab-sl" \ + QA_REMOTE_GRID_ACCESS_KEY="<found in Sauce Lab account>" \ + GITLAB_QA_ACCESS_TOKEN="<token>" \ + bundle exec bin/qa Test::Instance::All http://<local_ip>:3000 -- <relative_spec_path> +``` + +Results can be watched in real time while logged into Sauce Labs under AUTOMATED > Test Results. + +### How to add an existing test to the mobile suite + +The main reason a test might fail when adding the `:mobile` tag is navigation differences in desktop vs mobile layouts, therefore the test needs to be updated to use mobile navigation when running mobile tests. + +If an existing method needs to be changed or a new one created, a new mobile page object should be created in `qa/qa/mobile/page/` and it should be prepended in the original page object by adding: + +```ruby +prepend Mobile::Page::NewPageObject if Runtime::Env.mobile_layout? +``` + +For example to change an existing method when running mobile tests: + +New mobile page object: + +```ruby +module QA + module Mobile + module Page + module Project + module Show + extend QA::Page::PageConcern + + def self.prepended(base) + super + + base.class_eval do + prepend QA::Mobile::Page::Main::Menu + + view 'app/assets/javascripts/nav/components/top_nav_new_dropdown.vue' do + element :new_issue_mobile_button + end + end + end + + def go_to_new_issue + open_mobile_new_dropdown + + click_element(:new_issue_mobile_button) + end + end + end + end + end +end +``` + +Original page object prepending the new mobile if there's a mobile layout: + +```ruby +module QA + module Page + module Project + class Show < Page::Base + prepend Mobile::Page::Project::Show if Runtime::Env.mobile_layout? + + view 'app/views/layouts/header/_new_dropdown.html.haml' do + element :new_menu_toggle + end + + view 'app/helpers/nav/new_dropdown_helper.rb' do + element :new_issue_link + end + + def go_to_new_issue + click_element(:new_menu_toggle) + click_element(:new_issue_link) + end + end + end + end +end +``` + +When running mobile tests for phone layouts, both `remote_mobile_device_name` and `mobile_layout` are `true` but when using a tablet layout, only `remote_mobile_device_name` is true. This is because phone layouts have more menus closed by default such as how both tablets and phones have the left nav closed but unlike phone layouts, tablets have the regular top navigation bar, not the mobile one. So in the case where the navigation being edited needs to be used in tablet layouts as well, use `remote_mobile_device_name` instead of `mobile_layout?` when prepending so it will use it if it's a tablet layout as well. diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md index 6442ca09b96..46b4ef6c96b 100644 --- a/doc/user/application_security/dependency_scanning/index.md +++ b/doc/user/application_security/dependency_scanning/index.md @@ -360,8 +360,8 @@ always take the latest dependency scanning artifact available. ### Enable Dependency Scanning via an automatic merge request -> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4908) in GitLab 14.1. -> - [Enabled with `sec_dependency_scanning_ui_enable` flag](https://gitlab.com/gitlab-org/gitlab/-/issues/282533) for self-managed GitLab in GitLab 14.1 and is ready for production use. +> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4908) in GitLab 14.1 [with a flag](../../../administration/feature_flags.md) named `sec_dependency_scanning_ui_enable`. Enabled by default. +> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/282533) in GitLab 14.1. > - [Feature flag sec_dependency_scanning_ui_enable removed](https://gitlab.com/gitlab-org/gitlab/-/issues/326005) in GitLab 14.2. To enable Dependency Scanning in a project, you can create a merge request diff --git a/doc/user/clusters/agent/index.md b/doc/user/clusters/agent/index.md index b9e7932e16a..efc07b32725 100644 --- a/doc/user/clusters/agent/index.md +++ b/doc/user/clusters/agent/index.md @@ -203,7 +203,7 @@ specified the `kas-address` correctly. ``` This error occurs if the `kas-address` doesn't include a trailing slash. To fix it, make sure that the -`wss` or `ws` URL ends with a training slash, such as `wss://GitLab.host.tld:443/-/kubernetes-agent/` +`wss` or `ws` URL ends with a trailing slash, such as `wss://GitLab.host.tld:443/-/kubernetes-agent/` or `ws://GitLab.host.tld:80/-/kubernetes-agent/`. #### ValidationError(Deployment.metadata) diff --git a/qa/qa/flow/login.rb b/qa/qa/flow/login.rb index 05a509588f1..5f7e0227ac5 100644 --- a/qa/qa/flow/login.rb +++ b/qa/qa/flow/login.rb @@ -23,8 +23,11 @@ module QA end def sign_in(as: nil, address: :gitlab, skip_page_validation: false, admin: false) - Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform(&:signed_in?) - Runtime::Browser.visit(address, Page::Main::Login) + unless Page::Main::Login.perform(&:on_login_page?) + Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform(&:signed_in?) + Runtime::Browser.visit(address, Page::Main::Login) + end + Page::Main::Login.perform do |login| if admin login.sign_in_using_admin_credentials diff --git a/qa/qa/mobile/page/main/menu.rb b/qa/qa/mobile/page/main/menu.rb new file mode 100644 index 00000000000..40bb421b383 --- /dev/null +++ b/qa/qa/mobile/page/main/menu.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module QA + module Mobile + module Page + module Main + module Menu + extend QA::Page::PageConcern + + def self.prepended(base) + super + + base.class_eval do + view 'app/views/layouts/header/_default.html.haml' do + element :mobile_navbar_button, required: true + end + + view 'app/assets/javascripts/nav/components/responsive_home.vue' do + element :mobile_new_dropdown + end + end + end + + def open_mobile_menu + if has_no_element?(:user_avatar) + Support::Retrier.retry_until do + click_element(:mobile_navbar_button) + has_element?(:user_avatar) + end + end + end + + def open_mobile_new_dropdown + open_mobile_menu + + Support::Retrier.retry_until do + find('[data-qa-selector="mobile_new_dropdown"] > button').click + has_css?('.dropdown-menu-right.show') + end + end + + def has_personal_area?(wait: Capybara.default_max_wait_time) + open_mobile_menu + super + end + + def has_no_personal_area?(wait: Capybara.default_max_wait_time) + open_mobile_menu + super + end + + def within_user_menu + open_mobile_menu + super + end + end + end + end + end +end diff --git a/qa/qa/mobile/page/profile/menu.rb b/qa/qa/mobile/page/profile/menu.rb new file mode 100644 index 00000000000..34c53a95e03 --- /dev/null +++ b/qa/qa/mobile/page/profile/menu.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module QA + module Mobile + module Page + module Profile + module Menu + extend QA::Page::PageConcern + + def self.prepended(base) + super + + base.class_eval do + prepend QA::Mobile::Page::Main::Menu + end + end + + def within_sidebar + open_mobile_nav_sidebar + super + end + end + end + end + end +end diff --git a/qa/qa/mobile/page/project/issue/show.rb b/qa/qa/mobile/page/project/issue/show.rb new file mode 100644 index 00000000000..017ecebcb69 --- /dev/null +++ b/qa/qa/mobile/page/project/issue/show.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module QA + module Mobile + module Page + module Project + module Issue + module Show + extend QA::Page::PageConcern + + def self.prepended(base) + super + + base.class_eval do + view 'app/assets/javascripts/issue_show/components/header_actions.vue' do + element :issue_actions_dropdown + element :mobile_close_issue_button + element :mobile_reopen_issue_button + end + end + end + + def click_close_issue_button + find('[data-qa-selector="issue_actions_dropdown"] > button').click + find_element(:mobile_close_issue_button, visible: false).click + end + + def has_reopen_issue_button? + find('[data-qa-selector="issue_actions_dropdown"] > button').click + has_element?(:mobile_reopen_issue_button) + end + end + end + end + end + end +end diff --git a/qa/qa/mobile/page/project/show.rb b/qa/qa/mobile/page/project/show.rb new file mode 100644 index 00000000000..8a0a222c852 --- /dev/null +++ b/qa/qa/mobile/page/project/show.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module QA + module Mobile + module Page + module Project + module Show + extend QA::Page::PageConcern + + def self.prepended(base) + super + + base.class_eval do + prepend QA::Mobile::Page::Main::Menu + + view 'app/assets/javascripts/nav/components/top_nav_new_dropdown.vue' do + element :new_issue_mobile_button + end + end + end + + def go_to_new_issue + open_mobile_new_dropdown + + click_element(:new_issue_mobile_button) + end + end + end + end + end +end diff --git a/qa/qa/mobile/page/sub_menus/common.rb b/qa/qa/mobile/page/sub_menus/common.rb new file mode 100644 index 00000000000..6a0477a3f31 --- /dev/null +++ b/qa/qa/mobile/page/sub_menus/common.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module QA + module Mobile + module Page + module SubMenus + module Common + def open_mobile_nav_sidebar + if has_element?(:project_sidebar, visible: false) + Support::Retrier.retry_until do + click_element(:toggle_mobile_nav_button) + has_element?(:project_sidebar, visible: true) + end + end + end + + def within_sidebar + wait_for_requests + + open_mobile_nav_sidebar + + super + end + end + end + end + end +end diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb index c3170478733..5cba9d4bce4 100644 --- a/qa/qa/page/main/login.rb +++ b/qa/qa/page/main/login.rb @@ -45,6 +45,10 @@ module QA has_element?(:sign_in_button) end + def on_login_page? + has_element?(:login_page, wait: 0) + end + def sign_in_using_credentials(user: nil, skip_page_validation: false) # Don't try to log-in if we're already logged-in return if Page::Main::Menu.perform(&:signed_in?) @@ -164,6 +168,8 @@ module QA fill_element :password_field, user.password click_element :sign_in_button + Support::WaitForRequests.wait_for_requests + Page::Main::Terms.perform do |terms| terms.accept_terms if terms.visible? end diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index ad5cd971afc..e3bb585955b 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -4,6 +4,8 @@ module QA module Page module Main class Menu < Page::Base + prepend Mobile::Page::Main::Menu if Runtime::Env.mobile_layout? + view 'app/views/layouts/header/_current_user_dropdown.html.haml' do element :sign_out_link element :edit_profile_link @@ -12,12 +14,12 @@ module QA view 'app/views/layouts/header/_default.html.haml' do element :navbar, required: true element :canary_badge_link - element :user_avatar, required: true - element :user_menu, required: true + element :user_avatar, required: !QA::Runtime::Env.mobile_layout? + element :user_menu, required: !QA::Runtime::Env.mobile_layout? element :stop_impersonation_link - element :issues_shortcut_button, required: true - element :merge_requests_shortcut_button, required: true - element :todos_shortcut_button, required: true + element :issues_shortcut_button, required: !QA::Runtime::Env.mobile_layout? + element :merge_requests_shortcut_button, required: !QA::Runtime::Env.mobile_layout? + element :todos_shortcut_button, required: !QA::Runtime::Env.mobile_layout? end view 'app/assets/javascripts/nav/components/top_nav_app.vue' do @@ -98,10 +100,14 @@ module QA end def signed_in? + return false if Page::Main::Login.perform(&:on_login_page?) + has_personal_area?(wait: 0) end def not_signed_in? + return true if Page::Main::Login.perform(&:on_login_page?) + has_no_personal_area? end @@ -115,7 +121,7 @@ module QA click_element :sign_out_link end - has_no_element?(:user_avatar) + not_signed_in? end end diff --git a/qa/qa/page/profile/menu.rb b/qa/qa/page/profile/menu.rb index a12db2918dc..d638a378610 100644 --- a/qa/qa/page/profile/menu.rb +++ b/qa/qa/page/profile/menu.rb @@ -4,6 +4,10 @@ module QA module Page module Profile class Menu < Page::Base + # We need to check remote_mobile_device_name instead of mobile_layout? here + # since tablets have the regular top navigation bar but still close the left nav + prepend QA::Mobile::Page::Profile::Menu if QA::Runtime::Env.remote_mobile_device_name + view 'app/views/layouts/nav/sidebar/_profile.html.haml' do element :access_token_link, 'link_to profile_personal_access_tokens_path' # rubocop:disable QA/ElementWithPattern element :access_token_title, 'Access Tokens' # rubocop:disable QA/ElementWithPattern diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb index 7a5a153db86..3b033830420 100644 --- a/qa/qa/page/project/issue/show.rb +++ b/qa/qa/page/project/issue/show.rb @@ -9,6 +9,7 @@ module QA include Page::Component::Note include Page::Component::DesignManagement include Page::Component::Issuable::Sidebar + prepend Mobile::Page::Project::Issue::Show if Runtime::Env.mobile_layout? view 'app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue' do element :remove_related_issue_button @@ -64,6 +65,10 @@ module QA def has_metrics_unfurled? has_element?(:prometheus_graph_widgets, wait: 30) end + + def has_reopen_issue_button? + has_element?(:reopen_issue_button) + end end end end diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index 6e5097c3812..18a29f518dd 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -9,6 +9,7 @@ module QA include Page::Component::Breadcrumbs include Page::Project::SubMenus::Settings include Page::File::Shared::CommitMessage + prepend Mobile::Page::Project::Show if Runtime::Env.mobile_layout? view 'app/assets/javascripts/repository/components/preview/index.vue' do element :blob_viewer_content @@ -117,7 +118,7 @@ module QA end def go_to_new_issue - click_element :new_menu_toggle + click_element(:new_menu_toggle) click_element(:new_issue_link) end diff --git a/qa/qa/page/project/sub_menus/common.rb b/qa/qa/page/project/sub_menus/common.rb index c20710bc393..112f49a90ee 100644 --- a/qa/qa/page/project/sub_menus/common.rb +++ b/qa/qa/page/project/sub_menus/common.rb @@ -19,6 +19,10 @@ module QA view 'app/views/shared/nav/_sidebar_menu.html.haml' do element :sidebar_menu_link end + + view 'app/views/layouts/nav/_breadcrumbs.html.haml' do + element :toggle_mobile_nav_button + end end end diff --git a/qa/qa/page/sub_menus/common.rb b/qa/qa/page/sub_menus/common.rb index 2efeeb062e8..518b3b4e84e 100644 --- a/qa/qa/page/sub_menus/common.rb +++ b/qa/qa/page/sub_menus/common.rb @@ -4,6 +4,10 @@ module QA module Page module SubMenus module Common + # We need to check remote_mobile_device_name instead of mobile_layout? here + # since tablets have the regular top navigation bar but still close the left nav + prepend Mobile::Page::SubMenus::Common if QA::Runtime::Env.remote_mobile_device_name + def hover_element(element) within_sidebar do find_element(element).hover diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index 0566bc237bb..44153eb4104 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -205,6 +205,9 @@ module QA simulate_slow_connection if Runtime::Env.simulate_slow_connection? + # Wait until the new page is ready for us to interact with it + Support::WaitForRequests.wait_for_requests + page_class.validate_elements_present! if page_class.respond_to?(:validate_elements_present!) if QA::Runtime::Env.qa_cookies diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index cdfa95457c7..be641cc283a 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -153,6 +153,12 @@ module QA ENV['QA_REMOTE_MOBILE_DEVICE_NAME'] end + def mobile_layout? + return false if ENV['QA_REMOTE_MOBILE_DEVICE_NAME'].blank? + + !(ENV['QA_REMOTE_MOBILE_DEVICE_NAME'].downcase.include?('ipad') || ENV['QA_REMOTE_MOBILE_DEVICE_NAME'].downcase.include?('tablet')) + end + def user_username ENV['GITLAB_USERNAME'] end diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb index ca95d567316..9625771164c 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :smoke do + RSpec.describe 'Manage', :smoke, :mobile do describe 'basic user login' do it 'user logs in using basic credentials and logs out', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1578' do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb index 7519f4daae2..81ae8b82ef6 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb @@ -9,7 +9,7 @@ module QA Flow::Login.sign_in end - it 'creates an issue', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1185' do + it 'creates an issue', :mobile, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1185' do issue = Resource::Issue.fabricate_via_browser_ui! Page::Project::Menu.perform(&:click_issues) @@ -19,13 +19,13 @@ module QA end end - it 'closes an issue', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1222' do + it 'closes an issue', :mobile, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1222' do closed_issue.visit! Page::Project::Issue::Show.perform do |issue_page| issue_page.click_close_issue_button - expect(issue_page).to have_element(:reopen_issue_button) + expect(issue_page).to have_reopen_issue_button end Page::Project::Menu.perform(&:click_issues) diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh index 2aec8a67734..7ac6b98938f 100644 --- a/scripts/rspec_helpers.sh +++ b/scripts/rspec_helpers.sh @@ -196,8 +196,8 @@ function rspec_rerun_previous_failed_tests() { local test_file_count=$(wc -w "${matching_tests_file}" | awk {'print $1'}) if [[ "${test_file_count}" -gt "${test_file_count_threshold}" ]]; then - echo "This job is intentionally failed because there are more than ${test_file_count_threshold} test files to rerun." - exit 1 + echo "This job is intentionally exited because there are more than ${test_file_count_threshold} test files to rerun." + exit 0 fi if [[ -n $test_files ]]; then diff --git a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap index 31fb6addcac..db9684239a1 100644 --- a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap +++ b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap @@ -4,9 +4,17 @@ exports[`Blob Header Default Actions rendering matches the snapshot 1`] = ` <div class="js-file-title file-title-flex-parent" > - <blob-filepath-stub - blob="[object Object]" - /> + <div + class="gl-display-flex" + > + <table-of-contents-stub + class="gl-pr-2" + /> + + <blob-filepath-stub + blob="[object Object]" + /> + </div> <div class="gl-display-none gl-sm-display-flex" diff --git a/spec/frontend/blob/components/blob_header_spec.js b/spec/frontend/blob/components/blob_header_spec.js index f841785be42..bd81b1594bf 100644 --- a/spec/frontend/blob/components/blob_header_spec.js +++ b/spec/frontend/blob/components/blob_header_spec.js @@ -3,6 +3,7 @@ import BlobHeader from '~/blob/components/blob_header.vue'; import DefaultActions from '~/blob/components/blob_header_default_actions.vue'; import BlobFilepath from '~/blob/components/blob_header_filepath.vue'; import ViewerSwitcher from '~/blob/components/blob_header_viewer_switcher.vue'; +import TableContents from '~/blob/components/table_contents.vue'; import { Blob } from './mock_data'; @@ -43,6 +44,7 @@ describe('Blob Header Default Actions', () => { it('renders all components', () => { createComponent(); + expect(wrapper.find(TableContents).exists()).toBe(true); expect(wrapper.find(ViewerSwitcher).exists()).toBe(true); expect(findDefaultActions().exists()).toBe(true); expect(wrapper.find(BlobFilepath).exists()).toBe(true); diff --git a/spec/frontend/blob/components/table_contents_spec.js b/spec/frontend/blob/components/table_contents_spec.js index 09633dc5d5d..ade35d39b4f 100644 --- a/spec/frontend/blob/components/table_contents_spec.js +++ b/spec/frontend/blob/components/table_contents_spec.js @@ -32,10 +32,30 @@ describe('Markdown table of contents component', () => { }); describe('not loaded', () => { + const findDropdownItem = () => wrapper.findComponent(GlDropdownItem); + it('does not populate dropdown', () => { createComponent(); - expect(wrapper.findComponent(GlDropdownItem).exists()).toBe(false); + expect(findDropdownItem().exists()).toBe(false); + }); + + it('does not show dropdown when loading blob content', async () => { + createComponent(); + + await setLoaded(false); + + expect(findDropdownItem().exists()).toBe(false); + }); + + it('does not show dropdown when viewing non-rich content', async () => { + createComponent(); + + document.querySelector('.blob-viewer').setAttribute('data-type', 'simple'); + + await setLoaded(true); + + expect(findDropdownItem().exists()).toBe(false); }); }); diff --git a/spec/requests/api/graphql/mutations/issues/create_spec.rb b/spec/requests/api/graphql/mutations/issues/create_spec.rb index 886f3140086..6baed352b37 100644 --- a/spec/requests/api/graphql/mutations/issues/create_spec.rb +++ b/spec/requests/api/graphql/mutations/issues/create_spec.rb @@ -48,5 +48,9 @@ RSpec.describe 'Create an issue' do expect(mutation_response['issue']).to include('discussionLocked' => true) expect(Issue.last.work_item_type.base_type).to eq('issue') end + + it_behaves_like 'has spam protection' do + let(:mutation_class) { ::Mutations::Issues::Create } + end end end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 78646665539..c78e19ea62d 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -5,8 +5,8 @@ require 'spec_helper' RSpec.describe Ci::CreatePipelineService do include ProjectForksHelper - let_it_be(:project, reload: true) { create(:project, :repository) } - let_it_be(:user, reload: true) { project.owner } + let_it_be_with_refind(:project) { create(:project, :repository) } + let_it_be_with_reload(:user) { project.owner } let(:ref_name) { 'refs/heads/master' } diff --git a/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb b/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb index 2b810e790f0..e1d864213b5 100644 --- a/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb +++ b/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb @@ -38,6 +38,11 @@ RSpec.shared_context 'stubbed service ping metrics definitions' do ) end + after do |example| + Gitlab::Usage::Metric.instance_variable_set(:@all, nil) + Gitlab::Usage::MetricDefinition.instance_variable_set(:@all, nil) + end + def metric_attributes(key_path, category, value_type = 'string') { 'key_path' => key_path, |