Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
5eeb391043
commit
901af2a0dd
|
|
@ -41,7 +41,6 @@ After your merge request has been approved according to our [approval guidelines
|
|||
- [ ] Fill in any upgrade notes that users may need to take into account in the [details section](#details)
|
||||
- [ ] Add Yes/No and further details if needed to the migration and settings columns in the [details section](#details)
|
||||
- [ ] Add the nickname of the external user who found the issue (and/or HackerOne profile) to the Thanks row in the [details section](#details)
|
||||
- [ ] Once your `master` MR is merged, comment on the original security issue with a link to that MR indicating the issue is fixed.
|
||||
|
||||
## Summary
|
||||
|
||||
|
|
|
|||
|
|
@ -27,17 +27,22 @@ const setupAxiosStartupCalls = axios => {
|
|||
if (existing) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
req.adapter = () =>
|
||||
existing.fetchCall.then(res =>
|
||||
existing.fetchCall.then(res => {
|
||||
const fetchHeaders = {};
|
||||
res.headers.forEach((val, key) => {
|
||||
fetchHeaders[key] = val;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line promise/no-nesting
|
||||
res.json().then(data => ({
|
||||
return res.json().then(data => ({
|
||||
data,
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
headers: res.headers,
|
||||
headers: fetchHeaders,
|
||||
config: req,
|
||||
request: req,
|
||||
})),
|
||||
);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
return req;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { getLocationHash, visitUrl } from './lib/utils/url_utility';
|
|||
|
||||
// everything else
|
||||
import loadAwardsHandler from './awards_handler';
|
||||
import applyGitLabUIConfig from '@gitlab/ui/dist/config';
|
||||
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
|
||||
import Flash, { removeFlashClickListener } from './flash';
|
||||
import './gl_dropdown';
|
||||
|
|
@ -42,6 +43,8 @@ import { __ } from './locale';
|
|||
|
||||
import 'ee_else_ce/main_ee';
|
||||
|
||||
applyGitLabUIConfig();
|
||||
|
||||
// expose jQuery as global (TODO: remove these)
|
||||
window.jQuery = jQuery;
|
||||
window.$ = jQuery;
|
||||
|
|
|
|||
|
|
@ -353,7 +353,10 @@ export default {
|
|||
</gl-deprecated-button>
|
||||
</div>
|
||||
|
||||
<div v-if="externalDashboardUrl.length" class="mb-2 mr-2 d-flex d-sm-block">
|
||||
<div
|
||||
v-if="externalDashboardUrl && externalDashboardUrl.length"
|
||||
class="mb-2 mr-2 d-flex d-sm-block"
|
||||
>
|
||||
<gl-deprecated-button
|
||||
class="flex-grow-1 js-external-dashboard-link"
|
||||
variant="primary"
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const defaultClient = createDefaultClient(
|
|||
},
|
||||
readme(_, { url }) {
|
||||
return axios
|
||||
.get(url, { params: { viewer: 'rich', format: 'json' } })
|
||||
.get(url, { params: { format: 'json', viewer: 'rich' } })
|
||||
.then(({ data }) => ({ ...data, __typename: 'ReadmeFile' }));
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ module AlertManagement
|
|||
include Sortable
|
||||
include Noteable
|
||||
include Gitlab::SQL::Pattern
|
||||
include Presentable
|
||||
|
||||
STATUSES = {
|
||||
triggered: 0,
|
||||
|
|
@ -25,6 +26,8 @@ module AlertManagement
|
|||
ignored: :ignore
|
||||
}.freeze
|
||||
|
||||
DETAILS_IGNORED_PARAMS = %w(start_time).freeze
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :issue, optional: true
|
||||
|
||||
|
|
@ -136,7 +139,7 @@ module AlertManagement
|
|||
end
|
||||
|
||||
def details
|
||||
details_payload = payload.except(*attributes.keys)
|
||||
details_payload = payload.except(*attributes.keys, *DETAILS_IGNORED_PARAMS)
|
||||
|
||||
Gitlab::Utils::InlineHash.merge_keys(details_payload)
|
||||
end
|
||||
|
|
@ -161,6 +164,12 @@ module AlertManagement
|
|||
project.execute_services(hook_data, :alert_hooks)
|
||||
end
|
||||
|
||||
def present
|
||||
return super(presenter_class: AlertManagement::PrometheusAlertPresenter) if prometheus?
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def hook_data
|
||||
|
|
|
|||
|
|
@ -553,10 +553,28 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
def lazy_ref_commit
|
||||
return unless ::Gitlab::Ci::Features.pipeline_latest?
|
||||
|
||||
BatchLoader.for(ref).batch do |refs, loader|
|
||||
next unless project.repository_exists?
|
||||
|
||||
project.repository.list_commits_by_ref_name(refs).then do |commits|
|
||||
loader.call(ref, commits[ref])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def latest?
|
||||
return false unless git_ref && commit.present?
|
||||
|
||||
project.commit(git_ref) == commit
|
||||
unless ::Gitlab::Ci::Features.pipeline_latest?
|
||||
return project.commit(git_ref) == commit
|
||||
end
|
||||
|
||||
return false if lazy_ref_commit.nil?
|
||||
|
||||
lazy_ref_commit.id == commit.id
|
||||
end
|
||||
|
||||
def retried
|
||||
|
|
|
|||
|
|
@ -15,5 +15,19 @@ module Integration
|
|||
|
||||
Project.where(id: custom_integration_project_ids)
|
||||
end
|
||||
|
||||
def ids_without_integration(integration, limit)
|
||||
services = Service
|
||||
.select('1')
|
||||
.where('services.project_id = projects.id')
|
||||
.where(type: integration.type)
|
||||
|
||||
Project
|
||||
.where('NOT EXISTS (?)', services)
|
||||
.where(pending_delete: false)
|
||||
.where(archived: false)
|
||||
.limit(limit)
|
||||
.pluck(:id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module AlertManagement
|
||||
class AlertPresenter < Gitlab::View::Presenter::Delegated
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
include IncidentManagement::Settings
|
||||
|
||||
MARKDOWN_LINE_BREAK = " \n".freeze
|
||||
|
||||
def initialize(alert, _attributes = {})
|
||||
super
|
||||
|
||||
@alert = alert
|
||||
@project = alert.project
|
||||
end
|
||||
|
||||
def issue_description
|
||||
horizontal_line = "\n\n---\n\n"
|
||||
|
||||
[
|
||||
issue_summary_markdown,
|
||||
alert_markdown,
|
||||
incident_management_setting.issue_template_content
|
||||
].compact.join(horizontal_line)
|
||||
end
|
||||
|
||||
def start_time
|
||||
started_at&.strftime('%d %B %Y, %-l:%M%p (%Z)')
|
||||
end
|
||||
|
||||
def issue_summary_markdown
|
||||
<<~MARKDOWN.chomp
|
||||
#### Summary
|
||||
|
||||
#{metadata_list}
|
||||
#{alert_details}#{metric_embed_for_alert}
|
||||
MARKDOWN
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :alert, :project
|
||||
|
||||
def alerting_alert
|
||||
strong_memoize(:alerting_alert) do
|
||||
Gitlab::Alerting::Alert.new(project: project, payload: alert.payload).present
|
||||
end
|
||||
end
|
||||
|
||||
def alert_markdown; end
|
||||
|
||||
def metadata_list
|
||||
metadata = []
|
||||
|
||||
metadata << list_item('Start time', start_time)
|
||||
metadata << list_item('Severity', severity)
|
||||
metadata << list_item('full_query', backtick(full_query)) if full_query
|
||||
metadata << list_item('Service', service) if service
|
||||
metadata << list_item('Monitoring tool', monitoring_tool) if monitoring_tool
|
||||
metadata << list_item('Hosts', host_links) if hosts.any?
|
||||
|
||||
metadata.join(MARKDOWN_LINE_BREAK)
|
||||
end
|
||||
|
||||
def alert_details
|
||||
if details.present?
|
||||
<<~MARKDOWN.chomp
|
||||
|
||||
#### Alert Details
|
||||
|
||||
#{details_list}
|
||||
MARKDOWN
|
||||
end
|
||||
end
|
||||
|
||||
def details_list
|
||||
alert.details
|
||||
.map { |label, value| list_item(label, value) }
|
||||
.join(MARKDOWN_LINE_BREAK)
|
||||
end
|
||||
|
||||
def metric_embed_for_alert; end
|
||||
|
||||
def full_query; end
|
||||
|
||||
def list_item(key, value)
|
||||
"**#{key}:** #{value}".strip
|
||||
end
|
||||
|
||||
def backtick(value)
|
||||
"`#{value}`"
|
||||
end
|
||||
|
||||
def host_links
|
||||
hosts.join(' ')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module AlertManagement
|
||||
class PrometheusAlertPresenter < AlertManagement::AlertPresenter
|
||||
private
|
||||
|
||||
def alert_markdown
|
||||
alerting_alert.alert_markdown
|
||||
end
|
||||
|
||||
def details_list
|
||||
alerting_alert.annotation_list
|
||||
end
|
||||
|
||||
def metric_embed_for_alert
|
||||
alerting_alert.metric_embed_for_alert
|
||||
end
|
||||
|
||||
def full_query
|
||||
alerting_alert.full_query
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -58,6 +58,21 @@ module Projects
|
|||
MARKDOWN
|
||||
end
|
||||
|
||||
def annotation_list
|
||||
strong_memoize(:annotation_list) do
|
||||
annotations
|
||||
.reject { |annotation| annotation.label.in?(RESERVED_ANNOTATIONS | GENERIC_ALERT_SUMMARY_ANNOTATIONS) }
|
||||
.map { |annotation| list_item(annotation.label, annotation.value) }
|
||||
.join(MARKDOWN_LINE_BREAK)
|
||||
end
|
||||
end
|
||||
|
||||
def metric_embed_for_alert
|
||||
url = embed_url_for_gitlab_alert || embed_url_for_self_managed_alert
|
||||
|
||||
"\n[](#{url})" if url
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def alert_title
|
||||
|
|
@ -93,15 +108,6 @@ module Projects
|
|||
end
|
||||
end
|
||||
|
||||
def annotation_list
|
||||
strong_memoize(:annotation_list) do
|
||||
annotations
|
||||
.reject { |annotation| annotation.label.in?(RESERVED_ANNOTATIONS | GENERIC_ALERT_SUMMARY_ANNOTATIONS) }
|
||||
.map { |annotation| list_item(annotation.label, annotation.value) }
|
||||
.join(MARKDOWN_LINE_BREAK)
|
||||
end
|
||||
end
|
||||
|
||||
def list_item(key, value)
|
||||
"**#{key}:** #{value}".strip
|
||||
end
|
||||
|
|
@ -120,12 +126,6 @@ module Projects
|
|||
Array(hosts.value).join(' ')
|
||||
end
|
||||
|
||||
def metric_embed_for_alert
|
||||
url = embed_url_for_gitlab_alert || embed_url_for_self_managed_alert
|
||||
|
||||
"\n[](#{url})" if url
|
||||
end
|
||||
|
||||
def embed_url_for_gitlab_alert
|
||||
return unless gitlab_alert
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ module Admin
|
|||
|
||||
def create_integration_for_projects_without_integration
|
||||
loop do
|
||||
batch = Project.uncached { project_ids_without_integration }
|
||||
batch = Project.uncached { Project.ids_without_integration(integration, BATCH_SIZE) }
|
||||
|
||||
bulk_create_from_integration(batch) unless batch.empty?
|
||||
|
||||
|
|
@ -114,22 +114,6 @@ module Admin
|
|||
integration.type == 'ExternalWikiService'
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def project_ids_without_integration
|
||||
services = Service
|
||||
.select('1')
|
||||
.where('services.project_id = projects.id')
|
||||
.where(type: integration.type)
|
||||
|
||||
Project
|
||||
.where('NOT EXISTS (?)', services)
|
||||
.where(pending_delete: false)
|
||||
.where(archived: false)
|
||||
.limit(BATCH_SIZE)
|
||||
.pluck(:id)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def service_hash
|
||||
@service_hash ||= integration.to_service_hash
|
||||
.tap { |json| json['inherit_from_id'] = integration.id }
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ module AlertManagement
|
|||
return error_no_permissions unless allowed?
|
||||
return error_issue_already_exists if alert.issue
|
||||
|
||||
result = create_issue(user, alert_payload)
|
||||
result = create_issue
|
||||
@issue = result.payload[:issue]
|
||||
|
||||
return error(result.message) if result.error?
|
||||
|
|
@ -36,7 +36,7 @@ module AlertManagement
|
|||
user.can?(:create_issue, project)
|
||||
end
|
||||
|
||||
def create_issue(user, alert_payload)
|
||||
def create_issue
|
||||
issue = do_create_issue(label_ids: issue_label_ids)
|
||||
|
||||
# Create an unlabelled issue if we couldn't create the issue
|
||||
|
|
@ -53,14 +53,6 @@ module AlertManagement
|
|||
success
|
||||
end
|
||||
|
||||
def alert_payload
|
||||
if alert.prometheus?
|
||||
alert.payload
|
||||
else
|
||||
Gitlab::Alerting::NotificationPayloadParser.call(alert.payload.to_h)
|
||||
end
|
||||
end
|
||||
|
||||
def update_alert_issue_id
|
||||
alert.update(issue_id: issue.id)
|
||||
end
|
||||
|
|
@ -85,24 +77,16 @@ module AlertManagement
|
|||
Issues::CreateService.new(
|
||||
project,
|
||||
user,
|
||||
title: issue_title,
|
||||
description: issue_description,
|
||||
title: alert_presenter.title,
|
||||
description: alert_presenter.issue_description,
|
||||
**params
|
||||
).execute
|
||||
end
|
||||
|
||||
def issue_title
|
||||
alert_presenter.full_title
|
||||
end
|
||||
|
||||
def issue_description
|
||||
horizontal_line = "\n\n---\n\n"
|
||||
|
||||
[
|
||||
alert_summary,
|
||||
alert_markdown,
|
||||
issue_template_content
|
||||
].compact.join(horizontal_line)
|
||||
def alert_presenter
|
||||
strong_memoize(:alert_presenter) do
|
||||
alert.present
|
||||
end
|
||||
end
|
||||
|
||||
def issue_label_ids
|
||||
|
|
@ -117,31 +101,6 @@ module AlertManagement
|
|||
.execute
|
||||
end
|
||||
|
||||
def alert_summary
|
||||
alert_presenter.issue_summary_markdown
|
||||
end
|
||||
|
||||
def alert_markdown
|
||||
alert_presenter.alert_markdown
|
||||
end
|
||||
|
||||
def alert_presenter
|
||||
strong_memoize(:alert_presenter) do
|
||||
Gitlab::Alerting::Alert.new(project: project, payload: alert_payload).present
|
||||
end
|
||||
end
|
||||
|
||||
def issue_template_content
|
||||
incident_management_setting.issue_template_content
|
||||
end
|
||||
|
||||
def incident_management_setting
|
||||
strong_memoize(:incident_management_setting) do
|
||||
project.incident_management_setting ||
|
||||
project.build_incident_management_setting
|
||||
end
|
||||
end
|
||||
|
||||
def issue_errors(issue)
|
||||
issue.errors.full_messages.to_sentence
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ module Projects
|
|||
|
||||
def propagate_projects_with_template
|
||||
loop do
|
||||
batch = Project.uncached { project_ids_without_integration }
|
||||
batch = Project.uncached { Project.ids_without_integration(template, BATCH_SIZE) }
|
||||
|
||||
bulk_create_from_template(batch) unless batch.empty?
|
||||
|
||||
|
|
@ -50,22 +50,6 @@ module Projects
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def project_ids_without_integration
|
||||
services = Service
|
||||
.select('1')
|
||||
.where('services.project_id = projects.id')
|
||||
.where(type: template.type)
|
||||
|
||||
Project
|
||||
.where('NOT EXISTS (?)', services)
|
||||
.where(pending_delete: false)
|
||||
.where(archived: false)
|
||||
.limit(BATCH_SIZE)
|
||||
.pluck(:id)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def bulk_insert(klass, columns, values_array)
|
||||
items_to_insert = values_array.map { |array| Hash[columns.zip(array)] }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Improve pipeline index controller performance by resolving Gitaly N+1 calls
|
||||
merge_request: 34160
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddAuthorIdIndexToAuditEvents < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
INDEX_NAME = 'index_audit_events_on_entity_id_entity_type_id_desc_author_id'
|
||||
OLD_INDEX_NAME = 'index_audit_events_on_entity_id_and_entity_type_and_id_desc'
|
||||
|
||||
def up
|
||||
add_concurrent_index(:audit_events, [:entity_id, :entity_type, :id, :author_id], order: { id: :desc }, name: INDEX_NAME)
|
||||
remove_concurrent_index_by_name(:audit_events, OLD_INDEX_NAME)
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index(:audit_events, [:entity_id, :entity_type, :id], order: { id: :desc }, name: OLD_INDEX_NAME)
|
||||
remove_concurrent_index_by_name(:audit_events, INDEX_NAME)
|
||||
end
|
||||
end
|
||||
|
|
@ -9419,7 +9419,7 @@ CREATE INDEX index_approvers_on_target_id_and_target_type ON public.approvers US
|
|||
|
||||
CREATE INDEX index_approvers_on_user_id ON public.approvers USING btree (user_id);
|
||||
|
||||
CREATE INDEX index_audit_events_on_entity_id_and_entity_type_and_id_desc ON public.audit_events USING btree (entity_id, entity_type, id DESC);
|
||||
CREATE INDEX index_audit_events_on_entity_id_entity_type_id_desc_author_id ON public.audit_events USING btree (entity_id, entity_type, id DESC, author_id);
|
||||
|
||||
CREATE INDEX index_audit_events_on_ruby_object_in_details ON public.audit_events USING btree (id) WHERE (details ~~ '%ruby/object%'::text);
|
||||
|
||||
|
|
@ -14108,6 +14108,7 @@ COPY "schema_migrations" (version) FROM STDIN;
|
|||
20200615123055
|
||||
20200615193524
|
||||
20200615232735
|
||||
20200616145031
|
||||
20200617000757
|
||||
20200617001001
|
||||
20200617001118
|
||||
|
|
|
|||
|
|
@ -133,34 +133,34 @@ replicating data from those features will cause the data to be **lost**.
|
|||
If you wish to use those features on a **secondary** node, or to execute a failover
|
||||
successfully, you must replicate their data using some other means.
|
||||
|
||||
| Feature | Replicated | Verified | Notes |
|
||||
| Feature | Replicated (added in GitLab version) | Verified (added in GitLab version) | Notes |
|
||||
|:---------------------------------------------------------------------|:---------------------------------------------------------|:--------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------|
|
||||
| Application data in PostgreSQL | **Yes** | **Yes** | |
|
||||
| Project repository | **Yes** | **Yes** | |
|
||||
| Project wiki repository | **Yes** | **Yes** | |
|
||||
| Project designs repository | **Yes** | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/32467) | |
|
||||
| Uploads | **Yes** | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Verified only on transfer, or manually (*1*) |
|
||||
| LFS objects | **Yes** | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8922) | Verified only on transfer, or manually (*1*). Unavailable for new LFS objects in 11.11.x and 12.0.x (*2*). |
|
||||
| CI job artifacts (other than traces) | **Yes** | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Verified only manually (*1*) |
|
||||
| Archived traces | **Yes** | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Verified only on transfer, or manually (*1*) |
|
||||
| Personal snippets | **Yes** | **Yes** | |
|
||||
| Application data in PostgreSQL | **Yes** (10.2) | **Yes** (10.2) | |
|
||||
| Project repository | **Yes** (10.2) | **Yes** (10.7) | |
|
||||
| Project wiki repository | **Yes** (10.2) | **Yes** (10.7) | |
|
||||
| Project designs repository | **Yes** (12.7) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/32467) | |
|
||||
| Uploads | **Yes** (10.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Verified only on transfer, or manually (*1*) |
|
||||
| LFS objects | **Yes** (10.2) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8922) | Verified only on transfer, or manually (*1*). Unavailable for new LFS objects in 11.11.x and 12.0.x (*2*). |
|
||||
| CI job artifacts (other than traces) | **Yes** (10.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Verified only manually (*1*) |
|
||||
| Archived traces | **Yes** (10.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Verified only on transfer, or manually (*1*) |
|
||||
| Personal snippets | **Yes** (10.2) | **Yes** (10.2) | |
|
||||
| [Versioned snippets](../../../user/snippets.md#versioned-snippets) | [No](https://gitlab.com/groups/gitlab-org/-/epics/2809) | [No](https://gitlab.com/groups/gitlab-org/-/epics/2810) | |
|
||||
| Project snippets | **Yes** | **Yes** | |
|
||||
| Object pools for forked project deduplication | **Yes** | No | |
|
||||
| Project snippets | **Yes** (10.2) | **Yes** (10.2) | |
|
||||
| Object pools for forked project deduplication | **Yes** | No | |
|
||||
| [Server-side Git Hooks](../../custom_hooks.md) | No | No | |
|
||||
| [Elasticsearch integration](../../../integration/elasticsearch.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/1186) | No | |
|
||||
| [GitLab Pages](../../pages/index.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/589) | No | |
|
||||
| [Container Registry](../../packages/container_registry.md) | **Yes** | No | |
|
||||
| [NPM Registry](../../../user/packages/npm_registry/index.md) | **Yes** | No | |
|
||||
| [Maven Repository](../../../user/packages/maven_repository/index.md) | **Yes** | No | |
|
||||
| [Conan Repository](../../../user/packages/conan_repository/index.md) | **Yes** | No | |
|
||||
| [NuGet Repository](../../../user/packages/nuget_repository/index.md) | **Yes** | No | |
|
||||
| [PyPi Repository](../../../user/packages/pypi_repository/index.md) | **Yes** | No | |
|
||||
| [Composer Repository](../../../user/packages/composer_repository/index.md) | **Yes** | No | |
|
||||
| [Container Registry](../../packages/container_registry.md) | **Yes** (12.3) | No | |
|
||||
| [NPM Registry](../../../user/packages/npm_registry/index.md) | **Yes** (13.2) | No | |
|
||||
| [Maven Repository](../../../user/packages/maven_repository/index.md) | **Yes** (13.2) | No | |
|
||||
| [Conan Repository](../../../user/packages/conan_repository/index.md) | **Yes** (13.2) | No | |
|
||||
| [NuGet Repository](../../../user/packages/nuget_repository/index.md) | **Yes** (13.2) | No | |
|
||||
| [PyPi Repository](../../../user/packages/pypi_repository/index.md) | **Yes** (13.2) | No | |
|
||||
| [Composer Repository](../../../user/packages/composer_repository/index.md) | **Yes** (13.2) | No | |
|
||||
| [External merge request diffs](../../merge_request_diffs.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/33817) | No | |
|
||||
| [Terraform State](../../terraform_state.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/3112)(*3*) | No | |
|
||||
| [Vulnerability Export](../../../user/application_security/security_dashboard/#export-vulnerabilities-1) | [No](https://gitlab.com/groups/gitlab-org/-/epics/3111)(*3*) | No | | |
|
||||
| Content in object storage | **Yes** | No | |
|
||||
| Content in object storage | **Yes** (12.4) | No | |
|
||||
|
||||
- (*1*): The integrity can be verified manually using
|
||||
[Integrity Check Rake Task](../../raketasks/check.md) on both nodes and comparing
|
||||
|
|
|
|||
|
|
@ -387,31 +387,9 @@ Gitaly makes the following assumptions:
|
|||
clients, and that Gitaly server can read and write to `/mnt/gitlab/storage2`.
|
||||
- Your `gitaly1.internal` and `gitaly2.internal` Gitaly servers can reach each other.
|
||||
|
||||
Note you can't a use mixed setup, with at least one of your Gitaly servers configured as a local
|
||||
server with the `path` setting provided. This is because other Gitaly instances can't communicate
|
||||
with it. The following setup is _incorrect_, because:
|
||||
|
||||
- You must replace `path` with `gitaly_address` containing a proper value.
|
||||
- The address must be reachable from the other two addresses provided.
|
||||
|
||||
```ruby
|
||||
git_data_dirs({
|
||||
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
|
||||
'storage1' => { 'path' => '/var/opt/gitlab/git-data' },
|
||||
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
|
||||
})
|
||||
```
|
||||
|
||||
You should use configuration similar to the following:
|
||||
|
||||
```ruby
|
||||
git_data_dirs({
|
||||
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
|
||||
# this should be the IP address of the GitLab server that has Gitaly running on it
|
||||
'storage1' => { 'gitaly_address' => 'tcp://gitlab.internal:8075' },
|
||||
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
|
||||
})
|
||||
```
|
||||
You can't define Gitaly servers with some as a local directory (with `path`) and some as remote
|
||||
server (with `gitaly_address`). However, local and remote Gitaly services can be used together. See
|
||||
[mixed configuration](#mixed-configuration) for more information.
|
||||
|
||||
**For Omnibus GitLab**
|
||||
|
||||
|
|
@ -475,6 +453,34 @@ If you have [server hooks](../server_hooks.md) configured, either per repository
|
|||
must move these to the Gitaly servers. If you have multiple Gitaly servers, copy your server hooks
|
||||
to all Gitaly servers.
|
||||
|
||||
#### Mixed configuration
|
||||
|
||||
GitLab can reside on the same server as one of many Gitaly servers, but doesn't support
|
||||
configuration that mixes local and remote configuration. The following setup is incorrect, because:
|
||||
|
||||
- `path` is invalid for some of the Gitaly servers.
|
||||
- All addresses must be reachable from the other Gitaly servers.
|
||||
|
||||
```ruby
|
||||
git_data_dirs({
|
||||
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
|
||||
'storage1' => { 'path' => '/var/opt/gitlab/git-data' },
|
||||
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
|
||||
})
|
||||
```
|
||||
|
||||
To combine local and remote Gitaly servers, use an external address for the local Gitaly server. For
|
||||
example:
|
||||
|
||||
```ruby
|
||||
git_data_dirs({
|
||||
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
|
||||
# Address of the GitLab server that has Gitaly running on it
|
||||
'storage1' => { 'gitaly_address' => 'tcp://gitlab.internal:8075' },
|
||||
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
|
||||
})
|
||||
```
|
||||
|
||||
### Disable Gitaly where not required (optional)
|
||||
|
||||
If you are running Gitaly [as a remote service](#run-gitaly-on-its-own-server) you may want to
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@ or higher, are required for your CPU or node counts. For more information, see
|
|||
our [Sysbench](https://github.com/akopytov/sysbench)-based
|
||||
[CPU benchmark](https://gitlab.com/gitlab-org/quality/performance/-/wikis/Reference-Architectures/GCP-CPU-Benchmarks).
|
||||
|
||||
AWS-equivalent and Azure-equivalent configurations are rough suggestions that
|
||||
may change in the future, and haven't been tested or validated.
|
||||
|
||||
Due to better performance and availability, for data objects (such as LFS,
|
||||
uploads, or artifacts), using an [object storage service](#configure-the-object-storage)
|
||||
is recommended instead of using NFS. Using an object storage service also
|
||||
|
|
|
|||
|
|
@ -146,3 +146,20 @@ export const fetchFoos = ({ state }) => {
|
|||
return axios.get(state.settings.fooPath);
|
||||
};
|
||||
```
|
||||
|
||||
### 7. How can I test the production build locally?
|
||||
|
||||
Sometimes it's necessary to test locally what the frontend production build would produce, to do so the steps are:
|
||||
|
||||
1. Stop webpack: `gdk stop webpack`.
|
||||
1. Open `gitlab.yaml` located in your `gitlab` installation folder, scroll down to the `webpack` section and change `dev_server` to `enabled: false`.
|
||||
1. Run `yarn webpack-prod && gdk restart rails-web`.
|
||||
|
||||
The production build takes a few minutes to be completed; any code change at this point will be
|
||||
displayed only after executing the item 3 above again.
|
||||
To return to the normal development mode:
|
||||
|
||||
1. Open `gitlab.yaml` located in your `gitlab` installation folder, scroll down to the `webpack` section and change back `dev_server` to `enabled: true`.
|
||||
1. Run `yarn clean` to remove the production assets and free some space (optional).
|
||||
1. Start webpack again: `gdk start webpack`.
|
||||
1. Restart GDK: `gdk-restart rails-web`.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# GitLab Composer Repository **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15886) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.1.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15886) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
|
||||
|
||||
With the GitLab Composer Repository, every project can have its own space to store [Composer](https://getcomposer.org/) packages.
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ The Packages feature allows GitLab to act as a repository for the following:
|
|||
| [NuGet Repository](nuget_repository/index.md) **(PREMIUM)** | The GitLab NuGet Repository will enable every project in GitLab to have its own space to store [NuGet](https://www.nuget.org/) packages. | 12.8+ |
|
||||
| [PyPi Repository](pypi_repository/index.md) **(PREMIUM)** | The GitLab PyPi Repository will enable every project in GitLab to have its own space to store [PyPi](https://pypi.org/) packages. | 12.10+ |
|
||||
| [Go Proxy](go_proxy/index.md) **(PREMIUM)** | The Go proxy for GitLab enables every project in GitLab to be fetched with the [Go proxy protocol](https://proxy.golang.org/). | 13.1+ |
|
||||
| [Composer Repository](composer_repository/index.md) **(PREMIUM)** | The GitLab Composer Repository will enable every project in GitLab to have its own space to store [Composer](https://getcomposer.org/) packages. | 13.1+ |
|
||||
| [Composer Repository](composer_repository/index.md) **(PREMIUM)** | The GitLab Composer Repository will enable every project in GitLab to have its own space to store [Composer](https://getcomposer.org/) packages. | 13.2+ |
|
||||
|
||||
## Enable the Package Registry for your project
|
||||
|
||||
|
|
|
|||
|
|
@ -35,18 +35,16 @@ To create and enable a feature flag:
|
|||
|
||||
1. Navigate to your project's **Operations > Feature Flags**.
|
||||
1. Click the **New feature flag** button.
|
||||
1. Fill in the details:
|
||||
- Enter a name that starts with a letter and contains only lowercase letters, digits, underscores (`_`),
|
||||
or dashes (`-`), and does not end with a dash (`-`) or underscore (`_`).
|
||||
- Enter a description (optional, 255 characters max).
|
||||
1. Enter a name that starts with a letter and contains only lowercase letters, digits, underscores (`_`),
|
||||
or dashes (`-`), and does not end with a dash (`-`) or underscore (`_`).
|
||||
1. Enter a description (optional, 255 characters max).
|
||||
1. Enter details about how the flag should be applied:
|
||||
- In GitLab 13.0 and earlier, add **Environment specs**. For each environment,
|
||||
include the:
|
||||
- Status (default enabled)
|
||||
- [Rollout strategy](#rollout-strategy-legacy) (defaults to all users)
|
||||
- In GitLab 13.1 and later, add Feature Flag [**Strategies**](#feature-flag-strategies). For
|
||||
each strategy, include the:
|
||||
- Type (defaults to [All users](#all-users))
|
||||
- Environment (defaults to all environments)
|
||||
include the **Status** (default enabled) and [**Rollout strategy**](#rollout-strategy-legacy)
|
||||
(defaults to **All users**).
|
||||
- In GitLab 13.1 and later, add Feature Flag [**Strategies**](#feature-flag-strategies).
|
||||
For each strategy, include the **Type** (defaults to [**All users**](#all-users))
|
||||
and **Environments** (defaults to all environments).
|
||||
1. Click **Create feature flag**.
|
||||
|
||||
You can change these settings by clicking the **{pencil}** (edit) button
|
||||
|
|
|
|||
|
|
@ -1,49 +1,5 @@
|
|||
---
|
||||
type: reference, howto
|
||||
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
|
||||
redirect_to: 'pages_ci_cd_template.md'
|
||||
---
|
||||
|
||||
# Create a Pages website by using a CI/CD template
|
||||
|
||||
GitLab provides `.gitlab-ci.yml` templates for the most popular Static Site Generators (SSGs).
|
||||
You can create your own `.gitlab-ci.yml` file from one of these templates, and run
|
||||
the CI/CD pipeline to generate a Pages website.
|
||||
|
||||
Use a `.gitlab-ci.yml` template when you have an existing project that you want to add a Pages site to.
|
||||
|
||||
Your GitLab repository should contain files specific to an SSG, or plain HTML.
|
||||
After you complete these steps, you may need to do additional
|
||||
configuration for the Pages site to generate properly.
|
||||
|
||||
1. In the left sidebar, click **Project overview**.
|
||||
1. Click **Set up CI/CD**.
|
||||
|
||||

|
||||
|
||||
If this button is not available, CI/CD is already configured for
|
||||
your project. You may want to browse the `.gitlab-ci.yml` files
|
||||
[in these projects instead](https://gitlab.com/pages).
|
||||
|
||||
1. From the **Apply a template** list, choose a template for the SSG you're using.
|
||||
You can also choose plain HTML.
|
||||
|
||||

|
||||
|
||||
If you don't find a corresponding template, you can view the
|
||||
[GitLab Pages group of sample projects](https://gitlab.com/pages).
|
||||
These projects contain `.gitlab-ci.yml` files that you can modify for your needs.
|
||||
You can also [learn how to write your own `.gitlab-ci.yml`
|
||||
file for GitLab Pages](../getting_started_part_four.md).
|
||||
|
||||
1. Save and commit the `.gitlab-ci.yml` file.
|
||||
|
||||
If everything is configured correctly, the site can take approximately 30 minutes to deploy.
|
||||
|
||||
You can watch the pipeline run by going to **CI / CD > Pipelines**.
|
||||
When the pipeline is finished, go to **Settings > Pages** to find the link to
|
||||
your Pages website.
|
||||
|
||||
For every change pushed to your repository, GitLab CI/CD runs a new pipeline
|
||||
that immediately publishes your changes to the Pages site.
|
||||
This document was moved to [pages_ci_cd_template.md](pages_ci_cd_template.md).
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
type: reference, howto
|
||||
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
|
||||
---
|
||||
|
||||
# Create a Pages website by using a CI/CD template
|
||||
|
||||
GitLab provides `.gitlab-ci.yml` templates for the most popular Static Site Generators (SSGs).
|
||||
You can create your own `.gitlab-ci.yml` file from one of these templates, and run
|
||||
the CI/CD pipeline to generate a Pages website.
|
||||
|
||||
Use a `.gitlab-ci.yml` template when you have an existing project that you want to add a Pages site to.
|
||||
|
||||
Your GitLab repository should contain files specific to an SSG, or plain HTML.
|
||||
After you complete these steps, you may need to do additional
|
||||
configuration for the Pages site to generate properly.
|
||||
|
||||
1. In the left sidebar, click **Project overview**.
|
||||
1. Click **Set up CI/CD**.
|
||||
|
||||

|
||||
|
||||
If this button is not available, CI/CD is already configured for
|
||||
your project. You may want to browse the `.gitlab-ci.yml` files
|
||||
[in these projects instead](https://gitlab.com/pages).
|
||||
|
||||
1. From the **Apply a template** list, choose a template for the SSG you're using.
|
||||
You can also choose plain HTML.
|
||||
|
||||

|
||||
|
||||
If you don't find a corresponding template, you can view the
|
||||
[GitLab Pages group of sample projects](https://gitlab.com/pages).
|
||||
These projects contain `.gitlab-ci.yml` files that you can modify for your needs.
|
||||
You can also [learn how to write your own `.gitlab-ci.yml`
|
||||
file for GitLab Pages](../getting_started_part_four.md).
|
||||
|
||||
1. Save and commit the `.gitlab-ci.yml` file.
|
||||
|
||||
If everything is configured correctly, the site can take approximately 30 minutes to deploy.
|
||||
|
||||
You can watch the pipeline run by going to **CI / CD > Pipelines**.
|
||||
When the pipeline is finished, go to **Settings > Pages** to find the link to
|
||||
your Pages website.
|
||||
|
||||
For every change pushed to your repository, GitLab CI/CD runs a new pipeline
|
||||
that immediately publishes your changes to the Pages site.
|
||||
|
|
@ -48,7 +48,7 @@ To create a GitLab Pages website:
|
|||
| -------- | ----------- |
|
||||
| [Fork a sample project](getting_started/fork_sample_project.md) | Create a new project with Pages already configured by forking a sample project. |
|
||||
| [Use a new project template](getting_started/pages_new_project_template.md) | Create a new project with Pages already configured by using a new project template. |
|
||||
| [Use a `.gitlab-ci.yml` template](getting_started/new_or_existing_website.md) | Add a Pages site to an existing project. Use a pre-populated CI template file. |
|
||||
| [Use a `.gitlab-ci.yml` template](getting_started/pages_ci_cd_template.md) | Add a Pages site to an existing project. Use a pre-populated CI template file. |
|
||||
| [Create a `gitlab-ci.yml` file from scratch](getting_started_part_four.md) | Add a Pages site to an existing project. Learn how to create and configure your own CI file. |
|
||||
|
||||
To update a GitLab Pages website:
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ module Gitlab
|
|||
::Feature.enabled?(:ci_atomic_processing, project, default_enabled: true)
|
||||
end
|
||||
|
||||
def self.pipeline_latest?
|
||||
::Feature.enabled?(:ci_pipeline_latest, default_enabled: true)
|
||||
end
|
||||
|
||||
def self.release_generation_enabled?
|
||||
::Feature.enabled?(:ci_release_generation)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ module Gitlab
|
|||
pipelines.each do |pipeline|
|
||||
self.new(pipeline).tap do |preloader|
|
||||
preloader.preload_commit_authors
|
||||
preloader.preload_ref_commits
|
||||
preloader.preload_pipeline_warnings
|
||||
preloader.preload_stages_warnings
|
||||
end
|
||||
|
|
@ -27,12 +28,19 @@ module Gitlab
|
|||
@pipeline = pipeline
|
||||
end
|
||||
|
||||
# This also preloads the author of every commit. We're using "lazy_author"
|
||||
# here since "author" immediately loads the data on the first call.
|
||||
def preload_commit_authors
|
||||
# This also preloads the author of every commit. We're using "lazy_author"
|
||||
# here since "author" immediately loads the data on the first call.
|
||||
@pipeline.commit.try(:lazy_author)
|
||||
end
|
||||
|
||||
# This preloads latest commits for given refs and therefore makes it
|
||||
# much less expensive to check if a pipeline is a latest one for
|
||||
# given branch.
|
||||
def preload_ref_commits
|
||||
@pipeline.lazy_ref_commit
|
||||
end
|
||||
|
||||
def preload_pipeline_warnings
|
||||
# This preloads the number of warnings for every pipeline, ensuring
|
||||
# that Ci::Pipeline#has_warnings? doesn't execute any additional
|
||||
|
|
@ -40,10 +48,10 @@ module Gitlab
|
|||
@pipeline.number_of_warnings
|
||||
end
|
||||
|
||||
# This preloads the number of warnings for every stage, ensuring
|
||||
# that Ci::Stage#has_warnings? doesn't execute any additional
|
||||
# queries.
|
||||
def preload_stages_warnings
|
||||
# This preloads the number of warnings for every stage, ensuring
|
||||
# that Ci::Stage#has_warnings? doesn't execute any additional
|
||||
# queries.
|
||||
@pipeline.stages.each { |stage| stage.number_of_warnings }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1008,6 +1008,12 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def list_commits_by_ref_name(refs)
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_commit_client.list_commits_by_ref_name(refs)
|
||||
end
|
||||
end
|
||||
|
||||
def last_commit_for_path(sha, path, literal_pathspec: false)
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_commit_client.last_commit_for_path(sha, path, literal_pathspec: literal_pathspec)
|
||||
|
|
|
|||
|
|
@ -391,6 +391,21 @@ module Gitlab
|
|||
messages
|
||||
end
|
||||
|
||||
def list_commits_by_ref_name(refs)
|
||||
request = Gitaly::ListCommitsByRefNameRequest
|
||||
.new(repository: @gitaly_repo, ref_names: refs)
|
||||
|
||||
response = GitalyClient.call(@repository.storage, :commit_service, :list_commits_by_ref_name, request, timeout: GitalyClient.medium_timeout)
|
||||
|
||||
commit_refs = response.flat_map do |message|
|
||||
message.commit_refs.map do |commit_ref|
|
||||
[commit_ref.ref_name, Gitlab::Git::Commit.new(@repository, commit_ref.commit)]
|
||||
end
|
||||
end
|
||||
|
||||
Hash[commit_refs]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def call_commit_diff(request_params, options = {})
|
||||
|
|
|
|||
|
|
@ -77,9 +77,9 @@ RSpec.describe Projects::PipelinesController do
|
|||
|
||||
expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
|
||||
|
||||
# ListCommitsByOid, RepositoryExists, HasLocalBranches
|
||||
# ListCommitsByOid, RepositoryExists, HasLocalBranches, ListCommitsByRefNames
|
||||
expect { get_pipelines_index_json }
|
||||
.to change { Gitlab::GitalyClient.get_request_count }.by(3)
|
||||
.to change { Gitlab::GitalyClient.get_request_count }.by(4)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -111,13 +111,15 @@ RSpec.describe Projects::PipelinesController do
|
|||
context 'scope is branches or tags' do
|
||||
before do
|
||||
create(:ci_pipeline, :failed, project: project, ref: 'v1.0.0', tag: true)
|
||||
create(:ci_pipeline, :failed, project: project, ref: 'master', tag: false)
|
||||
create(:ci_pipeline, :failed, project: project, ref: 'feature', tag: false)
|
||||
end
|
||||
|
||||
context 'when scope is branches' do
|
||||
it 'returns matched pipelines' do
|
||||
get_pipelines_index_json(scope: 'branches')
|
||||
|
||||
check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4)
|
||||
check_pipeline_response(returned: 2, all: 9, running: 2, pending: 1, finished: 6)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -125,7 +127,7 @@ RSpec.describe Projects::PipelinesController do
|
|||
it 'returns matched pipelines' do
|
||||
get_pipelines_index_json(scope: 'tags')
|
||||
|
||||
check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4)
|
||||
check_pipeline_response(returned: 1, all: 9, running: 2, pending: 1, finished: 6)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -234,7 +236,8 @@ RSpec.describe Projects::PipelinesController do
|
|||
user = create(:user)
|
||||
pipeline = create(:ci_empty_pipeline, status: status,
|
||||
project: project,
|
||||
sha: sha,
|
||||
sha: sha.id,
|
||||
ref: sha.id.first(8),
|
||||
user: user,
|
||||
merge_request: merge_request)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
|
|||
include JavaScriptFixturesHelpers
|
||||
include MetricsDashboardHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { project_with_dashboard('.gitlab/dashboards/test.yml') }
|
||||
let(:environment) { create(:environment, project: project) }
|
||||
let(:params) { { environment: environment } }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:namespace) { create(:namespace, name: 'monitoring' )}
|
||||
let_it_be(:project) { project_with_dashboard_namespace('.gitlab/dashboards/test.yml', namespace: namespace) }
|
||||
let_it_be(:environment) { create(:environment, id: 1, project: project) }
|
||||
let_it_be(:params) { { environment: environment } }
|
||||
|
||||
before(:all) do
|
||||
clean_frontend_fixtures('metrics_dashboard/')
|
||||
|
|
@ -24,6 +25,7 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
|
|||
project.add_maintainer(user)
|
||||
|
||||
allow(controller).to receive(:project).and_return(project)
|
||||
allow(controller).to receive(:environment).and_return(environment)
|
||||
allow(controller)
|
||||
.to receive(:metrics_dashboard_params)
|
||||
.and_return(params)
|
||||
|
|
@ -35,7 +37,9 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
|
|||
|
||||
it 'metrics_dashboard/environment_metrics_dashboard.json' do
|
||||
routes.draw { get "metrics_dashboard" => "anonymous#metrics_dashboard" }
|
||||
|
||||
response = get :metrics_dashboard, format: :json
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,19 @@
|
|||
exports[`Dashboard template matches the default snapshot 1`] = `
|
||||
<div
|
||||
class="prometheus-graphs"
|
||||
currentenvironmentname="environment1"
|
||||
customdashboardbasepath=".gitlab/dashboards"
|
||||
dashboardendpoint="/monitoring/monitor-project/-/environments/1/metrics_dashboard.json"
|
||||
dashboardsendpoint="/monitoring/monitor-project/-/performance_monitoring/dashboards.json"
|
||||
dashboardtimezone="LOCAL"
|
||||
data-qa-selector="prometheus_graphs"
|
||||
deploymentsendpoint="/monitoring/monitor-project/-/environments/1/deployments.json"
|
||||
environmentstate="available"
|
||||
logspath="/monitoring/monitor-project/-/logs?environment_name=environment1"
|
||||
metricsdashboardbasepath="/monitoring/monitor-project/-/environments/1/metrics"
|
||||
metricsendpoint="/monitoring/monitor-project/-/environments/1/additional_metrics.json"
|
||||
projectpath="/monitoring/monitor-project"
|
||||
prometheusstatus=""
|
||||
>
|
||||
<div
|
||||
class="prometheus-graphs-header d-sm-flex flex-sm-wrap pt-2 pr-1 pb-0 pl-2 border-bottom bg-gray-light"
|
||||
|
|
@ -135,15 +147,15 @@ exports[`Dashboard template matches the default snapshot 1`] = `
|
|||
<!---->
|
||||
|
||||
<empty-state-stub
|
||||
clusterspath="/path/to/clusters"
|
||||
documentationpath="/path/to/docs"
|
||||
emptygettingstartedsvgpath="/path/to/getting-started.svg"
|
||||
emptyloadingsvgpath="/path/to/loading.svg"
|
||||
emptynodatasmallsvgpath="/path/to/no-data-small.svg"
|
||||
emptynodatasvgpath="/path/to/no-data.svg"
|
||||
emptyunabletoconnectsvgpath="/path/to/unable-to-connect.svg"
|
||||
clusterspath="/monitoring/monitor-project/-/clusters"
|
||||
documentationpath="/help/administration/monitoring/prometheus/index.md"
|
||||
emptygettingstartedsvgpath="/images/illustrations/monitoring/getting_started.svg"
|
||||
emptyloadingsvgpath="/images/illustrations/monitoring/loading.svg"
|
||||
emptynodatasmallsvgpath="/images/illustrations/chart-empty-state-small.svg"
|
||||
emptynodatasvgpath="/images/illustrations/monitoring/no_data.svg"
|
||||
emptyunabletoconnectsvgpath="/images/illustrations/monitoring/unable_to_connect.svg"
|
||||
selectedstate="gettingStarted"
|
||||
settingspath="/path/to/settings"
|
||||
settingspath="/monitoring/monitor-project/-/services/prometheus/edit"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import {
|
|||
singleStatMetricsResult,
|
||||
graphDataPrometheusQueryRangeMultiTrack,
|
||||
barMockData,
|
||||
propsData,
|
||||
} from '../mock_data';
|
||||
import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data';
|
||||
|
||||
import { panelTypes } from '~/monitoring/constants';
|
||||
|
||||
|
|
@ -32,7 +32,6 @@ import MonitorColumnChart from '~/monitoring/components/charts/column.vue';
|
|||
import MonitorBarChart from '~/monitoring/components/charts/bar.vue';
|
||||
import MonitorStackedColumnChart from '~/monitoring/components/charts/stacked_column.vue';
|
||||
|
||||
import { graphData, graphDataEmpty } from '../fixture_data';
|
||||
import { createStore, monitoringDashboard } from '~/monitoring/stores';
|
||||
import { createStore as createEmbedGroupStore } from '~/monitoring/stores/embed_group';
|
||||
|
||||
|
|
@ -63,7 +62,7 @@ describe('Dashboard Panel', () => {
|
|||
wrapper = shallowMount(DashboardPanel, {
|
||||
propsData: {
|
||||
graphData,
|
||||
settingsPath: propsData.settingsPath,
|
||||
settingsPath: dashboardProps.settingsPath,
|
||||
...props,
|
||||
},
|
||||
store,
|
||||
|
|
@ -316,7 +315,7 @@ describe('Dashboard Panel', () => {
|
|||
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(findEditCustomMetricLink().text()).toBe('Edit metrics');
|
||||
expect(findEditCustomMetricLink().attributes('href')).toBe(propsData.settingsPath);
|
||||
expect(findEditCustomMetricLink().attributes('href')).toBe(dashboardProps.settingsPath);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -433,7 +432,7 @@ describe('Dashboard Panel', () => {
|
|||
wrapper = shallowMount(DashboardPanel, {
|
||||
propsData: {
|
||||
clipboardText: exampleText,
|
||||
settingsPath: propsData.settingsPath,
|
||||
settingsPath: dashboardProps.settingsPath,
|
||||
graphData: {
|
||||
y_label: 'metric',
|
||||
...graphData,
|
||||
|
|
@ -483,7 +482,7 @@ describe('Dashboard Panel', () => {
|
|||
wrapper = shallowMount(DashboardPanel, {
|
||||
propsData: {
|
||||
graphData,
|
||||
settingsPath: propsData.settingsPath,
|
||||
settingsPath: dashboardProps.settingsPath,
|
||||
namespace: mockNamespace,
|
||||
},
|
||||
store,
|
||||
|
|
|
|||
|
|
@ -27,8 +27,12 @@ import {
|
|||
setupStoreWithVariable,
|
||||
setupStoreWithLinks,
|
||||
} from '../store_utils';
|
||||
import { environmentData, dashboardGitResponse, propsData } from '../mock_data';
|
||||
import { metricsDashboardViewModel, metricsDashboardPanelCount } from '../fixture_data';
|
||||
import { environmentData, dashboardGitResponse } from '../mock_data';
|
||||
import {
|
||||
metricsDashboardViewModel,
|
||||
metricsDashboardPanelCount,
|
||||
dashboardProps,
|
||||
} from '../fixture_data';
|
||||
import createFlash from '~/flash';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
|
@ -48,7 +52,7 @@ describe('Dashboard', () => {
|
|||
|
||||
const createShallowWrapper = (props = {}, options = {}) => {
|
||||
wrapper = shallowMount(Dashboard, {
|
||||
propsData: { ...propsData, ...props },
|
||||
propsData: { ...dashboardProps, ...props },
|
||||
store,
|
||||
stubs: {
|
||||
DashboardHeader,
|
||||
|
|
@ -59,7 +63,7 @@ describe('Dashboard', () => {
|
|||
|
||||
const createMountedWrapper = (props = {}, options = {}) => {
|
||||
wrapper = mount(Dashboard, {
|
||||
propsData: { ...propsData, ...props },
|
||||
propsData: { ...dashboardProps, ...props },
|
||||
store,
|
||||
stubs: {
|
||||
'graph-group': true,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import Dashboard from '~/monitoring/components/dashboard.vue';
|
|||
import DashboardHeader from '~/monitoring/components/dashboard_header.vue';
|
||||
import { createStore } from '~/monitoring/stores';
|
||||
import { setupAllDashboards } from '../store_utils';
|
||||
import { propsData } from '../mock_data';
|
||||
import { dashboardProps } from '../fixture_data';
|
||||
|
||||
jest.mock('~/lib/utils/url_utility');
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ describe('Dashboard template', () => {
|
|||
|
||||
it('matches the default snapshot', () => {
|
||||
wrapper = shallowMount(Dashboard, {
|
||||
propsData: { ...propsData },
|
||||
propsData: { ...dashboardProps },
|
||||
store,
|
||||
stubs: {
|
||||
DashboardHeader,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ import {
|
|||
updateHistory,
|
||||
} from '~/lib/utils/url_utility';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { mockProjectDir, propsData } from '../mock_data';
|
||||
import { mockProjectDir } from '../mock_data';
|
||||
import { dashboardProps } from '../fixture_data';
|
||||
|
||||
import Dashboard from '~/monitoring/components/dashboard.vue';
|
||||
import DashboardHeader from '~/monitoring/components/dashboard_header.vue';
|
||||
|
|
@ -26,7 +27,7 @@ describe('dashboard invalid url parameters', () => {
|
|||
|
||||
const createMountedWrapper = (props = { hasMetrics: true }, options = {}) => {
|
||||
wrapper = mount(Dashboard, {
|
||||
propsData: { ...propsData, ...props },
|
||||
propsData: { ...dashboardProps, ...props },
|
||||
store,
|
||||
stubs: { 'graph-group': true, 'dashboard-panel': true, 'dashboard-header': DashboardHeader },
|
||||
...options,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { mapToDashboardViewModel } from '~/monitoring/stores/utils';
|
||||
import { metricStates } from '~/monitoring/constants';
|
||||
import { parseBoolean, convertObjectProps } from '~/lib/utils/common_utils';
|
||||
import { convertToCamelCase } from '~/lib/utils/text_utility';
|
||||
|
||||
import { metricsResult } from './mock_data';
|
||||
|
||||
|
|
@ -8,6 +10,20 @@ export const metricsDashboardResponse = getJSONFixture(
|
|||
'metrics_dashboard/environment_metrics_dashboard.json',
|
||||
);
|
||||
export const metricsDashboardPayload = metricsDashboardResponse.dashboard;
|
||||
|
||||
const metricsData = convertObjectProps(
|
||||
// Some props use kebab-case, convert to snake_case first
|
||||
key => convertToCamelCase(key.replace(/-/g, '_')),
|
||||
metricsDashboardResponse.metrics_data,
|
||||
);
|
||||
|
||||
export const dashboardProps = {
|
||||
...metricsData,
|
||||
hasMetrics: parseBoolean(metricsData.hasMetrics),
|
||||
customMetricsAvailable: parseBoolean(metricsData.customMetricsAvailable),
|
||||
prometheusAlertsAvailable: parseBoolean(metricsData.prometheusAlertsAvailable),
|
||||
};
|
||||
|
||||
export const metricsDashboardViewModel = mapToDashboardViewModel(metricsDashboardPayload);
|
||||
|
||||
export const metricsDashboardPanelCount = 22;
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import MockAdapter from 'axios-mock-adapter';
|
|||
import Dashboard from '~/monitoring/components/dashboard.vue';
|
||||
import { createStore } from '~/monitoring/stores';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { mockApiEndpoint, propsData } from '../mock_data';
|
||||
import { metricsDashboardPayload } from '../fixture_data';
|
||||
import { mockApiEndpoint } from '../mock_data';
|
||||
import { metricsDashboardPayload, dashboardProps } from '../fixture_data';
|
||||
import { setupStoreWithData } from '../store_utils';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
|
|
@ -56,7 +56,7 @@ describe('Dashboard', () => {
|
|||
component = new DashboardComponent({
|
||||
el: document.querySelector('.prometheus-graphs'),
|
||||
propsData: {
|
||||
...propsData,
|
||||
...dashboardProps,
|
||||
hasMetrics: true,
|
||||
showPanels: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ describe Gitlab::Ci::Pipeline::Preloader do
|
|||
end
|
||||
end
|
||||
|
||||
it 'preloads commit authors and number of warnings' do
|
||||
it 'preloads commit authors, number of warnings and ref commits' do
|
||||
expect(commit).to receive(:lazy_author)
|
||||
expect(pipeline).to receive(:lazy_ref_commit)
|
||||
expect(pipeline).to receive(:number_of_warnings)
|
||||
expect(stage).to receive(:number_of_warnings)
|
||||
|
||||
|
|
@ -38,6 +39,7 @@ describe Gitlab::Ci::Pipeline::Preloader do
|
|||
|
||||
it 'returns original collection' do
|
||||
allow(commit).to receive(:lazy_author)
|
||||
allow(pipeline).to receive(:lazy_ref_commit)
|
||||
allow(pipeline).to receive(:number_of_warnings)
|
||||
allow(stage).to receive(:number_of_warnings)
|
||||
|
||||
|
|
|
|||
|
|
@ -381,4 +381,15 @@ describe Gitlab::GitalyClient::CommitService do
|
|||
commits.map { |commit| Gitlab::Git::Commit.new(repository, commit) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#list_commits_by_ref_name' do
|
||||
it 'lists latest commits grouped by a ref name' do
|
||||
response = client.list_commits_by_ref_name(%w[master feature v1.0.0 nonexistent])
|
||||
|
||||
expect(response.fetch('master').id).to eq 'b83d6e391c22777fca1ed3012fce84f633d7fed0'
|
||||
expect(response.fetch('feature').id).to eq '0b4bc9a49b562e85de7cc9e834518ea6828729b9'
|
||||
expect(response.fetch('v1.0.0').id).to eq '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9'
|
||||
expect(response).not_to have_key 'nonexistent'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -337,4 +337,22 @@ describe AlertManagement::Alert do
|
|||
expect { subject }.to change { alert.events }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#present' do
|
||||
context 'when alert is generic' do
|
||||
let(:alert) { build(:alert_management_alert) }
|
||||
|
||||
it 'uses generic alert presenter' do
|
||||
expect(alert.present).to be_kind_of(AlertManagement::AlertPresenter)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when alert is Prometheus specific' do
|
||||
let(:alert) { build(:alert_management_alert, :prometheus) }
|
||||
|
||||
it 'uses Prometheus Alert presenter' do
|
||||
expect(alert.present).to be_kind_of(AlertManagement::PrometheusAlertPresenter)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1488,6 +1488,12 @@ describe Ci::Pipeline, :mailer do
|
|||
sha: project.commit.sha)
|
||||
end
|
||||
|
||||
describe '#lazy_ref_commit' do
|
||||
it 'returns the latest commit for a ref lazily' do
|
||||
expect(pipeline.lazy_ref_commit.id).to eq project.commit(pipeline.ref).id
|
||||
end
|
||||
end
|
||||
|
||||
describe '#latest?' do
|
||||
context 'with latest sha' do
|
||||
it 'returns true' do
|
||||
|
|
@ -1496,17 +1502,26 @@ describe Ci::Pipeline, :mailer do
|
|||
end
|
||||
|
||||
context 'with a branch name as the ref' do
|
||||
it 'looks up commit with the full ref name' do
|
||||
expect(pipeline.project).to receive(:commit).with('refs/heads/master').and_call_original
|
||||
it 'looks up a commit for a branch' do
|
||||
expect(pipeline.ref).to eq 'master'
|
||||
expect(pipeline).to be_latest
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a tag name as a ref' do
|
||||
it 'looks up a commit for a tag' do
|
||||
expect(project.repository.branch_names).not_to include 'v1.0.0'
|
||||
|
||||
pipeline.update(sha: project.commit('v1.0.0').sha, ref: 'v1.0.0', tag: true)
|
||||
|
||||
expect(pipeline).to be_tag
|
||||
expect(pipeline).to be_latest
|
||||
end
|
||||
end
|
||||
|
||||
context 'with not latest sha' do
|
||||
before do
|
||||
pipeline.update(
|
||||
sha: project.commit("#{project.default_branch}~1").sha)
|
||||
pipeline.update(sha: project.commit("#{project.default_branch}~1").sha)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Integration do
|
||||
let(:project_1) { create(:project) }
|
||||
let(:project_2) { create(:project) }
|
||||
let!(:project_1) { create(:project) }
|
||||
let!(:project_2) { create(:project) }
|
||||
let!(:project_3) { create(:project) }
|
||||
let(:instance_integration) { create(:jira_service, :instance) }
|
||||
|
||||
before do
|
||||
|
|
@ -18,4 +19,10 @@ RSpec.describe Integration do
|
|||
expect(Project.with_custom_integration_for(instance_integration)).to contain_exactly(project_2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ids_without_integration' do
|
||||
it 'returns projects ids without an integration' do
|
||||
expect(Project.ids_without_integration(instance_integration, 100)).to contain_exactly(project_3.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe AlertManagement::AlertPresenter do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:generic_payload) do
|
||||
{
|
||||
'title' => 'Alert title',
|
||||
'start_time' => '2020-04-27T10:10:22.265949279Z',
|
||||
'custom' => { 'param' => 73 }
|
||||
}
|
||||
end
|
||||
let_it_be(:alert) do
|
||||
create(:alert_management_alert, :with_host, :with_service, :with_monitoring_tool, project: project, payload: generic_payload)
|
||||
end
|
||||
|
||||
subject(:presenter) { described_class.new(alert) }
|
||||
|
||||
describe '#issue_description' do
|
||||
let(:markdown_line_break) { ' ' }
|
||||
|
||||
it 'returns an alert issue description' do
|
||||
expect(presenter.issue_description).to eq(
|
||||
<<~MARKDOWN.chomp
|
||||
#### Summary
|
||||
|
||||
**Start time:** #{presenter.start_time}#{markdown_line_break}
|
||||
**Severity:** #{presenter.severity}#{markdown_line_break}
|
||||
**Service:** #{alert.service}#{markdown_line_break}
|
||||
**Monitoring tool:** #{alert.monitoring_tool}#{markdown_line_break}
|
||||
**Hosts:** #{alert.hosts.join(' ')}
|
||||
|
||||
#### Alert Details
|
||||
|
||||
**custom.param:** 73
|
||||
MARKDOWN
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe AlertManagement::PrometheusAlertPresenter do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:prometheus_payload) do
|
||||
{
|
||||
'annotations' => {
|
||||
'title' => 'Alert title',
|
||||
'gitlab_incident_markdown' => '**`markdown example`**',
|
||||
'custom annotation' => 'custom annotation value'
|
||||
},
|
||||
'startsAt' => '2020-04-27T10:10:22.265949279Z',
|
||||
'generatorURL' => 'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1'
|
||||
}
|
||||
end
|
||||
let_it_be(:alert) do
|
||||
create(:alert_management_alert, :prometheus, project: project, payload: prometheus_payload)
|
||||
end
|
||||
|
||||
subject(:presenter) { described_class.new(alert) }
|
||||
|
||||
describe '#issue_description' do
|
||||
let(:markdown_line_break) { ' ' }
|
||||
|
||||
it 'returns an alert issue description' do
|
||||
expect(presenter.issue_description).to eq(
|
||||
<<~MARKDOWN.chomp
|
||||
#### Summary
|
||||
|
||||
**Start time:** #{presenter.start_time}#{markdown_line_break}
|
||||
**Severity:** #{presenter.severity}#{markdown_line_break}
|
||||
**full_query:** `vector(1)`#{markdown_line_break}
|
||||
**Monitoring tool:** Prometheus
|
||||
|
||||
#### Alert Details
|
||||
|
||||
**custom annotation:** custom annotation value
|
||||
|
||||
---
|
||||
|
||||
**`markdown example`**
|
||||
MARKDOWN
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -8,10 +8,6 @@ RSpec.describe AlertManagement::CreateAlertIssueService do
|
|||
let_it_be(:project) { create(:project, group: group) }
|
||||
let_it_be(:payload) do
|
||||
{
|
||||
'title' => 'Alert title',
|
||||
'annotations' => {
|
||||
'title' => 'Alert title'
|
||||
},
|
||||
'startsAt' => '2020-04-27T10:10:22.265949279Z',
|
||||
'generatorURL' => 'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1'
|
||||
}
|
||||
|
|
@ -19,6 +15,7 @@ RSpec.describe AlertManagement::CreateAlertIssueService do
|
|||
let_it_be(:generic_alert, reload: true) { create(:alert_management_alert, :triggered, project: project, payload: payload) }
|
||||
let_it_be(:prometheus_alert, reload: true) { create(:alert_management_alert, :triggered, :prometheus, project: project, payload: payload) }
|
||||
let(:alert) { generic_alert }
|
||||
let(:alert_presenter) { alert.present }
|
||||
let(:created_issue) { Issue.last! }
|
||||
|
||||
describe '#execute' do
|
||||
|
|
@ -61,7 +58,7 @@ RSpec.describe AlertManagement::CreateAlertIssueService do
|
|||
end
|
||||
|
||||
it 'sets the issue title' do
|
||||
expect(created_issue.title).to eq(alert_presenter.title)
|
||||
expect(created_issue.title).to eq(alert.title)
|
||||
end
|
||||
|
||||
it 'sets the issue description' do
|
||||
|
|
@ -165,9 +162,6 @@ RSpec.describe AlertManagement::CreateAlertIssueService do
|
|||
|
||||
context 'when the alert is prometheus alert' do
|
||||
let(:alert) { prometheus_alert }
|
||||
let(:alert_presenter) do
|
||||
Gitlab::Alerting::Alert.new(project: project, payload: alert.payload).present
|
||||
end
|
||||
|
||||
it_behaves_like 'creating an alert issue'
|
||||
it_behaves_like 'setting an issue attributes'
|
||||
|
|
@ -176,10 +170,6 @@ RSpec.describe AlertManagement::CreateAlertIssueService do
|
|||
|
||||
context 'when the alert is generic' do
|
||||
let(:alert) { generic_alert }
|
||||
let(:alert_presenter) do
|
||||
alert_payload = Gitlab::Alerting::NotificationPayloadParser.call(alert.payload.to_h)
|
||||
Gitlab::Alerting::Alert.new(project: project, payload: alert_payload).present
|
||||
end
|
||||
|
||||
it_behaves_like 'creating an alert issue'
|
||||
it_behaves_like 'setting an issue attributes'
|
||||
|
|
@ -187,11 +177,11 @@ RSpec.describe AlertManagement::CreateAlertIssueService do
|
|||
end
|
||||
|
||||
context 'when issue cannot be created' do
|
||||
let(:alert) { prometheus_alert }
|
||||
let(:alert) { generic_alert }
|
||||
|
||||
before do
|
||||
# set invalid payload for Prometheus alert
|
||||
alert.update!(payload: {})
|
||||
# Invalid alert
|
||||
alert.update_columns(title: '')
|
||||
end
|
||||
|
||||
it 'has an unsuccessful status' do
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@ module MetricsDashboardHelpers
|
|||
create(:project, :custom_repo, files: { dashboard_path => dashboard_yml })
|
||||
end
|
||||
|
||||
def project_with_dashboard_namespace(dashboard_path, dashboard_yml = nil)
|
||||
dashboard_yml ||= fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml')
|
||||
|
||||
create(:project, :custom_repo, namespace: namespace, path: 'monitor-project', files: { dashboard_path => dashboard_yml })
|
||||
end
|
||||
|
||||
def delete_project_dashboard(project, user, dashboard_path)
|
||||
project.repository.delete_file(
|
||||
user,
|
||||
|
|
|
|||
Loading…
Reference in New Issue