Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
69f0d90aad
commit
11b7785066
46 changed files with 357 additions and 323 deletions
11
.rubocop.yml
11
.rubocop.yml
|
@ -90,6 +90,17 @@ RSpec/FilePath:
|
|||
- 'ee/spec/frontend/fixtures/*'
|
||||
- 'spec/requests/api/v3/*'
|
||||
|
||||
# Configuration parameters: AllowSubject.
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
Max: 28
|
||||
AllowSubject: true
|
||||
Exclude:
|
||||
- 'spec/migrations/**/*.rb'
|
||||
- 'spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/populate_finding_uuid_for_vulnerability_feedback_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/populate_uuids_for_security_findings_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb'
|
||||
|
||||
Naming/FileName:
|
||||
ExpectMatchingDefinition: true
|
||||
Exclude:
|
||||
|
|
|
@ -463,11 +463,6 @@ RSpec/ExpectChange:
|
|||
RSpec/ExpectInHook:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 16403
|
||||
# Configuration parameters: AllowSubject.
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
Max: 40
|
||||
|
||||
# Offense count: 2352
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: Strict, EnforcedStyle, AllowedExplicitMatchers.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Activities from '~/activities';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => new Activities());
|
||||
// eslint-disable-next-line no-new
|
||||
new Activities();
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<script>
|
||||
import { GlSprintf } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlSprintf,
|
||||
},
|
||||
i18n: {
|
||||
title: __('Optimize your workflow with CI/CD Pipelines'),
|
||||
body: __(
|
||||
'Create a new %{codeStart}.gitlab-ci.yml%{codeEnd} file at the root of the repository to get started.',
|
||||
),
|
||||
},
|
||||
inject: {
|
||||
emptyStateIllustrationPath: {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="gl-display-flex gl-flex-direction-column gl-align-items-center gl-mt-11">
|
||||
<img :src="emptyStateIllustrationPath" />
|
||||
<h1 class="gl-font-size-h1">{{ $options.i18n.title }}</h1>
|
||||
<p>
|
||||
<gl-sprintf :message="$options.i18n.body">
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
|
@ -5,7 +5,6 @@ export const COMMIT_FAILURE = 'COMMIT_FAILURE';
|
|||
export const COMMIT_SUCCESS = 'COMMIT_SUCCESS';
|
||||
|
||||
export const DEFAULT_FAILURE = 'DEFAULT_FAILURE';
|
||||
export const LOAD_FAILURE_NO_FILE = 'LOAD_FAILURE_NO_FILE';
|
||||
export const LOAD_FAILURE_UNKNOWN = 'LOAD_FAILURE_UNKNOWN';
|
||||
|
||||
export const CREATE_TAB = 'CREATE_TAB';
|
||||
|
|
|
@ -25,6 +25,7 @@ export const initPipelineEditor = (selector = '#js-pipeline-editor') => {
|
|||
// Add to provide/inject API for static values
|
||||
ciConfigPath,
|
||||
defaultBranch,
|
||||
emptyStateIllustrationPath,
|
||||
lintHelpPagePath,
|
||||
newMergeRequestPath,
|
||||
projectFullPath,
|
||||
|
@ -51,6 +52,7 @@ export const initPipelineEditor = (selector = '#js-pipeline-editor') => {
|
|||
provide: {
|
||||
ciConfigPath,
|
||||
defaultBranch,
|
||||
emptyStateIllustrationPath,
|
||||
lintHelpPagePath,
|
||||
newMergeRequestPath,
|
||||
projectFullPath,
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
<script>
|
||||
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
|
||||
import httpStatusCodes from '~/lib/utils/http_status';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import { __, s__ } from '~/locale';
|
||||
|
||||
import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils';
|
||||
import ConfirmUnsavedChangesDialog from './components/ui/confirm_unsaved_changes_dialog.vue';
|
||||
import {
|
||||
COMMIT_FAILURE,
|
||||
COMMIT_SUCCESS,
|
||||
DEFAULT_FAILURE,
|
||||
LOAD_FAILURE_NO_FILE,
|
||||
LOAD_FAILURE_UNKNOWN,
|
||||
} from './constants';
|
||||
import PipelineEditorEmptyState from './components/ui/pipeline_editor_empty_state.vue';
|
||||
import { COMMIT_FAILURE, COMMIT_SUCCESS, DEFAULT_FAILURE, LOAD_FAILURE_UNKNOWN } from './constants';
|
||||
import getBlobContent from './graphql/queries/blob_content.graphql';
|
||||
import getCiConfigData from './graphql/queries/ci_config.graphql';
|
||||
import PipelineEditorHome from './pipeline_editor_home.vue';
|
||||
|
@ -21,6 +16,7 @@ export default {
|
|||
ConfirmUnsavedChangesDialog,
|
||||
GlAlert,
|
||||
GlLoadingIcon,
|
||||
PipelineEditorEmptyState,
|
||||
PipelineEditorHome,
|
||||
},
|
||||
inject: {
|
||||
|
@ -40,6 +36,7 @@ export default {
|
|||
// Success and failure state
|
||||
failureType: null,
|
||||
failureReasons: [],
|
||||
hasNoCiConfigFile: false,
|
||||
initialCiFileContent: '',
|
||||
lastCommittedContent: '',
|
||||
currentCiFileContent: '',
|
||||
|
@ -102,21 +99,11 @@ export default {
|
|||
isBlobContentLoading() {
|
||||
return this.$apollo.queries.initialCiFileContent.loading;
|
||||
},
|
||||
isBlobContentError() {
|
||||
return this.failureType === LOAD_FAILURE_NO_FILE;
|
||||
},
|
||||
isCiConfigDataLoading() {
|
||||
return this.$apollo.queries.ciConfigData.loading;
|
||||
},
|
||||
failure() {
|
||||
switch (this.failureType) {
|
||||
case LOAD_FAILURE_NO_FILE:
|
||||
return {
|
||||
text: sprintf(this.$options.errorTexts[LOAD_FAILURE_NO_FILE], {
|
||||
filePath: this.ciConfigPath,
|
||||
}),
|
||||
variant: 'danger',
|
||||
};
|
||||
case LOAD_FAILURE_UNKNOWN:
|
||||
return {
|
||||
text: this.$options.errorTexts[LOAD_FAILURE_UNKNOWN],
|
||||
|
@ -154,9 +141,6 @@ export default {
|
|||
errorTexts: {
|
||||
[COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'),
|
||||
[DEFAULT_FAILURE]: __('Something went wrong on our end.'),
|
||||
[LOAD_FAILURE_NO_FILE]: s__(
|
||||
'Pipelines|There is no %{filePath} file in this repository, please add one and visit the Pipeline Editor again.',
|
||||
),
|
||||
[LOAD_FAILURE_UNKNOWN]: s__('Pipelines|The CI configuration was not loaded, please try again.'),
|
||||
},
|
||||
successTexts: {
|
||||
|
@ -173,7 +157,7 @@ export default {
|
|||
response?.status === httpStatusCodes.NOT_FOUND ||
|
||||
response?.status === httpStatusCodes.BAD_REQUEST
|
||||
) {
|
||||
this.reportFailure(LOAD_FAILURE_NO_FILE);
|
||||
this.hasNoCiConfigFile = true;
|
||||
} else {
|
||||
this.reportFailure(LOAD_FAILURE_UNKNOWN);
|
||||
}
|
||||
|
@ -216,18 +200,19 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-mt-4">
|
||||
<gl-alert v-if="showSuccessAlert" :variant="success.variant" @dismiss="dismissSuccess">
|
||||
{{ success.text }}
|
||||
</gl-alert>
|
||||
<gl-alert v-if="showFailureAlert" :variant="failure.variant" @dismiss="dismissFailure">
|
||||
{{ failure.text }}
|
||||
<ul v-if="failureReasons.length" class="gl-mb-0">
|
||||
<li v-for="reason in failureReasons" :key="reason">{{ reason }}</li>
|
||||
</ul>
|
||||
</gl-alert>
|
||||
<div class="gl-mt-4 gl-relative">
|
||||
<gl-loading-icon v-if="isBlobContentLoading" size="lg" class="gl-m-3" />
|
||||
<div v-else-if="!isBlobContentError" class="gl-mt-4">
|
||||
<pipeline-editor-empty-state v-else-if="hasNoCiConfigFile" />
|
||||
<div v-else>
|
||||
<gl-alert v-if="showSuccessAlert" :variant="success.variant" @dismiss="dismissSuccess">
|
||||
{{ success.text }}
|
||||
</gl-alert>
|
||||
<gl-alert v-if="showFailureAlert" :variant="failure.variant" @dismiss="dismissFailure">
|
||||
{{ failure.text }}
|
||||
<ul v-if="failureReasons.length" class="gl-mb-0">
|
||||
<li v-for="reason in failureReasons" :key="reason">{{ reason }}</li>
|
||||
</ul>
|
||||
</gl-alert>
|
||||
<pipeline-editor-home
|
||||
:is-ci-config-data-loading="isCiConfigDataLoading"
|
||||
:ci-config-data="ciConfigData"
|
||||
|
@ -237,7 +222,7 @@ export default {
|
|||
@showError="showErrorAlert"
|
||||
@updateCiConfig="updateCiConfig"
|
||||
/>
|
||||
<confirm-unsaved-changes-dialog :has-unsaved-changes="hasUnsavedChanges" />
|
||||
</div>
|
||||
<confirm-unsaved-changes-dialog :has-unsaved-changes="hasUnsavedChanges" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -38,7 +38,7 @@ $dark-cp: #969896;
|
|||
$dark-c1: #969896;
|
||||
$dark-cs: #969896;
|
||||
$dark-gd: #c66;
|
||||
$dark-gh: #c5c8c6;
|
||||
$dark-gh: #8abeb7;
|
||||
$dark-gi: #b5bd68;
|
||||
$dark-gp: #969896;
|
||||
$dark-gu: #8abeb7;
|
||||
|
|
|
@ -87,6 +87,7 @@ $monokai-il: #ae81ff;
|
|||
$monokai-gu: #75715e;
|
||||
$monokai-gd: #f92672;
|
||||
$monokai-gi: #a6e22e;
|
||||
$monokai-gh: #75715e;
|
||||
|
||||
.code.monokai {
|
||||
// Line numbers
|
||||
|
@ -281,4 +282,5 @@ $monokai-gi: #a6e22e;
|
|||
.gu { color: $monokai-gu; } /* Generic.Subheading & Diff Unified/Comment? */
|
||||
.gd { color: $monokai-gd; } /* Generic.Deleted & Diff Deleted */
|
||||
.gi { color: $monokai-gi; } /* Generic.Inserted & Diff Inserted */
|
||||
.gh { color: $monokai-gh; } /* Generic.Heading */
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ $white-gd-bg: #fdd;
|
|||
$white-gd-x: $black;
|
||||
$white-gd-x-bg: #faa;
|
||||
$white-gr: #a00;
|
||||
$white-gh: #999;
|
||||
$white-gh: #800080;
|
||||
$white-gi: $black;
|
||||
$white-gi-bg: #dfd;
|
||||
$white-gi-x: $black;
|
||||
|
@ -280,7 +280,9 @@ span.highlight_word {
|
|||
|
||||
.ge { font-style: italic; }
|
||||
.gr { color: $white-gr; }
|
||||
.gh { color: $white-gh; }
|
||||
|
||||
.gh { color: $white-gh;
|
||||
font-weight: $gl-font-weight-bold; }
|
||||
|
||||
.gi {
|
||||
color: $white-gi;
|
||||
|
|
|
@ -11,7 +11,6 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController
|
|||
feature_category :pipeline_authoring
|
||||
|
||||
def show
|
||||
render_404 unless ::Gitlab::Ci::Features.ci_pipeline_editor_page_enabled?(@project)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -5,8 +5,7 @@ module Ci
|
|||
include ChecksCollaboration
|
||||
|
||||
def can_view_pipeline_editor?(project)
|
||||
can_collaborate_with_project?(project) &&
|
||||
Gitlab::Ci::Features.ci_pipeline_editor_page_enabled?(project)
|
||||
can_collaborate_with_project?(project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -72,52 +72,6 @@ module NotificationsHelper
|
|||
end
|
||||
end
|
||||
|
||||
def notification_list_item(level, setting)
|
||||
title = notification_title(level)
|
||||
|
||||
data = {
|
||||
notification_level: level,
|
||||
notification_title: title
|
||||
}
|
||||
|
||||
content_tag(:li, role: "menuitem") do
|
||||
link_to '#', class: "update-notification #{('is-active' if setting.level == level)}", data: data do
|
||||
link_output = content_tag(:strong, title, class: 'dropdown-menu-inner-title')
|
||||
link_output << content_tag(:span, notification_description(level), class: 'dropdown-menu-inner-content')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Identifier to trigger individually dropdowns and custom settings modals in the same view
|
||||
def notifications_menu_identifier(type, notification_setting)
|
||||
"#{type}-#{notification_setting.user_id}-#{notification_setting.source_id}-#{notification_setting.source_type}"
|
||||
end
|
||||
|
||||
# Create hidden field to send notification setting source to controller
|
||||
def hidden_setting_source_input(notification_setting)
|
||||
return unless notification_setting.source_type
|
||||
|
||||
hidden_field_tag "#{notification_setting.source_type.downcase}_id", notification_setting.source_id
|
||||
end
|
||||
|
||||
def notification_event_name(event)
|
||||
# All values from NotificationSetting.email_events
|
||||
case event
|
||||
when :success_pipeline
|
||||
s_('NotificationEvent|Successful pipeline')
|
||||
else
|
||||
event_name = "NotificationEvent|#{event.to_s.humanize}"
|
||||
s_(event_name)
|
||||
end
|
||||
end
|
||||
|
||||
def notification_setting_icon(notification_setting = nil)
|
||||
sprite_icon(
|
||||
!notification_setting.present? || notification_setting.disabled? ? "notifications-off" : "notifications",
|
||||
css_class: "icon notifications-icon js-notifications-icon"
|
||||
)
|
||||
end
|
||||
|
||||
def show_unsubscribe_title?(noteable)
|
||||
can?(current_user, "read_#{noteable.to_ability_name}".to_sym, noteable)
|
||||
end
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
- page_title s_('Pipelines|Pipeline Editor')
|
||||
|
||||
#js-pipeline-editor{ data: { "ci-config-path": @project.ci_config_path_or_default,
|
||||
"commit-sha" => @project.commit ? @project.commit.sha : '',
|
||||
"default-branch" => @project.default_branch,
|
||||
"empty-state-illustration-path" => image_path('illustrations/empty-state/empty-dag-md.svg'),
|
||||
"lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'),
|
||||
"new-merge-request-path" => namespace_project_new_merge_request_path,
|
||||
"project-path" => @project.path,
|
||||
"project-full-path" => @project.full_path,
|
||||
"project-namespace" => @project.namespace.full_path,
|
||||
"default-branch" => @project.default_branch,
|
||||
"commit-sha" => @project.commit ? @project.commit.sha : '',
|
||||
"new-merge-request-path" => namespace_project_new_merge_request_path,
|
||||
"lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'),
|
||||
"yml-help-page-path" => help_page_path('ci/yaml/README'),
|
||||
} }
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Align heading style with subheadings in markdown
|
||||
merge_request: 55284
|
||||
author:
|
||||
type: other
|
5
changelogs/unreleased/pipeline-editor-empty-state.yml
Normal file
5
changelogs/unreleased/pipeline-editor-empty-state.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add empty state to pipeline editor section
|
||||
merge_request: 55227
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove pipeline editor feature flag
|
||||
merge_request: 54971
|
||||
author:
|
||||
type: other
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: ci_pipeline_editor_page
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46580
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/270059
|
||||
milestone: '13.6'
|
||||
type: development
|
||||
group: group::pipeline authoring
|
||||
default_enabled: true
|
14
doc/.vale/gitlab/DefaultBranch.yml
Normal file
14
doc/.vale/gitlab/DefaultBranch.yml
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
# Warning: gitlab.DefaultBranch
|
||||
#
|
||||
# Do not refer to the default branch as the "master" branch, if possible.
|
||||
#
|
||||
# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
|
||||
extends: existence
|
||||
message: 'Use "default branch" or `main` instead of `master`, when possible.'
|
||||
level: warning
|
||||
ignorecase: true
|
||||
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html
|
||||
scope: raw
|
||||
raw:
|
||||
- '\`master\`'
|
|
@ -337,38 +337,41 @@ attribute.
|
|||
|
||||
### Examples
|
||||
|
||||
For these examples we use the project ID 42, and assume the project is hosted on
|
||||
GitLab.com. The example API token we use is `token`. We use
|
||||
[curl](https://curl.se/) to perform the HTTP requests.
|
||||
These examples use [cURL](https://curl.se/) to perform HTTP requests.
|
||||
The example commands use these values:
|
||||
|
||||
Let's start with a basic example:
|
||||
- **Project ID**: 42
|
||||
- **Location**: hosted on GitLab.com
|
||||
- **Example API token**: `token`
|
||||
|
||||
This command generates a changelog for version `1.0.0`.
|
||||
|
||||
The commit range:
|
||||
|
||||
- Starts with the tag of the last release.
|
||||
- Ends with the last commit on the target branch. The default target branch is the project's default branch.
|
||||
|
||||
If the last tag is `v0.9.0` and the default branch is `main`, the range of commits
|
||||
included in this example is `v0.9.0..main`:
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: token" --data "version=1.0.0" "https://gitlab.com/api/v4/projects/42/repository/changelog"
|
||||
```
|
||||
|
||||
This generates a changelog for version `1.0.0`. The start of the range of
|
||||
commits to include is the tag of the last release. The end of the range is the
|
||||
last commit on the target branch, which defaults to the project's default
|
||||
branch. So if the last tag is `v0.9.0`, and the default branch is `main`, this
|
||||
means the range of commits is `v0.9.0..main`.
|
||||
|
||||
If you want to generate the data on a different branch, you can do so as
|
||||
follows:
|
||||
To generate the data on a different branch, specify the `branch` parameter. This
|
||||
command generates data from the `foo` branch:
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: token" --data "version=1.0.0&branch=foo" "https://gitlab.com/api/v4/projects/42/repository/changelog"
|
||||
```
|
||||
|
||||
This generates the data on the `foo` branch.
|
||||
|
||||
A different trailer to use is specified as follows:
|
||||
To use a different trailer, use the `trailer` parameter:
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: token" --data "version=1.0.0&trailer=Type" "https://gitlab.com/api/v4/projects/42/repository/changelog"
|
||||
```
|
||||
|
||||
Or perhaps you want to store the results in a different file:
|
||||
To store the results in a different file, use the `file` parameter:
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: token" --data "version=1.0.0&file=NEWS" "https://gitlab.com/api/v4/projects/42/repository/changelog"
|
||||
|
|
|
@ -74,15 +74,15 @@ runs by enabling the [Skip outdated deployment jobs](../pipelines/settings.md#sk
|
|||
|
||||
Example of a problematic pipeline flow **before** enabling Skip outdated deployment jobs:
|
||||
|
||||
1. Pipeline-A is created on the `master` branch.
|
||||
1. Later, Pipeline-B is created on the `master` branch (with a newer commit SHA).
|
||||
1. Pipeline-A is created on the default branch.
|
||||
1. Later, Pipeline-B is created on the default branch (with a newer commit SHA).
|
||||
1. The `deploy` job in Pipeline-B finishes first, and deploys the newer code.
|
||||
1. The `deploy` job in Pipeline-A finished later, and deploys the older code, **overwriting** the newer (latest) deployment.
|
||||
|
||||
The improved pipeline flow **after** enabling Skip outdated deployment jobs:
|
||||
|
||||
1. Pipeline-A is created on the `master` branch.
|
||||
1. Later, Pipeline-B is created on the `master` branch (with a newer SHA).
|
||||
1. Pipeline-A is created on the default branch.
|
||||
1. Later, Pipeline-B is created on the default branch (with a newer SHA).
|
||||
1. The `deploy` job in Pipeline-B finishes first, and deploys the newer code.
|
||||
1. The `deploy` job in Pipeline-A is automatically cancelled, so that it doesn't overwrite the deployment from the newer pipeline.
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ $ vault write auth/jwt/config \
|
|||
|
||||
For the full list of available configuration options, see Vault's [API documentation](https://www.vaultproject.io/api/auth/jwt#configure).
|
||||
|
||||
The following job, when run for the `master` branch, is able to read secrets under `secret/myproject/staging/`, but not the secrets under `secret/myproject/production/`:
|
||||
The following job, when run for the default branch, is able to read secrets under `secret/myproject/staging/`, but not the secrets under `secret/myproject/production/`:
|
||||
|
||||
```yaml
|
||||
read_secrets:
|
||||
|
|
|
@ -122,7 +122,7 @@ Therefore, for a production environment we use additional steps to ensure that a
|
|||
|
||||
Since this was a WordPress project, I gave real life code snippets. Some further ideas you can pursue:
|
||||
|
||||
- Having a slightly different script for `master` branch allows you to deploy to a production server from that branch and to a stage server from any other branches.
|
||||
- Having a slightly different script for the default branch allows you to deploy to a production server from that branch and to a stage server from any other branches.
|
||||
- Instead of pushing it live, you can push it to WordPress official repository (with creating a SVN commit, etc.).
|
||||
- You could generate i18n text domains on the fly.
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ Test the pipeline by creating a commit with a message like:
|
|||
fix: testing patch releases
|
||||
```
|
||||
|
||||
Push the commit to `master`. The pipeline should create a new release (`v1.0.0`) on the project's **Releases** page and publish a new version of the package to the project's **Package Registry** page.
|
||||
Push the commit to the default branch. The pipeline should create a new release (`v1.0.0`) on the project's **Releases** page and publish a new version of the package to the project's **Package Registry** page.
|
||||
|
||||
To create a minor release, use a commit message like:
|
||||
|
||||
|
|
|
@ -8,10 +8,7 @@ type: reference
|
|||
# Pipeline Editor **(FREE)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4540) in GitLab 13.8.
|
||||
> - It's [deployed behind a feature flag](../../user/feature_flags.md), enabled by default.
|
||||
> - It's enabled on GitLab.com.
|
||||
> - It's recommended for production use.
|
||||
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-pipeline-editor). **(FREE SELF)**
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/270059) in GitLab 13.10.
|
||||
|
||||
WARNING:
|
||||
This feature might not be available to you. Check the **version history** note above for details.
|
||||
|
@ -30,7 +27,7 @@ From the pipeline editor page you can:
|
|||
|
||||
NOTE:
|
||||
You must already have [a `.gitlab-ci.yml` file](../quick_start/index.md#create-a-gitlab-ciyml-file)
|
||||
on the default branch (usually `master`) of your project to use the editor.
|
||||
on the default branch of your project to use the editor.
|
||||
|
||||
## Validate CI configuration
|
||||
|
||||
|
@ -68,7 +65,6 @@ reflected in the CI lint. It displays the same results as the existing [CI Lint
|
|||
|
||||
WARNING:
|
||||
This feature might not be available to you. Check the **version history** note above for details.
|
||||
It is not accessible if the [pipeline editor is disabled](#enable-or-disable-pipeline-editor).
|
||||
|
||||
To view a visualization of your `gitlab-ci.yml` configuration, in your project,
|
||||
go to **CI/CD > Editor**, and then select the **Visualize** tab. The
|
||||
|
@ -150,22 +146,3 @@ If you enter a new branch name, the **Start a new merge request with these chang
|
|||
checkbox appears. Select it to start a new merge request after you commit the changes.
|
||||
|
||||
![The commit form with a new branch](img/pipeline_editor_commit_v13_8.png)
|
||||
|
||||
## Enable or disable pipeline editor **(FREE SELF)**
|
||||
|
||||
The pipeline editor is under development but ready for production use. It is
|
||||
deployed behind a feature flag that is **enabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
|
||||
can disable it.
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:ci_pipeline_editor_page)
|
||||
```
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:ci_pipeline_editor_page)
|
||||
```
|
||||
|
|
|
@ -66,7 +66,7 @@ In this file, you define:
|
|||
- The decisions the runner should make when specific conditions are encountered.
|
||||
|
||||
For example, you might want to run a suite of tests when you commit to
|
||||
any branch except `master`. When you commit to `master`, you want
|
||||
any branch except the default branch. When you commit to the default branch, you want
|
||||
to run the same suite, but also publish your application.
|
||||
|
||||
All of this is defined in the `.gitlab-ci.yml` file.
|
||||
|
|
|
@ -31,8 +31,8 @@ In the above example:
|
|||
|
||||
- A Review App is built every time a commit is pushed to `topic branch`.
|
||||
- The reviewer fails two reviews before passing the third review.
|
||||
- After the review has passed, `topic branch` is merged into `master` where it is deployed to staging.
|
||||
- After having been approved in staging, the changes that were merged into `master` are deployed in to production.
|
||||
- After the review passes, `topic branch` is merged into the default branch, where it's deployed to staging.
|
||||
- After its approval in staging, the changes that were merged into the default branch are deployed to production.
|
||||
|
||||
## How Review Apps work
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ a branch to its remote repository. To illustrate the problem, suppose you've had
|
|||
|
||||
1. A user creates a feature branch named `example` and pushes it to a remote repository.
|
||||
1. A new pipeline starts running on the `example` branch.
|
||||
1. A user rebases the `example` branch on the latest `master` branch and force-pushes it to its remote repository.
|
||||
1. A user rebases the `example` branch on the latest default branch and force-pushes it to its remote repository.
|
||||
1. A new pipeline starts running on the `example` branch again, however,
|
||||
the previous pipeline (2) fails because of `fatal: reference is not a tree:` error.
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ in the pipeline detail view.
|
|||
|
||||
Consider the following workflow:
|
||||
|
||||
1. Your `master` branch is rock solid, your project is using GitLab CI/CD and
|
||||
1. Your default branch is rock solid, your project is using GitLab CI/CD and
|
||||
your pipelines indicate that there isn't anything broken.
|
||||
1. Someone from your team submits a merge request, a test fails and the pipeline
|
||||
gets the known red icon. To investigate more, you have to go through the job
|
||||
|
@ -44,7 +44,7 @@ First, GitLab Runner uploads all [JUnit report format XML files](https://www.ibm
|
|||
as [artifacts](pipelines/job_artifacts.md#artifactsreportsjunit) to GitLab. Then, when you visit a merge request, GitLab starts
|
||||
comparing the head and base branch's JUnit report format XML files, where:
|
||||
|
||||
- The base branch is the target branch (usually `master`).
|
||||
- The base branch is the target branch (usually the default branch).
|
||||
- The head branch is the source branch (the latest pipeline in each merge request).
|
||||
|
||||
The reports panel has a summary showing how many tests failed, how many had errors
|
||||
|
|
|
@ -247,7 +247,7 @@ include:
|
|||
```
|
||||
|
||||
The [`MergeRequest-Pipelines` template](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/Workflows/MergeRequest-Pipelines.gitlab-ci.yml)
|
||||
makes your pipelines run for the default branch (usually `master`), tags, and
|
||||
makes your pipelines run for the default branch, tags, and
|
||||
all types of merge request pipelines. Use this template if you use any of the
|
||||
the [Pipelines for Merge Requests features](../merge_request_pipelines/), as mentioned
|
||||
above.
|
||||
|
@ -1260,9 +1260,9 @@ Other commonly used variables for `if` clauses:
|
|||
|
||||
- `if: $CI_COMMIT_TAG`: If changes are pushed for a tag.
|
||||
- `if: $CI_COMMIT_BRANCH`: If changes are pushed to any branch.
|
||||
- `if: '$CI_COMMIT_BRANCH == "master"'`: If changes are pushed to `master`.
|
||||
- `if: '$CI_COMMIT_BRANCH == "main"'`: If changes are pushed to `main`.
|
||||
- `if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'`: If changes are pushed to the default
|
||||
branch (usually `master`). Use when you want to have the same configuration in multiple
|
||||
branch. Use when you want to have the same configuration in multiple
|
||||
projects with different default branches.
|
||||
- `if: '$CI_COMMIT_BRANCH =~ /regex-expression/'`: If the commit branch matches a regular expression.
|
||||
- `if: '$CUSTOM_VARIABLE !~ /regex-expression/'`: If the [custom variable](../variables/README.md#custom-cicd-variables)
|
||||
|
|
|
@ -1607,34 +1607,31 @@ displayed for the page or feature.
|
|||
|
||||
#### Version text in the **Version History**
|
||||
|
||||
If all content in a section is related, add version text after the header
|
||||
for the section. The version information must be surrounded by blank lines, and
|
||||
each entry should be on its own line.
|
||||
If all content in a section is related, add version text after the header for
|
||||
the section. The version information must:
|
||||
|
||||
Add the version history information as a blockquote:
|
||||
- Be surrounded by blank lines.
|
||||
- Start with `>`.
|
||||
- Version histories with more than one entry should have each entry on its own
|
||||
line (long lines are okay). Start each line with `> -` to get unordered list
|
||||
formatting.
|
||||
- Whenever possible, have a link to the completed issue, merge request, or epic
|
||||
that introduced the feature. An issue is preferred over a merge request, and
|
||||
a merge request is preferred over an epic.
|
||||
|
||||
```markdown
|
||||
## Feature name
|
||||
|
||||
> Introduced in GitLab 11.3.
|
||||
> [Introduced](<link-to-issue>) in GitLab 11.3.
|
||||
|
||||
This feature does something.
|
||||
```
|
||||
|
||||
Whenever possible, version text should have a link to the completed issue, merge
|
||||
request, or epic that introduced the feature. An issue is preferred over a merge
|
||||
request, and a merge request is preferred over an epic. For example:
|
||||
## Feature name 2
|
||||
|
||||
```markdown
|
||||
> [Introduced](<link-to-issue>) in GitLab 11.3.
|
||||
```
|
||||
|
||||
If you're adding information about new features or changes in a release, update
|
||||
the blockquote to use a bulleted list:
|
||||
|
||||
```markdown
|
||||
> - [Introduced](<link-to-issue>) in GitLab 11.3.
|
||||
> - Enabled by default in GitLab 11.4.
|
||||
> - [Enabled by default](<link-to-issue>) in GitLab 11.4.
|
||||
|
||||
This feature does something else.
|
||||
```
|
||||
|
||||
If a feature is moved to another tier:
|
||||
|
|
|
@ -41,8 +41,8 @@ On your profile page, you can see the following information:
|
|||
- Personal projects: your personal projects (respecting the project's visibility level)
|
||||
- Starred projects: projects you starred
|
||||
- Snippets: your personal code [snippets](../snippets.md#personal-snippets)
|
||||
- Followers: people following you
|
||||
- Following: people you are following
|
||||
- Followers: people [following](../index.md#user-activity) you
|
||||
- Following: people you are [following](../index.md#user-activity)
|
||||
|
||||
Profile page with active Following view:
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@ module Gitlab
|
|||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def markdown_description
|
||||
self.class.name
|
||||
end
|
||||
|
||||
def self.identifier
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
|
|
@ -55,10 +55,6 @@ module Gitlab
|
|||
::Feature.enabled?(:ci_trace_log_invalid_chunks, project, type: :ops, default_enabled: false)
|
||||
end
|
||||
|
||||
def self.ci_pipeline_editor_page_enabled?(project)
|
||||
::Feature.enabled?(:ci_pipeline_editor_page, project, default_enabled: :yaml)
|
||||
end
|
||||
|
||||
def self.validate_build_dependencies?(project)
|
||||
::Feature.enabled?(:ci_validate_build_dependencies, project, default_enabled: :yaml) &&
|
||||
::Feature.disabled?(:ci_validate_build_dependencies_override, project)
|
||||
|
|
|
@ -8560,6 +8560,9 @@ msgstr ""
|
|||
msgid "Create a merge request"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create a new %{codeStart}.gitlab-ci.yml%{codeEnd} file at the root of the repository to get started."
|
||||
msgstr ""
|
||||
|
||||
msgid "Create a new branch"
|
||||
msgstr ""
|
||||
|
||||
|
@ -9073,6 +9076,18 @@ msgstr ""
|
|||
msgid "Cycle Time"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalyticsEvent|%{label_reference} label was added to the issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalyticsEvent|%{label_reference} label was added to the merge request"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalyticsEvent|%{label_reference} label was removed from the issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalyticsEvent|%{label_reference} label was removed from the merge request"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalyticsEvent|Issue closed"
|
||||
msgstr ""
|
||||
|
||||
|
@ -21229,6 +21244,9 @@ msgstr ""
|
|||
msgid "OperationsDashboard|The operations dashboard provides a summary of each project's operational health, including pipeline and alert statuses."
|
||||
msgstr ""
|
||||
|
||||
msgid "Optimize your workflow with CI/CD Pipelines"
|
||||
msgstr ""
|
||||
|
||||
msgid "Optional"
|
||||
msgstr ""
|
||||
|
||||
|
@ -22102,9 +22120,6 @@ msgstr ""
|
|||
msgid "Pipelines|There are currently no pipelines."
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipelines|There is no %{filePath} file in this repository, please add one and visit the Pipeline Editor again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -36,18 +36,5 @@ RSpec.describe Projects::Ci::PipelineEditorController do
|
|||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ci_pipeline_editor_page feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_pipeline_editor_page: false)
|
||||
project.add_developer(user)
|
||||
|
||||
get :show, params: { namespace_id: project.namespace, project_id: project }
|
||||
end
|
||||
|
||||
it 'responds with 404' do
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,15 +23,21 @@ FactoryBot.define do
|
|||
end
|
||||
|
||||
trait :with_aggregation_schedule do
|
||||
association :aggregation_schedule, factory: :namespace_aggregation_schedules
|
||||
after(:create) do |namespace|
|
||||
create(:namespace_aggregation_schedules, namespace: namespace)
|
||||
end
|
||||
end
|
||||
|
||||
trait :with_root_storage_statistics do
|
||||
association :root_storage_statistics, factory: :namespace_root_storage_statistics
|
||||
after(:create) do |namespace|
|
||||
create(:namespace_root_storage_statistics, namespace: namespace)
|
||||
end
|
||||
end
|
||||
|
||||
trait :with_namespace_settings do
|
||||
association :namespace_settings, factory: :namespace_settings
|
||||
after(:create) do |namespace|
|
||||
create(:namespace_settings, namespace: namespace)
|
||||
end
|
||||
end
|
||||
|
||||
trait :shared_runners_disabled do
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import { GlSprintf } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue';
|
||||
|
||||
describe('Pipeline editor empty state', () => {
|
||||
let wrapper;
|
||||
const defaultProvide = {
|
||||
emptyStateIllustrationPath: 'my/svg/path',
|
||||
};
|
||||
|
||||
const createComponent = () => {
|
||||
wrapper = shallowMount(PipelineEditorEmptyState, {
|
||||
provide: defaultProvide,
|
||||
});
|
||||
};
|
||||
|
||||
const findSvgImage = () => wrapper.find('img');
|
||||
const findTitle = () => wrapper.find('h1');
|
||||
const findDescription = () => wrapper.findComponent(GlSprintf);
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders an svg image', () => {
|
||||
expect(findSvgImage().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders a title', () => {
|
||||
expect(findTitle().exists()).toBe(true);
|
||||
expect(findTitle().text()).toBe(wrapper.vm.$options.i18n.title);
|
||||
});
|
||||
|
||||
it('renders a description', () => {
|
||||
expect(findDescription().exists()).toBe(true);
|
||||
expect(findDescription().html()).toContain(wrapper.vm.$options.i18n.body);
|
||||
});
|
||||
});
|
|
@ -7,6 +7,7 @@ import httpStatusCodes from '~/lib/utils/http_status';
|
|||
import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue';
|
||||
import TextEditor from '~/pipeline_editor/components/editor/text_editor.vue';
|
||||
|
||||
import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue';
|
||||
import { COMMIT_SUCCESS, COMMIT_FAILURE, LOAD_FAILURE_UNKNOWN } from '~/pipeline_editor/constants';
|
||||
import getCiConfigData from '~/pipeline_editor/graphql/queries/ci_config.graphql';
|
||||
import PipelineEditorApp from '~/pipeline_editor/pipeline_editor_app.vue';
|
||||
|
@ -92,6 +93,7 @@ describe('Pipeline editor app component', () => {
|
|||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findEditorHome = () => wrapper.findComponent(PipelineEditorHome);
|
||||
const findTextEditor = () => wrapper.findComponent(TextEditor);
|
||||
const findEmptyState = () => wrapper.findComponent(PipelineEditorEmptyState);
|
||||
|
||||
beforeEach(() => {
|
||||
mockBlobContentData = jest.fn();
|
||||
|
@ -146,45 +148,51 @@ describe('Pipeline editor app component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('when no file exists', () => {
|
||||
const noFileAlertMsg =
|
||||
'There is no .gitlab-ci.yml file in this repository, please add one and visit the Pipeline Editor again.';
|
||||
describe('when no CI config file exists', () => {
|
||||
describe('in a project without a repository', () => {
|
||||
it('shows an empty state and does not show editor home component', async () => {
|
||||
mockBlobContentData.mockRejectedValueOnce({
|
||||
response: {
|
||||
status: httpStatusCodes.BAD_REQUEST,
|
||||
},
|
||||
});
|
||||
createComponentWithApollo();
|
||||
|
||||
it('shows a 404 error message and does not show editor home component', async () => {
|
||||
mockBlobContentData.mockRejectedValueOnce({
|
||||
response: {
|
||||
status: httpStatusCodes.NOT_FOUND,
|
||||
},
|
||||
await waitForPromises();
|
||||
|
||||
expect(findEmptyState().exists()).toBe(true);
|
||||
expect(findAlert().exists()).toBe(false);
|
||||
expect(findEditorHome().exists()).toBe(false);
|
||||
});
|
||||
createComponentWithApollo();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(findAlert().text()).toBe(noFileAlertMsg);
|
||||
expect(findEditorHome().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('shows a 400 error message and does not show editor home component', async () => {
|
||||
mockBlobContentData.mockRejectedValueOnce({
|
||||
response: {
|
||||
status: httpStatusCodes.BAD_REQUEST,
|
||||
},
|
||||
describe('in a project with a repository', () => {
|
||||
it('shows an empty state and does not show editor home component', async () => {
|
||||
mockBlobContentData.mockRejectedValueOnce({
|
||||
response: {
|
||||
status: httpStatusCodes.NOT_FOUND,
|
||||
},
|
||||
});
|
||||
createComponentWithApollo();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(findEmptyState().exists()).toBe(true);
|
||||
expect(findAlert().exists()).toBe(false);
|
||||
expect(findEditorHome().exists()).toBe(false);
|
||||
});
|
||||
createComponentWithApollo();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(findAlert().text()).toBe(noFileAlertMsg);
|
||||
expect(findEditorHome().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('shows a unkown error message', async () => {
|
||||
mockBlobContentData.mockRejectedValueOnce(new Error('My error!'));
|
||||
createComponentWithApollo();
|
||||
await waitForPromises();
|
||||
describe('because of a fetching error', () => {
|
||||
it('shows a unkown error message', async () => {
|
||||
mockBlobContentData.mockRejectedValueOnce(new Error('My error!'));
|
||||
createComponentWithApollo();
|
||||
await waitForPromises();
|
||||
|
||||
expect(findAlert().text()).toBe(wrapper.vm.$options.errorTexts[LOAD_FAILURE_UNKNOWN]);
|
||||
expect(findEditorHome().exists()).toBe(true);
|
||||
expect(findEmptyState().exists()).toBe(false);
|
||||
expect(findAlert().text()).toBe(wrapper.vm.$options.errorTexts[LOAD_FAILURE_UNKNOWN]);
|
||||
expect(findEditorHome().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -19,12 +19,5 @@ RSpec.describe Ci::PipelineEditorHelper do
|
|||
|
||||
expect(subject).to be false
|
||||
end
|
||||
|
||||
it 'user can not view editor if feature is disabled' do
|
||||
allow(helper).to receive(:can_collaborate_with_project?).and_return(true)
|
||||
stub_feature_flags(ci_pipeline_editor_page: false)
|
||||
|
||||
expect(subject).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,22 +19,6 @@ RSpec.describe NotificationsHelper do
|
|||
it { expect(notification_title(:global)).to match('Global') }
|
||||
end
|
||||
|
||||
describe '#notification_event_name' do
|
||||
context 'for success_pipeline' do
|
||||
it 'returns the custom name' do
|
||||
expect(FastGettext).to receive(:cached_find).with('NotificationEvent|Successful pipeline')
|
||||
expect(notification_event_name(:success_pipeline)).to eq('Successful pipeline')
|
||||
end
|
||||
end
|
||||
|
||||
context 'for everything else' do
|
||||
it 'returns a humanized name' do
|
||||
expect(FastGettext).to receive(:cached_find).with('NotificationEvent|Failed pipeline')
|
||||
expect(notification_event_name(:failed_pipeline)).to eq('Failed pipeline')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#notification_icon_level' do
|
||||
let(:user) { create(:user) }
|
||||
let(:global_setting) { user.global_notification_setting }
|
||||
|
|
|
@ -134,4 +134,14 @@ RSpec.describe Gitlab::Ci::Status::Factory do
|
|||
it_behaves_like 'compound decorator factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'behaviour of FactoryBot traits that create associations' do
|
||||
context 'creating a namespace with an associated aggregation_schedule record' do
|
||||
it 'creates only one Namespace record and one Namespace::AggregationSchedule record' do
|
||||
expect { create(:namespace, :with_aggregation_schedule) }
|
||||
.to change { Namespace.count }.by(1)
|
||||
.and change { Namespace::AggregationSchedule.count }.by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
# rubocop: disable RSpec/MultipleMemoizedHelpers
|
||||
RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
|
||||
context "with worker attribution" do
|
||||
subject { described_class.new }
|
||||
|
@ -287,3 +288,4 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
|
|||
end
|
||||
end
|
||||
end
|
||||
# rubocop: enable RSpec/MultipleMemoizedHelpers
|
||||
|
|
|
@ -4,40 +4,41 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Boards::Issues::ListService do
|
||||
describe '#execute' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
context 'when parent is a project' do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
let(:board) { create(:board, project: project) }
|
||||
let_it_be(:project) { create(:project, :empty_repo) }
|
||||
let_it_be(:board) { create(:board, project: project) }
|
||||
|
||||
let(:m1) { create(:milestone, project: project) }
|
||||
let(:m2) { create(:milestone, project: project) }
|
||||
let_it_be(:m1) { create(:milestone, project: project) }
|
||||
let_it_be(:m2) { create(:milestone, project: project) }
|
||||
|
||||
let(:bug) { create(:label, project: project, name: 'Bug') }
|
||||
let(:development) { create(:label, project: project, name: 'Development') }
|
||||
let(:testing) { create(:label, project: project, name: 'Testing') }
|
||||
let(:p1) { create(:label, title: 'P1', project: project, priority: 1) }
|
||||
let(:p2) { create(:label, title: 'P2', project: project, priority: 2) }
|
||||
let(:p3) { create(:label, title: 'P3', project: project, priority: 3) }
|
||||
let_it_be(:bug) { create(:label, project: project, name: 'Bug') }
|
||||
let_it_be(:development) { create(:label, project: project, name: 'Development') }
|
||||
let_it_be(:testing) { create(:label, project: project, name: 'Testing') }
|
||||
let_it_be(:p1) { create(:label, title: 'P1', project: project, priority: 1) }
|
||||
let_it_be(:p2) { create(:label, title: 'P2', project: project, priority: 2) }
|
||||
let_it_be(:p3) { create(:label, title: 'P3', project: project, priority: 3) }
|
||||
|
||||
let!(:backlog) { create(:backlog_list, board: board) }
|
||||
let!(:list1) { create(:list, board: board, label: development, position: 0) }
|
||||
let!(:list2) { create(:list, board: board, label: testing, position: 1) }
|
||||
let!(:closed) { create(:closed_list, board: board) }
|
||||
let_it_be(:backlog) { create(:backlog_list, board: board) }
|
||||
let_it_be(:list1) { create(:list, board: board, label: development, position: 0) }
|
||||
let_it_be(:list2) { create(:list, board: board, label: testing, position: 1) }
|
||||
let_it_be(:closed) { create(:closed_list, board: board) }
|
||||
|
||||
let!(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) }
|
||||
let!(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2]) }
|
||||
let!(:reopened_issue1) { create(:issue, :opened, project: project, title: 'Reopened Issue 1' ) }
|
||||
let_it_be(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) }
|
||||
let_it_be(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2]) }
|
||||
let_it_be(:reopened_issue1) { create(:issue, :opened, project: project, title: 'Reopened Issue 1' ) }
|
||||
|
||||
let!(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, development]) }
|
||||
let!(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) }
|
||||
let!(:list1_issue3) { create(:labeled_issue, project: project, milestone: m1, labels: [development, p1]) }
|
||||
let!(:list2_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [testing]) }
|
||||
let_it_be(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, development]) }
|
||||
let_it_be(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) }
|
||||
let_it_be(:list1_issue3) { create(:labeled_issue, project: project, milestone: m1, labels: [development, p1]) }
|
||||
let_it_be(:list2_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [testing]) }
|
||||
|
||||
let!(:closed_issue1) { create(:labeled_issue, :closed, project: project, labels: [bug], closed_at: 1.day.ago) }
|
||||
let!(:closed_issue2) { create(:labeled_issue, :closed, project: project, labels: [p3], closed_at: 2.days.ago) }
|
||||
let!(:closed_issue3) { create(:issue, :closed, project: project, closed_at: 1.week.ago) }
|
||||
let!(:closed_issue4) { create(:labeled_issue, :closed, project: project, labels: [p1], closed_at: 1.year.ago) }
|
||||
let!(:closed_issue5) { create(:labeled_issue, :closed, project: project, labels: [development], closed_at: 2.years.ago) }
|
||||
let_it_be(:closed_issue1) { create(:labeled_issue, :closed, project: project, labels: [bug], closed_at: 1.day.ago) }
|
||||
let_it_be(:closed_issue2) { create(:labeled_issue, :closed, project: project, labels: [p3], closed_at: 2.days.ago) }
|
||||
let_it_be(:closed_issue3) { create(:issue, :closed, project: project, closed_at: 1.week.ago) }
|
||||
let_it_be(:closed_issue4) { create(:labeled_issue, :closed, project: project, labels: [p1], closed_at: 1.year.ago) }
|
||||
let_it_be(:closed_issue5) { create(:labeled_issue, :closed, project: project, labels: [development], closed_at: 2.years.ago) }
|
||||
|
||||
let(:parent) { project }
|
||||
|
||||
|
@ -48,14 +49,16 @@ RSpec.describe Boards::Issues::ListService do
|
|||
it_behaves_like 'issues list service'
|
||||
|
||||
context 'when project is archived' do
|
||||
let(:project) { create(:project, :archived) }
|
||||
before do
|
||||
project.update!(archived: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'issues list service'
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop: disable RSpec/MultipleMemoizedHelpers
|
||||
context 'when parent is a group' do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :empty_repo, namespace: group) }
|
||||
let(:project1) { create(:project, :empty_repo, namespace: group) }
|
||||
let(:project_archived) { create(:project, :empty_repo, :archived, namespace: group) }
|
||||
|
@ -104,7 +107,7 @@ RSpec.describe Boards::Issues::ListService do
|
|||
group.add_developer(user)
|
||||
end
|
||||
|
||||
context 'and group has no parent' do
|
||||
context 'when the group has no parent' do
|
||||
let(:parent) { group }
|
||||
let(:group) { create(:group) }
|
||||
let(:board) { create(:board, group: group) }
|
||||
|
@ -112,7 +115,7 @@ RSpec.describe Boards::Issues::ListService do
|
|||
it_behaves_like 'issues list service'
|
||||
end
|
||||
|
||||
context 'and group is an ancestor' do
|
||||
context 'when the group is an ancestor' do
|
||||
let(:parent) { create(:group) }
|
||||
let(:group) { create(:group, parent: parent) }
|
||||
let!(:backlog) { create(:backlog_list, board: board) }
|
||||
|
@ -125,5 +128,6 @@ RSpec.describe Boards::Issues::ListService do
|
|||
it_behaves_like 'issues list service'
|
||||
end
|
||||
end
|
||||
# rubocop: enable RSpec/MultipleMemoizedHelpers
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,9 +4,9 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Labels::PromoteService do
|
||||
describe '#execute' do
|
||||
let!(:user) { create(:user) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
context 'project without group' do
|
||||
context 'without a group' do
|
||||
let!(:project_1) { create(:project) }
|
||||
|
||||
let!(:project_label_1_1) { create(:label, project: project_1) }
|
||||
|
@ -18,40 +18,40 @@ RSpec.describe Labels::PromoteService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'project with group' do
|
||||
let!(:promoted_label_name) { "Promoted Label" }
|
||||
let!(:untouched_label_name) { "Untouched Label" }
|
||||
let!(:promoted_description) { "Promoted Description" }
|
||||
let!(:promoted_color) { "#0000FF" }
|
||||
let!(:label_2_1_priority) { 1 }
|
||||
let!(:label_3_1_priority) { 2 }
|
||||
context 'with a group' do
|
||||
let_it_be(:promoted_label_name) { "Promoted Label" }
|
||||
let_it_be(:untouched_label_name) { "Untouched Label" }
|
||||
let_it_be(:promoted_description) { "Promoted Description" }
|
||||
let_it_be(:promoted_color) { "#0000FF" }
|
||||
let_it_be(:label_2_1_priority) { 1 }
|
||||
let_it_be(:label_3_1_priority) { 2 }
|
||||
|
||||
let!(:group_1) { create(:group) }
|
||||
let!(:group_2) { create(:group) }
|
||||
let_it_be(:group_1) { create(:group) }
|
||||
let_it_be(:group_2) { create(:group) }
|
||||
|
||||
let!(:project_1) { create(:project, namespace: group_1) }
|
||||
let!(:project_2) { create(:project, namespace: group_1) }
|
||||
let!(:project_3) { create(:project, namespace: group_1) }
|
||||
let!(:project_4) { create(:project, namespace: group_2) }
|
||||
let_it_be(:project_1) { create(:project, :repository, namespace: group_1) }
|
||||
let_it_be(:project_2) { create(:project, :repository, namespace: group_1) }
|
||||
let_it_be(:project_3) { create(:project, :repository, namespace: group_1) }
|
||||
let_it_be(:project_4) { create(:project, :repository, namespace: group_2) }
|
||||
|
||||
# Labels/issues can't be lazily created so we might as well eager initialize
|
||||
# all other objects too since we use them inside
|
||||
let!(:project_label_1_1) { create(:label, project: project_1, name: promoted_label_name, color: promoted_color, description: promoted_description) }
|
||||
let!(:project_label_1_2) { create(:label, project: project_1, name: untouched_label_name) }
|
||||
let!(:project_label_2_1) { create(:label, project: project_2, priority: label_2_1_priority, name: promoted_label_name, color: "#FF0000") }
|
||||
let!(:project_label_3_1) { create(:label, project: project_3, priority: label_3_1_priority, name: promoted_label_name) }
|
||||
let!(:project_label_3_2) { create(:label, project: project_3, priority: 1, name: untouched_label_name) }
|
||||
let!(:project_label_4_1) { create(:label, project: project_4, name: promoted_label_name) }
|
||||
let_it_be(:project_label_1_1) { create(:label, project: project_1, name: promoted_label_name, color: promoted_color, description: promoted_description) }
|
||||
let_it_be(:project_label_1_2) { create(:label, project: project_1, name: untouched_label_name) }
|
||||
let_it_be(:project_label_2_1) { create(:label, project: project_2, priority: label_2_1_priority, name: promoted_label_name, color: "#FF0000") }
|
||||
let_it_be(:project_label_3_1) { create(:label, project: project_3, priority: label_3_1_priority, name: promoted_label_name) }
|
||||
let_it_be(:project_label_3_2) { create(:label, project: project_3, priority: 1, name: untouched_label_name) }
|
||||
let_it_be(:project_label_4_1) { create(:label, project: project_4, name: promoted_label_name) }
|
||||
|
||||
let!(:issue_1_1) { create(:labeled_issue, project: project_1, labels: [project_label_1_1, project_label_1_2]) }
|
||||
let!(:issue_1_2) { create(:labeled_issue, project: project_1, labels: [project_label_1_2]) }
|
||||
let!(:issue_2_1) { create(:labeled_issue, project: project_2, labels: [project_label_2_1]) }
|
||||
let!(:issue_4_1) { create(:labeled_issue, project: project_4, labels: [project_label_4_1]) }
|
||||
let_it_be(:issue_1_1) { create(:labeled_issue, project: project_1, labels: [project_label_1_1, project_label_1_2]) }
|
||||
let_it_be(:issue_1_2) { create(:labeled_issue, project: project_1, labels: [project_label_1_2]) }
|
||||
let_it_be(:issue_2_1) { create(:labeled_issue, project: project_2, labels: [project_label_2_1]) }
|
||||
let_it_be(:issue_4_1) { create(:labeled_issue, project: project_4, labels: [project_label_4_1]) }
|
||||
|
||||
let!(:merge_3_1) { create(:labeled_merge_request, source_project: project_3, target_project: project_3, labels: [project_label_3_1, project_label_3_2]) }
|
||||
let_it_be(:merge_3_1) { create(:labeled_merge_request, source_project: project_3, target_project: project_3, labels: [project_label_3_1, project_label_3_2]) }
|
||||
|
||||
let!(:issue_board_2_1) { create(:board, project: project_2) }
|
||||
let!(:issue_board_list_2_1) { create(:list, board: issue_board_2_1, label: project_label_2_1) }
|
||||
let_it_be(:issue_board_2_1) { create(:board, project: project_2) }
|
||||
let_it_be(:issue_board_list_2_1) { create(:list, board: issue_board_2_1, label: project_label_2_1) }
|
||||
|
||||
let(:new_label) { group_1.labels.find_by(title: promoted_label_name) }
|
||||
|
||||
|
@ -82,8 +82,8 @@ RSpec.describe Labels::PromoteService do
|
|||
|
||||
expect { service.execute(project_label_1_1) }.to change { Subscription.count }.from(4).to(3)
|
||||
|
||||
expect(new_label.subscribed?(user)).to be_truthy
|
||||
expect(new_label.subscribed?(user2)).to be_truthy
|
||||
expect(new_label).to be_subscribed(user)
|
||||
expect(new_label).to be_subscribed(user2)
|
||||
end
|
||||
|
||||
it 'recreates priorities' do
|
||||
|
@ -165,12 +165,12 @@ RSpec.describe Labels::PromoteService do
|
|||
service.execute(project_label_1_1)
|
||||
|
||||
Label.reflect_on_all_associations.each do |association|
|
||||
expect(project_label_1_1.send(association.name).any?).to be_falsey
|
||||
expect(project_label_1_1.send(association.name).reset).not_to be_any
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'if there is an existing identical group label' do
|
||||
context 'when there is an existing identical group label' do
|
||||
let!(:existing_group_label) { create(:group_label, group: group_1, title: project_label_1_1.title ) }
|
||||
|
||||
it 'uses the existing group label' do
|
||||
|
@ -187,7 +187,7 @@ RSpec.describe Labels::PromoteService do
|
|||
it_behaves_like 'promoting a project label to a group label'
|
||||
end
|
||||
|
||||
context 'if there is no existing identical group label' do
|
||||
context 'when there is no existing identical group label' do
|
||||
let(:existing_group_label) { nil }
|
||||
|
||||
it 'recreates the label as a group label' do
|
||||
|
|
|
@ -8,6 +8,7 @@ RSpec.shared_examples_for 'value stream analytics event' do
|
|||
it { expect(described_class.identifier).to be_a_kind_of(Symbol) }
|
||||
it { expect(instance.object_type.ancestors).to include(ApplicationRecord) }
|
||||
it { expect(instance).to respond_to(:timestamp_projection) }
|
||||
it { expect(instance).to respond_to(:markdown_description) }
|
||||
it { expect(instance.column_list).to be_a_kind_of(Array) }
|
||||
|
||||
describe '#apply_query_customization' do
|
||||
|
|
Loading…
Reference in a new issue