Commit b5cc8c42 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch '5491-license-management-at-pipeline-ee' into 'master'

Show License Management at pipeline level

Closes #5491

See merge request gitlab-org/gitlab-ee!6688
parents 5678460d 011fd86e
...@@ -7,10 +7,6 @@ import pipelineGraph from './components/graph/graph_component.vue'; ...@@ -7,10 +7,6 @@ import pipelineGraph from './components/graph/graph_component.vue';
import pipelineHeader from './components/header_component.vue'; import pipelineHeader from './components/header_component.vue';
import eventHub from './event_hub'; import eventHub from './event_hub';
import SecurityReportApp from 'ee/vue_shared/security_reports/split_security_reports_app.vue'; // eslint-disable-line import/first
import SastSummaryWidget from 'ee/pipelines/components/security_reports/report_summary_widget.vue'; // eslint-disable-line import/first
import createStore from 'ee/vue_shared/security_reports/store'; // eslint-disable-line import/first
Vue.use(Translate); Vue.use(Translate);
export default () => { export default () => {
...@@ -87,103 +83,4 @@ export default () => { ...@@ -87,103 +83,4 @@ export default () => {
}); });
}, },
}); });
/**
* EE only
*/
const securityTab = document.getElementById('js-security-report-app');
const sastSummary = document.querySelector('.js-sast-summary');
const updateBadgeCount = count => {
const badge = document.querySelector('.js-sast-counter');
if (badge.textContent !== '') {
badge.textContent = parseInt(badge.textContent, 10) + count;
} else {
badge.textContent = count;
}
badge.classList.remove('hidden');
};
// They are being rendered under the same condition
if (securityTab && sastSummary) {
const datasetOptions = securityTab.dataset;
const {
endpoint,
blobPath,
sastHelpPath,
dependencyScanningEndpoint,
dependencyScanningHelpPath,
vulnerabilityFeedbackPath,
vulnerabilityFeedbackHelpPath,
dastEndpoint,
sastContainerEndpoint,
dastHelpPath,
sastContainerHelpPath,
} = datasetOptions;
const pipelineId = parseInt(datasetOptions.pipelineId, 10);
const { canCreateIssue, canCreateFeedback } = datasetOptions;
const store = createStore();
// Widget summary
// eslint-disable-next-line no-new
new Vue({
el: sastSummary,
store,
components: {
SastSummaryWidget,
},
methods: {
updateBadge(count) {
updateBadgeCount(count);
},
},
render(createElement) {
return createElement('sast-summary-widget', {
on: {
updateBadgeCount: this.updateBadge,
},
});
},
});
// Tab content
// eslint-disable-next-line no-new
new Vue({
el: securityTab,
store,
components: {
SecurityReportApp,
},
methods: {
updateBadge(count) {
updateBadgeCount(count);
},
},
render(createElement) {
return createElement('security-report-app', {
props: {
headBlobPath: blobPath,
sastHeadPath: endpoint,
sastHelpPath,
dependencyScanningHeadPath: dependencyScanningEndpoint,
dependencyScanningHelpPath,
vulnerabilityFeedbackPath,
vulnerabilityFeedbackHelpPath,
pipelineId,
dastHeadPath: dastEndpoint,
sastContainerHeadPath: sastContainerEndpoint,
dastHelpPath,
sastContainerHelpPath,
canCreateFeedback,
canCreateIssue,
},
on: {
updateBadgeCount: this.updateBadge,
},
});
},
});
}
}; };
...@@ -232,6 +232,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -232,6 +232,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get :failures get :failures
get :status get :status
get :security get :security
get :licenses
end end
end end
......
// /builds is an alias for show
import '../show/index';
// /failures is an alias for show
import '../show/index';
// /licenses is an alias for show
import '../show/index';
import initPipelineDetails from '~/pipelines/pipeline_details_bundle'; // /security is an alias for show
import initPipelines from '~/pages/projects/pipelines/init_pipelines'; import '../show/index';
document.addEventListener('DOMContentLoaded', () => {
initPipelines();
initPipelineDetails();
});
import initPipelineDetails from '~/pipelines/pipeline_details_bundle';
import initPipelines from '~/pages/projects/pipelines/init_pipelines';
import initSecurityReport from './security_report';
import initLicenseReport from './license_report';
document.addEventListener('DOMContentLoaded', () => {
initPipelines();
initPipelineDetails();
initSecurityReport();
initLicenseReport();
});
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import LicenseReportApp from 'ee/vue_shared/license_management/mr_widget_license_report.vue';
import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
import { updateBadgeCount } from './utils';
Vue.use(Translate);
export default () => {
const licensesTab = document.getElementById('js-licenses-app');
if (licensesTab) {
const { licenseHeadPath, canManageLicenses, apiUrl } = licensesTab.dataset;
// eslint-disable-next-line no-new
new Vue({
el: licensesTab,
components: {
LicenseReportApp,
},
render(createElement) {
return createElement('license-report-app', {
props: {
apiUrl,
headPath: licenseHeadPath,
canManageLicenses: convertPermissionToBoolean(canManageLicenses),
alwaysOpen: true,
reportSectionClass: 'split-report-section',
},
on: {
updateBadgeCount: (count) => {
updateBadgeCount('.js-licenses-counter', count);
},
},
});
},
});
}
};
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import SecurityReportApp from 'ee/vue_shared/security_reports/split_security_reports_app.vue';
import SastSummaryWidget from 'ee/pipelines/components/security_reports/report_summary_widget.vue';
import createStore from 'ee/vue_shared/security_reports/store';
import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
import { updateBadgeCount } from './utils';
Vue.use(Translate);
export default () => {
const securityTab = document.getElementById('js-security-report-app');
const sastSummary = document.querySelector('.js-sast-summary');
// They are being rendered under the same condition
if (securityTab) {
const datasetOptions = securityTab.dataset;
const {
headBlobPath,
sastHeadPath,
sastHelpPath,
dependencyScanningHeadPath,
dependencyScanningHelpPath,
vulnerabilityFeedbackPath,
vulnerabilityFeedbackHelpPath,
dastHeadPath,
sastContainerHeadPath,
dastHelpPath,
sastContainerHelpPath,
canCreateIssue,
canCreateFeedback,
} = datasetOptions;
const pipelineId = parseInt(datasetOptions.pipelineId, 10);
const store = createStore();
// Widget summary
if (sastSummary) {
// eslint-disable-next-line no-new
new Vue({
el: sastSummary,
store,
components: {
SastSummaryWidget,
},
render(createElement) {
return createElement('sast-summary-widget');
},
});
}
// Tab content
// eslint-disable-next-line no-new
new Vue({
el: securityTab,
store,
components: {
SecurityReportApp,
},
render(createElement) {
return createElement('security-report-app', {
props: {
headBlobPath,
sastHeadPath,
sastHelpPath,
dependencyScanningHeadPath,
dependencyScanningHelpPath,
vulnerabilityFeedbackPath,
vulnerabilityFeedbackHelpPath,
pipelineId,
dastHeadPath,
sastContainerHeadPath,
dastHelpPath,
sastContainerHelpPath,
canCreateFeedback: convertPermissionToBoolean(canCreateFeedback),
canCreateIssue: convertPermissionToBoolean(canCreateIssue),
},
on: {
updateBadgeCount: (count) => {
updateBadgeCount('.js-licenses-counter', count);
},
},
});
},
});
}
};
/* eslint-disable import/prefer-default-export */
/**
*
* Sets the text content of a DOM element to a given value.
* If the given value is an integer,
* the text content will set to the value and will be shown.
* If the given value is not an integer,
* the text content will be emptied and the element will be hidden.
*
* The visibility of the element is based on the helper class `.hidden`
*
* @param selector {String} selector of the DOM element
* @param count {Number=} value for the DOM element
*/
export const updateBadgeCount = (selector, count) => {
const badge = document.querySelector(selector);
if (Number.isInteger(count)) {
badge.textContent = `${count}`;
badge.classList.remove('hidden');
} else {
badge.classList.add('hidden');
badge.textContent = '';
}
};
...@@ -36,6 +36,16 @@ export default { ...@@ -36,6 +36,16 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
reportSectionClass: {
type: String,
required: false,
default: '',
},
alwaysOpen: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
...mapState(['loadLicenseReportError']), ...mapState(['loadLicenseReportError']),
...@@ -48,6 +58,14 @@ export default { ...@@ -48,6 +58,14 @@ export default {
return this.checkReportStatus(this.isLoading, this.loadLicenseReportError); return this.checkReportStatus(this.isLoading, this.loadLicenseReportError);
}, },
}, },
watch: {
licenseReport() {
this.$emit(
'updateBadgeCount',
this.licenseReport.length,
);
},
},
mounted() { mounted() {
const { headPath, basePath, apiUrl, canManageLicenses } = this; const { headPath, basePath, apiUrl, canManageLicenses } = this;
...@@ -77,7 +95,9 @@ export default { ...@@ -77,7 +95,9 @@ export default {
:neutral-issues="licenseReport" :neutral-issues="licenseReport"
:has-issues="hasLicenseReportIssues" :has-issues="hasLicenseReportIssues"
:component="$options.componentNames.LicenseIssueBody" :component="$options.componentNames.LicenseIssueBody"
class="license-report-widget mr-widget-border-top" :class="reportSectionClass"
:always-open="alwaysOpen"
class="license-report-widget"
/> />
</div> </div>
</template> </template>
...@@ -110,6 +110,20 @@ export default { ...@@ -110,6 +110,20 @@ export default {
dastText() { dastText() {
return this.summaryTextBuilder('DAST', this.dast.newIssues.length); return this.summaryTextBuilder('DAST', this.dast.newIssues.length);
}, },
issuesCount() {
return (
this.dast.newIssues.length +
this.dependencyScanning.newIssues.length +
this.sastContainer.newIssues.length +
this.sast.newIssues.length
);
},
},
watch: {
issuesCount() {
this.$emit('updateBadgeCount', this.issuesCount);
},
}, },
created() { created() {
// update the store with the received props // update the store with the received props
...@@ -123,21 +137,15 @@ export default { ...@@ -123,21 +137,15 @@ export default {
if (this.sastHeadPath) { if (this.sastHeadPath) {
this.setSastHeadPath(this.sastHeadPath); this.setSastHeadPath(this.sastHeadPath);
this.fetchSastReports() this.fetchSastReports().catch(() =>
.then(() => { createFlash(s__('ciReport|There was an error loading SAST report')),
this.$emit('updateBadgeCount', this.sast.newIssues.length); );
})
.catch(() => createFlash(s__('ciReport|There was an error loading SAST report')));
} }
if (this.dependencyScanningHeadPath) { if (this.dependencyScanningHeadPath) {
this.setDependencyScanningHeadPath(this.dependencyScanningHeadPath); this.setDependencyScanningHeadPath(this.dependencyScanningHeadPath);
this.fetchDependencyScanningReports() this.fetchDependencyScanningReports().catch(() =>
.then(() => {
this.$emit('updateBadgeCount', this.dependencyScanning.newIssues.length);
})
.catch(() =>
createFlash(s__('ciReport|There was an error loading dependency scanning report')), createFlash(s__('ciReport|There was an error loading dependency scanning report')),
); );
} }
...@@ -145,11 +153,7 @@ export default { ...@@ -145,11 +153,7 @@ export default {
if (this.sastContainerHeadPath) { if (this.sastContainerHeadPath) {
this.setSastContainerHeadPath(this.sastContainerHeadPath); this.setSastContainerHeadPath(this.sastContainerHeadPath);
this.fetchSastContainerReports() this.fetchSastContainerReports().catch(() =>
.then(() => {
this.$emit('updateBadgeCount', this.sastContainer.newIssues.length);
})
.catch(() =>
createFlash(s__('ciReport|There was an error loading container scanning report')), createFlash(s__('ciReport|There was an error loading container scanning report')),
); );
} }
...@@ -157,11 +161,7 @@ export default { ...@@ -157,11 +161,7 @@ export default {
if (this.dastHeadPath) { if (this.dastHeadPath) {
this.setDastHeadPath(this.dastHeadPath); this.setDastHeadPath(this.dastHeadPath);
this.fetchDastReports() this.fetchDastReports().catch(() =>
.then(() => {
this.$emit('updateBadgeCount', this.dast.newIssues.length);
})
.catch(() =>
createFlash(s__('ciReport|There was an error loading DAST report')), createFlash(s__('ciReport|There was an error loading DAST report')),
); );
} }
...@@ -184,7 +184,6 @@ export default { ...@@ -184,7 +184,6 @@ export default {
'setCanCreateIssuePermission', 'setCanCreateIssuePermission',
'setCanCreateFeedbackPermission', 'setCanCreateFeedbackPermission',
]), ]),
summaryTextBuilder(type, issuesCount = 0) { summaryTextBuilder(type, issuesCount = 0) {
if (issuesCount === 0) { if (issuesCount === 0) {
return sprintf(s__('ciReport|%{type} detected no vulnerabilities'), { return sprintf(s__('ciReport|%{type} detected no vulnerabilities'), {
......
...@@ -4,7 +4,15 @@ module EE ...@@ -4,7 +4,15 @@ module EE
extend ActiveSupport::Concern extend ActiveSupport::Concern
def security def security
if pipeline.expose_sast_data? if pipeline.expose_security_dashboard?
render_show
else
redirect_to pipeline_path(pipeline)
end
end
def licenses
if pipeline.expose_license_management_data?
render_show render_show
else else
redirect_to pipeline_path(pipeline) redirect_to pipeline_path(pipeline)
......
...@@ -2,6 +2,7 @@ module EE ...@@ -2,6 +2,7 @@ module EE
module GitlabRoutingHelper module GitlabRoutingHelper
include ::ProjectsHelper include ::ProjectsHelper
include ::ApplicationSettingsHelper include ::ApplicationSettingsHelper
include ::API::Helpers::RelatedResourcesHelpers
def geo_primary_web_url(project_or_wiki) def geo_primary_web_url(project_or_wiki)
File.join(::Gitlab::Geo.primary_node.url, project_or_wiki.full_path) File.join(::Gitlab::Geo.primary_node.url, project_or_wiki.full_path)
...@@ -64,5 +65,9 @@ module EE ...@@ -64,5 +65,9 @@ module EE
pipeline.license_management_artifact, pipeline.license_management_artifact,
path: Ci::Build::LICENSE_MANAGEMENT_FILE) path: Ci::Build::LICENSE_MANAGEMENT_FILE)
end end
def license_management_api_url(project)
api_v4_projects_managed_licenses_path(id: project.id)
end
end end
end end
- pipeline = local_assigns.fetch(:pipeline) - pipeline = local_assigns.fetch(:pipeline)
- project = local_assigns.fetch(:project) - project = local_assigns.fetch(:project)
- return unless pipeline.expose_security_dashboard?
- sast_endpoint = pipeline.expose_sast_data? ? sast_artifact_url(pipeline) : nil - sast_endpoint = pipeline.expose_sast_data? ? sast_artifact_url(pipeline) : nil
- dependency_scanning_endpoint = pipeline.expose_dependency_scanning_data? ? dependency_scanning_artifact_url(pipeline) : nil - dependency_scanning_endpoint = pipeline.expose_dependency_scanning_data? ? dependency_scanning_artifact_url(pipeline) : nil
- dast_endpoint = pipeline.expose_dast_data? ? dast_artifact_url(pipeline) : nil - dast_endpoint = pipeline.expose_dast_data? ? dast_artifact_url(pipeline) : nil
- sast_container_endpoint = pipeline.expose_sast_container_data? ? sast_container_artifact_url(pipeline) : pipeline.expose_container_scanning_data? ? container_scanning_artifact_url(pipeline) : nil - sast_container_endpoint = pipeline.expose_sast_container_data? ? sast_container_artifact_url(pipeline) : pipeline.expose_container_scanning_data? ? container_scanning_artifact_url(pipeline) : nil
- blob_path = project_blob_path(project, pipeline.sha) - blob_path = project_blob_path(project, pipeline.sha)
#js-tab-security.build-security.tab-pane - if pipeline.expose_security_dashboard?
#js-security-report-app{ data: { endpoint: sast_endpoint, #js-tab-security.build-security.tab-pane
blob_path: blob_path, #js-security-report-app{ data: { head_blob_path: blob_path,
dependency_scanning_endpoint: dependency_scanning_endpoint, sast_head_path: sast_endpoint,
dast_endpoint: dast_endpoint, dependency_scanning_head_path: dependency_scanning_endpoint,
sast_container_endpoint: sast_container_endpoint, dast_head_path: dast_endpoint,
sast_container_head_path: sast_container_endpoint,
pipeline_id: pipeline.id, pipeline_id: pipeline.id,
vulnerability_feedback_path: project_vulnerability_feedback_index_path(project), vulnerability_feedback_path: project_vulnerability_feedback_index_path(project),
vulnerability_feedback_help_path: help_page_path("user/project/merge_requests/index", anchor: "interacting-with-security-reports-ultimate"), vulnerability_feedback_help_path: help_page_path("user/project/merge_requests/index", anchor: "interacting-with-security-reports-ultimate"),
...@@ -22,5 +21,11 @@ ...@@ -22,5 +21,11 @@
dependency_scanning_help_path: help_page_path('user/project/merge_requests/dependency_scanning'), dependency_scanning_help_path: help_page_path('user/project/merge_requests/dependency_scanning'),
dast_help_path: help_page_path('user/project/merge_requests/dast'), dast_help_path: help_page_path('user/project/merge_requests/dast'),
sast_container_help_path: help_page_path('user/project/merge_requests/sast_container'), sast_container_help_path: help_page_path('user/project/merge_requests/sast_container'),
can_create_feedback: can?(current_user, :admin_vulnerability_feedback, project), can_create_feedback: can?(current_user, :admin_vulnerability_feedback, project).to_s,
can_create_issue: show_new_issue_link?(project)} } can_create_issue: show_new_issue_link?(project).to_s } }
- if pipeline.expose_license_management_data?
#js-tab-licenses.tab-pane
#js-licenses-app{ data: { license_head_path: pipeline.expose_license_management_data? ? license_management_artifact_url(pipeline) : nil,
api_url: license_management_api_url(project),
can_manage_licenses: can?(current_user, :admin_software_license_policy, project).to_s } }
- pipeline = local_assigns.fetch(:pipeline) - pipeline = local_assigns.fetch(:pipeline)
- project = local_assigns.fetch(:project) - project = local_assigns.fetch(:project)
- return unless pipeline.expose_security_dashboard? - if pipeline.expose_security_dashboard?
%li.js-security-tab-link
%li.js-security-tab-link
= link_to security_project_pipeline_path(project, pipeline), data: { target: '#js-tab-security', action: 'security', toggle: 'tab' }, class: 'security-tab' do = link_to security_project_pipeline_path(project, pipeline), data: { target: '#js-tab-security', action: 'security', toggle: 'tab' }, class: 'security-tab' do
= _("Security report") = _("Security")
%span.badge.badge-pill.js-sast-counter.hidden %span.badge.badge-pill.js-sast-counter.hidden
- if pipeline.expose_license_management_data?
%li.js-licenses-tab-link
= link_to licenses_project_pipeline_path(project, pipeline), data: { target: '#js-tab-licenses', action: 'licenses', toggle: 'tab' }, class: 'licenses-tab' do
= _("Licenses")
%span.badge.badge-pill.js-licenses-counter.hidden
---
title: Show License Management at pipeline level
merge_request: 6688
author:
type: added
...@@ -11,7 +11,7 @@ describe Projects::PipelinesController do ...@@ -11,7 +11,7 @@ describe Projects::PipelinesController do
end end
describe 'GET security' do describe 'GET security' do
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) } set(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) }
context 'with a sast artifact' do context 'with a sast artifact' do
before do before do
...@@ -31,7 +31,7 @@ describe Projects::PipelinesController do ...@@ -31,7 +31,7 @@ describe Projects::PipelinesController do
context 'with feature enabled' do context 'with feature enabled' do
before do before do
allow(License).to receive(:feature_available?).and_return(true) stub_licensed_features(sast: true)
get :security, namespace_id: project.namespace, project_id: project, id: pipeline get :security, namespace_id: project.namespace, project_id: project, id: pipeline
end end
...@@ -48,7 +48,6 @@ describe Projects::PipelinesController do ...@@ -48,7 +48,6 @@ describe Projects::PipelinesController do
end end
it do it do
expect(response).to have_gitlab_http_status(:redirect)
expect(response).to redirect_to(pipeline_path(pipeline)) expect(response).to redirect_to(pipeline_path(pipeline))
end end
end end
...@@ -57,13 +56,12 @@ describe Projects::PipelinesController do ...@@ -57,13 +56,12 @@ describe Projects::PipelinesController do
context 'without sast artifact' do context 'without sast artifact' do
context 'with feature enabled' do context 'with feature enabled' do
before do before do
allow(License).to receive(:feature_available?).and_return(true) stub_licensed_features(sast: true)
get :security, namespace_id: project.namespace, project_id: project, id: pipeline get :security, namespace_id: project.namespace, project_id: project, id: pipeline
end end
it do it do
expect(response).to have_gitlab_http_status(:redirect)
expect(response).to redirect_to(pipeline_path(pipeline)) expect(response).to redirect_to(pipeline_path(pipeline))
end end
end end
...@@ -74,7 +72,74 @@ describe Projects::PipelinesController do ...@@ -74,7 +72,74 @@ describe Projects::PipelinesController do
end end
it do it do
expect(response).to have_gitlab_http_status(:redirect) expect(response).to redirect_to(pipeline_path(pipeline))
end
end
end
end
describe 'GET licenses' do
set(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) }
context 'with a license management artifact' do
before do
create(
:ci_build,
:success,
:artifacts,
name: 'license_management',
pipeline: pipeline,
options: {
artifacts: {
paths: [Ci::Build::LICENSE_MANAGEMENT_FILE]
}
}
)
end
context 'with feature enabled' do
before do
stub_licensed_features(license_management: true)
get :licenses, namespace_id: project.namespace, project_id: project, id: pipeline
end
it do
expect(response).to have_gitlab_http_status(200)
expect(response).to render_template :show
end
end
context 'with feature disabled' do
before do
get :licenses, namespace_id: project.namespace, project_id: project, id: pipeline
end
it do
expect(response).to redirect_to(pipeline_path(pipeline))
end
end
end
context 'without license management artifact' do
context 'with feature enabled' do
before do
stub_licensed_features(license_management: true)
get :licenses, namespace_id: project.namespace, project_id: project, id: pipeline
end
it do
expect(response).to redirect_to(pipeline_path(pipeline))
end
end
context 'with feature disabled' do
before do
get :licenses, namespace_id: project.namespace, project_id: project, id: pipeline
end
it do
expect(response).to redirect_to(pipeline_path(pipeline)) expect(response).to redirect_to(pipeline_path(pipeline))
end end
end end
......
...@@ -7,13 +7,15 @@ describe 'Pipeline', :js do ...@@ -7,13 +7,15 @@ describe 'Pipeline', :js do
before do before do
sign_in(user) sign_in(user)
project.add_developer(user) project.add_developer(user)
allow(License).to receive(:feature_available?).and_return(true)
end end
describe 'GET /:project/pipelines/:id/security' do describe 'GET /:project/pipelines/:id/security' do
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) } let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) }
before do
stub_licensed_features(sast: true)
end
context 'with a sast artifact' do context 'with a sast artifact' do
before do before do
create( create(
...@@ -33,7 +35,7 @@ describe 'Pipeline', :js do ...@@ -33,7 +35,7 @@ describe 'Pipeline', :js do
end end
it 'shows jobs tab pane as active' do it 'shows jobs tab pane as active' do
expect(page).to have_content('Security report') expect(page).to have_content('Security')
expect(page).to have_css('#js-tab-security') expect(page).to have_css('#js-tab-security')
end end
...@@ -49,7 +51,56 @@ describe 'Pipeline', :js do ...@@ -49,7 +51,56 @@ describe 'Pipeline', :js do
it 'displays the pipeline graph' do it 'displays the pipeline graph' do
expect(current_path).to eq(pipeline_path(pipeline)) expect(current_path).to eq(pipeline_path(pipeline))
expect(page).not_to have_content('Security report') expect(page).not_to have_content('Security')
expect(page).to have_selector('.pipeline-visualization')
end
end
end
describe 'GET /:project/pipelines/:id/licenses' do
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) }
before do
stub_licensed_features(license_management: true)
end
context 'with a license management artifact' do
before do
create(
:ci_build,
:success,
:artifacts,
name: 'license_management',
pipeline: pipeline,
options: {
artifacts: {
paths: [Ci::Build::LICENSE_MANAGEMENT_FILE]
}
}
)
visit licenses_project_pipeline_path(project, pipeline)
end
it 'shows jobs tab pane as active' do
expect(page).to have_content('Licenses')
expect(page).to have_css('#js-tab-licenses')
expect(find('.js-licenses-counter')).to have_content('0')
end
it 'shows security report section' do
expect(page).to have_content('Loading license management report')
end
end
context 'without license management artifact' do
before do
visit licenses_project_pipeline_path(project, pipeline)
end
it 'displays the pipeline graph' do
expect(current_path).to eq(pipeline_path(pipeline))
expect(page).not_to have_content('Licenses')
expect(page).to have_selector('.pipeline-visualization') expect(page).to have_selector('.pipeline-visualization')
end end
end end
......
...@@ -3934,6 +3934,9 @@ msgstr "" ...@@ -3934,6 +3934,9 @@ msgstr ""
msgid "LicenseManagement|You are about to remove the license, %{name}, from this project." msgid "LicenseManagement|You are about to remove the license, %{name}, from this project."
msgstr "" msgstr ""
msgid "Licenses"
msgstr ""
msgid "LinkedIn" msgid "LinkedIn"
msgstr "" msgstr ""
...@@ -5645,10 +5648,10 @@ msgstr "" ...@@ -5645,10 +5648,10 @@ msgstr ""
msgid "Secret:" msgid "Secret:"
msgstr "" msgstr ""
msgid "Security Dashboard" msgid "Security"
msgstr "" msgstr ""
msgid "Security report" msgid "Security Dashboard"
msgstr "" msgstr ""
msgid "SecurityDashboard|Monitor vulnerabilities in your code" msgid "SecurityDashboard|Monitor vulnerabilities in your code"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment