diff --git a/app/assets/javascripts/security_configuration/components/constants.js b/app/assets/javascripts/security_configuration/components/constants.js
index e4d2bd08f50..5b04ad6f9ba 100644
--- a/app/assets/javascripts/security_configuration/components/constants.js
+++ b/app/assets/javascripts/security_configuration/components/constants.js
@@ -310,3 +310,7 @@ export const TEMP_PROVIDER_URLS = {
Kontra: 'https://application.security/',
[__('Secure Code Warrior')]: 'https://www.securecodewarrior.com/',
};
+
+export const LICENSE_ULTIMATE = 'ultimate';
+export const LICENSE_FREE = 'free';
+export const LICENSE_PREMIUM = 'premium';
diff --git a/app/assets/javascripts/security_configuration/graphql/current_license.query.graphql b/app/assets/javascripts/security_configuration/graphql/current_license.query.graphql
new file mode 100644
index 00000000000..9ab4f4d4347
--- /dev/null
+++ b/app/assets/javascripts/security_configuration/graphql/current_license.query.graphql
@@ -0,0 +1,6 @@
+query getCurrentLicensePlan {
+ currentLicense {
+ id
+ plan
+ }
+}
diff --git a/app/assets/javascripts/security_configuration/index.js b/app/assets/javascripts/security_configuration/index.js
index 637d510e684..dcc41a38067 100644
--- a/app/assets/javascripts/security_configuration/index.js
+++ b/app/assets/javascripts/security_configuration/index.js
@@ -56,7 +56,6 @@ export const initSecurityConfiguration = (el) => {
'gitlabCiPresent',
'autoDevopsEnabled',
'canEnableAutoDevops',
- 'securityTrainingEnabled',
]),
},
});
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 0efc157bcdf..a6b37d93979 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
@@ -155,7 +155,7 @@ export default {
requests.forEach((request) => {
const poll = new Poll({
resource: {
- fetchData: () => request(this.$props),
+ fetchData: () => request(this),
},
method: 'fetchData',
successCallback: (response) => {
@@ -180,7 +180,7 @@ export default {
initExtensionPolling() {
const poll = new Poll({
resource: {
- fetchData: () => this.fetchCollapsedData(this.$props),
+ fetchData: () => this.fetchCollapsedData(this),
},
method: 'fetchData',
successCallback: ({ data }) => {
@@ -208,7 +208,7 @@ export default {
this.initExtensionPolling();
}
} else {
- this.fetchCollapsedData(this.$props)
+ this.fetchCollapsedData(this)
.then((data) => {
this.setCollapsedData(data);
})
@@ -231,7 +231,7 @@ export default {
this.loadingState = LOADING_STATES.expandedLoading;
- this.fetchFullData(this.$props)
+ this.fetchFullData(this)
.then((data) => {
this.loadingState = null;
this.fullData = data.map((x, i) => ({ id: i, ...x }));
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js
index b9dfd3bd41e..c38e1054090 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js
@@ -34,13 +34,7 @@ export default {
{ ...extension },
{
props: {
- ...extension.props.reduce(
- (acc, key) => ({
- ...acc,
- [key]: this.mr[key],
- }),
- {},
- ),
+ mr: this.mr,
},
},
),
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js
index 65273678fb9..f22c6c756cd 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js
@@ -10,12 +10,26 @@ export const registerExtension = (extension) => {
registeredExtensions.extensions.push({
extends: ExtensionBase,
name: extension.name,
- props: extension.props,
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ },
+ },
i18n: extension.i18n,
expandEvent: extension.expandEvent,
enablePolling: extension.enablePolling,
modalComponent: extension.modalComponent,
computed: {
+ ...extension.props.reduce(
+ (acc, propKey) => ({
+ ...acc,
+ [propKey]() {
+ return this.mr[propKey];
+ },
+ }),
+ {},
+ ),
...Object.keys(extension.computed).reduce(
(acc, computedKey) => ({
...acc,
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue
index 456a1f17aae..bb626c9adba 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue
@@ -49,7 +49,7 @@ export default {
]"
class="gl-rounded-full gl-mr-3 gl-relative gl-p-2"
>
-
+
# String-based single-word label title, or
- [A-Za-z0-9_\-\?\.&]+
+ #{Gitlab::Regex.sep_by_1(/:{1,2}/, /[A-Za-z0-9_\-\?\.&]+/)}
(? [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211339) in GitLab 13.6.
A deployment job can fail because a newer one has run. If you retry the failed deployment job, the
-environment could be overwritten with older source code. If you click **Retry**, a modal warns you
+environment could be overwritten with older source code. If you select **Retry**, a modal warns you
about this and asks for confirmation.
For more information, see [Deployment safety](../environments/deployment_safety.md).
diff --git a/doc/ci/runners/configure_runners.md b/doc/ci/runners/configure_runners.md
index a5e567ad461..221060f89c5 100644
--- a/doc/ci/runners/configure_runners.md
+++ b/doc/ci/runners/configure_runners.md
@@ -85,9 +85,9 @@ To protect or unprotect a runner:
1. Go to the project's **Settings > CI/CD** and expand the **Runners** section.
1. Find the runner you want to protect or unprotect. Make sure it's enabled.
-1. Click the pencil button.
+1. Select the pencil button.
1. Check the **Protected** option.
-1. Click **Save changes**.
+1. Select **Save changes**.
![specific runners edit icon](img/protected_runners_check_box_v14_1.png)
@@ -113,7 +113,7 @@ To reset the registration token:
1. Go to the project's **Settings > CI/CD**.
1. Expand the **General pipelines settings** section.
-1. Find the **Runner token** form field and click the **Reveal value** button.
+1. Find the **Runner token** form field and select **Reveal value**.
1. Delete the value and save the form.
1. After the page is refreshed, expand the **Runners settings** section
and check the registration token - it should be changed.
@@ -193,9 +193,9 @@ To make a runner pick untagged jobs:
1. Go to the project's **Settings > CI/CD** and expand the **Runners** section.
1. Find the runner you want to pick untagged jobs and make sure it's enabled.
-1. Click the pencil button.
+1. Select the pencil button.
1. Check the **Run untagged jobs** option.
-1. Click the **Save changes** button for the changes to take effect.
+1. Select **Save changes** for the changes to take effect.
NOTE:
The runner tags list can not be empty when it's not allowed to pick untagged jobs.
diff --git a/doc/ci/runners/runners_scope.md b/doc/ci/runners/runners_scope.md
index 01032c116df..8b2753d26f1 100644
--- a/doc/ci/runners/runners_scope.md
+++ b/doc/ci/runners/runners_scope.md
@@ -84,7 +84,7 @@ To disable shared runners for a group:
1. Go to the group's **Settings > CI/CD** and expand the **Runners** section.
1. In the **Shared runners** area, turn off the **Enable shared runners for this group** toggle.
1. Optionally, to allow shared runners to be enabled for individual projects or subgroups,
- click **Allow projects and subgroups to override the group setting**.
+ select **Allow projects and subgroups to override the group setting**.
NOTE:
To re-enable the shared runners for a group, turn on the
@@ -200,11 +200,11 @@ You must have the Owner role for the group.
1. Go to the group you want to remove or pause the runner for.
1. On the left sidebar, select **CI/CD > Runners**.
-1. Click **Pause** or **Remove runner**.
+1. Select **Pause** or **Remove runner**.
- If you pause a group runner that is used by multiple projects, the runner pauses for all projects.
- From the group view, you cannot remove a runner that is assigned to more than one project.
You must remove it from each project first.
-1. On the confirmation dialog, click **OK**.
+1. On the confirmation dialog, select **OK**.
## Specific runners
diff --git a/doc/ci/secure_files/index.md b/doc/ci/secure_files/index.md
index 673dca65335..fb421ab8944 100644
--- a/doc/ci/secure_files/index.md
+++ b/doc/ci/secure_files/index.md
@@ -34,8 +34,8 @@ Additional features and capabilities are planned.
To add a secure file to a project:
-1. On the top bar, select **Menu > Projects** and find your project.
-1. On the left sidebar, select **Settings > CI/CD**.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > CI/CD**.
1. In the **Secure Files** section, select **Manage**.
1. Select **Upload File**.
1. Find the file to upload, select **Open**, and the file upload begins immediately.
diff --git a/doc/cloud_seed/index.md b/doc/cloud_seed/index.md
index d4b8d040758..77b22609b12 100644
--- a/doc/cloud_seed/index.md
+++ b/doc/cloud_seed/index.md
@@ -115,6 +115,6 @@ There are several ways you can contribute to Cloud Seed:
and [share feedback](https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/feedback/-/issues/new?template=general_feedback).
- If you are familiar with Ruby on Rails or Vue.js,
consider [contributing to GitLab](../development/contributing/index.md) as a developer.
- - Much of Cloud Seed is an internal module within the GitLab code base.
+ - Much of Cloud Seed is an internal module within the GitLab codebase.
- If you are familiar with GitLab pipelines, consider contributing to
the [Cloud Seed Library](https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/library) project.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index ea1bffe91b0..e12ff085707 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -226,9 +226,9 @@ Download Ruby and compile it:
```shell
mkdir /tmp/ruby && cd /tmp/ruby
-curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.5.tar.gz"
-echo '2755b900a21235b443bb16dadd9032f784d4a88f143d852bc5d154f22b8781f1 ruby-2.7.5.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.5.tar.gz
-cd ruby-2.7.5
+curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.6.tar.gz"
+echo 'e7203b0cc09442ed2c08936d483f8ac140ec1c72e37bb5c401646b7866cb5d10 ruby-2.7.6.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.6.tar.gz
+cd ruby-2.7.6
./configure --disable-install-rdoc --enable-shared
make
diff --git a/doc/integration/auth0.md b/doc/integration/auth0.md
index 1e1ee9aebc5..71c71bd8b5c 100644
--- a/doc/integration/auth0.md
+++ b/doc/integration/auth0.md
@@ -97,6 +97,6 @@ application.
[restart GitLab](../administration/restart_gitlab.md#installations-from-source).
On the sign-in page there should now be an Auth0 icon below the regular sign-in
-form. Click the icon to begin the authentication process. Auth0 asks the
+form. Select the icon to begin the authentication process. Auth0 asks the
user to sign in and authorize the GitLab application. If the user authenticates
successfully, the user is returned to GitLab and signed in.
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index e8780e152c6..ded1449682d 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -261,7 +261,7 @@ To enable languages support:
1. On the left sidebar, select **Settings > Advanced Search**.
1. Locate **Custom analyzers: language support**.
1. Enable plugins support for **Indexing**.
-1. Click **Save changes** for the changes to take effect.
+1. Select **Save changes** for the changes to take effect.
1. Trigger [Zero downtime reindexing](#zero-downtime-reindexing) or reindex everything from scratch to create a new index with updated mappings.
1. Enable plugins support for **Searching** after the previous step is completed.
@@ -435,7 +435,7 @@ Some migrations are built with a retry limit. If the migration cannot finish wit
it is halted and a notification is displayed in the Advanced Search integration settings.
It is recommended to check the [`elasticsearch.log` file](../administration/logs.md#elasticsearchlog) to
debug why the migration was halted and make any changes before retrying the migration. Once you believe you've
-fixed the cause of the failure, click "Retry migration", and the migration is scheduled to be retried
+fixed the cause of the failure, select "Retry migration", and the migration is scheduled to be retried
in the background.
If you cannot get the migration to succeed, you may
@@ -611,7 +611,7 @@ Sidekiq processes](../administration/operations/extra_sidekiq_processes.md).
This enqueues a Sidekiq job for each project that needs to be indexed.
You can view the jobs in **Menu > Admin > Monitoring > Background Jobs > Queues Tab**
- and click `elastic_commit_indexer`, or you can query indexing status using a Rake task:
+ and select `elastic_commit_indexer`, or you can query indexing status using a Rake task:
```shell
# Omnibus installations
diff --git a/doc/subscriptions/index.md b/doc/subscriptions/index.md
index 16bc70792ff..fbc68094f96 100644
--- a/doc/subscriptions/index.md
+++ b/doc/subscriptions/index.md
@@ -91,7 +91,7 @@ To change your personal details, including name, billing address, and email addr
1. Select **My account > Account details**.
1. Expand the **Personal details** section.
1. Edit your personal details.
-1. Click **Save changes**.
+1. Select **Save changes**.
### Change your company details
@@ -101,7 +101,7 @@ To change your company details, including company name and VAT number:
1. Select **My account > Account details**.
1. Expand the **Company details** section.
1. Edit the company details.
-1. Click **Save changes**.
+1. Select **Save changes**.
### Change your payment method
@@ -117,7 +117,7 @@ To change your payment method:
1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
1. Select **My account > Payment methods**.
1. **Edit** an existing payment method's information or **Add new payment method**.
-1. Click **Save Changes**.
+1. Select **Save Changes**.
#### Set a default payment method
@@ -127,7 +127,7 @@ method as the default:
1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
1. Select **My account > Payment methods**.
1. **Edit** the selected payment method and check the **Make default payment method** checkbox.
-1. Click **Save Changes**.
+1. Select **Save Changes**.
### Change the linked account
@@ -137,8 +137,8 @@ To change the GitLab.com account linked to your Customers Portal account:
[Customers Portal](https://customers.gitlab.com/customers/sign_in).
1. In a separate browser tab, go to [GitLab SaaS](https://gitlab.com) and ensure you
are not logged in.
-1. On the Customers Portal page, click **My account > Account details**.
-1. Under **Your GitLab.com account**, click **Change linked account**.
+1. On the Customers Portal page, select **My account > Account details**.
+1. Under **Your GitLab.com account**, select **Change linked account**.
1. Log in to the [GitLab SaaS](https://gitlab.com) account you want to link to the Customers Portal
account.
@@ -164,9 +164,9 @@ Only one namespace can be linked to a subscription.
To change the password for this customers portal account:
1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
-1. Select the **My account** drop-down and click on **Account details**.
+1. Select the **My account** drop-down and select on **Account details**.
1. Make the required changes to the **Your password** section.
-1. Click **Save changes**.
+1. Select **Save changes**.
## Community program subscriptions
diff --git a/doc/update/upgrading_from_source.md b/doc/update/upgrading_from_source.md
index 485dbc1b0bc..8dacadfe27b 100644
--- a/doc/update/upgrading_from_source.md
+++ b/doc/update/upgrading_from_source.md
@@ -69,9 +69,9 @@ Download Ruby and compile it:
```shell
mkdir /tmp/ruby && cd /tmp/ruby
-curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.5.tar.gz"
-echo '2755b900a21235b443bb16dadd9032f784d4a88f143d852bc5d154f22b8781f1 ruby-2.7.5.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.5.tar.gz
-cd ruby-2.7.5
+curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.6.tar.gz"
+echo 'e7203b0cc09442ed2c08936d483f8ac140ec1c72e37bb5c401646b7866cb5d10 ruby-2.7.6.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.6.tar.gz
+cd ruby-2.7.6
./configure --disable-install-rdoc --enable-shared
make
diff --git a/doc/user/asciidoc.md b/doc/user/asciidoc.md
index 80c85358fcb..2a6fbea0bff 100644
--- a/doc/user/asciidoc.md
+++ b/doc/user/asciidoc.md
@@ -235,7 +235,7 @@ v1.0, 2019-01-01
NOTE:
[Wiki pages](project/wiki/index.md#create-a-new-wiki-page) created with the AsciiDoc
format are saved with the file extension `.asciidoc`. When working with AsciiDoc wiki
-pages, change the file name from `.adoc` to `.asciidoc`.
+pages, change the filename from `.adoc` to `.asciidoc`.
```plaintext
include::basics.adoc[]
diff --git a/doc/user/clusters/environments.md b/doc/user/clusters/environments.md
index 4ba0de3bf55..b7732a7abf8 100644
--- a/doc/user/clusters/environments.md
+++ b/doc/user/clusters/environments.md
@@ -49,7 +49,7 @@ In order to:
After you have successful deployments to your group-level or instance-level cluster:
1. Navigate to your group's **Kubernetes** page.
-1. Click on the **Environments** tab.
+1. Select the **Environments** tab.
Only successful deployments to the cluster are included in this page.
Non-cluster environments aren't included.
diff --git a/doc/user/clusters/integrations.md b/doc/user/clusters/integrations.md
index a6dbb5fe0d7..94fb443e0fb 100644
--- a/doc/user/clusters/integrations.md
+++ b/doc/user/clusters/integrations.md
@@ -98,7 +98,7 @@ To enable the Prometheus integration for your cluster:
**Kubernetes** page.
1. Select the **Integrations** tab.
1. Check the **Enable Prometheus integration** checkbox.
-1. Click **Save changes**.
+1. Select **Save changes**.
1. Go to the **Health** tab to see your cluster's metrics.
## Elastic Stack cluster integration **(FREE SELF)**
@@ -165,5 +165,5 @@ To enable the Elastic Stack integration for your cluster:
**Kubernetes** page.
1. Select the **Integrations** tab.
1. Check the **Enable Elastic Stack integration** checkbox.
-1. Click **Save changes**.
+1. Select **Save changes**.
1. Go to the **Health** tab to see your cluster's metrics.
diff --git a/doc/user/group/contribution_analytics/index.md b/doc/user/group/contribution_analytics/index.md
index cd2d5c190a1..ba805d6e1bb 100644
--- a/doc/user/group/contribution_analytics/index.md
+++ b/doc/user/group/contribution_analytics/index.md
@@ -49,7 +49,7 @@ Select the desired period from the calendar dropdown.
## Sorting by different factors
-Contributions per group member are also presented in tabular format. Click a column header to sort the table by that column:
+Contributions per group member are also presented in tabular format. Select a column header to sort the table by that column:
- Member name
- Number of pushed events
diff --git a/doc/user/group/saml_sso/group_managed_accounts.md b/doc/user/group/saml_sso/group_managed_accounts.md
index 6771ff8739a..64f292c18b3 100644
--- a/doc/user/group/saml_sso/group_managed_accounts.md
+++ b/doc/user/group/saml_sso/group_managed_accounts.md
@@ -115,7 +115,7 @@ To set a limit on how long personal access tokens are valid for users in a group
1. Navigate to the **Settings > General** page in your group's sidebar.
1. Expand the **Permissions and group features** section.
1. Fill in the **Maximum allowable lifetime for access tokens (days)** field.
-1. Click **Save changes**.
+1. Select **Save changes**.
Once a lifetime for personal access tokens is set:
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 7c784b0d50e..a767dbb6d06 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -577,7 +577,7 @@ To generate a SAML Response:
- [SAML-tracer](https://addons.mozilla.org/en-US/firefox/addon/saml-tracer/) for Firefox.
1. Open a new browser tab.
1. Open the SAML tracer console:
- - Chrome: Right click on the page, select **Inspect**, then click on the SAML tab in the opened developer console.
+ - Chrome: Right click on the page, select **Inspect**, then select the SAML tab in the opened developer console.
- Firefox: Select the SAML-tracer icon located on the browser toolbar.
1. Go to the GitLab single sign-on URL for the group in the same browser tab with the SAML tracer open.
1. Select **Authorize** or attempt to log in. A SAML response is displayed in the tracer console that resembles this
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index 42cf442ea94..cc154b96ed0 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -82,7 +82,7 @@ table, use the Azure defaults. For a list of required attributes, refer to the [
For guidance, you can view [an example configuration in the troubleshooting reference](../../../administration/troubleshooting/group_saml_scim.md#azure-active-directory).
-1. Below the mapping list click on **Show advanced options > Edit attribute list for AppName**.
+1. Below the mapping list select **Show advanced options > Edit attribute list for AppName**.
1. Ensure the `id` is the primary and required field, and `externalId` is also required.
NOTE:
diff --git a/doc/user/operations_dashboard/index.md b/doc/user/operations_dashboard/index.md
index 6525a3e2a8d..1b14582a3f0 100644
--- a/doc/user/operations_dashboard/index.md
+++ b/doc/user/operations_dashboard/index.md
@@ -23,9 +23,9 @@ To add a project to the dashboard:
1. Ensure your alerts populate the `gitlab_environment_name` label on the alerts you set up in Prometheus.
The value of this should match the name of your environment in GitLab.
In GitLab 13.9, you can display alerts for the `production` environment only.
-1. Click the **Add projects** button in the home screen of the dashboard.
+1. Select **Add projects** in the home screen of the dashboard.
1. Search and add one or more projects using the **Search your projects** field.
-1. Click the **Add projects** button.
+1. Select **Add projects**.
Once added, the dashboard displays the project's number of active alerts,
last commit, pipeline status, and when it was last deployed.
diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md
index fffa21c308f..0403bbae2b5 100644
--- a/doc/user/packages/container_registry/index.md
+++ b/doc/user/packages/container_registry/index.md
@@ -57,7 +57,7 @@ To download and run a container image hosted in the GitLab Container Registry:
1. Copy the link to your container image:
- Go to your project or group's **Packages & Registries > Container Registry**
and find the image you want.
- - Next to the image name, click the **Copy** button.
+ - Next to the image name, select **Copy**.
![Container Registry image URL](img/container_registry_hover_path_13_4.png)
@@ -404,7 +404,7 @@ To delete images from within GitLab:
by clicking the red **{remove}** **Trash** icon next to the tag you want
to delete.
-1. In the dialog box, click **Remove tag**.
+1. In the dialog box, select **Remove tag**.
### Delete images using the API
@@ -506,7 +506,7 @@ You can, however, remove the Container Registry for a project:
1. Go to your project's **Settings > General** page.
1. Expand the **Visibility, project features, permissions** section
and disable **Container Registry**.
-1. Click **Save changes**.
+1. Select **Save changes**.
The **Packages & Registries > Container Registry** entry is removed from the project's sidebar.
diff --git a/doc/user/packages/container_registry/reduce_container_registry_storage.md b/doc/user/packages/container_registry/reduce_container_registry_storage.md
index 7b52a6a8ce3..3e41a260854 100644
--- a/doc/user/packages/container_registry/reduce_container_registry_storage.md
+++ b/doc/user/packages/container_registry/reduce_container_registry_storage.md
@@ -109,12 +109,12 @@ To create a cleanup policy in the UI:
| **Remove tags older than** | Remove only tags older than X days. |
| **Remove tags matching** | The regex pattern that determines which tags to remove. This value cannot be blank. For all tags, use `.*`. See other [regex pattern examples](#regex-pattern-examples). |
-1. Click **Save**.
+1. Select **Save**.
Depending on the interval you chose, the policy is scheduled to run.
NOTE:
-If you edit the policy and click **Save** again, the interval is reset.
+If you edit the policy and select **Save** again, the interval is reset.
### Regex pattern examples
diff --git a/doc/user/packages/maven_repository/index.md b/doc/user/packages/maven_repository/index.md
index 1e3b5bdc323..eaa04404a1f 100644
--- a/doc/user/packages/maven_repository/index.md
+++ b/doc/user/packages/maven_repository/index.md
@@ -701,7 +701,7 @@ dependencies {
For your project, go to **Packages & Registries > Package Registry**.
-To remove a package, click the red trash icon or, from the package details, the **Delete** button.
+To remove a package, select the red trash icon or, from the package details, the **Delete** button.
## Create Maven packages with GitLab CI/CD
diff --git a/doc/user/packages/nuget_repository/index.md b/doc/user/packages/nuget_repository/index.md
index 37b6404d487..2e182d20811 100644
--- a/doc/user/packages/nuget_repository/index.md
+++ b/doc/user/packages/nuget_repository/index.md
@@ -171,7 +171,7 @@ To use the [project-level](#use-the-gitlab-endpoint-for-nuget-packages) NuGet en
![Visual Studio Adding a NuGet source](img/visual_studio_adding_nuget_source.png)
-1. Click **Save**.
+1. Select **Save**.
The source is displayed in your list.
@@ -200,7 +200,7 @@ To use the [group-level](#use-the-gitlab-endpoint-for-nuget-packages) NuGet endp
![Visual Studio Adding a NuGet source](img/visual_studio_adding_nuget_source.png)
-1. Click **Save**.
+1. Select **Save**.
The source is displayed in your list.
diff --git a/doc/user/packages/package_registry/reduce_package_registry_storage.md b/doc/user/packages/package_registry/reduce_package_registry_storage.md
index f8a1e63a228..ed4ef1665bc 100644
--- a/doc/user/packages/package_registry/reduce_package_registry_storage.md
+++ b/doc/user/packages/package_registry/reduce_package_registry_storage.md
@@ -31,7 +31,7 @@ To delete a package in the UI, from your group or project:
1. Go to **Packages & Registries > Package Registry**.
1. Find the name of the package you want to delete.
-1. Click **Delete**.
+1. Select **Delete**.
The package is permanently deleted.
diff --git a/doc/user/search/global_search/advanced_search_syntax.md b/doc/user/search/global_search/advanced_search_syntax.md
index 5604177431c..219531070b3 100644
--- a/doc/user/search/global_search/advanced_search_syntax.md
+++ b/doc/user/search/global_search/advanced_search_syntax.md
@@ -33,7 +33,7 @@ Advanced Search searches default project branches only.
| Use | Description | Example |
|--------------|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `filename:` | File name | [`filename:*spec.rb`](https://gitlab.com/search?snippets=&scope=blobs&repository_ref=&search=filename%3A*spec.rb&group_id=9970&project_id=278964) |
+| `filename:` | Filename | [`filename:*spec.rb`](https://gitlab.com/search?snippets=&scope=blobs&repository_ref=&search=filename%3A*spec.rb&group_id=9970&project_id=278964) |
| `path:` | Repository location | [`path:spec/workers/`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=path%3Aspec%2Fworkers&snippets=) |
| `extension:` | File extension, without the `.` | [`extension:js`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=extension%3Ajs&snippets=) |
| `blob:` | Git object ID | [`blob:998707*`](https://gitlab.com/search?snippets=false&scope=blobs&repository_ref=&search=blob%3A998707*&group_id=9970) |
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index 171d8a63d2d..9cec9cb3316 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -181,7 +181,7 @@ Search history is available for issues and merge requests, and is stored locally
in your browser. To run a search from history:
1. In the top menu, select **Issues** or **Merge requests**.
-1. To the left of the search bar, click **Recent searches**, and select a search from the list.
+1. To the left of the search bar, select **Recent searches**, and select a search from the list.
## Removing search filters
diff --git a/doc/user/upgrade_email_bypass.md b/doc/user/upgrade_email_bypass.md
index 8cd9a47f3e6..6401828270d 100644
--- a/doc/user/upgrade_email_bypass.md
+++ b/doc/user/upgrade_email_bypass.md
@@ -27,7 +27,7 @@ sent within five minutes, with a link for users to re-confirm the subject email
## Do the confirmation emails expire?
-The links in these re-confirmation emails expire after one day by default. Users who click an expired link are asked to request a new re-confirmation email. Any user can request a new re-confirmation email from `http://gitlab.example.com/users/confirmation/new`.
+The links in these re-confirmation emails expire after one day by default. Users who select an expired link are asked to request a new re-confirmation email. Any user can request a new re-confirmation email from `http://gitlab.example.com/users/confirmation/new`.
## Generate a list of affected users
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 205106afddb..50ac90cb449 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -481,6 +481,11 @@ module Gitlab
"can contain only lowercase letters, digits, '_' and '-'. " \
"Must start with a letter, and cannot end with '-' or '_'"
end
+
+ # One or more `part`s, separated by separator
+ def sep_by_1(separator, part)
+ %r(#{part} (#{separator} #{part})*)x
+ end
end
end
diff --git a/lib/sidebars/groups/menus/customer_relations_menu.rb b/lib/sidebars/groups/menus/customer_relations_menu.rb
index 0aaa6ec45f1..e0772cfe403 100644
--- a/lib/sidebars/groups/menus/customer_relations_menu.rb
+++ b/lib/sidebars/groups/menus/customer_relations_menu.rb
@@ -35,7 +35,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Contacts'),
link: group_crm_contacts_path(context.group),
- active_routes: { path: 'groups/crm#contacts' },
+ active_routes: { controller: 'groups/crm/contacts' },
item_id: :crm_contacts
)
end
@@ -44,7 +44,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Organizations'),
link: group_crm_organizations_path(context.group),
- active_routes: { path: 'groups/crm#organizations' },
+ active_routes: { controller: 'groups/crm/organizations' },
item_id: :crm_organizations
)
end
diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js
index 161f1a405d1..d7d46d0d415 100644
--- a/spec/frontend/security_configuration/components/app_spec.js
+++ b/spec/frontend/security_configuration/components/app_spec.js
@@ -2,6 +2,7 @@ import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { GlTab, GlTabs, GlLink } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
+
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
import stubChildren from 'helpers/stub_children';
@@ -19,14 +20,22 @@ import {
LICENSE_COMPLIANCE_DESCRIPTION,
LICENSE_COMPLIANCE_HELP_PATH,
AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY,
+ LICENSE_ULTIMATE,
+ LICENSE_PREMIUM,
+ LICENSE_FREE,
} from '~/security_configuration/components/constants';
import FeatureCard from '~/security_configuration/components/feature_card.vue';
import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import currentLicenseQuery from '~/security_configuration/graphql/current_license.query.graphql';
+import waitForPromises from 'helpers/wait_for_promises';
+
import UpgradeBanner from '~/security_configuration/components/upgrade_banner.vue';
import {
REPORT_TYPE_LICENSE_COMPLIANCE,
REPORT_TYPE_SAST,
} from '~/vue_shared/security_reports/constants';
+import { getCurrentLicensePlanResponse } from '../mock_data';
const upgradePath = '/upgrade';
const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath';
@@ -41,40 +50,31 @@ Vue.use(VueApollo);
describe('App component', () => {
let wrapper;
let userCalloutDismissSpy;
+ let mockApollo;
- const securityFeaturesMock = [
- {
- name: SAST_NAME,
- shortName: SAST_SHORT_NAME,
- description: SAST_DESCRIPTION,
- helpPath: SAST_HELP_PATH,
- configurationHelpPath: SAST_CONFIG_HELP_PATH,
- type: REPORT_TYPE_SAST,
- available: true,
- },
- ];
-
- const complianceFeaturesMock = [
- {
- name: LICENSE_COMPLIANCE_NAME,
- description: LICENSE_COMPLIANCE_DESCRIPTION,
- helpPath: LICENSE_COMPLIANCE_HELP_PATH,
- type: REPORT_TYPE_LICENSE_COMPLIANCE,
- configurationHelpPath: LICENSE_COMPLIANCE_HELP_PATH,
- },
- ];
-
- const createComponent = ({ shouldShowCallout = true, ...propsData } = {}) => {
+ const createComponent = ({
+ shouldShowCallout = true,
+ licenseQueryResponse = LICENSE_ULTIMATE,
+ ...propsData
+ }) => {
userCalloutDismissSpy = jest.fn();
+ mockApollo = createMockApollo([
+ [
+ currentLicenseQuery,
+ jest
+ .fn()
+ .mockResolvedValue(
+ licenseQueryResponse instanceof Error
+ ? licenseQueryResponse
+ : getCurrentLicensePlanResponse(licenseQueryResponse),
+ ),
+ ],
+ ]);
+
wrapper = extendedWrapper(
mount(SecurityConfigurationApp, {
- propsData: {
- augmentedSecurityFeatures: securityFeaturesMock,
- augmentedComplianceFeatures: complianceFeaturesMock,
- securityTrainingEnabled: true,
- ...propsData,
- },
+ propsData,
provide: {
upgradePath,
autoDevopsHelpPagePath,
@@ -82,6 +82,7 @@ describe('App component', () => {
projectFullPath,
vulnerabilityTrainingDocsPath,
},
+ apolloProvider: mockApollo,
stubs: {
...stubChildren(SecurityConfigurationApp),
GlLink: false,
@@ -132,13 +133,40 @@ describe('App component', () => {
const findAutoDevopsEnabledAlert = () => wrapper.findComponent(AutoDevopsEnabledAlert);
const findVulnerabilityManagementTab = () => wrapper.findByTestId('vulnerability-management-tab');
+ const securityFeaturesMock = [
+ {
+ name: SAST_NAME,
+ shortName: SAST_SHORT_NAME,
+ description: SAST_DESCRIPTION,
+ helpPath: SAST_HELP_PATH,
+ configurationHelpPath: SAST_CONFIG_HELP_PATH,
+ type: REPORT_TYPE_SAST,
+ available: true,
+ },
+ ];
+
+ const complianceFeaturesMock = [
+ {
+ name: LICENSE_COMPLIANCE_NAME,
+ description: LICENSE_COMPLIANCE_DESCRIPTION,
+ helpPath: LICENSE_COMPLIANCE_HELP_PATH,
+ type: REPORT_TYPE_LICENSE_COMPLIANCE,
+ configurationHelpPath: LICENSE_COMPLIANCE_HELP_PATH,
+ },
+ ];
+
afterEach(() => {
wrapper.destroy();
+ mockApollo = null;
});
describe('basic structure', () => {
- beforeEach(() => {
- createComponent();
+ beforeEach(async () => {
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ });
+ await waitForPromises();
});
it('renders main-heading with correct text', () => {
@@ -198,7 +226,10 @@ describe('App component', () => {
describe('Manage via MR Error Alert', () => {
beforeEach(() => {
- createComponent();
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ });
});
describe('on initial load', () => {
@@ -234,6 +265,8 @@ describe('App component', () => {
describe('given the right props', () => {
beforeEach(() => {
createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
autoDevopsEnabled: false,
gitlabCiPresent: false,
canEnableAutoDevops: true,
@@ -255,7 +288,10 @@ describe('App component', () => {
describe('given the wrong props', () => {
beforeEach(() => {
- createComponent();
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ });
});
it('should not show AutoDevopsAlert', () => {
expect(findAutoDevopsAlert().exists()).toBe(false);
@@ -279,7 +315,11 @@ describe('App component', () => {
);
}
- createComponent({ autoDevopsEnabled });
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ autoDevopsEnabled,
+ });
});
it(shouldRender ? 'renders' : 'does not render', () => {
@@ -305,7 +345,12 @@ describe('App component', () => {
);
}
- createComponent({ autoDevopsEnabled: true });
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ autoDevopsEnabled: true,
+ });
+
findAutoDevopsEnabledAlert().vm.$emit('dismiss');
});
@@ -330,6 +375,7 @@ describe('App component', () => {
describe('given at least one unavailable feature', () => {
beforeEach(() => {
createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)),
});
});
@@ -350,6 +396,7 @@ describe('App component', () => {
describe('given at least one unavailable feature, but banner is already dismissed', () => {
beforeEach(() => {
createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)),
shouldShowCallout: false,
});
@@ -376,7 +423,11 @@ describe('App component', () => {
describe('when given latestPipelinePath props', () => {
beforeEach(() => {
- createComponent({ latestPipelinePath: 'test/path' });
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ latestPipelinePath: 'test/path',
+ });
});
it('should show latest pipeline info on the security tab with correct link when latestPipelinePath is defined', () => {
@@ -401,6 +452,8 @@ describe('App component', () => {
describe('given gitlabCiPresent & gitlabCiHistoryPath props', () => {
beforeEach(() => {
createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
gitlabCiPresent: true,
gitlabCiHistoryPath,
});
@@ -415,36 +468,48 @@ describe('App component', () => {
});
});
- describe('Vulnerability management tab', () => {
- it('does not show tab if security training is disabled', () => {
- createComponent({ securityTrainingEnabled: false });
-
- expect(findVulnerabilityManagementTab().exists()).toBe(false);
+ describe('Vulnerability management', () => {
+ beforeEach(async () => {
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ });
+ await waitForPromises();
});
- describe('security training enabled', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('shows the tab if security training is enabled', () => {
- expect(findVulnerabilityManagementTab().exists()).toBe(true);
- });
-
- it('renders TrainingProviderList component', () => {
- expect(findTrainingProviderList().exists()).toBe(true);
- });
-
- it('renders security training description', () => {
- expect(findVulnerabilityManagementTab().text()).toContain(i18n.securityTrainingDescription);
- });
-
- it('renders link to help docs', () => {
- const trainingLink = findVulnerabilityManagementTab().findComponent(GlLink);
-
- expect(trainingLink.text()).toBe('Learn more about vulnerability training');
- expect(trainingLink.attributes('href')).toBe(vulnerabilityTrainingDocsPath);
- });
+ it('renders TrainingProviderList component', () => {
+ expect(findTrainingProviderList().exists()).toBe(true);
});
+
+ it('renders security training description', () => {
+ expect(findVulnerabilityManagementTab().text()).toContain(i18n.securityTrainingDescription);
+ });
+
+ it('renders link to help docs', () => {
+ const trainingLink = findVulnerabilityManagementTab().findComponent(GlLink);
+
+ expect(trainingLink.text()).toBe('Learn more about vulnerability training');
+ expect(trainingLink.attributes('href')).toBe(vulnerabilityTrainingDocsPath);
+ });
+
+ it.each`
+ licenseQueryResponse | display
+ ${LICENSE_ULTIMATE} | ${true}
+ ${LICENSE_PREMIUM} | ${false}
+ ${LICENSE_FREE} | ${false}
+ ${null} | ${true}
+ ${new Error()} | ${true}
+ `(
+ 'displays $display for license $licenseQueryResponse',
+ async ({ licenseQueryResponse, display }) => {
+ createComponent({
+ licenseQueryResponse,
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ });
+ await waitForPromises();
+ expect(findVulnerabilityManagementTab().exists()).toBe(display);
+ },
+ );
});
});
diff --git a/spec/frontend/security_configuration/mock_data.js b/spec/frontend/security_configuration/mock_data.js
index 18a480bf082..94a36472a1d 100644
--- a/spec/frontend/security_configuration/mock_data.js
+++ b/spec/frontend/security_configuration/mock_data.js
@@ -111,3 +111,12 @@ export const tempProviderLogos = {
svg: ``,
},
};
+
+export const getCurrentLicensePlanResponse = (plan) => ({
+ data: {
+ currentLicense: {
+ id: 'gid://gitlab/License/1',
+ plan,
+ },
+ },
+});
diff --git a/spec/frontend/vue_mr_widget/components/extensions/index_spec.js b/spec/frontend/vue_mr_widget/components/extensions/index_spec.js
index 63df63a9b00..dc25596655a 100644
--- a/spec/frontend/vue_mr_widget/components/extensions/index_spec.js
+++ b/spec/frontend/vue_mr_widget/components/extensions/index_spec.js
@@ -21,8 +21,8 @@ describe('MR widget extension registering', () => {
expect.objectContaining({
extends: ExtensionBase,
name: 'Test',
- props: ['helloWorld'],
computed: {
+ helloWorld: expect.any(Function),
test: expect.any(Function),
},
methods: {
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 5cbdba70815..5e4ffeb8455 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -8323,14 +8323,6 @@ RSpec.describe Project, factory_default: :keep do
end
end
- describe '#security_training_available?' do
- subject { build(:project) }
-
- it 'returns false' do
- expect(subject.security_training_available?).to eq false
- end
- end
-
private
def finish_job(export_job)
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index b67fd928e00..d928c1fb64a 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -122,7 +122,7 @@ RSpec.describe QuickActions::InterpretService do
inprogress # populate the label
_, updates, _ = service.execute(content, issuable)
- expect(updates).to eq(add_label_ids: [bug.id, inprogress.id])
+ expect(updates).to match(add_label_ids: contain_exactly(bug.id, inprogress.id))
end
it 'returns the label message' do
@@ -130,7 +130,10 @@ RSpec.describe QuickActions::InterpretService do
inprogress # populate the label
_, _, message = service.execute(content, issuable)
- expect(message).to eq("Added #{bug.to_reference(format: :name)} #{inprogress.to_reference(format: :name)} labels.")
+ # Compare message without making assumptions about ordering.
+ expect(message).to match %r{Added ~".*" ~".*" labels.}
+ expect(message).to include(bug.to_reference(format: :name))
+ expect(message).to include(inprogress.to_reference(format: :name))
end
end
@@ -1196,6 +1199,64 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { merge_request }
end
+ context 'with a colon label' do
+ let(:bug) { create(:label, project: project, title: 'Category:Bug') }
+ let(:inprogress) { create(:label, project: project, title: 'status:in:progress') }
+
+ context 'when quoted' do
+ let(:content) { %(/label ~"#{inprogress.title}" ~"#{bug.title}" ~unknown) }
+
+ it_behaves_like 'label command' do
+ let(:issuable) { merge_request }
+ end
+
+ it_behaves_like 'label command' do
+ let(:issuable) { issue }
+ end
+ end
+
+ context 'when unquoted' do
+ let(:content) { %(/label ~#{inprogress.title} ~#{bug.title} ~unknown) }
+
+ it_behaves_like 'label command' do
+ let(:issuable) { merge_request }
+ end
+
+ it_behaves_like 'label command' do
+ let(:issuable) { issue }
+ end
+ end
+ end
+
+ context 'with a scoped label' do
+ let(:bug) { create(:label, :scoped, project: project) }
+ let(:inprogress) { create(:label, project: project, title: 'three::part::label') }
+
+ context 'when quoted' do
+ let(:content) { %(/label ~"#{inprogress.title}" ~"#{bug.title}" ~unknown) }
+
+ it_behaves_like 'label command' do
+ let(:issuable) { merge_request }
+ end
+
+ it_behaves_like 'label command' do
+ let(:issuable) { issue }
+ end
+ end
+
+ context 'when unquoted' do
+ let(:content) { %(/label ~#{inprogress.title} ~#{bug.title} ~unknown) }
+
+ it_behaves_like 'label command' do
+ let(:issuable) { merge_request }
+ end
+
+ it_behaves_like 'label command' do
+ let(:issuable) { issue }
+ end
+ end
+ end
+
it_behaves_like 'multiple label command' do
let(:content) { %(/label ~"#{inprogress.title}" \n/label ~#{bug.title}) }
let(:issuable) { issue }