Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-05-24 21:09:08 +00:00
parent 8015f09545
commit e09f6bdfd1
52 changed files with 340 additions and 179 deletions

View File

@ -38,9 +38,9 @@ export const toggleContainerClasses = (containerEl, classList) => {
/** /**
* Return a object mapping element dataset names to booleans. * Return a object mapping element dataset names to booleans.
* *
* This is useful for data- attributes whose presence represent * This is useful for data- attributes whose presense represent
* a truthiness, no matter the value of the attribute. The absence of the * a truthiness, no matter the value of the attribute. The absense of the
* attribute represents falsiness. * attribute represents falsiness.
* *
* This can be useful when Rails-provided boolean-like values are passed * This can be useful when Rails-provided boolean-like values are passed
* directly to the HAML template, rather than cast to a string. * directly to the HAML template, rather than cast to a string.

View File

@ -4,9 +4,10 @@ import { __, s__ } from '~/locale';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue'; import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
import SectionLayout from '~/vue_shared/security_configuration/components/section_layout.vue'; import SectionLayout from '~/vue_shared/security_configuration/components/section_layout.vue';
import currentLicenseQuery from '~/security_configuration/graphql/current_license.query.graphql';
import AutoDevOpsAlert from './auto_dev_ops_alert.vue'; import AutoDevOpsAlert from './auto_dev_ops_alert.vue';
import AutoDevOpsEnabledAlert from './auto_dev_ops_enabled_alert.vue'; import AutoDevOpsEnabledAlert from './auto_dev_ops_enabled_alert.vue';
import { AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY } from './constants'; import { AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY, LICENSE_ULTIMATE } from './constants';
import FeatureCard from './feature_card.vue'; import FeatureCard from './feature_card.vue';
import TrainingProviderList from './training_provider_list.vue'; import TrainingProviderList from './training_provider_list.vue';
import UpgradeBanner from './upgrade_banner.vue'; import UpgradeBanner from './upgrade_banner.vue';
@ -50,6 +51,17 @@ export default {
TrainingProviderList, TrainingProviderList,
}, },
inject: ['projectFullPath', 'vulnerabilityTrainingDocsPath'], inject: ['projectFullPath', 'vulnerabilityTrainingDocsPath'],
apollo: {
currentLicensePlan: {
query: currentLicenseQuery,
update({ currentLicense }) {
return currentLicense?.plan;
},
error() {
this.hasCurrentLicenseFetchError = true;
},
},
},
props: { props: {
augmentedSecurityFeatures: { augmentedSecurityFeatures: {
type: Array, type: Array,
@ -84,15 +96,13 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
securityTrainingEnabled: {
type: Boolean,
required: true,
},
}, },
data() { data() {
return { return {
autoDevopsEnabledAlertDismissedProjects: [], autoDevopsEnabledAlertDismissedProjects: [],
errorMessage: '', errorMessage: '',
currentLicensePlan: '',
hasCurrentLicenseFetchError: false,
}; };
}, },
computed: { computed: {
@ -113,6 +123,12 @@ export default {
!this.autoDevopsEnabledAlertDismissedProjects.includes(this.projectFullPath) !this.autoDevopsEnabledAlertDismissedProjects.includes(this.projectFullPath)
); );
}, },
shouldShowVulnerabilityManagementTab() {
// if the query fails (if the plan is `null` also means an error has occurred) we still want to show the feature
const hasQueryError = this.hasCurrentLicenseFetchError || this.currentLicensePlan === null;
return hasQueryError || this.currentLicensePlan === LICENSE_ULTIMATE;
},
}, },
methods: { methods: {
dismissAutoDevopsEnabledAlert() { dismissAutoDevopsEnabledAlert() {
@ -237,9 +253,9 @@ export default {
{{ $options.i18n.description }} {{ $options.i18n.description }}
</p> </p>
<p v-if="canViewCiHistory"> <p v-if="canViewCiHistory">
<gl-link data-testid="compliance-view-history-link" :href="gitlabCiHistoryPath"> <gl-link data-testid="compliance-view-history-link" :href="gitlabCiHistoryPath">{{
{{ $options.i18n.configurationHistory }} $options.i18n.configurationHistory
</gl-link> }}</gl-link>
</p> </p>
</template> </template>
<template #features> <template #features>
@ -254,18 +270,20 @@ export default {
</section-layout> </section-layout>
</gl-tab> </gl-tab>
<gl-tab <gl-tab
v-if="securityTrainingEnabled" v-if="shouldShowVulnerabilityManagementTab"
data-testid="vulnerability-management-tab" data-testid="vulnerability-management-tab"
:title="$options.i18n.vulnerabilityManagement" :title="$options.i18n.vulnerabilityManagement"
query-param-value="vulnerability-management" query-param-value="vulnerability-management"
> >
<section-layout :heading="$options.i18n.securityTraining"> <section-layout :heading="$options.i18n.securityTraining">
<template #description> <template #description>
<p>{{ $options.i18n.securityTrainingDescription }}</p>
<p> <p>
<gl-link :href="vulnerabilityTrainingDocsPath"> {{ $options.i18n.securityTrainingDescription }}
{{ $options.i18n.securityTrainingDoc }} </p>
</gl-link> <p>
<gl-link :href="vulnerabilityTrainingDocsPath">{{
$options.i18n.securityTrainingDoc
}}</gl-link>
</p> </p>
</template> </template>
<template #features> <template #features>

View File

@ -310,3 +310,7 @@ export const TEMP_PROVIDER_URLS = {
Kontra: 'https://application.security/', Kontra: 'https://application.security/',
[__('Secure Code Warrior')]: 'https://www.securecodewarrior.com/', [__('Secure Code Warrior')]: 'https://www.securecodewarrior.com/',
}; };
export const LICENSE_ULTIMATE = 'ultimate';
export const LICENSE_FREE = 'free';
export const LICENSE_PREMIUM = 'premium';

View File

@ -0,0 +1,6 @@
query getCurrentLicensePlan {
currentLicense {
id
plan
}
}

View File

@ -56,7 +56,6 @@ export const initSecurityConfiguration = (el) => {
'gitlabCiPresent', 'gitlabCiPresent',
'autoDevopsEnabled', 'autoDevopsEnabled',
'canEnableAutoDevops', 'canEnableAutoDevops',
'securityTrainingEnabled',
]), ]),
}, },
}); });

View File

@ -155,7 +155,7 @@ export default {
requests.forEach((request) => { requests.forEach((request) => {
const poll = new Poll({ const poll = new Poll({
resource: { resource: {
fetchData: () => request(this.$props), fetchData: () => request(this),
}, },
method: 'fetchData', method: 'fetchData',
successCallback: (response) => { successCallback: (response) => {
@ -180,7 +180,7 @@ export default {
initExtensionPolling() { initExtensionPolling() {
const poll = new Poll({ const poll = new Poll({
resource: { resource: {
fetchData: () => this.fetchCollapsedData(this.$props), fetchData: () => this.fetchCollapsedData(this),
}, },
method: 'fetchData', method: 'fetchData',
successCallback: ({ data }) => { successCallback: ({ data }) => {
@ -208,7 +208,7 @@ export default {
this.initExtensionPolling(); this.initExtensionPolling();
} }
} else { } else {
this.fetchCollapsedData(this.$props) this.fetchCollapsedData(this)
.then((data) => { .then((data) => {
this.setCollapsedData(data); this.setCollapsedData(data);
}) })
@ -231,7 +231,7 @@ export default {
this.loadingState = LOADING_STATES.expandedLoading; this.loadingState = LOADING_STATES.expandedLoading;
this.fetchFullData(this.$props) this.fetchFullData(this)
.then((data) => { .then((data) => {
this.loadingState = null; this.loadingState = null;
this.fullData = data.map((x, i) => ({ id: i, ...x })); this.fullData = data.map((x, i) => ({ id: i, ...x }));

View File

@ -34,13 +34,7 @@ export default {
{ ...extension }, { ...extension },
{ {
props: { props: {
...extension.props.reduce( mr: this.mr,
(acc, key) => ({
...acc,
[key]: this.mr[key],
}),
{},
),
}, },
}, },
), ),

View File

@ -10,12 +10,26 @@ export const registerExtension = (extension) => {
registeredExtensions.extensions.push({ registeredExtensions.extensions.push({
extends: ExtensionBase, extends: ExtensionBase,
name: extension.name, name: extension.name,
props: extension.props, props: {
mr: {
type: Object,
required: true,
},
},
i18n: extension.i18n, i18n: extension.i18n,
expandEvent: extension.expandEvent, expandEvent: extension.expandEvent,
enablePolling: extension.enablePolling, enablePolling: extension.enablePolling,
modalComponent: extension.modalComponent, modalComponent: extension.modalComponent,
computed: { computed: {
...extension.props.reduce(
(acc, propKey) => ({
...acc,
[propKey]() {
return this.mr[propKey];
},
}),
{},
),
...Object.keys(extension.computed).reduce( ...Object.keys(extension.computed).reduce(
(acc, computedKey) => ({ (acc, computedKey) => ({
...acc, ...acc,

View File

@ -49,7 +49,7 @@ export default {
]" ]"
class="gl-rounded-full gl-mr-3 gl-relative gl-p-2" class="gl-rounded-full gl-mr-3 gl-relative gl-p-2"
> >
<gl-loading-icon v-if="isLoading" size="lg" inline class="gl-display-block" /> <gl-loading-icon v-if="isLoading" size="sm" inline class="gl-display-block" />
<gl-icon <gl-icon
v-else v-else
:name="$options.EXTENSION_ICON_NAMES[iconName]" :name="$options.EXTENSION_ICON_NAMES[iconName]"

View File

@ -8,8 +8,7 @@
a { a {
color: $gl-text-color; color: $gl-text-color;
&.link, &.link {
&.gl-link {
color: $blue-600; color: $blue-600;
} }
} }

View File

@ -246,13 +246,13 @@ module MergeRequestsHelper
'' ''
end end
link_to branch, branch_path, title: branch, class: 'gl-link gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mb-n2' link_to branch, branch_path, title: branch, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mb-n2'
end end
def merge_request_header(project, merge_request) def merge_request_header(project, merge_request)
link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-weight-bold', avatar: false) link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-weight-bold', avatar: false)
copy_button = clipboard_button(text: merge_request.source_branch, title: _('Copy branch name'), class: 'btn btn-default btn-sm gl-button btn-default-tertiary btn-icon gl-display-none! gl-md-display-inline-block! js-source-branch-copy') copy_button = clipboard_button(text: merge_request.source_branch, title: _('Copy branch name'), class: 'btn btn-default btn-sm gl-button btn-default-tertiary btn-icon gl-display-none! gl-md-display-inline-block! js-source-branch-copy')
target_branch = link_to merge_request.target_branch, project_tree_path(merge_request.target_project, merge_request.target_branch), title: merge_request.target_branch, class: 'gl-link gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mb-n2' target_branch = link_to merge_request.target_branch, project_tree_path(merge_request.target_project, merge_request.target_branch), title: merge_request.target_branch, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mb-n2'
_('%{author} requested to merge %{source_branch} %{copy_button} into %{target_branch} %{created_at}').html_safe % { author: link_to_author.html_safe, source_branch: merge_request_source_branch(merge_request).html_safe, copy_button: copy_button.html_safe, target_branch: target_branch.html_safe, created_at: time_ago_with_tooltip(merge_request.created_at, html_class: 'gl-display-inline-block').html_safe } _('%{author} requested to merge %{source_branch} %{copy_button} into %{target_branch} %{created_at}').html_safe % { author: link_to_author.html_safe, source_branch: merge_request_source_branch(merge_request).html_safe, copy_button: copy_button.html_safe, target_branch: target_branch.html_safe, created_at: time_ago_with_tooltip(merge_request.created_at, html_class: 'gl-display-inline-block').html_safe }
end end

View File

@ -118,7 +118,7 @@ class Label < ApplicationRecord
| # Integer-based label ID, or | # Integer-based label ID, or
(?<label_name> (?<label_name>
# String-based single-word label title, or # String-based single-word label title, or
[A-Za-z0-9_\-\?\.&]+ #{Gitlab::Regex.sep_by_1(/:{1,2}/, /[A-Za-z0-9_\-\?\.&]+/)}
(?<!\.|\?) (?<!\.|\?)
| |
# String-based multi-word label surrounded in quotes # String-based multi-word label surrounded in quotes

View File

@ -2906,10 +2906,6 @@ class Project < ApplicationRecord
build_artifacts_size_refresh&.started? build_artifacts_size_refresh&.started?
end end
def security_training_available?
licensed_feature_available?(:security_training)
end
private private
# overridden in EE # overridden in EE

View File

@ -24,8 +24,7 @@ module Projects
gitlab_ci_history_path: gitlab_ci_history_path, gitlab_ci_history_path: gitlab_ci_history_path,
auto_fix_enabled: autofix_enabled, auto_fix_enabled: autofix_enabled,
can_toggle_auto_fix_settings: can_toggle_autofix, can_toggle_auto_fix_settings: can_toggle_autofix,
auto_fix_user_path: auto_fix_user_path, auto_fix_user_path: auto_fix_user_path
security_training_enabled: project.security_training_available?
} }
end end

View File

@ -37,7 +37,7 @@ instance of the [GraphiQL explorer](https://gitlab.com/-/graphql-explorer):
1. Open the [GraphiQL Explorer](https://gitlab.com/-/graphql-explorer) page. 1. Open the [GraphiQL Explorer](https://gitlab.com/-/graphql-explorer) page.
1. Paste the `query` listed above into the left window of your GraphiQL explorer tool. 1. Paste the `query` listed above into the left window of your GraphiQL explorer tool.
1. Click Play to get the result shown here: 1. Select Play to get the result shown here:
![GraphiQL explorer search for boards](img/sample_issue_boards_v13_2.png) ![GraphiQL explorer search for boards](img/sample_issue_boards_v13_2.png)

View File

@ -48,7 +48,7 @@ GET /runners?tag_list=tag1,tag2
|------------|--------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |------------|--------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided | | `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` | | `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
| `status` | string | no | The status of runners to show, one of: `online`, `offline` and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 | | `status` | string | no | The status of runners to show, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs | | `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
| `tag_list` | string array | no | List of the runner's tags | | `tag_list` | string array | no | List of the runner's tags |
@ -113,7 +113,7 @@ GET /runners/all?tag_list=tag1,tag2
|------------|--------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |------------|--------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of runners to show, one of: `specific`, `shared`, `active`, `paused`, `online` and `offline`; showing all runners if none provided | | `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of runners to show, one of: `specific`, `shared`, `active`, `paused`, `online` and `offline`; showing all runners if none provided |
| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` | | `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
| `status` | string | no | The status of runners to show, one of: `online` and `offline`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 | | `status` | string | no | The status of runners to show, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs | | `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
| `tag_list` | string array | no | List of the runner's tags | | `tag_list` | string array | no | List of the runner's tags |
@ -464,7 +464,7 @@ GET /projects/:id/runners?tag_list=tag1,tag2
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided | | `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` | | `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
| `status` | string | no | The status of runners to show, one of: `online` and `offline`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 | | `status` | string | no | The status of runners to show, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs | | `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
| `tag_list` | string array | no | List of the runner's tags | | `tag_list` | string array | no | List of the runner's tags |
@ -580,7 +580,7 @@ GET /groups/:id/runners?tag_list=tag1,tag2
|------------|----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |------------|----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id` | integer | yes | The ID of the group owned by the authenticated user | | `id` | integer | yes | The ID of the group owned by the authenticated user |
| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type`. The `project_type` value is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/351466) and will be removed in GitLab 15.0 | | `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type`. The `project_type` value is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/351466) and will be removed in GitLab 15.0 |
| `status` | string | no | The status of runners to show, one of: `online` and `offline`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 | | `status` | string | no | The status of runners to show, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs | | `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
| `tag_list` | string array | no | List of the runner's tags | | `tag_list` | string array | no | List of the runner's tags |

View File

@ -100,7 +100,7 @@ Supported attributes:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
|-----------------|----------------|------------------------|-------------| |-----------------|----------------|------------------------|-------------|
| `project_id` | integer/string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. | | `project_id` | integer/string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `name` | string | **{check-circle}** Yes | The `name` of the file being uploaded. The file name must be unique within the project. | | `name` | string | **{check-circle}** Yes | The `name` of the file being uploaded. The filename must be unique within the project. |
| `file` | file | **{check-circle}** Yes | The `file` being uploaded (5 MB limit). | | `file` | file | **{check-circle}** Yes | The `file` being uploaded (5 MB limit). |
Example request: Example request:

View File

@ -36,9 +36,9 @@ environments are not displayed.
To add a project to the dashboard: To add a project to the dashboard:
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. 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, you can see a summary of each project's environment operational Once added, you can see a summary of each project's environment operational
health, including the latest commit, pipeline status, and deployment time. health, including the latest commit, pipeline status, and deployment time.

View File

@ -63,7 +63,7 @@ rollout 10%:
ROLLOUT_PERCENTAGE: 10 ROLLOUT_PERCENTAGE: 10
``` ```
When the jobs are built, a **play** button appears next to the job's name. Click the **play** button When the jobs are built, a **play** button appears next to the job's name. Select **play**
to release each stage of pods. You can also rollback by running a lower percentage job. Once 100% to release each stage of pods. You can also rollback by running a lower percentage job. Once 100%
is reached, you cannot roll back using this method. It is still possible to roll back by redeploying is reached, you cannot roll back using this method. It is still possible to roll back by redeploying
the old version using the **Rollback** button on the environment page. the old version using the **Rollback** button on the environment page.

View File

@ -92,7 +92,7 @@ For more information, see [Deployment safety](../environments/deployment_safety.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211339) in GitLab 13.6. > [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 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. about this and asks for confirmation.
For more information, see [Deployment safety](../environments/deployment_safety.md). For more information, see [Deployment safety](../environments/deployment_safety.md).

View File

@ -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. 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. 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. Check the **Protected** option.
1. Click **Save changes**. 1. Select **Save changes**.
![specific runners edit icon](img/protected_runners_check_box_v14_1.png) ![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. Go to the project's **Settings > CI/CD**.
1. Expand the **General pipelines settings** section. 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. Delete the value and save the form.
1. After the page is refreshed, expand the **Runners settings** section 1. After the page is refreshed, expand the **Runners settings** section
and check the registration token - it should be changed. 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. 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. 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. 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: NOTE:
The runner tags list can not be empty when it's not allowed to pick untagged jobs. The runner tags list can not be empty when it's not allowed to pick untagged jobs.

View File

@ -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. 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. 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, 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: NOTE:
To re-enable the shared runners for a group, turn on the 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. Go to the group you want to remove or pause the runner for.
1. On the left sidebar, select **CI/CD > Runners**. 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. - 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. - 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. You must remove it from each project first.
1. On the confirmation dialog, click **OK**. 1. On the confirmation dialog, select **OK**.
## Specific runners ## Specific runners

View File

@ -34,8 +34,8 @@ Additional features and capabilities are planned.
To add a secure file to a project: To add a secure file to a project:
1. On the top bar, select **Menu > Projects** and find your 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 left sidebar, select **Settings > CI/CD**.
1. In the **Secure Files** section, select **Manage**. 1. In the **Secure Files** section, select **Manage**.
1. Select **Upload File**. 1. Select **Upload File**.
1. Find the file to upload, select **Open**, and the file upload begins immediately. 1. Find the file to upload, select **Open**, and the file upload begins immediately.

View File

@ -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). 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, - If you are familiar with Ruby on Rails or Vue.js,
consider [contributing to GitLab](../development/contributing/index.md) as a developer. 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 - 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. the [Cloud Seed Library](https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/library) project.

View File

@ -226,9 +226,9 @@ Download Ruby and compile it:
```shell ```shell
mkdir /tmp/ruby && cd /tmp/ruby 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" curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.6.tar.gz"
echo '2755b900a21235b443bb16dadd9032f784d4a88f143d852bc5d154f22b8781f1 ruby-2.7.5.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.5.tar.gz echo 'e7203b0cc09442ed2c08936d483f8ac140ec1c72e37bb5c401646b7866cb5d10 ruby-2.7.6.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.6.tar.gz
cd ruby-2.7.5 cd ruby-2.7.6
./configure --disable-install-rdoc --enable-shared ./configure --disable-install-rdoc --enable-shared
make make

View File

@ -97,6 +97,6 @@ application.
[restart GitLab](../administration/restart_gitlab.md#installations-from-source). [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 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 user to sign in and authorize the GitLab application. If the user authenticates
successfully, the user is returned to GitLab and signed in. successfully, the user is returned to GitLab and signed in.

View File

@ -261,7 +261,7 @@ To enable languages support:
1. On the left sidebar, select **Settings > Advanced Search**. 1. On the left sidebar, select **Settings > Advanced Search**.
1. Locate **Custom analyzers: language support**. 1. Locate **Custom analyzers: language support**.
1. Enable plugins support for **Indexing**. 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. 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. 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 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 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 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. in the background.
If you cannot get the migration to succeed, you may 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. 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** 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 ```shell
# Omnibus installations # Omnibus installations

View File

@ -91,7 +91,7 @@ To change your personal details, including name, billing address, and email addr
1. Select **My account > Account details**. 1. Select **My account > Account details**.
1. Expand the **Personal details** section. 1. Expand the **Personal details** section.
1. Edit your personal details. 1. Edit your personal details.
1. Click **Save changes**. 1. Select **Save changes**.
### Change your company details ### 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. Select **My account > Account details**.
1. Expand the **Company details** section. 1. Expand the **Company details** section.
1. Edit the company details. 1. Edit the company details.
1. Click **Save changes**. 1. Select **Save changes**.
### Change your payment method ### 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. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
1. Select **My account > Payment methods**. 1. Select **My account > Payment methods**.
1. **Edit** an existing payment method's information or **Add new payment method**. 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 #### 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. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
1. Select **My account > Payment methods**. 1. Select **My account > Payment methods**.
1. **Edit** the selected payment method and check the **Make default payment method** checkbox. 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 ### 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). [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 1. In a separate browser tab, go to [GitLab SaaS](https://gitlab.com) and ensure you
are not logged in. are not logged in.
1. On the Customers Portal page, click **My account > Account details**. 1. On the Customers Portal page, select **My account > Account details**.
1. Under **Your GitLab.com account**, click **Change linked account**. 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 1. Log in to the [GitLab SaaS](https://gitlab.com) account you want to link to the Customers Portal
account. account.
@ -164,9 +164,9 @@ Only one namespace can be linked to a subscription.
To change the password for this customers portal account: To change the password for this customers portal account:
1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in). 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. Make the required changes to the **Your password** section.
1. Click **Save changes**. 1. Select **Save changes**.
## Community program subscriptions ## Community program subscriptions

View File

@ -69,9 +69,9 @@ Download Ruby and compile it:
```shell ```shell
mkdir /tmp/ruby && cd /tmp/ruby 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" curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.6.tar.gz"
echo '2755b900a21235b443bb16dadd9032f784d4a88f143d852bc5d154f22b8781f1 ruby-2.7.5.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.5.tar.gz echo 'e7203b0cc09442ed2c08936d483f8ac140ec1c72e37bb5c401646b7866cb5d10 ruby-2.7.6.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.6.tar.gz
cd ruby-2.7.5 cd ruby-2.7.6
./configure --disable-install-rdoc --enable-shared ./configure --disable-install-rdoc --enable-shared
make make

View File

@ -235,7 +235,7 @@ v1.0, 2019-01-01
NOTE: NOTE:
[Wiki pages](project/wiki/index.md#create-a-new-wiki-page) created with the AsciiDoc [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 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 ```plaintext
include::basics.adoc[] include::basics.adoc[]

View File

@ -49,7 +49,7 @@ In order to:
After you have successful deployments to your group-level or instance-level cluster: After you have successful deployments to your group-level or instance-level cluster:
1. Navigate to your group's **Kubernetes** page. 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. Only successful deployments to the cluster are included in this page.
Non-cluster environments aren't included. Non-cluster environments aren't included.

View File

@ -98,7 +98,7 @@ To enable the Prometheus integration for your cluster:
**Kubernetes** page. **Kubernetes** page.
1. Select the **Integrations** tab. 1. Select the **Integrations** tab.
1. Check the **Enable Prometheus integration** checkbox. 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. 1. Go to the **Health** tab to see your cluster's metrics.
## Elastic Stack cluster integration **(FREE SELF)** ## Elastic Stack cluster integration **(FREE SELF)**
@ -165,5 +165,5 @@ To enable the Elastic Stack integration for your cluster:
**Kubernetes** page. **Kubernetes** page.
1. Select the **Integrations** tab. 1. Select the **Integrations** tab.
1. Check the **Enable Elastic Stack integration** checkbox. 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. 1. Go to the **Health** tab to see your cluster's metrics.

View File

@ -49,7 +49,7 @@ Select the desired period from the calendar dropdown.
## Sorting by different factors ## 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 - Member name
- Number of pushed events - Number of pushed events

View File

@ -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. Navigate to the **Settings > General** page in your group's sidebar.
1. Expand the **Permissions and group features** section. 1. Expand the **Permissions and group features** section.
1. Fill in the **Maximum allowable lifetime for access tokens (days)** field. 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: Once a lifetime for personal access tokens is set:

View File

@ -577,7 +577,7 @@ To generate a SAML Response:
- [SAML-tracer](https://addons.mozilla.org/en-US/firefox/addon/saml-tracer/) for Firefox. - [SAML-tracer](https://addons.mozilla.org/en-US/firefox/addon/saml-tracer/) for Firefox.
1. Open a new browser tab. 1. Open a new browser tab.
1. Open the SAML tracer console: 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. - 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. 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 1. Select **Authorize** or attempt to log in. A SAML response is displayed in the tracer console that resembles this

View File

@ -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). 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. 1. Ensure the `id` is the primary and required field, and `externalId` is also required.
NOTE: NOTE:

View File

@ -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. 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. 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. 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. 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, Once added, the dashboard displays the project's number of active alerts,
last commit, pipeline status, and when it was last deployed. last commit, pipeline status, and when it was last deployed.

View File

@ -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: 1. Copy the link to your container image:
- Go to your project or group's **Packages & Registries > Container Registry** - Go to your project or group's **Packages & Registries > Container Registry**
and find the image you want. 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) ![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 by clicking the red **{remove}** **Trash** icon next to the tag you want
to delete. to delete.
1. In the dialog box, click **Remove tag**. 1. In the dialog box, select **Remove tag**.
### Delete images using the API ### 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. Go to your project's **Settings > General** page.
1. Expand the **Visibility, project features, permissions** section 1. Expand the **Visibility, project features, permissions** section
and disable **Container Registry**. 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. The **Packages & Registries > Container Registry** entry is removed from the project's sidebar.

View File

@ -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 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). | | **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. Depending on the interval you chose, the policy is scheduled to run.
NOTE: 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 ### Regex pattern examples

View File

@ -701,7 +701,7 @@ dependencies {
For your project, go to **Packages & Registries > Package Registry**. 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 ## Create Maven packages with GitLab CI/CD

View File

@ -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) ![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. 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) ![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. The source is displayed in your list.

View File

@ -31,7 +31,7 @@ To delete a package in the UI, from your group or project:
1. Go to **Packages & Registries > Package Registry**. 1. Go to **Packages & Registries > Package Registry**.
1. Find the name of the package you want to delete. 1. Find the name of the package you want to delete.
1. Click **Delete**. 1. Select **Delete**.
The package is permanently deleted. The package is permanently deleted.

View File

@ -33,7 +33,7 @@ Advanced Search searches default project branches only.
| Use | Description | Example | | 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=) | | `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=) | | `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) | | `blob:` | Git object ID | [`blob:998707*`](https://gitlab.com/search?snippets=false&scope=blobs&repository_ref=&search=blob%3A998707*&group_id=9970) |

View File

@ -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: in your browser. To run a search from history:
1. In the top menu, select **Issues** or **Merge requests**. 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 ## Removing search filters

View File

@ -27,7 +27,7 @@ sent within five minutes, with a link for users to re-confirm the subject email
## Do the confirmation emails expire? ## 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 ## Generate a list of affected users

View File

@ -481,6 +481,11 @@ module Gitlab
"can contain only lowercase letters, digits, '_' and '-'. " \ "can contain only lowercase letters, digits, '_' and '-'. " \
"Must start with a letter, and cannot end with '-' or '_'" "Must start with a letter, and cannot end with '-' or '_'"
end end
# One or more `part`s, separated by separator
def sep_by_1(separator, part)
%r(#{part} (#{separator} #{part})*)x
end
end end
end end

View File

@ -35,7 +35,7 @@ module Sidebars
::Sidebars::MenuItem.new( ::Sidebars::MenuItem.new(
title: _('Contacts'), title: _('Contacts'),
link: group_crm_contacts_path(context.group), link: group_crm_contacts_path(context.group),
active_routes: { path: 'groups/crm#contacts' }, active_routes: { controller: 'groups/crm/contacts' },
item_id: :crm_contacts item_id: :crm_contacts
) )
end end
@ -44,7 +44,7 @@ module Sidebars
::Sidebars::MenuItem.new( ::Sidebars::MenuItem.new(
title: _('Organizations'), title: _('Organizations'),
link: group_crm_organizations_path(context.group), link: group_crm_organizations_path(context.group),
active_routes: { path: 'groups/crm#organizations' }, active_routes: { controller: 'groups/crm/organizations' },
item_id: :crm_organizations item_id: :crm_organizations
) )
end end

View File

@ -2,6 +2,7 @@ import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import { GlTab, GlTabs, GlLink } from '@gitlab/ui'; import { GlTab, GlTabs, GlLink } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser'; import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
import stubChildren from 'helpers/stub_children'; import stubChildren from 'helpers/stub_children';
@ -19,14 +20,22 @@ import {
LICENSE_COMPLIANCE_DESCRIPTION, LICENSE_COMPLIANCE_DESCRIPTION,
LICENSE_COMPLIANCE_HELP_PATH, LICENSE_COMPLIANCE_HELP_PATH,
AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY, AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY,
LICENSE_ULTIMATE,
LICENSE_PREMIUM,
LICENSE_FREE,
} from '~/security_configuration/components/constants'; } from '~/security_configuration/components/constants';
import FeatureCard from '~/security_configuration/components/feature_card.vue'; import FeatureCard from '~/security_configuration/components/feature_card.vue';
import TrainingProviderList from '~/security_configuration/components/training_provider_list.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 UpgradeBanner from '~/security_configuration/components/upgrade_banner.vue';
import { import {
REPORT_TYPE_LICENSE_COMPLIANCE, REPORT_TYPE_LICENSE_COMPLIANCE,
REPORT_TYPE_SAST, REPORT_TYPE_SAST,
} from '~/vue_shared/security_reports/constants'; } from '~/vue_shared/security_reports/constants';
import { getCurrentLicensePlanResponse } from '../mock_data';
const upgradePath = '/upgrade'; const upgradePath = '/upgrade';
const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath'; const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath';
@ -41,40 +50,31 @@ Vue.use(VueApollo);
describe('App component', () => { describe('App component', () => {
let wrapper; let wrapper;
let userCalloutDismissSpy; let userCalloutDismissSpy;
let mockApollo;
const securityFeaturesMock = [ const createComponent = ({
{ shouldShowCallout = true,
name: SAST_NAME, licenseQueryResponse = LICENSE_ULTIMATE,
shortName: SAST_SHORT_NAME, ...propsData
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 } = {}) => {
userCalloutDismissSpy = jest.fn(); userCalloutDismissSpy = jest.fn();
mockApollo = createMockApollo([
[
currentLicenseQuery,
jest
.fn()
.mockResolvedValue(
licenseQueryResponse instanceof Error
? licenseQueryResponse
: getCurrentLicensePlanResponse(licenseQueryResponse),
),
],
]);
wrapper = extendedWrapper( wrapper = extendedWrapper(
mount(SecurityConfigurationApp, { mount(SecurityConfigurationApp, {
propsData: { propsData,
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
securityTrainingEnabled: true,
...propsData,
},
provide: { provide: {
upgradePath, upgradePath,
autoDevopsHelpPagePath, autoDevopsHelpPagePath,
@ -82,6 +82,7 @@ describe('App component', () => {
projectFullPath, projectFullPath,
vulnerabilityTrainingDocsPath, vulnerabilityTrainingDocsPath,
}, },
apolloProvider: mockApollo,
stubs: { stubs: {
...stubChildren(SecurityConfigurationApp), ...stubChildren(SecurityConfigurationApp),
GlLink: false, GlLink: false,
@ -132,13 +133,40 @@ describe('App component', () => {
const findAutoDevopsEnabledAlert = () => wrapper.findComponent(AutoDevopsEnabledAlert); const findAutoDevopsEnabledAlert = () => wrapper.findComponent(AutoDevopsEnabledAlert);
const findVulnerabilityManagementTab = () => wrapper.findByTestId('vulnerability-management-tab'); 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(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
mockApollo = null;
}); });
describe('basic structure', () => { describe('basic structure', () => {
beforeEach(() => { beforeEach(async () => {
createComponent(); createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
});
await waitForPromises();
}); });
it('renders main-heading with correct text', () => { it('renders main-heading with correct text', () => {
@ -198,7 +226,10 @@ describe('App component', () => {
describe('Manage via MR Error Alert', () => { describe('Manage via MR Error Alert', () => {
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
});
}); });
describe('on initial load', () => { describe('on initial load', () => {
@ -234,6 +265,8 @@ describe('App component', () => {
describe('given the right props', () => { describe('given the right props', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
autoDevopsEnabled: false, autoDevopsEnabled: false,
gitlabCiPresent: false, gitlabCiPresent: false,
canEnableAutoDevops: true, canEnableAutoDevops: true,
@ -255,7 +288,10 @@ describe('App component', () => {
describe('given the wrong props', () => { describe('given the wrong props', () => {
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
});
}); });
it('should not show AutoDevopsAlert', () => { it('should not show AutoDevopsAlert', () => {
expect(findAutoDevopsAlert().exists()).toBe(false); 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', () => { 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'); findAutoDevopsEnabledAlert().vm.$emit('dismiss');
}); });
@ -330,6 +375,7 @@ describe('App component', () => {
describe('given at least one unavailable feature', () => { describe('given at least one unavailable feature', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)), augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)),
}); });
}); });
@ -350,6 +396,7 @@ describe('App component', () => {
describe('given at least one unavailable feature, but banner is already dismissed', () => { describe('given at least one unavailable feature, but banner is already dismissed', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)), augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)),
shouldShowCallout: false, shouldShowCallout: false,
}); });
@ -376,7 +423,11 @@ describe('App component', () => {
describe('when given latestPipelinePath props', () => { describe('when given latestPipelinePath props', () => {
beforeEach(() => { 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', () => { 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', () => { describe('given gitlabCiPresent & gitlabCiHistoryPath props', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
gitlabCiPresent: true, gitlabCiPresent: true,
gitlabCiHistoryPath, gitlabCiHistoryPath,
}); });
@ -415,36 +468,48 @@ describe('App component', () => {
}); });
}); });
describe('Vulnerability management tab', () => { describe('Vulnerability management', () => {
it('does not show tab if security training is disabled', () => { beforeEach(async () => {
createComponent({ securityTrainingEnabled: false }); createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
expect(findVulnerabilityManagementTab().exists()).toBe(false); augmentedComplianceFeatures: complianceFeaturesMock,
});
await waitForPromises();
}); });
describe('security training enabled', () => { it('renders TrainingProviderList component', () => {
beforeEach(() => { expect(findTrainingProviderList().exists()).toBe(true);
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 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);
},
);
}); });
}); });

View File

@ -111,3 +111,12 @@ export const tempProviderLogos = {
svg: `<svg>${[testProviderName[1]]}</svg>`, svg: `<svg>${[testProviderName[1]]}</svg>`,
}, },
}; };
export const getCurrentLicensePlanResponse = (plan) => ({
data: {
currentLicense: {
id: 'gid://gitlab/License/1',
plan,
},
},
});

View File

@ -21,8 +21,8 @@ describe('MR widget extension registering', () => {
expect.objectContaining({ expect.objectContaining({
extends: ExtensionBase, extends: ExtensionBase,
name: 'Test', name: 'Test',
props: ['helloWorld'],
computed: { computed: {
helloWorld: expect.any(Function),
test: expect.any(Function), test: expect.any(Function),
}, },
methods: { methods: {

View File

@ -8323,14 +8323,6 @@ RSpec.describe Project, factory_default: :keep do
end end
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 private
def finish_job(export_job) def finish_job(export_job)

View File

@ -122,7 +122,7 @@ RSpec.describe QuickActions::InterpretService do
inprogress # populate the label inprogress # populate the label
_, updates, _ = service.execute(content, issuable) _, 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 end
it 'returns the label message' do it 'returns the label message' do
@ -130,7 +130,10 @@ RSpec.describe QuickActions::InterpretService do
inprogress # populate the label inprogress # populate the label
_, _, message = service.execute(content, issuable) _, _, 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
end end
@ -1196,6 +1199,64 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { merge_request } let(:issuable) { merge_request }
end 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 it_behaves_like 'multiple label command' do
let(:content) { %(/label ~"#{inprogress.title}" \n/label ~#{bug.title}) } let(:content) { %(/label ~"#{inprogress.title}" \n/label ~#{bug.title}) }
let(:issuable) { issue } let(:issuable) { issue }