Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b58ab6c33c
commit
fd11748fe8
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
import { GlLoadingIcon, GlButton } from '@gitlab/ui';
|
||||
import { GlLoadingIcon, GlButton, GlModalDirective } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { PROJECT_BADGE } from '../constants';
|
||||
import Badge from './badge.vue';
|
||||
|
@ -12,6 +12,9 @@ export default {
|
|||
GlLoadingIcon,
|
||||
GlButton,
|
||||
},
|
||||
directives: {
|
||||
GlModal: GlModalDirective,
|
||||
},
|
||||
props: {
|
||||
badge: {
|
||||
type: Object,
|
||||
|
@ -61,13 +64,13 @@ export default {
|
|||
@click="editBadge(badge)"
|
||||
/>
|
||||
<gl-button
|
||||
v-gl-modal.delete-badge-modal
|
||||
:disabled="badge.isDeleting"
|
||||
variant="danger"
|
||||
data-toggle="modal"
|
||||
data-target="#delete-badge-modal"
|
||||
icon="remove"
|
||||
size="medium"
|
||||
:aria-label="__('Delete')"
|
||||
data-testid="delete-badge"
|
||||
@click="updateBadgeInModal(badge)"
|
||||
/>
|
||||
<gl-loading-icon v-show="badge.isDeleting" :inline="true" />
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<script>
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { GlSprintf } from '@gitlab/ui';
|
||||
import { GlSprintf, GlModal } from '@gitlab/ui';
|
||||
import { deprecatedCreateFlash as createFlash } from '~/flash';
|
||||
import { s__ } from '~/locale';
|
||||
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
|
||||
import Badge from './badge.vue';
|
||||
import BadgeForm from './badge_form.vue';
|
||||
import BadgeList from './badge_list.vue';
|
||||
|
@ -14,7 +13,7 @@ export default {
|
|||
Badge,
|
||||
BadgeForm,
|
||||
BadgeList,
|
||||
GlModal: DeprecatedModal2,
|
||||
GlModal,
|
||||
GlSprintf,
|
||||
},
|
||||
i18n: {
|
||||
|
@ -24,6 +23,17 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapState(['badgeInModal', 'isEditing']),
|
||||
primaryProps() {
|
||||
return {
|
||||
text: s__('Delete badge'),
|
||||
attributes: [{ category: 'primary' }, { variant: 'danger' }],
|
||||
};
|
||||
},
|
||||
cancelProps() {
|
||||
return {
|
||||
text: s__('Cancel'),
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['deleteBadge']),
|
||||
|
@ -44,11 +54,11 @@ export default {
|
|||
<template>
|
||||
<div class="badge-settings">
|
||||
<gl-modal
|
||||
id="delete-badge-modal"
|
||||
:header-title-text="s__('Badges|Delete badge?')"
|
||||
:footer-primary-button-text="s__('Badges|Delete badge')"
|
||||
footer-primary-button-variant="danger"
|
||||
@submit="onSubmitModal"
|
||||
modal-id="delete-badge-modal"
|
||||
:title="s__('Badges|Delete badge?')"
|
||||
:action-primary="primaryProps"
|
||||
:action-cancel="cancelProps"
|
||||
@primary="onSubmitModal"
|
||||
>
|
||||
<div class="well">
|
||||
<badge
|
||||
|
@ -65,9 +75,9 @@ export default {
|
|||
</p>
|
||||
</gl-modal>
|
||||
|
||||
<badge-form v-show="isEditing" :is-editing="true" />
|
||||
<badge-form v-show="isEditing" :is-editing="true" data-testid="edit-badge" />
|
||||
|
||||
<badge-form v-show="!isEditing" :is-editing="false" />
|
||||
<badge-form v-show="!isEditing" :is-editing="false" data-testid="add-new-badge" />
|
||||
<badge-list v-show="!isEditing" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { GlButton, GlFormCheckbox, GlIcon, GlLink, GlAlert } from '@gitlab/ui';
|
||||
import EditorLite from '~/vue_shared/components/editor_lite.vue';
|
||||
import CiLintResults from './ci_lint_results.vue';
|
||||
import lintCIMutation from '../graphql/mutations/lint_ci.mutation.graphql';
|
||||
|
||||
|
@ -11,6 +12,7 @@ export default {
|
|||
GlLink,
|
||||
GlAlert,
|
||||
CiLintResults,
|
||||
EditorLite,
|
||||
},
|
||||
props: {
|
||||
endpoint: {
|
||||
|
@ -62,6 +64,9 @@ export default {
|
|||
this.isErrorDismissed = false;
|
||||
}
|
||||
},
|
||||
clear() {
|
||||
this.content = '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -76,22 +81,31 @@ export default {
|
|||
@dismiss="isErrorDismissed = true"
|
||||
>{{ apiError }}</gl-alert
|
||||
>
|
||||
|
||||
<textarea v-model="content" cols="175" rows="20"></textarea>
|
||||
<div class="file-holder gl-mb-3">
|
||||
<div class="js-file-title file-title clearfix">
|
||||
{{ __('Contents of .gitlab-ci.yml') }}
|
||||
</div>
|
||||
<editor-lite v-model="content" file-name="*.yml" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 gl-display-flex gl-justify-content-space-between">
|
||||
<div class="gl-display-flex gl-align-items-center">
|
||||
<gl-button class="gl-mr-4" category="primary" variant="success" @click="lint">{{
|
||||
__('Validate')
|
||||
}}</gl-button>
|
||||
<gl-button
|
||||
class="gl-mr-4"
|
||||
category="primary"
|
||||
variant="success"
|
||||
data-testid="ci-lint-validate"
|
||||
@click="lint"
|
||||
>{{ __('Validate') }}</gl-button
|
||||
>
|
||||
<gl-form-checkbox v-model="dryRun"
|
||||
>{{ __('Simulate a pipeline created for the default branch') }}
|
||||
<gl-link :href="helpPagePath" target="_blank"
|
||||
><gl-icon class="gl-text-blue-600" name="question-o"/></gl-link
|
||||
></gl-form-checkbox>
|
||||
</div>
|
||||
<gl-button>{{ __('Clear') }}</gl-button>
|
||||
<gl-button data-testid="ci-lint-clear" @click="clear">{{ __('Clear') }}</gl-button>
|
||||
</div>
|
||||
|
||||
<ci-lint-results
|
||||
|
|
|
@ -2,6 +2,7 @@ import $ from 'jquery';
|
|||
import { __ } from '~/locale';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { deprecatedCreateFlash as flash } from './flash';
|
||||
import { fixTitle, hide } from '~/tooltips';
|
||||
|
||||
const tooltipTitles = {
|
||||
group: __('Unsubscribe at group level'),
|
||||
|
@ -59,9 +60,9 @@ export default class GroupLabelSubscription {
|
|||
const type = $button.hasClass('js-group-level') ? 'group' : 'project';
|
||||
const newTitle = tooltipTitles[type];
|
||||
|
||||
$('.js-unsubscribe-button', $button.closest('.label-actions-list'))
|
||||
.tooltip('hide')
|
||||
.attr('title', newTitle)
|
||||
.tooltip('_fixTitle');
|
||||
const $el = $('.js-unsubscribe-button', $button.closest('.label-actions-list'));
|
||||
hide($el);
|
||||
$el.attr('title', `${newTitle}`);
|
||||
fixTitle($el);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
<script>
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
import tooltip from '~/vue_shared/directives/tooltip';
|
||||
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlIcon,
|
||||
},
|
||||
directives: {
|
||||
tooltip,
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
|
@ -51,7 +50,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<span
|
||||
v-tooltip
|
||||
v-gl-tooltip
|
||||
:data-placement="tooltipPlacement"
|
||||
:class="cssClass"
|
||||
:title="title"
|
||||
|
|
|
@ -11,6 +11,8 @@ class Environment < ApplicationRecord
|
|||
self.reactive_cache_hard_limit = 10.megabytes
|
||||
self.reactive_cache_work_type = :external_dependency
|
||||
|
||||
PRODUCTION_ENVIRONMENT_IDENTIFIERS = %w[prod production].freeze
|
||||
|
||||
belongs_to :project, required: true
|
||||
|
||||
use_fast_destroy :all_deployments
|
||||
|
@ -213,7 +215,7 @@ class Environment < ApplicationRecord
|
|||
end
|
||||
|
||||
def update_merge_request_metrics?
|
||||
folder_name == "production"
|
||||
PRODUCTION_ENVIRONMENT_IDENTIFIERS.include?(folder_name.downcase)
|
||||
end
|
||||
|
||||
def ref_path
|
||||
|
|
|
@ -1695,7 +1695,7 @@ class MergeRequest < ApplicationRecord
|
|||
end
|
||||
|
||||
def allows_reviewers?
|
||||
Feature.enabled?(:merge_request_reviewers, project)
|
||||
Feature.enabled?(:merge_request_reviewers, project, default_enabled: true)
|
||||
end
|
||||
|
||||
def allows_multiple_reviewers?
|
||||
|
|
|
@ -14,8 +14,8 @@ module Ci
|
|||
Gitlab::Ci::Pipeline::Chain::Config::Process,
|
||||
Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs,
|
||||
Gitlab::Ci::Pipeline::Chain::Skip,
|
||||
Gitlab::Ci::Pipeline::Chain::Seed,
|
||||
Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules,
|
||||
Gitlab::Ci::Pipeline::Chain::Seed,
|
||||
Gitlab::Ci::Pipeline::Chain::Limit::Size,
|
||||
Gitlab::Ci::Pipeline::Chain::Validate::External,
|
||||
Gitlab::Ci::Pipeline::Chain::Populate,
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
- if merge_request.assignees.any?
|
||||
%li.gl-display-flex.gl-align-items-center
|
||||
= render 'shared/issuable/assignees', project: merge_request.project, issuable: merge_request
|
||||
- if Feature.enabled?(:merge_request_reviewers, @project) && merge_request.reviewers.any?
|
||||
- if Feature.enabled?(:merge_request_reviewers, @project, default_enabled: true) && merge_request.reviewers.any?
|
||||
%li.gl-display-flex.issuable-reviewers
|
||||
= render 'shared/issuable/reviewers', project: merge_request.project, issuable: merge_request
|
||||
= render 'projects/merge_requests/approvals_count', merge_request: merge_request
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
.block.assignee.qa-assignee-block
|
||||
= render "shared/issuable/sidebar_assignees", issuable_sidebar: issuable_sidebar, assignees: assignees, signed_in: signed_in
|
||||
|
||||
- if Feature.enabled?(:merge_request_reviewers, @project) && reviewers
|
||||
- if Feature.enabled?(:merge_request_reviewers, @project, default_enabled: true) && reviewers
|
||||
.block.reviewer.qa-reviewer-block
|
||||
= render "shared/issuable/sidebar_reviewers", issuable_sidebar: issuable_sidebar, reviewers: reviewers, signed_in: signed_in
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Fix workflow:rules not accessing passed-upstream and trigger variables
|
||||
merge_request: 44935
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update delete badge modal to gl-modal
|
||||
merge_request: 44495
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow more naming conventions for VSA production environment
|
||||
merge_request: 45069
|
||||
author:
|
||||
type: changed
|
|
@ -4,4 +4,4 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40488
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/245190
|
||||
group: group::source code
|
||||
type: development
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -14557,9 +14557,9 @@ CREATE TABLE plan_limits (
|
|||
nuget_max_file_size bigint DEFAULT 524288000 NOT NULL,
|
||||
pypi_max_file_size bigint DEFAULT '3221225472'::bigint NOT NULL,
|
||||
generic_packages_max_file_size bigint DEFAULT '5368709120'::bigint NOT NULL,
|
||||
project_feature_flags integer DEFAULT 200 NOT NULL,
|
||||
golang_max_file_size bigint DEFAULT 104857600 NOT NULL,
|
||||
debian_max_file_size bigint DEFAULT '3221225472'::bigint NOT NULL,
|
||||
project_feature_flags integer DEFAULT 200 NOT NULL,
|
||||
ci_max_artifact_size_api_fuzzing integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
|
|
|
@ -120,6 +120,10 @@ Note the following when promoting a secondary:
|
|||
1. Edit `/etc/gitlab/gitlab.rb` to reflect its new status as **primary** by
|
||||
removing any lines that enabled the `geo_secondary_role`:
|
||||
|
||||
Users of GitLab 13.5 or later can skip this step, due to the appropriate
|
||||
roles being enabled or disabled during the promotion in the following
|
||||
step.
|
||||
|
||||
```ruby
|
||||
## In pre-11.5 documentation, the role was enabled as follows. Remove this line.
|
||||
geo_secondary_role['enable'] = true
|
||||
|
|
|
@ -553,7 +553,7 @@ POST /runners
|
|||
|--------------|---------|----------|---------------------|
|
||||
| `token` | string | yes | [Registration token](#registration-and-authentication-tokens). |
|
||||
| `description`| string | no | Runner's description|
|
||||
| `info` | hash | no | Runner's metadata |
|
||||
| `info` | hash | no | Runner's metadata. You can include `name`, `version`, `revision`, `platform`, and `architecture`, but only `version` is displayed in the Admin area of the UI. |
|
||||
| `active` | boolean | no | Whether the runner is active |
|
||||
| `locked` | boolean | no | Whether the runner should be locked for current project |
|
||||
| `run_untagged` | boolean | no | Whether the runner should handle untagged jobs |
|
||||
|
|
|
@ -96,8 +96,7 @@ Value Stream Analytics records stage time and data based on the project issues w
|
|||
exception of the staging stage, where only data deployed to
|
||||
production are measured.
|
||||
|
||||
Specifically, if your CI is not set up and you have not defined a `production`
|
||||
or `production/*` [environment](../../ci/yaml/README.md#environment), then you will not have any
|
||||
Specifically, if your CI is not set up and you have not defined a [production environment](#how-the-production-environment-is-identified), then you will not have any
|
||||
data for this stage.
|
||||
|
||||
Each stage of Value Stream Analytics is further described in the table below.
|
||||
|
@ -109,7 +108,7 @@ Each stage of Value Stream Analytics is further described in the table below.
|
|||
| Code | Measures the median time between pushing a first commit (previous stage) and creating a merge request (MR) related to that commit. The key to keep the process tracked is to include the [issue closing pattern](../project/issues/managing_issues.md#closing-issues-automatically) to the description of the merge request (for example, `Closes #xxx`, where `xxx` is the number of the issue related to this merge request). If the issue closing pattern is not present in the merge request description, the MR is not considered to the measurement time of the stage. |
|
||||
| Test | Measures the median time to run the entire pipeline for that project. It's related to the time GitLab CI/CD takes to run every job for the commits pushed to that merge request defined in the previous stage. It is basically the start->finish time for all pipelines. |
|
||||
| Review | Measures the median time taken to review the merge request that has a closing issue pattern, between its creation and until it's merged. |
|
||||
| Staging | Measures the median time between merging the merge request with a closing issue pattern until the very first deployment to production. It's tracked by the environment set to `production` or matching `production/*` (case-sensitive, `Production` won't work) in your GitLab CI/CD configuration. If there isn't a production environment, this is not tracked. |
|
||||
| Staging | Measures the median time between merging the merge request with a closing issue pattern until the very first deployment to a [production environment](#how-the-production-environment-is-identified). If there isn't a production environment, this is not tracked. |
|
||||
|
||||
How this works, behind the scenes:
|
||||
|
||||
|
@ -128,8 +127,18 @@ Value Stream Analytics dashboard will not present any data for:
|
|||
|
||||
- Merge requests that do not close an issue.
|
||||
- Issues not labeled with a label present in the Issue Board or for issues not assigned a milestone.
|
||||
- Staging stage, if the project has no `production` or `production/*`
|
||||
environment.
|
||||
- Staging stage, if the project has no [production environment](#how-the-production-environment-is-identified).
|
||||
|
||||
## How the production environment is identified
|
||||
|
||||
Value Stream Analytics identifies production environments by looking for project [environments](../../ci/yaml/README.md#environment) with a name matching any of these patterns:
|
||||
|
||||
- `prod` or `prod/*`
|
||||
- `production` or `production/*`
|
||||
|
||||
These patterns are not case-sensitive.
|
||||
|
||||
You can change the name of a project environment in your GitLab CI/CD configuration.
|
||||
|
||||
## Example workflow
|
||||
|
||||
|
|
|
@ -111,6 +111,48 @@ It is also possible to manage multiple assignees:
|
|||
- When creating a merge request.
|
||||
- Using [quick actions](../quick_actions.md#quick-actions-for-issues-merge-requests-and-epics).
|
||||
|
||||
## Reviewer
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216054) in GitLab 13.5.
|
||||
> - It's [deployed behind a feature flag](../../../user/feature_flags.md), enabled by default.
|
||||
> - It's disabled on GitLab.com.
|
||||
> - It's not recommended for production use.
|
||||
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-merge-request-reviewers). **(CORE ONLY)**
|
||||
|
||||
CAUTION: **Warning:**
|
||||
This feature might not be available to you. Check the **version history** note above for details.
|
||||
|
||||
Requesting a code review is an important part of contributing code. However, deciding who should review
|
||||
your code and asking for a review are no easy tasks. Using the "assignee" field for both authors and
|
||||
reviewers makes it hard for others to determine who's doing what on a merge request.
|
||||
|
||||
GitLab's Merge Request Reviewers easily allow authors to request a review as well as see the status of the
|
||||
review. By selecting one or more users from the **Reviewers** field in the merge request's right-hand
|
||||
sidebar, the assigned reviewers will receive a notification of the request to review the merge request.
|
||||
|
||||
This makes it easy to determine the relevant roles for the users involved in the merge request, as well as formally requesting a review from a peer.
|
||||
|
||||
To request it, open the **Reviewers** drop-down box to search for the user you wish to get a review from.
|
||||
|
||||
### Enable or disable Merge Request Reviewers **(CORE ONLY)**
|
||||
|
||||
Merge Request Reviewers is under development and not ready for production use. It is
|
||||
deployed behind a feature flag that is **disabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
|
||||
can enable it.
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:merge_request_reviewers)
|
||||
```
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:merge_request_reviewers)
|
||||
```
|
||||
|
||||
### Merge requests to close issues
|
||||
|
||||
If the merge request is being created to resolve an issue, you can
|
||||
|
|
|
@ -9,7 +9,7 @@ variables:
|
|||
# (SAST, Dependency Scanning, ...)
|
||||
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
|
||||
|
||||
SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, sobelow, pmd-apex, kubesec"
|
||||
SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, sobelow, pmd-apex, kubesec, mobsf"
|
||||
SAST_EXCLUDED_PATHS: "spec, test, tests, tmp"
|
||||
SAST_ANALYZER_IMAGE_TAG: 2
|
||||
SCAN_KUBERNETES_MANIFESTS: "false"
|
||||
|
@ -125,6 +125,42 @@ gosec-sast:
|
|||
exists:
|
||||
- '**/*.go'
|
||||
|
||||
mobsf-android-sast:
|
||||
extends: .sast-analyzer
|
||||
services:
|
||||
- name: opensecurity/mobile-security-framework-mobsf:latest
|
||||
alias: mobsf
|
||||
image:
|
||||
name: "$SAST_ANALYZER_IMAGE"
|
||||
variables:
|
||||
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/mobsf:$SAST_ANALYZER_IMAGE_TAG"
|
||||
rules:
|
||||
- if: $SAST_DISABLED
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH &&
|
||||
$SAST_DEFAULT_ANALYZERS =~ /mobsf/ &&
|
||||
$SAST_EXPERIMENTAL_FEATURES == 'true'
|
||||
exists:
|
||||
- '**/AndroidManifest.xml'
|
||||
|
||||
mobsf-ios-sast:
|
||||
extends: .sast-analyzer
|
||||
services:
|
||||
- name: opensecurity/mobile-security-framework-mobsf:latest
|
||||
alias: mobsf
|
||||
image:
|
||||
name: "$SAST_ANALYZER_IMAGE"
|
||||
variables:
|
||||
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/mobsf:$SAST_ANALYZER_IMAGE_TAG"
|
||||
rules:
|
||||
- if: $SAST_DISABLED
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH &&
|
||||
$SAST_DEFAULT_ANALYZERS =~ /mobsf/ &&
|
||||
$SAST_EXPERIMENTAL_FEATURES == 'true'
|
||||
exists:
|
||||
- '**/*.xcodeproj/*'
|
||||
|
||||
nodejs-scan-sast:
|
||||
extends: .sast-analyzer
|
||||
image:
|
||||
|
@ -203,6 +239,11 @@ spotbugs-sast:
|
|||
variables:
|
||||
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/spotbugs:$SAST_ANALYZER_IMAGE_TAG"
|
||||
rules:
|
||||
- if: $SAST_DEFAULT_ANALYZERS =~ /mobsf/ &&
|
||||
$SAST_EXPERIMENTAL_FEATURES == 'true'
|
||||
exists:
|
||||
- '**/AndroidManifest.xml'
|
||||
when: never
|
||||
- if: $SAST_DISABLED
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH &&
|
||||
|
|
|
@ -4028,9 +4028,6 @@ msgstr ""
|
|||
msgid "Badges|Badge image preview"
|
||||
msgstr ""
|
||||
|
||||
msgid "Badges|Delete badge"
|
||||
msgstr ""
|
||||
|
||||
msgid "Badges|Delete badge?"
|
||||
msgstr ""
|
||||
|
||||
|
@ -8561,6 +8558,9 @@ msgstr ""
|
|||
msgid "Delete artifacts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete badge"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete board"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1,117 +1,71 @@
|
|||
import Vue from 'vue';
|
||||
import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
|
||||
import Vuex from 'vuex';
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import { GlModal } from '@gitlab/ui';
|
||||
import store from '~/badges/store';
|
||||
import BadgeSettings from '~/badges/components/badge_settings.vue';
|
||||
import BadgeList from '~/badges/components/badge_list.vue';
|
||||
import BadgeListRow from '~/badges/components/badge_list_row.vue';
|
||||
import { createDummyBadge } from '../dummy_badge';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('BadgeSettings component', () => {
|
||||
const Component = Vue.extend(BadgeSettings);
|
||||
let vm;
|
||||
let wrapper;
|
||||
const badge = createDummyBadge();
|
||||
|
||||
const createComponent = (isEditing = false) => {
|
||||
store.state.badges = [badge];
|
||||
store.state.kind = 'project';
|
||||
store.state.isEditing = isEditing;
|
||||
|
||||
wrapper = shallowMount(BadgeSettings, {
|
||||
store,
|
||||
localVue,
|
||||
stubs: {
|
||||
'badge-list': BadgeList,
|
||||
'badge-list-row': BadgeListRow,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
setFixtures(`
|
||||
<div id="dummy-element"></div>
|
||||
<button
|
||||
id="dummy-modal-button"
|
||||
type="button"
|
||||
data-toggle="modal"
|
||||
data-target="#delete-badge-modal"
|
||||
>Show modal</button>
|
||||
`);
|
||||
|
||||
// Can be removed once GlLoadingIcon no longer throws a warning
|
||||
jest.spyOn(global.console, 'warn').mockImplementation(() => jest.fn());
|
||||
|
||||
vm = mountComponentWithStore(Component, {
|
||||
el: '#dummy-element',
|
||||
store,
|
||||
});
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('displays modal if button is clicked', done => {
|
||||
const badge = createDummyBadge();
|
||||
store.state.badgeInModal = badge;
|
||||
const modal = vm.$el.querySelector('#delete-badge-modal');
|
||||
const button = document.getElementById('dummy-modal-button');
|
||||
it('displays modal if button for deleting a badge is clicked', async () => {
|
||||
const button = wrapper.find('[data-testid="delete-badge"]');
|
||||
|
||||
button.click();
|
||||
button.vm.$emit('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
Vue.nextTick()
|
||||
.then(() => {
|
||||
expect(modal.innerText).toMatch('Delete badge?');
|
||||
const badgeElement = modal.querySelector('img.project-badge');
|
||||
expect(badgeElement).not.toBe(null);
|
||||
expect(badgeElement.getAttribute('src')).toBe(badge.renderedImageUrl);
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
const modal = wrapper.find(GlModal);
|
||||
expect(modal.isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it('displays a form to add a badge', () => {
|
||||
const form = vm.$el.querySelector('form:nth-of-type(2)');
|
||||
|
||||
expect(form).not.toBe(null);
|
||||
const button = form.querySelector('.btn-success');
|
||||
|
||||
expect(button).not.toBe(null);
|
||||
expect(button).toHaveText(/Add badge/);
|
||||
expect(wrapper.find('[data-testid="add-new-badge"]').isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it('displays badge list', () => {
|
||||
const badgeListElement = vm.$el.querySelector('.card');
|
||||
|
||||
expect(badgeListElement).not.toBe(null);
|
||||
expect(badgeListElement).toBeVisible();
|
||||
expect(badgeListElement.innerText).toMatch('Your badges');
|
||||
expect(wrapper.find(BadgeList).isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
describe('when editing', () => {
|
||||
beforeEach(done => {
|
||||
store.state.isEditing = true;
|
||||
|
||||
Vue.nextTick()
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
beforeEach(() => {
|
||||
createComponent(true);
|
||||
});
|
||||
|
||||
it('displays a form to edit a badge', () => {
|
||||
const form = vm.$el.querySelector('form:nth-of-type(1)');
|
||||
|
||||
expect(form).not.toBe(null);
|
||||
const cancelButton = form.querySelector('[data-testid="cancelEditing"]');
|
||||
|
||||
expect(cancelButton).not.toBe(null);
|
||||
expect(cancelButton).toHaveText(/Cancel/);
|
||||
const submitButton = form.querySelector('[data-testid="saveEditing"]');
|
||||
|
||||
expect(submitButton).not.toBe(null);
|
||||
expect(submitButton).toHaveText(/Save changes/);
|
||||
expect(wrapper.find('[data-testid="edit-badge"]').isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it('displays no badge list', () => {
|
||||
const badgeListElement = vm.$el.querySelector('.card');
|
||||
|
||||
expect(badgeListElement).toBeHidden();
|
||||
});
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
describe('onSubmitModal', () => {
|
||||
it('triggers ', () => {
|
||||
jest.spyOn(vm, 'deleteBadge').mockImplementation(() => Promise.resolve());
|
||||
const modal = vm.$el.querySelector('#delete-badge-modal');
|
||||
const deleteButton = modal.querySelector('.btn-danger');
|
||||
|
||||
deleteButton.click();
|
||||
|
||||
const badge = store.state.badgeInModal;
|
||||
|
||||
expect(vm.deleteBadge).toHaveBeenCalledWith(badge);
|
||||
});
|
||||
expect(wrapper.find(BadgeList).isVisible()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import EditorLite from '~/vue_shared/components/editor_lite.vue';
|
||||
import CiLint from '~/ci_lint/components/ci_lint.vue';
|
||||
import lintCIMutation from '~/ci_lint/graphql/mutations/lint_ci.mutation.graphql';
|
||||
|
||||
describe('CI Lint', () => {
|
||||
let wrapper;
|
||||
|
||||
const endpoint = '/namespace/project/-/ci/lint';
|
||||
const content =
|
||||
"test_job:\n stage: build\n script: echo 'Building'\n only:\n - web\n - chat\n - pushes\n allow_failure: true ";
|
||||
|
||||
const createComponent = () => {
|
||||
wrapper = shallowMount(CiLint, {
|
||||
data() {
|
||||
return {
|
||||
content,
|
||||
};
|
||||
},
|
||||
propsData: {
|
||||
endpoint,
|
||||
helpPagePath: '/help/ci/lint#pipeline-simulation',
|
||||
},
|
||||
mocks: {
|
||||
$apollo: {
|
||||
mutate: jest.fn(),
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findEditor = () => wrapper.find(EditorLite);
|
||||
const findValidateBtn = () => wrapper.find('[data-testid="ci-lint-validate"]');
|
||||
const findClearBtn = () => wrapper.find('[data-testid="ci-lint-clear"]');
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('displays the editor', () => {
|
||||
expect(findEditor().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('validate action calls mutation correctly', () => {
|
||||
findValidateBtn().vm.$emit('click');
|
||||
|
||||
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
|
||||
mutation: lintCIMutation,
|
||||
variables: { content, dry: false, endpoint },
|
||||
});
|
||||
});
|
||||
|
||||
it('validate action calls mutation with dry run', async () => {
|
||||
const dryRunEnabled = true;
|
||||
|
||||
await wrapper.setData({ dryRun: dryRunEnabled });
|
||||
|
||||
findValidateBtn().vm.$emit('click');
|
||||
|
||||
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
|
||||
mutation: lintCIMutation,
|
||||
variables: { content, dry: dryRunEnabled, endpoint },
|
||||
});
|
||||
});
|
||||
|
||||
it('content is cleared on clear action', async () => {
|
||||
expect(findEditor().props('value')).toBe(content);
|
||||
|
||||
await findClearBtn().vm.$emit('click');
|
||||
|
||||
expect(findEditor().props('value')).toBe('');
|
||||
});
|
||||
});
|
|
@ -203,7 +203,7 @@ describe('GroupItemComponent', () => {
|
|||
expect(vm.$el.querySelector('.title a.no-expand')).toBeDefined();
|
||||
|
||||
expect(visibilityIconEl).not.toBe(null);
|
||||
expect(visibilityIconEl.dataset.originalTitle).toBe(vm.visibilityTooltip);
|
||||
expect(visibilityIconEl.title).toBe(vm.visibilityTooltip);
|
||||
expect(visibilityIconEl.querySelectorAll('svg').length).toBeGreaterThan(0);
|
||||
|
||||
expect(vm.$el.querySelector('.access-type')).toBeDefined();
|
||||
|
|
|
@ -49,7 +49,7 @@ describe('ItemStatsValue', () => {
|
|||
});
|
||||
|
||||
it('renders element tooltip correctly', () => {
|
||||
expect(wrapper.attributes('data-original-title')).toBe('Subgroups');
|
||||
expect(wrapper.attributes('title')).toBe('Subgroups');
|
||||
expect(wrapper.attributes('data-placement')).toBe('left');
|
||||
});
|
||||
|
||||
|
|
|
@ -312,18 +312,25 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
|
|||
|
||||
describe '#update_merge_request_metrics?' do
|
||||
{
|
||||
'gprd' => false,
|
||||
'prod' => true,
|
||||
'prod-test' => false,
|
||||
'PROD' => true,
|
||||
'production' => true,
|
||||
'production-test' => false,
|
||||
'PRODUCTION' => true,
|
||||
'production/eu' => true,
|
||||
'PRODUCTION/EU' => true,
|
||||
'production/www.gitlab.com' => true,
|
||||
'productioneu' => false,
|
||||
'Production' => false,
|
||||
'Production/eu' => false,
|
||||
'Production' => true,
|
||||
'Production/eu' => true,
|
||||
'test-production' => false
|
||||
}.each do |name, expected_value|
|
||||
it "returns #{expected_value} for #{name}" do
|
||||
env = create(:environment, name: name)
|
||||
|
||||
expect(env.update_merge_request_metrics?).to eq(expected_value)
|
||||
expect(env.update_merge_request_metrics?).to eq(expected_value), "Expected the name '#{name}' to result in #{expected_value}, but it didn't."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -581,40 +581,5 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when downstream pipeline has workflow rule' do
|
||||
before do
|
||||
stub_ci_pipeline_yaml_file(config)
|
||||
end
|
||||
|
||||
let(:config) do
|
||||
<<-EOY
|
||||
workflow:
|
||||
rules:
|
||||
- if: $my_var
|
||||
|
||||
regular-job:
|
||||
script: 'echo Hello, World!'
|
||||
EOY
|
||||
end
|
||||
|
||||
context 'when passing the required variable' do
|
||||
before do
|
||||
bridge.yaml_variables = [{ key: 'my_var', value: 'var', public: true }]
|
||||
end
|
||||
|
||||
it 'creates the pipeline' do
|
||||
expect { service.execute(bridge) }.to change(downstream_project.ci_pipelines, :count).by(1)
|
||||
|
||||
expect(bridge.reload).to be_success
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not passing the required variable' do
|
||||
it 'does not create the pipeline' do
|
||||
expect { service.execute(bridge) }.not_to change(downstream_project.ci_pipelines, :count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -41,9 +41,7 @@ RSpec.describe Ci::CreatePipelineService do
|
|||
save_on_errors: save_on_errors,
|
||||
trigger_request: trigger_request,
|
||||
merge_request: merge_request,
|
||||
external_pull_request: external_pull_request) do |pipeline|
|
||||
yield(pipeline) if block_given?
|
||||
end
|
||||
external_pull_request: external_pull_request)
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
|
@ -2276,108 +2274,6 @@ RSpec.describe Ci::CreatePipelineService do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with workflow rules with persisted variables' do
|
||||
let(:config) do
|
||||
<<-EOY
|
||||
workflow:
|
||||
rules:
|
||||
- if: $CI_COMMIT_REF_NAME == "master"
|
||||
|
||||
regular-job:
|
||||
script: 'echo Hello, World!'
|
||||
EOY
|
||||
end
|
||||
|
||||
context 'with matches' do
|
||||
it 'creates a pipeline' do
|
||||
expect(pipeline).to be_persisted
|
||||
expect(build_names).to contain_exactly('regular-job')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no matches' do
|
||||
let(:ref_name) { 'refs/heads/feature' }
|
||||
|
||||
it 'does not create a pipeline' do
|
||||
expect(pipeline).not_to be_persisted
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with workflow rules with pipeline variables' do
|
||||
let(:pipeline) do
|
||||
execute_service(variables_attributes: variables_attributes)
|
||||
end
|
||||
|
||||
let(:config) do
|
||||
<<-EOY
|
||||
workflow:
|
||||
rules:
|
||||
- if: $SOME_VARIABLE
|
||||
|
||||
regular-job:
|
||||
script: 'echo Hello, World!'
|
||||
EOY
|
||||
end
|
||||
|
||||
context 'with matches' do
|
||||
let(:variables_attributes) do
|
||||
[{ key: 'SOME_VARIABLE', secret_value: 'SOME_VAR' }]
|
||||
end
|
||||
|
||||
it 'creates a pipeline' do
|
||||
expect(pipeline).to be_persisted
|
||||
expect(build_names).to contain_exactly('regular-job')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no matches' do
|
||||
let(:variables_attributes) { {} }
|
||||
|
||||
it 'does not create a pipeline' do
|
||||
expect(pipeline).not_to be_persisted
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with workflow rules with trigger variables' do
|
||||
let(:pipeline) do
|
||||
execute_service do |pipeline|
|
||||
pipeline.variables.build(variables)
|
||||
end
|
||||
end
|
||||
|
||||
let(:config) do
|
||||
<<-EOY
|
||||
workflow:
|
||||
rules:
|
||||
- if: $SOME_VARIABLE
|
||||
|
||||
regular-job:
|
||||
script: 'echo Hello, World!'
|
||||
EOY
|
||||
end
|
||||
|
||||
context 'with matches' do
|
||||
let(:variables) do
|
||||
[{ key: 'SOME_VARIABLE', secret_value: 'SOME_VAR' }]
|
||||
end
|
||||
|
||||
it 'creates a pipeline' do
|
||||
expect(pipeline).to be_persisted
|
||||
expect(build_names).to contain_exactly('regular-job')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no matches' do
|
||||
let(:variables) { {} }
|
||||
|
||||
it 'does not create a pipeline' do
|
||||
expect(pipeline).not_to be_persisted
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -161,29 +161,6 @@ RSpec.describe Ci::PipelineTriggerService do
|
|||
expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables)
|
||||
expect(job.sourced_pipelines.last.pipeline_id).to eq(result[:pipeline].id)
|
||||
end
|
||||
|
||||
context 'when the config has workflow rule with the variable' do
|
||||
let(:config) do
|
||||
<<-EOY
|
||||
workflow:
|
||||
rules:
|
||||
- if: $AAA
|
||||
|
||||
regular-job:
|
||||
script: 'echo Hello, World!'
|
||||
EOY
|
||||
end
|
||||
|
||||
before do
|
||||
stub_ci_pipeline_yaml_file(config)
|
||||
end
|
||||
|
||||
it 'runs the pipeline' do
|
||||
expect { result }.to change { Ci::Pipeline.count }.by(1)
|
||||
|
||||
expect(result[:status]).to eq(:success)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue