Commit 0b28bd79 authored by Thong Kuah's avatar Thong Kuah

Merge branch 'indicator-for-pipeline-for-merge-train' into 'master'

Show indicator to Pipelines for merge train

See merge request gitlab-org/gitlab-ee!14664
parents 58d174bd 4ab6c4e1
<script>
/* eslint-disable vue/require-default-prop */
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
import { sprintf, __ } from '~/locale';
import { sprintf, s__ } 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';
......@@ -73,8 +73,8 @@ export default {
},
errorText() {
return sprintf(
__(
'Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation.%{linkEnd}',
s__(
'Pipeline|Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation.%{linkEnd}',
),
{
linkStart: `<a href="${this.troubleshootingDocsPath}">`,
......@@ -89,6 +89,9 @@ export default {
isMergeRequestPipeline() {
return Boolean(this.pipeline.flags && this.pipeline.flags.merge_request_pipeline);
},
showSourceBranch() {
return Boolean(this.pipeline.ref.branch);
},
},
};
</script>
......@@ -108,7 +111,7 @@ export default {
<div class="ci-widget-content">
<div class="media-body">
<div class="font-weight-bold js-pipeline-info-container">
{{ s__('Pipeline|Pipeline') }}
{{ pipeline.details.name }}
<gl-link :href="pipeline.path" class="pipeline-id font-weight-normal pipeline-number"
>#{{ pipeline.id }}</gl-link
>
......@@ -120,48 +123,13 @@ export default {
class="commit-sha js-commit-link font-weight-normal"
>{{ pipeline.commit.short_id }}</gl-link
>
</template>
<template v-if="showSourceBranch">
{{ s__('Pipeline|on') }}
<template v-if="isTriggeredByMergeRequest">
<gl-link
v-gl-tooltip
:href="pipeline.merge_request.path"
:title="pipeline.merge_request.title"
class="font-weight-normal"
>!{{ pipeline.merge_request.iid }}</gl-link
>
{{ s__('Pipeline|with') }}
<tooltip-on-truncate
:title="pipeline.merge_request.source_branch"
truncate-target="child"
class="label-branch label-truncate"
>
<gl-link
:href="pipeline.merge_request.source_branch_path"
class="font-weight-normal"
>{{ pipeline.merge_request.source_branch }}</gl-link
>
</tooltip-on-truncate>
<template v-if="isMergeRequestPipeline">
{{ s__('Pipeline|into') }}
<tooltip-on-truncate
:title="pipeline.merge_request.target_branch"
truncate-target="child"
class="label-branch label-truncate"
>
<gl-link
:href="pipeline.merge_request.target_branch_path"
class="font-weight-normal"
>{{ pipeline.merge_request.target_branch }}</gl-link
>
</tooltip-on-truncate>
</template>
</template>
<tooltip-on-truncate
v-else
:title="sourceBranch"
truncate-target="child"
class="label-branch label-truncate"
class="label-branch label-truncate font-weight-normal"
v-html="sourceBranchLink"
/>
</template>
......
......@@ -835,12 +835,12 @@ module Ci
return unless merge_request_event?
strong_memoize(:merge_request_event_type) do
if detached_merge_request_pipeline?
:detached
if merge_train_pipeline?
:merge_train
elsif merge_request_pipeline?
:merged_result
elsif merge_train_pipeline?
:merge_train
elsif detached_merge_request_pipeline?
:detached
end
end
end
......
---
title: Make MR pipeline widget text more descriptive
merge_request: 32025
author:
type: changed
......@@ -24,6 +24,15 @@ FactoryBot.modify do
end
end
trait :with_merge_train_pipeline do
with_merge_request_pipeline
after(:create) do |merge_request, evaluator|
merge_request.pipelines_for_merge_request.last
.update(ref: merge_request.train_ref_path)
end
end
trait :add_to_merge_train_when_pipeline_succeeds do
auto_merge_enabled true
auto_merge_strategy AutoMergeService::STRATEGY_ADD_TO_MERGE_TRAIN_WHEN_PIPELINE_SUCCEEDS
......
......@@ -47,6 +47,24 @@ describe 'Merge request > User sees merge widget', :js do
end
end
context 'when the head pipeline is merge train pipeline' do
let(:traits) { [:with_merge_train_pipeline] }
let(:options) { { merge_sha: project.commit.sha } }
let(:pipeline) { merge_request.all_pipelines.first }
before do
merge_request.update_head_pipeline
end
it 'shows head pipeline information' do
visit project_merge_request_path(project, merge_request)
within '.ci-widget-content' do
expect(page).to have_content("Merge train pipeline ##{pipeline.id} pending for #{pipeline.short_sha}")
end
end
end
context 'when merge request is submitted from a forked project' do
let(:source_project) { fork_project(project, user, repository: true) }
let(:traits) { [:with_detached_merge_request_pipeline] }
......
......@@ -3,6 +3,7 @@ import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_p
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import mockData from 'ee_spec/vue_mr_widget/mock_data';
import mockLinkedPipelines from 'ee_spec/pipelines/graph/linked_pipelines_mock_data';
import { trimText } from 'spec/helpers/text_helper';
describe('MRWidgetPipeline', () => {
let vm;
......@@ -55,4 +56,53 @@ describe('MRWidgetPipeline', () => {
});
});
});
describe('for each type of pipeline', () => {
let pipeline;
beforeEach(() => {
({ pipeline } = JSON.parse(JSON.stringify(mockData)));
pipeline.ref.tag = false;
pipeline.ref.branch = false;
});
const factory = () => {
vm = mountComponent(Component, {
pipeline,
hasCi: true,
ciStatus: 'success',
troubleshootingDocsPath: 'help',
sourceBranchLink: mockData.source_branch_link,
});
};
describe('for a merge train pipeline', () => {
it('renders a pipeline widget that reads "Merge train pipeline <ID> <status> for <SHA>"', () => {
pipeline.details.name = 'Merge train pipeline';
pipeline.merge_request_event_type = 'merge_train';
factory();
const expected = `Merge train pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
expect(actual).toBe(expected);
});
});
describe('for a merged result pipeline', () => {
it('renders a pipeline widget that reads "Merged result pipeline <ID> <status> for <SHA>"', () => {
pipeline.details.name = 'Merged result pipeline';
pipeline.merge_request_event_type = 'merged_result';
factory();
const expected = `Merged result pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
expect(actual).toBe(expected);
});
});
});
});
......@@ -4226,9 +4226,6 @@ msgstr ""
msgid "Could not remove the trigger."
msgstr ""
msgid "Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation.%{linkEnd}"
msgstr ""
msgid "Could not revoke impersonation token %{token_name}."
msgstr ""
......@@ -11026,6 +11023,9 @@ msgstr ""
msgid "Pipeline|Commit"
msgstr ""
msgid "Pipeline|Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation.%{linkEnd}"
msgstr ""
msgid "Pipeline|Coverage"
msgstr ""
......@@ -11092,18 +11092,12 @@ msgstr ""
msgid "Pipeline|for"
msgstr ""
msgid "Pipeline|into"
msgstr ""
msgid "Pipeline|on"
msgstr ""
msgid "Pipeline|success"
msgstr ""
msgid "Pipeline|with"
msgstr ""
msgid "Pipeline|with stage"
msgstr ""
......
......@@ -189,26 +189,20 @@ describe 'Merge request > User sees merge widget', :js do
visit project_merge_request_path(project, merge_request)
end
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Pipeline ##{pipeline.id} pending " \
"for #{pipeline.short_sha} " \
"on #{merge_request.to_reference} " \
"with #{merge_request.source_branch}")
shared_examples 'pipeline widget' do
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Detached merge request pipeline ##{pipeline.id} pending for #{pipeline.short_sha}")
end
end
end
include_examples 'pipeline widget'
context 'when source project is a forked project' do
let(:source_project) { fork_project(project, user, repository: true) }
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Pipeline ##{pipeline.id} pending " \
"for #{pipeline.short_sha} " \
"on #{merge_request.to_reference} " \
"with #{merge_request.source_branch}")
end
end
include_examples 'pipeline widget'
end
end
......@@ -234,29 +228,21 @@ describe 'Merge request > User sees merge widget', :js do
visit project_merge_request_path(project, merge_request)
end
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Pipeline ##{pipeline.id} pending " \
"for #{pipeline.short_sha} " \
"on #{merge_request.to_reference} " \
"with #{merge_request.source_branch} " \
"into #{merge_request.target_branch}")
shared_examples 'pipeline widget' do
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Merged result pipeline ##{pipeline.id} pending for #{pipeline.short_sha}")
end
end
end
include_examples 'pipeline widget'
context 'when source project is a forked project' do
let(:source_project) { fork_project(project, user, repository: true) }
let(:merge_sha) { source_project.commit.sha }
it 'shows head pipeline information' do
within '.ci-widget-content' do
expect(page).to have_content("Pipeline ##{pipeline.id} pending " \
"for #{pipeline.short_sha} " \
"on #{merge_request.to_reference} " \
"with #{merge_request.source_branch} " \
"into #{merge_request.target_branch}")
end
end
include_examples 'pipeline widget'
end
end
......
......@@ -69,7 +69,6 @@ describe('MRWidgetPipeline', () => {
vm = mountComponent(Component, {
pipeline: mockData.pipeline,
hasCi: true,
ciStatus: null,
troubleshootingDocsPath: 'help',
});
......@@ -208,71 +207,66 @@ describe('MRWidgetPipeline', () => {
});
});
describe('without pipeline.merge_request', () => {
it('should render info that includes the commit and branch details', () => {
const mockCopy = JSON.parse(JSON.stringify(mockData));
delete mockCopy.pipeline.merge_request;
const { pipeline } = mockCopy;
vm = mountComponent(Component, {
pipeline,
hasCi: true,
ciStatus: 'success',
troubleshootingDocsPath: 'help',
sourceBranchLink: mockCopy.source_branch_link,
});
const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id} on ${mockCopy.source_branch_link}`;
describe('for each type of pipeline', () => {
let pipeline;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
beforeEach(() => {
({ pipeline } = JSON.parse(JSON.stringify(mockData)));
expect(actual).toBe(expected);
pipeline.details.name = 'Pipeline';
pipeline.merge_request_event_type = undefined;
pipeline.ref.tag = false;
pipeline.ref.branch = false;
});
});
describe('with pipeline.merge_request and flags.merge_request_pipeline', () => {
it('should render info that includes the commit, MR, source branch, and target branch details', () => {
const mockCopy = JSON.parse(JSON.stringify(mockData));
const { pipeline } = mockCopy;
pipeline.flags.merge_request_pipeline = true;
pipeline.flags.detached_merge_request_pipeline = false;
const factory = () => {
vm = mountComponent(Component, {
pipeline,
hasCi: true,
ciStatus: 'success',
troubleshootingDocsPath: 'help',
sourceBranchLink: mockCopy.source_branch_link,
sourceBranchLink: mockData.source_branch_link,
});
};
describe('for a branch pipeline', () => {
it('renders a pipeline widget that reads "Pipeline <ID> <status> for <SHA> on <branch>"', () => {
pipeline.ref.branch = true;
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}`;
factory();
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id} on ${mockData.source_branch_link}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
expect(actual).toBe(expected);
expect(actual).toBe(expected);
});
});
});
describe('with pipeline.merge_request and flags.detached_merge_request_pipeline', () => {
it('should render info that includes the commit, MR, and source branch details', () => {
const mockCopy = JSON.parse(JSON.stringify(mockData));
const { pipeline } = mockCopy;
pipeline.flags.merge_request_pipeline = false;
pipeline.flags.detached_merge_request_pipeline = true;
describe('for a tag pipeline', () => {
it('renders a pipeline widget that reads "Pipeline <ID> <status> for <SHA> on <branch>"', () => {
pipeline.ref.tag = true;
vm = mountComponent(Component, {
pipeline,
hasCi: true,
ciStatus: 'success',
troubleshootingDocsPath: 'help',
sourceBranchLink: mockCopy.source_branch_link,
factory();
const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
expect(actual).toBe(expected);
});
});
describe('for a detached merge request pipeline', () => {
it('renders a pipeline widget that reads "Detached merge request pipeline <ID> <status> for <SHA>"', () => {
pipeline.details.name = 'Detached merge request pipeline';
pipeline.merge_request_event_type = 'detached';
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}`;
factory();
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
const expected = `Detached merge request pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`;
const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
expect(actual).toBe(expected);
expect(actual).toBe(expected);
});
});
});
});
......
......@@ -259,6 +259,8 @@ export const mockStore = {
tooltip: 'passed',
},
},
flags: {},
ref: {},
},
mergePipeline: {
id: 1,
......@@ -276,6 +278,8 @@ export const mockStore = {
tooltip: 'passed',
},
},
flags: {},
ref: {},
},
targetBranch: 'target-branch',
sourceBranch: 'source-branch',
......
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