Commit 6811f1ac authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'nfriend-update-job-detail-view-sidebar' into 'master'

Update job detail view sidebar to accommodate post-merge pipelines

See merge request gitlab-org/gitlab-ce!25777
parents a8bb2c12 6fe0739b
<script>
import _ from 'underscore';
import { GlLink } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Icon from '~/vue_shared/components/icon.vue';
......@@ -7,6 +8,7 @@ export default {
components: {
CiIcon,
Icon,
GlLink,
},
props: {
pipeline: {
......@@ -26,6 +28,12 @@ export default {
hasRef() {
return !_.isEmpty(this.pipeline.ref);
},
isTriggeredByMergeRequest() {
return Boolean(this.pipeline.merge_request);
},
isMergeRequestPipeline() {
return Boolean(this.pipeline.flags && this.pipeline.flags.merge_request_pipeline);
},
},
methods: {
onStageClick(stage) {
......@@ -36,16 +44,41 @@ export default {
</script>
<template>
<div class="block-last dropdown">
<ci-icon :status="pipeline.details.status" class="vertical-align-middle" />
<div class="js-pipeline-info">
<ci-icon :status="pipeline.details.status" class="vertical-align-middle" />
<span class="font-weight-bold">{{ __('Pipeline') }}</span>
<a :href="pipeline.path" class="js-pipeline-path link-commit qa-pipeline-path"
>#{{ pipeline.id }}</a
>
<template v-if="hasRef">
{{ __('from') }}
<a :href="pipeline.ref.path" class="link-commit ref-name">{{ pipeline.ref.name }}</a>
</template>
<span class="font-weight-bold">{{ s__('Job|Pipeline') }}</span>
<gl-link :href="pipeline.path" class="js-pipeline-path link-commit qa-pipeline-path"
>#{{ pipeline.id }}</gl-link
>
<template v-if="hasRef">
{{ s__('Job|for') }}
<template v-if="isTriggeredByMergeRequest">
<gl-link :href="pipeline.merge_request.path" class="link-commit ref-name js-mr-link"
>!{{ pipeline.merge_request.iid }}</gl-link
>
{{ s__('Job|with') }}
<gl-link
:href="pipeline.merge_request.source_branch_path"
class="link-commit ref-name js-source-branch-link"
>{{ pipeline.merge_request.source_branch }}</gl-link
>
<template v-if="isMergeRequestPipeline">
{{ s__('Job|into') }}
<gl-link
:href="pipeline.merge_request.target_branch_path"
class="link-commit ref-name js-target-branch-link"
>{{ pipeline.merge_request.target_branch }}</gl-link
>
</template>
</template>
<gl-link v-else :href="pipeline.ref.path" class="link-commit ref-name">{{
pipeline.ref.name
}}</gl-link>
</template>
</div>
<button
type="button"
......
---
title: Update job detail sidebar to accommodate post-merge pipeline information
merge_request: 25777
author:
type: added
......@@ -4439,6 +4439,9 @@ msgstr ""
msgid "Job|Keep"
msgstr ""
msgid "Job|Pipeline"
msgstr ""
msgid "Job|Scroll to bottom"
msgstr ""
......@@ -4457,6 +4460,15 @@ msgstr ""
msgid "Job|This job is stuck because the project doesn't have any runners online assigned to it."
msgstr ""
msgid "Job|for"
msgstr ""
msgid "Job|into"
msgstr ""
msgid "Job|with"
msgstr ""
msgid "Jul"
msgstr ""
......
......@@ -2,6 +2,9 @@ require 'spec_helper'
require 'tempfile'
describe 'Jobs', :clean_gitlab_redis_shared_state do
include Gitlab::Routing
include ProjectForksHelper
let(:user) { create(:user) }
let(:user_access_level) { :developer }
let(:project) { create(:project, :repository) }
......@@ -121,6 +124,112 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end
end
context 'pipeline info block', :js do
it 'shows pipeline id and source branch' do
visit project_job_path(project, job)
within '.js-pipeline-info' do
expect(page).to have_content("Pipeline ##{pipeline.id} for #{pipeline.ref}")
end
end
context 'when pipeline is detached merge request pipeline' do
let(:merge_request) do
create(:merge_request,
:with_detached_merge_request_pipeline,
target_project: target_project,
source_project: source_project)
end
let(:source_project) { project }
let(:target_project) { project }
let(:pipeline) { merge_request.all_pipelines.last }
let(:job) { create(:ci_build, pipeline: pipeline) }
it 'shows merge request iid and source branch' do
visit project_job_path(project, job)
within '.js-pipeline-info' do
expect(page).to have_content("for !#{pipeline.merge_request.iid} " \
"with #{pipeline.merge_request.source_branch}")
expect(page).to have_link("!#{pipeline.merge_request.iid}",
href: project_merge_request_path(project, merge_request))
expect(page).to have_link(pipeline.merge_request.source_branch,
href: project_commits_path(project, merge_request.source_branch))
end
end
context 'when source project is a forked project' do
let(:source_project) { fork_project(project, user, repository: true) }
let(:target_project) { project }
it 'shows merge request iid and source branch' do
visit project_job_path(source_project, job)
within '.js-pipeline-info' do
expect(page).to have_content("for !#{pipeline.merge_request.iid} " \
"with #{pipeline.merge_request.source_branch}")
expect(page).to have_link("!#{pipeline.merge_request.iid}",
href: project_merge_request_path(project, merge_request))
expect(page).to have_link(pipeline.merge_request.source_branch,
href: project_commits_path(source_project, merge_request.source_branch))
end
end
end
end
context 'when pipeline is merge request pipeline' do
let(:merge_request) do
create(:merge_request,
:with_merge_request_pipeline,
target_project: target_project,
source_project: source_project)
end
let(:source_project) { project }
let(:target_project) { project }
let(:pipeline) { merge_request.all_pipelines.last }
let(:job) { create(:ci_build, pipeline: pipeline) }
it 'shows merge request iid and source branch' do
visit project_job_path(project, job)
within '.js-pipeline-info' do
expect(page).to have_content("for !#{pipeline.merge_request.iid} " \
"with #{pipeline.merge_request.source_branch} " \
"into #{pipeline.merge_request.target_branch}")
expect(page).to have_link("!#{pipeline.merge_request.iid}",
href: project_merge_request_path(project, merge_request))
expect(page).to have_link(pipeline.merge_request.source_branch,
href: project_commits_path(project, merge_request.source_branch))
expect(page).to have_link(pipeline.merge_request.target_branch,
href: project_commits_path(project, merge_request.target_branch))
end
end
context 'when source project is a forked project' do
let(:source_project) { fork_project(project, user, repository: true) }
let(:target_project) { project }
it 'shows merge request iid and source branch' do
visit project_job_path(source_project, job)
within '.js-pipeline-info' do
expect(page).to have_content("for !#{pipeline.merge_request.iid} " \
"with #{pipeline.merge_request.source_branch} " \
"into #{pipeline.merge_request.target_branch}")
expect(page).to have_link("!#{pipeline.merge_request.iid}",
href: project_merge_request_path(project, merge_request))
expect(page).to have_link(pipeline.merge_request.source_branch,
href: project_commits_path(source_project, merge_request.source_branch))
expect(page).to have_link(pipeline.merge_request.target_branch,
href: project_commits_path(project, merge_request.target_branch))
end
end
end
end
end
context 'sidebar', :js do
let(:job) { create(:ci_build, :success, :trace_live, pipeline: pipeline, name: '<img src=x onerror=alert(document.domain)>') }
......
import Vue from 'vue';
import component from '~/jobs/components/stages_dropdown.vue';
import { trimText } from 'spec/helpers/vue_component_helper';
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('Stages Dropdown', () => {
const Component = Vue.extend(component);
let vm;
beforeEach(() => {
vm = mountComponent(Component, {
pipeline: {
id: 28029444,
details: {
status: {
details_path: '/gitlab-org/gitlab-ce/pipelines/28029444',
group: 'success',
has_details: true,
icon: 'status_success',
label: 'passed',
text: 'passed',
tooltip: 'passed',
},
},
path: 'pipeline/28029444',
const mockPipelineData = {
id: 28029444,
details: {
status: {
details_path: '/gitlab-org/gitlab-ce/pipelines/28029444',
group: 'success',
has_details: true,
icon: 'status_success',
label: 'passed',
text: 'passed',
tooltip: 'passed',
},
stages: [
{
name: 'build',
},
{
name: 'test',
},
],
selectedStage: 'deploy',
},
path: 'pipeline/28029444',
flags: {
merge_request_pipeline: true,
detached_merge_request_pipeline: false,
},
merge_request: {
iid: 1234,
path: '/root/detached-merge-request-pipelines/merge_requests/1',
title: 'Update README.md',
source_branch: 'feature-1234',
source_branch_path: '/root/detached-merge-request-pipelines/branches/feature-1234',
target_branch: 'master',
target_branch_path: '/root/detached-merge-request-pipelines/branches/master',
},
ref: {
name: 'test-branch',
},
};
describe('without a merge request pipeline', () => {
let pipeline;
beforeEach(() => {
pipeline = JSON.parse(JSON.stringify(mockPipelineData));
delete pipeline.merge_request;
delete pipeline.flags.merge_request_pipeline;
delete pipeline.flags.detached_merge_request_pipeline;
vm = mountComponent(Component, {
pipeline,
stages: [{ name: 'build' }, { name: 'test' }],
selectedStage: 'deploy',
});
});
});
afterEach(() => {
vm.$destroy();
});
afterEach(() => {
vm.$destroy();
});
it('renders pipeline status', () => {
expect(vm.$el.querySelector('.js-ci-status-icon-success')).not.toBeNull();
});
it('renders pipeline status', () => {
expect(vm.$el.querySelector('.js-ci-status-icon-success')).not.toBeNull();
});
it('renders pipeline link', () => {
expect(vm.$el.querySelector('.js-pipeline-path').getAttribute('href')).toEqual(
'pipeline/28029444',
);
});
it('renders dropdown with stages', () => {
expect(vm.$el.querySelector('.dropdown .js-stage-item').textContent).toContain('build');
});
it('rendes selected stage', () => {
expect(vm.$el.querySelector('.dropdown .js-selected-stage').textContent).toContain('deploy');
});
it('renders pipeline link', () => {
expect(vm.$el.querySelector('.js-pipeline-path').getAttribute('href')).toEqual(
'pipeline/28029444',
);
it(`renders the pipeline info text like "Pipeline #123 for source_branch"`, () => {
const expected = `Pipeline #${pipeline.id} for ${pipeline.ref.name}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info').innerText);
expect(actual).toBe(expected);
});
});
it('renders dropdown with stages', () => {
expect(vm.$el.querySelector('.dropdown .js-stage-item').textContent).toContain('build');
describe('with an "attached" merge request pipeline', () => {
let pipeline;
beforeEach(() => {
pipeline = JSON.parse(JSON.stringify(mockPipelineData));
pipeline.flags.merge_request_pipeline = true;
pipeline.flags.detached_merge_request_pipeline = false;
vm = mountComponent(Component, {
pipeline,
stages: [],
selectedStage: 'deploy',
});
});
it(`renders the pipeline info text like "Pipeline #123 for !456 with source_branch into target_branch"`, () => {
const expected = `Pipeline #${pipeline.id} for !${pipeline.merge_request.iid} with ${
pipeline.merge_request.source_branch
} into ${pipeline.merge_request.target_branch}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info').innerText);
expect(actual).toBe(expected);
});
it(`renders the correct merge request link`, () => {
const actual = vm.$el.querySelector('.js-mr-link').href;
expect(actual).toContain(pipeline.merge_request.path);
});
it(`renders the correct source branch link`, () => {
const actual = vm.$el.querySelector('.js-source-branch-link').href;
expect(actual).toContain(pipeline.merge_request.source_branch_path);
});
it(`renders the correct target branch link`, () => {
const actual = vm.$el.querySelector('.js-target-branch-link').href;
expect(actual).toContain(pipeline.merge_request.target_branch_path);
});
});
it('rendes selected stage', () => {
expect(vm.$el.querySelector('.dropdown .js-selected-stage').textContent).toContain('deploy');
describe('with a detached merge request pipeline', () => {
let pipeline;
beforeEach(() => {
pipeline = JSON.parse(JSON.stringify(mockPipelineData));
pipeline.flags.merge_request_pipeline = false;
pipeline.flags.detached_merge_request_pipeline = true;
vm = mountComponent(Component, {
pipeline,
stages: [],
selectedStage: 'deploy',
});
});
it(`renders the pipeline info like "Pipeline #123 for !456 with source_branch"`, () => {
const expected = `Pipeline #${pipeline.id} for !${pipeline.merge_request.iid} with ${
pipeline.merge_request.source_branch
}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info').innerText);
expect(actual).toBe(expected);
});
it(`renders the correct merge request link`, () => {
const actual = vm.$el.querySelector('.js-mr-link').href;
expect(actual).toContain(pipeline.merge_request.path);
});
it(`renders the correct source branch link`, () => {
const actual = vm.$el.querySelector('.js-source-branch-link').href;
expect(actual).toContain(pipeline.merge_request.source_branch_path);
});
});
});
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