Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d9aac35d79
commit
0698388e65
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class GroupVariableEntity < Ci::BasicVariableEntity
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class GroupVariableSerializer < BaseSerializer
|
||||
entity ::Ci::GroupVariableEntity
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class VariableEntity < Ci::BasicVariableEntity
|
||||
expose :environment_scope
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class VariableSerializer < BaseSerializer
|
||||
entity ::Ci::VariableEntity
|
||||
end
|
||||
end
|
|
@ -1,4 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class GroupVariableEntity < Ci::BasicVariableEntity
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class GroupVariableSerializer < BaseSerializer
|
||||
entity GroupVariableEntity
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class VariableEntity < Ci::BasicVariableEntity
|
||||
expose :environment_scope
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class VariableSerializer < BaseSerializer
|
||||
entity VariableEntity
|
||||
end
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Support fenced code blocks in Atlassian Document Format converter
|
||||
merge_request: 35065
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Open new alert when existing alert is resolved
|
||||
merge_request: 36261
|
||||
author:
|
||||
type: added
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -21,6 +21,7 @@ exceptions:
|
|||
- CLI
|
||||
- CNAME
|
||||
- CPU
|
||||
- CORE
|
||||
- CSS
|
||||
- CSV
|
||||
- DNS
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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` |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:**
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -14,6 +14,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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,17 +1,38 @@
|
|||
export function makeIssue({ parentIssue, project, users }) {
|
||||
```javascript
|
||||
export function makeIssue({ parentIssue, project, users }) {
|
||||
|
||||
const issueType = pickRandom(project.issueTypes)
|
||||
const issueType = pickRandom(project.issueTypes)
|
||||
|
||||
console.log(data)
|
||||
console.log(data)
|
||||
|
||||
return data
|
||||
}
|
||||
```
|
||||
|
||||
<!-- -->
|
||||
|
||||
```css
|
||||
.overflow { overflow: hidden; }
|
||||
```
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
* 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
|
||||
```
|
||||
|
||||
|
|
|
@ -165,37 +165,40 @@ Col 3 Row 3
|
|||
|
||||
<del>Strikethrough</del>
|
||||
|
||||
export function makeIssue({ parentIssue, project, users }) {
|
||||
```javascript
|
||||
export function makeIssue({ parentIssue, project, users }) {
|
||||
|
||||
const issueType = pickRandom(project.issueTypes)
|
||||
const issueType = pickRandom(project.issueTypes)
|
||||
|
||||
let data = {
|
||||
fields: {
|
||||
summary: faker.lorem.sentence(),
|
||||
issuetype: {
|
||||
id: issueType.id
|
||||
},
|
||||
project: {
|
||||
id: project.id
|
||||
},
|
||||
reporter: {
|
||||
id: pickRandom(users)
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(data)
|
||||
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
if (issueType.subtask) {
|
||||
data = {
|
||||
parent: {
|
||||
key: parentIssue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(data)
|
||||
|
||||
return data
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
![jira-10050-field-description](adf-media://79411c6b-50e0-477f-b4ed-ac3a5887750c)
|
||||
|
||||
|
|
|
@ -146,6 +146,25 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "orderedList",
|
||||
"content": [
|
||||
{
|
||||
"type": "listItem",
|
||||
"content": [
|
||||
{
|
||||
"type": "paragraph",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Another list"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -17,4 +17,9 @@
|
|||
9. Number list item 9
|
||||
|
||||
10. Number list item 10
|
||||
<!-- -->
|
||||
|
||||
1. Another list
|
||||
|
||||
<!-- -->
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) }
|
||||
|
|
@ -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) }
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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 'does not create AlertManagement::Alert' do
|
||||
expect { subject }.not_to change(AlertManagement::Alert, :count)
|
||||
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_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
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue