diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-14 00:09:24 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-14 00:09:24 +0300 |
commit | 0698388e65ed3556a11ec7eb2e76e7b7f9f0489e (patch) | |
tree | e1f5121a371023c3bf14fab12d4ca4a2ff7b6429 | |
parent | d9aac35d79489591396456aceefa609de4b8b05c (diff) |
Add latest changes from gitlab-org/gitlab@master
60 files changed, 595 insertions, 218 deletions
diff --git a/app/assets/javascripts/diffs/components/no_changes.vue b/app/assets/javascripts/diffs/components/no_changes.vue index 94c2695a945..93afa978862 100644 --- a/app/assets/javascripts/diffs/components/no_changes.vue +++ b/app/assets/javascripts/diffs/components/no_changes.vue @@ -1,12 +1,12 @@ <script> import { mapGetters } from 'vuex'; import { escape } from 'lodash'; -import { GlDeprecatedButton } from '@gitlab/ui'; +import { GlButton } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; export default { components: { - GlDeprecatedButton, + GlButton, }, props: { changesEmptyStateIllustration: { @@ -43,9 +43,9 @@ export default { <div class="text-content text-center"> <span v-html="emptyStateText"></span> <div class="text-center"> - <gl-deprecated-button :href="getNoteableData.new_blob_path" variant="success">{{ + <gl-button :href="getNoteableData.new_blob_path" variant="success" category="primary">{{ __('Create commit') - }}</gl-deprecated-button> + }}</gl-button> </div> </div> </div> diff --git a/app/assets/javascripts/vue_merge_request_widget/index.js b/app/assets/javascripts/vue_merge_request_widget/index.js index c59af0c4a1a..068829912bf 100644 --- a/app/assets/javascripts/vue_merge_request_widget/index.js +++ b/app/assets/javascripts/vue_merge_request_widget/index.js @@ -1,8 +1,15 @@ import Vue from 'vue'; import MrWidgetOptions from 'ee_else_ce/vue_merge_request_widget/mr_widget_options.vue'; import Translate from '../vue_shared/translate'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; Vue.use(Translate); +Vue.use(VueApollo); + +const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), +}); export default () => { if (gl.mrWidget) return; @@ -10,7 +17,7 @@ export default () => { gl.mrWidgetData.gitlabLogo = gon.gitlab_logo; gl.mrWidgetData.defaultAvatarUrl = gon.default_avatar_url; - const vm = new Vue(MrWidgetOptions); + const vm = new Vue({ ...MrWidgetOptions, apolloProvider }); window.gl.mrWidget = { checkStatus: vm.checkStatus, diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index aebc5cb757a..3a210d66420 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -360,14 +360,6 @@ table { } } -.toolbar-button-icon { - position: relative; - top: 1px; - margin-right: $gl-padding-4; - color: inherit; - font-size: 16px; -} - .toolbar-text { font-size: 14px; line-height: 16px; diff --git a/app/controllers/groups/variables_controller.rb b/app/controllers/groups/variables_controller.rb index 11e3cfb01e4..02b015e8e53 100644 --- a/app/controllers/groups/variables_controller.rb +++ b/app/controllers/groups/variables_controller.rb @@ -9,7 +9,7 @@ module Groups def show respond_to do |format| format.json do - render status: :ok, json: { variables: GroupVariableSerializer.new.represent(@group.variables) } + render status: :ok, json: { variables: ::Ci::GroupVariableSerializer.new.represent(@group.variables) } end end end @@ -29,7 +29,7 @@ module Groups private def render_group_variables - render status: :ok, json: { variables: GroupVariableSerializer.new.represent(@group.variables) } + render status: :ok, json: { variables: ::Ci::GroupVariableSerializer.new.represent(@group.variables) } end def render_error diff --git a/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb b/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb new file mode 100644 index 00000000000..45c288243d7 --- /dev/null +++ b/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Projects + module IncidentManagement + class PagerDutyIncidentsController < Projects::ApplicationController + respond_to :json + + skip_before_action :verify_authenticity_token + skip_before_action :project + + prepend_before_action :project_without_auth + + def create + result = ServiceResponse.success(http_status: :accepted) + + unless Feature.enabled?(:pagerduty_webhook, @project) + result = ServiceResponse.error(message: 'Unauthorized', http_status: :unauthorized) + end + + head result.http_status + end + + private + + def project_without_auth + @project ||= Project + .find_by_full_path("#{params[:namespace_id]}/#{params[:project_id]}") + end + end + end +end diff --git a/app/controllers/projects/pipelines/stages_controller.rb b/app/controllers/projects/pipelines/stages_controller.rb new file mode 100644 index 00000000000..ce08b49ce9f --- /dev/null +++ b/app/controllers/projects/pipelines/stages_controller.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Projects + module Pipelines + class StagesController < Projects::Pipelines::ApplicationController + before_action :authorize_update_pipeline! + + def play_manual + ::Ci::PlayManualStageService + .new(@project, current_user, pipeline: pipeline) + .execute(stage) + + respond_to do |format| + format.json do + render json: StageSerializer + .new(project: @project, current_user: @current_user) + .represent(stage) + end + end + end + + private + + def stage + @pipeline_stage ||= pipeline.find_stage_by_name!(params[:stage_name]) + end + end + end +end diff --git a/app/controllers/projects/stages_controller.rb b/app/controllers/projects/stages_controller.rb deleted file mode 100644 index c8db5b1277f..00000000000 --- a/app/controllers/projects/stages_controller.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -class Projects::StagesController < Projects::PipelinesController - before_action :authorize_update_pipeline! - - def play_manual - ::Ci::PlayManualStageService - .new(@project, current_user, pipeline: pipeline) - .execute(stage) - - respond_to do |format| - format.json do - render json: StageSerializer - .new(project: @project, current_user: @current_user) - .represent(stage) - end - end - end - - private - - def stage - @pipeline_stage ||= pipeline.find_stage_by_name!(params[:stage_name]) - end -end diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb index 1dffc57fcf0..2cc030d18fc 100644 --- a/app/controllers/projects/variables_controller.rb +++ b/app/controllers/projects/variables_controller.rb @@ -6,7 +6,7 @@ class Projects::VariablesController < Projects::ApplicationController def show respond_to do |format| format.json do - render status: :ok, json: { variables: VariableSerializer.new.represent(@project.variables) } + render status: :ok, json: { variables: ::Ci::VariableSerializer.new.represent(@project.variables) } end end end @@ -26,7 +26,7 @@ class Projects::VariablesController < Projects::ApplicationController private def render_variables - render status: :ok, json: { variables: VariableSerializer.new.represent(@project.variables) } + render status: :ok, json: { variables: ::Ci::VariableSerializer.new.represent(@project.variables) } end def render_error diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 8a32d3c8a3f..aeba88d4939 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -53,6 +53,15 @@ module IconsHelper content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{sprite_icon_path}##{icon_name}" } ), class: css_classes.empty? ? nil : css_classes.join(' ')) end + def loading_icon(container: false, color: 'orange', size: 'sm', css_class: nil) + css_classes = ['gl-spinner', "gl-spinner-#{color}", "gl-spinner-#{size}"] + css_classes << "#{css_class}" unless css_class.blank? + + spinner = content_tag(:span, "", { class: css_classes.join(' '), aria: { label: _('Loading') } }) + + container == true ? content_tag(:div, spinner, { class: 'gl-spinner-container' }) : spinner + end + def external_snippet_icon(name) content_tag(:span, "", class: "gl-snippet-icon gl-snippet-icon-#{name}") end diff --git a/app/models/alert_management/alert.rb b/app/models/alert_management/alert.rb index 394957beb40..1a8a3f7a54c 100644 --- a/app/models/alert_management/alert.rb +++ b/app/models/alert_management/alert.rb @@ -57,7 +57,7 @@ module AlertManagement validates :started_at, presence: true validates :fingerprint, allow_blank: true, uniqueness: { scope: :project, - conditions: -> { where.not(status: STATUSES[:resolved]) }, + conditions: -> { not_resolved }, message: -> (object, data) { _('Cannot have multiple unresolved alerts') } }, unless: :resolved? validate :hosts_length @@ -120,6 +120,7 @@ module AlertManagement scope :for_environment, -> (environment) { where(environment: environment) } scope :search, -> (query) { fuzzy_search(query, [:title, :description, :monitoring_tool, :service]) } scope :open, -> { with_status(:triggered, :acknowledged) } + scope :not_resolved, -> { where.not(status: STATUSES[:resolved]) } scope :with_prometheus_alert, -> { includes(:prometheus_alert) } scope :order_start_time, -> (sort_order) { order(started_at: sort_order) } diff --git a/app/presenters/projects/prometheus/alert_presenter.rb b/app/presenters/projects/prometheus/alert_presenter.rb index 8307c0ed8b8..1cf8b202810 100644 --- a/app/presenters/projects/prometheus/alert_presenter.rb +++ b/app/presenters/projects/prometheus/alert_presenter.rb @@ -6,7 +6,7 @@ module Projects RESERVED_ANNOTATIONS = %w(gitlab_incident_markdown gitlab_y_label title).freeze GENERIC_ALERT_SUMMARY_ANNOTATIONS = %w(monitoring_tool service hosts).freeze MARKDOWN_LINE_BREAK = " \n".freeze - INCIDENT_LABEL_NAME = IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES[:title].freeze + INCIDENT_LABEL_NAME = ::IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES[:title].freeze METRIC_TIME_WINDOW = 30.minutes def full_title diff --git a/app/serializers/ci/group_variable_entity.rb b/app/serializers/ci/group_variable_entity.rb new file mode 100644 index 00000000000..e7d0a957082 --- /dev/null +++ b/app/serializers/ci/group_variable_entity.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module Ci + class GroupVariableEntity < Ci::BasicVariableEntity + end +end diff --git a/app/serializers/ci/group_variable_serializer.rb b/app/serializers/ci/group_variable_serializer.rb new file mode 100644 index 00000000000..b100a931620 --- /dev/null +++ b/app/serializers/ci/group_variable_serializer.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Ci + class GroupVariableSerializer < BaseSerializer + entity ::Ci::GroupVariableEntity + end +end diff --git a/app/serializers/ci/variable_entity.rb b/app/serializers/ci/variable_entity.rb new file mode 100644 index 00000000000..715f829a0e1 --- /dev/null +++ b/app/serializers/ci/variable_entity.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Ci + class VariableEntity < Ci::BasicVariableEntity + expose :environment_scope + end +end diff --git a/app/serializers/ci/variable_serializer.rb b/app/serializers/ci/variable_serializer.rb new file mode 100644 index 00000000000..eb47d3b71b5 --- /dev/null +++ b/app/serializers/ci/variable_serializer.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Ci + class VariableSerializer < BaseSerializer + entity ::Ci::VariableEntity + end +end diff --git a/app/serializers/group_variable_entity.rb b/app/serializers/group_variable_entity.rb deleted file mode 100644 index 4f44723fefe..00000000000 --- a/app/serializers/group_variable_entity.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -class GroupVariableEntity < Ci::BasicVariableEntity -end diff --git a/app/serializers/group_variable_serializer.rb b/app/serializers/group_variable_serializer.rb deleted file mode 100644 index ed20b240cce..00000000000 --- a/app/serializers/group_variable_serializer.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -class GroupVariableSerializer < BaseSerializer - entity GroupVariableEntity -end diff --git a/app/serializers/variable_entity.rb b/app/serializers/variable_entity.rb deleted file mode 100644 index 9b0db371acb..00000000000 --- a/app/serializers/variable_entity.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -class VariableEntity < Ci::BasicVariableEntity - expose :environment_scope -end diff --git a/app/serializers/variable_serializer.rb b/app/serializers/variable_serializer.rb deleted file mode 100644 index 586666cad8e..00000000000 --- a/app/serializers/variable_serializer.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -class VariableSerializer < BaseSerializer - entity VariableEntity -end diff --git a/app/services/alert_management/process_prometheus_alert_service.rb b/app/services/alert_management/process_prometheus_alert_service.rb index 24c091b4815..573d3914c05 100644 --- a/app/services/alert_management/process_prometheus_alert_service.rb +++ b/app/services/alert_management/process_prometheus_alert_service.rb @@ -94,7 +94,7 @@ module AlertManagement end def am_alert - @am_alert ||= AlertManagement::Alert.for_fingerprint(project, gitlab_fingerprint).first + @am_alert ||= AlertManagement::Alert.not_resolved.for_fingerprint(project, gitlab_fingerprint).first end def bad_request diff --git a/app/services/projects/alerting/notify_service.rb b/app/services/projects/alerting/notify_service.rb index 4af3eba5df0..e08bc8efb15 100644 --- a/app/services/projects/alerting/notify_service.rb +++ b/app/services/projects/alerting/notify_service.rb @@ -4,7 +4,7 @@ module Projects module Alerting class NotifyService < BaseService include Gitlab::Utils::StrongMemoize - include IncidentManagement::Settings + include ::IncidentManagement::Settings def execute(token) return forbidden unless alerts_service_activated? @@ -55,7 +55,7 @@ module Projects def find_alert_by_fingerprint(fingerprint) return unless fingerprint - AlertManagement::Alert.for_fingerprint(project, fingerprint).first + AlertManagement::Alert.not_resolved.for_fingerprint(project, fingerprint).first end def send_email? @@ -65,7 +65,7 @@ module Projects def process_incident_issues(alert) return if alert.issue - IncidentManagement::ProcessAlertWorker.perform_async(nil, nil, alert.id) + ::IncidentManagement::ProcessAlertWorker.perform_async(nil, nil, alert.id) end def send_alert_email diff --git a/app/services/projects/prometheus/alerts/notify_service.rb b/app/services/projects/prometheus/alerts/notify_service.rb index 4b3aed2d1d9..ea557ebe20f 100644 --- a/app/services/projects/prometheus/alerts/notify_service.rb +++ b/app/services/projects/prometheus/alerts/notify_service.rb @@ -5,7 +5,7 @@ module Projects module Alerts class NotifyService < BaseService include Gitlab::Utils::StrongMemoize - include IncidentManagement::Settings + include ::IncidentManagement::Settings # This set of keys identifies a payload as a valid Prometheus # payload and thus processable by this service. See also diff --git a/app/views/shared/notes/_hints.html.haml b/app/views/shared/notes/_hints.html.haml index df20c04ed47..abd5d8cd9db 100644 --- a/app/views/shared/notes/_hints.html.haml +++ b/app/views/shared/notes/_hints.html.haml @@ -16,8 +16,7 @@ %span.attaching-file-message -# Populated by app/assets/javascripts/dropzone_input.js %span.uploading-progress 0% - %span.uploading-spinner - .toolbar-button-icon.spinner.align-text-top + = loading_icon(css_class: 'align-text-bottom gl-mr-2') %span.uploading-error-container.hide %span.uploading-error-icon diff --git a/changelogs/unreleased/223097-support-fenced-code-blocks-in-atlassian-document-format-converter.yml b/changelogs/unreleased/223097-support-fenced-code-blocks-in-atlassian-document-format-converter.yml new file mode 100644 index 00000000000..0a99851b08a --- /dev/null +++ b/changelogs/unreleased/223097-support-fenced-code-blocks-in-atlassian-document-format-converter.yml @@ -0,0 +1,5 @@ +--- +title: Support fenced code blocks in Atlassian Document Format converter +merge_request: 35065 +author: +type: fixed diff --git a/changelogs/unreleased/223151-open-new-alert-when-existing-are-resolved.yml b/changelogs/unreleased/223151-open-new-alert-when-existing-are-resolved.yml new file mode 100644 index 00000000000..bd1ddd3e3ae --- /dev/null +++ b/changelogs/unreleased/223151-open-new-alert-when-existing-are-resolved.yml @@ -0,0 +1,5 @@ +--- +title: Open new alert when existing alert is resolved +merge_request: 36261 +author: +type: added diff --git a/config/routes/pipelines.rb b/config/routes/pipelines.rb index 50269d6e6ba..c7f9bf8791c 100644 --- a/config/routes/pipelines.rb +++ b/config/routes/pipelines.rb @@ -22,10 +22,8 @@ resources :pipelines, only: [:index, :new, :create, :show, :destroy] do get :test_reports_count end - member do - resources :stages, only: [], param: :name do - post :play_manual - end + resources :stages, only: [], param: :name, controller: 'pipelines/stages' do + post :play_manual end resources :tests, only: [:show], param: :suite_name, controller: 'pipelines/tests' do diff --git a/config/routes/project.rb b/config/routes/project.rb index f660e1958f9..135e4a2f1bd 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -406,6 +406,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do post 'alerts/notify', to: 'alerting/notifications#create' + post 'incident_management/pager_duty', to: 'incident_management/pager_duty_incidents#create' + draw :legacy_builds resources :hooks, only: [:index, :create, :edit, :update, :destroy], constraints: { id: /\d+/ } do # rubocop: disable Cop/PutProjectRoutesUnderScope diff --git a/doc/.vale/gitlab/Acronyms.yml b/doc/.vale/gitlab/Acronyms.yml index 90ec3d9a830..d166e71491c 100644 --- a/doc/.vale/gitlab/Acronyms.yml +++ b/doc/.vale/gitlab/Acronyms.yml @@ -21,6 +21,7 @@ exceptions: - CLI - CNAME - CPU + - CORE - CSS - CSV - DNS diff --git a/doc/.vale/gitlab/OutdatedVersions.yml b/doc/.vale/gitlab/OutdatedVersions.yml index 3b93cdace01..3252481a523 100644 --- a/doc/.vale/gitlab/OutdatedVersions.yml +++ b/doc/.vale/gitlab/OutdatedVersions.yml @@ -11,11 +11,11 @@ level: warning nonword: true ignorecase: true tokens: - - "GitLab 2." - - "GitLab 3." - - "GitLab 4." - - "GitLab 5." - - "GitLab 6." - - "GitLab 7." - - "GitLab 8." - - "GitLab 9." + - "GitLab (v)?2." + - "GitLab (v)?3." + - "GitLab (v)?4." + - "GitLab (v)?5." + - "GitLab (v)?6." + - "GitLab (v)?7." + - "GitLab (v)?8." + - "GitLab (v)?9." diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md index 2adf06a8e95..551b17a2d7b 100644 --- a/doc/api/api_resources.md +++ b/doc/api/api_resources.md @@ -140,7 +140,7 @@ The following API resources are available outside of project and group contexts | [Notification settings](notification_settings.md) | `/notification_settings` (also available for groups and projects) | | [Pages domains](pages_domains.md) | `/pages/domains` (also available for projects) | | [Projects](projects.md) | `/users/:id/projects` (also available for projects) | -| [Project Repository Storage Moves](project_repository_storage_moves.md) | `/project_repository_storage_moves` | +| [Project repository storage moves](project_repository_storage_moves.md) **(CORE ONLY)** | `/project_repository_storage_moves` | | [Runners](runners.md) | `/runners` (also available for projects) | | [Search](search.md) | `/search` (also available for groups and projects) | | [Settings](settings.md) **(CORE ONLY)** | `/application/settings` | diff --git a/doc/api/deployments.md b/doc/api/deployments.md index 8c952ba07b1..426b3e10ecf 100644 --- a/doc/api/deployments.md +++ b/doc/api/deployments.md @@ -1,3 +1,10 @@ +--- +stage: Release +group: Release Management +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +type: concepts, howto +--- + # Deployments API ## List project deployments diff --git a/doc/api/environments.md b/doc/api/environments.md index 75222c1bc52..2287ec9aad2 100644 --- a/doc/api/environments.md +++ b/doc/api/environments.md @@ -1,3 +1,10 @@ +--- +stage: Release +group: Release Management +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +type: concepts, howto +--- + # Environments API ## List environments diff --git a/doc/api/error_tracking.md b/doc/api/error_tracking.md index e18fbaf25c3..658480ce6fa 100644 --- a/doc/api/error_tracking.md +++ b/doc/api/error_tracking.md @@ -1,3 +1,9 @@ +--- +stage: Monitor +group: Health +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +--- + # Error Tracking settings API > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34940) in GitLab 12.7. diff --git a/doc/api/freeze_periods.md b/doc/api/freeze_periods.md index f82213d5a46..e6a5e69497f 100644 --- a/doc/api/freeze_periods.md +++ b/doc/api/freeze_periods.md @@ -1,3 +1,10 @@ +--- +stage: Release +group: Release Management +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +type: concepts, howto +--- + # Freeze Periods API > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29382) in GitLab 13.0. diff --git a/doc/api/group_clusters.md b/doc/api/group_clusters.md index 8a436b3d8df..17413ea2a3b 100644 --- a/doc/api/group_clusters.md +++ b/doc/api/group_clusters.md @@ -1,3 +1,9 @@ +--- +stage: Configure +group: Configure +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +--- + # Group clusters API > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30213) in GitLab 12.1. diff --git a/doc/api/metrics_dashboard_annotations.md b/doc/api/metrics_dashboard_annotations.md index 05bf7156a7e..10dfd3d1c3b 100644 --- a/doc/api/metrics_dashboard_annotations.md +++ b/doc/api/metrics_dashboard_annotations.md @@ -1,3 +1,10 @@ +--- +stage: Monitor +group: APM +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +type: concepts, howto +--- + # Dashboard annotations API > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29089) in GitLab 12.10 behind a disabled feature flag. diff --git a/doc/api/metrics_user_starred_dashboards.md b/doc/api/metrics_user_starred_dashboards.md index 1ed6b15c660..df9cdd3b0e4 100644 --- a/doc/api/metrics_user_starred_dashboards.md +++ b/doc/api/metrics_user_starred_dashboards.md @@ -1,3 +1,10 @@ +--- +stage: Monitor +group: APM +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +type: concepts, howto +--- + # User-starred metrics dashboards API The starred dashboard feature makes navigating to frequently-used dashboards easier diff --git a/doc/api/project_clusters.md b/doc/api/project_clusters.md index 550461e24a2..04694157561 100644 --- a/doc/api/project_clusters.md +++ b/doc/api/project_clusters.md @@ -1,3 +1,9 @@ +--- +stage: Configure +group: Configure +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +--- + # Project clusters API > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/23922) in GitLab 11.7. diff --git a/doc/api/project_repository_storage_moves.md b/doc/api/project_repository_storage_moves.md index c55d4a19feb..f7fb361bf53 100644 --- a/doc/api/project_repository_storage_moves.md +++ b/doc/api/project_repository_storage_moves.md @@ -5,11 +5,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w type: reference --- -# Project repository storage move API +# Project repository storage moves API **(CORE ONLY)** > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31285) in GitLab 13.0. -Project repository storage can be moved. To retrieve project repository storage moves using the API, you must [authenticate yourself](README.md#authentication) as an administrator. +Project repository storage can be moved. To retrieve project repository storage moves using the API, +you must [authenticate yourself](README.md#authentication) as an administrator. ## Retrieve all project repository storage moves @@ -23,7 +24,7 @@ are [paginated](README.md#pagination). Example request: ```shell -curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/project_repository_storage_moves' +curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/project_repository_storage_moves" ``` Example response: @@ -66,7 +67,7 @@ Parameters: Example request: ```shell -curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/1/repository_storage_moves' +curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/repository_storage_moves" ``` Example response: @@ -106,7 +107,7 @@ Parameters: Example request: ```shell -curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/project_repository_storage_moves/1' +curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/project_repository_storage_moves/1" ``` Example response: @@ -145,7 +146,7 @@ Parameters: Example request: ```shell -curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/1/repository_storage_moves/1' +curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/repository_storage_moves/1" ``` Example response: @@ -185,7 +186,7 @@ Example request: ```shell curl --request POST --header "PRIVATE_TOKEN: <your_access_token>" --header "Content-Type: application/json" \ ---data '{"destination_storage_name":"storage2"}' 'https://gitlab.example.com/api/v4/projects/1/repository_storage_moves' +--data '{"destination_storage_name":"storage2"}' "https://gitlab.example.com/api/v4/projects/1/repository_storage_moves" ``` Example response: diff --git a/doc/api/protected_environments.md b/doc/api/protected_environments.md index 765b8d2364d..56b399cec9b 100644 --- a/doc/api/protected_environments.md +++ b/doc/api/protected_environments.md @@ -1,3 +1,10 @@ +--- +stage: Release +group: Release Management +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +type: concepts, howto +--- + # Protected environments API **(PREMIUM)** > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30595) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.8. diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md index 1afb7f02df4..4dcbdfb8270 100644 --- a/doc/user/clusters/applications.md +++ b/doc/user/clusters/applications.md @@ -963,8 +963,8 @@ a corresponding cluster type. The default value is blank. You can check the recommended variables for each cluster type in the official documentation: -- [Google GKE](https://cilium.readthedocs.io/en/stable/gettingstarted/k8s-install-gke/#prepare-deploy-cilium) -- [AWS EKS](https://cilium.readthedocs.io/en/stable/gettingstarted/k8s-install-eks/#prepare-deploy-cilium) +- [Google GKE](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-gke/#deploy-cilium) +- [AWS EKS](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-eks/#deploy-cilium) You can customize Cilium's Helm variables by defining the `.gitlab/managed-apps/cilium/values.yaml` file in your cluster @@ -974,9 +974,9 @@ for the available configuration options. CAUTION: **Caution:** Installation and removal of the Cilium requires a **manual** -[restart](https://cilium.readthedocs.io/en/stable/gettingstarted/k8s-install-gke/#restart-remaining-pods) +[restart](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-gke/#restart-unmanaged-pods) of all affected pods in all namespaces to ensure that they are -[managed](https://cilium.readthedocs.io/en/stable/troubleshooting/#ensure-pod-is-managed-by-cilium) +[managed](https://docs.cilium.io/en/stable/troubleshooting/#ensure-pod-is-managed-by-cilium) by the correct networking plugin. NOTE: **Note:** diff --git a/doc/user/project/integrations/generic_alerts.md b/doc/user/project/integrations/generic_alerts.md index d7312839442..8515008efbd 100644 --- a/doc/user/project/integrations/generic_alerts.md +++ b/doc/user/project/integrations/generic_alerts.md @@ -101,4 +101,6 @@ displays a counter on the [Alert Management List](../operations/alert_management.md#alert-management-list) and details pages. +If the existing alert is already `resolved`, then a new alert will be created instead. + ![Alert Management List](../operations/img/alert_list_v13_1.png) diff --git a/lib/gitlab/ci/status/stage/play_manual.rb b/lib/gitlab/ci/status/stage/play_manual.rb index ac3fc0912fa..58859a8f191 100644 --- a/lib/gitlab/ci/status/stage/play_manual.rb +++ b/lib/gitlab/ci/status/stage/play_manual.rb @@ -18,7 +18,7 @@ module Gitlab def action_path pipeline = subject.pipeline - project_stage_play_manual_path(pipeline.project, pipeline, subject.name) + project_pipeline_stage_play_manual_path(pipeline.project, pipeline, subject.name) end def action_method diff --git a/lib/kramdown/converter/commonmark.rb b/lib/kramdown/converter/commonmark.rb index c7257d8278d..4abb34cc008 100644 --- a/lib/kramdown/converter/commonmark.rb +++ b/lib/kramdown/converter/commonmark.rb @@ -12,6 +12,46 @@ module Kramdown # Note: this is only an initial implementation. Currently don't # strip out IALs or other specific kramdown syntax. class Commonmark < ::Kramdown::Converter::Kramdown + # replaces the ^ used in kramdown. This forces the current + # block to end, so that a different list or codeblock can be + # started. https://kramdown.gettalong.org/syntax.html#eob-marker + END_OF_BLOCK = '<!-- -->' + + def convert(el, opts = { indent: 0 }) + res = super + + if [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] && + ([el.type, :codeblock].include?(opts[:next].type) || + (opts[:next].type == :blank && opts[:nnext] && + [el.type, :codeblock].include?(opts[:nnext].type))) + # replace the end of block character + res.sub!(/\^\n\n\z/m, "#{END_OF_BLOCK}\n\n") + end + + res + end + + def convert_codeblock(el, _opts) + # Although tildes are supported in CommonMark, backticks are more common + "```#{el.options[:lang]}\n" + + el.value.split(/\n/).map {|l| l.empty? ? "" : "#{l}" }.join("\n") + + "\n```\n\n" + end + + def convert_li(el, opts) + res = super + + if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent] + if el.children.size == 1 && @stack.last.children.last == el && + (@stack.last.children.any? {|c| c.children.first.type != :p } || @stack.last.children.size == 1) + # replace the end of block character + res.sub!(/\^\n\z/m, "#{END_OF_BLOCK}\n") + end + end + + res + end + def convert_table(el, opts) return super unless @options[:html_tables] diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 954d229b1e5..f19ad07a192 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -71,6 +71,11 @@ msgstr "" msgid "\"%{path}\" did not exist on \"%{ref}\"" msgstr "" +msgid "%d Scanned URL" +msgid_plural "%d Scanned URLs" +msgstr[0] "" +msgstr[1] "" + msgid "%d URL scanned" msgid_plural "%d URLs scanned" msgstr[0] "" @@ -8305,6 +8310,9 @@ msgstr "" msgid "Download as" msgstr "" +msgid "Download as CSV" +msgstr "" + msgid "Download asset" msgstr "" @@ -24515,6 +24523,9 @@ msgstr "" msgid "To this GitLab instance" msgstr "" +msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file" +msgstr "" + msgid "To view the roadmap, add a start or due date to one of your epics in this group or its subgroups. In the months view, only epics in the past month, current month, and next 5 months are shown." msgstr "" diff --git a/spec/controllers/projects/incident_management/pager_duty_incidents_controller_spec.rb b/spec/controllers/projects/incident_management/pager_duty_incidents_controller_spec.rb new file mode 100644 index 00000000000..92df9c65698 --- /dev/null +++ b/spec/controllers/projects/incident_management/pager_duty_incidents_controller_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::IncidentManagement::PagerDutyIncidentsController do + let_it_be(:project) { create(:project) } + + describe 'POST #create' do + let(:payload) { { messages: [] } } + + def make_request + post :create, params: project_params, body: payload.to_json, as: :json + end + + context 'when pagerduty_webhook feature enabled' do + before do + stub_feature_flags(pagerduty_webhook: project) + end + + it 'responds with 202 Accepted' do + make_request + + expect(response).to have_gitlab_http_status(:accepted) + end + end + + context 'when pagerduty_webhook feature disabled' do + before do + stub_feature_flags(pagerduty_webhook: false) + end + + it 'responds with 401 Unauthorized' do + make_request + + expect(response).to have_gitlab_http_status(:unauthorized) + end + end + end + + private + + def project_params(opts = {}) + opts.reverse_merge(namespace_id: project.namespace, project_id: project) + end +end diff --git a/spec/controllers/projects/stages_controller_spec.rb b/spec/controllers/projects/pipelines/stages_controller_spec.rb index dcf8607ae18..6e8c08d95a1 100644 --- a/spec/controllers/projects/stages_controller_spec.rb +++ b/spec/controllers/projects/pipelines/stages_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Projects::StagesController do +RSpec.describe Projects::Pipelines::StagesController do let(:user) { create(:user) } let(:project) { create(:project, :repository) } @@ -60,7 +60,7 @@ RSpec.describe Projects::StagesController do post :play_manual, params: { namespace_id: project.namespace, project_id: project, - id: pipeline.id, + pipeline_id: pipeline.id, stage_name: stage_name }, format: :json end diff --git a/spec/fixtures/lib/kramdown/atlassian_document_format/code_block.json b/spec/fixtures/lib/kramdown/atlassian_document_format/code_block.json index 26f468626c2..007493bdf49 100644 --- a/spec/fixtures/lib/kramdown/atlassian_document_format/code_block.json +++ b/spec/fixtures/lib/kramdown/atlassian_document_format/code_block.json @@ -15,6 +15,18 @@ ] }, { + "type": "codeBlock", + "attrs": { + "language": "css" + }, + "content": [ + { + "type": "text", + "text": ".overflow { overflow: hidden; }" + } + ] + }, + { "type": "bulletList", "content": [ { @@ -37,6 +49,37 @@ "text": "public DemoClass()\n{\n // assign default value\n x = 0;\n}" } ] + }, + { + "type": "orderedList", + "content": [ + { + "type": "listItem", + "content": [ + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Number list Item 1" + } + ] + }, + { + "type": "codeBlock", + "attrs": { + "language": "ruby" + }, + "content": [ + { + "type": "text", + "text": "def test\n # assign default value\n x = 0\nend" + } + ] + } + ] + } + ] } ] } diff --git a/spec/fixtures/lib/kramdown/atlassian_document_format/code_block.md b/spec/fixtures/lib/kramdown/atlassian_document_format/code_block.md index 77eee3081db..c89710afd36 100644 --- a/spec/fixtures/lib/kramdown/atlassian_document_format/code_block.md +++ b/spec/fixtures/lib/kramdown/atlassian_document_format/code_block.md @@ -1,17 +1,38 @@ - export function makeIssue({ parentIssue, project, users }) { - - const issueType = pickRandom(project.issueTypes) - - console.log(data) - - return data - } +```javascript +export function makeIssue({ parentIssue, project, users }) { + + const issueType = pickRandom(project.issueTypes) + + console.log(data) + + return data +} +``` + +<!-- --> + +```css +.overflow { overflow: hidden; } +``` + * Item 1 - public DemoClass() - { - // assign default value - x = 0; - } + ```java + public DemoClass() + { + // assign default value + x = 0; + } + ``` + + + 1. Number list Item 1 + + ```ruby + def test + # assign default value + x = 0 + end + ``` diff --git a/spec/fixtures/lib/kramdown/atlassian_document_format/complex_document.md b/spec/fixtures/lib/kramdown/atlassian_document_format/complex_document.md index 7933e6425f9..d4faf84e971 100644 --- a/spec/fixtures/lib/kramdown/atlassian_document_format/complex_document.md +++ b/spec/fixtures/lib/kramdown/atlassian_document_format/complex_document.md @@ -165,37 +165,40 @@ Col 3 Row 3 <del>Strikethrough</del> - export function makeIssue({ parentIssue, project, users }) { - - const issueType = pickRandom(project.issueTypes) - - let data = { - fields: { - summary: faker.lorem.sentence(), - issuetype: { - id: issueType.id - }, - project: { - id: project.id - }, - reporter: { - id: pickRandom(users) - } - } +```javascript +export function makeIssue({ parentIssue, project, users }) { + + const issueType = pickRandom(project.issueTypes) + + let data = { + fields: { + summary: faker.lorem.sentence(), + issuetype: { + id: issueType.id + }, + project: { + id: project.id + }, + reporter: { + id: pickRandom(users) } - - if (issueType.subtask) { - data = { - parent: { - key: parentIssue - } - } + } + } + + if (issueType.subtask) { + data = { + parent: { + key: parentIssue } - - console.log(data) - - return data } + } + + console.log(data) + + return data +} +``` + ![jira-10050-field-description](adf-media://79411c6b-50e0-477f-b4ed-ac3a5887750c) diff --git a/spec/fixtures/lib/kramdown/atlassian_document_format/ordered_list.json b/spec/fixtures/lib/kramdown/atlassian_document_format/ordered_list.json index b63bf087b23..71d638c6a38 100644 --- a/spec/fixtures/lib/kramdown/atlassian_document_format/ordered_list.json +++ b/spec/fixtures/lib/kramdown/atlassian_document_format/ordered_list.json @@ -146,6 +146,25 @@ ] } ] + }, + { + "type": "orderedList", + "content": [ + { + "type": "listItem", + "content": [ + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Another list" + } + ] + } + ] + } + ] } ] } diff --git a/spec/fixtures/lib/kramdown/atlassian_document_format/ordered_list.md b/spec/fixtures/lib/kramdown/atlassian_document_format/ordered_list.md index 435bfadbd74..2c1f45cd810 100644 --- a/spec/fixtures/lib/kramdown/atlassian_document_format/ordered_list.md +++ b/spec/fixtures/lib/kramdown/atlassian_document_format/ordered_list.md @@ -17,4 +17,9 @@ 9. Number list item 9 10. Number list item 10 +<!-- --> + +1. Another list + +<!-- --> diff --git a/spec/frontend/diffs/components/no_changes_spec.js b/spec/frontend/diffs/components/no_changes_spec.js index 245651af61c..2eca97a47fd 100644 --- a/spec/frontend/diffs/components/no_changes_spec.js +++ b/spec/frontend/diffs/components/no_changes_spec.js @@ -2,6 +2,7 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; import Vuex from 'vuex'; import { createStore } from '~/mr_notes/stores'; import NoChanges from '~/diffs/components/no_changes.vue'; +import { GlButton } from '@gitlab/ui'; describe('Diff no changes empty state', () => { let vm; @@ -37,4 +38,11 @@ describe('Diff no changes empty state', () => { expect(vm.contains('script')).toBe(false); }); + + describe('Renders', () => { + it('Show create commit button', () => { + createComponent(); + expect(vm.find(GlButton).exists()).toBe(true); + }); + }); }); diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb index 3000a044298..e2e6659382a 100644 --- a/spec/helpers/icons_helper_spec.rb +++ b/spec/helpers/icons_helper_spec.rb @@ -235,4 +235,25 @@ RSpec.describe IconsHelper do .to eq("<span class=\"gl-snippet-icon gl-snippet-icon-download\"></span>") end end + + describe 'loading_icon' do + it 'returns span with gl-spinner class and default configuration' do + expect(loading_icon.to_s) + .to eq '<span class="gl-spinner gl-spinner-orange gl-spinner-sm" aria-label="Loading"></span>' + end + + context 'when css_class is provided' do + it 'appends css_class to gl-spinner element' do + expect(loading_icon(css_class: 'gl-mr-2').to_s) + .to eq '<span class="gl-spinner gl-spinner-orange gl-spinner-sm gl-mr-2" aria-label="Loading"></span>' + end + end + + context 'when container is true' do + it 'creates a container that has the gl-spinner-container class selector' do + expect(loading_icon(container: true).to_s) + .to eq '<div class="gl-spinner-container"><span class="gl-spinner gl-spinner-orange gl-spinner-sm" aria-label="Loading"></span></div>' + end + end + end end diff --git a/spec/models/alert_management/alert_spec.rb b/spec/models/alert_management/alert_spec.rb index 2c62046a7eb..becc5475c15 100644 --- a/spec/models/alert_management/alert_spec.rb +++ b/spec/models/alert_management/alert_spec.rb @@ -235,6 +235,14 @@ RSpec.describe AlertManagement::Alert do it { is_expected.to contain_exactly(acknowledged_alert, triggered_alert) } end + + describe '.not_resolved' do + subject { described_class.not_resolved } + + let!(:acknowledged_alert) { create(:alert_management_alert, :acknowledged, project: project) } + + it { is_expected.to contain_exactly(acknowledged_alert, triggered_alert, ignored_alert) } + end end describe '.last_prometheus_alert_by_project_id' do diff --git a/spec/serializers/group_variable_entity_spec.rb b/spec/serializers/ci/group_variable_entity_spec.rb index 17efe2d2022..a7e12905924 100644 --- a/spec/serializers/group_variable_entity_spec.rb +++ b/spec/serializers/ci/group_variable_entity_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe GroupVariableEntity do +RSpec.describe Ci::GroupVariableEntity do let(:variable) { create(:ci_group_variable) } let(:entity) { described_class.new(variable) } diff --git a/spec/serializers/variable_entity_spec.rb b/spec/serializers/ci/variable_entity_spec.rb index 0b20207d815..38da0b16bbd 100644 --- a/spec/serializers/variable_entity_spec.rb +++ b/spec/serializers/ci/variable_entity_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe VariableEntity do +RSpec.describe Ci::VariableEntity do let(:variable) { create(:ci_variable) } let(:entity) { described_class.new(variable) } diff --git a/spec/services/alert_management/process_prometheus_alert_service_spec.rb b/spec/services/alert_management/process_prometheus_alert_service_spec.rb index 8e496824e40..3618ca20f73 100644 --- a/spec/services/alert_management/process_prometheus_alert_service_spec.rb +++ b/spec/services/alert_management/process_prometheus_alert_service_spec.rb @@ -39,22 +39,27 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do context 'when Prometheus alert status is firing' do context 'when alert with the same fingerprint already exists' do - let!(:alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } - it 'increases alert events count' do - expect { execute }.to change { alert.reload.events }.by(1) + it_behaves_like 'adds an alert management alert event' + + context 'existing alert is resolved' do + let!(:alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } + + it_behaves_like 'creates an alert management alert' end - context 'when status can be changed' do - it 'changes status to triggered' do - expect { execute }.to change { alert.reload.triggered? }.to(true) - end + context 'existing alert is ignored' do + let!(:alert) { create(:alert_management_alert, :ignored, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } + + it_behaves_like 'adds an alert management alert event' end - it 'does not executes the alert service hooks' do - expect(alert).not_to receive(:execute_services) + context 'two existing alerts, one resolved one open' do + let!(:resolved_alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } - subject + it_behaves_like 'adds an alert management alert event' end context 'when status change did not succeed' do @@ -73,23 +78,11 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do execute end end - - it { is_expected.to be_success } end context 'when alert does not exist' do context 'when alert can be created' do - it 'creates a new alert' do - expect { execute }.to change { AlertManagement::Alert.where(project: project).count }.by(1) - end - - it 'executes the alert service hooks' do - slack_service = create(:service, type: 'SlackService', project: project, alert_events: true, active: true) - - subject - - expect(ProjectServiceWorker).to have_received(:perform_async).with(slack_service.id, an_instance_of(Hash)) - end + it_behaves_like 'creates an alert management alert' end context 'when alert cannot be created' do diff --git a/spec/services/projects/alerting/notify_service_spec.rb b/spec/services/projects/alerting/notify_service_spec.rb index 7afad925cdd..123b0bad2a8 100644 --- a/spec/services/projects/alerting/notify_service_spec.rb +++ b/spec/services/projects/alerting/notify_service_spec.rb @@ -64,12 +64,6 @@ RSpec.describe Projects::Alerting::NotifyService do end end - shared_examples 'NotifyService does not create alert' do - it 'does not create alert' do - expect { subject }.not_to change(AlertManagement::Alert, :count) - end - end - describe '#execute' do let(:token) { 'invalid-token' } let(:starts_at) { Time.current.change(usec: 0) } @@ -107,62 +101,64 @@ RSpec.describe Projects::Alerting::NotifyService do end context 'with valid payload' do + shared_examples 'assigns the alert properties' do + it 'ensure that created alert has all data properly assigned' do + subject + + expect(last_alert_attributes).to match( + project_id: project.id, + title: payload_raw.fetch(:title), + started_at: Time.zone.parse(payload_raw.fetch(:start_time)), + severity: payload_raw.fetch(:severity), + status: AlertManagement::Alert::STATUSES[:triggered], + events: 1, + hosts: payload_raw.fetch(:hosts), + payload: payload_raw.with_indifferent_access, + issue_id: nil, + description: payload_raw.fetch(:description), + monitoring_tool: payload_raw.fetch(:monitoring_tool), + service: payload_raw.fetch(:service), + fingerprint: Digest::SHA1.hexdigest(fingerprint), + ended_at: nil, + prometheus_alert_id: nil, + environment_id: nil + ) + end + end + let(:last_alert_attributes) do AlertManagement::Alert.last.attributes .except('id', 'iid', 'created_at', 'updated_at') .with_indifferent_access end - it 'creates AlertManagement::Alert' do - expect { subject }.to change(AlertManagement::Alert, :count).by(1) - end - - it 'created alert has all data properly assigned' do - subject - - expect(last_alert_attributes).to match( - project_id: project.id, - title: payload_raw.fetch(:title), - started_at: Time.zone.parse(payload_raw.fetch(:start_time)), - severity: payload_raw.fetch(:severity), - status: AlertManagement::Alert::STATUSES[:triggered], - events: 1, - hosts: payload_raw.fetch(:hosts), - payload: payload_raw.with_indifferent_access, - issue_id: nil, - description: payload_raw.fetch(:description), - monitoring_tool: payload_raw.fetch(:monitoring_tool), - service: payload_raw.fetch(:service), - fingerprint: Digest::SHA1.hexdigest(fingerprint), - ended_at: nil, - prometheus_alert_id: nil, - environment_id: nil - ) - end - - it 'executes the alert service hooks' do - slack_service = create(:service, type: 'SlackService', project: project, alert_events: true, active: true) - subject - - expect(ProjectServiceWorker).to have_received(:perform_async).with(slack_service.id, an_instance_of(Hash)) - end + it_behaves_like 'creates an alert management alert' + it_behaves_like 'assigns the alert properties' context 'existing alert with same fingerprint' do let(:fingerprint_sha) { Digest::SHA1.hexdigest(fingerprint) } - let!(:existing_alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } + + it_behaves_like 'adds an alert management alert event' + + context 'existing alert is resolved' do + let!(:alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: fingerprint_sha) } - it 'does not create AlertManagement::Alert' do - expect { subject }.not_to change(AlertManagement::Alert, :count) + it_behaves_like 'creates an alert management alert' + it_behaves_like 'assigns the alert properties' end - it 'increments the existing alert count' do - expect { subject }.to change { existing_alert.reload.events }.from(1).to(2) + context 'existing alert is ignored' do + let!(:alert) { create(:alert_management_alert, :ignored, project: project, fingerprint: fingerprint_sha) } + + it_behaves_like 'adds an alert management alert event' end - it 'does not executes the alert service hooks' do - subject + context 'two existing alerts, one resolved one open' do + let!(:resolved_existing_alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: fingerprint_sha) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } - expect(ProjectServiceWorker).not_to have_received(:perform_async) + it_behaves_like 'adds an alert management alert event' end end @@ -174,9 +170,7 @@ RSpec.describe Projects::Alerting::NotifyService do } end - it 'creates AlertManagement::Alert' do - expect { subject }.to change(AlertManagement::Alert, :count).by(1) - end + it_behaves_like 'creates an alert management alert' it 'created alert has all data properly assigned' do subject @@ -218,19 +212,19 @@ RSpec.describe Projects::Alerting::NotifyService do end it_behaves_like 'does not process incident issues due to error', http_status: :bad_request - it_behaves_like 'NotifyService does not create alert' + it_behaves_like 'does not an create alert management alert' end context 'when alert already exists' do let(:fingerprint_sha) { Digest::SHA1.hexdigest(fingerprint) } - let!(:existing_alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } context 'when existing alert does not have an associated issue' do it_behaves_like 'processes incident issues' end context 'when existing alert has an associated issue' do - let!(:existing_alert) { create(:alert_management_alert, :with_issue, project: project, fingerprint: fingerprint_sha) } + let!(:alert) { create(:alert_management_alert, :with_issue, project: project, fingerprint: fingerprint_sha) } it_behaves_like 'does not process incident issues' end @@ -246,14 +240,14 @@ RSpec.describe Projects::Alerting::NotifyService do context 'with invalid token' do it_behaves_like 'does not process incident issues due to error', http_status: :unauthorized - it_behaves_like 'NotifyService does not create alert' + it_behaves_like 'does not an create alert management alert' end context 'with deactivated Alerts Service' do let!(:alerts_service) { create(:alerts_service, :inactive, project: project) } it_behaves_like 'does not process incident issues due to error', http_status: :forbidden - it_behaves_like 'NotifyService does not create alert' + it_behaves_like 'does not an create alert management alert' end end end diff --git a/spec/support/shared_examples/services/alert_management_shared_examples.rb b/spec/support/shared_examples/services/alert_management_shared_examples.rb new file mode 100644 index 00000000000..a1354a8099b --- /dev/null +++ b/spec/support/shared_examples/services/alert_management_shared_examples.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'creates an alert management alert' do + it { is_expected.to be_success } + + it 'creates AlertManagement::Alert' do + expect { subject }.to change(AlertManagement::Alert, :count).by(1) + end + + it 'executes the alert service hooks' do + slack_service = create(:service, type: 'SlackService', project: project, alert_events: true, active: true) + + subject + + expect(ProjectServiceWorker).to have_received(:perform_async).with(slack_service.id, an_instance_of(Hash)) + end +end + +RSpec.shared_examples 'does not an create alert management alert' do + it 'does not create alert' do + expect { subject }.not_to change(AlertManagement::Alert, :count) + end +end + +RSpec.shared_examples 'adds an alert management alert event' do + it { is_expected.to be_success } + + it 'does not create an alert' do + expect { subject }.not_to change(AlertManagement::Alert, :count) + end + + it 'increases alert events count' do + expect { subject }.to change { alert.reload.events }.by(1) + end + + it 'does not executes the alert service hooks' do + expect(alert).not_to receive(:execute_services) + + subject + end +end |