Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c16b752f86
commit
39c98649d2
|
@ -143,25 +143,6 @@ Performance/ConstantRegexp:
|
|||
Performance/MethodObjectAsBlock:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 18
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AutoCorrect.
|
||||
Performance/StringInclude:
|
||||
Exclude:
|
||||
- 'app/models/snippet_repository.rb'
|
||||
- 'config/initializers/macos.rb'
|
||||
- 'config/spring.rb'
|
||||
- 'ee/app/models/ee/container_registry/event.rb'
|
||||
- 'ee/lib/gitlab/auth/smartcard/certificate.rb'
|
||||
- 'lib/gitlab/database/migration_helpers.rb'
|
||||
- 'lib/kramdown/parser/atlassian_document_format.rb'
|
||||
- 'lib/prometheus/pid_provider.rb'
|
||||
- 'qa/qa/ee/page/merge_request/show.rb'
|
||||
- 'qa/qa/specs/runner.rb'
|
||||
- 'spec/features/projects/jobs_spec.rb'
|
||||
- 'spec/spec_helper.rb'
|
||||
- 'spec/support_specs/helpers/active_record/query_recorder_spec.rb'
|
||||
|
||||
# Offense count: 15209
|
||||
# Configuration parameters: Prefixes.
|
||||
# Prefixes: when, with, without
|
||||
|
@ -282,11 +263,6 @@ Rails/HelperInstanceVariable:
|
|||
Rails/IndexWith:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 1
|
||||
Rails/Inquiry:
|
||||
Exclude:
|
||||
- 'spec/helpers/labels_helper_spec.rb'
|
||||
|
||||
# Offense count: 118
|
||||
# Configuration parameters: Include.
|
||||
# Include: app/models/**/*.rb
|
||||
|
@ -335,11 +311,6 @@ Rails/RakeEnvironment:
|
|||
Rails/RedundantForeignKey:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 1
|
||||
Rails/RenderInline:
|
||||
Exclude:
|
||||
- 'ee/app/controllers/sitemap_controller.rb'
|
||||
|
||||
# Offense count: 1144
|
||||
# Configuration parameters: ForbiddenMethods, AllowedMethods.
|
||||
# ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
# Cop supports --auto-correct.
|
||||
Performance/StringInclude:
|
||||
Exclude:
|
||||
- 'app/models/snippet_repository.rb'
|
||||
- 'config/initializers/macos.rb'
|
||||
- 'config/spring.rb'
|
||||
- 'ee/app/models/ee/container_registry/event.rb'
|
||||
- 'ee/lib/gitlab/auth/smartcard/certificate.rb'
|
||||
- 'lib/gitlab/database/migration_helpers.rb'
|
||||
- 'lib/kramdown/parser/atlassian_document_format.rb'
|
||||
- 'lib/prometheus/pid_provider.rb'
|
||||
- 'qa/qa/specs/runner.rb'
|
||||
- 'spec/features/projects/jobs_spec.rb'
|
||||
- 'spec/spec_helper.rb'
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Rails/Inquiry:
|
||||
Exclude:
|
||||
- 'spec/helpers/labels_helper_spec.rb'
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Rails/RenderInline:
|
||||
Exclude:
|
||||
- 'ee/app/controllers/sitemap_controller.rb'
|
|
@ -1 +0,0 @@
|
|||
<svg width="16" height="17" xmlns="http://www.w3.org/2000/svg"><path fill="#fffff" d="M1.53 7.639l-.476.88.476-.88zm0-1.758L1.054 5l.476.88zm2.257 2.982h1v-.596l-.523-.283-.477.879zm8.424 0l-.476-.88-.524.284v.596h1zm2.257-1.224l.477.88-.477-.88zm0-1.758l-.476.879.476-.88zM8.476 2.632l-.477.88.477-.88zm-.953 0l.476.88-.476-.88zM2.007 6.76l-.953-1.758c-1.396.756-1.396 2.76 0 3.516l.953-1.758zm2.257 1.224L2.007 6.76l-.953 1.758L3.31 9.742l.953-1.758zm.523 1.995V8.863h-2v1.116h2zM8 12.5c-1.949 0-3.212-1.289-3.212-2.52h-2c0 2.656 2.51 4.52 5.212 4.52v-2zm3.212-2.52c0 1.231-1.262 2.52-3.212 2.52v2c2.704 0 5.212-1.864 5.212-4.52h-2zm0-1.117v1.116h2V8.863h-2zm2.78-2.103l-2.256 1.223.953 1.759 2.257-1.224-.953-1.758zm0 0l.954 1.758c1.396-.757 1.396-2.76 0-3.516l-.953 1.758zM8 3.51l5.993 3.249.953-1.758-5.993-3.249L8 3.511zm0 0l.953-1.758a2 2 0 00-1.906 0L8 3.511zM2.007 6.76l5.992-3.25-.953-1.758-5.992 3.249.953 1.758z"/><path fill="#fffff" d="M7.228 7.541c-.187-.112-.277-.427-.201-.704.076-.276.288-.41.475-.297L11 8.644v5.316c0 .298-.163.54-.365.54-.2 0-.364-.242-.364-.54V9.37L7.228 7.54z"/></svg>
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -3,6 +3,7 @@ import {
|
|||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownDivider,
|
||||
GlDropdownText,
|
||||
GlSearchBoxByType,
|
||||
GlSprintf,
|
||||
} from '@gitlab/ui';
|
||||
|
@ -15,6 +16,7 @@ export default {
|
|||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownDivider,
|
||||
GlDropdownText,
|
||||
GlSearchBoxByType,
|
||||
GlSprintf,
|
||||
},
|
||||
|
@ -73,13 +75,24 @@ export default {
|
|||
this.clearSearch();
|
||||
this.focusSearch();
|
||||
},
|
||||
onKeyEnter() {
|
||||
if (!this.searchTerm?.length) {
|
||||
return;
|
||||
}
|
||||
this.$refs.dropdown.hide();
|
||||
this.selectAgent(this.searchTerm);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-dropdown :text="dropdownText" :loading="isRegistering" @shown="handleShow">
|
||||
<gl-dropdown ref="dropdown" :text="dropdownText" :loading="isRegistering" @shown="handleShow">
|
||||
<template #header>
|
||||
<gl-search-box-by-type ref="searchInput" v-model.trim="searchTerm" />
|
||||
<gl-search-box-by-type
|
||||
ref="searchInput"
|
||||
v-model.trim="searchTerm"
|
||||
@keydown.enter.stop.prevent="onKeyEnter"
|
||||
/>
|
||||
</template>
|
||||
<gl-dropdown-item
|
||||
v-for="agent in filteredResults"
|
||||
|
@ -90,9 +103,9 @@ export default {
|
|||
>
|
||||
{{ agent }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item v-if="!filteredResults.length" ref="noMatchingResults">{{
|
||||
<gl-dropdown-text v-if="!filteredResults.length" ref="noMatchingResults">{{
|
||||
$options.i18n.noResults
|
||||
}}</gl-dropdown-item>
|
||||
}}</gl-dropdown-text>
|
||||
<template v-if="shouldRenderCreateButton">
|
||||
<gl-dropdown-divider />
|
||||
<gl-dropdown-item data-testid="create-config-button" @click="selectAgent(searchTerm)">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlButton, GlTable } from '@gitlab/ui';
|
||||
import { GlButton, GlTableLite } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
const DEFAULT_TD_CLASSES = 'gl-w-half gl-font-sm! gl-border-gray-200!';
|
||||
|
@ -25,7 +25,7 @@ export default {
|
|||
],
|
||||
components: {
|
||||
GlButton,
|
||||
GlTable,
|
||||
GlTableLite,
|
||||
},
|
||||
props: {
|
||||
trigger: {
|
||||
|
@ -84,7 +84,7 @@ export default {
|
|||
>
|
||||
</p>
|
||||
|
||||
<gl-table :items="trigger.variables" :fields="$options.fields" small bordered fixed>
|
||||
<gl-table-lite :items="trigger.variables" :fields="$options.fields" small bordered fixed>
|
||||
<template #cell(key)="{ item }">
|
||||
<span class="gl-overflow-break-word">{{ item.key }}</span>
|
||||
</template>
|
||||
|
@ -92,7 +92,7 @@ export default {
|
|||
<template #cell(value)="data">
|
||||
<span class="gl-overflow-break-word">{{ getDisplayValue(data.value) }}</span>
|
||||
</template>
|
||||
</gl-table>
|
||||
</gl-table-lite>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
@import '../highlight/hljs';
|
||||
|
||||
.file-content.code {
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
.code.highlight {
|
||||
.hljs-comment {
|
||||
color: var(--color-hljs-comment);
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
color: var(--color-hljs-link);
|
||||
}
|
||||
|
||||
.hljs-meta {
|
||||
color: var(--color-hljs-meta);
|
||||
}
|
||||
|
||||
.hljs-keyword {
|
||||
color: var(--color-hljs-keyword);
|
||||
}
|
||||
|
||||
.hljs-type {
|
||||
color: var(--color-hljs-type);
|
||||
}
|
||||
|
||||
.hljs-attr,
|
||||
.hljs-property {
|
||||
color: var(--color-hljs-attr);
|
||||
}
|
||||
|
||||
.hljs-built_in {
|
||||
color: var(--color-hljs-builtin);
|
||||
}
|
||||
|
||||
.hljs-literal {
|
||||
color: var(--color-hljs-literal);
|
||||
}
|
||||
|
||||
.hljs-title {
|
||||
color: var(--color-hljs-title);
|
||||
|
||||
&.class_ {
|
||||
color: var(--color-hljs-class);
|
||||
}
|
||||
|
||||
&.function_ {
|
||||
color: var(--color-hljs-function);
|
||||
}
|
||||
}
|
||||
|
||||
.hljs-tag ,
|
||||
.hljs-name {
|
||||
color: var(--color-hljs-tag);
|
||||
}
|
||||
|
||||
.hljs-number {
|
||||
color: var(--color-hljs-number);
|
||||
}
|
||||
|
||||
.hljs-subst {
|
||||
color: var(--color-hljs-subst);
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-section,
|
||||
.hljs-bullet {
|
||||
color: var(--color-hljs-string);
|
||||
}
|
||||
|
||||
.hljs-symbol {
|
||||
color: var(--color-hljs-symbol);
|
||||
}
|
||||
|
||||
.hljs-variable {
|
||||
color: var(--color-hljs-variable);
|
||||
|
||||
&.language_ {
|
||||
color: var(--color-hljs-language);
|
||||
}
|
||||
|
||||
&.constant_ {
|
||||
color: var(--color-hljs-constant);
|
||||
}
|
||||
}
|
||||
|
||||
.hljs-attribute {
|
||||
color: var(--color-hljs-attribute);
|
||||
}
|
||||
|
||||
.hljs-operator {
|
||||
color: var(--color-hljs-operator);
|
||||
}
|
||||
|
||||
.hljs-punctuation {
|
||||
color: var(--color-hljs-punctuation);
|
||||
}
|
||||
|
||||
.hljs-regexp {
|
||||
color: var(--color-hljs-regexp);
|
||||
}
|
||||
|
||||
.hljs-params {
|
||||
color: var(--color-hljs-params);
|
||||
}
|
||||
|
||||
.hljs-doctag {
|
||||
color: var(--color-hljs-doctag);
|
||||
}
|
||||
|
||||
.hljs-selector-tag {
|
||||
color: var(--color-hljs-selector-tag);
|
||||
}
|
||||
|
||||
.hljs-selector-class {
|
||||
color: var(--color-hljs-selector-class);
|
||||
}
|
||||
|
||||
.hljs-selector-id {
|
||||
color: var(--color-hljs-selector-id);
|
||||
}
|
||||
|
||||
.hljs-selector-attr {
|
||||
color: var(--color-hljs-selector-attr);
|
||||
}
|
||||
|
||||
.hljs-selector-pseudo {
|
||||
color: var(--color-hljs-selector-pseudo);
|
||||
}
|
||||
}
|
|
@ -88,6 +88,39 @@ $dark-vg: #c66;
|
|||
$dark-vi: #c66;
|
||||
$dark-il: #de935f;
|
||||
|
||||
:root {
|
||||
--color-hljs-comment: #{$dark-c};
|
||||
--color-hljs-variable: #{$dark-k};
|
||||
--color-hljs-link: #{$dark-l};
|
||||
--color-hljs-meta: #{$dark-cp};
|
||||
--color-hljs-keyword: #{$dark-kd};
|
||||
--color-hljs-type: #{$dark-kt};
|
||||
--color-hljs-attr: #{$dark-na};
|
||||
--color-hljs-builtin: #{$dark-nb};
|
||||
--color-hljs-title: #{$dark-n};
|
||||
--color-hljs-class: #{$dark-nc};
|
||||
--color-hljs-function: #{$dark-nf};
|
||||
--color-hljs-tag: #{$dark-nt};
|
||||
--color-hljs-number: #{$dark-mi};
|
||||
--color-hljs-subst: #{$dark-sc};
|
||||
--color-hljs-string: #{$dark-s1};
|
||||
--color-hljs-symbol: #{$dark-ss};
|
||||
--color-hljs-variable: #{$dark-vi};
|
||||
--color-hljs-operator: #{$dark-o};
|
||||
--color-hljs-punctuation: #{$dark-p};
|
||||
--color-hljs-regexp: #{$dark-sr};
|
||||
--color-hljs-constant: #{$dark-nx};
|
||||
--color-hljs-literal: #{$dark-kc};
|
||||
--color-hljs-language: #{$dark-nx};
|
||||
--color-hljs-params: #{$dark-nx};
|
||||
--color-hljs-selector-doctag: #{$dark-cm};
|
||||
--color-hljs-selector-tag: #{$dark-nt};
|
||||
--color-hljs-selector-class: #{$dark-nc};
|
||||
--color-hljs-selector-id: #{$dark-nn};
|
||||
--color-hljs-selector-attr: #{$dark-nt};
|
||||
--color-hljs-selector-pseudo: #{$dark-nd};
|
||||
}
|
||||
|
||||
.code.dark {
|
||||
// Line numbers
|
||||
.file-line-num {
|
||||
|
|
|
@ -200,6 +200,18 @@ module Issuable
|
|||
incident?
|
||||
end
|
||||
|
||||
# When :incident_escalations feature flag is disabled, new
|
||||
# incidents should not have a status record unless the incident
|
||||
# is associated with the alert. However, escalation attributes
|
||||
# are synced with Alert/IssuableEscalationStatus, so we want to
|
||||
# ensure that parity is kept prior to rollout.
|
||||
# Remove with https://gitlab.com/gitlab-org/gitlab/-/issues/345769.
|
||||
def sync_escalation_attributes_from_alert?
|
||||
incident? &&
|
||||
::Feature.disabled?(:incident_escalations, project) &&
|
||||
alert_management_alert.present?
|
||||
end
|
||||
|
||||
def incident?
|
||||
is_a?(Issue) && super
|
||||
end
|
||||
|
|
|
@ -3,13 +3,16 @@
|
|||
class ProjectMemberPolicy < BasePolicy
|
||||
delegate { @subject.project }
|
||||
|
||||
condition(:target_is_owner, scope: :subject) { @subject.user == @subject.project.owner }
|
||||
condition(:target_is_holder_of_the_personal_namespace, scope: :subject) do
|
||||
@subject.project.personal_namespace_holder?(@subject.user)
|
||||
end
|
||||
|
||||
condition(:target_is_self) { @user && @subject.user == @user }
|
||||
condition(:project_bot) { @subject.user&.project_bot? }
|
||||
|
||||
rule { anonymous }.prevent_all
|
||||
|
||||
rule { target_is_owner }.policy do
|
||||
rule { target_is_holder_of_the_personal_namespace }.policy do
|
||||
prevent :update_project_member
|
||||
prevent :destroy_project_member
|
||||
end
|
||||
|
|
|
@ -151,14 +151,25 @@ module AlertManagement
|
|||
status_change_reason: " by changing the status of #{alert.to_reference(project)}"
|
||||
}
|
||||
}
|
||||
).execute(alert.issue)
|
||||
).execute(issue)
|
||||
end
|
||||
|
||||
def issue
|
||||
strong_memoize(:issue) { alert.issue }
|
||||
end
|
||||
|
||||
def should_sync_to_incident?
|
||||
alert.issue &&
|
||||
alert.issue.supports_escalation? &&
|
||||
alert.issue.escalation_status &&
|
||||
alert.issue.escalation_status.status != alert.status
|
||||
return false unless sync_available?
|
||||
|
||||
issue.escalation_status&.status != alert.status
|
||||
end
|
||||
|
||||
def sync_available?
|
||||
return false unless issue.present?
|
||||
|
||||
# Remove sync check with https://gitlab.com/gitlab-org/gitlab/-/issues/345769
|
||||
issue.supports_escalation? ||
|
||||
issue.sync_escalation_attributes_from_alert?
|
||||
end
|
||||
|
||||
def filter_duplicate
|
||||
|
|
|
@ -31,7 +31,10 @@ module IncidentManagement
|
|||
attr_reader :issuable, :param_errors
|
||||
|
||||
def available?
|
||||
issuable.supports_escalation? && user_has_permissions?
|
||||
(
|
||||
issuable.supports_escalation? ||
|
||||
issuable.sync_escalation_attributes_from_alert? # Remove with https://gitlab.com/gitlab-org/gitlab/-/issues/345769
|
||||
) && user_has_permissions?
|
||||
end
|
||||
|
||||
def user_has_permissions?
|
||||
|
@ -60,6 +63,14 @@ module IncidentManagement
|
|||
status = params.delete(:status)
|
||||
return unless status
|
||||
|
||||
# If we're updating the escalation status because the
|
||||
# alert was updated & the feature flag is disabled, then
|
||||
# we should not allow the status to be different from the alert's.
|
||||
# Remove with https://gitlab.com/gitlab-org/gitlab/-/issues/345769
|
||||
if issuable.sync_escalation_attributes_from_alert? && status != issuable.alert_management_alert.status_name
|
||||
add_param_error(:status) && return
|
||||
end
|
||||
|
||||
status_event = escalation_status.status_event_for(status)
|
||||
add_param_error(:status) && return unless status_event
|
||||
|
||||
|
|
|
@ -87,7 +87,10 @@ module Issues
|
|||
attr_reader :spam_params
|
||||
|
||||
def create_escalation_status(issue)
|
||||
::IncidentManagement::IssuableEscalationStatuses::CreateService.new(issue).execute if issue.supports_escalation?
|
||||
# Remove sync check with https://gitlab.com/gitlab-org/gitlab/-/issues/345769
|
||||
return unless issue.supports_escalation? || issue.sync_escalation_attributes_from_alert?
|
||||
|
||||
::IncidentManagement::IssuableEscalationStatuses::CreateService.new(issue).execute
|
||||
end
|
||||
|
||||
def user_agent_detail_service
|
||||
|
|
|
@ -167,7 +167,7 @@ options:
|
|||
- p_ci_templates_implicit_security_cluster_image_scanning
|
||||
- p_ci_templates_kaniko
|
||||
- p_ci_templates_qualys_iac_security
|
||||
- p_ci_templates_database_liquibase
|
||||
- p_ci_templates_liquibase
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_database_liquibase_monthly
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_liquibase_monthly
|
||||
description: ""
|
||||
product_section: ""
|
||||
product_stage: ""
|
||||
|
@ -22,4 +22,4 @@ tier:
|
|||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- p_ci_templates_database_liquibase
|
||||
- p_ci_templates_liquibase
|
||||
|
|
|
@ -167,7 +167,7 @@ options:
|
|||
- p_ci_templates_implicit_security_cluster_image_scanning
|
||||
- p_ci_templates_kaniko
|
||||
- p_ci_templates_qualys_iac_security
|
||||
- p_ci_templates_database_liquibase
|
||||
- p_ci_templates_liquibase
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_database_liquibase_weekly
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_liquibase_weekly
|
||||
description: ""
|
||||
product_section: ""
|
||||
product_stage: ""
|
||||
|
@ -22,4 +22,4 @@ tier:
|
|||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- p_ci_templates_database_liquibase
|
||||
- p_ci_templates_liquibase
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BackfillNamespaceStatisticsWithDependencyProxySize < Gitlab::Database::Migration[1.0]
|
||||
DELAY_INTERVAL = 2.minutes.to_i
|
||||
BATCH_SIZE = 500
|
||||
MIGRATION = 'PopulateNamespaceStatistics'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
groups = exec_query <<~SQL
|
||||
SELECT dependency_proxy_manifests.group_id FROM dependency_proxy_manifests
|
||||
UNION
|
||||
SELECT dependency_proxy_blobs.group_id from dependency_proxy_blobs
|
||||
SQL
|
||||
|
||||
groups.rows.flatten.in_groups_of(BATCH_SIZE, false).each_with_index do |group_ids, index|
|
||||
migrate_in(index * DELAY_INTERVAL, MIGRATION, [group_ids, [:dependency_proxy_size]])
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
bce595c1c6587e785bc49d6e5a7181b5cc0164f2201375ad82d4bd19c217cd35
|
|
@ -77,7 +77,7 @@ If a test failed in the project's default branch in the last 14 days, a message
|
|||
|
||||
To enable the Unit test reports in merge requests, you must add
|
||||
[`artifacts:reports:junit`](yaml/artifacts_reports.md#artifactsreportsjunit)
|
||||
in `.gitlab-ci.yml`, and specify the path(s) of the generated test reports.
|
||||
in `.gitlab-ci.yml`, and specify the paths of the generated test reports.
|
||||
The reports must be `.xml` files, otherwise [GitLab returns an Error 500](https://gitlab.com/gitlab-org/gitlab/-/issues/216575).
|
||||
|
||||
In the following examples, the job in the `test` stage runs and GitLab
|
||||
|
|
|
@ -365,6 +365,35 @@ file for the [`gitlab`](https://gitlab.com/gitlab-org/gitlab) project.
|
|||
To set up `lefthook` for documentation linting, see
|
||||
[Pre-push static analysis](../contributing/style_guides.md#pre-push-static-analysis-with-lefthook).
|
||||
|
||||
#### Show Vale warnings on push
|
||||
|
||||
By default, `lefthook` shows only Vale errors when pushing changes to a branch. The default branches
|
||||
have no Vale errors, so any errors listed here are introduced by commits to the branch.
|
||||
|
||||
To also see the Vale warnings when pushing to a branch, set a local environment variable: `VALE_WARNINGS=true`.
|
||||
|
||||
Enable Vale warnings on push to improve the documentation suite by:
|
||||
|
||||
- Detecting warnings you might be introducing with your commits.
|
||||
- Identifying warnings that already exist in the page, which you can resolve to reduce technical debt.
|
||||
|
||||
These warnings:
|
||||
|
||||
- Don't stop the push from working.
|
||||
- Don't result in a broken pipeline.
|
||||
- Include all warnings for a file, not just warnings that are introduced by the commits.
|
||||
|
||||
To enable Vale warnings on push:
|
||||
|
||||
- Automatically, add `VALE_WARNINGS=true` to your shell configuration.
|
||||
- Manually, prepend `VALE_WARNINGS=true` to invocations of `lefthook`. For example:
|
||||
|
||||
```shell
|
||||
VALE_WARNINGS=true bundle exec lefthook run pre-push
|
||||
```
|
||||
|
||||
You can also [configure your editor](#configure-editors) to show Vale warnings.
|
||||
|
||||
### Show subset of Vale alerts
|
||||
|
||||
You can set Visual Studio Code to display only a subset of Vale alerts when viewing files:
|
||||
|
|
26
doc/index.md
26
doc/index.md
|
@ -32,7 +32,7 @@ No matter how you use GitLab, we have documentation for you.
|
|||
| Essential documentation | Essential documentation |
|
||||
|:------------------------|:------------------------|
|
||||
| [**User documentation**](user/index.md)<br>Discover features and concepts for GitLab users. | [**Administrator documentation**](administration/index.md)<br/>Everything GitLab self-managed administrators need to know. |
|
||||
| [**Contributing to GitLab**](#contributing-to-gitlab)<br/>At GitLab, everyone can contribute! | [**New to Git and GitLab?**](#new-to-git-and-gitlab)<br/>We have the resources to get you started. |
|
||||
| [**Contributing to GitLab**](#contributing-to-gitlab)<br/>At GitLab, everyone can contribute! | [**New to Git and GitLab?**](tutorials/index.md)<br/>We have the resources to get you started. |
|
||||
| [**Build an integration with GitLab**](#build-an-integration-with-gitlab)<br/>Consult our integration documentation. | [**Coming to GitLab from another platform?**](#coming-to-gitlab-from-another-platform)<br/>Consult our guides. |
|
||||
| [**Install GitLab**](https://about.gitlab.com/install/)<br/>Installation options for different platforms. | [**Customers**](subscriptions/index.md)<br/>Information for new and existing customers. |
|
||||
| [**Update GitLab**](update/index.md)<br/>Update your GitLab self-managed instance to the latest version. | [**Reference Architectures**](administration/reference_architectures/index.md)<br/>GitLab reference architectures. |
|
||||
|
@ -64,20 +64,6 @@ GitLab makes the software lifecycle faster and radically improves the speed of b
|
|||
|
||||
GitLab provides solutions for [each of the stages of the DevOps lifecycle](https://about.gitlab.com/stages-devops-lifecycle/).
|
||||
|
||||
## New to Git and GitLab?
|
||||
|
||||
Working with new systems can be daunting.
|
||||
|
||||
We have the following documentation to rapidly uplift your GitLab knowledge:
|
||||
|
||||
| Topic | Description |
|
||||
|:--------------------------------------------------------------------------------------------------|:------------|
|
||||
| [GitLab basics guides](gitlab-basics/index.md) | Start working on the command line and with GitLab. |
|
||||
| [What is GitLab Flow?](https://about.gitlab.com/topics/version-control/what-is-gitlab-flow/) | Enhance your workflow with the best of GitLab Flow. |
|
||||
| [Get started with GitLab CI/CD](ci/quick_start/index.md) | Quickly implement GitLab CI/CD. |
|
||||
| [Auto DevOps](topics/autodevops/index.md) | Learn more about Auto DevOps in GitLab. |
|
||||
| [GitLab Markdown](user/markdown.md) | Advanced formatting system (GitLab Flavored Markdown). |
|
||||
|
||||
### User account
|
||||
|
||||
Learn more about GitLab account management:
|
||||
|
@ -89,16 +75,6 @@ Learn more about GitLab account management:
|
|||
| [User settings](user/profile/index.md#access-your-user-settings) | Manage your user settings, two factor authentication, and more. |
|
||||
| [User permissions](user/permissions.md) | Learn what each role in a project can do. |
|
||||
|
||||
### Git and GitLab
|
||||
|
||||
Learn more about using Git, and using Git with GitLab:
|
||||
|
||||
| Topic | Description |
|
||||
|:-----------------------------------------------------------------------------|:------------|
|
||||
| [Git](topics/git/index.md) | Getting started with Git, branching strategies, Git LFS, and advanced use. |
|
||||
| [Git cheat sheet](https://about.gitlab.com/images/press/git-cheat-sheet.pdf) | Download a PDF describing the most used Git operations. |
|
||||
| [GitLab Flow](topics/gitlab_flow.md) | Explore the best of Git with the GitLab Flow strategy. |
|
||||
|
||||
## Coming to GitLab from another platform
|
||||
|
||||
If you are coming to GitLab from another platform, the following information is useful:
|
||||
|
|
|
@ -42,7 +42,7 @@ pre-push:
|
|||
tags: documentation style
|
||||
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
|
||||
glob: 'doc/*.md'
|
||||
run: 'if command -v vale > /dev/null 2>&1; then if ! vale --config .vale.ini --minAlertLevel error {files}; then echo "ERROR: Fix any linting errors and make sure you are using the latest version of Vale."; exit 1; fi; else echo "ERROR: Vale not found. For more information, see https://docs.errata.ai/vale/install."; exit 1; fi'
|
||||
run: 'if [ $VALE_WARNINGS ]; then minWarnings=warning; else minWarnings=error; fi; if command -v vale > /dev/null 2>&1; then if ! vale --config .vale.ini --minAlertLevel $minWarnings {files}; then echo "ERROR: Fix any linting errors and make sure you are using the latest version of Vale."; exit 1; fi; else echo "ERROR: Vale not found. For more information, see https://docs.errata.ai/vale/install."; exit 1; fi'
|
||||
gettext:
|
||||
skip: true # This is disabled by default. You can enable this check by adding skip: false in lefhook-local.yml https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md#skipping-commands
|
||||
tags: backend frontend view haml
|
||||
|
|
|
@ -5,9 +5,40 @@ module Gitlab
|
|||
# This class creates/updates those namespace statistics
|
||||
# that haven't been created nor initialized.
|
||||
# It also updates the related namespace statistics
|
||||
# This is only required in EE
|
||||
class PopulateNamespaceStatistics
|
||||
def perform(group_ids, statistics)
|
||||
# Updating group statistics might involve calling Gitaly.
|
||||
# For example, when calculating `wiki_size`, we will need
|
||||
# to perform the request to check if the repo exists and
|
||||
# also the repository size.
|
||||
#
|
||||
# The `allow_n_plus_1_calls` method is only intended for
|
||||
# dev and test. It won't be raised in prod.
|
||||
::Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
relation(group_ids).each do |group|
|
||||
upsert_namespace_statistics(group, statistics)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def upsert_namespace_statistics(group, statistics)
|
||||
response = ::Groups::UpdateStatisticsService.new(group, statistics: statistics).execute
|
||||
|
||||
error_message("#{response.message} group: #{group.id}") if response.error?
|
||||
end
|
||||
|
||||
def logger
|
||||
@logger ||= ::Gitlab::BackgroundMigration::Logger.build
|
||||
end
|
||||
|
||||
def error_message(message)
|
||||
logger.error(message: "Namespace Statistics Migration: #{message}")
|
||||
end
|
||||
|
||||
def relation(group_ids)
|
||||
Group.includes(:namespace_statistics).where(id: group_ids)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,21 +5,6 @@
|
|||
|
||||
image: golang:latest
|
||||
|
||||
variables:
|
||||
# Please edit to your GitLab project
|
||||
REPO_NAME: gitlab.com/namespace/project
|
||||
|
||||
# The problem is that to be able to use go get, one needs to put
|
||||
# the repository in the $GOPATH. So for example if your gitlab domain
|
||||
# is gitlab.com, and that your repository is namespace/project, and
|
||||
# the default GOPATH being /go, then you'd need to have your
|
||||
# repository in /go/src/gitlab.com/namespace/project
|
||||
# Thus, making a symbolic link corrects this.
|
||||
before_script:
|
||||
- mkdir -p "$GOPATH/src/$(dirname $REPO_NAME)"
|
||||
- ln -svf "$CI_PROJECT_DIR" "$GOPATH/src/$REPO_NAME"
|
||||
- cd "$GOPATH/src/$REPO_NAME"
|
||||
|
||||
stages:
|
||||
- test
|
||||
- build
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
# To contribute improvements to CI/CD templates, please follow the Development guide at:
|
||||
# https://docs.gitlab.com/ee/development/cicd/templates.html
|
||||
# This specific template is located at:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Database/liquibase.gitlab-ci.yml
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/liquibase.gitlab-ci.yml
|
||||
|
||||
# This template must be configured with CI/CD variables before it will work.
|
||||
# See https://www.liquibase.com/blog/secure-database-developer-flow-using-gitlab-pipelines
|
||||
# to learn how to configure the Liquibase template by using variables.
|
||||
# Be sure to add the variables before running pipelines with this template.
|
||||
# You may not want to run all the jobs in this template. You can comment out or delete the jobs you don't wish to use.
|
||||
# You may not want to run all the jobs in this template. You can comment out or delete the jobs you don't wish to use.
|
||||
|
||||
# List of stages for jobs and their order of execution.
|
||||
stages:
|
||||
|
@ -132,7 +132,7 @@ TEST->PROD:
|
|||
expire_in: 1 week
|
||||
|
||||
|
||||
# This job creates a snapshot of prod database. You can use the snapshot file to run comparisons with the production database to investigate for any potential issues. https://www.liquibase.com/devsecops
|
||||
# This job creates a snapshot of prod database. You can use the snapshot file to run comparisons with the production database to investigate for any potential issues. https://www.liquibase.com/devsecops
|
||||
snapshot PROD:
|
||||
image: liquibase/liquibase:latest # Using the Liquibase Docker Image
|
||||
stage: .post
|
|
@ -12,6 +12,11 @@ module Gitlab
|
|||
Gitlab::UrlBuilder.build(deployment.deployable)
|
||||
end
|
||||
|
||||
commit_url =
|
||||
if (commit = deployment.commit)
|
||||
Gitlab::UrlBuilder.build(commit)
|
||||
end
|
||||
|
||||
{
|
||||
object_kind: 'deployment',
|
||||
status: deployment.status,
|
||||
|
@ -24,8 +29,8 @@ module Gitlab
|
|||
short_sha: deployment.short_sha,
|
||||
user: deployment.deployed_by.hook_attrs,
|
||||
user_url: Gitlab::UrlBuilder.build(deployment.deployed_by),
|
||||
commit_url: Gitlab::UrlBuilder.build(deployment.commit),
|
||||
commit_title: deployment.commit.title,
|
||||
commit_url: commit_url,
|
||||
commit_title: deployment.commit&.title,
|
||||
ref: deployment.ref
|
||||
}
|
||||
end
|
||||
|
|
|
@ -615,7 +615,7 @@
|
|||
category: ci_templates
|
||||
redis_slot: ci_templates
|
||||
aggregation: weekly
|
||||
- name: p_ci_templates_database_liquibase
|
||||
- name: p_ci_templates_liquibase
|
||||
category: ci_templates
|
||||
redis_slot: ci_templates
|
||||
aggregation: weekly
|
||||
|
|
|
@ -45,9 +45,9 @@ module Sidebars
|
|||
}
|
||||
end
|
||||
|
||||
override :image_path
|
||||
def image_path
|
||||
'learn_gitlab/graduation_hat.svg'
|
||||
override :sprite_icon
|
||||
def sprite_icon
|
||||
'bulb'
|
||||
end
|
||||
|
||||
override :render?
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { ENTER_KEY } from '~/lib/utils/keys';
|
||||
import AvailableAgentsDropdown from '~/clusters_list/components/available_agents_dropdown.vue';
|
||||
import { I18N_AVAILABLE_AGENTS_DROPDOWN } from '~/clusters_list/constants';
|
||||
|
||||
|
@ -18,6 +19,7 @@ describe('AvailableAgentsDropdown', () => {
|
|||
propsData,
|
||||
stubs: { GlDropdown },
|
||||
});
|
||||
wrapper.vm.$refs.dropdown.hide = jest.fn();
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -96,6 +98,25 @@ describe('AvailableAgentsDropdown', () => {
|
|||
expect(findDropdown().props('text')).toBe('new-agent');
|
||||
});
|
||||
});
|
||||
|
||||
describe('click enter to register new agent without configuration', () => {
|
||||
beforeEach(async () => {
|
||||
await findSearchInput().vm.$emit('input', 'new-agent');
|
||||
await findSearchInput().vm.$emit('keydown', new KeyboardEvent({ key: ENTER_KEY }));
|
||||
});
|
||||
|
||||
it('emits agentSelected with the name of the clicked agent', () => {
|
||||
expect(wrapper.emitted('agentSelected')).toEqual([['new-agent']]);
|
||||
});
|
||||
|
||||
it('marks the clicked item as selected', () => {
|
||||
expect(findDropdown().props('text')).toBe('new-agent');
|
||||
});
|
||||
|
||||
it('closes the dropdown', () => {
|
||||
expect(wrapper.vm.$refs.dropdown.hide).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('registration in progress', () => {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { GlButton, GlTable } from '@gitlab/ui';
|
||||
import { GlButton, GlTableLite } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import TriggerBlock from '~/jobs/components/trigger_block.vue';
|
||||
|
||||
describe('Trigger block', () => {
|
||||
let wrapper;
|
||||
|
||||
const findRevealButton = () => wrapper.find(GlButton);
|
||||
const findVariableTable = () => wrapper.find(GlTable);
|
||||
const findRevealButton = () => wrapper.findComponent(GlButton);
|
||||
const findVariableTable = () => wrapper.findComponent(GlTableLite);
|
||||
const findShortToken = () => wrapper.find('[data-testid="trigger-short-token"]');
|
||||
const findVariableValue = (index) =>
|
||||
wrapper.findAll('[data-testid="trigger-build-value"]').at(index);
|
||||
|
@ -22,7 +22,6 @@ describe('Trigger block', () => {
|
|||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
describe('with short token and no variables', () => {
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BackgroundMigration::PopulateNamespaceStatistics do
|
||||
let_it_be(:namespaces) { table(:namespaces) }
|
||||
let_it_be(:namespace_statistics) { table(:namespace_statistics) }
|
||||
let_it_be(:dependency_proxy_manifests) { table(:dependency_proxy_manifests) }
|
||||
let_it_be(:dependency_proxy_blobs) { table(:dependency_proxy_blobs) }
|
||||
|
||||
let!(:group1) { namespaces.create!(id: 10, type: 'Group', name: 'group1', path: 'group1') }
|
||||
let!(:group2) { namespaces.create!(id: 20, type: 'Group', name: 'group2', path: 'group2') }
|
||||
|
||||
let!(:group1_manifest) do
|
||||
dependency_proxy_manifests.create!(group_id: 10, size: 20, file_name: 'test-file', file: 'test', digest: 'abc123')
|
||||
end
|
||||
|
||||
let!(:group2_manifest) do
|
||||
dependency_proxy_manifests.create!(group_id: 20, size: 20, file_name: 'test-file', file: 'test', digest: 'abc123')
|
||||
end
|
||||
|
||||
let!(:group1_stats) { namespace_statistics.create!(id: 10, namespace_id: 10) }
|
||||
|
||||
let(:ids) { namespaces.pluck(:id) }
|
||||
let(:statistics) { [] }
|
||||
|
||||
subject(:perform) { described_class.new.perform(ids, statistics) }
|
||||
|
||||
it 'creates/updates all namespace_statistics and updates root storage statistics', :aggregate_failures do
|
||||
expect(Namespaces::ScheduleAggregationWorker).to receive(:perform_async).with(group1.id)
|
||||
expect(Namespaces::ScheduleAggregationWorker).to receive(:perform_async).with(group2.id)
|
||||
|
||||
expect { perform }.to change(namespace_statistics, :count).from(1).to(2)
|
||||
|
||||
namespace_statistics.all.each do |stat|
|
||||
expect(stat.dependency_proxy_size).to eq 20
|
||||
expect(stat.storage_size).to eq 20
|
||||
end
|
||||
end
|
||||
|
||||
context 'when just a stat is passed' do
|
||||
let(:statistics) { [:dependency_proxy_size] }
|
||||
|
||||
it 'calls the statistics update service with just that stat' do
|
||||
expect(Groups::UpdateStatisticsService)
|
||||
.to receive(:new)
|
||||
.with(anything, statistics: [:dependency_proxy_size])
|
||||
.twice.and_call_original
|
||||
|
||||
perform
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a statistics update fails' do
|
||||
before do
|
||||
error_response = instance_double(ServiceResponse, message: 'an error', error?: true)
|
||||
|
||||
allow_next_instance_of(Groups::UpdateStatisticsService) do |instance|
|
||||
allow(instance).to receive(:execute).and_return(error_response)
|
||||
end
|
||||
end
|
||||
|
||||
it 'logs an error' do
|
||||
expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |instance|
|
||||
expect(instance).to receive(:error).twice
|
||||
end
|
||||
|
||||
perform
|
||||
end
|
||||
end
|
||||
end
|
|
@ -46,5 +46,24 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
|
|||
|
||||
expect(data[:deployable_url]).to be_nil
|
||||
end
|
||||
|
||||
context 'when commit does not exist in the repository' do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:deployment) { create(:deployment, project: project) }
|
||||
|
||||
subject(:data) { described_class.build(deployment, Time.current) }
|
||||
|
||||
before(:all) do
|
||||
project.repository.remove
|
||||
end
|
||||
|
||||
it 'does not include commit_url' do
|
||||
expect(data[:commit_url]).to be_nil
|
||||
end
|
||||
|
||||
it 'does not include commit_title' do
|
||||
expect(data[:commit_title]).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe BackfillNamespaceStatisticsWithDependencyProxySize do
|
||||
let_it_be(:groups) { table(:namespaces) }
|
||||
let_it_be(:group1) { groups.create!(id: 10, name: 'test1', path: 'test1', type: 'Group') }
|
||||
let_it_be(:group2) { groups.create!(id: 20, name: 'test2', path: 'test2', type: 'Group') }
|
||||
let_it_be(:group3) { groups.create!(id: 30, name: 'test3', path: 'test3', type: 'Group') }
|
||||
let_it_be(:group4) { groups.create!(id: 40, name: 'test4', path: 'test4', type: 'Group') }
|
||||
|
||||
let_it_be(:dependency_proxy_blobs) { table(:dependency_proxy_blobs) }
|
||||
let_it_be(:dependency_proxy_manifests) { table(:dependency_proxy_manifests) }
|
||||
|
||||
let_it_be(:group1_manifest) { create_manifest(10, 10) }
|
||||
let_it_be(:group2_manifest) { create_manifest(20, 20) }
|
||||
let_it_be(:group3_manifest) { create_manifest(30, 30) }
|
||||
|
||||
let_it_be(:group1_blob) { create_blob(10, 10) }
|
||||
let_it_be(:group2_blob) { create_blob(20, 20) }
|
||||
let_it_be(:group3_blob) { create_blob(30, 30) }
|
||||
|
||||
describe '#up' do
|
||||
it 'correctly schedules background migrations' do
|
||||
stub_const("#{described_class}::BATCH_SIZE", 2)
|
||||
|
||||
Sidekiq::Testing.fake! do
|
||||
freeze_time do
|
||||
migrate!
|
||||
|
||||
aggregate_failures do
|
||||
expect(described_class::MIGRATION)
|
||||
.to be_scheduled_migration([10, 30], ['dependency_proxy_size'])
|
||||
|
||||
expect(described_class::MIGRATION)
|
||||
.to be_scheduled_delayed_migration(2.minutes, [20], ['dependency_proxy_size'])
|
||||
|
||||
expect(BackgroundMigrationWorker.jobs.size).to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_manifest(group_id, size)
|
||||
dependency_proxy_manifests.create!(
|
||||
group_id: group_id,
|
||||
size: size,
|
||||
file_name: 'test-file',
|
||||
file: 'test',
|
||||
digest: 'abc123'
|
||||
)
|
||||
end
|
||||
|
||||
def create_blob(group_id, size)
|
||||
dependency_proxy_blobs.create!(
|
||||
group_id: group_id,
|
||||
size: size,
|
||||
file_name: 'test-file',
|
||||
file: 'test'
|
||||
)
|
||||
end
|
||||
end
|
|
@ -993,6 +993,33 @@ RSpec.describe Issuable do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#sync_escalation_attributes_from_alert?' do
|
||||
where(:issuable_type, :args, :sync_escalation_attributes_from_alert) do
|
||||
:issue | {} | false
|
||||
:issue | ref(:alert_args) | false
|
||||
:incident | {} | false
|
||||
:incident | ref(:alert_args) | true
|
||||
:merge_request | {} | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:alert_args) { { alert_management_alert: build_stubbed(:alert_management_alert) } }
|
||||
let(:issuable) { build_stubbed(issuable_type, **args) }
|
||||
|
||||
subject { issuable.sync_escalation_attributes_from_alert? }
|
||||
|
||||
it { is_expected.to eq(false) }
|
||||
|
||||
context 'with feature disabled' do
|
||||
before do
|
||||
stub_feature_flags(incident_escalations: false)
|
||||
end
|
||||
|
||||
it { is_expected.to eq(sync_escalation_attributes_from_alert) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#incident?' do
|
||||
where(:issuable_type, :incident) do
|
||||
:issue | false
|
||||
|
|
|
@ -23,9 +23,9 @@ RSpec.describe ProjectMemberPolicy do
|
|||
it { is_expected.not_to be_allowed(:destroy_project_bot_member) }
|
||||
end
|
||||
|
||||
context 'when user is project owner' do
|
||||
let(:member_user) { project.first_owner }
|
||||
let(:member) { project.members.find_by!(user: member_user) }
|
||||
context 'when user is the holder of personal namespace in which the project resides' do
|
||||
let(:namespace_holder) { project.namespace.owner }
|
||||
let(:member) { project.members.find_by!(user: namespace_holder) }
|
||||
|
||||
it { is_expected.to be_allowed(:read_project) }
|
||||
it { is_expected.to be_disallowed(:update_project_member) }
|
||||
|
|
|
@ -253,25 +253,51 @@ RSpec.describe AlertManagement::Alerts::UpdateService do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'updates the incident escalation status with the new alert status' do
|
||||
specify do
|
||||
expect(::Issues::UpdateService).to receive(:new).once.and_call_original
|
||||
expect(described_class).to receive(:new).once.and_call_original
|
||||
|
||||
expect { response }.to change { escalation_status&.reload&.acknowledged? }.to(true)
|
||||
.and change { alert.reload.acknowledged? }.to(true)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'does not sync with the incident status'
|
||||
|
||||
context 'when feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(incident_escalations: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'does not sync with the incident status'
|
||||
end
|
||||
|
||||
context 'when the issue is an incident' do
|
||||
before do
|
||||
issue.update!(issue_type: Issue.issue_types[:incident])
|
||||
end
|
||||
|
||||
it_behaves_like 'does not sync with the incident status'
|
||||
context 'when the incident does not have an escalation status' do
|
||||
it_behaves_like 'updates the incident escalation status with the new alert status'
|
||||
|
||||
context 'when feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(incident_escalations: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'updates the incident escalation status with the new alert status'
|
||||
end
|
||||
|
||||
def escalation_status
|
||||
issue.reload.escalation_status
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the incident has an escalation status' do
|
||||
let_it_be(:escalation_status, reload: true) { create(:incident_management_issuable_escalation_status, issue: issue) }
|
||||
|
||||
it 'updates the incident escalation status with the new alert status' do
|
||||
expect(::Issues::UpdateService).to receive(:new).once.and_call_original
|
||||
expect(described_class).to receive(:new).once.and_call_original
|
||||
|
||||
expect { response }.to change { escalation_status.reload.acknowledged? }.to(true)
|
||||
.and change { alert.reload.acknowledged? }.to(true)
|
||||
end
|
||||
it_behaves_like 'updates the incident escalation status with the new alert status'
|
||||
|
||||
context 'when the statuses match' do
|
||||
before do
|
||||
|
@ -286,7 +312,7 @@ RSpec.describe AlertManagement::Alerts::UpdateService do
|
|||
stub_feature_flags(incident_escalations: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'does not sync with the incident status'
|
||||
it_behaves_like 'updates the incident escalation status with the new alert status'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,6 +48,29 @@ RSpec.describe IncidentManagement::IssuableEscalationStatuses::PrepareUpdateServ
|
|||
end
|
||||
|
||||
it_behaves_like 'availability error response'
|
||||
|
||||
context 'with incident associated with alert' do
|
||||
let(:alert_status) { :acknowledged }
|
||||
|
||||
before do
|
||||
create(:alert_management_alert, alert_status, project: issue.project, issue: issue)
|
||||
issue.reload
|
||||
end
|
||||
|
||||
it_behaves_like 'successful response', { status_event: :acknowledge }
|
||||
|
||||
context 'when alert status does not match incident status' do
|
||||
let(:alert_status) { :triggered }
|
||||
|
||||
include_examples 'error response', 'Invalid value was provided for parameters: status'
|
||||
end
|
||||
|
||||
context 'with a standard issue' do
|
||||
let(:issue) { create(:issue) }
|
||||
|
||||
it_behaves_like 'availability error response'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is anonymous' do
|
||||
|
|
|
@ -98,6 +98,7 @@ RSpec.describe Issues::CreateService do
|
|||
end
|
||||
|
||||
it_behaves_like 'not an incident issue'
|
||||
include_examples 'does not call the escalation status CreateService'
|
||||
|
||||
context 'when issue is incident type' do
|
||||
before do
|
||||
|
@ -118,12 +119,22 @@ RSpec.describe Issues::CreateService do
|
|||
end
|
||||
|
||||
it_behaves_like 'incident issue'
|
||||
include_examples 'calls the escalation status CreateService'
|
||||
|
||||
it 'calls IncidentManagement::Incidents::CreateEscalationStatusService' do
|
||||
expect_next(::IncidentManagement::IssuableEscalationStatuses::CreateService, a_kind_of(Issue))
|
||||
.to receive(:execute)
|
||||
context 'when :incident_escalations feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(incident_escalations: false)
|
||||
end
|
||||
|
||||
issue
|
||||
include_examples 'does not call the escalation status CreateService'
|
||||
|
||||
context 'with associated alert' do
|
||||
before do
|
||||
opts.merge!(alert_management_alert: build(:alert_management_alert, project: project))
|
||||
end
|
||||
|
||||
include_examples 'calls the escalation status CreateService'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when invalid' do
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# This shared_example requires the following variables:
|
||||
# - issue (required)
|
||||
RSpec.shared_examples 'calls the escalation status CreateService' do
|
||||
it 'calls IncidentManagement::Incidents::CreateEscalationStatusService' do
|
||||
expect_next(::IncidentManagement::IssuableEscalationStatuses::CreateService, a_kind_of(Issue))
|
||||
.to receive(:execute)
|
||||
|
||||
issue
|
||||
end
|
||||
end
|
||||
|
||||
# This shared_example requires the following variables:
|
||||
# - issue (required)
|
||||
RSpec.shared_examples 'does not call the escalation status CreateService' do
|
||||
it 'does not call the ::IncidentManagement::IssuableEscalationStatuses::CreateService' do
|
||||
expect(::IncidentManagement::IssuableEscalationStatuses::CreateService).not_to receive(:new)
|
||||
|
||||
issue
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue