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
This commit is contained in:
commit
6811f1aca5
5 changed files with 316 additions and 49 deletions
|
@ -1,5 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import _ from 'underscore';
|
import _ from 'underscore';
|
||||||
|
import { GlLink } from '@gitlab/ui';
|
||||||
import CiIcon from '~/vue_shared/components/ci_icon.vue';
|
import CiIcon from '~/vue_shared/components/ci_icon.vue';
|
||||||
import Icon from '~/vue_shared/components/icon.vue';
|
import Icon from '~/vue_shared/components/icon.vue';
|
||||||
|
|
||||||
|
@ -7,6 +8,7 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
CiIcon,
|
CiIcon,
|
||||||
Icon,
|
Icon,
|
||||||
|
GlLink,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
pipeline: {
|
pipeline: {
|
||||||
|
@ -26,6 +28,12 @@ export default {
|
||||||
hasRef() {
|
hasRef() {
|
||||||
return !_.isEmpty(this.pipeline.ref);
|
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: {
|
methods: {
|
||||||
onStageClick(stage) {
|
onStageClick(stage) {
|
||||||
|
@ -36,16 +44,41 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="block-last dropdown">
|
<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>
|
<span class="font-weight-bold">{{ s__('Job|Pipeline') }}</span>
|
||||||
<a :href="pipeline.path" class="js-pipeline-path link-commit qa-pipeline-path"
|
<gl-link :href="pipeline.path" class="js-pipeline-path link-commit qa-pipeline-path"
|
||||||
>#{{ pipeline.id }}</a
|
>#{{ pipeline.id }}</gl-link
|
||||||
>
|
>
|
||||||
<template v-if="hasRef">
|
<template v-if="hasRef">
|
||||||
{{ __('from') }}
|
{{ s__('Job|for') }}
|
||||||
<a :href="pipeline.ref.path" class="link-commit ref-name">{{ pipeline.ref.name }}</a>
|
|
||||||
</template>
|
<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
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
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"
|
msgid "Job|Keep"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Job|Pipeline"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Job|Scroll to bottom"
|
msgid "Job|Scroll to bottom"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -4457,6 +4460,15 @@ msgstr ""
|
||||||
msgid "Job|This job is stuck because the project doesn't have any runners online assigned to it."
|
msgid "Job|This job is stuck because the project doesn't have any runners online assigned to it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Job|for"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Job|into"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Job|with"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Jul"
|
msgid "Jul"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@ require 'spec_helper'
|
||||||
require 'tempfile'
|
require 'tempfile'
|
||||||
|
|
||||||
describe 'Jobs', :clean_gitlab_redis_shared_state do
|
describe 'Jobs', :clean_gitlab_redis_shared_state do
|
||||||
|
include Gitlab::Routing
|
||||||
|
include ProjectForksHelper
|
||||||
|
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:user_access_level) { :developer }
|
let(:user_access_level) { :developer }
|
||||||
let(:project) { create(:project, :repository) }
|
let(:project) { create(:project, :repository) }
|
||||||
|
@ -121,6 +124,112 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
|
||||||
end
|
end
|
||||||
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
|
context 'sidebar', :js do
|
||||||
let(:job) { create(:ci_build, :success, :trace_live, pipeline: pipeline, name: '<img src=x onerror=alert(document.domain)>') }
|
let(:job) { create(:ci_build, :success, :trace_live, pipeline: pipeline, name: '<img src=x onerror=alert(document.domain)>') }
|
||||||
|
|
||||||
|
|
|
@ -1,59 +1,167 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import component from '~/jobs/components/stages_dropdown.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';
|
import mountComponent from '../../helpers/vue_mount_component_helper';
|
||||||
|
|
||||||
describe('Stages Dropdown', () => {
|
describe('Stages Dropdown', () => {
|
||||||
const Component = Vue.extend(component);
|
const Component = Vue.extend(component);
|
||||||
let vm;
|
let vm;
|
||||||
|
|
||||||
beforeEach(() => {
|
const mockPipelineData = {
|
||||||
vm = mountComponent(Component, {
|
id: 28029444,
|
||||||
pipeline: {
|
details: {
|
||||||
id: 28029444,
|
status: {
|
||||||
details: {
|
details_path: '/gitlab-org/gitlab-ce/pipelines/28029444',
|
||||||
status: {
|
group: 'success',
|
||||||
details_path: '/gitlab-org/gitlab-ce/pipelines/28029444',
|
has_details: true,
|
||||||
group: 'success',
|
icon: 'status_success',
|
||||||
has_details: true,
|
label: 'passed',
|
||||||
icon: 'status_success',
|
text: 'passed',
|
||||||
label: 'passed',
|
tooltip: 'passed',
|
||||||
text: 'passed',
|
|
||||||
tooltip: 'passed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
path: 'pipeline/28029444',
|
|
||||||
},
|
},
|
||||||
stages: [
|
},
|
||||||
{
|
path: 'pipeline/28029444',
|
||||||
name: 'build',
|
flags: {
|
||||||
},
|
merge_request_pipeline: true,
|
||||||
{
|
detached_merge_request_pipeline: false,
|
||||||
name: 'test',
|
},
|
||||||
},
|
merge_request: {
|
||||||
],
|
iid: 1234,
|
||||||
selectedStage: 'deploy',
|
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();
|
||||||
|
});
|
||||||
|
|
||||||
|
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 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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
describe('with an "attached" merge request pipeline', () => {
|
||||||
vm.$destroy();
|
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('renders pipeline status', () => {
|
describe('with a detached merge request pipeline', () => {
|
||||||
expect(vm.$el.querySelector('.js-ci-status-icon-success')).not.toBeNull();
|
let pipeline;
|
||||||
});
|
|
||||||
|
|
||||||
it('renders pipeline link', () => {
|
beforeEach(() => {
|
||||||
expect(vm.$el.querySelector('.js-pipeline-path').getAttribute('href')).toEqual(
|
pipeline = JSON.parse(JSON.stringify(mockPipelineData));
|
||||||
'pipeline/28029444',
|
pipeline.flags.merge_request_pipeline = false;
|
||||||
);
|
pipeline.flags.detached_merge_request_pipeline = true;
|
||||||
});
|
|
||||||
|
|
||||||
it('renders dropdown with stages', () => {
|
vm = mountComponent(Component, {
|
||||||
expect(vm.$el.querySelector('.dropdown .js-stage-item').textContent).toContain('build');
|
pipeline,
|
||||||
});
|
stages: [],
|
||||||
|
selectedStage: 'deploy',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('rendes selected stage', () => {
|
it(`renders the pipeline info like "Pipeline #123 for !456 with source_branch"`, () => {
|
||||||
expect(vm.$el.querySelector('.dropdown .js-selected-stage').textContent).toContain('deploy');
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue