diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-02 00:11:09 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-02 00:11:09 +0300 |
commit | 11b7785066d3e81916cbf653f4eb6568148f7e01 (patch) | |
tree | d4e66091e1cbef57db10d2c9c16cd98106e9a633 | |
parent | 69f0d90aad454a2b8f3c4e2f2ca31886a14a8642 (diff) |
Add latest changes from gitlab-org/gitlab@master
46 files changed, 363 insertions, 329 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index 56d9f784113..f25d73fdf09 100644 --- a/.rubocop.yml +++ b/.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: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 0189a3d6372..f15256cae0c 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -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. diff --git a/app/assets/javascripts/pages/groups/activity/index.js b/app/assets/javascripts/pages/groups/activity/index.js index 1b887cad496..8b7c36a0976 100644 --- a/app/assets/javascripts/pages/groups/activity/index.js +++ b/app/assets/javascripts/pages/groups/activity/index.js @@ -1,3 +1,4 @@ import Activities from '~/activities'; -document.addEventListener('DOMContentLoaded', () => new Activities()); +// eslint-disable-next-line no-new +new Activities(); diff --git a/app/assets/javascripts/pipeline_editor/components/ui/pipeline_editor_empty_state.vue b/app/assets/javascripts/pipeline_editor/components/ui/pipeline_editor_empty_state.vue new file mode 100644 index 00000000000..2864e69505c --- /dev/null +++ b/app/assets/javascripts/pipeline_editor/components/ui/pipeline_editor_empty_state.vue @@ -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> diff --git a/app/assets/javascripts/pipeline_editor/constants.js b/app/assets/javascripts/pipeline_editor/constants.js index e676fdeae02..471de7e4f75 100644 --- a/app/assets/javascripts/pipeline_editor/constants.js +++ b/app/assets/javascripts/pipeline_editor/constants.js @@ -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'; diff --git a/app/assets/javascripts/pipeline_editor/index.js b/app/assets/javascripts/pipeline_editor/index.js index dc427f55b5f..4e8106a6136 100644 --- a/app/assets/javascripts/pipeline_editor/index.js +++ b/app/assets/javascripts/pipeline_editor/index.js @@ -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, diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue index ae1c8f53604..f0e8a232f71 100644 --- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue +++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue @@ -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> diff --git a/app/assets/stylesheets/highlight/themes/dark.scss b/app/assets/stylesheets/highlight/themes/dark.scss index 64387fbce09..0dc01213606 100644 --- a/app/assets/stylesheets/highlight/themes/dark.scss +++ b/app/assets/stylesheets/highlight/themes/dark.scss @@ -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; diff --git a/app/assets/stylesheets/highlight/themes/monokai.scss b/app/assets/stylesheets/highlight/themes/monokai.scss index 119908ffba8..95c3e8e9103 100644 --- a/app/assets/stylesheets/highlight/themes/monokai.scss +++ b/app/assets/stylesheets/highlight/themes/monokai.scss @@ -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 */ } diff --git a/app/assets/stylesheets/highlight/white_base.scss b/app/assets/stylesheets/highlight/white_base.scss index 777332881f3..128fe0cc046 100644 --- a/app/assets/stylesheets/highlight/white_base.scss +++ b/app/assets/stylesheets/highlight/white_base.scss @@ -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; diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb index 79e4ec375b7..4514bf288c5 100644 --- a/app/controllers/projects/ci/pipeline_editor_controller.rb +++ b/app/controllers/projects/ci/pipeline_editor_controller.rb @@ -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 diff --git a/app/helpers/ci/pipeline_editor_helper.rb b/app/helpers/ci/pipeline_editor_helper.rb index 3f48b2687b9..a71b0f4a83a 100644 --- a/app/helpers/ci/pipeline_editor_helper.rb +++ b/app/helpers/ci/pipeline_editor_helper.rb @@ -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 diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 729585be84a..9db28b54fe9 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -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 diff --git a/app/views/projects/ci/pipeline_editor/show.html.haml b/app/views/projects/ci/pipeline_editor/show.html.haml index 10aed15f380..a6c031fd80b 100644 --- a/app/views/projects/ci/pipeline_editor/show.html.haml +++ b/app/views/projects/ci/pipeline_editor/show.html.haml @@ -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'), } } diff --git a/changelogs/unreleased/mvanremmerden-master-patch-70791.yml b/changelogs/unreleased/mvanremmerden-master-patch-70791.yml new file mode 100644 index 00000000000..b7a2a57a805 --- /dev/null +++ b/changelogs/unreleased/mvanremmerden-master-patch-70791.yml @@ -0,0 +1,5 @@ +--- +title: Align heading style with subheadings in markdown +merge_request: 55284 +author: +type: other diff --git a/changelogs/unreleased/pipeline-editor-empty-state.yml b/changelogs/unreleased/pipeline-editor-empty-state.yml new file mode 100644 index 00000000000..9c729aa1b7f --- /dev/null +++ b/changelogs/unreleased/pipeline-editor-empty-state.yml @@ -0,0 +1,5 @@ +--- +title: Add empty state to pipeline editor section +merge_request: 55227 +author: +type: changed diff --git a/changelogs/unreleased/remove-pipeline-editor-section-feature-flag.yml b/changelogs/unreleased/remove-pipeline-editor-section-feature-flag.yml new file mode 100644 index 00000000000..4cfdc38fd4b --- /dev/null +++ b/changelogs/unreleased/remove-pipeline-editor-section-feature-flag.yml @@ -0,0 +1,5 @@ +--- +title: Remove pipeline editor feature flag +merge_request: 54971 +author: +type: other diff --git a/config/feature_flags/development/ci_pipeline_editor_page.yml b/config/feature_flags/development/ci_pipeline_editor_page.yml deleted file mode 100644 index 313126f3444..00000000000 --- a/config/feature_flags/development/ci_pipeline_editor_page.yml +++ /dev/null @@ -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 diff --git a/doc/.vale/gitlab/DefaultBranch.yml b/doc/.vale/gitlab/DefaultBranch.yml new file mode 100644 index 00000000000..4bc68433c6d --- /dev/null +++ b/doc/.vale/gitlab/DefaultBranch.yml @@ -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\`' diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 649fe0cce8b..49a53039847 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -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" diff --git a/doc/ci/environments/deployment_safety.md b/doc/ci/environments/deployment_safety.md index eecc8ffd18f..358117ed796 100644 --- a/doc/ci/environments/deployment_safety.md +++ b/doc/ci/environments/deployment_safety.md @@ -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. diff --git a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md index a5024e8a65f..40ba7cff5f9 100644 --- a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md +++ b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md @@ -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: diff --git a/doc/ci/examples/deployment/composer-npm-deploy.md b/doc/ci/examples/deployment/composer-npm-deploy.md index 2d7ba2bc759..62607320410 100644 --- a/doc/ci/examples/deployment/composer-npm-deploy.md +++ b/doc/ci/examples/deployment/composer-npm-deploy.md @@ -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. diff --git a/doc/ci/examples/semantic-release.md b/doc/ci/examples/semantic-release.md index c0fc93fe1b3..6580719b969 100644 --- a/doc/ci/examples/semantic-release.md +++ b/doc/ci/examples/semantic-release.md @@ -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: diff --git a/doc/ci/pipeline_editor/index.md b/doc/ci/pipeline_editor/index.md index 9f4a1afe2f9..f85e287e3dc 100644 --- a/doc/ci/pipeline_editor/index.md +++ b/doc/ci/pipeline_editor/index.md @@ -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) -``` diff --git a/doc/ci/quick_start/index.md b/doc/ci/quick_start/index.md index 7ae76ad3a84..664523a08e4 100644 --- a/doc/ci/quick_start/index.md +++ b/doc/ci/quick_start/index.md @@ -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. diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md index b44526135a1..fc83c45763a 100644 --- a/doc/ci/review_apps/index.md +++ b/doc/ci/review_apps/index.md @@ -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 diff --git a/doc/ci/troubleshooting.md b/doc/ci/troubleshooting.md index 0f57a8e00e2..d4b9282ac38 100644 --- a/doc/ci/troubleshooting.md +++ b/doc/ci/troubleshooting.md @@ -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. diff --git a/doc/ci/unit_test_reports.md b/doc/ci/unit_test_reports.md index c1720675d6a..e20d2a90192 100644 --- a/doc/ci/unit_test_reports.md +++ b/doc/ci/unit_test_reports.md @@ -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 diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index c4aa60cccdd..51ddf5d3dd1 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -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) diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md index 29f2da8858f..c4418f37846 100644 --- a/doc/development/documentation/styleguide/index.md +++ b/doc/development/documentation/styleguide/index.md @@ -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. - -Add the version history information as a blockquote: +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. +- 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: - -```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: +## Feature name 2 -```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: diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md index 17516adf799..146114c99ad 100644 --- a/doc/user/profile/index.md +++ b/doc/user/profile/index.md @@ -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: diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb index 79738747e71..cfc9300a710 100644 --- a/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb +++ b/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb @@ -19,6 +19,10 @@ module Gitlab raise NotImplementedError end + def markdown_description + self.class.name + end + def self.identifier raise NotImplementedError end diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb index 0c549a79393..2e89aa7bc31 100644 --- a/lib/gitlab/ci/features.rb +++ b/lib/gitlab/ci/features.rb @@ -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) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 1d847c1cd26..5bd1a5384fe 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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 "" diff --git a/spec/controllers/projects/ci/pipeline_editor_controller_spec.rb b/spec/controllers/projects/ci/pipeline_editor_controller_spec.rb index 1bf6ff95c44..942402a6d00 100644 --- a/spec/controllers/projects/ci/pipeline_editor_controller_spec.rb +++ b/spec/controllers/projects/ci/pipeline_editor_controller_spec.rb @@ -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 diff --git a/spec/factories/namespaces.rb b/spec/factories/namespaces.rb index 398e4f8b4f9..f4b57369678 100644 --- a/spec/factories/namespaces.rb +++ b/spec/factories/namespaces.rb @@ -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 diff --git a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js new file mode 100644 index 00000000000..2210fc87f68 --- /dev/null +++ b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js @@ -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); + }); +}); diff --git a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js index b44ba0e4543..0dfd123db75 100644 --- a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js +++ b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js @@ -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.'; - - it('shows a 404 error message and does not show editor home component', async () => { - mockBlobContentData.mockRejectedValueOnce({ - response: { - status: httpStatusCodes.NOT_FOUND, - }, - }); - createComponentWithApollo(); + 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(); - await waitForPromises(); + await waitForPromises(); - expect(findAlert().text()).toBe(noFileAlertMsg); - expect(findEditorHome().exists()).toBe(false); + expect(findEmptyState().exists()).toBe(true); + expect(findAlert().exists()).toBe(false); + 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, - }, - }); - createComponentWithApollo(); + 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(); + await waitForPromises(); - expect(findAlert().text()).toBe(noFileAlertMsg); - expect(findEditorHome().exists()).toBe(false); + expect(findEmptyState().exists()).toBe(true); + expect(findAlert().exists()).toBe(false); + 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); + }); }); }); diff --git a/spec/helpers/ci/pipeline_editor_helper_spec.rb b/spec/helpers/ci/pipeline_editor_helper_spec.rb index 8f38d3b1439..7686983eb0f 100644 --- a/spec/helpers/ci/pipeline_editor_helper_spec.rb +++ b/spec/helpers/ci/pipeline_editor_helper_spec.rb @@ -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 diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb index 555cffba614..a5338659659 100644 --- a/spec/helpers/notifications_helper_spec.rb +++ b/spec/helpers/notifications_helper_spec.rb @@ -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 } diff --git a/spec/lib/gitlab/ci/status/factory_spec.rb b/spec/lib/gitlab/ci/status/factory_spec.rb index 641cb0183d3..94a6255f1e2 100644 --- a/spec/lib/gitlab/ci/status/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/factory_spec.rb @@ -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 diff --git a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb index e58e41d3e4f..de37b997d13 100644 --- a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb +++ b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb @@ -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 diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index 29b49db42f9..2fd544ab949 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -4,40 +4,41 @@ require 'spec_helper' RSpec.describe Boards::Issues::ListService do describe '#execute' do - context 'when parent is a project' do - let(:user) { create(:user) } - let(:project) { create(:project) } - let(:board) { create(:board, project: project) } - - let(:m1) { create(:milestone, project: project) } - let(: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!(: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(:user) { create(:user) } - 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!(: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!(: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) } + context 'when parent is a project' do + let_it_be(:project) { create(:project, :empty_repo) } + let_it_be(:board) { create(:board, project: project) } + + let_it_be(:m1) { create(:milestone, project: project) } + let_it_be(:m2) { create(:milestone, project: project) } + + 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_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_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_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_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 diff --git a/spec/services/labels/promote_service_spec.rb b/spec/services/labels/promote_service_spec.rb index 15d53857f33..81c24b26c9f 100644 --- a/spec/services/labels/promote_service_spec.rb +++ b/spec/services/labels/promote_service_spec.rb @@ -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 diff --git a/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb index 145a7290ac8..7d341d79bae 100644 --- a/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb +++ b/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb @@ -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 |