summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/logs/components/environment_logs.vue10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_terraform_plan.vue152
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js1
-rw-r--r--app/controllers/projects/static_site_editor_controller.rb11
-rw-r--r--app/services/metrics/dashboard/base_service.rb5
-rw-r--r--app/services/metrics/dashboard/system_dashboard_service.rb5
-rw-r--r--app/views/projects/static_site_editor/show.html.haml2
-rw-r--r--app/workers/concerns/project_import_options.rb7
-rw-r--r--changelogs/unreleased/207528-tf-plan-in-mr.yml5
-rw-r--r--changelogs/unreleased/212560_initialize_sse_frontend.yml5
-rw-r--r--changelogs/unreleased/213325-elastic-recommendation-alert-appears-when-the-screen-is-loaded.yml5
-rw-r--r--lib/gitlab/metrics/dashboard/stages/alerts_inserter.rb41
-rw-r--r--lib/gitlab/static_site_editor/config.rb36
-rw-r--r--locale/gitlab.pot21
-rw-r--r--spec/controllers/projects/static_site_editor_controller_spec.rb15
-rw-r--r--spec/frontend/logs/components/environment_logs_spec.js10
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_terraform_plan_spec.js89
-rw-r--r--spec/lib/gitlab/metrics/dashboard/processor_spec.rb52
-rw-r--r--spec/lib/gitlab/static_site_editor/config_spec.rb30
-rw-r--r--spec/workers/concerns/project_import_options_spec.rb11
21 files changed, 500 insertions, 17 deletions
diff --git a/app/assets/javascripts/logs/components/environment_logs.vue b/app/assets/javascripts/logs/components/environment_logs.vue
index 487b4f30b5b..0d84798d690 100644
--- a/app/assets/javascripts/logs/components/environment_logs.vue
+++ b/app/assets/javascripts/logs/components/environment_logs.vue
@@ -70,9 +70,10 @@ export default {
return this.logs.isLoading;
},
shouldShowElasticStackCallout() {
- return (
- !this.isElasticStackCalloutDismissed &&
- (this.environments.isLoading || !this.showAdvancedFilters)
+ return !(
+ this.environments.isLoading ||
+ this.isElasticStackCalloutDismissed ||
+ this.showAdvancedFilters
);
},
},
@@ -120,7 +121,8 @@ export default {
<div class="environment-logs-viewer d-flex flex-column py-3">
<gl-alert
v-if="shouldShowElasticStackCallout"
- class="mb-3 js-elasticsearch-alert"
+ ref="elasticsearchNotice"
+ class="mb-3"
@dismiss="isElasticStackCalloutDismissed = true"
>
{{
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_terraform_plan.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_terraform_plan.vue
new file mode 100644
index 00000000000..edf90085a5b
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_terraform_plan.vue
@@ -0,0 +1,152 @@
+<script>
+import { __ } from '~/locale';
+import { GlIcon, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
+import axios from '~/lib/utils/axios_utils';
+import CiIcon from '../../vue_shared/components/ci_icon.vue';
+import flash from '~/flash';
+import Poll from '~/lib/utils/poll';
+import Visibility from 'visibilityjs';
+
+export default {
+ name: 'MRWidgetTerraformPlan',
+ components: {
+ CiIcon,
+ GlIcon,
+ GlLoadingIcon,
+ GlSprintf,
+ },
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ loading: true,
+ plans: {},
+ };
+ },
+ computed: {
+ addNum() {
+ return Number(this.plan.create);
+ },
+ changeNum() {
+ return Number(this.plan.update);
+ },
+ deleteNum() {
+ return Number(this.plan.delete);
+ },
+ iconStatusObj() {
+ return {
+ group: 'warning',
+ icon: 'status_warning',
+ };
+ },
+ logUrl() {
+ return this.plan.job_path;
+ },
+ plan() {
+ return this.plans['tfplan.json'] || {};
+ },
+ validPlanValues() {
+ return this.addNum + this.changeNum + this.deleteNum >= 0;
+ },
+ },
+ created() {
+ this.fetchPlans();
+ },
+ methods: {
+ fetchPlans() {
+ this.loading = true;
+
+ const poll = new Poll({
+ resource: {
+ fetchPlans: () => axios.get(this.endpoint),
+ },
+ data: this.endpoint,
+ method: 'fetchPlans',
+ successCallback: ({ data }) => {
+ this.plans = data;
+ this.loading = false;
+ },
+ errorCallback: () => {
+ this.plans = {};
+ this.loading = false;
+ flash(__('An error occurred while loading terraform report'));
+ },
+ });
+
+ if (!Visibility.hidden()) {
+ poll.makeRequest();
+ }
+
+ Visibility.change(() => {
+ if (!Visibility.hidden()) {
+ poll.restart();
+ } else {
+ poll.stop();
+ }
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <section class="mr-widget-section">
+ <div class="mr-widget-body media d-flex flex-row">
+ <span class="append-right-default align-self-start align-self-lg-center">
+ <ci-icon :status="iconStatusObj" :size="24" />
+ </span>
+
+ <div class="d-flex flex-fill flex-column flex-md-row">
+ <div class="terraform-mr-plan-text normal d-flex flex-column flex-lg-row">
+ <p class="m-0 pr-1">{{ __('A terraform report was generated in your pipelines.') }}</p>
+
+ <gl-loading-icon v-if="loading" size="md" />
+
+ <p v-else-if="validPlanValues" class="m-0">
+ <gl-sprintf
+ :message="
+ __(
+ 'Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete',
+ )
+ "
+ >
+ <template #addNum>
+ <strong>{{ addNum }}</strong>
+ </template>
+
+ <template #changeNum>
+ <strong>{{ changeNum }}</strong>
+ </template>
+
+ <template #deleteNum>
+ <strong>{{ deleteNum }}</strong>
+ </template>
+ </gl-sprintf>
+ </p>
+
+ <p v-else class="m-0">{{ __('Changes are unknown') }}</p>
+ </div>
+
+ <div class="terraform-mr-plan-actions">
+ <a
+ v-if="logUrl"
+ :href="logUrl"
+ target="_blank"
+ data-track-event="click_terraform_mr_plan_button"
+ data-track-label="mr_widget_terraform_mr_plan_button"
+ data-track-property="terraform_mr_plan_button"
+ class="btn btn-sm js-terraform-report-link"
+ rel="noopener"
+ >
+ {{ __('View full log') }}
+ <gl-icon name="external-link" />
+ </a>
+ </div>
+ </div>
+ </div>
+ </section>
+</template>
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 084deee042b..1bc28b15f74 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
@@ -36,6 +36,7 @@ import CheckingState from './components/states/mr_widget_checking.vue';
import eventHub from './event_hub';
import notify from '~/lib/utils/notify';
import SourceBranchRemovalStatus from './components/source_branch_removal_status.vue';
+import TerraformPlan from './components/mr_widget_terraform_plan.vue';
import GroupedTestReportsApp from '../reports/components/grouped_test_reports_app.vue';
import { setFaviconOverlay } from '../lib/utils/common_utils';
@@ -74,6 +75,7 @@ export default {
'mr-widget-rebase': RebaseState,
SourceBranchRemovalStatus,
GroupedTestReportsApp,
+ TerraformPlan,
},
props: {
mrData: {
@@ -379,6 +381,8 @@ export default {
:endpoint="mr.testResultsPath"
/>
+ <terraform-plan v-if="mr.terraformReportsPath" :endpoint="mr.terraformReportsPath" />
+
<div class="mr-widget-section">
<component :is="componentName" :mr="mr" :service="service" />
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 321b9270dde..9f001dda540 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -101,6 +101,7 @@ export default class MergeRequestStore {
this.isPipelineActive = data.pipeline ? data.pipeline.active : false;
this.isPipelineBlocked = pipelineStatus ? pipelineStatus.group === 'manual' : false;
this.ciStatusFaviconPath = pipelineStatus ? pipelineStatus.favicon : null;
+ this.terraformReportsPath = data.terraform_reports_path;
this.testResultsPath = data.test_reports_path;
this.exposedArtifactsPath = data.exposed_artifacts_path;
this.cancelAutoMergePath = data.cancel_auto_merge_path;
diff --git a/app/controllers/projects/static_site_editor_controller.rb b/app/controllers/projects/static_site_editor_controller.rb
index 597bfccf422..98ec2335899 100644
--- a/app/controllers/projects/static_site_editor_controller.rb
+++ b/app/controllers/projects/static_site_editor_controller.rb
@@ -1,10 +1,21 @@
# frozen_string_literal: true
class Projects::StaticSiteEditorController < Projects::ApplicationController
+ include ExtractsPath
layout 'fullscreen'
prepend_before_action :authenticate_user!, only: [:show]
+ before_action :assign_ref_and_path, only: [:show]
def show
+ @config = Gitlab::StaticSiteEditor::Config.new(@repository, @ref, @path, params[:return_url])
+ end
+
+ private
+
+ def assign_ref_and_path
+ @ref, @path = extract_ref(params[:id])
+
+ render_404 if @ref.blank? || @path.blank?
end
end
diff --git a/app/services/metrics/dashboard/base_service.rb b/app/services/metrics/dashboard/base_service.rb
index 219b26defb1..c112d75a9b5 100644
--- a/app/services/metrics/dashboard/base_service.rb
+++ b/app/services/metrics/dashboard/base_service.rb
@@ -12,7 +12,8 @@ module Metrics
STAGES::CommonMetricsInserter,
STAGES::EndpointInserter,
STAGES::PanelIdsInserter,
- STAGES::Sorter
+ STAGES::Sorter,
+ STAGES::AlertsInserter
].freeze
def get_dashboard
@@ -117,5 +118,3 @@ module Metrics
end
end
end
-
-Metrics::Dashboard::BaseService.prepend_if_ee('EE::Metrics::Dashboard::BaseService')
diff --git a/app/services/metrics/dashboard/system_dashboard_service.rb b/app/services/metrics/dashboard/system_dashboard_service.rb
index c28b7b875df..ed4b78ba159 100644
--- a/app/services/metrics/dashboard/system_dashboard_service.rb
+++ b/app/services/metrics/dashboard/system_dashboard_service.rb
@@ -14,7 +14,8 @@ module Metrics
STAGES::CustomMetricsDetailsInserter,
STAGES::EndpointInserter,
STAGES::PanelIdsInserter,
- STAGES::Sorter
+ STAGES::Sorter,
+ STAGES::AlertsInserter
].freeze
class << self
@@ -30,5 +31,3 @@ module Metrics
end
end
end
-
-Metrics::Dashboard::SystemDashboardService.prepend_if_ee('EE::Metrics::Dashboard::SystemDashboardService')
diff --git a/app/views/projects/static_site_editor/show.html.haml b/app/views/projects/static_site_editor/show.html.haml
index 9ccc54e6d51..8d2649be588 100644
--- a/app/views/projects/static_site_editor/show.html.haml
+++ b/app/views/projects/static_site_editor/show.html.haml
@@ -1 +1 @@
-#static-site-editor{ data: { project_id: '8', path: 'README.md' } }
+#static-site-editor{ data: @config.payload }
diff --git a/app/workers/concerns/project_import_options.rb b/app/workers/concerns/project_import_options.rb
index 2baf768bfd1..c8ee5539441 100644
--- a/app/workers/concerns/project_import_options.rb
+++ b/app/workers/concerns/project_import_options.rb
@@ -18,7 +18,12 @@ module ProjectImportOptions
"import"
end
- project.import_state.mark_as_failed(_("Every %{action} attempt has failed: %{job_error_message}. Please try again.") % { action: action, job_error_message: job['error_message'] })
+ if project.jira_import?
+ project.latest_jira_import.do_fail!
+ else
+ project.import_state.mark_as_failed(_("Every %{action} attempt has failed: %{job_error_message}. Please try again.") % { action: action, job_error_message: job['error_message'] })
+ end
+
Sidekiq.logger.warn "Failed #{job['class']} with #{job['args']}: #{job['error_message']}"
end
end
diff --git a/changelogs/unreleased/207528-tf-plan-in-mr.yml b/changelogs/unreleased/207528-tf-plan-in-mr.yml
new file mode 100644
index 00000000000..6535e17d48c
--- /dev/null
+++ b/changelogs/unreleased/207528-tf-plan-in-mr.yml
@@ -0,0 +1,5 @@
+---
+title: Add terraform report to merge request widget
+merge_request: 27700
+author:
+type: added
diff --git a/changelogs/unreleased/212560_initialize_sse_frontend.yml b/changelogs/unreleased/212560_initialize_sse_frontend.yml
new file mode 100644
index 00000000000..0ee5d7669ba
--- /dev/null
+++ b/changelogs/unreleased/212560_initialize_sse_frontend.yml
@@ -0,0 +1,5 @@
+---
+title: Provide configuration options for Static Site Editor
+merge_request: 29058
+author:
+type: added
diff --git a/changelogs/unreleased/213325-elastic-recommendation-alert-appears-when-the-screen-is-loaded.yml b/changelogs/unreleased/213325-elastic-recommendation-alert-appears-when-the-screen-is-loaded.yml
new file mode 100644
index 00000000000..43583268c84
--- /dev/null
+++ b/changelogs/unreleased/213325-elastic-recommendation-alert-appears-when-the-screen-is-loaded.yml
@@ -0,0 +1,5 @@
+---
+title: Elasticsearch recommendation alert does not appears while screen is loaded
+merge_request: 29097
+author:
+type: fixed
diff --git a/lib/gitlab/metrics/dashboard/stages/alerts_inserter.rb b/lib/gitlab/metrics/dashboard/stages/alerts_inserter.rb
new file mode 100644
index 00000000000..38736158c3b
--- /dev/null
+++ b/lib/gitlab/metrics/dashboard/stages/alerts_inserter.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'set'
+
+module Gitlab
+ module Metrics
+ module Dashboard
+ module Stages
+ class AlertsInserter < BaseStage
+ include ::Gitlab::Utils::StrongMemoize
+
+ def transform!
+ return if metrics_with_alerts.empty?
+
+ for_metrics do |metric|
+ next unless metrics_with_alerts.include?(metric[:metric_id])
+
+ metric[:alert_path] = alert_path(metric[:metric_id], project, params[:environment])
+ end
+ end
+
+ private
+
+ def metrics_with_alerts
+ strong_memoize(:metrics_with_alerts) do
+ alerts = ::Projects::Prometheus::AlertsFinder
+ .new(project: project, environment: params[:environment])
+ .execute
+
+ Set.new(alerts.map(&:prometheus_metric_id))
+ end
+ end
+
+ def alert_path(metric_id, project, environment)
+ ::Gitlab::Routing.url_helpers.project_prometheus_alert_path(project, metric_id, environment_id: environment.id, format: :json)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/static_site_editor/config.rb b/lib/gitlab/static_site_editor/config.rb
new file mode 100644
index 00000000000..4bc0fc95abd
--- /dev/null
+++ b/lib/gitlab/static_site_editor/config.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module StaticSiteEditor
+ class Config
+ def initialize(repository, ref, file_path, return_url)
+ @repository = repository
+ @ref = ref
+ @file_path = file_path
+ @return_url = return_url
+ end
+
+ def payload
+ {
+ branch: ref,
+ path: file_path,
+ commit: commit.id,
+ project_id: project.id,
+ project: project.path,
+ namespace: project.namespace.path,
+ return_url: return_url
+ }
+ end
+
+ private
+
+ attr_reader :repository, :ref, :file_path, :return_url
+
+ delegate :project, to: :repository
+
+ def commit
+ repository.commit(ref)
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 0c35c77f8cf..9b39c97cb38 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -888,6 +888,9 @@ msgstr ""
msgid "A subscription will trigger a new pipeline on the default branch of this project when a pipeline successfully completes for a new tag on the %{default_branch_docs} of the subscribed project."
msgstr ""
+msgid "A terraform report was generated in your pipelines."
+msgstr ""
+
msgid "A user with write access to the source branch selected this option"
msgstr ""
@@ -2008,6 +2011,9 @@ msgstr ""
msgid "An error occurred while loading merge requests."
msgstr ""
+msgid "An error occurred while loading terraform report"
+msgstr ""
+
msgid "An error occurred while loading the data. Please try again."
msgstr ""
@@ -3526,6 +3532,9 @@ msgstr ""
msgid "Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision."
msgstr ""
+msgid "Changes are unknown"
+msgstr ""
+
msgid "Changes suppressed. Click to show."
msgstr ""
@@ -15632,6 +15641,12 @@ msgstr ""
msgid "Project name"
msgstr ""
+msgid "Project name suffix"
+msgstr ""
+
+msgid "Project name suffix is a user-defined string which will be appended to the project path, and will form the Service Desk email address."
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -17019,6 +17034,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete"
+msgstr ""
+
msgid "Reporter"
msgstr ""
@@ -22694,6 +22712,9 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
+msgid "View full log"
+msgstr ""
+
msgid "View group labels"
msgstr ""
diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb
index 7f1b67fc734..d1224bb75c0 100644
--- a/spec/controllers/projects/static_site_editor_controller_spec.rb
+++ b/spec/controllers/projects/static_site_editor_controller_spec.rb
@@ -10,7 +10,8 @@ describe Projects::StaticSiteEditorController do
{
namespace_id: project.namespace,
project_id: project,
- id: 'master/README.md'
+ id: 'master/README.md',
+ return_url: 'http://example.com'
}
end
@@ -38,6 +39,18 @@ describe Projects::StaticSiteEditorController do
it 'renders the edit page' do
expect(response).to render_template(:show)
end
+
+ it 'assigns a config variable' do
+ expect(assigns(:config)).to be_a(Gitlab::StaticSiteEditor::Config)
+ end
+
+ context 'when combination of ref and file path is incorrect' do
+ let(:default_params) { super().merge(id: 'unknown') }
+
+ it 'responds with 404 page' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
end
end
end
diff --git a/spec/frontend/logs/components/environment_logs_spec.js b/spec/frontend/logs/components/environment_logs_spec.js
index befcd462828..d097610cb0a 100644
--- a/spec/frontend/logs/components/environment_logs_spec.js
+++ b/spec/frontend/logs/components/environment_logs_spec.js
@@ -43,7 +43,7 @@ describe('EnvironmentLogs', () => {
const findSimpleFilters = () => wrapper.find({ ref: 'log-simple-filters' });
const findAdvancedFilters = () => wrapper.find({ ref: 'log-advanced-filters' });
- const findInfoAlert = () => wrapper.find('.js-elasticsearch-alert');
+ const findElasticsearchNotice = () => wrapper.find({ ref: 'elasticsearchNotice' });
const findLogControlButtons = () => wrapper.find({ name: 'log-control-buttons-stub' });
const findInfiniteScroll = () => wrapper.find({ ref: 'infiniteScroll' });
@@ -160,6 +160,10 @@ describe('EnvironmentLogs', () => {
initWrapper();
});
+ it('does not display an alert to upgrade to ES', () => {
+ expect(findElasticsearchNotice().exists()).toBe(false);
+ });
+
it('displays a disabled environments dropdown', () => {
expect(findEnvironmentsDropdown().attributes('disabled')).toBe('true');
expect(findEnvironmentsDropdown().findAll(GlDropdownItem).length).toBe(0);
@@ -204,7 +208,7 @@ describe('EnvironmentLogs', () => {
});
it('displays an alert to upgrade to ES', () => {
- expect(findInfoAlert().exists()).toBe(true);
+ expect(findElasticsearchNotice().exists()).toBe(true);
});
it('displays simple filters for kubernetes logs API', () => {
@@ -235,7 +239,7 @@ describe('EnvironmentLogs', () => {
});
it('does not display an alert to upgrade to ES', () => {
- expect(findInfoAlert().exists()).toBe(false);
+ expect(findElasticsearchNotice().exists()).toBe(false);
});
it('populates environments dropdown', () => {
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_terraform_plan_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_terraform_plan_spec.js
new file mode 100644
index 00000000000..1951b56587a
--- /dev/null
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_terraform_plan_spec.js
@@ -0,0 +1,89 @@
+import { GlLoadingIcon, GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import axios from '~/lib/utils/axios_utils';
+import MockAdapter from 'axios-mock-adapter';
+import MrWidgetTerraformPlan from '~/vue_merge_request_widget/components/mr_widget_terraform_plan.vue';
+
+const plan = {
+ create: 10,
+ update: 20,
+ delete: 30,
+ job_path: '/path/to/ci/logs',
+};
+
+describe('MrWidgetTerraformPlan', () => {
+ let mock;
+ let wrapper;
+
+ const propsData = { endpoint: '/path/to/terraform/report.json' };
+
+ const mockPollingApi = (response, body, header) => {
+ mock.onGet(propsData.endpoint).reply(response, body, header);
+ };
+
+ const mountWrapper = () => {
+ wrapper = shallowMount(MrWidgetTerraformPlan, { propsData });
+ return axios.waitForAll();
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ mock.restore();
+ });
+
+ describe('loading poll', () => {
+ beforeEach(() => {
+ mockPollingApi(200, { 'tfplan.json': plan }, {});
+
+ return mountWrapper().then(() => {
+ wrapper.setData({ loading: true });
+ return wrapper.vm.$nextTick();
+ });
+ });
+
+ it('Diplays loading icon when loading is true', () => {
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+
+ expect(wrapper.find(GlSprintf).exists()).toBe(false);
+
+ expect(wrapper.text()).not.toContain(
+ 'A terraform report was generated in your pipelines. Changes are unknown',
+ );
+ });
+ });
+
+ describe('successful poll', () => {
+ beforeEach(() => {
+ mockPollingApi(200, { 'tfplan.json': plan }, {});
+ return mountWrapper();
+ });
+
+ it('content change text', () => {
+ expect(wrapper.find(GlSprintf).exists()).toBe(true);
+ });
+
+ it('renders button when url is found', () => {
+ expect(wrapper.find('a').text()).toContain('View full log');
+ });
+ });
+
+ describe('polling fails', () => {
+ beforeEach(() => {
+ mockPollingApi(500, null, {});
+ return mountWrapper();
+ });
+
+ it('does not display changes text when api fails', () => {
+ expect(wrapper.text()).toContain(
+ 'A terraform report was generated in your pipelines. Changes are unknown',
+ );
+
+ expect(wrapper.find('.js-terraform-report-link').exists()).toBe(false);
+ expect(wrapper.text()).not.toContain('View full log');
+ });
+ });
+});
diff --git a/spec/lib/gitlab/metrics/dashboard/processor_spec.rb b/spec/lib/gitlab/metrics/dashboard/processor_spec.rb
index d957b1c992f..3cb02a8bcb3 100644
--- a/spec/lib/gitlab/metrics/dashboard/processor_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/processor_spec.rb
@@ -14,9 +14,11 @@ describe Gitlab::Metrics::Dashboard::Processor do
Gitlab::Metrics::Dashboard::Stages::CustomMetricsInserter,
Gitlab::Metrics::Dashboard::Stages::CustomMetricsDetailsInserter,
Gitlab::Metrics::Dashboard::Stages::EndpointInserter,
- Gitlab::Metrics::Dashboard::Stages::Sorter
+ Gitlab::Metrics::Dashboard::Stages::Sorter,
+ Gitlab::Metrics::Dashboard::Stages::AlertsInserter
]
end
+
let(:process_params) { [project, dashboard_yml, sequence, { environment: environment }] }
let(:dashboard) { described_class.new(*process_params).process }
@@ -113,6 +115,54 @@ describe Gitlab::Metrics::Dashboard::Processor do
end
end
+ context 'when the dashboard references persisted metrics with alerts' do
+ let!(:alert) do
+ create(
+ :prometheus_alert,
+ environment: environment,
+ project: project,
+ prometheus_metric: persisted_metric
+ )
+ end
+
+ shared_examples_for 'has saved alerts' do
+ it 'includes an alert path' do
+ target_metric = all_metrics.find { |metric| metric[:metric_id] == persisted_metric.id }
+
+ expect(target_metric).to be_a Hash
+ expect(target_metric).to include(:alert_path)
+ expect(target_metric[:alert_path]).to include(
+ project.path,
+ persisted_metric.id.to_s,
+ environment.id.to_s
+ )
+ end
+ end
+
+ context 'that are shared across projects' do
+ let!(:persisted_metric) { create(:prometheus_metric, :common, identifier: 'metric_a1') }
+
+ it_behaves_like 'has saved alerts'
+ end
+
+ context 'when the project has associated metrics' do
+ let!(:persisted_metric) { create(:prometheus_metric, project: project, group: :business) }
+
+ it_behaves_like 'has saved alerts'
+ end
+ end
+
+ context 'when there are no alerts' do
+ let!(:persisted_metric) { create(:prometheus_metric, :common, identifier: 'metric_a1') }
+
+ it 'does not insert an alert_path' do
+ target_metric = all_metrics.find { |metric| metric[:metric_id] == persisted_metric.id }
+
+ expect(target_metric).to be_a Hash
+ expect(target_metric).not_to include(:alert_path)
+ end
+ end
+
shared_examples_for 'errors with message' do |expected_message|
it 'raises a DashboardLayoutError' do
error_class = Gitlab::Metrics::Dashboard::Errors::DashboardProcessingError
diff --git a/spec/lib/gitlab/static_site_editor/config_spec.rb b/spec/lib/gitlab/static_site_editor/config_spec.rb
new file mode 100644
index 00000000000..dea79fb0e92
--- /dev/null
+++ b/spec/lib/gitlab/static_site_editor/config_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::StaticSiteEditor::Config do
+ subject(:config) { described_class.new(repository, ref, file_path, return_url) }
+
+ let(:project) { create(:project, :public, :repository, name: 'project', namespace: namespace) }
+ let(:namespace) { create(:namespace, name: 'namespace') }
+ let(:repository) { project.repository }
+ let(:ref) { 'master' }
+ let(:file_path) { 'README.md' }
+ let(:return_url) { 'http://example.com' }
+
+ describe '#payload' do
+ subject { config.payload }
+
+ it 'returns data for the frontend component' do
+ is_expected.to eq(
+ branch: 'master',
+ commit: repository.commit.id,
+ namespace: 'namespace',
+ path: 'README.md',
+ project: 'project',
+ project_id: project.id,
+ return_url: 'http://example.com'
+ )
+ end
+ end
+end
diff --git a/spec/workers/concerns/project_import_options_spec.rb b/spec/workers/concerns/project_import_options_spec.rb
index c5fbcfb5fb0..3ccfb21b653 100644
--- a/spec/workers/concerns/project_import_options_spec.rb
+++ b/spec/workers/concerns/project_import_options_spec.rb
@@ -39,6 +39,17 @@ describe ProjectImportOptions do
expect(project.import_state.reload.last_error).to include("import")
end
+ context 'when project is jira import' do
+ let(:project) { create(:project, import_type: 'jira') }
+ let!(:jira_import) { create(:jira_import_state, project: project) }
+
+ it 'logs the appropriate error message for forked projects' do
+ worker_class.sidekiq_retries_exhausted_block.call(job)
+
+ expect(project.latest_jira_import.reload.status).to eq('failed')
+ end
+ end
+
context 'when project does not have import_state' do
let(:project) { create(:project) }