diff --git a/.gitlab/merge_request_templates/Quarantine End to End Test.md b/.gitlab/merge_request_templates/Quarantine End to End Test.md
index 5794a62df96..772167af3e9 100644
--- a/.gitlab/merge_request_templates/Quarantine End to End Test.md
+++ b/.gitlab/merge_request_templates/Quarantine End to End Test.md
@@ -21,7 +21,7 @@ the noise (due to constantly failing tests, flaky tests, and so on) so that new
- [ ] Quarantine test check-list
- [ ] Follow the [Quarantining Tests guide](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests).
- [ ] Confirm the test has a [`quarantine:` tag with the specified quarantine type](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantined-test-types).
- - [ ] Note if the test should be [quarantined for a specific environment](https://docs.gitlab.com/ee/development/testing_guide/end_to_end/environment_selection.html#quarantining-a-test-for-a-specific-environment).
+ - [ ] Note if the test should be [quarantined for a specific environment](https://docs.gitlab.com/ee/development/testing_guide/end_to_end/execution_context_selection.html#quarantine-a-test-for-a-specific-environment).
- [ ] Dequarantine test check-list
- [ ] Follow the [Dequarantining Tests guide](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#dequarantining-tests).
- [ ] Confirm the test consistently passes on the target GitLab environment(s).
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
index ff081552ef2..ea45b5e3ec7 100644
--- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
@@ -162,8 +162,10 @@ export default {
diff --git a/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb b/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb
new file mode 100644
index 00000000000..090a9a4e0ef
--- /dev/null
+++ b/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Security
+ module CiConfiguration
+ class BaseSecurityAnalyzer < BaseMutation
+ include FindsProject
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'Full path of the project.'
+
+ field :success_path, GraphQL::STRING_TYPE, null: true,
+ description: 'Redirect path to use when the response is successful.'
+
+ field :branch, GraphQL::STRING_TYPE, null: true,
+ description: 'Branch that has the new/modified `.gitlab-ci.yml` file.'
+
+ authorize :push_code
+
+ def resolve(project_path:, **args)
+ project = authorized_find!(project_path)
+
+ result = configure_analyzer(project, **args)
+ prepare_response(result)
+ end
+
+ private
+
+ def configure_analyzer(project, **args)
+ raise NotImplementedError
+ end
+
+ def prepare_response(result)
+ {
+ branch: result.payload[:branch],
+ success_path: result.payload[:success_path],
+ errors: result.errors
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/security/ci_configuration/configure_sast.rb b/app/graphql/mutations/security/ci_configuration/configure_sast.rb
index 237aff1f052..7ce0bf83a4b 100644
--- a/app/graphql/mutations/security/ci_configuration/configure_sast.rb
+++ b/app/graphql/mutations/security/ci_configuration/configure_sast.rb
@@ -3,9 +3,7 @@
module Mutations
module Security
module CiConfiguration
- class ConfigureSast < BaseMutation
- include FindsProject
-
+ class ConfigureSast < BaseSecurityAnalyzer
graphql_name 'ConfigureSast'
description <<~DESC
Configure SAST for a project by enabling SAST in a new or modified
@@ -13,37 +11,12 @@ module Mutations
create a Merge Request are a part of the response.
DESC
- argument :project_path, GraphQL::ID_TYPE,
- required: true,
- description: 'Full path of the project.'
-
argument :configuration, ::Types::CiConfiguration::Sast::InputType,
required: true,
description: 'SAST CI configuration for the project.'
- field :success_path, GraphQL::STRING_TYPE, null: true,
- description: 'Redirect path to use when the response is successful.'
-
- field :branch, GraphQL::STRING_TYPE, null: true,
- description: 'Branch that has the new/modified `.gitlab-ci.yml` file.'
-
- authorize :push_code
-
- def resolve(project_path:, configuration:)
- project = authorized_find!(project_path)
-
- result = ::Security::CiConfiguration::SastCreateService.new(project, current_user, configuration).execute
- prepare_response(result)
- end
-
- private
-
- def prepare_response(result)
- {
- branch: result.payload[:branch],
- success_path: result.payload[:success_path],
- errors: result.errors
- }
+ def configure_analyzer(project, **args)
+ ::Security::CiConfiguration::SastCreateService.new(project, current_user, args[:configuration]).execute
end
end
end
diff --git a/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb b/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb
index 32ad670edaa..54322babb26 100644
--- a/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb
+++ b/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb
@@ -3,9 +3,7 @@
module Mutations
module Security
module CiConfiguration
- class ConfigureSecretDetection < BaseMutation
- include FindsProject
-
+ class ConfigureSecretDetection < BaseSecurityAnalyzer
graphql_name 'ConfigureSecretDetection'
description <<~DESC
Configure Secret Detection for a project by enabling Secret Detection
@@ -14,33 +12,8 @@ module Mutations
response.
DESC
- argument :project_path, GraphQL::ID_TYPE,
- required: true,
- description: 'Full path of the project.'
-
- field :success_path, GraphQL::STRING_TYPE, null: true,
- description: 'Redirect path to use when the response is successful.'
-
- field :branch, GraphQL::STRING_TYPE, null: true,
- description: 'Branch that has the new/modified `.gitlab-ci.yml` file.'
-
- authorize :push_code
-
- def resolve(project_path:)
- project = authorized_find!(project_path)
-
- result = ::Security::CiConfiguration::SecretDetectionCreateService.new(project, current_user).execute
- prepare_response(result)
- end
-
- private
-
- def prepare_response(result)
- {
- branch: result.payload[:branch],
- success_path: result.payload[:success_path],
- errors: result.errors
- }
+ def configure_analyzer(project, **_args)
+ ::Security::CiConfiguration::SecretDetectionCreateService.new(project, current_user).execute
end
end
end
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb
index ce2f184bcb4..75fdb41ceb6 100644
--- a/app/graphql/types/base_field.rb
+++ b/app/graphql/types/base_field.rb
@@ -95,7 +95,15 @@ module Types
end
def feature_documentation_message(key, description)
- "#{description} Available only when feature flag `#{key}` is enabled."
+ message_parts = ["#{description} Available only when feature flag `#{key}` is enabled."]
+
+ message_parts << if Feature::Definition.has_definition?(key) && Feature::Definition.default_enabled?(key)
+ "This flag is enabled by default."
+ else
+ "This flag is disabled by default, because the feature is experimental and is subject to change without notice."
+ end
+
+ message_parts.join(' ')
end
def check_feature_flag(args)
diff --git a/app/views/groups/settings/_pages_settings.html.haml b/app/views/groups/settings/_pages_settings.html.haml
index a7b1813e4f1..456e0b0f1d0 100644
--- a/app/views/groups/settings/_pages_settings.html.haml
+++ b/app/views/groups/settings/_pages_settings.html.haml
@@ -2,4 +2,4 @@
= render_if_exists 'shared/pages/max_pages_size_input', form: f
.gl-mt-3
- = f.submit s_('GitLabPages|Save'), class: 'btn gl-button btn-confirm'
+ = f.submit s_('GitLabPages|Save changes'), class: 'btn gl-button btn-confirm'
diff --git a/app/views/layouts/nav/sidebar/_group_scope_menu.html.haml b/app/views/layouts/nav/sidebar/_group_scope_menu.html.haml
deleted file mode 100644
index 57c0663f3ae..00000000000
--- a/app/views/layouts/nav/sidebar/_group_scope_menu.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-= nav_link(path: ['groups#show', 'groups#details'], html_options: { class: 'context-header' }) do
- = link_to group_path(@group), title: @group.name, data: { qa_selector: 'group_scope_link' } do
- %span{ class: ['avatar-container', 'rect-avatar', 'group-avatar' , 's32'] }
- = group_icon(@group, class: ['avatar', 'avatar-tile', 's32'])
- %span.sidebar-context-title
- = @group.name
diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml
index 66fc313213a..55696337bc1 100644
--- a/app/views/projects/_new_project_fields.html.haml
+++ b/app/views/projects/_new_project_fields.html.haml
@@ -23,7 +23,7 @@
display_path: true,
extra_group: namespace_id),
{},
- { class: 'select2 js-select-namespace qa-project-namespace-select block-truncated', data: { track_label: "#{track_label}", track_event: "activate_form_input", track_property: "project_path", track_value: "" }})
+ { class: 'select2 js-select-namespace qa-project-namespace-select block-truncated', data: { track_label: "#{track_label}", track_event: "activate_form_input", track_property: "project_path", track_value: "", qa_selector: "select_namespace_dropdown" }})
- else
.input-group-prepend.static-namespace.flex-shrink-0.has-tooltip{ title: user_url(current_user.username) + '/' }
diff --git a/app/views/projects/default_branch/_show.html.haml b/app/views/projects/default_branch/_show.html.haml
index 9e9fc08dac0..68ca318e88c 100644
--- a/app/views/projects/default_branch/_show.html.haml
+++ b/app/views/projects/default_branch/_show.html.haml
@@ -17,7 +17,7 @@
- else
.form-group
= f.label :default_branch, "Default branch", class: 'label-bold'
- = f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'})
+ = f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide', data: { qa_selector: 'default_branch_dropdown' }})
.form-group
.form-check
@@ -28,4 +28,4 @@
= _("When merge requests and commits in the default branch close, any issues they reference also close.")
= link_to sprite_icon('question-o'), help_page_path('user/project/issues/managing_issues.md', anchor: 'disabling-automatic-issue-closing'), target: '_blank'
- = f.submit _('Save changes'), class: "gl-button btn btn-confirm"
+ = f.submit _('Save changes'), class: "gl-button btn btn-confirm", data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/projects/pages/_pages_settings.html.haml b/app/views/projects/pages/_pages_settings.html.haml
index 483f192109b..2db44528d51 100644
--- a/app/views/projects/pages/_pages_settings.html.haml
+++ b/app/views/projects/pages/_pages_settings.html.haml
@@ -1,5 +1,8 @@
= form_for @project, url: project_pages_path(@project), html: { class: 'inline', title: pages_https_only_title } do |f|
- = render_if_exists 'shared/pages/max_pages_size_input', form: f
+ - if can?(current_user, :update_max_pages_size)
+ = render_if_exists 'shared/pages/max_pages_size_input', form: f
+ .gl-mt-3
+ = f.submit s_('GitLabPages|Save changes'), class: 'btn btn-confirm gl-button'
- if Gitlab.config.pages.external_http || Gitlab.config.pages.external_https
@@ -15,4 +18,4 @@
= s_("GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}").html_safe % { docs_link_start: docs_link_start, link_end: link_end }
.gl-mt-3
- = f.submit s_('GitLabPages|Save'), class: 'btn btn-confirm gl-button'
+ = f.submit s_('GitLabPages|Save changes'), class: 'btn btn-confirm gl-button'
diff --git a/config/routes/project.rb b/config/routes/project.rb
index b3a6173bb78..65cdb8bba96 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -547,12 +547,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
- # TODO: Deprecated. This should be removed in 14.2.
- scope :usage_ping, controller: :service_ping do
- post :web_ide_clientside_preview # rubocop:todo Cop/PutProjectRoutesUnderScope
- post :web_ide_pipelines_count # rubocop:todo Cop/PutProjectRoutesUnderScope
- end
-
scope :service_ping, controller: :service_ping do
post :web_ide_clientside_preview # rubocop:todo Cop/PutProjectRoutesUnderScope
post :web_ide_pipelines_count # rubocop:todo Cop/PutProjectRoutesUnderScope
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index 8d531e657c1..ea1e99524b8 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -662,24 +662,27 @@ Follow the steps below to configure the proxy listener of GitLab Pages.
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
-### Override maximum pages size per project or group **(PREMIUM SELF)**
+## Override maximum pages size per project or group **(PREMIUM SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16610) in GitLab 12.7.
NOTE:
-Only GitLab admin users are able to view and override the **Maximum size of Pages** setting.
+Only GitLab administrators are able to view and override the **Maximum size of Pages** setting.
To override the global maximum pages size for a specific project:
-1. Go to your project's **Settings > Pages** page.
-1. Edit the **Maximum size of pages**.
-1. Click **Save changes**.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Pages**.
+1. Enter a value under **Maximum size of pages** in MB.
+1. Select **Save changes**.
To override the global maximum pages size for a specific group:
-1. Go to your group's **Settings > General** page and expand **Pages**.
-1. Edit the **Maximum size of pages**.
-1. Click **Save changes**.
+1. On the top bar, select **Menu > Groups** and find your group.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Pages**.
+1. Enter a value under **Maximum size of pages** in MB.
+1. Select **Save changes**.
## Running GitLab Pages on a separate server
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index ca924255154..8d622371257 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -294,7 +294,7 @@ Returns [`QueryComplexity`](#querycomplexity).
### `Query.runner`
-Find a runner. Available only when feature flag `runner_graphql_query` is enabled.
+Find a runner. Available only when feature flag `runner_graphql_query` is enabled. This flag is enabled by default.
Returns [`CiRunner`](#cirunner).
@@ -331,7 +331,7 @@ Returns [`RunnerSetup`](#runnersetup).
### `Query.runners`
-Find runners visible to the current user. Available only when feature flag `runner_graphql_query` is enabled.
+Find runners visible to the current user. Available only when feature flag `runner_graphql_query` is enabled. This flag is enabled by default.
Returns [`CiRunnerConnection`](#cirunnerconnection).
@@ -1121,7 +1121,7 @@ Input type: `CreateComplianceFrameworkInput`
### `Mutation.createCustomEmoji`
-Available only when feature flag `custom_emoji` is enabled.
+Available only when feature flag `custom_emoji` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice.
Input type: `CreateCustomEmojiInput`
@@ -3618,7 +3618,7 @@ Input type: `RepositionImageDiffNoteInput`
### `Mutation.runnerDelete`
-Available only when feature flag `runner_graphql_query` is enabled.
+Available only when feature flag `runner_graphql_query` is enabled. This flag is enabled by default.
Input type: `RunnerDeleteInput`
@@ -3638,7 +3638,7 @@ Input type: `RunnerDeleteInput`
### `Mutation.runnerUpdate`
-Available only when feature flag `runner_graphql_query` is enabled.
+Available only when feature flag `runner_graphql_query` is enabled. This flag is enabled by default.
Input type: `RunnerUpdateInput`
@@ -3668,7 +3668,7 @@ Input type: `RunnerUpdateInput`
### `Mutation.runnersRegistrationTokenReset`
-Available only when feature flag `runner_graphql_query` is enabled.
+Available only when feature flag `runner_graphql_query` is enabled. This flag is enabled by default.
Input type: `RunnersRegistrationTokenResetInput`
@@ -8552,7 +8552,7 @@ Snapshot.
| `recordedAt` | [`Time!`](#time) | The time the snapshot was recorded. |
| `runnerConfigured` | [`Boolean!`](#boolean) | At least one runner was used. |
| `sastEnabledCount` | [`Int`](#int) | Total number of projects with enabled SAST. |
-| `securityScanSucceeded` | [`Boolean!`](#boolean) | At least one security scan succeeded. |
+| `securityScanSucceeded` **{warning-solid}** | [`Boolean!`](#boolean) | **Deprecated** in 14.1. Substituted with specific security metrics. Always false. |
| `startTime` | [`Time!`](#time) | The start time for the snapshot where the data points were collected. |
| `totalProjectsCount` | [`Int`](#int) | Total number of projects. |
| `vulnerabilityManagementUsedCount` | [`Int`](#int) | Total number of projects with vulnerability management used at least once. |
@@ -9271,7 +9271,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| `billableMembersCount` | [`Int`](#int) | The number of billable users in the group. |
| `containerRepositoriesCount` | [`Int!`](#int) | Number of container repositories in the group. |
| `containsLockedProjects` | [`Boolean!`](#boolean) | Includes at least one project where the repository size exceeds the limit. |
-| `customEmoji` | [`CustomEmojiConnection`](#customemojiconnection) | Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled. (see [Connections](#connections)) |
+| `customEmoji` | [`CustomEmojiConnection`](#customemojiconnection) | Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice. (see [Connections](#connections)) |
| `description` | [`String`](#string) | Description of the namespace. |
| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. |
| `dora` | [`Dora`](#dora) | The group's DORA metrics. |
diff --git a/doc/development/testing_guide/end_to_end/environment_selection.md b/doc/development/testing_guide/end_to_end/environment_selection.md
index 02d8e0513a3..2192d9c4ed4 100644
--- a/doc/development/testing_guide/end_to_end/environment_selection.md
+++ b/doc/development/testing_guide/end_to_end/environment_selection.md
@@ -1,89 +1,8 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+redirect_to: 'execution_context_selection.md'
---
-# Environment selection
+This file was moved to [another location](execution_context_selection.md).
-Some tests are designed to be run against specific environments or [pipelines](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#scheduled-qa-test-pipelines).
-We can specify what environments or pipelines to run tests against using the `only` metadata.
-
-## Available switches
-
-| Switch | Function | Type |
-| -------| ------- | ----- |
-| `tld` | Set the top-level domain matcher | `String` |
-| `subdomain` | Set the subdomain matcher | `Array` or `String` |
-| `domain` | Set the domain matcher | `String` |
-| `production` | Match against production | `Static` |
-| `pipeline` | Match against a pipeline | `Array` or `Static`|
-
-WARNING:
-You cannot specify `:production` and `{ : 'value' }` simultaneously.
-These options are mutually exclusive. If you want to specify production, you
-can control the `tld` and `domain` independently.
-
-## Examples
-
-| Environment or pipeline | Key | Matches (regex for environments, string matching for pipelines) |
-| ---------------- | --- | --------------- |
-| `any` | `` | `.+.com` |
-| `gitlab.com` | `only: :production` | `gitlab.com` |
-| `staging.gitlab.com` | `only: { subdomain: :staging }` | `(staging).+.com` |
-| `gitlab.com and staging.gitlab.com` | `only: { subdomain: /(staging.)?/, domain: 'gitlab' }` | `(staging.)?gitlab.com` |
-| `dev.gitlab.org` | `only: { tld: '.org', domain: 'gitlab', subdomain: 'dev' }` | `(dev).gitlab.org` |
-| `staging.gitlab.com & domain.gitlab.com` | `only: { subdomain: %i[staging domain] }` | `(staging|domain).+.com` |
-| `nightly` | `only: { pipeline: :nightly }` | "nightly" |
-| `nightly`, `canary` | `only: { pipeline: [:nightly, :canary] }` | ["nightly"](https://gitlab.com/gitlab-org/quality/nightly) and ["canary"](https://gitlab.com/gitlab-org/quality/canary) |
-
-```ruby
-RSpec.describe 'Area' do
- it 'runs in any environment or pipeline' do; end
-
- it 'runs only in production environment', only: :production do; end
-
- it 'runs only in staging environment', only: { subdomain: :staging } do; end
-
- it 'runs in dev environment', only: { tld: '.org', domain: 'gitlab', subdomain: 'dev' } do; end
-
- it 'runs in prod and staging environments', only: { subdomain: /(staging.)?/, domain: 'gitlab' } {}
-
- it 'runs only in nightly pipeline', only: { pipeline: :nightly } do; end
-
- it 'runs in nightly and canary pipelines', only: { pipeline: [:nightly, :canary] } do; end
-end
-```
-
-If the test has a `before` or `after`, you must add the `only` metadata
-to the outer `RSpec.describe`.
-
-If you want to run an `only: { :pipeline }` tagged test on your local GDK make sure either the `CI_PROJECT_NAME` CI/CD variable is unset, or that the `CI_PROJECT_NAME` variable matches the specified pipeline in the `only: { :pipeline }` tag, or just delete the `only: { :pipeline }` tag.
-
-## Quarantining a test for a specific environment
-
-Similarly to specifying that a test should only run against a specific environment, it's also possible to quarantine a
-test only when it runs against a specific environment. The syntax is exactly the same, except that the `only: { ... }`
-hash is nested in the [`quarantine: { ... }`](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests) hash.
-For instance, `quarantine: { only: { subdomain: :staging } }` only quarantines the test when run against staging.
-
-## Excluding a test from running in a particular job
-
-Sometimes we need to skip a test in a particular job but allow it to run in other jobs of the same pipeline or environment.
-We can do it with the help of `exclude` metadata.
-
-Examples:
-
-```ruby
-RSpec.describe 'Excluding' do
- it 'skips given a single named job', exclude: { job: 'ee:instance-image' } do; end
-
- it 'skips given a single regex pattern', exclude: { job: '.*:instance-image' } do; end
-
- it 'skips given an array of jobs', exclude: { job: %w[ee:instance-image qa-schedules-browser_ui-3_create] } do; end
-
- it 'skips given an array of regex patterns', exclude: { job: %w[ee:.* qa-schedules-browser_ui.*] } do; end
-
- it 'skips given a mix of strings and regex patterns', exclude: { job: %w[ee:instance-image qa-schedules-browser_ui.*] } do; end
-end
-```
+
+
diff --git a/doc/development/testing_guide/end_to_end/execution_context_selection.md b/doc/development/testing_guide/end_to_end/execution_context_selection.md
new file mode 100644
index 00000000000..8456cfa8314
--- /dev/null
+++ b/doc/development/testing_guide/end_to_end/execution_context_selection.md
@@ -0,0 +1,122 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+---
+
+# Execution context selection
+
+Some tests are designed to be run against specific environments, or in specific [pipelines](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#scheduled-qa-test-pipelines) or jobs. We can specify the test execution context using the `only` and `except` metadata.
+
+## Available switches
+
+| Switch | Function | Type |
+| -------| ------- | ----- |
+| `tld` | Set the top-level domain matcher | `String` |
+| `subdomain` | Set the subdomain matcher | `Array` or `String` |
+| `domain` | Set the domain matcher | `String` |
+| `production` | Match the production environment | `Static` |
+| `pipeline` | Match a pipeline | `Array` or `Static`|
+| `job` | Match a job | `Array` or `Static`|
+
+WARNING:
+You cannot specify `:production` and `{ : 'value' }` simultaneously.
+These options are mutually exclusive. If you want to specify production, you
+can control the `tld` and `domain` independently.
+
+## Examples
+
+### Only
+
+Run tests in only the specified context.
+
+Matches use:
+
+- Regex for environments.
+- String matching for pipelines.
+- Regex or string matching for jobs.
+
+| Test execution context | Key | Matches |
+| ---------------- | --- | --------------- |
+| `gitlab.com` | `only: :production` | `gitlab.com` |
+| `staging.gitlab.com` | `only: { subdomain: :staging }` | `(staging).+.com` |
+| `gitlab.com and staging.gitlab.com` | `only: { subdomain: /(staging.)?/, domain: 'gitlab' }` | `(staging.)?gitlab.com` |
+| `dev.gitlab.org` | `only: { tld: '.org', domain: 'gitlab', subdomain: 'dev' }` | `(dev).gitlab.org` |
+| `staging.gitlab.com and domain.gitlab.com` | `only: { subdomain: %i[staging domain] }` | `(staging\|domain).+.com` |
+| The `nightly` pipeline | `only: { pipeline: :nightly }` | "nightly" |
+| The `nightly` and `canary` pipelines | `only: { pipeline: [:nightly, :canary] }` | ["nightly"](https://gitlab.com/gitlab-org/quality/nightly) and ["canary"](https://gitlab.com/gitlab-org/quality/canary) |
+| The `ee:instance` job | `only: { job: 'ee:instance' }` | The `ee:instance` job in any pipeline |
+| Any `quarantine` job | `only: { job: '.*quarantine' }` | Any job ending in `quarantine` in any pipeline |
+
+```ruby
+RSpec.describe 'Area' do
+ it 'runs in any environment or pipeline' do; end
+ it 'runs only in production environment', only: :production do; end
+
+ it 'runs only in staging environment', only: { subdomain: :staging } do; end
+
+ it 'runs in dev environment', only: { tld: '.org', domain: 'gitlab', subdomain: 'dev' } do; end
+
+ it 'runs in prod and staging environments', only: { subdomain: /(staging.)?/, domain: 'gitlab' } {}
+
+ it 'runs only in nightly pipeline', only: { pipeline: :nightly } do; end
+
+ it 'runs in nightly and canary pipelines', only: { pipeline: [:nightly, :canary] } do; end
+end
+```
+
+### Except
+
+Run tests in their typical contexts _except_ as specified.
+
+Matches use:
+
+- Regex for environments.
+- String matching for pipelines.
+- Regex or string matching for jobs.
+
+| Test execution context | Key | Matches |
+| ---------------- | --- | --------------- |
+| `gitlab.com` | `except: :production` | `gitlab.com` |
+| `staging.gitlab.com` | `except: { subdomain: :staging }` | `(staging).+.com` |
+| `gitlab.com and staging.gitlab.com` | `except: { subdomain: /(staging.)?/, domain: 'gitlab' }` | `(staging.)?gitlab.com` |
+| `dev.gitlab.org` | `except: { tld: '.org', domain: 'gitlab', subdomain: 'dev' }` | `(dev).gitlab.org` |
+| `staging.gitlab.com and domain.gitlab.com` | `except: { subdomain: %i[staging domain] }` | `(staging\|domain).+.com` |
+| The `nightly` pipeline | `except: { pipeline: :nightly }` | ["nightly"](https://gitlab.com/gitlab-org/quality/nightly) |
+| The `nightly` and `canary` pipelines | `except: { pipeline: [:nightly, :canary] }` | ["nightly"](https://gitlab.com/gitlab-org/quality/nightly) and ["canary"](https://gitlab.com/gitlab-org/quality/canary) |
+| The `ee:instance` job | `except: { job: 'ee:instance' }` | The `ee:instance` job in any pipeline |
+| Any `quarantine` job | `except: { job: '.*quarantine' }` | Any job ending in `quarantine` in any pipeline |
+
+```ruby
+RSpec.describe 'Area' do
+ it 'runs in any execution context except the production environment', except: :production do; end
+
+ it 'runs in any execution context except the staging environment', except: { subdomain: :staging } do; end
+
+ it 'runs in any execution context except the nightly pipeline', except: { pipeline: :nightly } do; end
+
+ it 'runs in any execution context except the ee:instance job', except: { job: 'ee:instance' } do; end
+end
+```
+
+## Usage notes
+
+If the test has a `before` or `after` block, you must add the `only` or `except` metadata to the outer `RSpec.describe` block.
+
+To run a test tagged with `only` on your local GitLab instance, you can do one of the following:
+
+- Make sure you **do not** have the `CI_PROJECT_NAME` or `CI_JOB_NAME` environment variables set.
+- Set the appropriate variable to match the metadata. For example, if the metadata is `only: { pipeline: :nightly }` then set `CI_PROJECT_NAME=nightly`. If the metadata is `only: { job: 'ee:instance' }` then set `CI_JOB_NAME=ee:instance`.
+- Temporarily remove the metadata.
+
+To run a test tagged with `except` locally, you can either:
+
+- Make sure you **do not** have the `CI_PROJECT_NAME` or `CI_JOB_NAME` environment variables set.
+- Temporarily remove the metadata.
+
+## Quarantine a test for a specific environment
+
+Similarly to specifying that a test should only run against a specific environment, it's also possible to quarantine a
+test only when it runs against a specific environment. The syntax is exactly the same, except that the `only: { ... }`
+hash is nested in the [`quarantine: { ... }`](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests) hash.
+For example, `quarantine: { only: { subdomain: :staging } }` only quarantines the test when run against `staging`.
diff --git a/doc/development/testing_guide/end_to_end/index.md b/doc/development/testing_guide/end_to_end/index.md
index 5ce429ac93c..eca649b73a5 100644
--- a/doc/development/testing_guide/end_to_end/index.md
+++ b/doc/development/testing_guide/end_to_end/index.md
@@ -212,6 +212,7 @@ Continued reading:
- [Testing with feature flags](feature_flags.md)
- [Flows](flows.md)
- [RSpec metadata/tags](rspec_metadata_tests.md)
+- [Execution context selection](execution_context_selection.md)
## Where can I ask for help?
diff --git a/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md b/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md
index 9b28137c6d5..7f541f1be3f 100644
--- a/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md
+++ b/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md
@@ -14,7 +14,7 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec
| Tag | Description |
|-----|-------------|
| `:elasticsearch` | The test requires an Elasticsearch service. It is used by the [instance-level scenario](https://gitlab.com/gitlab-org/gitlab-qa#definitions) [`Test::Integration::Elasticsearch`](https://gitlab.com/gitlab-org/gitlab/-/blob/72b62b51bdf513e2936301cb6c7c91ec27c35b4d/qa/qa/ee/scenario/test/integration/elasticsearch.rb) to include only tests that require Elasticsearch. |
-| `:exclude` | The test is excluded from running in a specific job. See [Environment selection](environment_selection.md#excluding-a-test-from-running-in-a-particular-job) for more information. |
+| `:except` | The test is to be run in their typical execution contexts _except_ as specified. See [test execution context selection](execution_context_selection.md) for more information. |
| `:geo` | The test requires two GitLab Geo instances - a primary and a secondary - to be spun up. |
| `:gitaly_cluster` | The test runs against a GitLab instance where repositories are stored on redundant Gitaly nodes behind a Praefect node. All nodes are [separate containers](../../../administration/gitaly/praefect.md#requirements-for-configuring-a-gitaly-cluster). Tests that use this tag have a longer setup time since there are three additional containers that need to be started. |
| `:github` | The test requires a GitHub personal access token. |
@@ -27,10 +27,10 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec
| `:ldap_tls` | The test requires a GitLab instance to be configured to use an external LDAP server with TLS enabled. |
| `:mattermost` | The test requires a GitLab Mattermost service on the GitLab instance. |
| `:object_storage` | The test requires a GitLab instance to be configured to use multiple [object storage types](../../../administration/object_storage.md). Uses MinIO as the object storage server. |
-| `:only` | The test is only to be run against specific environments or pipelines. See [Environment selection](environment_selection.md) for more information. |
+| `:only` | The test is only to be run in specific execution contexts. See [test execution context selection](execution_context_selection.md) for more information. |
| `:orchestrated` | The GitLab instance under test may be [configured by `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#orchestrated-tests) to be different to the default GitLab configuration, or `gitlab-qa` may launch additional services in separate Docker containers, or both. Tests tagged with `:orchestrated` are excluded when testing environments where we can't dynamically modify the GitLab configuration (for example, Staging). |
| `:packages` | The test requires a GitLab instance that has the [Package Registry](../../../administration/packages/#gitlab-package-registry-administration) enabled. |
-| `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests), runs in a separate job that only includes quarantined tests, and is allowed to fail. The test is skipped in its regular job so that if it fails it doesn't hold up the pipeline. Note that you can also [quarantine a test only when it runs against specific environment](environment_selection.md#quarantining-a-test-for-a-specific-environment). |
+| `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests), runs in a separate job that only includes quarantined tests, and is allowed to fail. The test is skipped in its regular job so that if it fails it doesn't hold up the pipeline. Note that you can also [quarantine a test only when it runs in a specific context](execution_context_selection.md#quarantine-a-test-for-a-specific-environment). |
| `:relative_url` | The test requires a GitLab instance to be installed under a [relative URL](../../../install/relative_url.md). |
| `:reliable` | The test has been [promoted to a reliable test](https://about.gitlab.com/handbook/engineering/quality/guidelines/reliable-tests/#promoting-an-existing-test-to-reliable) meaning it passes consistently in all pipelines, including merge requests. |
| `:repository_storage` | The test requires a GitLab instance to be configured to use multiple [repository storage paths](../../../administration/repository_storage_paths.md). Paired with the `:orchestrated` tag. |
diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md
index 79d4c09be83..d24c1cfec13 100644
--- a/doc/development/usage_ping/dictionary.md
+++ b/doc/development/usage_ping/dictionary.md
@@ -22436,7 +22436,7 @@ Group: `group::monitor`
Data Category: `Optional`
-Status: `data_available`
+Status: `deprecated`
Tiers: `premium`, `ultimate`
diff --git a/doc/user/admin_area/analytics/dev_ops_report.md b/doc/user/admin_area/analytics/dev_ops_report.md
index 6158a89a13e..89d8a5ea054 100644
--- a/doc/user/admin_area/analytics/dev_ops_report.md
+++ b/doc/user/admin_area/analytics/dev_ops_report.md
@@ -57,7 +57,6 @@ DevOps Adoption shows you which groups in your organization are using the most e
- Sec
- DAST
- SAST
- - Scans
- Ops
- Deployments
- Pipelines
diff --git a/doc/user/clusters/agent/index.md b/doc/user/clusters/agent/index.md
index ab2719e1174..83933524fd4 100644
--- a/doc/user/clusters/agent/index.md
+++ b/doc/user/clusters/agent/index.md
@@ -7,7 +7,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab Kubernetes Agent **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223061) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.4.
-> - [In GitLab 13.10](https://gitlab.com/gitlab-org/gitlab/-/issues/300960), KAS became available on GitLab.com under `wss://kas.gitlab.com` through an Early Adopter Program.
+> - [Introduced](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/issues/7) in GitLab 13.6, `grpcs` is supported.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/300960) in GitLab 13.10, KAS became available on GitLab.com under `wss://kas.gitlab.com` through an Early Adopter Program.
> - Introduced in GitLab 13.11, the GitLab Kubernetes Agent became available to every project on GitLab.com.
The [GitLab Kubernetes Agent](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent)
@@ -249,12 +250,11 @@ example [`resources.yml` file](#example-resourcesyml-file) in the following ways
- Specify the `grpc` scheme if both Agent and Server are installed in one cluster.
In this case, you may specify `kas-address` value as
`grpc://gitlab-kas.:8150`) to use gRPC directly, where `gitlab-kas`
- is the name of the service created by `gitlab-kas` chart, and `your-namespace`
- is the namespace where the chart was installed. Encrypted gRPC is not supported yet.
- Follow the
- [Support TLS for gRPC communication issue](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/issues/7)
- for progress updates.
- - When deploying KAS through the [GitLab chart](https://docs.gitlab.com/charts/), it's possible to customize the `kas-address` for `wss` and `ws` schemes to whatever you need.
+ is the name of the service created by `gitlab-kas` chart, and ``
+ is the namespace where the chart was installed.
+ - Specify the `grpcs` scheme to use an encrypted gRPC connection.
+ - When deploying KAS through the [GitLab chart](https://docs.gitlab.com/charts/), it's possible to customize the
+ `kas-address` for `wss` and `ws` schemes to whatever you need.
Check the [chart's KAS Ingress documentation](https://docs.gitlab.com/charts/charts/gitlab/kas/#ingress)
to learn more about it.
- In the near future, Omnibus GitLab intends to provision `gitlab-kas` under a sub-domain by default, instead of the `/-/kubernetes-agent/` path. Please follow [this issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5784) for details.
diff --git a/doc/user/group/devops_adoption/index.md b/doc/user/group/devops_adoption/index.md
index e6c9a492c2c..4332f261481 100644
--- a/doc/user/group/devops_adoption/index.md
+++ b/doc/user/group/devops_adoption/index.md
@@ -27,7 +27,6 @@ Group DevOps Adoption shows you how individual groups and sub-groups within your
- Sec
- DAST
- SAST
- - Scans
- Ops
- Deployments
- Pipelines
diff --git a/doc/user/project/time_tracking.md b/doc/user/project/time_tracking.md
index a1469c50b8e..29aedb33003 100644
--- a/doc/user/project/time_tracking.md
+++ b/doc/user/project/time_tracking.md
@@ -6,14 +6,12 @@ group: Project Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
-# Time Tracking **(FREE)**
+# Time tracking **(FREE)**
-Time Tracking allows you to track estimates and time spent on issues and merge
-requests within GitLab.
+With time tracking you can track estimates and time spent on issues and merge
+requests in GitLab.
-## Overview
-
-Time Tracking allows you to:
+Use time tracking for these tasks:
- Record the time spent working on an issue or a merge request.
- Add an estimate of the amount of time needed to complete an issue or a merge
@@ -22,14 +20,13 @@ Time Tracking allows you to:
You don't have to indicate an estimate to enter the time spent, and vice versa.
-Data about time tracking is shown on the issue/merge request sidebar, as shown
-below.
+Data about time tracking shows up on the issue and merge request sidebar:
![Time tracking in the sidebar](img/time_tracking_sidebar_v13_12.png)
## How to enter data
-Time Tracking uses two [quick actions](quick_actions.md): `/spend` and `/estimate`.
+Time tracking uses two [quick actions](quick_actions.md): `/spend` and `/estimate`.
If you use either quick action more than once in a single comment, only the last occurrence is applied.
@@ -42,9 +39,10 @@ with [Reporter and higher permission levels](../permissions.md).
### Estimates
-To enter an estimate, write `/estimate`, followed by the time. For example, if
-you need to enter an estimate of 1 month, 2 weeks, 3 days, 4 hours and 5 minutes,
-write `/estimate 1mo 2w 3d 4h 5m`.
+To enter an estimate, type `/estimate`, followed by the time.
+
+For example, if you need to enter an estimate of 1 month, 2 weeks, 3 days, 4 hours, and 5 minutes,
+type `/estimate 1mo 2w 3d 4h 5m`.
Check the [time units you can use](#configuration).
Every time you enter a new time estimate, any previous time estimates are
@@ -55,21 +53,22 @@ To remove an estimation entirely, use `/remove_estimate`.
### Time spent
-To enter time spent, write `/spend`, followed by the time. For example, if you need
-to log 1 month, 2 weeks, 3 days, 4 hours and 5 minutes, you would write `/spend 1mo 2w 3d 4h 5m`.
-Time units that we support are listed at the bottom of this help page.
+To enter time spent, type `/spend`, followed by the time.
+
+For example, if you need
+to log 1 month, 2 weeks, 3 days, 4 hours, and 5 minutes, type `/spend 1mo 2w 3d 4h 5m`.
+Check the [time units you can use](#configuration).
Every new time spent entry is added to the current total time spent for the
issue or the merge request.
-You can remove time by entering a negative amount: for example, `/spend -3d` removes three
+To subtract time, enter a negative value. For example, `/spend -3d` removes three
days from the total time spent. You can't go below 0 minutes of time spent,
-so GitLab automatically resets the time spent if you remove a larger amount
-of time compared to the time that was entered already.
+so if you remove more time than already entered, GitLab ignores the subtraction.
You can log time in the past by providing a date after the time.
For example, if you want to log 1 hour of time spent on the 31 January 2021,
-you would write `/spend 1h 2021-01-31`. If you supply a date in the future, the
+you would type `/spend 1h 2021-01-31`. If you supply a date in the future, the
command fails and no time is logged.
To remove all the time spent at once, use `/remove_time_spent`.
@@ -95,13 +94,13 @@ The breakdown of spent time is limited to a maximum of 100 entries.
The following time units are available:
-- Months (mo)
-- Weeks (w)
-- Days (d)
-- Hours (h)
-- Minutes (m)
-
-Default conversion rates are 1mo = 4w, 1w = 5d and 1d = 8h.
+| Time unit | What to type | Default conversion rate |
+| --------- | ------------ | ----------------------- |
+| Month | `mo` | 4w |
+| Week | `w` | 5d |
+| Day | `d` | 8h |
+| Hour | `h` | 60m |
+| Minute | `m` | |
### Limit displayed units to hours **(FREE SELF)**
@@ -119,11 +118,11 @@ To do so:
With this option enabled, `75h` is displayed instead of `1w 4d 3h`.
-## Other interesting links
+## Related links
-- [Time Tracking solutions page](https://about.gitlab.com/solutions/time-tracking/)
-- Time Tracking GraphQL references:
+- [Time tracking solutions page](https://about.gitlab.com/solutions/time-tracking/)
+- Time tracking GraphQL references:
- [Connection](../../api/graphql/reference/index.md#timelogconnection)
- [Edge](../../api/graphql/reference/index.md#timelogedge)
- [Fields](../../api/graphql/reference/index.md#timelog)
- - [Group Timelogs](../../api/graphql/reference/index.md#grouptimelogs)
+ - [Group timelogs](../../api/graphql/reference/index.md#grouptimelogs)
diff --git a/lib/sidebars/groups/menus/scope_menu.rb b/lib/sidebars/groups/menus/scope_menu.rb
new file mode 100644
index 00000000000..02c359e3c99
--- /dev/null
+++ b/lib/sidebars/groups/menus/scope_menu.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Groups
+ module Menus
+ class ScopeMenu < ::Sidebars::Menu
+ override :link
+ def link
+ group_path(context.group)
+ end
+
+ override :title
+ def title
+ context.group.name
+ end
+
+ override :active_routes
+ def active_routes
+ { path: %w[groups#show groups#details] }
+ end
+
+ override :extra_nav_link_html_options
+ def extra_nav_link_html_options
+ { class: 'context-header' }
+ end
+
+ override :render?
+ def render?
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/groups/panel.rb b/lib/sidebars/groups/panel.rb
index c11ca04c316..fe669bf0b29 100644
--- a/lib/sidebars/groups/panel.rb
+++ b/lib/sidebars/groups/panel.rb
@@ -3,9 +3,9 @@
module Sidebars
module Groups
class Panel < ::Sidebars::Panel
- override :render_raw_scope_menu_partial
- def render_raw_scope_menu_partial
- 'layouts/nav/sidebar/group_scope_menu'
+ override :configure_menus
+ def configure_menus
+ set_scope_menu(Sidebars::Groups::Menus::ScopeMenu.new(context))
end
override :render_raw_menus_partial
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 6d5e640b8d8..b46bb1d50ae 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -11324,9 +11324,6 @@ msgstr ""
msgid "DevopsAdoption|At least one pipeline successfully run"
msgstr ""
-msgid "DevopsAdoption|At least one security scan of any type run in pipeline"
-msgstr ""
-
msgid "DevopsAdoption|Code owners"
msgstr ""
@@ -11393,9 +11390,6 @@ msgstr ""
msgid "DevopsAdoption|SAST enabled for at least one project"
msgstr ""
-msgid "DevopsAdoption|Scanning"
-msgstr ""
-
msgid "DevopsAdoption|Sec"
msgstr ""
@@ -15151,7 +15145,7 @@ msgstr ""
msgid "GitLabPages|Removing pages will prevent them from being exposed to the outside world."
msgstr ""
-msgid "GitLabPages|Save"
+msgid "GitLabPages|Save changes"
msgstr ""
msgid "GitLabPages|Something went wrong while obtaining the Let's Encrypt certificate for %{domain}. To retry visit your %{link_start}domain details%{link_end}."
@@ -15922,6 +15916,9 @@ msgstr ""
msgid "GroupSettings|Select a subgroup to use as the source for custom project templates for this group."
msgstr ""
+msgid "GroupSettings|Set the maximum size of GitLab Pages for this group. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
msgid "GroupSettings|The Auto DevOps pipeline runs if no alternative CI configuration file is found."
msgstr ""
@@ -30399,9 +30396,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Size settings for static websites"
-msgstr ""
-
msgid "Skip outdated deployment jobs"
msgstr ""
diff --git a/qa/qa.rb b/qa/qa.rb
index 75df6f36828..566effb3cd9 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -79,6 +79,7 @@ module QA
autoload :GroupLabel, 'qa/resource/group_label'
autoload :MergeRequest, 'qa/resource/merge_request'
autoload :ProjectImportedFromGithub, 'qa/resource/project_imported_from_github'
+ autoload :ProjectImportedFromURL, 'qa/resource/project_imported_from_url'
autoload :MergeRequestFromFork, 'qa/resource/merge_request_from_fork'
autoload :DeployKey, 'qa/resource/deploy_key'
autoload :DeployToken, 'qa/resource/deploy_token'
@@ -290,6 +291,7 @@ module QA
module Import
autoload :Github, 'qa/page/project/import/github'
+ autoload :RepoByURL, 'qa/page/project/import/repo_by_url'
end
module Pipeline
@@ -337,6 +339,7 @@ module QA
autoload :MergeRequest, 'qa/page/project/settings/merge_request'
autoload :MirroringRepositories, 'qa/page/project/settings/mirroring_repositories'
autoload :ProtectedTags, 'qa/page/project/settings/protected_tags'
+ autoload :DefaultBranch, 'qa/page/project/settings/default_branch'
autoload :VisibilityFeaturesPermissions, 'qa/page/project/settings/visibility_features_permissions'
autoload :AccessTokens, 'qa/page/project/settings/access_tokens'
diff --git a/qa/qa/page/project/import/repo_by_url.rb b/qa/qa/page/project/import/repo_by_url.rb
new file mode 100644
index 00000000000..0e7524a181a
--- /dev/null
+++ b/qa/qa/page/project/import/repo_by_url.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Import
+ class RepoByURL < Page::Base
+ include Page::Component::Select2
+
+ view 'app/views/projects/_new_project_fields.html.haml' do
+ element :select_namespace_dropdown
+ end
+
+ def import!(gitlab_repo_path, name)
+ fill_git_repository_url_link(gitlab_repo_path)
+ fill_project_name(name)
+ choose_test_namespace
+ click_create_button
+
+ wait_for_success
+
+ go_to_project(name)
+ end
+
+ private
+
+ def fill_git_repository_url_link(gitlab_repo_path)
+ fill_in 'project_import_url', with: gitlab_repo_path
+ end
+
+ def fill_project_name(name)
+ fill_in 'project_name', with: name
+ end
+
+ def choose_test_namespace
+ find('.js-select-namespace').click
+ search_and_select(Runtime::Namespace.path)
+ end
+
+ def click_create_button
+ find('.btn-confirm').click
+ end
+
+ def wait_for_success
+ wait_until(max_duration: 60, sleep_interval: 5.0, reload: true, skip_finished_loading_check_on_refresh: true) do
+ page.has_no_content?('Import in progress', wait: 3.0)
+ end
+ end
+
+ def go_to_project(name)
+ Page::Main::Menu.perform(&:go_to_projects)
+ Page::Dashboard::Projects.perform do |dashboard|
+ dashboard.go_to_project(name)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb
index d3c06119efc..170cc14b27f 100644
--- a/qa/qa/page/project/new.rb
+++ b/qa/qa/page/project/new.rb
@@ -79,6 +79,10 @@ module QA
click_link 'GitHub'
end
+ def click_repo_by_url_link
+ click_button 'Repo by URL'
+ end
+
def enable_initialize_with_readme
check_element(:initialize_with_readme_checkbox)
end
diff --git a/qa/qa/page/project/settings/default_branch.rb b/qa/qa/page/project/settings/default_branch.rb
new file mode 100644
index 00000000000..cc28b37b88f
--- /dev/null
+++ b/qa/qa/page/project/settings/default_branch.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Settings
+ class DefaultBranch < Page::Base
+ include Page::Component::Select2
+
+ view 'app/views/projects/default_branch/_show.html.haml' do
+ element :save_changes_button
+ element :default_branch_dropdown
+ end
+
+ def set_default_branch(branch)
+ find('.select2-chosen').click
+ search_and_select(branch)
+ end
+
+ def click_save_changes_button
+ find('.btn-confirm').click
+ end
+ end
+ end
+ end
+ end
+end
+
+QA::Page::Project::Settings::DefaultBranch.prepend_mod_with('Page::Project::Settings::DefaultBranch', namespace: QA)
diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb
index a02b3d6a7d6..de5b4f37076 100644
--- a/qa/qa/page/project/settings/repository.rb
+++ b/qa/qa/page/project/settings/repository.rb
@@ -56,6 +56,14 @@ module QA
ProtectedTags.perform(&block)
end
end
+
+ def expand_default_branch(&block)
+ within('#default-branch-settings') do
+ find('.btn-default').click do
+ DefaultBranch.perform(&block)
+ end
+ end
+ end
end
end
end
diff --git a/qa/qa/resource/project_imported_from_url.rb b/qa/qa/resource/project_imported_from_url.rb
new file mode 100644
index 00000000000..f159a174840
--- /dev/null
+++ b/qa/qa/resource/project_imported_from_url.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'securerandom'
+
+module QA
+ module Resource
+ class ProjectImportedFromURL < Resource::Project
+ def fabricate!
+ self.import = true
+ super
+
+ group.visit!
+
+ Page::Group::Show.perform(&:go_to_new_project)
+
+ Page::Project::New.perform do |project_page|
+ project_page.click_import_project
+ project_page.click_repo_by_url_link
+ end
+
+ Page::Project::Import::RepoByURL.perform do |import_page|
+ import_page.import!(@gitlab_repository_path, @name)
+ end
+ end
+ end
+ end
+end
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 64645ed16cd..2243437fc71 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
@@ -51,7 +51,7 @@ module QA
# The following example is excluded from running in `review-qa-smoke` job
# as it proved to be flaky when running against Review App
# See https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/11568#note_621999351
- it 'comments on an issue with an attachment', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1742', exclude: { job: 'review-qa-smoke' } do
+ it 'comments on an issue with an attachment', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1742', except: { job: 'review-qa-smoke' } do
Page::Project::Issue::Show.perform do |show|
show.comment('See attached image for scale', attachment: file_to_attach)
diff --git a/qa/qa/specs/features/browser_ui/5_package/online_garbage_collection_spec.rb b/qa/qa/specs/features/browser_ui/5_package/online_garbage_collection_spec.rb
new file mode 100644
index 00000000000..65fc12545b7
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/5_package/online_garbage_collection_spec.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Package' do
+ describe 'Container Registry Online Garbage Collection', :registry_gc, only: { subdomain: %i[pre] } do
+ let(:group) { Resource::Group.fabricate_via_api! }
+
+ let(:imported_project) do
+ Resource::ProjectImportedFromURL.fabricate_via_browser_ui! do |project|
+ project.name = 'container-registry'
+ project.group = group
+ project.gitlab_repository_path = 'https://gitlab.com/gitlab-org/container-registry.git'
+ end
+ end
+
+ let!(:gitlab_ci_yaml) do
+ <<~YAML
+ variables:
+ GOPATH: $CI_PROJECT_DIR/.go
+ BUILD_CACHE: $CI_PROJECT_DIR/.online-gc-tester
+ STAGE_ONE_VALIDATION_DELAY: "6m"
+ STAGE_TWO_VALIDATION_DELAY: "12m"
+ STAGE_THREE_VALIDATION_DELAY: "6m"
+ STAGE_FOUR_VALIDATION_DELAY: "12m"
+ STAGE_FIVE_VALIDATION_DELAY: "12m"
+
+ stages:
+ - generate
+ - build
+ - test
+
+ .base: &base
+ image: docker:19
+ services:
+ - docker:19-dind
+ variables:
+ DOCKER_HOST: tcp://docker:2376
+ DOCKER_TLS_CERTDIR: "/certs"
+ DOCKER_TLS_VERIFY: 1
+ DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
+ before_script:
+ - until docker info; do sleep 1; done
+ - mkdir -p $GOPATH
+ - mkdir -p $BUILD_CACHE
+ - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+
+ test:
+ stage: generate
+ extends: .base
+ script:
+ - apk add go make git
+ - make binaries
+ - ./bin/online-gc-tester generate --base-dir=$BUILD_CACHE
+ - ./bin/online-gc-tester build --base-dir=$BUILD_CACHE
+ - ./bin/online-gc-tester push --base-dir=$BUILD_CACHE
+ - ./bin/online-gc-tester pull --base-dir=$BUILD_CACHE
+ - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=1 --delay=$STAGE_ONE_VALIDATION_DELAY
+ - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=2 --delay=$STAGE_TWO_VALIDATION_DELAY
+ - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=3 --delay=$STAGE_THREE_VALIDATION_DELAY
+ - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=4 --delay=$STAGE_FOUR_VALIDATION_DELAY
+ - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=5 --delay=$STAGE_FIVE_VALIDATION_DELAY
+ timeout: 1h 30m
+ YAML
+ end
+
+ before do
+ Flow::Login.sign_in
+
+ imported_project
+
+ Page::Project::Menu.perform(&:go_to_repository_settings)
+
+ Page::Project::Settings::Repository.perform do |setting|
+ setting.expand_default_branch
+ end
+
+ Page::Project::Settings::DefaultBranch.perform do |setting|
+ setting.set_default_branch('online-gc-test-builder-poc')
+ setting.click_save_changes_button
+ end
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = imported_project
+ commit.branch = 'online-gc-test-builder-poc'
+ commit.commit_message = 'Update .gitlab-ci.yml'
+ commit.update_files([{
+ file_path: '.gitlab-ci.yml',
+ content: gitlab_ci_yaml
+ }])
+ end
+ end
+
+ it 'runs the online garbage collector tool', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1854' do
+ imported_project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('test')
+ end
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful(timeout: 3900)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/helpers/context_selector.rb b/qa/qa/specs/helpers/context_selector.rb
index 4313f7c34dd..40ecb9b3506 100644
--- a/qa/qa/specs/helpers/context_selector.rb
+++ b/qa/qa/specs/helpers/context_selector.rb
@@ -13,15 +13,17 @@ module QA
config.before do |example|
if example.metadata.key?(:only)
skip('Test is not compatible with this environment or pipeline') unless ContextSelector.context_matches?(example.metadata[:only])
- elsif example.metadata.key?(:exclude)
- skip('Test is excluded in this job') if ContextSelector.exclude?(example.metadata[:exclude])
+ elsif example.metadata.key?(:except)
+ skip('Test is excluded in this job') if ContextSelector.except?(example.metadata[:except])
end
end
end
end
- def exclude?(*options)
- return false unless Runtime::Env.ci_job_name.present?
+ def except?(*options)
+ return false if Runtime::Env.ci_job_name.blank? && options.any? { |o| o.is_a?(Hash) && o[:job].present? }
+ return false if Runtime::Env.ci_project_name.blank? && options.any? { |o| o.is_a?(Hash) && o[:pipeline].present? }
+ return false if Runtime::Scenario.attributes[:gitlab_address].blank?
context_matches?(*options)
end
@@ -40,10 +42,14 @@ module QA
next unless option.is_a?(Hash)
- if option[:pipeline].present? && Runtime::Env.ci_project_name.present?
+ if option[:pipeline].present?
+ return true if Runtime::Env.ci_project_name.blank?
+
return pipeline_matches?(option[:pipeline])
elsif option[:job].present?
+ return true if Runtime::Env.ci_job_name.blank?
+
return job_matches?(option[:job])
elsif option[:subdomain].present?
diff --git a/qa/spec/specs/helpers/context_selector_spec.rb b/qa/spec/specs/helpers/context_selector_spec.rb
index 7792d33dcf9..f0250103008 100644
--- a/qa/spec/specs/helpers/context_selector_spec.rb
+++ b/qa/spec/specs/helpers/context_selector_spec.rb
@@ -49,8 +49,10 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
it 'matches multiple subdomains' do
QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
- expect(described_class.context_matches?(subdomain: [:release, :staging])).to be_truthy
- expect(described_class.context_matches?(:production, subdomain: [:release, :staging])).to be_truthy
+ aggregate_failures do
+ expect(described_class.context_matches?(subdomain: [:release, :staging])).to be_truthy
+ expect(described_class.context_matches?(:production, subdomain: [:release, :staging])).to be_truthy
+ end
end
it 'matches :production' do
@@ -87,6 +89,16 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
expect(group.examples[0].execution_result.status).to eq(:passed)
end
+
+ context 'when excluding contexts' do
+ it 'can apply to contexts or descriptions' do
+ group = describe_successfully 'skips staging', except: { subdomain: :staging } do
+ it('skips staging') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ end
+ end
end
context 'with different environment set' do
@@ -102,6 +114,16 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
expect(group.examples[0].execution_result.status).to eq(:pending)
end
+
+ context 'when excluding contexts' do
+ it 'runs against production' do
+ group = describe_successfully 'Runs in staging', :something, except: { subdomain: :staging } do
+ it('runs in staging') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ end
+ end
end
end
@@ -113,10 +135,28 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
it('runs in any env') {}
end
- expect(group.examples[0].execution_result.status).to eq(:passed)
- expect(group.examples[1].execution_result.status).to eq(:pending)
- expect(group.examples[2].execution_result.status).to eq(:passed)
- expect(group.examples[3].execution_result.status).to eq(:passed)
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:pending)
+ expect(group.examples[2].execution_result.status).to eq(:passed)
+ expect(group.examples[3].execution_result.status).to eq(:passed)
+ end
+ end
+
+ context 'when excluding contexts' do
+ it 'skips staging' do
+ group = describe_successfully do
+ it('skips staging', except: { subdomain: :staging }) {}
+ it('runs in staging', except: :production) {}
+ it('skips staging also', except: { subdomain: %i[release staging] }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ expect(group.examples[2].execution_result.status).to eq(:pending)
+ end
+ end
end
context 'custom env' do
@@ -130,8 +170,24 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
it('does not run on release', only: :production) {}
end
- expect(group.examples.first.execution_result.status).to eq(:passed)
- expect(group.examples.last.execution_result.status).to eq(:pending)
+ aggregate_failures do
+ expect(group.examples.first.execution_result.status).to eq(:passed)
+ expect(group.examples.last.execution_result.status).to eq(:pending)
+ end
+ end
+
+ context 'when excluding contexts' do
+ it 'skips a custom environment' do
+ group = describe_successfully do
+ it('skips release gitlab net', except: { tld: '.net', subdomain: :release, domain: 'gitlab' }) {}
+ it('runs on release', except: :production) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples.first.execution_result.status).to eq(:pending)
+ expect(group.examples.last.execution_result.status).to eq(:passed)
+ end
+ end
end
end
@@ -147,9 +203,27 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
it('runs in prod and staging', only: { subdomain: /(staging.)?/, domain: 'gitlab' }) {}
end
- expect(group.examples[0].execution_result.status).to eq(:passed)
- expect(group.examples[1].execution_result.status).to eq(:pending)
- expect(group.examples[2].execution_result.status).to eq(:passed)
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:pending)
+ expect(group.examples[2].execution_result.status).to eq(:passed)
+ end
+ end
+
+ context 'when excluding contexts' do
+ it 'skips production' do
+ group = describe_successfully do
+ it('skips prod', except: :production) {}
+ it('runs on prod', except: { subdomain: :staging }) {}
+ it('skips prod and staging', except: { subdomain: /(staging.)?/, domain: 'gitlab' }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ expect(group.examples[2].execution_result.status).to eq(:pending)
+ end
+ end
end
end
@@ -179,6 +253,21 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
expect(group.examples[1].execution_result.status).to eq(:passed)
end
end
+
+ context 'when excluding contexts' do
+ it 'runs in any pipeline' do
+ group = describe_successfully do
+ it('runs given a single named pipeline', except: { pipeline: :nightly }) {}
+ it('runs given an array of pipelines', except: { pipeline: [:canary, :not_nightly] }) {}
+ end
+
+ aggregate_failures do
+ group.examples.each do |example|
+ expect(example.execution_result.status).to eq(:passed)
+ end
+ end
+ end
+ end
end
context 'when a pipeline triggered from the default branch runs in gitlab-qa' do
@@ -200,6 +289,22 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
expect(group.examples[2].execution_result.status).to eq(:pending)
end
end
+
+ context 'when excluding contexts' do
+ it 'skips default branch pipelines' do
+ group = describe_successfully do
+ it('skips main pipeline given a single pipeline', except: { pipeline: :main }) {}
+ it('skips main given an array of pipelines', except: { pipeline: [:canary, :main] }) {}
+ it('runs non-default pipelines', except: { pipeline: [:nightly, :not_nightly, :not_main] }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:pending)
+ expect(group.examples[2].execution_result.status).to eq(:passed)
+ end
+ end
+ end
end
context 'with CI_PROJECT_NAME set' do
@@ -223,24 +328,42 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
expect(group.examples[3].execution_result.status).to eq(:pending)
end
end
+
+ context 'when excluding contexts' do
+ it 'skips designated pipeline' do
+ group = describe_successfully do
+ it('skips nightly', except: { pipeline: :nightly }) {}
+ it('runs in not_nightly', except: { pipeline: :not_nightly }) {}
+ it('skips on nightly given an array', except: { pipeline: [:canary, :nightly] }) {}
+ it('runs in not_nightly given an array', except: { pipeline: [:not_nightly, :canary] }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ expect(group.examples[2].execution_result.status).to eq(:pending)
+ expect(group.examples[3].execution_result.status).to eq(:passed)
+ end
+ end
+ end
end
end
- context 'when excluding contexts' do
- context 'with job constraints' do
- context 'without CI_JOB_NAME set' do
- before do
- stub_env('CI_JOB_NAME', nil)
- described_class.configure_rspec
- end
+ context 'with job constraints' do
+ context 'without CI_JOB_NAME set' do
+ before do
+ stub_env('CI_JOB_NAME', nil)
+ described_class.configure_rspec
+ end
+ context 'when excluding contexts' do
it 'runs in any job' do
group = describe_successfully do
- it('runs given a single named job', exclude: { job: 'ee:instance-image' }) {}
- it('runs given a single regex pattern', exclude: { job: '.*:instance-image' }) {}
- it('runs given an array of jobs', exclude: { job: %w[ee:instance-image qa-schedules-browser_ui-3_create] }) {}
- it('runs given an array of regex patterns', exclude: { job: %w[ee:.* qa-schedules-browser_ui.*] }) {}
- it('runs given a mix of strings and regex patterns', exclude: { job: %w[ee:instance-image qa-schedules-browser_ui.*] }) {}
+ it('runs given a single named job', except: { job: 'ee:instance-image' }) {}
+ it('runs given a single regex pattern', except: { job: '.*:instance-image' }) {}
+ it('runs given an array of jobs', except: { job: %w[ee:instance-image qa-schedules-browser_ui-3_create] }) {}
+ it('runs given an array of regex patterns', except: { job: %w[ee:.* qa-schedules-browser_ui.*] }) {}
+ it('runs given a mix of strings and regex patterns', except: { job: %w[ee:instance-image qa-schedules-browser_ui.*] }) {}
end
aggregate_failures do
@@ -251,19 +374,39 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
- context 'with CI_JOB_NAME set' do
- before do
- stub_env('CI_JOB_NAME', 'ee:instance-image')
- described_class.configure_rspec
- end
+ context 'when including only specific contexts' do
+ it 'runs in any job' do
+ group = describe_successfully do
+ it('runs given a single named job', only: { job: 'ee:instance-image' }) {}
+ it('runs given a single regex pattern', only: { job: '.*:instance-image' }) {}
+ it('runs given an array of jobs', only: { job: %w[ee:instance-image qa-schedules-browser_ui-3_create] }) {}
+ it('runs given an array of regex patterns', only: { job: %w[ee:.* qa-schedules-browser_ui.*] }) {}
+ it('runs given a mix of strings and regex patterns', only: { job: %w[ee:instance-image qa-schedules-browser_ui.*] }) {}
+ end
+ aggregate_failures do
+ group.examples.each do |example|
+ expect(example.execution_result.status).to eq(:passed)
+ end
+ end
+ end
+ end
+ end
+
+ context 'with CI_JOB_NAME set' do
+ before do
+ stub_env('CI_JOB_NAME', 'ee:instance-image')
+ described_class.configure_rspec
+ end
+
+ context 'when excluding contexts' do
it 'does not run in the specified job' do
group = describe_successfully do
- it('skips given a single named job', exclude: { job: 'ee:instance-image' }) {}
- it('skips given a single regex pattern', exclude: { job: '.*:instance-image' }) {}
- it('skips given an array of jobs', exclude: { job: %w[ee:instance-image qa-schedules-browser_ui-3_create] }) {}
- it('skips given an array of regex patterns', exclude: { job: %w[ee:.* qa-schedules-browser_ui.*] }) {}
- it('skips given a mix of strings and regex patterns', exclude: { job: %w[ee:instance-image qa-schedules-browser_ui.*] }) {}
+ it('skips given a single named job', except: { job: 'ee:instance-image' }) {}
+ it('skips given a single regex pattern', except: { job: '.*:instance-image' }) {}
+ it('skips given an array of jobs', except: { job: %w[ee:instance-image qa-schedules-browser_ui-3_create] }) {}
+ it('skips given an array of regex patterns', except: { job: %w[ee:.* qa-schedules-browser_ui.*] }) {}
+ it('skips given a mix of strings and regex patterns', except: { job: %w[ee:instance-image qa-schedules-browser_ui.*] }) {}
end
aggregate_failures do
@@ -275,11 +418,11 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
it 'runs in jobs that do not match' do
group = describe_successfully do
- it('runs given a single named job', exclude: { job: 'ce:instance-image' }) {}
- it('runs given a single regex pattern', exclude: { job: '.*:instance-image-quarantine' }) {}
- it('runs given an array of jobs', exclude: { job: %w[ce:instance-image qa-schedules-browser_ui-3_create] }) {}
- it('runs given an array of regex patterns', exclude: { job: %w[ce:.* qa-schedules-browser_ui.*] }) {}
- it('runs given a mix of strings and regex patterns', exclude: { job: %w[ce:instance-image qa-schedules-browser_ui.*] }) {}
+ it('runs given a single named job', except: { job: 'ce:instance-image' }) {}
+ it('runs given a single regex pattern', except: { job: '.*:instance-image-quarantine' }) {}
+ it('runs given an array of jobs', except: { job: %w[ce:instance-image qa-schedules-browser_ui-3_create] }) {}
+ it('runs given an array of regex patterns', except: { job: %w[ce:.* qa-schedules-browser_ui.*] }) {}
+ it('runs given a mix of strings and regex patterns', except: { job: %w[ce:instance-image qa-schedules-browser_ui.*] }) {}
end
aggregate_failures do
@@ -289,6 +432,40 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
end
+
+ context 'when including only specific contexts' do
+ it 'runs only in the specified jobs' do
+ group = describe_successfully do
+ it('runs given a single named job', only: { job: 'ee:instance-image' }) {}
+ it('runs given a single regex pattern', only: { job: '.*:instance-image' }) {}
+ it('runs given an array of jobs', only: { job: %w[ee:instance-image qa-schedules-browser_ui-3_create] }) {}
+ it('runs given an array of regex patterns', only: { job: %w[ee:.* qa-schedules-browser_ui.*] }) {}
+ it('runs given a mix of strings and regex patterns', only: { job: %w[ee:instance-image qa-schedules-browser_ui.*] }) {}
+ end
+
+ aggregate_failures do
+ group.examples.each do |example|
+ expect(example.execution_result.status).to eq(:passed)
+ end
+ end
+ end
+
+ it 'does not run in jobs that do not match' do
+ group = describe_successfully do
+ it('skips given a single named job', only: { job: 'ce:instance-image' }) {}
+ it('skips given a single regex pattern', only: { job: '.*:instance-image-quarantine' }) {}
+ it('skips given an array of jobs', only: { job: %w[ce:instance-image qa-schedules-browser_ui-3_create] }) {}
+ it('skips given an array of regex patterns', only: { job: %w[ce:.* qa-schedules-browser_ui.*] }) {}
+ it('skips given a mix of strings and regex patterns', only: { job: %w[ce:instance-image qa-schedules-browser_ui.*] }) {}
+ end
+
+ aggregate_failures do
+ group.examples.each do |example|
+ expect(example.execution_result.status).to eq(:pending)
+ end
+ end
+ end
+ end
end
end
end
diff --git a/spec/graphql/mutations/security/ci_configuration/base_security_analyzer_spec.rb b/spec/graphql/mutations/security/ci_configuration/base_security_analyzer_spec.rb
new file mode 100644
index 00000000000..818a7d303bd
--- /dev/null
+++ b/spec/graphql/mutations/security/ci_configuration/base_security_analyzer_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Security::CiConfiguration::BaseSecurityAnalyzer do
+ include GraphqlHelpers
+
+ it 'raises a NotImplementedError error if the resolve method is called on the base class' do
+ user = create(:user)
+ project = create(:project, :public, :repository)
+ project.add_developer(user)
+ expect { resolve(described_class, args: { project_path: project.full_path }, ctx: { current_user: user }) }.to raise_error(NotImplementedError)
+ end
+end
diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb
index ebdb3299bc9..c34fbf42dd8 100644
--- a/spec/graphql/types/base_field_spec.rb
+++ b/spec/graphql/types/base_field_spec.rb
@@ -160,17 +160,17 @@ RSpec.describe Types::BaseField do
let(:flag) { :test_flag }
it 'prepends the description' do
- expect(field.description). to eq 'Test description. Available only when feature flag `test_flag` is enabled.'
+ expect(field.description).to start_with 'Test description. Available only when feature flag `test_flag` is enabled.'
end
context 'falsey feature_flag values' do
using RSpec::Parameterized::TableSyntax
- where(:flag, :feature_value) do
- '' | false
- '' | true
- nil | false
- nil | true
+ where(:flag, :feature_value, :default_enabled) do
+ '' | false | false
+ '' | true | false
+ nil | false | true
+ nil | true | false
end
with_them do
@@ -179,6 +179,33 @@ RSpec.describe Types::BaseField do
end
end
end
+
+ context 'with different default_enabled values' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:feature_value, :default_enabled, :expected_description) do
+ disabled_ff_description = "Test description. Available only when feature flag `test_flag` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice."
+ enabled_ff_description = "Test description. Available only when feature flag `test_flag` is enabled. This flag is enabled by default."
+
+ false | false | disabled_ff_description
+ true | false | disabled_ff_description
+ false | true | enabled_ff_description
+ true | true | enabled_ff_description
+ end
+
+ with_them do
+ before do
+ stub_feature_flags("#{flag}": feature_value)
+
+ allow(Feature::Definition).to receive(:has_definition?).with(flag).and_return(true)
+ allow(Feature::Definition).to receive(:default_enabled?).and_return(default_enabled)
+ end
+
+ it 'returns the correct availability in the description' do
+ expect(field.description). to eq expected_description
+ end
+ end
+ end
end
end
@@ -196,9 +223,8 @@ RSpec.describe Types::BaseField do
feature_flag: 'foo_flag'
)
- expectation = 'Field description. Available only when feature flag `foo_flag` is enabled. Deprecated in 1.10: Deprecation reason.'
-
- expect(field.description).to eq(expectation)
+ expect(field.description).to start_with('Field description. Available only when feature flag `foo_flag` is enabled.')
+ expect(field.description).to end_with('Deprecated in 1.10: Deprecation reason.')
end
end
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 7b194ef8122..f3d0179ffdd 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -771,16 +771,6 @@ RSpec.describe 'project routing' do
end
describe Projects::ServicePingController, 'routing' do
- describe 'deprecated routing' do
- it 'routes to service_ping#web_ide_clientside_preview' do
- expect(post('/gitlab/gitlabhq/usage_ping/web_ide_clientside_preview')).to route_to('projects/service_ping#web_ide_clientside_preview', namespace_id: 'gitlab', project_id: 'gitlabhq')
- end
-
- it 'routes to service_ping#web_ide_pipelines_count' do
- expect(post('/gitlab/gitlabhq/usage_ping/web_ide_pipelines_count')).to route_to('projects/service_ping#web_ide_pipelines_count', namespace_id: 'gitlab', project_id: 'gitlabhq')
- end
- end
-
it 'routes to service_ping#web_ide_clientside_preview' do
expect(post('/gitlab/gitlabhq/service_ping/web_ide_clientside_preview')).to route_to('projects/service_ping#web_ide_clientside_preview', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
diff --git a/vendor/project_templates/cluster_management.tar.gz b/vendor/project_templates/cluster_management.tar.gz
index d24470f1642..a7ed11e7ce3 100644
Binary files a/vendor/project_templates/cluster_management.tar.gz and b/vendor/project_templates/cluster_management.tar.gz differ