Add Pipeline IID to views

* Add Pipeline IID to MR's
* Add Pipeline IID to commit box
* Add Pipeline IID to builds page
* Add Pipeline IID to job sidebar
* Add Pipeline IID to header on view pipeline pages
* Add changelog entry
* Update tests
This commit is contained in:
Mike Scott 2019-05-30 09:32:20 +00:00 committed by Filipa Lacerda
parent 847fd2a5c1
commit 852738a498
25 changed files with 150 additions and 54 deletions

View File

@ -2,6 +2,7 @@
import _ from 'underscore';
import { GlLink } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import PipelineLink from '~/vue_shared/components/ci_pipeline_link.vue';
import Icon from '~/vue_shared/components/icon.vue';
export default {
@ -9,6 +10,7 @@ export default {
CiIcon,
Icon,
GlLink,
PipelineLink,
},
props: {
pipeline: {
@ -48,9 +50,12 @@ export default {
<ci-icon :status="pipeline.details.status" class="vertical-align-middle" />
<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
>
<pipeline-link
:href="pipeline.path"
:pipeline-id="pipeline.id"
:pipeline-iid="pipeline.iid"
class="js-pipeline-path link-commit qa-pipeline-path"
/>
<template v-if="hasRef">
{{ s__('Job|for') }}

View File

@ -83,6 +83,8 @@ export default {
v-if="shouldRenderContent"
:status="status"
:item-id="pipeline.id"
:item-iid="pipeline.iid"
:item-id-tooltip="__('Pipeline ID (IID)')"
:time="pipeline.created_at"
:user="pipeline.user"
:actions="actions"

View File

@ -2,6 +2,7 @@
import { GlLink, GlTooltipDirective } from '@gitlab/ui';
import _ from 'underscore';
import { __, sprintf } from '~/locale';
import PipelineLink from '~/vue_shared/components/ci_pipeline_link.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import popover from '~/vue_shared/directives/popover';
@ -19,6 +20,7 @@ export default {
components: {
UserAvatarLink,
GlLink,
PipelineLink,
},
directives: {
GlTooltip: GlTooltipDirective,
@ -59,10 +61,13 @@ export default {
};
</script>
<template>
<div class="table-section section-10 d-none d-sm-none d-md-block pipeline-tags">
<gl-link :href="pipeline.path" class="js-pipeline-url-link">
<span class="pipeline-id">#{{ pipeline.id }}</span>
</gl-link>
<div class="table-section section-10 d-none d-sm-none d-md-block pipeline-tags section-wrap">
<pipeline-link
:href="pipeline.path"
:pipeline-id="pipeline.id"
:pipeline-iid="pipeline.iid"
class="js-pipeline-url-link"
/>
<div class="label-container">
<span
v-if="pipeline.flags.latest"

View File

@ -5,6 +5,7 @@ import { sprintf, __ } from '~/locale';
import PipelineStage from '~/pipelines/components/stage.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Icon from '~/vue_shared/components/icon.vue';
import PipelineLink from '~/vue_shared/components/ci_pipeline_link.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
import mrWidgetPipelineMixin from 'ee_else_ce/vue_merge_request_widget/mixins/mr_widget_pipeline';
@ -16,6 +17,7 @@ export default {
Icon,
TooltipOnTruncate,
GlLink,
PipelineLink,
LinkedPipelinesMiniList: () =>
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
},
@ -112,9 +114,12 @@ export default {
<div class="media-body">
<div class="font-weight-bold js-pipeline-info-container">
{{ s__('Pipeline|Pipeline') }}
<gl-link :href="pipeline.path" class="pipeline-id font-weight-normal pipeline-number"
>#{{ pipeline.id }}</gl-link
>
<pipeline-link
:href="pipeline.path"
:pipeline-id="pipeline.id"
:pipeline-iid="pipeline.iid"
class="pipeline-id pipeline-iid font-weight-normal"
/>
{{ pipeline.details.status.label }}
<template v-if="hasCommitInfo">
{{ s__('Pipeline|for') }}

View File

@ -0,0 +1,32 @@
<script>
import { GlLink, GlTooltipDirective } from '@gitlab/ui';
export default {
components: {
GlLink,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
href: {
type: String,
required: true,
},
pipelineId: {
type: Number,
required: true,
},
pipelineIid: {
type: Number,
required: true,
},
},
};
</script>
<template>
<gl-link v-gl-tooltip :href="href" :title="__('Pipeline ID (IID)')">
<span class="pipeline-id">#{{ pipelineId }}</span>
<span class="pipeline-iid">(#{{ pipelineIid }})</span>
</gl-link>
</template>

View File

@ -37,6 +37,16 @@ export default {
type: Number,
required: true,
},
itemIid: {
type: Number,
required: false,
default: null,
},
itemIdTooltip: {
type: String,
required: false,
default: '',
},
time: {
type: String,
required: true,
@ -85,7 +95,12 @@ export default {
<section class="header-main-content">
<ci-icon-badge :status="status" />
<strong> {{ itemName }} #{{ itemId }} </strong>
<strong v-gl-tooltip :title="itemIdTooltip">
{{ itemName }} #{{ itemId }}
<template v-if="itemIid"
>(#{{ itemIid }})</template
>
</strong>
<template v-if="shouldRenderTriggeredLabel">
triggered
@ -96,9 +111,8 @@ export default {
<timeago-tooltip :time="time" />
by
<template v-if="user">
by
<gl-link
v-gl-tooltip
:href="user.path"

View File

@ -4,6 +4,7 @@ class PipelineEntity < Grape::Entity
include RequestAwareEntity
expose :id
expose :iid
expose :user, using: UserEntity
expose :active?, as: :active

View File

@ -53,9 +53,10 @@
%span.badge.badge-info= _('manual')
- if pipeline_link
%td
= link_to pipeline_path(pipeline) do
%td.pipeline-link
= link_to pipeline_path(pipeline), class: 'has-tooltip', title: _('Pipeline ID (IID)') do
%span.pipeline-id ##{pipeline.id}
%span.pipeline-iid (##{pipeline.iid})
%span by
- if pipeline.user
= user_avatar(user: pipeline.user, size: 20)

View File

@ -81,7 +81,7 @@
= link_to project_pipeline_path(@project, last_pipeline.id), class: "ci-status-icon-#{last_pipeline.status}" do
= ci_icon_for_status(last_pipeline.status)
#{ _('Pipeline') }
= link_to "##{last_pipeline.id}", project_pipeline_path(@project, last_pipeline.id)
= link_to "##{last_pipeline.id} (##{last_pipeline.iid})", project_pipeline_path(@project, last_pipeline.id), class: "has-tooltip", title: _('Pipeline ID (IID)')
= ci_label_for_status(last_pipeline.status)
- if last_pipeline.stages_count.nonzero?
#{ n_(s_('Pipeline|with stage'), s_('Pipeline|with stages'), last_pipeline.stages_count) }

View File

@ -0,0 +1,5 @@
---
title: Show Pipeline IID everywhere Pipeline ID is shown
merge_request: 57414
author: Mike Scott
type: added

View File

@ -6886,6 +6886,9 @@ msgstr ""
msgid "Pipeline"
msgstr ""
msgid "Pipeline ID (IID)"
msgstr ""
msgid "Pipeline Schedule"
msgstr ""

View File

@ -52,7 +52,7 @@ describe 'Merge request > User merges when pipeline succeeds', :js do
# so we have to wait for asynchronous call to reload it
# and have_content expectation handles that.
#
expect(page).to have_content "Pipeline ##{pipeline.id} running"
expect(page).to have_content "Pipeline ##{pipeline.id} (##{pipeline.iid}) running"
end
it_behaves_like 'Merge when pipeline succeeds activator'

View File

@ -160,7 +160,7 @@ describe 'Merge request > User sees merge widget', :js do
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Pipeline ##{pipeline.id} pending " \
expect(page).to have_content("Pipeline ##{pipeline.id} (##{pipeline.iid}) pending " \
"for #{pipeline.short_sha} " \
"on #{pipeline.ref}")
end
@ -189,7 +189,7 @@ describe 'Merge request > User sees merge widget', :js do
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Pipeline ##{pipeline.id} pending " \
expect(page).to have_content("Pipeline ##{pipeline.id} (##{pipeline.iid}) pending " \
"for #{pipeline.short_sha} " \
"on #{merge_request.to_reference} " \
"with #{merge_request.source_branch}")
@ -201,7 +201,7 @@ describe 'Merge request > User sees merge widget', :js do
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Pipeline ##{pipeline.id} pending " \
expect(page).to have_content("Pipeline ##{pipeline.id} (##{pipeline.iid}) pending " \
"for #{pipeline.short_sha} " \
"on #{merge_request.to_reference} " \
"with #{merge_request.source_branch}")
@ -234,7 +234,7 @@ describe 'Merge request > User sees merge widget', :js do
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Pipeline ##{pipeline.id} pending " \
expect(page).to have_content("Pipeline ##{pipeline.id} (##{pipeline.iid}) pending " \
"for #{pipeline.short_sha} " \
"on #{merge_request.to_reference} " \
"with #{merge_request.source_branch} " \
@ -248,7 +248,7 @@ describe 'Merge request > User sees merge widget', :js do
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Pipeline ##{pipeline.id} pending " \
expect(page).to have_content("Pipeline ##{pipeline.id} (##{pipeline.iid}) pending " \
"for #{pipeline.short_sha} " \
"on #{merge_request.to_reference} " \
"with #{merge_request.source_branch} " \

View File

@ -61,7 +61,7 @@ describe 'User browses commits' do
it 'renders commit ci info' do
visit project_commit_path(project, sample_commit.id)
expect(page).to have_content "Pipeline ##{pipeline.id} pending"
expect(page).to have_content "Pipeline ##{pipeline.id} (##{pipeline.iid}) pending"
end
end

View File

@ -16,6 +16,12 @@ describe 'User browses jobs' do
visit(project_jobs_path(project))
end
it 'shows pipeline id and IID' do
page.within('td.pipeline-link') do
expect(page).to have_content("##{pipeline.id} (##{pipeline.iid})")
end
end
it 'shows the coverage' do
page.within('td.coverage') do
expect(page).to have_content('99.9%')

View File

@ -129,7 +129,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
visit project_job_path(project, job)
within '.js-pipeline-info' do
expect(page).to have_content("Pipeline ##{pipeline.id} for #{pipeline.ref}")
expect(page).to have_content("Pipeline ##{pipeline.id} (##{pipeline.iid}) for #{pipeline.ref}")
end
end

View File

@ -9,6 +9,7 @@ describe('Stages Dropdown', () => {
const mockPipelineData = {
id: 28029444,
iid: 123,
details: {
status: {
details_path: '/gitlab-org/gitlab-ce/pipelines/28029444',
@ -77,8 +78,8 @@ describe('Stages Dropdown', () => {
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}`;
it(`renders the pipeline info text like "Pipeline #123 (#12) for source_branch"`, () => {
const expected = `Pipeline #${pipeline.id} (#${pipeline.iid}) for ${pipeline.ref.name}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info').innerText);
expect(actual).toBe(expected);
@ -100,10 +101,10 @@ describe('Stages Dropdown', () => {
});
});
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}`;
it(`renders the pipeline info text like "Pipeline #123 (#12) for !456 with source_branch into target_branch"`, () => {
const expected = `Pipeline #${pipeline.id} (#${pipeline.iid}) 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);
@ -143,10 +144,10 @@ describe('Stages Dropdown', () => {
});
});
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
}`;
it(`renders the pipeline info like "Pipeline #123 (#12) for !456 with source_branch"`, () => {
const expected = `Pipeline #${pipeline.id} (#${pipeline.iid}) 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);

View File

@ -960,6 +960,7 @@ export default {
},
pipeline: {
id: 140,
iid: 13,
user: {
name: 'Root',
username: 'root',

View File

@ -1,5 +1,6 @@
export const pipelineWithStages = {
id: 20333396,
iid: 304399,
user: {
id: 128633,
name: 'Rémy Coutable',

View File

@ -13,6 +13,7 @@ describe('Pipeline Url Component', () => {
propsData: {
pipeline: {
id: 1,
iid: 1,
path: 'foo',
flags: {},
},
@ -28,6 +29,7 @@ describe('Pipeline Url Component', () => {
propsData: {
pipeline: {
id: 1,
iid: 1,
path: 'foo',
flags: {},
},
@ -47,6 +49,7 @@ describe('Pipeline Url Component', () => {
propsData: {
pipeline: {
id: 1,
iid: 1,
path: 'foo',
flags: {
latest: true,
@ -78,6 +81,7 @@ describe('Pipeline Url Component', () => {
propsData: {
pipeline: {
id: 1,
iid: 1,
path: 'foo',
flags: {
latest: true,
@ -100,6 +104,7 @@ describe('Pipeline Url Component', () => {
propsData: {
pipeline: {
id: 1,
iid: 1,
path: 'foo',
flags: {
failure_reason: true,

View File

@ -103,7 +103,7 @@ describe('MRWidgetPipeline', () => {
it('should render pipeline ID', () => {
expect(vm.$el.querySelector('.pipeline-id').textContent.trim()).toEqual(
`#${mockData.pipeline.id}`,
`#${mockData.pipeline.id} (#${mockData.pipeline.iid})`,
);
});
@ -150,7 +150,7 @@ describe('MRWidgetPipeline', () => {
it('should render pipeline ID', () => {
expect(vm.$el.querySelector('.pipeline-id').textContent.trim()).toEqual(
`#${mockData.pipeline.id}`,
`#${mockData.pipeline.id} (#${mockData.pipeline.iid})`,
);
});
@ -222,9 +222,9 @@ describe('MRWidgetPipeline', () => {
sourceBranchLink: mockCopy.source_branch_link,
});
const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${
pipeline.commit.short_id
} on ${mockCopy.source_branch_link}`;
const expected = `Pipeline #${pipeline.id} (#${pipeline.iid}) ${
pipeline.details.status.label
} for ${pipeline.commit.short_id} on ${mockCopy.source_branch_link}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
@ -247,11 +247,11 @@ describe('MRWidgetPipeline', () => {
sourceBranchLink: mockCopy.source_branch_link,
});
const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${
pipeline.commit.short_id
} on !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch} into ${
pipeline.merge_request.target_branch
}`;
const expected = `Pipeline #${pipeline.id} (#${pipeline.iid}) ${
pipeline.details.status.label
} for ${pipeline.commit.short_id} on !${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-container').innerText);
@ -274,9 +274,11 @@ describe('MRWidgetPipeline', () => {
sourceBranchLink: mockCopy.source_branch_link,
});
const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${
pipeline.commit.short_id
} on !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch}`;
const expected = `Pipeline #${pipeline.id} (#${pipeline.iid}) ${
pipeline.details.status.label
} for ${pipeline.commit.short_id} on !${pipeline.merge_request.iid} with ${
pipeline.merge_request.source_branch
}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);

View File

@ -62,6 +62,7 @@ export default {
"Merge branch 'daaaa' into 'master'\n\nUpdate README.md\n\nSee merge request !22",
pipeline: {
id: 172,
iid: 32,
user: {
name: 'Administrator',
username: 'root',
@ -241,6 +242,8 @@ export default {
export const mockStore = {
pipeline: {
id: 0,
iid: 0,
path: '/root/acets-app/pipelines/0',
details: {
status: {
details_path: '/root/review-app-tester/pipelines/66',
@ -258,6 +261,8 @@ export const mockStore = {
},
mergePipeline: {
id: 1,
iid: 1,
path: '/root/acets-app/pipelines/0',
details: {
status: {
details_path: '/root/review-app-tester/pipelines/66',

View File

@ -600,6 +600,7 @@ describe('mrWidgetOptions', () => {
];
const deploymentMockData = {
id: 15,
iid: 7,
name: 'review/diplo',
url: '/root/acets-review-apps/environments/15',
stop_url: '/root/acets-review-apps/environments/15/stop',
@ -646,6 +647,7 @@ describe('mrWidgetOptions', () => {
vm.mr.state = 'merged';
vm.mr.mergePipeline = {
id: 127,
iid: 35,
user: {
id: 1,
name: 'Administrator',

View File

@ -27,7 +27,7 @@ describe 'projects/commit/_commit_box.html.haml' do
render
expect(rendered).to have_text("Pipeline ##{third_pipeline.id} failed")
expect(rendered).to have_text("Pipeline ##{third_pipeline.id} (##{third_pipeline.iid}) failed")
end
end
@ -40,7 +40,7 @@ describe 'projects/commit/_commit_box.html.haml' do
it 'shows correct pipeline description' do
render
expect(rendered).to have_text "Pipeline ##{pipeline.id} " \
expect(rendered).to have_text "Pipeline ##{pipeline.id} (##{pipeline.iid}) " \
'waiting for manual action'
end
end

View File

@ -4,7 +4,7 @@ describe 'projects/ci/jobs/_build' do
include Devise::Test::ControllerHelpers
let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_empty_pipeline, id: 1337, project: project, sha: project.commit.id) }
let(:pipeline) { create(:ci_empty_pipeline, id: 1337, iid: 57, project: project, sha: project.commit.id) }
let(:build) { create(:ci_build, pipeline: pipeline, stage: 'test', stage_idx: 1, name: 'rspec 0:2', status: :pending) }
before do
@ -15,14 +15,14 @@ describe 'projects/ci/jobs/_build' do
it 'won\'t include a column with a link to its pipeline by default' do
render partial: 'projects/ci/builds/build', locals: { build: build }
expect(rendered).not_to have_link('#1337')
expect(rendered).not_to have_text('#1337 by API')
expect(rendered).not_to have_link('#1337 (#57)')
expect(rendered).not_to have_text('#1337 (#57) by API')
end
it 'can include a column with a link to its pipeline' do
render partial: 'projects/ci/builds/build', locals: { build: build, pipeline_link: true }
expect(rendered).to have_link('#1337')
expect(rendered).to have_text('#1337 by API')
expect(rendered).to have_link('#1337 (#57)')
expect(rendered).to have_text('#1337 (#57) by API')
end
end