Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-15 12:09:34 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-15 12:09:34 +0300
commita898b6057ecf9ab635c45217568d44eab5c32ec0 (patch)
treecaf9dbacd3058a6714478ea16b9bd54b2ac463ce
parent7d5d23819bd51063dc641c29bff7b334cea83d84 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/CODEOWNERS11
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue2
-rw-r--r--app/assets/javascripts/jobs/components/manual_variables_form.vue8
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue21
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard_header.vue9
-rw-r--r--app/assets/javascripts/monitoring/components/empty_state.vue67
-rw-r--r--app/assets/javascripts/monitoring/components/graph_group.vue17
-rw-r--r--app/assets/javascripts/monitoring/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/monitoring/stores/mutations.js12
-rw-r--r--app/assets/javascripts/monitoring/stores/state.js7
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue2
-rw-r--r--app/assets/javascripts/releases/components/release_block_header.vue2
-rw-r--r--app/assets/javascripts/reports/components/grouped_test_reports_app.vue7
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue2
-rw-r--r--app/assets/stylesheets/framework/common.scss1
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/pages/runners.scss3
-rw-r--r--app/graphql/mutations/notes/create/base.rb8
-rw-r--r--app/graphql/mutations/snippets/create.rb4
-rw-r--r--app/graphql/mutations/snippets/update.rb4
-rw-r--r--app/helpers/environments_helper.rb17
-rw-r--r--app/presenters/clusters/cluster_presenter.rb2
-rw-r--r--app/services/concerns/incident_management/settings.rb2
-rw-r--r--app/services/incident_management/pager_duty/create_incident_issue_service.rb72
-rw-r--r--app/services/snippets/base_service.rb16
-rw-r--r--app/services/snippets/create_service.rb6
-rw-r--r--app/services/snippets/update_service.rb8
-rw-r--r--app/views/admin/runners/_runner.html.haml4
-rw-r--r--app/views/ci/group_variables/_index.html.haml4
-rw-r--r--app/views/ci/group_variables/_variable_header.html.haml4
-rw-r--r--app/views/ci/variables/_environment_scope_header.html.haml2
-rw-r--r--app/views/ci/variables/_variable_header.html.haml6
-rw-r--r--app/views/profiles/active_sessions/_active_session.html.haml2
-rw-r--r--app/views/profiles/gpg_keys/_key.html.haml2
-rw-r--r--app/views/profiles/keys/_key.html.haml6
-rw-r--r--app/views/profiles/passwords/edit.html.haml2
-rw-r--r--app/views/profiles/two_factor_auths/_codes.html.haml2
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml2
-rw-r--r--app/views/projects/blob/_editor.html.haml4
-rw-r--r--app/views/projects/commit/_commit_box.html.haml4
-rw-r--r--app/views/projects/issues/_nav_btns.html.haml2
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml2
-rw-r--r--app/views/projects/merge_requests/_nav_btns.html.haml2
-rw-r--r--app/views/projects/mirrors/_ssh_host_keys.html.haml2
-rw-r--r--app/views/projects/no_repo.html.haml2
-rw-r--r--app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml4
-rw-r--r--app/views/projects/project_templates/_built_in_templates.html.haml4
-rw-r--r--app/views/projects/project_templates/_project_fields_form.html.haml2
-rw-r--r--app/views/sent_notifications/unsubscribe.html.haml4
-rw-r--r--app/views/shared/groups/_dropdown.html.haml2
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--app/views/shared/milestones/_deprecation_message.html.haml2
-rw-r--r--app/views/shared/notes/_comment_button.html.haml2
-rw-r--r--app/views/shared/projects/_project.html.haml4
-rw-r--r--app/workers/all_queues.yml16
-rw-r--r--app/workers/incident_management/pager_duty/process_incident_worker.rb42
-rw-r--r--changelogs/unreleased/207473-create-confidential-notes-graphql.yml5
-rw-r--r--changelogs/unreleased/217758-reduce-metrics-dashboard-loading.yml6
-rw-r--r--changelogs/unreleased/225933-fa-play-replacement.yml5
-rw-r--r--changelogs/unreleased/sh-update-grape-1-4-0.yml5
-rw-r--r--changelogs/unreleased/test-report-link-fix.yml5
-rw-r--r--config/initializers/grape_patch.rb31
-rw-r--r--doc/.vale/gitlab/AlertBoxStyle.yml13
-rw-r--r--doc/administration/auth/ldap/index.md2
-rw-r--r--doc/administration/reference_architectures/2k_users.md2
-rw-r--r--doc/administration/uploads.md2
-rw-r--r--doc/api/boards.md2
-rw-r--r--doc/api/epics.md2
-rw-r--r--doc/api/feature_flags.md2
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql15
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json30
-rw-r--r--doc/api/issues.md6
-rw-r--r--doc/api/merge_requests.md2
-rw-r--r--doc/api/releases/links.md2
-rw-r--r--doc/ci/README.md6
-rw-r--r--doc/ci/docker/using_docker_build.md2
-rw-r--r--doc/ci/environments/protected_environments.md2
-rw-r--r--doc/ci/introduction/index.md6
-rw-r--r--doc/ci/merge_request_pipelines/index.md2
-rw-r--r--doc/ci/pipelines/settings.md2
-rw-r--r--doc/ci/yaml/README.md2
-rw-r--r--doc/development/changelog.md7
-rw-r--r--doc/development/documentation/styleguide.md2
-rw-r--r--doc/development/elasticsearch.md5
-rw-r--r--doc/install/aws/index.md6
-rw-r--r--doc/integration/elasticsearch.md4
-rw-r--r--doc/integration/jira_development_panel.md6
-rw-r--r--doc/migrate_ci_to_ce/README.md2
-rw-r--r--doc/operations/metrics/index.md2
-rw-r--r--doc/policy/maintenance.md2
-rw-r--r--doc/raketasks/backup_restore.md24
-rw-r--r--doc/topics/autodevops/index.md2
-rw-r--r--doc/topics/autodevops/stages.md2
-rw-r--r--doc/topics/web_application_firewall/index.md4
-rw-r--r--doc/update/upgrading_from_ce_to_ee.md2
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md4
-rw-r--r--doc/user/application_security/configuration/index.md2
-rw-r--r--doc/user/application_security/dast/index.md6
-rw-r--r--doc/user/application_security/img/security_configuration_page_v13_1.pngbin199472 -> 0 bytes
-rw-r--r--doc/user/application_security/img/security_configuration_page_v13_2.pngbin0 -> 51691 bytes
-rw-r--r--doc/user/application_security/sast/index.md6
-rw-r--r--doc/user/packages/conan_repository/index.md8
-rw-r--r--doc/user/project/clusters/add_remove_clusters.md8
-rw-r--r--doc/user/project/clusters/index.md2
-rw-r--r--doc/user/project/clusters/kubernetes_pod_logs.md4
-rw-r--r--doc/user/project/code_owners.md2
-rw-r--r--doc/user/project/integrations/generic_alerts.md2
-rw-r--r--doc/user/project/integrations/jira_cloud_configuration.md2
-rw-r--r--doc/user/project/integrations/jira_server_configuration.md2
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/index.md2
-rw-r--r--doc/user/project/repository/reducing_the_repo_size_using_git.md2
-rw-r--r--lib/api/helpers.rb2
-rw-r--r--lib/gitlab/incident_management/pager_duty/incident_issue_description.rb64
-rw-r--r--lib/gitlab/instrumentation/redis_base.rb3
-rw-r--r--lib/gitlab/usage_data.rb2
-rw-r--r--lib/pager_duty/webhook_payload_parser.rb66
-rw-r--r--lib/peek/views/elasticsearch.rb2
-rw-r--r--locale/gitlab.pot20
-rw-r--r--spec/factories/projects.rb7
-rw-r--r--spec/fixtures/pager_duty/webhook_incident_trigger.json239
-rw-r--r--spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap4
-rw-r--r--spec/frontend/monitoring/components/__snapshots__/empty_state_spec.js.snap78
-rw-r--r--spec/frontend/monitoring/components/dashboard_spec.js39
-rw-r--r--spec/frontend/monitoring/components/empty_state_spec.js14
-rw-r--r--spec/frontend/monitoring/components/graph_group_spec.js120
-rw-r--r--spec/frontend/monitoring/components/links_section_spec.js2
-rw-r--r--spec/frontend/monitoring/components/variables_section_spec.js4
-rw-r--r--spec/frontend/monitoring/store/mutations_spec.js27
-rw-r--r--spec/frontend/reports/components/grouped_test_reports_app_spec.js1
-rw-r--r--spec/helpers/environments_helper_spec.rb24
-rw-r--r--spec/lib/gitlab/incident_management/pager_duty/incident_issue_description_spec.rb97
-rw-r--r--spec/lib/pager_duty/webhook_payload_parser_spec.rb80
-rw-r--r--spec/presenters/clusters/cluster_presenter_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/note_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/snippets/create_spec.rb2
-rw-r--r--spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb104
-rw-r--r--spec/services/snippets/create_service_spec.rb24
-rw-r--r--spec/services/snippets/update_service_spec.rb68
-rw-r--r--spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb57
-rw-r--r--symbol/icons.svg1
-rw-r--r--symbol/sprite.symbol.html177
148 files changed, 1486 insertions, 602 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 79e4d4925f1..4e2c4aa5c76 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -50,11 +50,6 @@
/ee/app/models/project_alias.rb @patrickbajao
/ee/lib/api/project_aliases.rb @patrickbajao
-# Code Owners
-#
-/ee/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
-/doc/user/project/code_owners.md @reprazent @kerrizor @garyh
-
# Quality owned files
/qa/ @gl-quality
@@ -78,3 +73,9 @@ Dangerfile @gl-quality/eng-prod
/lib/gitlab/usage_data.rb @gitlab-org/growth/telemetry
/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/telemetry
/lib/gitlab/usage_data_counters/ @gitlab-org/growth/telemetry
+
+[Code Owners]
+/ee/lib/gitlab/code_owners.rb @reprazent @kerrizor @garyh
+/ee/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
+/ee/spec/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
+/doc/user/project/code_owners.md @reprazent @kerrizor @garyh
diff --git a/Gemfile b/Gemfile
index 2bfc9d69660..e69cf8c2dce 100644
--- a/Gemfile
+++ b/Gemfile
@@ -81,7 +81,9 @@ gem 'gitlab_omniauth-ldap', '~> 2.1.1', require: 'omniauth-ldap'
gem 'net-ldap'
# API
-gem 'grape', '~> 1.3.3'
+# Locked at Grape v1.4.0 until https://github.com/ruby-grape/grape/pull/2088 is merged
+# Remove config/initializers/grape_patch.rb
+gem 'grape', '= 1.4.0'
gem 'grape-entity', '~> 0.7.1'
gem 'rack-cors', '~> 1.0.6', require: 'rack/cors'
diff --git a/Gemfile.lock b/Gemfile.lock
index ffd39ac85ed..c1ea8ab4e1e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -453,7 +453,7 @@ GEM
signet (~> 0.14)
gpgme (2.0.20)
mini_portile2 (~> 2.3)
- grape (1.3.3)
+ grape (1.4.0)
activesupport
builder
dry-types (>= 1.1)
@@ -1269,7 +1269,7 @@ DEPENDENCIES
google-api-client (~> 0.33)
google-protobuf (~> 3.8.0)
gpgme (~> 2.0.19)
- grape (~> 1.3.3)
+ grape (= 1.4.0)
grape-entity (~> 0.7.1)
grape-path-helpers (~> 1.3)
grape_logging (~> 1.7)
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index 80db9930259..dbe3e0790f6 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -233,7 +233,7 @@ export default {
</script>
<template>
- <div class="boards-switcher js-boards-selector append-right-10">
+ <div class="boards-switcher js-boards-selector gl-mr-3">
<span class="boards-selector-wrapper js-boards-selector-wrapper">
<gl-dropdown
data-qa-selector="boards_dropdown"
diff --git a/app/assets/javascripts/jobs/components/manual_variables_form.vue b/app/assets/javascripts/jobs/components/manual_variables_form.vue
index 9163e7a87f1..d83c598dd48 100644
--- a/app/assets/javascripts/jobs/components/manual_variables_form.vue
+++ b/app/assets/javascripts/jobs/components/manual_variables_form.vue
@@ -112,7 +112,7 @@ export default {
<div v-for="variable in variables" :key="variable.id" class="gl-responsive-table-row">
<div class="table-section section-50">
<div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Key') }}</div>
- <div class="table-mobile-content append-right-10">
+ <div class="table-mobile-content gl-mr-3">
<input
:ref="`${$options.inputTypes.key}-${variable.id}`"
v-model="variable.key"
@@ -124,7 +124,7 @@ export default {
<div class="table-section section-50">
<div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Value') }}</div>
- <div class="table-mobile-content append-right-10">
+ <div class="table-mobile-content gl-mr-3">
<input
:ref="`${$options.inputTypes.value}-${variable.id}`"
v-model="variable.secret_value"
@@ -149,7 +149,7 @@ export default {
<div class="gl-responsive-table-row">
<div class="table-section section-50">
<div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Key') }}</div>
- <div class="table-mobile-content append-right-10">
+ <div class="table-mobile-content gl-mr-3">
<input
ref="inputKey"
v-model="key"
@@ -161,7 +161,7 @@ export default {
<div class="table-section section-50">
<div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Value') }}</div>
- <div class="table-mobile-content append-right-10">
+ <div class="table-mobile-content gl-mr-3">
<input
ref="inputSecretValue"
v-model="secretValue"
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index f685d67751c..bde62275797 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -161,7 +161,6 @@ export default {
...mapState('monitoringDashboard', [
'dashboard',
'emptyState',
- 'showEmptyState',
'expandedPanel',
'variables',
'links',
@@ -169,6 +168,9 @@ export default {
'hasDashboardValidationWarnings',
]),
...mapGetters('monitoringDashboard', ['selectedDashboard', 'getMetricStates']),
+ shouldShowEmptyState() {
+ return Boolean(this.emptyState);
+ },
shouldShowVariablesSection() {
return Boolean(this.variables.length);
},
@@ -278,6 +280,14 @@ export default {
return null;
},
/**
+ * Return true if the entire group is loading.
+ * @param {String} groupKey - Identifier for group
+ * @returns {boolean}
+ */
+ isGroupLoading(groupKey) {
+ return this.groupSingleEmptyState(groupKey) === metricStates.LOADING;
+ },
+ /**
* A group should be not collapsed if any metric is loaded (OK)
*
* @param {String} groupKey - Identifier for group
@@ -412,9 +422,9 @@ export default {
@dateTimePickerInvalid="onDateTimePickerInvalid"
@setRearrangingPanels="onSetRearrangingPanels"
/>
- <variables-section v-if="shouldShowVariablesSection && !showEmptyState" />
- <links-section v-if="shouldShowLinksSection && !showEmptyState" />
- <div v-if="!showEmptyState">
+ <template v-if="!shouldShowEmptyState">
+ <variables-section v-if="shouldShowVariablesSection" />
+ <links-section v-if="shouldShowLinksSection" />
<dashboard-panel
v-show="expandedPanel.panel"
ref="expandedPanel"
@@ -449,6 +459,7 @@ export default {
:key="`${groupData.group}.${groupData.priority}`"
:name="groupData.group"
:show-panels="showPanels"
+ :is-loading="isGroupLoading(groupData.key)"
:collapse-group="collapseGroup(groupData.key)"
>
<vue-draggable
@@ -506,7 +517,7 @@ export default {
</div>
</graph-group>
</div>
- </div>
+ </template>
<empty-state
v-else
:selected-state="emptyState"
diff --git a/app/assets/javascripts/monitoring/components/dashboard_header.vue b/app/assets/javascripts/monitoring/components/dashboard_header.vue
index 1d929b3b558..ae8c586ff8c 100644
--- a/app/assets/javascripts/monitoring/components/dashboard_header.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard_header.vue
@@ -119,10 +119,10 @@ export default {
},
computed: {
...mapState('monitoringDashboard', [
+ 'emptyState',
'environmentsLoading',
'currentEnvironmentName',
'isUpdatingStarredValue',
- 'showEmptyState',
'dashboardTimezone',
'projectPath',
'canAccessOperationsSettings',
@@ -132,13 +132,16 @@ export default {
isOutOfTheBoxDashboard() {
return this.selectedDashboard?.out_of_the_box_dashboard;
},
+ shouldShowEmptyState() {
+ return Boolean(this.emptyState);
+ },
shouldShowEnvironmentsDropdownNoMatchedMsg() {
return !this.environmentsLoading && this.filteredEnvironments.length === 0;
},
addingMetricsAvailable() {
return (
this.customMetricsAvailable &&
- !this.showEmptyState &&
+ !this.shouldShowEmptyState &&
// Custom metrics only avaialble on system dashboards because
// they are stored in the database. This can be improved. See:
// https://gitlab.com/gitlab-org/gitlab/-/issues/28241
@@ -146,7 +149,7 @@ export default {
);
},
showRearrangePanelsBtn() {
- return !this.showEmptyState && this.rearrangePanelsAvailable;
+ return !this.shouldShowEmptyState && this.rearrangePanelsAvailable;
},
displayUtc() {
return this.dashboardTimezone === timezones.UTC;
diff --git a/app/assets/javascripts/monitoring/components/empty_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue
index 000420e2662..5e7c9b5d906 100644
--- a/app/assets/javascripts/monitoring/components/empty_state.vue
+++ b/app/assets/javascripts/monitoring/components/empty_state.vue
@@ -1,13 +1,19 @@
<script>
-import { GlEmptyState } from '@gitlab/ui';
+import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
import { __ } from '~/locale';
import { dashboardEmptyStates } from '../constants';
export default {
components: {
+ GlLoadingIcon,
GlEmptyState,
},
props: {
+ selectedState: {
+ type: String,
+ required: true,
+ validator: state => Object.values(dashboardEmptyStates).includes(state),
+ },
documentationPath: {
type: String,
required: true,
@@ -22,10 +28,6 @@ export default {
required: false,
default: '',
},
- selectedState: {
- type: String,
- required: true,
- },
emptyGettingStartedSvgPath: {
type: String,
required: true,
@@ -54,52 +56,49 @@ export default {
},
data() {
return {
+ /**
+ * Possible empty states.
+ * Keys in each state must match GlEmptyState props
+ */
states: {
[dashboardEmptyStates.GETTING_STARTED]: {
- svgUrl: this.emptyGettingStartedSvgPath,
+ svgPath: this.emptyGettingStartedSvgPath,
title: __('Get started with performance monitoring'),
description: __(`Stay updated about the performance and health
of your environment by configuring Prometheus to monitor your deployments.`),
- buttonText: __('Install on clusters'),
- buttonPath: this.clustersPath,
+ primaryButtonText: __('Install on clusters'),
+ primaryButtonLink: this.clustersPath,
secondaryButtonText: __('Configure existing installation'),
- secondaryButtonPath: this.settingsPath,
- },
- [dashboardEmptyStates.LOADING]: {
- svgUrl: this.emptyLoadingSvgPath,
- title: __('Waiting for performance data'),
- description: __(`Creating graphs uses the data from the Prometheus server.
- If this takes a long time, ensure that data is available.`),
- buttonText: __('View documentation'),
- buttonPath: this.documentationPath,
- secondaryButtonText: '',
- secondaryButtonPath: '',
+ secondaryButtonLink: this.settingsPath,
},
[dashboardEmptyStates.NO_DATA]: {
- svgUrl: this.emptyNoDataSvgPath,
+ svgPath: this.emptyNoDataSvgPath,
title: __('No data found'),
description: __(`You are connected to the Prometheus server, but there is currently
no data to display.`),
- buttonText: __('Configure Prometheus'),
- buttonPath: this.settingsPath,
+ primaryButtonText: __('Configure Prometheus'),
+ primaryButtonLink: this.settingsPath,
secondaryButtonText: '',
- secondaryButtonPath: '',
+ secondaryButtonLink: '',
},
[dashboardEmptyStates.UNABLE_TO_CONNECT]: {
- svgUrl: this.emptyUnableToConnectSvgPath,
+ svgPath: this.emptyUnableToConnectSvgPath,
title: __('Unable to connect to Prometheus server'),
description: __(
'Ensure connectivity is available from the GitLab server to the Prometheus server',
),
- buttonText: __('View documentation'),
- buttonPath: this.documentationPath,
+ primaryButtonText: __('View documentation'),
+ primaryButtonLink: this.documentationPath,
secondaryButtonText: __('Configure Prometheus'),
- secondaryButtonPath: this.settingsPath,
+ secondaryButtonLink: this.settingsPath,
},
},
};
},
computed: {
+ isLoading() {
+ return this.selectedState === dashboardEmptyStates.LOADING;
+ },
currentState() {
return this.states[this.selectedState];
},
@@ -108,14 +107,8 @@ export default {
</script>
<template>
- <gl-empty-state
- :title="currentState.title"
- :description="currentState.description"
- :primary-button-text="currentState.buttonText"
- :primary-button-link="currentState.buttonPath"
- :secondary-button-text="currentState.secondaryButtonText"
- :secondary-button-link="currentState.secondaryButtonPath"
- :svg-path="currentState.svgUrl"
- :compact="compact"
- />
+ <div>
+ <gl-loading-icon v-if="isLoading" size="xl" class="gl-my-9" />
+ <gl-empty-state v-if="currentState" v-bind="currentState" :compact="compact" />
+ </div>
</template>
diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue
index 2d3a839d826..ecb8ef4a0d0 100644
--- a/app/assets/javascripts/monitoring/components/graph_group.vue
+++ b/app/assets/javascripts/monitoring/components/graph_group.vue
@@ -1,9 +1,10 @@
<script>
-import Icon from '~/vue_shared/components/icon.vue';
+import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
export default {
components: {
- Icon,
+ GlLoadingIcon,
+ GlIcon,
},
props: {
name: {
@@ -15,6 +16,11 @@ export default {
required: false,
default: true,
},
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
/**
* Initial value of collapse on mount.
*/
@@ -55,15 +61,18 @@ export default {
<div v-if="showPanels" ref="graph-group" class="card prometheus-panel">
<div class="card-header d-flex align-items-center">
<h4 class="flex-grow-1">{{ name }}</h4>
+ <gl-loading-icon v-if="isLoading" name="loading" />
<a
data-testid="group-toggle-button"
+ :aria-label="__('Toggle collapse')"
+ :icon="caretIcon"
role="button"
- class="js-graph-group-toggle gl-text-gray-900"
+ class="js-graph-group-toggle gl-display-flex gl-ml-2 gl-text-gray-900"
tabindex="0"
@click="collapse"
@keyup.enter="collapse"
>
- <icon :size="16" :aria-label="__('Toggle collapse')" :name="caretIcon" />
+ <gl-icon :name="caretIcon" />
</a>
</div>
<div
diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js
index 72b48c251ae..e1fa037c5bb 100644
--- a/app/assets/javascripts/monitoring/stores/mutation_types.js
+++ b/app/assets/javascripts/monitoring/stores/mutation_types.js
@@ -40,7 +40,6 @@ export const SET_ALL_DASHBOARDS = 'SET_ALL_DASHBOARDS';
export const SET_ENDPOINTS = 'SET_ENDPOINTS';
export const SET_INITIAL_STATE = 'SET_INITIAL_STATE';
export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE';
-export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE';
export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER';
export const SET_PANEL_GROUP_METRICS = 'SET_PANEL_GROUP_METRICS';
export const SET_ENVIRONMENTS_FILTER = 'SET_ENVIRONMENTS_FILTER';
diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js
index 73d95f6638d..28c6b14a029 100644
--- a/app/assets/javascripts/monitoring/stores/mutations.js
+++ b/app/assets/javascripts/monitoring/stores/mutations.js
@@ -59,7 +59,6 @@ export default {
*/
[types.REQUEST_METRICS_DASHBOARD](state) {
state.emptyState = dashboardEmptyStates.LOADING;
- state.showEmptyState = true;
},
[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](state, dashboardYML) {
const { dashboard, panelGroups, variables, links } = mapToDashboardViewModel(dashboardYML);
@@ -72,13 +71,14 @@ export default {
if (!state.dashboard.panelGroups.length) {
state.emptyState = dashboardEmptyStates.NO_DATA;
+ } else {
+ state.emptyState = null;
}
},
[types.RECEIVE_METRICS_DASHBOARD_FAILURE](state, error) {
state.emptyState = error
? dashboardEmptyStates.UNABLE_TO_CONNECT
: dashboardEmptyStates.NO_DATA;
- state.showEmptyState = true;
},
[types.REQUEST_DASHBOARD_STARRING](state) {
@@ -152,9 +152,6 @@ export default {
const metric = findMetricInDashboard(metricId, state.dashboard);
metric.loading = false;
- state.showEmptyState = false;
- state.emptyState = null;
-
if (!data.result || data.result.length === 0) {
metric.state = metricStates.NO_DATA;
metric.result = null;
@@ -184,13 +181,8 @@ export default {
state.timeRange = timeRange;
},
[types.SET_GETTING_STARTED_EMPTY_STATE](state) {
- state.showEmptyState = true;
state.emptyState = dashboardEmptyStates.GETTING_STARTED;
},
- [types.SET_NO_DATA_EMPTY_STATE](state) {
- state.showEmptyState = true;
- state.emptyState = dashboardEmptyStates.NO_DATA;
- },
[types.SET_ALL_DASHBOARDS](state, dashboards) {
state.allDashboards = dashboards || [];
},
diff --git a/app/assets/javascripts/monitoring/stores/state.js b/app/assets/javascripts/monitoring/stores/state.js
index a7f07234287..89738756ffe 100644
--- a/app/assets/javascripts/monitoring/stores/state.js
+++ b/app/assets/javascripts/monitoring/stores/state.js
@@ -21,8 +21,13 @@ export default () => ({
// Dashboard data
hasDashboardValidationWarnings: false,
+
+ /**
+ * {?String} If set, dashboard should display a global
+ * empty state, there is no way to interact (yet)
+ * with the dashboard.
+ */
emptyState: dashboardEmptyStates.GETTING_STARTED,
- showEmptyState: true,
showErrorBanner: true,
isUpdatingStarredValue: false,
dashboard: {
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 679b81ce583..ac93d3df654 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -419,7 +419,7 @@ export default {
</gl-alert>
<div class="note-form-actions">
<div
- class="btn-group append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
+ class="btn-group gl-mr-3 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
>
<button
:disabled="isSubmitButtonDisabled"
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index f0c3bd9d874..24227d55ebf 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -410,7 +410,7 @@ export default {
</button>
<button
v-if="discussion.resolvable"
- class="btn btn-nr btn-default append-right-10 js-comment-resolve-button"
+ class="btn btn-nr btn-default gl-mr-3 js-comment-resolve-button"
@click.prevent="handleUpdate(true)"
>
{{ resolveButtonTitle }}
diff --git a/app/assets/javascripts/releases/components/release_block_header.vue b/app/assets/javascripts/releases/components/release_block_header.vue
index ed49841757a..310fba0fe76 100644
--- a/app/assets/javascripts/releases/components/release_block_header.vue
+++ b/app/assets/javascripts/releases/components/release_block_header.vue
@@ -56,7 +56,7 @@ export default {
v-gl-tooltip
category="primary"
variant="default"
- class="append-right-10 js-edit-button ml-2 pb-2"
+ class="gl-mr-3 js-edit-button ml-2 pb-2"
:title="__('Edit this release')"
:href="editLink"
>
diff --git a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
index b28a847e751..b8a8cb940e7 100644
--- a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
+++ b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
@@ -114,7 +114,12 @@ export default {
class="mr-widget-section grouped-security-reports mr-report"
>
<template v-if="showViewFullReport" #actionButtons>
- <gl-button :href="testTabURL" icon="external-link" data-testid="group-test-reports-full-link">
+ <gl-button
+ :href="testTabURL"
+ icon="external-link"
+ data-testid="group-test-reports-full-link"
+ class="gl-mr-3"
+ >
{{ s__('ciReport|View full report') }}
</gl-button>
</template>
diff --git a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
index 32b142a3346..80928649a03 100644
--- a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
@@ -62,7 +62,7 @@ export default {
<template>
<div class="sidebar-item-warning-message-actions">
- <button type="button" class="btn btn-default append-right-10" @click="closeForm">
+ <button type="button" class="btn btn-default gl-mr-3" @click="closeForm">
{{ __('Cancel') }}
</button>
<button
diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
index f88bde624b4..2e85ded8ade 100644
--- a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
+++ b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
@@ -41,7 +41,7 @@ export default {
<template>
<div class="sidebar-item-warning-message-actions">
- <button type="button" class="btn btn-default append-right-10" @click="closeForm">
+ <button type="button" class="btn btn-default gl-mr-3" @click="closeForm">
{{ __('Cancel') }}
</button>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
index 92848e86e76..f02e0ac84da 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
@@ -87,7 +87,7 @@ export default {
<status-icon status="success" />
<div class="media-body">
<h4 class="d-flex align-items-start">
- <span class="append-right-10">
+ <span class="gl-mr-3">
<span class="js-status-text-before-author">{{ statusTextBeforeAuthor }}</span>
<mr-widget-author :author="mr.setToAutoMergeBy" />
<span class="js-status-text-after-author">{{ statusTextAfterAuthor }}</span>
@@ -113,9 +113,7 @@ export default {
{{ s__('mrWidget|The source branch will be deleted') }}
</p>
<p v-else class="d-flex align-items-start">
- <span class="append-right-10">{{
- s__('mrWidget|The source branch will not be deleted')
- }}</span>
+ <span class="gl-mr-3">{{ s__('mrWidget|The source branch will not be deleted') }}</span>
<a
v-if="canRemoveSourceBranch"
:disabled="isRemovingSourceBranch"
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index a28936456ff..fdcbcdce51b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -384,7 +384,7 @@ export default {
v-if="mr.testResultsPath"
class="js-reports-container"
:endpoint="mr.testResultsPath"
- :pipeline-path="mr.mergeRequestAddCiConfigPath"
+ :pipeline-path="mr.pipeline.path"
/>
<terraform-plan v-if="mr.terraformReportsPath" :endpoint="mr.terraformReportsPath" />
diff --git a/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue b/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue
index 1cee800de44..8c6d795f4a6 100644
--- a/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue
+++ b/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue
@@ -56,7 +56,7 @@ export default {
@click="onClick"
>
<icon
- class="prepend-left-10 append-right-10 flex-shrink-0 position-top-0 js-selected-icon"
+ class="prepend-left-10 gl-mr-3 flex-shrink-0 position-top-0 js-selected-icon"
:class="{ 'js-selected visible': selected, 'js-unselected invisible': !selected }"
name="mobile-issue-close"
/>
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index fe48381d9c3..f2ff8b74790 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -404,7 +404,6 @@ img.emoji {
.prepend-left-15 { margin-left: 15px; }
.prepend-left-20 { margin-left: 20px; }
.prepend-left-64 { margin-left: 64px; }
-.append-right-10 { margin-right: 10px; }
.append-right-15 { margin-right: 15px; }
.append-right-20 { margin-right: 20px; }
.append-bottom-10 { margin-bottom: 10px; }
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 79f9cf5941f..265dceb3c61 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -171,7 +171,7 @@ $gray-500: #a7a7a7 !default;
$gray-600: #919191 !default;
$gray-700: #707070 !default;
$gray-800: #4f4f4f !default;
-$gray-900: #2e2e2e !default;
+$gray-900: #303030 !default;
$gray-950: #1f1f1f !default;
$greens: (
diff --git a/app/assets/stylesheets/pages/runners.scss b/app/assets/stylesheets/pages/runners.scss
index dc3811bab65..66d2f76c558 100644
--- a/app/assets/stylesheets/pages/runners.scss
+++ b/app/assets/stylesheets/pages/runners.scss
@@ -45,8 +45,7 @@
color: $gl-text-color-secondary;
}
- .fa-pause,
- .fa-play {
+ .fa-pause {
font-size: 11px;
}
}
diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb
index cf9f74a63d8..f081eac368e 100644
--- a/app/graphql/mutations/notes/create/base.rb
+++ b/app/graphql/mutations/notes/create/base.rb
@@ -18,6 +18,11 @@ module Mutations
required: true,
description: copy_field_description(Types::Notes::NoteType, :body)
+ argument :confidential,
+ GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: 'The confidentiality flag of a note. Default is false.'
+
def resolve(args)
noteable = authorized_find!(id: args[:noteable_id])
@@ -40,7 +45,8 @@ module Mutations
def create_note_params(noteable, args)
{
noteable: noteable,
- note: args[:body]
+ note: args[:body],
+ confidential: args[:confidential]
}
end
end
diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb
index 1545fd70290..89c21486a74 100644
--- a/app/graphql/mutations/snippets/create.rb
+++ b/app/graphql/mutations/snippets/create.rb
@@ -85,9 +85,9 @@ module Mutations
def create_params(args)
args.tap do |create_args|
- # We need to rename `files` into `snippet_files` because
+ # We need to rename `files` into `snippet_actions` because
# it's the expected key param
- create_args[:snippet_files] = create_args.delete(:files)&.map(&:to_h)
+ create_args[:snippet_actions] = create_args.delete(:files)&.map(&:to_h)
# We need to rename `uploaded_files` into `files` because
# it's the expected key param
diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb
index f0a22ebaa9d..8890158b0df 100644
--- a/app/graphql/mutations/snippets/update.rb
+++ b/app/graphql/mutations/snippets/update.rb
@@ -56,9 +56,9 @@ module Mutations
def update_params(args)
args.tap do |update_args|
- # We need to rename `files` into `snippet_files` because
+ # We need to rename `files` into `snippet_actions` because
# it's the expected key param
- update_args[:snippet_files] = update_args.delete(:files)&.map(&:to_h)
+ update_args[:snippet_actions] = update_args.delete(:files)&.map(&:to_h)
end
end
end
diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb
index 90ebab731ea..b522a9dfb4f 100644
--- a/app/helpers/environments_helper.rb
+++ b/app/helpers/environments_helper.rb
@@ -24,7 +24,7 @@ module EnvironmentsHelper
def metrics_data(project, environment)
metrics_data = {}
metrics_data.merge!(project_metrics_data(project)) if project
- metrics_data.merge!(environment_metrics_data(environment)) if environment
+ metrics_data.merge!(environment_metrics_data(environment, project)) if environment
metrics_data.merge!(project_and_environment_metrics_data(project, environment)) if project && environment
metrics_data.merge!(static_metrics_data)
@@ -66,11 +66,11 @@ module EnvironmentsHelper
}
end
- def environment_metrics_data(environment)
+ def environment_metrics_data(environment, project = nil)
return {} unless environment
{
- 'metrics-dashboard-base-path' => environment_metrics_path(environment),
+ 'metrics-dashboard-base-path' => metrics_dashboard_base_path(environment, project),
'current-environment-name' => environment.name,
'has-metrics' => "#{environment.has_metrics?}",
'prometheus-status' => "#{environment.prometheus_status}",
@@ -78,6 +78,17 @@ module EnvironmentsHelper
}
end
+ def metrics_dashboard_base_path(environment, project)
+ # This is needed to support our transition from environment scoped metric paths to project scoped.
+ if project
+ path = project_metrics_dashboard_path(project)
+
+ return path if request.path.include?(path)
+ end
+
+ environment_metrics_path(environment)
+ end
+
def project_and_environment_metrics_data(project, environment)
return {} unless project && environment
diff --git a/app/presenters/clusters/cluster_presenter.rb b/app/presenters/clusters/cluster_presenter.rb
index 3dfa9626a79..6185f5cb4e5 100644
--- a/app/presenters/clusters/cluster_presenter.rb
+++ b/app/presenters/clusters/cluster_presenter.rb
@@ -76,9 +76,11 @@ module Clusters
'clusters-path': clusterable.index_path,
'dashboard-endpoint': clusterable.metrics_dashboard_path(cluster),
'documentation-path': help_page_path('user/project/clusters/index', anchor: 'monitoring-your-kubernetes-cluster-ultimate'),
+ 'add-dashboard-documentation-path': help_page_path('user/project/integrations/prometheus.md', anchor: 'adding-a-new-dashboard-to-your-project'),
'empty-getting-started-svg-path': image_path('illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path': image_path('illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path': image_path('illustrations/monitoring/no_data.svg'),
+ 'empty-no-data-small-svg-path': image_path('illustrations/chart-empty-state-small.svg'),
'empty-unable-to-connect-svg-path': image_path('illustrations/monitoring/unable_to_connect.svg'),
'settings-path': '',
'project-path': '',
diff --git a/app/services/concerns/incident_management/settings.rb b/app/services/concerns/incident_management/settings.rb
index 5f56d6e7f53..491bd4fa6bf 100644
--- a/app/services/concerns/incident_management/settings.rb
+++ b/app/services/concerns/incident_management/settings.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module IncidentManagement
module Settings
+ include Gitlab::Utils::StrongMemoize
+
def incident_management_setting
strong_memoize(:incident_management_setting) do
project.incident_management_setting ||
diff --git a/app/services/incident_management/pager_duty/create_incident_issue_service.rb b/app/services/incident_management/pager_duty/create_incident_issue_service.rb
new file mode 100644
index 00000000000..ee0feb49e0d
--- /dev/null
+++ b/app/services/incident_management/pager_duty/create_incident_issue_service.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ module PagerDuty
+ class CreateIncidentIssueService < BaseService
+ include IncidentManagement::Settings
+
+ def initialize(project, incident_payload)
+ super(project, User.alert_bot, incident_payload)
+ end
+
+ def execute
+ return forbidden unless webhook_available?
+
+ issue = create_issue
+ return error(issue.errors.full_messages.to_sentence, issue) unless issue.valid?
+
+ success(issue)
+ end
+
+ private
+
+ alias_method :incident_payload, :params
+
+ def create_issue
+ label_result = find_or_create_incident_label
+
+ # Create an unlabelled issue if we couldn't create the label
+ # due to a race condition.
+ # See https://gitlab.com/gitlab-org/gitlab-foss/issues/65042
+ extra_params = label_result.success? ? { label_ids: [label_result.payload[:label].id] } : {}
+
+ Issues::CreateService.new(
+ project,
+ current_user,
+ title: issue_title,
+ description: issue_description,
+ **extra_params
+ ).execute
+ end
+
+ def webhook_available?
+ Feature.enabled?(:pagerduty_webhook, project) &&
+ incident_management_setting.pagerduty_active?
+ end
+
+ def forbidden
+ ServiceResponse.error(message: 'Forbidden', http_status: :forbidden)
+ end
+
+ def find_or_create_incident_label
+ ::IncidentManagement::CreateIncidentLabelService.new(project, current_user).execute
+ end
+
+ def issue_title
+ incident_payload['title']
+ end
+
+ def issue_description
+ Gitlab::IncidentManagement::PagerDuty::IncidentIssueDescription.new(incident_payload).to_s
+ end
+
+ def success(issue)
+ ServiceResponse.success(payload: { issue: issue })
+ end
+
+ def error(message, issue = nil)
+ ServiceResponse.error(payload: { issue: issue }, message: message)
+ end
+ end
+ end
+end
diff --git a/app/services/snippets/base_service.rb b/app/services/snippets/base_service.rb
index 1985ced9dd0..d9e8326f159 100644
--- a/app/services/snippets/base_service.rb
+++ b/app/services/snippets/base_service.rb
@@ -6,15 +6,15 @@ module Snippets
CreateRepositoryError = Class.new(StandardError)
- attr_reader :uploaded_assets, :snippet_files
+ attr_reader :uploaded_assets, :snippet_actions
def initialize(project, user = nil, params = {})
super
@uploaded_assets = Array(@params.delete(:files).presence)
- input_actions = Array(@params.delete(:snippet_files).presence)
- @snippet_files = SnippetInputActionCollection.new(input_actions, allowed_actions: restricted_files_actions)
+ input_actions = Array(@params.delete(:snippet_actions).presence)
+ @snippet_actions = SnippetInputActionCollection.new(input_actions, allowed_actions: restricted_files_actions)
filter_spam_check_params
end
@@ -32,18 +32,18 @@ module Snippets
end
def valid_params?
- return true if snippet_files.empty?
+ return true if snippet_actions.empty?
- (params.keys & [:content, :file_name]).none? && snippet_files.valid?
+ (params.keys & [:content, :file_name]).none? && snippet_actions.valid?
end
def invalid_params_error(snippet)
- if snippet_files.valid?
+ if snippet_actions.valid?
[:content, :file_name].each do |key|
snippet.errors.add(key, 'and snippet files cannot be used together') if params.key?(key)
end
else
- snippet.errors.add(:snippet_files, 'have invalid data')
+ snippet.errors.add(:snippet_actions, 'have invalid data')
end
snippet_error_response(snippet, 403)
@@ -75,7 +75,7 @@ module Snippets
end
def files_to_commit(snippet)
- snippet_files.to_commit_actions.presence || build_actions_from_params(snippet)
+ snippet_actions.to_commit_actions.presence || build_actions_from_params(snippet)
end
def build_actions_from_params(snippet)
diff --git a/app/services/snippets/create_service.rb b/app/services/snippets/create_service.rb
index 6039ca2e501..dab47de8a36 100644
--- a/app/services/snippets/create_service.rb
+++ b/app/services/snippets/create_service.rb
@@ -37,13 +37,13 @@ module Snippets
end
end
- # If the snippet_files param is present
+ # If the snippet_actions param is present
# we need to fill content and file_name from
# the model
def create_params
- return params if snippet_files.empty?
+ return params if snippet_actions.empty?
- params.merge(content: snippet_files[0].content, file_name: snippet_files[0].file_path)
+ params.merge(content: snippet_actions[0].content, file_name: snippet_actions[0].file_path)
end
def save_and_commit
diff --git a/app/services/snippets/update_service.rb b/app/services/snippets/update_service.rb
index 1c097ed447a..00146389e22 100644
--- a/app/services/snippets/update_service.rb
+++ b/app/services/snippets/update_service.rb
@@ -37,9 +37,9 @@ module Snippets
# is implemented.
# Once we can perform different operations through this service
# we won't need to keep track of the `content` and `file_name` fields
- if snippet_files.any?
- params[:content] = snippet_files[0].content if snippet_files[0].content
- params[:file_name] = snippet_files[0].file_path
+ if snippet_actions.any?
+ params[:content] = snippet_actions[0].content if snippet_actions[0].content
+ params[:file_name] = snippet_actions[0].file_path
end
snippet.assign_attributes(params)
@@ -109,7 +109,7 @@ module Snippets
end
def committable_attributes?
- (params.stringify_keys.keys & COMMITTABLE_ATTRIBUTES).present? || snippet_files.any?
+ (params.stringify_keys.keys & COMMITTABLE_ATTRIBUTES).present? || snippet_actions.any?
end
def build_actions_from_params(snippet)
diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml
index 423472324fe..5c834c2125f 100644
--- a/app/views/admin/runners/_runner.html.haml
+++ b/app/views/admin/runners/_runner.html.haml
@@ -72,8 +72,8 @@
= link_to [:pause, :admin, runner], method: :get, class: 'btn btn-default has-tooltip', title: _('Pause'), ref: 'tooltip', aria: { label: _('Pause') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do
= icon('pause')
- else
- = link_to [:resume, :admin, runner], method: :get, class: 'btn btn-default has-tooltip', title: _('Resume'), ref: 'tooltip', aria: { label: _('Resume') }, data: { placement: 'top', container: 'body'} do
- = icon('play')
+ = link_to [:resume, :admin, runner], method: :get, class: 'btn btn-default has-tooltip gl-px-3', title: _('Resume'), ref: 'tooltip', aria: { label: _('Resume') }, data: { placement: 'top', container: 'body'} do
+ = sprite_icon('play')
.btn-group
= link_to [:admin, runner], method: :delete, class: 'btn btn-danger has-tooltip', title: _('Remove'), ref: 'tooltip', aria: { label: _('Remove') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do
= icon('remove')
diff --git a/app/views/ci/group_variables/_index.html.haml b/app/views/ci/group_variables/_index.html.haml
index c350ba5caf7..84bcd42e07c 100644
--- a/app/views/ci/group_variables/_index.html.haml
+++ b/app/views/ci/group_variables/_index.html.haml
@@ -6,8 +6,8 @@
= render 'ci/group_variables/variable_header'
- variables.each do |variable|
.group-variable-row.d-flex.w-100.border-bottom.pt-2.pb-2
- .table-section.section-40.append-right-10.key
+ .table-section.section-40.gl-mr-3.key
= variable.key
- .table-section.section-40.append-right-10
+ .table-section.section-40.gl-mr-3
%a.group-origin-link{ href: group_settings_ci_cd_path(variable.group) }
= variable.group.name
diff --git a/app/views/ci/group_variables/_variable_header.html.haml b/app/views/ci/group_variables/_variable_header.html.haml
index 1a3168cf781..a8d533da0e0 100644
--- a/app/views/ci/group_variables/_variable_header.html.haml
+++ b/app/views/ci/group_variables/_variable_header.html.haml
@@ -1,5 +1,5 @@
.group-variable-keys.d-flex.w-100.align-items-center.pb-2.border-bottom
- .bold.table-section.section-40.append-right-10
+ .bold.table-section.section-40.gl-mr-3
= s_('Key')
- .bold.table-section.section-40.append-right-10
+ .bold.table-section.section-40.gl-mr-3
= s_('Origin')
diff --git a/app/views/ci/variables/_environment_scope_header.html.haml b/app/views/ci/variables/_environment_scope_header.html.haml
index 4ba4ceec16c..fc3b7f925fc 100644
--- a/app/views/ci/variables/_environment_scope_header.html.haml
+++ b/app/views/ci/variables/_environment_scope_header.html.haml
@@ -1,2 +1,2 @@
-.bold.table-section.section-15.append-right-10
+.bold.table-section.section-15.gl-mr-3
= s_('CiVariables|Scope')
diff --git a/app/views/ci/variables/_variable_header.html.haml b/app/views/ci/variables/_variable_header.html.haml
index d3b7a5ae883..65cea00a0c4 100644
--- a/app/views/ci/variables/_variable_header.html.haml
+++ b/app/views/ci/variables/_variable_header.html.haml
@@ -2,11 +2,11 @@
%li.ci-variable-row.m-0.d-none.d-sm-block
.d-flex.w-100.align-items-center.pb-2
- .bold.table-section.section-15.append-right-10
+ .bold.table-section.section-15.gl-mr-3
= s_('CiVariables|Type')
- .bold.table-section.section-15.append-right-10
+ .bold.table-section.section-15.gl-mr-3
= s_('CiVariables|Key')
- .bold.table-section.section-15.append-right-10
+ .bold.table-section.section-15.gl-mr-3
= s_('CiVariables|Value')
- unless only_key_value
.bold.table-section.section-20
diff --git a/app/views/profiles/active_sessions/_active_session.html.haml b/app/views/profiles/active_sessions/_active_session.html.haml
index f3ad0c4c8ad..68f5460e599 100644
--- a/app/views/profiles/active_sessions/_active_session.html.haml
+++ b/app/views/profiles/active_sessions/_active_session.html.haml
@@ -1,7 +1,7 @@
- is_current_session = active_session.current?(session)
%li.list-group-item
- .float-left.append-right-10{ data: { toggle: 'tooltip' }, title: active_session.human_device_type }
+ .float-left.gl-mr-3{ data: { toggle: 'tooltip' }, title: active_session.human_device_type }
= active_session_device_type_icon(active_session)
.description.float-left
diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml
index 2de5cf2f506..7a10b24c312 100644
--- a/app/views/profiles/gpg_keys/_key.html.haml
+++ b/app/views/profiles/gpg_keys/_key.html.haml
@@ -1,5 +1,5 @@
%li.key-list-item
- .float-left.append-right-10
+ .float-left.gl-mr-3
= icon 'key', class: "settings-list-icon d-none d-sm-block"
.key-list-item-info
- key.emails_with_verified_status.map do |email, verified|
diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml
index b227041c9de..c02711e31ae 100644
--- a/app/views/profiles/keys/_key.html.haml
+++ b/app/views/profiles/keys/_key.html.haml
@@ -1,5 +1,5 @@
%li.d-flex.align-items-center.key-list-item
- .append-right-10
+ .gl-mr-3
- if key.valid?
- if key.expired?
%span.d-inline-block.has-tooltip{ title: s_('Profiles|Your key has expired') }
@@ -17,10 +17,10 @@
= key.fingerprint
.key-list-item-dates.d-flex.align-items-start.justify-content-between
- %span.last-used-at.append-right-10
+ %span.last-used-at.gl-mr-3
= s_('Profiles|Last used:')
= key.last_used_at ? time_ago_with_tooltip(key.last_used_at) : _('Never')
- %span.expires.append-right-10
+ %span.expires.gl-mr-3
= s_('Profiles|Expires:')
= key.expires_at ? key.expires_at.to_date : _('Never')
%span.key-created-at
diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml
index d21db0a6511..fe16c2e2f28 100644
--- a/app/views/profiles/passwords/edit.html.haml
+++ b/app/views/profiles/passwords/edit.html.haml
@@ -30,6 +30,6 @@
= f.label :password_confirmation, _('Password confirmation'), class: 'label-bold'
= f.password_field :password_confirmation, required: true, class: 'form-control', data: { qa_selector: 'confirm_password_field' }
.gl-mt-3.gl-mb-3
- = f.submit _('Save password'), class: "btn btn-success append-right-10", data: { qa_selector: 'save_password_button' }
+ = f.submit _('Save password'), class: "btn btn-success gl-mr-3", data: { qa_selector: 'save_password_button' }
- unless @user.password_automatically_set?
= link_to _('I forgot my password'), reset_profile_password_path, method: :put
diff --git a/app/views/profiles/two_factor_auths/_codes.html.haml b/app/views/profiles/two_factor_auths/_codes.html.haml
index 94fd40ed669..68cd4875a33 100644
--- a/app/views/profiles/two_factor_auths/_codes.html.haml
+++ b/app/views/profiles/two_factor_auths/_codes.html.haml
@@ -9,5 +9,5 @@
%span.monospace= code
.d-flex
- = link_to _('Proceed'), profile_account_path, class: 'btn btn-success append-right-10', data: { qa_selector: 'proceed_button' }
+ = link_to _('Proceed'), profile_account_path, class: 'btn btn-success gl-mr-3', data: { qa_selector: 'proceed_button' }
= link_to _('Download codes'), "data:text/plain;charset=utf-8,#{CGI.escape(@codes.join("\n"))}", download: "gitlab-recovery-codes.txt", class: 'btn btn-default'
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index b8c5d626d17..0fde3e5fb10 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -19,7 +19,7 @@
= link_to _('Disable two-factor authentication'), profile_two_factor_auth_path,
method: :delete,
data: { confirm: _('Are you sure? This will invalidate your registered applications and U2F devices.') },
- class: 'btn btn-danger append-right-10'
+ class: 'btn btn-danger gl-mr-3'
= form_tag codes_profile_two_factor_auth_path, {style: 'display: inline-block', method: :post} do |f|
= submit_tag _('Regenerate recovery codes'), class: 'btn'
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
index 1e9cf68f3a5..b06ae31e73f 100644
--- a/app/views/projects/blob/_editor.html.haml
+++ b/app/views/projects/blob/_editor.html.haml
@@ -8,13 +8,13 @@
= sprite_icon('fork', size: 12)
= ref
- if current_action?(:edit) || current_action?(:update)
- %span.pull-left.append-right-10
+ %span.pull-left.gl-mr-3
= text_field_tag 'file_path', (params[:file_path] || @path),
class: 'form-control new-file-path js-file-path-name-input'
= render 'template_selectors'
- if current_action?(:new) || current_action?(:create)
- %span.pull-left.append-right-10
+ %span.pull-left.gl-mr-3
\/
= text_field_tag 'file_name', params[:file_name], placeholder: "File name",
required: true, class: 'form-control new-file-name js-file-path-name-input', value: params[:file_name] || (should_suggest_gitlab_ci_yml? ? '.gitlab-ci.yml' : '')
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 4442bdcdf1d..71cf6ca6922 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -22,10 +22,10 @@
.header-action-buttons
- if defined?(@notes_count) && @notes_count > 0
- %span.btn.disabled.btn-grouped.d-none.d-sm-block.append-right-10.has-tooltip{ title: n_("%d comment on this commit", "%d comments on this commit", @notes_count) % @notes_count }
+ %span.btn.disabled.btn-grouped.d-none.d-sm-block.gl-mr-3.has-tooltip{ title: n_("%d comment on this commit", "%d comments on this commit", @notes_count) % @notes_count }
= sprite_icon('comment')
= @notes_count
- = link_to project_tree_path(@project, @commit), class: "btn btn-default append-right-10 d-none d-sm-none d-md-inline" do
+ = link_to project_tree_path(@project, @commit), class: "btn btn-default gl-mr-3 d-none d-sm-none d-md-inline" do
#{ _('Browse files') }
.dropdown.inline
%a.btn.btn-default.dropdown-toggle.qa-options-button.d-md-inline{ data: { toggle: "dropdown" } }
diff --git a/app/views/projects/issues/_nav_btns.html.haml b/app/views/projects/issues/_nav_btns.html.haml
index 71c9bb36936..cc6ca4aca4a 100644
--- a/app/views/projects/issues/_nav_btns.html.haml
+++ b/app/views/projects/issues/_nav_btns.html.haml
@@ -14,7 +14,7 @@
= render 'projects/issues/import_csv/button'
- if @can_bulk_update
- = button_tag _("Edit issues"), class: "btn btn-default append-right-10 js-bulk-update-toggle"
+ = button_tag _("Edit issues"), class: "btn btn-default gl-mr-3 js-bulk-update-toggle"
- if show_new_issue_link?(@project)
= link_to _("New issue"), new_project_issue_path(@project,
issue: { assignee_id: finder.assignee.try(:id),
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index 3303aa72604..ecb51aca847 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -5,7 +5,7 @@
- if @merge_request.reopenable?
= link_to 'Reopen merge request', merge_request_path(@merge_request, merge_request: { state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-reopen reopen-mr-link js-note-target-close js-note-target-reopen", title: "Reopen merge request", data: { original_text: "Reopen merge request", alternative_text: "Comment & reopen merge request"}
%comment-and-resolve-btn{ "inline-template" => true }
- %button.btn.btn-nr.btn-default.append-right-10.js-comment-resolve-button{ "v-if" => "showButton", type: "submit", data: { project_path: "#{project_path(@merge_request.project)}" } }
+ %button.btn.btn-nr.btn-default.gl-mr-3.js-comment-resolve-button{ "v-if" => "showButton", type: "submit", data: { project_path: "#{project_path(@merge_request.project)}" } }
{{ buttonText }}
#notes= render "shared/notes/notes_with_form", :autocomplete => true
diff --git a/app/views/projects/merge_requests/_nav_btns.html.haml b/app/views/projects/merge_requests/_nav_btns.html.haml
index b7498216334..2ef10365c18 100644
--- a/app/views/projects/merge_requests/_nav_btns.html.haml
+++ b/app/views/projects/merge_requests/_nav_btns.html.haml
@@ -1,5 +1,5 @@
- if @can_bulk_update
- = button_tag "Edit merge requests", class: "btn append-right-10 js-bulk-update-toggle"
+ = button_tag "Edit merge requests", class: "btn gl-mr-3 js-bulk-update-toggle"
- if merge_project
= link_to new_merge_request_path, class: "btn btn-success", title: "New merge request" do
New merge request
diff --git a/app/views/projects/mirrors/_ssh_host_keys.html.haml b/app/views/projects/mirrors/_ssh_host_keys.html.haml
index ca8ed417255..236ede32d31 100644
--- a/app/views/projects/mirrors/_ssh_host_keys.html.haml
+++ b/app/views/projects/mirrors/_ssh_host_keys.html.haml
@@ -3,7 +3,7 @@
- verified_at = mirror.ssh_known_hosts_verified_at
.form-group.js-ssh-host-keys-section{ class: ('collapse' unless mirror.ssh_mirror_url?) }
- %button.btn.btn-inverted.btn-secondary.inline.js-detect-host-keys.append-right-10{ type: 'button', data: { qa_selector: 'detect_host_keys' } }
+ %button.btn.btn-inverted.btn-secondary.inline.js-detect-host-keys.gl-mr-3{ type: 'button', data: { qa_selector: 'detect_host_keys' } }
.js-spinner.d-none.spinner.mr-1
= _('Detect host keys')
.fingerprint-ssh-info.js-fingerprint-ssh-info.prepend-top-10.append-bottom-10{ class: ('collapse' unless mirror.ssh_mirror_url?) }
diff --git a/app/views/projects/no_repo.html.haml b/app/views/projects/no_repo.html.haml
index 7748aadf44d..3a9e9108256 100644
--- a/app/views/projects/no_repo.html.haml
+++ b/app/views/projects/no_repo.html.haml
@@ -15,7 +15,7 @@
= link_to project_repository_path(@project), method: :post, class: 'btn btn-primary' do
#{ _('Create empty repository') }
- %strong.prepend-left-10.append-right-10 or
+ %strong.prepend-left-10.gl-mr-3 or
= link_to new_project_import_path(@project), class: 'btn' do
#{ _('Import repository') }
diff --git a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
index 8d88f0be083..f48763cb544 100644
--- a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
+++ b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
@@ -27,8 +27,8 @@
%td
.float-right.btn-group
- if can?(current_user, :play_pipeline_schedule, pipeline_schedule)
- = link_to play_pipeline_schedule_path(pipeline_schedule), method: :post, title: s_('Play'), class: 'btn' do
- = icon('play')
+ = link_to play_pipeline_schedule_path(pipeline_schedule), method: :post, title: s_('Play'), class: 'btn btn-svg gl-display-flex gl-align-items-center gl-justify-content-center' do
+ = sprite_icon('play')
- if can?(current_user, :take_ownership_pipeline_schedule, pipeline_schedule)
= link_to take_ownership_pipeline_schedule_path(pipeline_schedule), method: :post, title: s_('PipelineSchedules|Take ownership'), class: 'btn' do
= s_('PipelineSchedules|Take ownership')
diff --git a/app/views/projects/project_templates/_built_in_templates.html.haml b/app/views/projects/project_templates/_built_in_templates.html.haml
index eb41a3e0785..43352952b37 100644
--- a/app/views/projects/project_templates/_built_in_templates.html.haml
+++ b/app/views/projects/project_templates/_built_in_templates.html.haml
@@ -1,6 +1,6 @@
- Gitlab::ProjectTemplate.all.each do |template|
.template-option.d-flex.align-items-center{ data: { qa_selector: 'template_option_row' } }
- .logo.append-right-10.px-1
+ .logo.gl-mr-3.px-1
= image_tag template.logo, size: 32, class: "btn-template-icon icon-#{template.name}"
.description
%strong
@@ -9,7 +9,7 @@
.text-muted
= template.description
.controls.d-flex.align-items-center
- %a.btn.btn-default.append-right-10{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_event: "click_button", track_value: "" } }
+ %a.btn.btn-default.gl-mr-3{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_event: "click_button", track_value: "" } }
= _("Preview")
%label.btn.btn-success.template-button.choose-template.gl-mb-0{ for: template.name }
%input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name, data: { track_label: "template_use", track_property: template.name, track_event: "click_button", track_value: "" } }
diff --git a/app/views/projects/project_templates/_project_fields_form.html.haml b/app/views/projects/project_templates/_project_fields_form.html.haml
index c96010550d8..201e2d5b5fb 100644
--- a/app/views/projects/project_templates/_project_fields_form.html.haml
+++ b/app/views/projects/project_templates/_project_fields_form.html.haml
@@ -5,7 +5,7 @@
.input-group.template-input-group
.input-group-prepend
.input-group-text
- .selected-icon.append-right-10
+ .selected-icon.gl-mr-3
.selected-template
.input-group-append
%button.btn.btn-default.change-template{ type: "button" }
diff --git a/app/views/sent_notifications/unsubscribe.html.haml b/app/views/sent_notifications/unsubscribe.html.haml
index 1eecbe3bc0e..7aeecf26c39 100644
--- a/app/views/sent_notifications/unsubscribe.html.haml
+++ b/app/views/sent_notifications/unsubscribe.html.haml
@@ -15,5 +15,5 @@
%p
= link_to _('Unsubscribe'), unsubscribe_sent_notification_path(@sent_notification, force: true),
- class: 'btn btn-primary append-right-10'
- = link_to _('Cancel'), new_user_session_path, class: 'btn append-right-10'
+ class: 'btn btn-primary gl-mr-3'
+ = link_to _('Cancel'), new_user_session_path, class: 'btn gl-mr-3'
diff --git a/app/views/shared/groups/_dropdown.html.haml b/app/views/shared/groups/_dropdown.html.haml
index f4915440cb2..9d2d3ce20c7 100644
--- a/app/views/shared/groups/_dropdown.html.haml
+++ b/app/views/shared/groups/_dropdown.html.haml
@@ -8,7 +8,7 @@
- else
- default_sort_by = sort_value_recently_created
-.dropdown.inline.js-group-filter-dropdown-wrap.append-right-10
+.dropdown.inline.js-group-filter-dropdown-wrap.gl-mr-3
%button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
%span.dropdown-label
= options_hash[default_sort_by]
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index cc5bd4d67c9..f54457b8b33 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -69,7 +69,7 @@
= link_to 'Delete', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable], params: { destroy_confirm: true }), data: { confirm: "#{issuable.human_class_name} will be removed! Are you sure?" }, method: :delete, class: 'btn btn-danger btn-grouped'
= link_to 'Cancel', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), class: 'btn btn-grouped btn-cancel'
- %span.append-right-10
+ %span.gl-mr-3
- if issuable.new_record?
= form.submit "Submit #{issuable.class.model_name.human.downcase}", class: 'btn btn-success qa-issuable-create-button'
- else
diff --git a/app/views/shared/milestones/_deprecation_message.html.haml b/app/views/shared/milestones/_deprecation_message.html.haml
index ba5eb54f017..31b8b383fe1 100644
--- a/app/views/shared/milestones/_deprecation_message.html.haml
+++ b/app/views/shared/milestones/_deprecation_message.html.haml
@@ -1,6 +1,6 @@
.banner-callout.compact.milestone-deprecation-message.js-milestone-deprecation-message.prepend-top-20
.banner-graphic= image_tag 'illustrations/milestone_removing-page.svg'
- .banner-body.prepend-left-10.append-right-10
+ .banner-body.prepend-left-10.gl-mr-3
%h5.banner-title.gl-mt-0= _('This page will be removed in a future release.')
%p.milestone-banner-text= _('Use group milestones to manage issues from multiple projects in the same milestone.')
= button_tag _('Promote these project milestones into a group milestone.'), class: 'btn btn-link js-popover-link text-align-left milestone-banner-link'
diff --git a/app/views/shared/notes/_comment_button.html.haml b/app/views/shared/notes/_comment_button.html.haml
index 748bb1e6534..e151e55d0d2 100644
--- a/app/views/shared/notes/_comment_button.html.haml
+++ b/app/views/shared/notes/_comment_button.html.haml
@@ -1,6 +1,6 @@
- noteable_name = @note.noteable.human_class_name
-.float-left.btn-group.append-right-10.droplab-dropdown.comment-type-dropdown.js-comment-type-dropdown
+.float-left.btn-group.gl-mr-3.droplab-dropdown.comment-type-dropdown.js-comment-type-dropdown
%input.btn.btn-nr.btn-success.js-comment-button.js-comment-submit-button{ type: 'submit', value: _('Comment'), data: { qa_selector: 'comment_button' } }
- if @note.can_be_discussion_note?
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index ddf0bdeca4e..626e94e0202 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -39,11 +39,11 @@
%span.project-name<
= project.name
- %span.metadata-info.visibility-icon.append-right-10.gl-mt-3.text-secondary.has-tooltip{ data: { container: 'body', placement: 'top' }, title: visibility_icon_description(project) }
+ %span.metadata-info.visibility-icon.gl-mr-3.gl-mt-3.text-secondary.has-tooltip{ data: { container: 'body', placement: 'top' }, title: visibility_icon_description(project) }
= visibility_level_icon(project.visibility_level, fw: true)
- if explore_projects_tab? && project_license_name(project)
- %span.metadata-info.d-inline-flex.align-items-center.append-right-10.gl-mt-3
+ %span.metadata-info.d-inline-flex.align-items-center.gl-mr-3.gl-mt-3
= sprite_icon('scale', size: 14, css_class: 'gl-mr-2')
= project_license_name(project)
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 0224b0db3dc..b079a114c71 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -691,6 +691,14 @@
:weight: 2
:idempotent: true
:tags: []
+- :name: incident_management:incident_management_pager_duty_process_incident
+ :feature_category: :incident_management
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 2
+ :idempotent:
+ :tags: []
- :name: incident_management:incident_management_process_alert
:feature_category: :incident_management
:has_external_dependencies:
@@ -869,7 +877,7 @@
:tags: []
- :name: pipeline_background:ci_pipeline_success_unlock_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -877,7 +885,7 @@
:tags: []
- :name: pipeline_background:ci_ref_delete_unlock_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1670,11 +1678,11 @@
:tags: []
- :name: service_desk_email_receiver
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: system_hook_push
:feature_category: :source_code_management
diff --git a/app/workers/incident_management/pager_duty/process_incident_worker.rb b/app/workers/incident_management/pager_duty/process_incident_worker.rb
new file mode 100644
index 00000000000..3f378b012a1
--- /dev/null
+++ b/app/workers/incident_management/pager_duty/process_incident_worker.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ module PagerDuty
+ class ProcessIncidentWorker # rubocop:disable Scalability/IdempotentWorker
+ include ApplicationWorker
+
+ queue_namespace :incident_management
+ feature_category :incident_management
+
+ def perform(project_id, incident_payload)
+ return unless project_id
+
+ project = find_project(project_id)
+ return unless project
+
+ result = create_issue(project, incident_payload)
+
+ log_error(result) if result.error?
+ end
+
+ private
+
+ def find_project(project_id)
+ Project.find_by_id(project_id)
+ end
+
+ def create_issue(project, incident_payload)
+ ::IncidentManagement::PagerDuty::CreateIncidentIssueService
+ .new(project, incident_payload)
+ .execute
+ end
+
+ def log_error(result)
+ Gitlab::AppLogger.warn(
+ message: 'Cannot create issue for PagerDuty incident',
+ issue_errors: result.message
+ )
+ end
+ end
+ end
+end
diff --git a/changelogs/unreleased/207473-create-confidential-notes-graphql.yml b/changelogs/unreleased/207473-create-confidential-notes-graphql.yml
new file mode 100644
index 00000000000..8d9edee07b2
--- /dev/null
+++ b/changelogs/unreleased/207473-create-confidential-notes-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Add confidential attribute to graphQL for notes creation
+merge_request: 36799
+author:
+type: added
diff --git a/changelogs/unreleased/217758-reduce-metrics-dashboard-loading.yml b/changelogs/unreleased/217758-reduce-metrics-dashboard-loading.yml
new file mode 100644
index 00000000000..d018c3bf7bb
--- /dev/null
+++ b/changelogs/unreleased/217758-reduce-metrics-dashboard-loading.yml
@@ -0,0 +1,6 @@
+---
+title: Replace initial dashboard loading state with a loading spinner, show dashboard
+ skeleton earlier with smaller loading indicators
+merge_request: 36399
+author:
+type: changed
diff --git a/changelogs/unreleased/225933-fa-play-replacement.yml b/changelogs/unreleased/225933-fa-play-replacement.yml
new file mode 100644
index 00000000000..7e850a46144
--- /dev/null
+++ b/changelogs/unreleased/225933-fa-play-replacement.yml
@@ -0,0 +1,5 @@
+---
+title: Replace FA play icon with svg in pipeline schedule and admin runner page
+merge_request: 36379
+author:
+type: other
diff --git a/changelogs/unreleased/sh-update-grape-1-4-0.yml b/changelogs/unreleased/sh-update-grape-1-4-0.yml
new file mode 100644
index 00000000000..d6273afea29
--- /dev/null
+++ b/changelogs/unreleased/sh-update-grape-1-4-0.yml
@@ -0,0 +1,5 @@
+---
+title: Update to Grape v1.4.0
+merge_request: 36628
+author:
+type: fixed
diff --git a/changelogs/unreleased/test-report-link-fix.yml b/changelogs/unreleased/test-report-link-fix.yml
new file mode 100644
index 00000000000..04a4e04bb81
--- /dev/null
+++ b/changelogs/unreleased/test-report-link-fix.yml
@@ -0,0 +1,5 @@
+---
+title: Fix for test report link in MR widget
+merge_request:
+author:
+type: fixed
diff --git a/config/initializers/grape_patch.rb b/config/initializers/grape_patch.rb
new file mode 100644
index 00000000000..a9ac0840541
--- /dev/null
+++ b/config/initializers/grape_patch.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+# Monkey patch for Grape v1.4.0: https://github.com/ruby-grape/grape/pull/2088
+
+require 'grape'
+
+# rubocop:disable Gitlab/ModuleWithInstanceVariables
+module Grape
+ module DSL
+ module InsideRoute
+ def stream(value = nil)
+ return if value.nil? && @stream.nil?
+
+ header 'Content-Length', nil
+ header 'Transfer-Encoding', nil
+ header 'Cache-Control', 'no-cache' # Skips ETag generation (reading the response up front)
+
+ if value.is_a?(String)
+ file_body = Grape::ServeStream::FileBody.new(value)
+ @stream = Grape::ServeStream::StreamResponse.new(file_body)
+ elsif value.respond_to?(:each)
+ @stream = Grape::ServeStream::StreamResponse.new(value)
+ elsif !value.is_a?(NilClass)
+ raise ArgumentError, 'Stream object must respond to :each.'
+ else
+ @stream
+ end
+ end
+ end
+ end
+end
+# rubocop:enable Gitlab/ModuleWithInstanceVariables
diff --git a/doc/.vale/gitlab/AlertBoxStyle.yml b/doc/.vale/gitlab/AlertBoxStyle.yml
new file mode 100644
index 00000000000..4eeda2ef37c
--- /dev/null
+++ b/doc/.vale/gitlab/AlertBoxStyle.yml
@@ -0,0 +1,13 @@
+---
+# Error: gitlab.AlertBoxStyle
+#
+# Makes sure alert boxes follow standard formatting.
+#
+# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+extends: existence
+message: 'Alert box "%s" must use the formatting detailed in the documentation style guide.'
+link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#alert-boxes
+level: error
+scope: raw
+raw:
+ - 'NOTE: \*\*[^:]*\*\*'
diff --git a/doc/administration/auth/ldap/index.md b/doc/administration/auth/ldap/index.md
index f4ecbf70b32..aef6c70ff92 100644
--- a/doc/administration/auth/ldap/index.md
+++ b/doc/administration/auth/ldap/index.md
@@ -53,7 +53,7 @@ are already logged in or are using Git over SSH will still be able to access
GitLab for up to one hour. Manually block the user in the GitLab Admin Area to
immediately block all access.
-NOTE: **Note**:
+NOTE: **Note:**
GitLab Enterprise Edition Starter supports a
[configurable sync time](#adjusting-ldap-user-sync-schedule-starter-only).
diff --git a/doc/administration/reference_architectures/2k_users.md b/doc/administration/reference_architectures/2k_users.md
index 43af39ece31..9b46fb1c303 100644
--- a/doc/administration/reference_architectures/2k_users.md
+++ b/doc/administration/reference_architectures/2k_users.md
@@ -473,7 +473,7 @@ nodes (including the Gitaly node using the certificate) and on all client nodes
that communicate with it following the procedure described in
[GitLab custom certificate configuration](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates).
-NOTE: **Note**
+NOTE: **Note:**
The self-signed certificate must specify the address you use to access the
Gitaly server. If you are addressing the Gitaly server by a hostname, you can
either use the Common Name field for this, or add it as a Subject Alternative
diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md
index cc2418f27b9..72fd0cd1c60 100644
--- a/doc/administration/uploads.md
+++ b/doc/administration/uploads.md
@@ -57,7 +57,7 @@ This configuration relies on valid AWS credentials to be configured already.
[Read more about using object storage with GitLab](object_storage.md).
-NOTE: **Note** We recommend using the [consolidated object storage settings](object_storage.md#consolidated-object-storage-configuration). The following instructions apply to the original config format.
+NOTE: **Note:** We recommend using the [consolidated object storage settings](object_storage.md#consolidated-object-storage-configuration). The following instructions apply to the original config format.
## Object Storage Settings
diff --git a/doc/api/boards.md b/doc/api/boards.md
index 155a876e76a..a370205aa01 100644
--- a/doc/api/boards.md
+++ b/doc/api/boards.md
@@ -452,7 +452,7 @@ POST /projects/:id/boards/:board_id/lists
| `assignee_id` **(PREMIUM)** | integer | no | The ID of a user |
| `milestone_id` **(PREMIUM)** | integer | no | The ID of a milestone |
-NOTE: **Note**:
+NOTE: **Note:**
Label, assignee and milestone arguments are mutually exclusive,
that is, only one of them are accepted in a request.
Check the [Issue Board docs](../user/project/issue_board.md#summary-of-features-per-tier)
diff --git a/doc/api/epics.md b/doc/api/epics.md
index a420ef4cd15..f2c3796f20c 100644
--- a/doc/api/epics.md
+++ b/doc/api/epics.md
@@ -42,7 +42,7 @@ CAUTION: **Deprecation**
> `reference` attribute in response is deprecated in favour of `references`.
> Introduced [GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354)
-NOTE: **Note**
+NOTE: **Note:**
> `references.relative` is relative to the group that the epic is being requested. When epic is fetched from its origin group
> `relative` format would be the same as `short` format and when requested cross groups it is expected to be the same as `full` format.
diff --git a/doc/api/feature_flags.md b/doc/api/feature_flags.md
index 911612274af..99303e23c37 100644
--- a/doc/api/feature_flags.md
+++ b/doc/api/feature_flags.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
-NOTE: **Note**
+NOTE: **Note:**
This API is behind a [feature flag](../operations/feature_flags.md#enable-or-disable-feature-flag-strategies).
If this flag is not enabled in your environment, you can use the [legacy feature flags API](feature_flags_legacy.md).
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 470126d568d..2d5c7f0691a 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -1692,6 +1692,11 @@ input CreateDiffNoteInput {
clientMutationId: String
"""
+ The confidentiality flag of a note. Default is false.
+ """
+ confidential: Boolean
+
+ """
The global id of the resource to add a note to
"""
noteableId: ID!
@@ -1817,6 +1822,11 @@ input CreateImageDiffNoteInput {
clientMutationId: String
"""
+ The confidentiality flag of a note. Default is false.
+ """
+ confidential: Boolean
+
+ """
The global id of the resource to add a note to
"""
noteableId: ID!
@@ -1917,6 +1927,11 @@ input CreateNoteInput {
clientMutationId: String
"""
+ The confidentiality flag of a note. Default is false.
+ """
+ confidential: Boolean
+
+ """
The global id of the discussion this note is in reply to
"""
discussionId: ID
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index d14ad46d205..f240703ba18 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -4497,6 +4497,16 @@
"defaultValue": null
},
{
+ "name": "confidential",
+ "description": "The confidentiality flag of a note. Default is false.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "position",
"description": "The position of this note on a diff",
"type": {
@@ -4835,6 +4845,16 @@
"defaultValue": null
},
{
+ "name": "confidential",
+ "description": "The confidentiality flag of a note. Default is false.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "position",
"description": "The position of this note on a diff",
"type": {
@@ -5107,6 +5127,16 @@
"defaultValue": null
},
{
+ "name": "confidential",
+ "description": "The confidentiality flag of a note. Default is false.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "discussionId",
"description": "The global id of the discussion this note is in reply to",
"type": {
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 75f74fa39a6..a4555b2a712 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -20,7 +20,7 @@ CAUTION: **Deprecation**
> `reference` attribute in response is deprecated in favour of `references`.
> Introduced [GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354)
-NOTE: **Note**
+NOTE: **Note:**
> `references.relative` is relative to the group / project that the issue is being requested. When issue is fetched from its project
> `relative` format would be the same as `short` format and when requested across groups / projects it is expected to be the same as `full` format.
@@ -877,10 +877,10 @@ the `weight` parameter:
NOTE: **Note:**
At least one of following parameters is required to be passed for the request to be successful: `:assignee_id`, `:assignee_ids`, `:confidential`, `:created_at`, `:description`, `:discussion_locked`, `:due_date`, `:labels`, `:milestone_id`, `:state_event`, or `:title`.
-NOTE: **Note**:
+NOTE: **Note:**
`assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
-NOTE: **Note**:
+NOTE: **Note:**
The `closed_by` attribute was [introduced in GitLab 10.6](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042). This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
## Delete an issue
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 5f28ff8d69e..2ec399fc507 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -6,7 +6,7 @@ CAUTION: **Deprecation**
> `reference` attribute in response is deprecated in favour of `references`.
> Introduced [GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354)
-NOTE: **Note**
+NOTE: **Note:**
> `references.relative` is relative to the group / project that the merge request is being requested. When merge request is fetched from its project
> `relative` format would be the same as `short` format and when requested across groups / projects it is expected to be the same as `full` format.
diff --git a/doc/api/releases/links.md b/doc/api/releases/links.md
index 35cb66e59a1..242b5eb41f5 100644
--- a/doc/api/releases/links.md
+++ b/doc/api/releases/links.md
@@ -138,7 +138,7 @@ PUT /projects/:id/releases/:tag_name/assets/links/:link_id
| `url` | string | no | The URL of the link. |
| `link_type` | string | no | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`. |
-NOTE: **NOTE**
+NOTE: **Note:**
You have to specify at least one of `name` or `url`
Example request:
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 6a4e7a16b90..724f71da118 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -16,9 +16,9 @@ through the [continuous methodologies](introduction/index.md#introduction-to-cic
- Continuous Delivery (CD)
- Continuous Deployment (CD)
-NOTE: **Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.**
-Watch our
-["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
+NOTE: **Note:**
+Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.
+Watch our ["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
webcast to learn about continuous methods and how GitLab’s built-in CI can help you simplify and scale software development.
## Overview
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index 6f429914409..4bed6d9e323 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -149,7 +149,7 @@ released.
#### TLS enabled
-NOTE: **Note**
+NOTE: **Note:**
Requires GitLab Runner 11.11 or later, but is not supported if GitLab
Runner is installed using the [Helm
chart](https://docs.gitlab.com/runner/install/kubernetes.html). See the
diff --git a/doc/ci/environments/protected_environments.md b/doc/ci/environments/protected_environments.md
index 3a44fcfb182..b6141ddc7ac 100644
--- a/doc/ci/environments/protected_environments.md
+++ b/doc/ci/environments/protected_environments.md
@@ -22,7 +22,7 @@ specific environments are "protected" to prevent unauthorized people from affect
By default, a protected environment does one thing: it ensures that only people
with the right privileges can deploy to it, thus keeping it safe.
-NOTE: **Note**:
+NOTE: **Note:**
A GitLab admin is always allowed to use environments, even if they are protected.
To protect, update, or unprotect an environment, you need to have at least
diff --git a/doc/ci/introduction/index.md b/doc/ci/introduction/index.md
index d2e569a1e73..1836c2a4112 100644
--- a/doc/ci/introduction/index.md
+++ b/doc/ci/introduction/index.md
@@ -12,9 +12,9 @@ In this document, we'll present an overview of the concepts of Continuous Integr
Continuous Delivery, and Continuous Deployment, as well as an introduction to
GitLab CI/CD.
-NOTE: **Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.**
-Watch our
-["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
+NOTE: **Note:**
+Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.
+Watch our ["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
webcast to learn about continuous methods and how GitLab’s built-in CI can help you simplify and scale software development.
## Introduction to CI/CD methodologies
diff --git a/doc/ci/merge_request_pipelines/index.md b/doc/ci/merge_request_pipelines/index.md
index 444569a6eaf..2a6008e6307 100644
--- a/doc/ci/merge_request_pipelines/index.md
+++ b/doc/ci/merge_request_pipelines/index.md
@@ -24,7 +24,7 @@ can run a pipeline for merge requests.
![Merge request page](img/merge_request.png)
-NOTE: **Note**:
+NOTE: **Note:**
If you use this feature with [merge when pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md),
pipelines for merge requests take precedence over the other regular pipelines.
diff --git a/doc/ci/pipelines/settings.md b/doc/ci/pipelines/settings.md
index eca96a5d89f..39acef14443 100644
--- a/doc/ci/pipelines/settings.md
+++ b/doc/ci/pipelines/settings.md
@@ -36,7 +36,7 @@ in `.gitlab-ci.yml`.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/28919) in GitLab 12.0.
-NOTE: **Note**:
+NOTE: **Note:**
As of GitLab 12.0, newly created projects will automatically have a default
`git depth` value of `50`.
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 1611d21e853..fad7243462c 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -4086,7 +4086,7 @@ You can set them globally or per-job in the [`variables`](#variables) section.
> Introduced in GitLab 8.9 as an experimental feature.
-NOTE: **Note**:
+NOTE: **Note:**
As of GitLab 12.0, newly created projects will automatically have a [default `git depth` value of `50`](../pipelines/settings.md#git-shallow-clone).
You can specify the depth of fetching and cloning using `GIT_DEPTH`. This allows
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index e7e32190298..00a0573a8ba 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -42,10 +42,9 @@ the `author` field. GitLab team members **should not**.
Example: "Fixed a typo on the search results page."
- Any docs-only changes **should not** have a changelog entry.
- Any change behind a feature flag **should not** have a changelog entry - unless
- the feature flag has been defaulted to true. The entry should be added
- [in the merge request removing the feature flags](feature_flags/development.md).
- If the change includes a database migration (regular, post, or data migration),
- there should be a changelog entry for the migration change.
+ the feature flag has been defaulted to true.
+- A change that [removes a feature flag](feature_flags/development.md) **should** have a changelog entry -
+ only if the feature flag did not default to true already.
- A fix for a regression introduced and then fixed in the same release (i.e.,
fixing a bug introduced during a monthly release candidate) **should not**
have a changelog entry.
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 43ad86c7074..1219ba9eced 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -800,7 +800,7 @@ To link to internal documentation:
- `../../issues/tags.md`
- `../../issues/tags.md#stages`
-NOTE: **Note**:
+NOTE: **Note:**
Using the Markdown extension is necessary for the [`/help`](index.md#gitlab-help) section of GitLab.
### Links to external documentation
diff --git a/doc/development/elasticsearch.md b/doc/development/elasticsearch.md
index 425b6b01b76..90debab3b5c 100644
--- a/doc/development/elasticsearch.md
+++ b/doc/development/elasticsearch.md
@@ -60,7 +60,7 @@ The `whitespace` tokenizer was selected in order to have more control over how t
Please see the `code` filter for an explanation on how tokens are split.
-NOTE: **Known Issues**:
+NOTE: **Note:**
Currently the [Elasticsearch code_analyzer doesn't account for all code cases](../integration/elasticsearch.md#known-issues).
#### `code_search_analyzer`
@@ -157,7 +157,8 @@ The global configurations per version are now in the `Elastic::(Version)::Config
### Creating new version of schema
-NOTE: **Note:** this is not applicable yet as multiple indices functionality is not fully implemented.
+NOTE: **Note:**
+This is not applicable yet as multiple indices functionality is not fully implemented.
Folders like `ee/lib/elastic/v12p1` contain snapshots of search logic from different versions. To keep a continuous Git history, the latest version lives under `ee/lib/elastic/latest`, but its classes are aliased under an actual version (e.g. `ee/lib/elastic/v12p3`). When referencing these classes, never use the `Latest` namespace directly, but use the actual version (e.g. `V12p3`).
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index 2e4811981b4..448c5e149cc 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -7,7 +7,7 @@ type: howto
This page offers a walkthrough of a common configuration
for GitLab on AWS. You should customize it to accommodate your needs.
-NOTE: **Note**
+NOTE: **Note:**
For organizations with 1,000 users or less, the recommended AWS installation method is to launch an EC2 single box [Omnibus Installation](https://about.gitlab.com/install/) and implement a snapshot strategy for backing up the data. See the [1,000 user reference architecture](../../administration/reference_architectures/1k_users.md) for more.
## Introduction
@@ -739,7 +739,7 @@ To back up GitLab:
sudo gitlab-backup create
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
### Restoring GitLab from a backup
@@ -760,7 +760,7 @@ released, you can update your GitLab instance:
sudo gitlab-backup create
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
1. Update the repositories and install GitLab:
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index 48f4472868d..aa534078105 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -545,7 +545,7 @@ Here are some common pitfalls and how to overcome them:
If you see `"Kaminari::PaginatableArray"` you are using Elasticsearch.
- NOTE: **Note**:
+ NOTE: **Note:**
The above instructions are used to verify that GitLab is using Elasticsearch only when indexing all namespaces. This is not to be used for scenarios that only index a [subset of namespaces](#limiting-namespaces-and-projects).
- **I updated GitLab and now I can't find anything**
@@ -568,7 +568,7 @@ Here are some common pitfalls and how to overcome them:
pp s.search_objects.to_a
```
- NOTE: **Note**:
+ NOTE: **Note:**
The above instructions are not to be used for scenarios that only index a [subset of namespaces](#limiting-namespaces-and-projects).
See [Elasticsearch Index Scopes](#elasticsearch-index-scopes) for more information on searching for specific types of data.
diff --git a/doc/integration/jira_development_panel.md b/doc/integration/jira_development_panel.md
index f032345b9e0..85404ff3164 100644
--- a/doc/integration/jira_development_panel.md
+++ b/doc/integration/jira_development_panel.md
@@ -16,7 +16,7 @@ A top-level GitLab group is one that does not have any parent group itself. All
as well as projects of the top-level group's subgroups nesting down, are connected. Alternatively, you can specify
a GitLab personal namespace in the Jira configuration, which will then connect the projects in that personal namespace to Jira.
-NOTE: **Note**:
+NOTE: **Note:**
Note this is different from the [existing Jira](../user/project/integrations/jira.md) project integration, where the mapping
is one GitLab project to the entire Jira instance.
@@ -55,7 +55,7 @@ There are no special requirements if you are using GitLab.com.
replacing `<your-gitlab-instance-domain>` appropriately. So for example, if you are using GitLab.com,
this would be `https://gitlab.com/login/oauth/callback`.
- NOTE: **Note**:
+ NOTE: **Note:**
If using a GitLab version earlier than 11.3, the `Redirect URI` must be
`https://<your-gitlab-instance-domain>/-/jira/login/oauth/callback`. If you want Jira
to have access to all projects, GitLab recommends an administrator creates the
@@ -90,7 +90,7 @@ There are no special requirements if you are using GitLab.com.
replacing `<your-gitlab-instance-domain>` appropriately. So for example, if you are using GitLab.com,
this would be `https://gitlab.com/`.
- NOTE: **Note**:
+ NOTE: **Note:**
If using a GitLab version earlier than 11.3 the `Host URL` value should be `https://<your-gitlab-instance-domain>/-/jira`
For the `Client ID` field, use the `Application ID` value from the previous section.
diff --git a/doc/migrate_ci_to_ce/README.md b/doc/migrate_ci_to_ce/README.md
index 10f22af30f7..6710356d760 100644
--- a/doc/migrate_ci_to_ce/README.md
+++ b/doc/migrate_ci_to_ce/README.md
@@ -77,7 +77,7 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production SKIP=r
If this fails you need to fix it before upgrading to 8.0. Also see
<https://about.gitlab.com/get-help/>
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
### 2. Check source and target database types
diff --git a/doc/operations/metrics/index.md b/doc/operations/metrics/index.md
index 1c1724842b8..8c7c4bf92be 100644
--- a/doc/operations/metrics/index.md
+++ b/doc/operations/metrics/index.md
@@ -94,7 +94,7 @@ receivers:
In order for GitLab to associate your alerts with an [environment](../../ci/environments/index.md), you need to configure a `gitlab_environment_name` label on the alerts you set up in Prometheus. The value of this should match the name of your Environment in GitLab.
-NOTE: **Note**
+NOTE: **Note:**
In GitLab versions 13.1 and greater, you can configure your manually configured Prometheus server to use the [Generic alerts integration](../../user/project/integrations/generic_alerts.md).
## Taking action on incidents **(ULTIMATE)**
diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md
index 6ee454d8b4b..c66a0625110 100644
--- a/doc/policy/maintenance.md
+++ b/doc/policy/maintenance.md
@@ -66,7 +66,7 @@ one major version. For example, it is safe to:
- `9.5.5` -> `9.5.9`
- `8.9.2` -> `8.9.6`
-NOTE: **Note** Version specific changes in Omnibus GitLab Linux packages can be found in [the Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/update/README.html#version-specific-changes).
+NOTE: **Note:** Version specific changes in Omnibus GitLab Linux packages can be found in [the Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/update/README.html#version-specific-changes).
NOTE: **Note:**
Instructions are available for downloading an Omnibus GitLab Linux package locally and [manually installing](https://docs.gitlab.com/omnibus/manual_install.html) it.
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index c10dac2750c..0df41894fec 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -67,7 +67,7 @@ Use this command if you've installed GitLab with the Omnibus package:
sudo gitlab-backup create
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
Use this if you've installed GitLab from source:
@@ -82,7 +82,7 @@ If you are running GitLab within a Docker container, you can run the backup from
docker exec -t <container name> gitlab-backup create
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
If you are using the [GitLab Helm chart](https://gitlab.com/gitlab-org/charts/gitlab) on a
@@ -198,7 +198,7 @@ To use the `copy` strategy instead of the default streaming strategy, specify
sudo gitlab-backup create STRATEGY=copy
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
#### Backup filename
@@ -213,7 +213,7 @@ By default a backup file is created according to the specification in [the Backu
sudo gitlab-backup create BACKUP=dump
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
The resulting file will then be `dump_gitlab_backup.tar`. This is useful for systems that make use of rsync and incremental backups, and will result in considerably faster transfer speeds.
@@ -228,7 +228,7 @@ Note that the `--rsyncable` option in `gzip` is not guaranteed to be available o
sudo gitlab-backup create BACKUP=dump GZIP_RSYNCABLE=yes
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
#### Excluding specific directories from the backup
@@ -256,7 +256,7 @@ For Omnibus GitLab packages:
sudo gitlab-backup create SKIP=db,uploads
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
For installations from source:
@@ -497,7 +497,7 @@ sudo gitlab-backup create DIRECTORY=daily
sudo gitlab-backup create DIRECTORY=weekly
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
#### Uploading to locally mounted shares
@@ -603,7 +603,7 @@ For Omnibus GitLab packages:
0 2 * * * /opt/gitlab/bin/gitlab-backup create CRON=1
```
- NOTE: **Note**
+ NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
For installations from source:
@@ -804,7 +804,7 @@ restore:
sudo gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:restore`.
CAUTION: **Warning:**
@@ -826,7 +826,7 @@ If there is a GitLab version mismatch between your backup tar file and the insta
version of GitLab, the restore command will abort with an error. Install the
[correct GitLab version](https://packages.gitlab.com/gitlab/) and try again.
-NOTE: **Note**
+NOTE: **Note:**
There is currently a [known issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/3470) for restore not working
with `pgbouncer`. In order to workaround the issue, the Rails node will need to bypass `pgbouncer` and connect
directly to the primary database node. This can be done by setting `gitlab_rails['db_host']` and `gitlab_rails['port']`
@@ -852,7 +852,7 @@ For Docker installations, the restore task can be run from host:
docker exec -it <name of container> gitlab-backup restore
```
-NOTE: **Note**
+NOTE: **Note:**
For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:restore`.
CAUTION: **Warning:**
@@ -881,7 +881,7 @@ export your project or group from there:
1. After importing only the project(s) or group(s) that you wanted is complete,
you may delete the new, temporary GitLab instance.
-NOTE: **Note**
+NOTE: **Note:**
A feature request to provide direct restore of individual projects or groups
is being discussed in [issue #17517](https://gitlab.com/gitlab-org/gitlab/-/issues/17517).
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 8fa061724f2..01e61095fe2 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -110,7 +110,7 @@ Auto DevOps provides great defaults for all the stages and makes use of [CI temp
For an overview on the creation of Auto DevOps, read more
[in this blog post](https://about.gitlab.com/blog/2017/06/29/whats-next-for-gitlab-ci/).
-NOTE: **Note**
+NOTE: **Note:**
Kubernetes clusters can [be used without](../../user/project/clusters/index.md)
Auto DevOps.
diff --git a/doc/topics/autodevops/stages.md b/doc/topics/autodevops/stages.md
index 3058afe9b50..6d782373f39 100644
--- a/doc/topics/autodevops/stages.md
+++ b/doc/topics/autodevops/stages.md
@@ -72,7 +72,7 @@ Heroku buildpacks, with the following caveats:
- The `/bin/herokuish` command is not present in the resulting image, and prefixing
commands with `/bin/herokuish procfile exec` is no longer required (nor possible).
-NOTE: **Note**: Auto Test still uses Herokuish, as test suite detection is not
+NOTE: **Note:** Auto Test still uses Herokuish, as test suite detection is not
yet part of the Cloud Native Buildpack specification. For more information, see
[this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/212689).
diff --git a/doc/topics/web_application_firewall/index.md b/doc/topics/web_application_firewall/index.md
index 0ecf4b2d109..5ce7c0779bb 100644
--- a/doc/topics/web_application_firewall/index.md
+++ b/doc/topics/web_application_firewall/index.md
@@ -25,7 +25,7 @@ applications which have an Ingress.
The ModSecurity module runs with the [OWASP Core Rule Set (CRS)](https://coreruleset.org/) by default. The OWASP CRS will detect and log a wide range of common attacks.
-NOTE: **Note**
+NOTE: **Note:**
The WAF is deployed in "Detection-only mode" by default and will only log attack
attempts.
@@ -60,7 +60,7 @@ If you are using a self-managed instance of GitLab, you need to configure the
[Google OAuth2 OmniAuth Provider](../../integration/google.md) before
you can configure a cluster on GKE. Once this is set up, you can follow the steps on the [quick start guide](quick_start_guide.md) to get started.
-NOTE: **Note**
+NOTE: **Note:**
This guide shows how the WAF can be deployed using Auto DevOps. The WAF
is available by default to all applications no matter how they are deployed,
as long as they are using Ingress.
diff --git a/doc/update/upgrading_from_ce_to_ee.md b/doc/update/upgrading_from_ce_to_ee.md
index 78227f18457..7be1feb99a5 100644
--- a/doc/update/upgrading_from_ce_to_ee.md
+++ b/doc/update/upgrading_from_ce_to_ee.md
@@ -4,7 +4,7 @@ comments: false
# Upgrading from Community Edition to Enterprise Edition from source
-NOTE: **NOTE** In the past we used separate documents for upgrading from
+NOTE: **Note:** In the past we used separate documents for upgrading from
Community Edition to Enterprise Edition. These documents can be found in the
[`doc/update` directory of Enterprise Edition's source
code](https://gitlab.com/gitlab-org/gitlab/tree/11-8-stable-ee/doc/update).
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index 92d29e6a49f..0479da7fb52 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -62,7 +62,7 @@ To change it at the:
1. Change the value of **maximum artifacts size (in MB)**.
1. Click **Save changes** for the changes to take effect.
-NOTE: **Note**
+NOTE: **Note:**
The setting at all levels is only available to GitLab administrators.
## Default artifacts expiration **(CORE ONLY)**
@@ -80,7 +80,7 @@ This setting is set per job and can be overridden in
[`.gitlab-ci.yml`](../../../ci/yaml/README.md#artifactsexpire_in).
To disable the expiration, set it to `0`. The default unit is in seconds.
-NOTE: **Note**
+NOTE: **Note:**
Any changes to this setting will apply to new artifacts only. The expiration time will not
be updated for artifacts created before this setting was changed.
The administrator may need to manually search for and expire previously-created
diff --git a/doc/user/application_security/configuration/index.md b/doc/user/application_security/configuration/index.md
index f0fcd0c4419..a9b879656ed 100644
--- a/doc/user/application_security/configuration/index.md
+++ b/doc/user/application_security/configuration/index.md
@@ -14,7 +14,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
The security configuration page displays the configuration state of each of the security
features and can be accessed through a project's sidebar nav.
-![Screenshot of security configuration page](../img/security_configuration_page_v13_1.png)
+![Screenshot of security configuration page](../img/security_configuration_page_v13_2.png)
The page uses the project's latest default branch [CI pipeline](../../../ci/pipelines/index.md) to determine the configuration
state of each feature. If a job with the expected security report artifact exists in the pipeline,
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 47b00e8bc64..272195fef87 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -9,9 +9,9 @@ type: reference, howto
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/4348) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.4.
-NOTE: **4 of the top 6 attacks were application based.**
-Download our whitepaper,
-["A Seismic Shift in Application Security"](https://about.gitlab.com/resources/whitepaper-seismic-shift-application-security/)
+NOTE: **Note:**
+The whitepaper ["A Seismic Shift in Application Security"](https://about.gitlab.com/resources/whitepaper-seismic-shift-application-security/)
+explains how **4 of the top 6 attacks were application based**. Download it
to learn how to protect your organization.
Running [static checks](../sast/index.md) on your code is the first step to detect
diff --git a/doc/user/application_security/img/security_configuration_page_v13_1.png b/doc/user/application_security/img/security_configuration_page_v13_1.png
deleted file mode 100644
index 176c64a9e87..00000000000
--- a/doc/user/application_security/img/security_configuration_page_v13_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/img/security_configuration_page_v13_2.png b/doc/user/application_security/img/security_configuration_page_v13_2.png
new file mode 100644
index 00000000000..016328948cc
--- /dev/null
+++ b/doc/user/application_security/img/security_configuration_page_v13_2.png
Binary files differ
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index 731c4fd0c7a..b5092f58d37 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -9,9 +9,9 @@ type: reference, howto
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3775) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.3.
-NOTE: **4 of the top 6 attacks were application based.**
-Download our whitepaper,
-["A Seismic Shift in Application Security"](https://about.gitlab.com/resources/whitepaper-seismic-shift-application-security/)
+NOTE: **Note:**
+The whitepaper ["A Seismic Shift in Application Security"](https://about.gitlab.com/resources/whitepaper-seismic-shift-application-security/)
+explains how **4 of the top 6 attacks were application based**. Download it
to learn how to protect your organization.
## Overview
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index 7a2eed39d84..41b420ce7f6 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -85,7 +85,7 @@ Next, you will create a package for that recipe by running `conan create` provid
conan create . my-org+my-group+my-project/beta
```
-NOTE: **Note**
+NOTE: **Note:**
Current [naming restrictions](#package-recipe-naming-convention) require you to name the `user` value as the `+` separated path of your project on GitLab.
The example above would create a package belonging to this project: `https://gitlab.com/my-org/my-group/my-project` with a channel of `beta`.
@@ -129,12 +129,12 @@ Once you have a personal access token and have [set your Conan remote](#adding-t
conan user <gitlab_username or deploy_token_username> -r gitlab -p <personal_access_token or deploy_token>
```
-Note: **Note**
+NOTE: **Note:**
If you named your remote something other than `gitlab`, your remote name should be used in this command instead of `gitlab`.
From now on, when you run commands using `--remote=gitlab`, your username and password will automatically be included in the requests.
-Note: **Note**
+NOTE: **Note:**
The personal access token is not stored locally at any moment. Conan uses JWT, so when you run this command, Conan will request an expirable token from GitLab using your token. The JWT does expire on a regular basis, so you will need to re-enter your personal access token when that happens.
Alternatively, you could explicitly include your credentials in any given command.
@@ -152,7 +152,7 @@ If you'd like Conan to always use GitLab as the registry for your package, you c
conan remote add_ref Hello/0.1@my-group+my-project/beta gitlab
```
-NOTE: **Note**
+NOTE: **Note:**
The package recipe does include the version, so setting the default remote for `Hello/0.1@user/channel` will not work for `Hello/0.2@user/channel`.
This functionality is best suited for when you want to consume or install packages from the GitLab registry without having to specify a remote.
diff --git a/doc/user/project/clusters/add_remove_clusters.md b/doc/user/project/clusters/add_remove_clusters.md
index f581383022e..5f5c5868900 100644
--- a/doc/user/project/clusters/add_remove_clusters.md
+++ b/doc/user/project/clusters/add_remove_clusters.md
@@ -13,9 +13,9 @@ GitLab offers integrated cluster creation for the following Kubernetes providers
GitLab can also integrate with any standard Kubernetes provider, either on-premise or hosted.
-NOTE: **Scalable app deployment with GitLab and Google Cloud Platform**
-[Watch the webcast](https://about.gitlab.com/webcast/scalable-app-deploy/) and
-learn how to spin up a Kubernetes cluster managed by Google Cloud Platform (GCP)
+NOTE: **Note:**
+Watch the webcast [Scalable app deployment with GitLab and Google Cloud Platform](https://about.gitlab.com/webcast/scalable-app-deploy/)
+and learn how to spin up a Kubernetes cluster managed by Google Cloud Platform (GCP)
in a few clicks.
TIP: **Tip:**
@@ -308,7 +308,7 @@ integration to work properly.
![rbac](img/rbac_v13_1.png)
-NOTE: **Note**: Disabling RBAC means that any application running in the cluster,
+NOTE: **Note:** Disabling RBAC means that any application running in the cluster,
or user who can authenticate to the cluster, has full API access. This is a
[security concern](index.md#security-implications), and may not be desirable.
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 4aa5e87e147..b99925f8e5d 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -224,7 +224,7 @@ Auto Monitoring) you will need the Kubernetes project integration enabled.
[Read more about Auto DevOps](../../../topics/autodevops/index.md)
-NOTE: **Note**
+NOTE: **Note:**
Kubernetes clusters can be used without Auto DevOps.
## Deploying to a Kubernetes cluster
diff --git a/doc/user/project/clusters/kubernetes_pod_logs.md b/doc/user/project/clusters/kubernetes_pod_logs.md
index 509be4ed0a8..ee642dc18cf 100644
--- a/doc/user/project/clusters/kubernetes_pod_logs.md
+++ b/doc/user/project/clusters/kubernetes_pod_logs.md
@@ -13,9 +13,9 @@ GitLab makes it easy to view the logs of running pods in [connected Kubernetes c
By displaying the logs directly in GitLab in the **Log Explorer**, developers can avoid
managing console tools or jumping to a different interface.
-NOTE: **Kubernetes + GitLab**
+NOTE: **Note:**
+[Learn more about Kubernetes + GitLab](https://about.gitlab.com/solutions/kubernetes/).
Everything you need to build, test, deploy, and run your application at scale.
-[Learn more](https://about.gitlab.com/solutions/kubernetes/).
## Overview
diff --git a/doc/user/project/code_owners.md b/doc/user/project/code_owners.md
index 6b81aea4b87..f2150270c56 100644
--- a/doc/user/project/code_owners.md
+++ b/doc/user/project/code_owners.md
@@ -73,7 +73,7 @@ be used for merge request approvals:
- As [merge request eligible approvers](merge_requests/merge_request_approvals.md#code-owners-as-eligible-approvers).
- As required approvers for [protected branches](protected_branches.md#protected-branches-approval-by-code-owners-premium). **(PREMIUM)**
-NOTE: **Note**:
+NOTE: **Note:**
Developer or higher [permissions](../permissions.md) are required in order to
approve a merge request.
diff --git a/doc/user/project/integrations/generic_alerts.md b/doc/user/project/integrations/generic_alerts.md
index f8b7cd2acd9..de343425931 100644
--- a/doc/user/project/integrations/generic_alerts.md
+++ b/doc/user/project/integrations/generic_alerts.md
@@ -18,7 +18,7 @@ create an issue with the payload in the body of the issue. You can always
The entire payload will be posted in the issue discussion as a comment
authored by the GitLab Alert Bot.
-NOTE: **Note**
+NOTE: **Note:**
In GitLab versions 13.1 and greater, you can configure [External Prometheus instances](../../../operations/metrics/index.md#external-prometheus-instances) to use this endpoint.
## Setting up generic alerts
diff --git a/doc/user/project/integrations/jira_cloud_configuration.md b/doc/user/project/integrations/jira_cloud_configuration.md
index 619c94b282b..c7157b6bd0e 100644
--- a/doc/user/project/integrations/jira_cloud_configuration.md
+++ b/doc/user/project/integrations/jira_cloud_configuration.md
@@ -5,7 +5,7 @@ below to create one:
1. Log in to [`id.atlassian.com`](https://id.atlassian.com/manage-profile/security/api-tokens) with your email address.
- NOTE: **Note**
+ NOTE: **Note:**
It is important that the user associated with this email address has *write* access
to projects in Jira.
diff --git a/doc/user/project/integrations/jira_server_configuration.md b/doc/user/project/integrations/jira_server_configuration.md
index 1efd0ff3944..c8278a0f083 100644
--- a/doc/user/project/integrations/jira_server_configuration.md
+++ b/doc/user/project/integrations/jira_server_configuration.md
@@ -6,7 +6,7 @@ need to integrate with GitLab.
As an example, we'll create a user named `gitlab` and add it to a new group
named `gitlab-developers`.
-NOTE: **Note**
+NOTE: **Note:**
It is important that the Jira user created for the integration is given 'write'
access to your Jira projects. This is covered in the process below.
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
index bf9b58acf14..0425ca56285 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
@@ -287,7 +287,7 @@ To enable this setting:
1. Navigate to your project's **Settings > Pages**.
1. Tick the checkbox **Force HTTPS (requires valid certificates)**.
-NOTE: **Note**
+NOTE: **Note:**
If you use CloudFlare CDN in front of GitLab Pages, make sure to set the SSL connection setting to `full` instead of `flexible`. For more details, see the [CloudFlare CDN directions](https://support.cloudflare.com/hc/en-us/articles/200170416-End-to-end-HTTPS-with-Cloudflare-Part-3-SSL-options#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef).
<!-- ## Troubleshooting
diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md
index 301f750d90a..baad5027703 100644
--- a/doc/user/project/repository/reducing_the_repo_size_using_git.md
+++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md
@@ -100,7 +100,7 @@ To make cloning your project faster, rewrite branches and tags to remove unwante
1. Manually run [project housekeeping](../../../administration/housekeeping.md#manual-housekeeping)
-NOTE: **Note**
+NOTE: **Note:**
Project statistics are cached for performance. You may need to wait 5-10 minutes
to see a reduction in storage utilization.
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 3cb7b38cd1c..01b89959c14 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -504,7 +504,7 @@ module API
header['X-Sendfile'] = path
body
else
- file path
+ sendfile path
end
end
diff --git a/lib/gitlab/incident_management/pager_duty/incident_issue_description.rb b/lib/gitlab/incident_management/pager_duty/incident_issue_description.rb
new file mode 100644
index 00000000000..cd947b15154
--- /dev/null
+++ b/lib/gitlab/incident_management/pager_duty/incident_issue_description.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module IncidentManagement
+ module PagerDuty
+ class IncidentIssueDescription
+ def initialize(incident_payload)
+ @incident_payload = incident_payload
+ end
+
+ def to_s
+ markdown_line_break = " \n"
+
+ [
+ "**Incident:** #{markdown_incident}",
+ "**Incident number:** #{incident_payload['incident_number']}",
+ "**Urgency:** #{incident_payload['urgency']}",
+ "**Status:** #{incident_payload['status']}",
+ "**Incident key:** #{incident_payload['incident_key']}",
+ "**Created at:** #{markdown_incident_created_at}",
+ "**Assignees:** #{markdown_assignees.join(', ')}",
+ "**Impacted services:** #{markdown_impacted_services.join(', ')}"
+ ].join(markdown_line_break)
+ end
+
+ private
+
+ attr_reader :incident_payload
+
+ def markdown_incident
+ markdown_link(incident_payload['title'], incident_payload['url'])
+ end
+
+ def incident_created_at
+ Time.parse(incident_payload['created_at'])
+ rescue
+ Time.current.utc # PagerDuty provides time in UTC
+ end
+
+ def markdown_incident_created_at
+ incident_created_at.strftime('%d %B %Y, %-l:%M%p (%Z)')
+ end
+
+ def markdown_assignees
+ Array(incident_payload['assignees']).map do |assignee|
+ markdown_link(assignee['summary'], assignee['url'])
+ end
+ end
+
+ def markdown_impacted_services
+ Array(incident_payload['impacted_services']).map do |is|
+ markdown_link(is['summary'], is['url'])
+ end
+ end
+
+ def markdown_link(label, url)
+ return label if url.blank?
+
+ "[#{label}](#{url})"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/instrumentation/redis_base.rb b/lib/gitlab/instrumentation/redis_base.rb
index 7c08d5e8461..ad2df70f35d 100644
--- a/lib/gitlab/instrumentation/redis_base.rb
+++ b/lib/gitlab/instrumentation/redis_base.rb
@@ -25,9 +25,6 @@ module Gitlab
# redis-rb passes an array (e.g. [[:get, key]])
return unless args.length == 1
- # TODO: Add information about current Redis client
- # being instrumented.
- # https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/316.
detail_store << {
cmd: args.first,
duration: duration,
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index f81db6a2d99..5bf7a4e06e3 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -124,7 +124,7 @@ module Gitlab
issues_created_manually_from_alerts: issues_created_manually_from_alerts,
incident_issues: alert_bot_incident_count,
alert_bot_incident_issues: alert_bot_incident_count,
- incident_labeled_issues: count(::Issue.with_label_attributes(IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES)),
+ incident_labeled_issues: count(::Issue.with_label_attributes(::IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES)),
keys: count(Key),
label_lists: count(List.label),
lfs_objects: count(LfsObject),
diff --git a/lib/pager_duty/webhook_payload_parser.rb b/lib/pager_duty/webhook_payload_parser.rb
new file mode 100644
index 00000000000..573fb36f0ca
--- /dev/null
+++ b/lib/pager_duty/webhook_payload_parser.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module PagerDuty
+ class WebhookPayloadParser
+ def initialize(payload)
+ @payload = payload
+ end
+
+ def self.call(payload)
+ new(payload).call
+ end
+
+ def call
+ Array(payload['messages']).map { |msg| parse_message(msg) }
+ end
+
+ private
+
+ attr_reader :payload
+
+ def parse_message(message)
+ {
+ 'event' => message['event'],
+ 'incident' => parse_incident(message['incident'])
+ }
+ end
+
+ def parse_incident(incident)
+ return {} if incident.blank?
+
+ {
+ 'url' => incident['html_url'],
+ 'incident_number' => incident['incident_number'],
+ 'title' => incident['title'],
+ 'status' => incident['status'],
+ 'created_at' => incident['created_at'],
+ 'urgency' => incident['urgency'],
+ 'incident_key' => incident['incident_key'],
+ 'assignees' => reject_empty(parse_assignees(incident)),
+ 'impacted_services' => reject_empty(parse_impacted_services(incident))
+ }
+ end
+
+ def parse_assignees(incident)
+ Array(incident['assignments']).map do |a|
+ {
+ 'summary' => a.dig('assignee', 'summary'),
+ 'url' => a.dig('assignee', 'html_url')
+ }
+ end
+ end
+
+ def parse_impacted_services(incident)
+ Array(incident['impacted_services']).map do |is|
+ {
+ 'summary' => is['summary'],
+ 'url' => is['html_url']
+ }
+ end
+ end
+
+ def reject_empty(entities)
+ Array(entities).reject { |e| e['summary'].blank? && e['url'].blank? }
+ end
+ end
+end
diff --git a/lib/peek/views/elasticsearch.rb b/lib/peek/views/elasticsearch.rb
index 626a6fb1316..4d82a6eac4f 100644
--- a/lib/peek/views/elasticsearch.rb
+++ b/lib/peek/views/elasticsearch.rb
@@ -40,7 +40,7 @@ module Peek
end
def format_call_details(call)
- super.merge(request: "#{call[:method]} #{call[:path]}")
+ super.merge(request: "#{call[:method]} #{call[:path]}?#{call[:params].to_query}")
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 44b1db921fc..5303a8106e4 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -20567,18 +20567,36 @@ msgstr ""
msgid "Security report is out of date. Run %{newPipelineLinkStart}a new pipeline%{newPipelineLinkEnd} for the target branch (%{targetBranchName})"
msgstr ""
+msgid "SecurityConfiguration|An error occurred while creating the merge request."
+msgstr ""
+
+msgid "SecurityConfiguration|Configure"
+msgstr ""
+
+msgid "SecurityConfiguration|Enable via Merge Request"
+msgstr ""
+
msgid "SecurityConfiguration|Enabled"
msgstr ""
+msgid "SecurityConfiguration|Enabled with Auto DevOps"
+msgstr ""
+
msgid "SecurityConfiguration|Feature documentation for %{featureName}"
msgstr ""
-msgid "SecurityConfiguration|Not yet enabled"
+msgid "SecurityConfiguration|Manage"
+msgstr ""
+
+msgid "SecurityConfiguration|Not enabled"
msgstr ""
msgid "SecurityConfiguration|Security Control"
msgstr ""
+msgid "SecurityConfiguration|See documentation"
+msgstr ""
+
msgid "SecurityConfiguration|Status"
msgstr ""
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 46ed50932b7..e4b53186ea8 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -382,4 +382,11 @@ FactoryBot.define do
)
end
end
+
+ factory :project_with_design, parent: :project do
+ after(:create) do |project|
+ issue = create(:issue, project: project)
+ create(:design, project: project, issue: issue)
+ end
+ end
end
diff --git a/spec/fixtures/pager_duty/webhook_incident_trigger.json b/spec/fixtures/pager_duty/webhook_incident_trigger.json
new file mode 100644
index 00000000000..872297adcf6
--- /dev/null
+++ b/spec/fixtures/pager_duty/webhook_incident_trigger.json
@@ -0,0 +1,239 @@
+{
+ "messages": [
+ {
+ "event": "incident.trigger",
+ "log_entries": [
+ {
+ "id": "R2XGXEI3W0FHMSDXHDIBQGBQ5E",
+ "type": "trigger_log_entry",
+ "summary": "Triggered through the website",
+ "self": "https://api.pagerduty.com/log_entries/R2XGXEI3W0FHMSDXHDIBQGBQ5E",
+ "html_url": "https://webdemo.pagerduty.com/incidents/PRORDTY/log_entries/R2XGXEI3W0FHMSDXHDIBQGBQ5E",
+ "created_at": "2017-09-26T15:14:36Z",
+ "agent": {
+ "id": "P553OPV",
+ "type": "user_reference",
+ "summary": "Laura Haley",
+ "self": "https://api.pagerduty.com/users/P553OPV",
+ "html_url": "https://webdemo.pagerduty.com/users/P553OPV"
+ },
+ "channel": {
+ "type": "web_trigger",
+ "summary": "My new incident",
+ "subject": "My new incident",
+ "details": "Oh my gosh",
+ "details_omitted": false
+ },
+ "service": {
+ "id": "PN49J75",
+ "type": "service_reference",
+ "summary": "Production XDB Cluster",
+ "self": "https://api.pagerduty.com/services/PN49J75",
+ "html_url": "https://webdemo.pagerduty.com/services/PN49J75"
+ },
+ "incident": {
+ "id": "PRORDTY",
+ "type": "incident_reference",
+ "summary": "[#33] My new incident",
+ "self": "https://api.pagerduty.com/incidents/PRORDTY",
+ "html_url": "https://webdemo.pagerduty.com/incidents/PRORDTY"
+ },
+ "teams": [
+ {
+ "id": "P4SI59S",
+ "type": "team_reference",
+ "summary": "Engineering",
+ "self": "https://api.pagerduty.com/teams/P4SI59S",
+ "html_url": "https://webdemo.pagerduty.com/teams/P4SI59S"
+ }
+ ],
+ "contexts": [],
+ "event_details": {
+ "description": "My new incident"
+ }
+ }
+ ],
+ "webhook": {
+ "endpoint_url": "https://requestb.in/18ao6fs1",
+ "name": "V2 wabhook",
+ "description": null,
+ "webhook_object": {
+ "id": "PN49J75",
+ "type": "service_reference",
+ "summary": "Production XDB Cluster",
+ "self": "https://api.pagerduty.com/services/PN49J75",
+ "html_url": "https://webdemo.pagerduty.com/services/PN49J75"
+ },
+ "config": {},
+ "outbound_integration": {
+ "id": "PJFWPEP",
+ "type": "outbound_integration_reference",
+ "summary": "Generic V2 Webhook",
+ "self": "https://api.pagerduty.com/outbound_integrations/PJFWPEP",
+ "html_url": null
+ },
+ "accounts_addon": null,
+ "id": "PKT9NNX",
+ "type": "webhook",
+ "summary": "V2 wabhook",
+ "self": "https://api.pagerduty.com/webhooks/PKT9NNX",
+ "html_url": null
+ },
+ "incident": {
+ "incident_number": 33,
+ "title": "My new incident",
+ "description": "My new incident",
+ "created_at": "2017-09-26T15:14:36Z",
+ "status": "triggered",
+ "pending_actions": [
+ {
+ "type": "escalate",
+ "at": "2017-09-26T15:44:36Z"
+ },
+ {
+ "type": "resolve",
+ "at": "2017-09-26T19:14:36Z"
+ }
+ ],
+ "incident_key": null,
+ "service": {
+ "id": "PN49J75",
+ "name": "Production XDB Cluster",
+ "description": "This service was created during onboarding on July 5, 2017.",
+ "auto_resolve_timeout": 14400,
+ "acknowledgement_timeout": 1800,
+ "created_at": "2017-07-05T17:33:09Z",
+ "status": "critical",
+ "last_incident_timestamp": "2017-09-26T15:14:36Z",
+ "teams": [
+ {
+ "id": "P4SI59S",
+ "type": "team_reference",
+ "summary": "Engineering",
+ "self": "https://api.pagerduty.com/teams/P4SI59S",
+ "html_url": "https://webdemo.pagerduty.com/teams/P4SI59S"
+ }
+ ],
+ "incident_urgency_rule": {
+ "type": "constant",
+ "urgency": "high"
+ },
+ "scheduled_actions": [],
+ "support_hours": null,
+ "escalation_policy": {
+ "id": "PINYWEF",
+ "type": "escalation_policy_reference",
+ "summary": "Default",
+ "self": "https://api.pagerduty.com/escalation_policies/PINYWEF",
+ "html_url": "https://webdemo.pagerduty.com/escalation_policies/PINYWEF"
+ },
+ "addons": [],
+ "privilege": null,
+ "alert_creation": "create_alerts_and_incidents",
+ "integrations": [
+ {
+ "id": "PUAYF96",
+ "type": "generic_events_api_inbound_integration_reference",
+ "summary": "API",
+ "self": "https://api.pagerduty.com/services/PN49J75/integrations/PUAYF96",
+ "html_url": "https://webdemo.pagerduty.com/services/PN49J75/integrations/PUAYF96"
+ },
+ {
+ "id": "P90GZUH",
+ "type": "generic_email_inbound_integration_reference",
+ "summary": "Email",
+ "self": "https://api.pagerduty.com/services/PN49J75/integrations/P90GZUH",
+ "html_url": "https://webdemo.pagerduty.com/services/PN49J75/integrations/P90GZUH"
+ }
+ ],
+ "metadata": {},
+ "type": "service",
+ "summary": "Production XDB Cluster",
+ "self": "https://api.pagerduty.com/services/PN49J75",
+ "html_url": "https://webdemo.pagerduty.com/services/PN49J75"
+ },
+ "assignments": [
+ {
+ "at": "2017-09-26T15:14:36Z",
+ "assignee": {
+ "id": "P553OPV",
+ "type": "user_reference",
+ "summary": "Laura Haley",
+ "self": "https://api.pagerduty.com/users/P553OPV",
+ "html_url": "https://webdemo.pagerduty.com/users/P553OPV"
+ }
+ }
+ ],
+ "acknowledgements": [],
+ "last_status_change_at": "2017-09-26T15:14:36Z",
+ "last_status_change_by": {
+ "id": "PN49J75",
+ "type": "service_reference",
+ "summary": "Production XDB Cluster",
+ "self": "https://api.pagerduty.com/services/PN49J75",
+ "html_url": "https://webdemo.pagerduty.com/services/PN49J75"
+ },
+ "first_trigger_log_entry": {
+ "id": "R2XGXEI3W0FHMSDXHDIBQGBQ5E",
+ "type": "trigger_log_entry_reference",
+ "summary": "Triggered through the website",
+ "self": "https://api.pagerduty.com/log_entries/R2XGXEI3W0FHMSDXHDIBQGBQ5E",
+ "html_url": "https://webdemo.pagerduty.com/incidents/PRORDTY/log_entries/R2XGXEI3W0FHMSDXHDIBQGBQ5E"
+ },
+ "escalation_policy": {
+ "id": "PINYWEF",
+ "type": "escalation_policy_reference",
+ "summary": "Default",
+ "self": "https://api.pagerduty.com/escalation_policies/PINYWEF",
+ "html_url": "https://webdemo.pagerduty.com/escalation_policies/PINYWEF"
+ },
+ "privilege": null,
+ "teams": [
+ {
+ "id": "P4SI59S",
+ "type": "team_reference",
+ "summary": "Engineering",
+ "self": "https://api.pagerduty.com/teams/P4SI59S",
+ "html_url": "https://webdemo.pagerduty.com/teams/P4SI59S"
+ }
+ ],
+ "alert_counts": {
+ "all": 0,
+ "triggered": 0,
+ "resolved": 0
+ },
+ "impacted_services": [
+ {
+ "id": "PN49J75",
+ "type": "service_reference",
+ "summary": "Production XDB Cluster",
+ "self": "https://api.pagerduty.com/services/PN49J75",
+ "html_url": "https://webdemo.pagerduty.com/services/PN49J75"
+ }
+ ],
+ "is_mergeable": true,
+ "basic_alert_grouping": null,
+ "alert_grouping": null,
+ "metadata": {},
+ "external_references": [],
+ "importance": null,
+ "incidents_responders": [],
+ "responder_requests": [],
+ "subscriber_requests": [],
+ "urgency": "high",
+ "id": "PRORDTY",
+ "type": "incident",
+ "summary": "[#33] My new incident",
+ "self": "https://api.pagerduty.com/incidents/PRORDTY",
+ "html_url": "https://webdemo.pagerduty.com/incidents/PRORDTY",
+ "alerts": [
+ {
+ "alert_key": "c24117fc42e44b44b4d6876190583378"
+ }
+ ]
+ },
+ "id": "69a7ced0-a2cd-11e7-a799-22000a15839c",
+ "created_on": "2017-09-26T15:14:36Z"
+ }
+ ]
+}
diff --git a/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
index 0a85dbc32d5..e7c51d82cd2 100644
--- a/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
+++ b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
@@ -141,10 +141,6 @@ exports[`Dashboard template matches the default snapshot 1`] = `
/>
</div>
- <!---->
-
- <!---->
-
<empty-state-stub
clusterspath="/monitoring/monitor-project/-/clusters"
documentationpath="/help/administration/monitoring/prometheus/index.md"
diff --git a/spec/frontend/monitoring/components/__snapshots__/empty_state_spec.js.snap b/spec/frontend/monitoring/components/__snapshots__/empty_state_spec.js.snap
index 611aa96fa0a..4f8a82692b8 100644
--- a/spec/frontend/monitoring/components/__snapshots__/empty_state_spec.js.snap
+++ b/spec/frontend/monitoring/components/__snapshots__/empty_state_spec.js.snap
@@ -1,49 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EmptyState shows gettingStarted state 1`] = `
-<gl-empty-state-stub
- description="Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments."
- primarybuttonlink="/clustersPath"
- primarybuttontext="Install on clusters"
- secondarybuttonlink="/settingsPath"
- secondarybuttontext="Configure existing installation"
- svgpath="/path/to/getting-started.svg"
- title="Get started with performance monitoring"
-/>
-`;
-
-exports[`EmptyState shows loading state 1`] = `
-<gl-empty-state-stub
- description="Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
- primarybuttonlink="/documentationPath"
- primarybuttontext="View documentation"
- secondarybuttonlink=""
- secondarybuttontext=""
- svgpath="/path/to/loading.svg"
- title="Waiting for performance data"
-/>
+<div>
+ <!---->
+
+ <gl-empty-state-stub
+ description="Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments."
+ primarybuttonlink="/clustersPath"
+ primarybuttontext="Install on clusters"
+ secondarybuttonlink="/settingsPath"
+ secondarybuttontext="Configure existing installation"
+ svgpath="/path/to/getting-started.svg"
+ title="Get started with performance monitoring"
+ />
+</div>
`;
exports[`EmptyState shows noData state 1`] = `
-<gl-empty-state-stub
- description="You are connected to the Prometheus server, but there is currently no data to display."
- primarybuttonlink="/settingsPath"
- primarybuttontext="Configure Prometheus"
- secondarybuttonlink=""
- secondarybuttontext=""
- svgpath="/path/to/no-data.svg"
- title="No data found"
-/>
+<div>
+ <!---->
+
+ <gl-empty-state-stub
+ description="You are connected to the Prometheus server, but there is currently no data to display."
+ primarybuttonlink="/settingsPath"
+ primarybuttontext="Configure Prometheus"
+ secondarybuttonlink=""
+ secondarybuttontext=""
+ svgpath="/path/to/no-data.svg"
+ title="No data found"
+ />
+</div>
`;
exports[`EmptyState shows unableToConnect state 1`] = `
-<gl-empty-state-stub
- description="Ensure connectivity is available from the GitLab server to the Prometheus server"
- primarybuttonlink="/documentationPath"
- primarybuttontext="View documentation"
- secondarybuttonlink="/settingsPath"
- secondarybuttontext="Configure Prometheus"
- svgpath="/path/to/unable-to-connect.svg"
- title="Unable to connect to Prometheus server"
-/>
+<div>
+ <!---->
+
+ <gl-empty-state-stub
+ description="Ensure connectivity is available from the GitLab server to the Prometheus server"
+ primarybuttonlink="/documentationPath"
+ primarybuttontext="View documentation"
+ secondarybuttonlink="/settingsPath"
+ secondarybuttontext="Configure Prometheus"
+ svgpath="/path/to/unable-to-connect.svg"
+ title="Unable to connect to Prometheus server"
+ />
+</div>
`;
diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js
index 996e11b2442..614b7a0fd6a 100644
--- a/spec/frontend/monitoring/components/dashboard_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_spec.js
@@ -143,7 +143,7 @@ describe('Dashboard', () => {
setupStoreWithData(store);
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.showEmptyState).toEqual(false);
+ expect(wrapper.vm.emptyState).toBeNull();
expect(wrapper.findAll('.prometheus-panel')).toHaveLength(0);
});
});
@@ -455,6 +455,33 @@ describe('Dashboard', () => {
});
});
+ describe('when all panels in the first group are loading', () => {
+ const findGroupAt = i => wrapper.findAll(GraphGroup).at(i);
+
+ beforeEach(() => {
+ setupStoreWithDashboard(store);
+
+ const { panels } = store.state.monitoringDashboard.dashboard.panelGroups[0];
+ panels.forEach(({ metrics }) => {
+ store.commit(`monitoringDashboard/${types.REQUEST_METRIC_RESULT}`, {
+ metricId: metrics[0].metricId,
+ });
+ });
+
+ createShallowWrapper();
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('a loading icon appears in the first group', () => {
+ expect(findGroupAt(0).props('isLoading')).toBe(true);
+ });
+
+ it('a loading icon does not appear in the second group', () => {
+ expect(findGroupAt(1).props('isLoading')).toBe(false);
+ });
+ });
+
describe('when all requests have been commited by the store', () => {
beforeEach(() => {
store.commit(`monitoringDashboard/${types.SET_INITIAL_STATE}`, {
@@ -478,6 +505,16 @@ describe('Dashboard', () => {
});
});
+ it('it does not show loading icons in any group', () => {
+ setupStoreWithData(store);
+
+ wrapper.vm.$nextTick(() => {
+ wrapper.findAll(GraphGroup).wrappers.forEach(groupWrapper => {
+ expect(groupWrapper.props('isLoading')).toBe(false);
+ });
+ });
+ });
+
// Note: This test is not working, .active does not show the active environment
// eslint-disable-next-line jest/no-disabled-tests
it.skip('renders the environments dropdown with a single active element', () => {
diff --git a/spec/frontend/monitoring/components/empty_state_spec.js b/spec/frontend/monitoring/components/empty_state_spec.js
index 3b03e16a446..abb8b21e9f4 100644
--- a/spec/frontend/monitoring/components/empty_state_spec.js
+++ b/spec/frontend/monitoring/components/empty_state_spec.js
@@ -1,11 +1,11 @@
import { shallowMount } from '@vue/test-utils';
+import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
import { dashboardEmptyStates } from '~/monitoring/constants';
import EmptyState from '~/monitoring/components/empty_state.vue';
function createComponent(props) {
return shallowMount(EmptyState, {
propsData: {
- ...props,
settingsPath: '/settingsPath',
clustersPath: '/clustersPath',
documentationPath: '/documentationPath',
@@ -14,22 +14,24 @@ function createComponent(props) {
emptyNoDataSvgPath: '/path/to/no-data.svg',
emptyNoDataSmallSvgPath: '/path/to/no-data-small.svg',
emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
+ ...props,
},
});
}
describe('EmptyState', () => {
- it('shows gettingStarted state', () => {
+ it('shows loading state with a loading icon', () => {
const wrapper = createComponent({
- selectedState: dashboardEmptyStates.GETTING_STARTED,
+ selectedState: dashboardEmptyStates.LOADING,
});
- expect(wrapper.element).toMatchSnapshot();
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.find(GlEmptyState).exists()).toBe(false);
});
- it('shows loading state', () => {
+ it('shows gettingStarted state', () => {
const wrapper = createComponent({
- selectedState: dashboardEmptyStates.LOADING,
+ selectedState: dashboardEmptyStates.GETTING_STARTED,
});
expect(wrapper.element).toMatchSnapshot();
diff --git a/spec/frontend/monitoring/components/graph_group_spec.js b/spec/frontend/monitoring/components/graph_group_spec.js
index 3b68f8ae30a..81f5d90c310 100644
--- a/spec/frontend/monitoring/components/graph_group_spec.js
+++ b/spec/frontend/monitoring/components/graph_group_spec.js
@@ -1,13 +1,14 @@
import { shallowMount } from '@vue/test-utils';
import GraphGroup from '~/monitoring/components/graph_group.vue';
-import Icon from '~/vue_shared/components/icon.vue';
+import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
describe('Graph group component', () => {
let wrapper;
const findGroup = () => wrapper.find({ ref: 'graph-group' });
const findContent = () => wrapper.find({ ref: 'graph-group-content' });
- const findCaretIcon = () => wrapper.find(Icon);
+ const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findCaretIcon = () => wrapper.find(GlIcon);
const findToggleButton = () => wrapper.find('[data-testid="group-toggle-button"]');
const createComponent = propsData => {
@@ -28,15 +29,19 @@ describe('Graph group component', () => {
});
});
+ it('should not show a loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
it('should show the angle-down caret icon', () => {
expect(findContent().isVisible()).toBe(true);
expect(findCaretIcon().props('name')).toBe('angle-down');
});
it('should show the angle-right caret icon when the user collapses the group', () => {
- wrapper.vm.collapse();
+ findToggleButton().trigger('click');
- return wrapper.vm.$nextTick(() => {
+ return wrapper.vm.$nextTick().then(() => {
expect(findContent().isVisible()).toBe(false);
expect(findCaretIcon().props('name')).toBe('angle-right');
});
@@ -53,77 +58,94 @@ describe('Graph group component', () => {
collapseGroup: true,
});
- return wrapper.vm.$nextTick(() => {
+ return wrapper.vm.$nextTick().then(() => {
expect(findContent().isVisible()).toBe(true);
expect(findCaretIcon().props('name')).toBe('angle-down');
});
});
+ });
- describe('When group is collapsed', () => {
- beforeEach(() => {
- createComponent({
- name: 'panel',
- collapseGroup: true,
- });
+ describe('When group is collapsed', () => {
+ beforeEach(() => {
+ createComponent({
+ name: 'panel',
+ collapseGroup: true,
});
+ });
- it('should show the angle-down caret icon when collapseGroup is true', () => {
- expect(wrapper.vm.caretIcon).toBe('angle-right');
- });
+ it('should show the angle-down caret icon when collapseGroup is true', () => {
+ expect(findCaretIcon().props('name')).toBe('angle-right');
+ });
- it('should show the angle-right caret icon when collapseGroup is false', () => {
- wrapper.vm.collapse();
+ it('should show the angle-right caret icon when collapseGroup is false', () => {
+ findToggleButton().trigger('click');
- expect(wrapper.vm.caretIcon).toBe('angle-down');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findCaretIcon().props('name')).toBe('angle-down');
});
+ });
- it('should call collapse the graph group content when enter is pressed on the caret icon', () => {
- const graphGroupContent = findContent();
- const button = findToggleButton();
+ it('should call collapse the graph group content when enter is pressed on the caret icon', () => {
+ const graphGroupContent = findContent();
+ const button = findToggleButton();
- button.trigger('keyup.enter');
+ button.trigger('keyup.enter');
- expect(graphGroupContent.isVisible()).toBe(false);
+ expect(graphGroupContent.isVisible()).toBe(false);
+ });
+ });
+
+ describe('When groups can not be collapsed', () => {
+ beforeEach(() => {
+ createComponent({
+ name: 'panel',
+ showPanels: false,
+ collapseGroup: false,
});
});
- describe('When groups can not be collapsed', () => {
- beforeEach(() => {
- createComponent({
- name: 'panel',
- showPanels: false,
- collapseGroup: false,
- });
+ it('should not have a container when showPanels is false', () => {
+ expect(findGroup().exists()).toBe(false);
+ expect(findContent().exists()).toBe(true);
+ });
+ });
+
+ describe('When group is loading', () => {
+ beforeEach(() => {
+ createComponent({
+ name: 'panel',
+ isLoading: true,
});
+ });
- it('should not have a container when showPanels is false', () => {
- expect(findGroup().exists()).toBe(false);
- expect(findContent().exists()).toBe(true);
+ it('should show a loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('When group does not show a panel heading', () => {
+ beforeEach(() => {
+ createComponent({
+ name: 'panel',
+ showPanels: false,
+ collapseGroup: false,
});
});
- describe('When group does not show a panel heading', () => {
- beforeEach(() => {
- createComponent({
- name: 'panel',
- showPanels: false,
- collapseGroup: false,
- });
+ it('should collapse the panel content', () => {
+ expect(findContent().isVisible()).toBe(true);
+ expect(findCaretIcon().exists()).toBe(false);
+ });
+
+ it('should show the panel content when collapse is set to false', () => {
+ wrapper.setProps({
+ collapseGroup: false,
});
- it('should collapse the panel content', () => {
+ return wrapper.vm.$nextTick().then(() => {
expect(findContent().isVisible()).toBe(true);
expect(findCaretIcon().exists()).toBe(false);
});
-
- it('should show the panel content when clicked', () => {
- wrapper.vm.collapse();
-
- return wrapper.vm.$nextTick(() => {
- expect(findContent().isVisible()).toBe(true);
- expect(findCaretIcon().exists()).toBe(false);
- });
- });
});
});
});
diff --git a/spec/frontend/monitoring/components/links_section_spec.js b/spec/frontend/monitoring/components/links_section_spec.js
index 3b5b72d84ee..b771d63d51f 100644
--- a/spec/frontend/monitoring/components/links_section_spec.js
+++ b/spec/frontend/monitoring/components/links_section_spec.js
@@ -15,7 +15,7 @@ describe('Links Section component', () => {
const setState = links => {
store.state.monitoringDashboard = {
...store.state.monitoringDashboard,
- showEmptyState: false,
+ emptyState: null,
links,
};
};
diff --git a/spec/frontend/monitoring/components/variables_section_spec.js b/spec/frontend/monitoring/components/variables_section_spec.js
index d8e63917eec..3097906ee68 100644
--- a/spec/frontend/monitoring/components/variables_section_spec.js
+++ b/spec/frontend/monitoring/components/variables_section_spec.js
@@ -29,7 +29,7 @@ describe('Metrics dashboard/variables section component', () => {
beforeEach(() => {
store = createStore();
- store.state.monitoringDashboard.showEmptyState = false;
+ store.state.monitoringDashboard.emptyState = null;
});
it('does not show the variables section', () => {
@@ -70,7 +70,7 @@ describe('Metrics dashboard/variables section component', () => {
monitoringDashboard: {
namespaced: true,
state: {
- showEmptyState: false,
+ emptyState: null,
variables: storeVariables,
},
actions: {
diff --git a/spec/frontend/monitoring/store/mutations_spec.js b/spec/frontend/monitoring/store/mutations_spec.js
index 734a3597569..14b38d79aa2 100644
--- a/spec/frontend/monitoring/store/mutations_spec.js
+++ b/spec/frontend/monitoring/store/mutations_spec.js
@@ -20,7 +20,6 @@ describe('Monitoring mutations', () => {
mutations[types.REQUEST_METRICS_DASHBOARD](stateCopy);
expect(stateCopy.emptyState).toBe(dashboardEmptyStates.LOADING);
- expect(stateCopy.showEmptyState).toBe(true);
});
});
@@ -98,14 +97,12 @@ describe('Monitoring mutations', () => {
mutations[types.RECEIVE_METRICS_DASHBOARD_FAILURE](stateCopy);
expect(stateCopy.emptyState).toBe(dashboardEmptyStates.NO_DATA);
- expect(stateCopy.showEmptyState).toBe(true);
});
it('sets an empty unableToConnect state when an error occurs', () => {
mutations[types.RECEIVE_METRICS_DASHBOARD_FAILURE](stateCopy, 'myerror');
expect(stateCopy.emptyState).toBe(dashboardEmptyStates.UNABLE_TO_CONNECT);
- expect(stateCopy.showEmptyState).toBe(true);
});
});
@@ -292,13 +289,10 @@ describe('Monitoring mutations', () => {
mutations[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](stateCopy, dashboard);
});
it('stores a loading state on a metric', () => {
- expect(stateCopy.showEmptyState).toBe(true);
-
mutations[types.REQUEST_METRIC_RESULT](stateCopy, {
metricId,
});
- expect(stateCopy.showEmptyState).toBe(true);
expect(getMetric()).toEqual(
expect.objectContaining({
loading: true,
@@ -311,17 +305,6 @@ describe('Monitoring mutations', () => {
beforeEach(() => {
mutations[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](stateCopy, dashboard);
});
- it('clears empty state', () => {
- expect(stateCopy.showEmptyState).toBe(true);
-
- mutations[types.RECEIVE_METRIC_RESULT_SUCCESS](stateCopy, {
- metricId,
- data,
- });
-
- expect(stateCopy.showEmptyState).toBe(false);
- expect(stateCopy.emptyState).toBe(null);
- });
it('adds results to the store', () => {
expect(getMetric().result).toBe(null);
@@ -345,16 +328,6 @@ describe('Monitoring mutations', () => {
beforeEach(() => {
mutations[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](stateCopy, dashboard);
});
- it('maintains the loading state when a metric fails', () => {
- expect(stateCopy.showEmptyState).toBe(true);
-
- mutations[types.RECEIVE_METRIC_RESULT_FAILURE](stateCopy, {
- metricId,
- error: 'an error',
- });
-
- expect(stateCopy.showEmptyState).toBe(true);
- });
it('stores a timeout error in a metric', () => {
mutations[types.RECEIVE_METRIC_RESULT_FAILURE](stateCopy, {
diff --git a/spec/frontend/reports/components/grouped_test_reports_app_spec.js b/spec/frontend/reports/components/grouped_test_reports_app_spec.js
index f4b21493a29..017e0335569 100644
--- a/spec/frontend/reports/components/grouped_test_reports_app_spec.js
+++ b/spec/frontend/reports/components/grouped_test_reports_app_spec.js
@@ -91,6 +91,7 @@ describe('Grouped test reports app', () => {
const fullTestReportLink = findFullTestReportLink();
expect(fullTestReportLink.exists()).toBe(true);
+ expect(pipelinePath).not.toBe('');
expect(fullTestReportLink.attributes('href')).toBe(`${pipelinePath}/test_report`);
});
});
diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb
index 33dca04fc57..90d6096654e 100644
--- a/spec/helpers/environments_helper_spec.rb
+++ b/spec/helpers/environments_helper_spec.rb
@@ -95,6 +95,30 @@ RSpec.describe EnvironmentsHelper do
it { is_expected.to include('environment-state' => 'stopped') }
end
+
+ context 'when request is from project scoped metrics path' do
+ let(:request) { double('request', path: path) }
+
+ before do
+ allow(helper).to receive(:request).and_return(request)
+ end
+
+ context '/:namespace/:project/-/metrics' do
+ let(:path) { project_metrics_dashboard_path(project) }
+
+ it 'uses correct path for metrics-dashboard-base-path' do
+ expect(metrics_data['metrics-dashboard-base-path']).to eq(project_metrics_dashboard_path(project))
+ end
+ end
+
+ context '/:namespace/:project/-/metrics/some_custom_dashboard.yml' do
+ let(:path) { "#{project_metrics_dashboard_path(project)}/some_custom_dashboard.yml" }
+
+ it 'uses correct path for metrics-dashboard-base-path' do
+ expect(metrics_data['metrics-dashboard-base-path']).to eq(project_metrics_dashboard_path(project))
+ end
+ end
+ end
end
describe '#custom_metrics_available?' do
diff --git a/spec/lib/gitlab/incident_management/pager_duty/incident_issue_description_spec.rb b/spec/lib/gitlab/incident_management/pager_duty/incident_issue_description_spec.rb
new file mode 100644
index 00000000000..9a55e21d031
--- /dev/null
+++ b/spec/lib/gitlab/incident_management/pager_duty/incident_issue_description_spec.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'timecop'
+
+RSpec.describe Gitlab::IncidentManagement::PagerDuty::IncidentIssueDescription do
+ describe '#to_s' do
+ let(:markdown_line_break) { ' ' }
+ let(:created_at) { '2017-09-26T15:14:36Z' }
+ let(:assignees) do
+ [{ 'summary' => 'Laura Haley', 'url' => 'https://webdemo.pagerduty.com/users/P553OPV' }]
+ end
+ let(:impacted_services) do
+ [{ 'summary' => 'Production XDB Cluster', 'url' => 'https://webdemo.pagerduty.com/services/PN49J75' }]
+ end
+ let(:incident_payload) do
+ {
+ 'url' => 'https://webdemo.pagerduty.com/incidents/PRORDTY',
+ 'incident_number' => 33,
+ 'title' => 'My new incident',
+ 'status' => 'triggered',
+ 'created_at' => created_at,
+ 'urgency' => 'high',
+ 'incident_key' => 'SOME-KEY',
+ 'assignees' => assignees,
+ 'impacted_services' => impacted_services
+ }
+ end
+
+ subject(:to_s) { described_class.new(incident_payload).to_s }
+
+ it 'returns description' do
+ expect(to_s).to eq(
+ <<~MARKDOWN.chomp
+ **Incident:** [My new incident](https://webdemo.pagerduty.com/incidents/PRORDTY)#{markdown_line_break}
+ **Incident number:** 33#{markdown_line_break}
+ **Urgency:** high#{markdown_line_break}
+ **Status:** triggered#{markdown_line_break}
+ **Incident key:** SOME-KEY#{markdown_line_break}
+ **Created at:** 26 September 2017, 3:14PM (UTC)#{markdown_line_break}
+ **Assignees:** [Laura Haley](https://webdemo.pagerduty.com/users/P553OPV)#{markdown_line_break}
+ **Impacted services:** [Production XDB Cluster](https://webdemo.pagerduty.com/services/PN49J75)
+ MARKDOWN
+ )
+ end
+
+ context 'when created_at is missing' do
+ let(:created_at) { nil }
+
+ it 'description contains current time in UTC' do
+ Timecop.freeze do
+ now = Time.current.utc.strftime('%d %B %Y, %-l:%M%p (%Z)')
+
+ expect(to_s).to include(
+ <<~MARKDOWN.chomp
+ **Created at:** #{now}#{markdown_line_break}
+ MARKDOWN
+ )
+ end
+ end
+ end
+
+ context 'when there are several assignees' do
+ let(:assignees) do
+ [
+ { 'summary' => 'Laura Haley', 'url' => 'https://laura.pagerduty.com' },
+ { 'summary' => 'John Doe', 'url' => 'https://john.pagerduty.com' }
+ ]
+ end
+
+ it 'assignees is a list of links' do
+ expect(to_s).to include(
+ <<~MARKDOWN.chomp
+ **Assignees:** [Laura Haley](https://laura.pagerduty.com), [John Doe](https://john.pagerduty.com)#{markdown_line_break}
+ MARKDOWN
+ )
+ end
+ end
+
+ context 'when there are several impacted services' do
+ let(:impacted_services) do
+ [
+ { 'summary' => 'XDB Cluster', 'url' => 'https://xdb.pagerduty.com' },
+ { 'summary' => 'BRB Cluster', 'url' => 'https://brb.pagerduty.com' }
+ ]
+ end
+
+ it 'impacted services is a list of links' do
+ expect(to_s).to include(
+ <<~MARKDOWN.chomp
+ **Impacted services:** [XDB Cluster](https://xdb.pagerduty.com), [BRB Cluster](https://brb.pagerduty.com)
+ MARKDOWN
+ )
+ end
+ end
+ end
+end
diff --git a/spec/lib/pager_duty/webhook_payload_parser_spec.rb b/spec/lib/pager_duty/webhook_payload_parser_spec.rb
new file mode 100644
index 00000000000..0010165318d
--- /dev/null
+++ b/spec/lib/pager_duty/webhook_payload_parser_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe PagerDuty::WebhookPayloadParser do
+ describe '.call' do
+ let(:fixture_file) do
+ File.read(File.join(File.dirname(__FILE__), '../../fixtures/pager_duty/webhook_incident_trigger.json'))
+ end
+
+ subject(:parse) { described_class.call(payload) }
+
+ context 'when payload is a correct PagerDuty payload' do
+ let(:payload) { Gitlab::Json.parse(fixture_file) }
+
+ it 'returns parsed payload' do
+ is_expected.to eq(
+ [
+ {
+ 'event' => 'incident.trigger',
+ 'incident' => {
+ 'url' => 'https://webdemo.pagerduty.com/incidents/PRORDTY',
+ 'incident_number' => 33,
+ 'title' => 'My new incident',
+ 'status' => 'triggered',
+ 'created_at' => '2017-09-26T15:14:36Z',
+ 'urgency' => 'high',
+ 'incident_key' => nil,
+ 'assignees' => [{
+ 'summary' => 'Laura Haley',
+ 'url' => 'https://webdemo.pagerduty.com/users/P553OPV'
+ }],
+ 'impacted_services' => [{
+ 'summary' => 'Production XDB Cluster',
+ 'url' => 'https://webdemo.pagerduty.com/services/PN49J75'
+ }]
+ }
+ }
+ ]
+ )
+ end
+
+ context 'when assignments summary and html_url are blank' do
+ before do
+ payload['messages'].each do |m|
+ m['incident']['assignments'] = [{ 'assignee' => { 'summary' => '', 'html_url' => '' } }]
+ end
+ end
+
+ it 'returns parsed payload with blank assignees' do
+ assignees = parse.map { |events| events['incident'].slice('assignees') }
+
+ expect(assignees).to eq([{ 'assignees' => [] }])
+ end
+ end
+
+ context 'when impacted_services summary and html_url are blank' do
+ before do
+ payload['messages'].each do |m|
+ m['incident']['impacted_services'] = [{ 'summary' => '', 'html_url' => '' }]
+ end
+ end
+
+ it 'returns parsed payload with blank assignees' do
+ assignees = parse.map { |events| events['incident'].slice('impacted_services') }
+
+ expect(assignees).to eq([{ 'impacted_services' => [] }])
+ end
+ end
+ end
+
+ context 'when payload has no incidents' do
+ let(:payload) { { 'messages' => [{ 'event' => 'incident.trigger' }] } }
+
+ it 'returns payload with blank incidents' do
+ is_expected.to eq([{ 'event' => 'incident.trigger', 'incident' => {} }])
+ end
+ end
+ end
+end
diff --git a/spec/presenters/clusters/cluster_presenter_spec.rb b/spec/presenters/clusters/cluster_presenter_spec.rb
index 541e96f5f07..9dcb6d199bc 100644
--- a/spec/presenters/clusters/cluster_presenter_spec.rb
+++ b/spec/presenters/clusters/cluster_presenter_spec.rb
@@ -265,9 +265,11 @@ RSpec.describe Clusters::ClusterPresenter do
is_expected.to include('clusters-path': clusterable_presenter.index_path,
'dashboard-endpoint': clusterable_presenter.metrics_dashboard_path(cluster),
'documentation-path': help_page_path('user/project/clusters/index', anchor: 'monitoring-your-kubernetes-cluster-ultimate'),
+ 'add-dashboard-documentation-path': help_page_path('user/project/integrations/prometheus.md', anchor: 'adding-a-new-dashboard-to-your-project'),
'empty-getting-started-svg-path': match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path': match_asset_path('/assets/illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path': match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
+ 'empty-no-data-small-svg-path': match_asset_path('illustrations/chart-empty-state-small.svg'),
'empty-unable-to-connect-svg-path': match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'),
'settings-path': '',
'project-path': '',
diff --git a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
index 2c34bf1c39b..391ced7dc98 100644
--- a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
@@ -13,7 +13,8 @@ RSpec.describe 'Adding a Note' do
variables = {
noteable_id: GitlabSchema.id_from_object(noteable).to_s,
discussion_id: (GitlabSchema.id_from_object(discussion).to_s if discussion),
- body: 'Body text'
+ body: 'Body text',
+ confidential: true
}
graphql_mutation(:create_note, variables)
@@ -40,6 +41,7 @@ RSpec.describe 'Adding a Note' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['note']['body']).to eq('Body text')
+ expect(mutation_response['note']['confidential']).to eq(true)
end
describe 'creating Notes in reply to a discussion' do
diff --git a/spec/requests/api/graphql/mutations/snippets/create_spec.rb b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
index 8894a73874e..e2474e1bcce 100644
--- a/spec/requests/api/graphql/mutations/snippets/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
@@ -174,7 +174,7 @@ RSpec.describe 'Creating a Snippet' do
context 'when action is invalid' do
let(:file_1) { { filePath: 'example_file1' }}
- it_behaves_like 'a mutation that returns errors in the response', errors: ['Snippet files have invalid data']
+ it_behaves_like 'a mutation that returns errors in the response', errors: ['Snippet actions have invalid data']
it_behaves_like 'does not create snippet'
end
end
diff --git a/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb b/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb
new file mode 100644
index 00000000000..cf43ed2411d
--- /dev/null
+++ b/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IncidentManagement::PagerDuty::CreateIncidentIssueService do
+ let_it_be(:project, reload: true) { create(:project) }
+ let_it_be(:user) { User.alert_bot }
+ let(:webhook_payload) { Gitlab::Json.parse(fixture_file('pager_duty/webhook_incident_trigger.json')) }
+ let(:parsed_payload) { ::PagerDuty::WebhookPayloadParser.call(webhook_payload) }
+ let(:incident_payload) { parsed_payload.first['incident'] }
+
+ subject(:execute) { described_class.new(project, incident_payload).execute }
+
+ describe '#execute' do
+ context 'when pagerduty_webhook feature enabled' do
+ before do
+ stub_feature_flags(pagerduty_webhook: project)
+ end
+
+ context 'when PagerDuty webhook setting is active' do
+ let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: true) }
+
+ context 'when issue can be created' do
+ it 'creates a new issue' do
+ expect { execute }.to change(Issue, :count).by(1)
+ end
+
+ it 'responds with success' do
+ response = execute
+
+ expect(response).to be_success
+ expect(response.payload[:issue]).to be_kind_of(Issue)
+ end
+
+ it 'the issue author is Alert bot' do
+ expect(execute.payload[:issue].author).to eq(User.alert_bot)
+ end
+
+ it 'issue has a correct title' do
+ expect(execute.payload[:issue].title).to eq(incident_payload['title'])
+ end
+
+ it 'issue has a correct description' do
+ markdown_line_break = ' '
+
+ expect(execute.payload[:issue].description).to eq(
+ <<~MARKDOWN.chomp
+ **Incident:** [My new incident](https://webdemo.pagerduty.com/incidents/PRORDTY)#{markdown_line_break}
+ **Incident number:** 33#{markdown_line_break}
+ **Urgency:** high#{markdown_line_break}
+ **Status:** triggered#{markdown_line_break}
+ **Incident key:** #{markdown_line_break}
+ **Created at:** 26 September 2017, 3:14PM (UTC)#{markdown_line_break}
+ **Assignees:** [Laura Haley](https://webdemo.pagerduty.com/users/P553OPV)#{markdown_line_break}
+ **Impacted services:** [Production XDB Cluster](https://webdemo.pagerduty.com/services/PN49J75)
+ MARKDOWN
+ )
+ end
+ end
+
+ context 'when the payload does not contain a title' do
+ let(:incident_payload) { {} }
+
+ it 'does not create a GitLab issue' do
+ expect { execute }.not_to change(Issue, :count)
+ end
+
+ it 'responds with error' do
+ expect(execute).to be_error
+ expect(execute.message).to eq("Title can't be blank")
+ end
+ end
+ end
+
+ context 'when PagerDuty webhook setting is not active' do
+ let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) }
+
+ it 'does not create a GitLab issue' do
+ expect { execute }.not_to change(Issue, :count)
+ end
+
+ it 'responds with forbidden' do
+ expect(execute).to be_error
+ expect(execute.http_status).to eq(:forbidden)
+ end
+ end
+ end
+
+ context 'when pagerduty_webhook feature disabled' do
+ before do
+ stub_feature_flags(pagerduty_webhook: false)
+ end
+
+ it 'does not create a GitLab issue' do
+ expect { execute }.not_to change(Issue, :count)
+ end
+
+ it 'responds with forbidden' do
+ expect(execute).to be_error
+ expect(execute.http_status).to eq(:forbidden)
+ end
+ end
+ end
+end
diff --git a/spec/services/snippets/create_service_spec.rb b/spec/services/snippets/create_service_spec.rb
index d0b2dde6ee4..62eef00b67f 100644
--- a/spec/services/snippets/create_service_spec.rb
+++ b/spec/services/snippets/create_service_spec.rb
@@ -228,15 +228,15 @@ RSpec.describe Snippets::CreateService do
end
end
- shared_examples 'when snippet_files param is present' do
+ shared_examples 'when snippet_actions param is present' do
let(:file_path) { 'snippet_file_path.rb' }
let(:content) { 'snippet_content' }
- let(:snippet_files) { [{ action: 'create', file_path: file_path, content: content }] }
+ let(:snippet_actions) { [{ action: 'create', file_path: file_path, content: content }] }
let(:base_opts) do
{
title: 'Test snippet',
visibility_level: Gitlab::VisibilityLevel::PRIVATE,
- snippet_files: snippet_files
+ snippet_actions: snippet_actions
}
end
@@ -266,28 +266,28 @@ RSpec.describe Snippets::CreateService do
end
end
- context 'when snippet_files param is invalid' do
- let(:snippet_files) { [{ action: 'invalid_action', file_path: 'snippet_file_path.rb', content: 'snippet_content' }] }
+ context 'when snippet_actions param is invalid' do
+ let(:snippet_actions) { [{ action: 'invalid_action', file_path: 'snippet_file_path.rb', content: 'snippet_content' }] }
it 'a validation error is raised' do
expect(subject).to be_error
- expect(snippet.errors.full_messages_for(:snippet_files)).to eq ['Snippet files have invalid data']
+ expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data']
expect(snippet.repository.exists?).to be_falsey
end
end
- context 'when snippet_files contain an action different from "create"' do
- let(:snippet_files) { [{ action: 'delete', file_path: 'snippet_file_path.rb' }] }
+ context 'when snippet_actions contain an action different from "create"' do
+ let(:snippet_actions) { [{ action: 'delete', file_path: 'snippet_file_path.rb' }] }
it 'a validation error is raised' do
expect(subject).to be_error
- expect(snippet.errors.full_messages_for(:snippet_files)).to eq ['Snippet files have invalid data']
+ expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data']
expect(snippet.repository.exists?).to be_falsey
end
end
context 'when "create" operation does not have file_path or is empty' do
- let(:snippet_files) { [{ action: 'create', content: content }, { action: 'create', content: content, file_path: '' }] }
+ let(:snippet_actions) { [{ action: 'create', content: content }, { action: 'create', content: content, file_path: '' }] }
it 'generates the file path for the files' do
expect(subject).to be_success
@@ -311,7 +311,7 @@ RSpec.describe Snippets::CreateService do
it_behaves_like 'an error service response when save fails'
it_behaves_like 'creates repository and files'
it_behaves_like 'after_save callback to store_mentions', ProjectSnippet
- it_behaves_like 'when snippet_files param is present'
+ it_behaves_like 'when snippet_actions param is present'
context 'when uploaded files are passed to the service' do
let(:extra_opts) { { files: ['foo'] } }
@@ -338,7 +338,7 @@ RSpec.describe Snippets::CreateService do
it_behaves_like 'an error service response when save fails'
it_behaves_like 'creates repository and files'
it_behaves_like 'after_save callback to store_mentions', PersonalSnippet
- it_behaves_like 'when snippet_files param is present'
+ it_behaves_like 'when snippet_actions param is present'
context 'when the snippet description contains files' do
include FileMoverHelpers
diff --git a/spec/services/snippets/update_service_spec.rb b/spec/services/snippets/update_service_spec.rb
index 5587668e9ed..66dddcc49de 100644
--- a/spec/services/snippets/update_service_spec.rb
+++ b/spec/services/snippets/update_service_spec.rb
@@ -302,22 +302,22 @@ RSpec.describe Snippets::UpdateService do
end
end
- shared_examples 'when snippet_files param is present' do
+ shared_examples 'when snippet_actions param is present' do
let(:file_path) { 'CHANGELOG' }
let(:content) { 'snippet_content' }
let(:new_title) { 'New title' }
- let(:snippet_files) { [{ action: 'update', previous_path: file_path, file_path: file_path, content: content }] }
+ let(:snippet_actions) { [{ action: 'update', previous_path: file_path, file_path: file_path, content: content }] }
let(:base_opts) do
{
title: new_title,
- snippet_files: snippet_files
+ snippet_actions: snippet_actions
}
end
it 'updates a snippet with the provided attributes' do
file_path = 'foo'
- snippet_files[0][:action] = 'move'
- snippet_files[0][:file_path] = file_path
+ snippet_actions[0][:action] = 'move'
+ snippet_actions[0][:file_path] = file_path
response = subject
snippet = response.payload[:snippet]
@@ -350,7 +350,7 @@ RSpec.describe Snippets::UpdateService do
end
context 'when snippet_file content is not present' do
- let(:snippet_files) { [{ action: :move, previous_path: file_path, file_path: 'new_file_path' }] }
+ let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: 'new_file_path' }] }
it 'does not update snippet content' do
content = snippet.content
@@ -361,15 +361,15 @@ RSpec.describe Snippets::UpdateService do
end
end
- context 'when snippet_files param is invalid' do
- let(:snippet_files) { [{ action: 'invalid_action' }] }
+ context 'when snippet_actions param is invalid' do
+ let(:snippet_actions) { [{ action: 'invalid_action' }] }
it 'raises a validation error' do
response = subject
snippet = response.payload[:snippet]
expect(response).to be_error
- expect(snippet.errors.full_messages_for(:snippet_files)).to eq ['Snippet files have invalid data']
+ expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data']
end
end
@@ -391,7 +391,7 @@ RSpec.describe Snippets::UpdateService do
context 'commit actions' do
let(:new_path) { 'created_new_file' }
- let(:base_opts) { { snippet_files: snippet_files } }
+ let(:base_opts) { { snippet_actions: snippet_actions } }
shared_examples 'returns an error' do |error_msg|
specify do
@@ -403,7 +403,7 @@ RSpec.describe Snippets::UpdateService do
end
context 'update action' do
- let(:snippet_files) { [{ action: :update, file_path: file_path, content: content }] }
+ let(:snippet_actions) { [{ action: :update, file_path: file_path, content: content }] }
it 'updates the file content' do
expect(subject).to be_success
@@ -414,7 +414,7 @@ RSpec.describe Snippets::UpdateService do
end
context 'when previous_path is present' do
- let(:snippet_files) { [{ action: :update, previous_path: file_path, file_path: file_path, content: content }] }
+ let(:snippet_actions) { [{ action: :update, previous_path: file_path, file_path: file_path, content: content }] }
it 'updates the file content' do
expect(subject).to be_success
@@ -426,13 +426,13 @@ RSpec.describe Snippets::UpdateService do
end
context 'when content is not present' do
- let(:snippet_files) { [{ action: :update, file_path: file_path }] }
+ let(:snippet_actions) { [{ action: :update, file_path: file_path }] }
- it_behaves_like 'returns an error', 'Snippet files have invalid data'
+ it_behaves_like 'returns an error', 'Snippet actions have invalid data'
end
context 'when file_path does not exist' do
- let(:snippet_files) { [{ action: :update, file_path: 'makeup_name', content: content }] }
+ let(:snippet_actions) { [{ action: :update, file_path: 'makeup_name', content: content }] }
it_behaves_like 'returns an error', 'Repository Error updating the snippet'
end
@@ -440,13 +440,13 @@ RSpec.describe Snippets::UpdateService do
context 'move action' do
context 'when file_path and previous_path are the same' do
- let(:snippet_files) { [{ action: :move, previous_path: file_path, file_path: file_path }] }
+ let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: file_path }] }
- it_behaves_like 'returns an error', 'Snippet files have invalid data'
+ it_behaves_like 'returns an error', 'Snippet actions have invalid data'
end
context 'when file_path and previous_path are different' do
- let(:snippet_files) { [{ action: :move, previous_path: file_path, file_path: new_path }] }
+ let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: new_path }] }
it 'renames the file' do
old_blob = blob(file_path)
@@ -461,13 +461,13 @@ RSpec.describe Snippets::UpdateService do
end
context 'when previous_path does not exist' do
- let(:snippet_files) { [{ action: :move, previous_path: 'makeup_name', file_path: new_path }] }
+ let(:snippet_actions) { [{ action: :move, previous_path: 'makeup_name', file_path: new_path }] }
it_behaves_like 'returns an error', 'Repository Error updating the snippet'
end
context 'when user wants to rename the file and update content' do
- let(:snippet_files) { [{ action: :move, previous_path: file_path, file_path: new_path, content: content }] }
+ let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: new_path, content: content }] }
it 'performs both operations' do
expect(subject).to be_success
@@ -481,7 +481,7 @@ RSpec.describe Snippets::UpdateService do
end
context 'delete action' do
- let(:snippet_files) { [{ action: :delete, file_path: file_path }] }
+ let(:snippet_actions) { [{ action: :delete, file_path: file_path }] }
shared_examples 'deletes the file' do
specify do
@@ -496,32 +496,32 @@ RSpec.describe Snippets::UpdateService do
it_behaves_like 'deletes the file'
context 'when previous_path is present and same as file_path' do
- let(:snippet_files) { [{ action: :delete, previous_path: file_path, file_path: file_path }] }
+ let(:snippet_actions) { [{ action: :delete, previous_path: file_path, file_path: file_path }] }
it_behaves_like 'deletes the file'
end
context 'when previous_path is present and is different from file_path' do
- let(:snippet_files) { [{ action: :delete, previous_path: 'foo', file_path: file_path }] }
+ let(:snippet_actions) { [{ action: :delete, previous_path: 'foo', file_path: file_path }] }
it_behaves_like 'deletes the file'
end
context 'when content is present' do
- let(:snippet_files) { [{ action: :delete, file_path: file_path, content: 'foo' }] }
+ let(:snippet_actions) { [{ action: :delete, file_path: file_path, content: 'foo' }] }
it_behaves_like 'deletes the file'
end
context 'when file_path does not exist' do
- let(:snippet_files) { [{ action: :delete, file_path: 'makeup_name' }] }
+ let(:snippet_actions) { [{ action: :delete, file_path: 'makeup_name' }] }
it_behaves_like 'returns an error', 'Repository Error updating the snippet'
end
end
context 'create action' do
- let(:snippet_files) { [{ action: :create, file_path: new_path, content: content }] }
+ let(:snippet_actions) { [{ action: :create, file_path: new_path, content: content }] }
it 'creates the file' do
expect(subject).to be_success
@@ -532,13 +532,13 @@ RSpec.describe Snippets::UpdateService do
end
context 'when content is not present' do
- let(:snippet_files) { [{ action: :create, file_path: new_path }] }
+ let(:snippet_actions) { [{ action: :create, file_path: new_path }] }
- it_behaves_like 'returns an error', 'Snippet files have invalid data'
+ it_behaves_like 'returns an error', 'Snippet actions have invalid data'
end
context 'when file_path is not present or empty' do
- let(:snippet_files) { [{ action: :create, content: content }, { action: :create, file_path: '', content: content }] }
+ let(:snippet_actions) { [{ action: :create, content: content }, { action: :create, file_path: '', content: content }] }
it 'generates the file path for the files' do
expect(blob('snippetfile1.txt')).to be_nil
@@ -552,13 +552,13 @@ RSpec.describe Snippets::UpdateService do
end
context 'when file_path already exists in the repository' do
- let(:snippet_files) { [{ action: :create, file_path: file_path, content: content }] }
+ let(:snippet_actions) { [{ action: :create, file_path: file_path, content: content }] }
it_behaves_like 'returns an error', 'Repository Error updating the snippet'
end
context 'when previous_path is present' do
- let(:snippet_files) { [{ action: :create, previous_path: 'foo', file_path: new_path, content: content }] }
+ let(:snippet_actions) { [{ action: :create, previous_path: 'foo', file_path: new_path, content: content }] }
it 'creates the file' do
expect(subject).to be_success
@@ -577,7 +577,7 @@ RSpec.describe Snippets::UpdateService do
let(:move_previous_path) { 'VERSION' }
let(:move_file_path) { 'VERSION_new' }
- let(:snippet_files) do
+ let(:snippet_actions) do
[
{ action: :create, file_path: create_file_path, content: content },
{ action: :update, file_path: update_file_path, content: content },
@@ -678,7 +678,7 @@ RSpec.describe Snippets::UpdateService do
it_behaves_like 'updates repository content'
it_behaves_like 'commit operation fails'
it_behaves_like 'committable attributes'
- it_behaves_like 'when snippet_files param is present'
+ it_behaves_like 'when snippet_actions param is present'
it_behaves_like 'only file_name is present'
it_behaves_like 'only content is present'
it_behaves_like 'snippets spam check is performed' do
@@ -705,7 +705,7 @@ RSpec.describe Snippets::UpdateService do
it_behaves_like 'updates repository content'
it_behaves_like 'commit operation fails'
it_behaves_like 'committable attributes'
- it_behaves_like 'when snippet_files param is present'
+ it_behaves_like 'when snippet_actions param is present'
it_behaves_like 'only file_name is present'
it_behaves_like 'only content is present'
it_behaves_like 'snippets spam check is performed' do
diff --git a/spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb b/spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb
new file mode 100644
index 00000000000..e2be91516b9
--- /dev/null
+++ b/spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IncidentManagement::PagerDuty::ProcessIncidentWorker do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: true) }
+
+ describe '#perform' do
+ subject(:perform) { described_class.new.perform(project.id, incident_payload) }
+
+ context 'with valid incident payload' do
+ let(:incident_payload) do
+ {
+ 'url' => 'https://webdemo.pagerduty.com/incidents/PRORDTY',
+ 'incident_number' => 33,
+ 'title' => 'My new incident',
+ 'status' => 'triggered',
+ 'created_at' => '2017-09-26T15:14:36Z',
+ 'urgency' => 'high',
+ 'incident_key' => nil,
+ 'assignees' => [{
+ 'summary' => 'Laura Haley', 'url' => 'https://webdemo.pagerduty.com/users/P553OPV'
+ }],
+ 'impacted_services' => [{
+ 'summary' => 'Production XDB Cluster', 'url' => 'https://webdemo.pagerduty.com/services/PN49J75'
+ }]
+ }
+ end
+
+ it 'creates a GitLab issue' do
+ expect { perform }.to change(Issue, :count).by(1)
+ end
+ end
+
+ context 'with invalid incident payload' do
+ let(:incident_payload) { {} }
+
+ before do
+ allow(Gitlab::AppLogger).to receive(:warn).and_call_original
+ end
+
+ it 'does not create a GitLab issue' do
+ expect { perform }.not_to change(Issue, :count)
+ end
+
+ it 'logs a warning' do
+ perform
+
+ expect(Gitlab::AppLogger).to have_received(:warn).with(
+ message: 'Cannot create issue for PagerDuty incident',
+ issue_errors: "Title can't be blank"
+ )
+ end
+ end
+ end
+end
diff --git a/symbol/icons.svg b/symbol/icons.svg
deleted file mode 100644
index 433bd2aca0d..00000000000
--- a/symbol/icons.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 1792 1792" id="clock_o" xmlns="http://www.w3.org/2000/svg"><path d="M1024 544v448q0 14-9 23t-23 9H672q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h224V544q0-14 9-23t23-9h64q14 0 23 9t9 23zm416 352q0-148-73-273t-198-198-273-73-273 73-198 198-73 273 73 273 198 198 273 73 273-73 198-198 73-273zm224 0q0 209-103 385.5T1281.5 1561 896 1664t-385.5-103T231 1281.5 128 896t103-385.5T510.5 231 896 128t385.5 103T1561 510.5 1664 896z"/></symbol><symbol viewBox="0 0 36 18" id="commit" xmlns="http://www.w3.org/2000/svg"><path d="M34 7h-7.2c-.9-4-4.5-7-8.8-7s-7.9 3-8.8 7H2C.9 7 0 7.9 0 9s.9 2 2 2h7.2c.9 4 4.5 7 8.8 7s7.9-3 8.8-7H34c1.1 0 2-.9 2-2s-.9-2-2-2m-16 7c-2.8 0-5-2.2-5-5s2.2-5 5-5 5 2.2 5 5-2.2 5-5 5"/></symbol><symbol viewBox="0 0 16 16" id="project" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177l-.038.044a.505.505 0 0 0 .038-.044zm-.787 0a.5.5 0 0 0 .038.043l-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol></svg> \ No newline at end of file
diff --git a/symbol/sprite.symbol.html b/symbol/sprite.symbol.html
deleted file mode 100644
index a2289014093..00000000000
--- a/symbol/sprite.symbol.html
+++ /dev/null
@@ -1,177 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta charset="utf-8"/>
- <meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
- <script src="https://rawgit.com/jonathantneal/svg4everybody/master/dist/svg4everybody.js"></script>
- <script>svg4everybody();</script>
- <title>SVG &lt;symbol&gt; sprite preview | svg-sprite</title>
- <style>@charset "UTF-8";body{padding:0;margin:0;color:#666;background:#fafafa;font-family:Arial,Helvetica,sans-serif;font-size:1em;line-height:1.4}header{display:block;padding:3em 3em 2em 3em;background-color:#fff}header p{margin:2em 0 0 0}section{border-top:1px solid #eee;padding:2em 3em 0 3em}section ul{margin:0;padding:0}section li{display:inline;display:inline-block;background-color:#fff;position:relative;margin:0 2em 2em 0;vertical-align:top;border:1px solid #ccc;padding:1em 1em 3em 1em;cursor:default}.icon-box{margin:0;width:144px;height:144px;position:relative;background:#ccc url("data:image/gif;base64,R0lGODlhDAAMAIAAAMzMzP///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjEgNjQuMTQwOTQ5LCAyMDEwLzEyLzA3LTEwOjU3OjAxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozQjk4OTI0MUY5NTIxMUUyQkJDMEI5NEFEM0Y1QTYwQyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozQjk4OTI0MkY5NTIxMUUyQkJDMEI5NEFEM0Y1QTYwQyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjNCOTg5MjNGRjk1MjExRTJCQkMwQjk0QUQzRjVBNjBDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjNCOTg5MjQwRjk1MjExRTJCQkMwQjk0QUQzRjVBNjBDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1NDMyMTAvLi0sKyopKCcmJSQjIiEgHx4dHBsaGRgXFhUUExIREA8ODQwLCgkIBwYFBAMCAQAAIfkEAAAAAAAsAAAAAAwADAAAAhaEH6mHmmzcgzJAUG/NVGrfOZ8YLlABADs=") top left repeat;border:1px solid #ccc;display:table-cell;vertical-align:middle;text-align:center}.icon{display:inline;display:inline-block}h1{margin-top:0}h2{margin:0;padding:0;font-size:1em;font-weight:normal;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;position:absolute;left:1em;right:1em;bottom:1em}footer{display:block;margin:0;padding:0 3em 3em 3em}footer p{margin:0;font-size:.7em}footer a{color:#0f7595;margin-left:0}</style>
-
-<!--
-
-Sprite shape dimensions
-====================================================================================================
-You will need to set the sprite shape dimensions via CSS when you use them as inline SVG, otherwise
-they would become a huge 100% in size. You may use the following dimension classes for doing so.
-They might well be outsourced to an external stylesheet of course.
-
--->
-
-<style type="text/css">
- .svg-clock_o-dims { width: 200px; height: 200px; }
- .svg-commit-dims { width: 36px; height: 18px; }
- .svg-project-dims { width: 16px; height: 16px; }
-</style>
-<!--
-====================================================================================================
--->
-
- </head>
- <body>
-
-<!--
-
-Inline <symbol> SVG sprite
-====================================================================================================
-This is an inlined version of the generated SVG sprite. The single images may be <use>d everywhere
-below within this document. Please see
-
- https://github.com/jkphl/svg-sprite/blob/master/docs/configuration.md#defs--symbol-mode
-
-for further details on how to create this embeddable sprite variant.
-
--->
-
-<svg width="0" height="0" style="position:absolute">
- <symbol viewBox="0 0 1792 1792" id="clock_o" xmlns="http://www.w3.org/2000/svg"><path d="M1024 544v448q0 14-9 23t-23 9H672q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h224V544q0-14 9-23t23-9h64q14 0 23 9t9 23zm416 352q0-148-73-273t-198-198-273-73-273 73-198 198-73 273 73 273 198 198 273 73 273-73 198-198 73-273zm224 0q0 209-103 385.5T1281.5 1561 896 1664t-385.5-103T231 1281.5 128 896t103-385.5T510.5 231 896 128t385.5 103T1561 510.5 1664 896z"/></symbol>
- <symbol viewBox="0 0 36 18" id="commit" xmlns="http://www.w3.org/2000/svg"><path d="M34 7h-7.2c-.9-4-4.5-7-8.8-7s-7.9 3-8.8 7H2C.9 7 0 7.9 0 9s.9 2 2 2h7.2c.9 4 4.5 7 8.8 7s7.9-3 8.8-7H34c1.1 0 2-.9 2-2s-.9-2-2-2m-16 7c-2.8 0-5-2.2-5-5s2.2-5 5-5 5 2.2 5 5-2.2 5-5 5"/></symbol>
- <symbol viewBox="0 0 16 16" id="project" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177l-.038.044a.505.505 0 0 0 .038-.044zm-.787 0a.5.5 0 0 0 .038.043l-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol>
-</svg>
-
-<!--
-====================================================================================================
--->
-
- <header>
- <h1>SVG <code>&lt;symbol&gt;</code> sprite preview</h1>
- <p>This preview features two methods of using the generated sprite in conjunction with inline SVG. Please have a look at the HTML source for further details and be aware of the following constraints:</p>
- <ul>
- <li>Your browser has to <a href="http://caniuse.com/#feat=svg-html5" target="_blank">support inline SVG</a> for these techniques to work.</li>
- <li>The embedded sprite (A) slightly differs from the generated external one. Please <a href="https://github.com/jkphl/svg-sprite/blob/master/docs/configuration.md#defs--symbol-mode" target="_blank">see the documentation</a> for details on how to create such an embeddable sprite.</li>
- <li>Internet Explorer up to version 11 doesn't support external sprites for use with inline SVG. For IE 9-11, you may polyfill this functionality with <a href="https://github.com/jonathantneal/svg4everybody" target="_blank">SVG for Everybody</a>.</li>
- </ul>
- </header>
- <section>
-
-<!--
-
-A) Inline SVG with embedded sprite
-====================================================================================================
-These SVG images make use of fragment identifiers (IDs) and are extracted out of the inline sprite
-embedded above. They may be styled via CSS.
-
--->
-
- <h3>A) Inline SVG with embedded sprite</h3>
- <ul>
-
- <li title="clock_o">
- <div class="icon-box">
-
- <!-- clock_o -->
- <svg class="svg-clock_o-dims">
- <use xlink:href="#clock_o"></use>
- </svg>
-
- </div>
- <h2>clock_o</h2>
- </li>
- <li title="commit">
- <div class="icon-box">
-
- <!-- commit -->
- <svg class="svg-commit-dims">
- <use xlink:href="#commit"></use>
- </svg>
-
- </div>
- <h2>commit</h2>
- </li>
- <li title="project">
- <div class="icon-box">
-
- <!-- project -->
- <svg class="svg-project-dims">
- <use xlink:href="#project"></use>
- </svg>
-
- </div>
- <h2>project</h2>
- </li>
- </ul>
-
-<!--
-====================================================================================================
--->
-
- </section>
- <section>
-
-<!--
-
-B) Inline SVG with external sprite (IE 9-11 with polyfill only)
-====================================================================================================
-These SVG images make use of an URL + fragment identifiers (IDs) and refer to the regular external
-SVG sprite. They may be styled via CSS. (IE 9-11 with polyfill only)
-
--->
-
- <h3>B) Inline SVG with external sprite (IE 9-11 with polyfill only)</h3>
- <ul>
-
- <li title="clock_o">
- <div class="icon-box">
-
- <!-- clock_o -->
- <svg class="svg-clock_o-dims">
- <use xlink:href="icons.svg#clock_o"></use>
- </svg>
-
- </div>
- <h2>clock_o</h2>
- </li>
- <li title="commit">
- <div class="icon-box">
-
- <!-- commit -->
- <svg class="svg-commit-dims">
- <use xlink:href="icons.svg#commit"></use>
- </svg>
-
- </div>
- <h2>commit</h2>
- </li>
- <li title="project">
- <div class="icon-box">
-
- <!-- project -->
- <svg class="svg-project-dims">
- <use xlink:href="icons.svg#project"></use>
- </svg>
-
- </div>
- <h2>project</h2>
- </li>
- </ul>
-
-<!--
-====================================================================================================
--->
-
- </section>
- <footer>
- <p>Generated at Fri, 25 Aug 2017 12:38:01 GMT by <a href="https://github.com/jkphl/svg-sprite" target="_blank">svg-sprite</a>.</p>
- </footer>
- </body>
-</html>