Commit 325eb990 authored by Enrique Alcántara's avatar Enrique Alcántara

Merge branch 'jivanvl-refactor-pipeline-url-component' into 'master'

Refactor pipeline_url component

See merge request gitlab-org/gitlab!82153
parents 33a87eea 52fe19b1
<script>
import { GlLink, GlPopover, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { SCHEDULE_ORIGIN } from '../../constants';
export default {
components: {
GlBadge,
GlLink,
GlPopover,
GlSprintf,
},
directives: {
GlTooltip: GlTooltipDirective,
},
inject: {
targetProjectFullPath: {
default: '',
},
},
props: {
pipeline: {
type: Object,
required: true,
},
pipelineScheduleUrl: {
type: String,
required: true,
},
},
computed: {
isScheduled() {
return this.pipeline.source === SCHEDULE_ORIGIN;
},
isInFork() {
return Boolean(
this.targetProjectFullPath &&
this.pipeline?.project?.full_path !== `/${this.targetProjectFullPath}`,
);
},
autoDevopsTagId() {
return `pipeline-url-autodevops-${this.pipeline.id}`;
},
autoDevopsHelpPath() {
return helpPagePath('topics/autodevops/index.md');
},
},
};
</script>
<template>
<div class="label-container gl-mt-1">
<gl-badge
v-if="isScheduled"
v-gl-tooltip
:href="pipelineScheduleUrl"
target="__blank"
:title="__('This pipeline was triggered by a schedule.')"
variant="info"
size="sm"
data-testid="pipeline-url-scheduled"
>{{ __('Scheduled') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.latest"
v-gl-tooltip
:title="__('Latest pipeline for the most recent commit on this branch')"
variant="success"
size="sm"
data-testid="pipeline-url-latest"
>{{ __('latest') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.merge_train_pipeline"
v-gl-tooltip
:title="
s__(
'Pipeline|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch.',
)
"
variant="info"
size="sm"
data-testid="pipeline-url-train"
>{{ s__('Pipeline|merge train') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.yaml_errors"
v-gl-tooltip
:title="pipeline.yaml_errors"
variant="danger"
size="sm"
data-testid="pipeline-url-yaml"
>{{ __('yaml invalid') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.failure_reason"
v-gl-tooltip
:title="pipeline.failure_reason"
variant="danger"
size="sm"
data-testid="pipeline-url-failure"
>{{ __('error') }}</gl-badge
>
<template v-if="pipeline.flags.auto_devops">
<gl-link
:id="autoDevopsTagId"
tabindex="0"
data-testid="pipeline-url-autodevops"
role="button"
>
<gl-badge variant="info" size="sm">
{{ __('Auto DevOps') }}
</gl-badge>
</gl-link>
<gl-popover :target="autoDevopsTagId" triggers="focus" placement="top">
<template #title>
<div class="gl-font-weight-normal gl-line-height-normal">
<gl-sprintf
:message="
__(
'This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}',
)
"
>
<template #strong="{ content }">
<b>{{ content }}</b>
</template>
</gl-sprintf>
</div>
</template>
<gl-link
:href="autoDevopsHelpPath"
data-testid="pipeline-url-autodevops-link"
target="_blank"
>
{{ __('Learn more about Auto DevOps') }}
</gl-link>
</gl-popover>
</template>
<gl-badge
v-if="pipeline.flags.stuck"
variant="warning"
size="sm"
data-testid="pipeline-url-stuck"
>{{ __('stuck') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.detached_merge_request_pipeline"
v-gl-tooltip
:title="
s__(
`Pipeline|This pipeline ran on the contents of this merge request's source branch, not the target branch.`,
)
"
variant="info"
size="sm"
data-testid="pipeline-url-detached"
>{{ s__('Pipeline|merge request') }}</gl-badge
>
<gl-badge
v-if="isInFork"
v-gl-tooltip
:title="__('Pipeline ran in fork of project')"
variant="info"
size="sm"
data-testid="pipeline-url-fork"
>{{ __('fork') }}</gl-badge
>
</div>
</template>
<script>
import { GlIcon, GlLink, GlPopover, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui';
import { GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import { SCHEDULE_ORIGIN, ICONS } from '../../constants';
import { ICONS } from '../../constants';
import PipelineLabels from './pipeline_labels.vue';
export default {
components: {
GlIcon,
GlLink,
GlPopover,
GlSprintf,
GlBadge,
PipelineLabels,
TooltipOnTruncate,
},
directives: {
GlTooltip: GlTooltipDirective,
},
inject: {
targetProjectFullPath: {
default: '',
},
},
props: {
pipeline: {
type: Object,
......@@ -35,27 +28,8 @@ export default {
type: String,
required: true,
},
viewType: {
type: String,
required: true,
},
},
computed: {
isScheduled() {
return this.pipeline.source === SCHEDULE_ORIGIN;
},
isInFork() {
return Boolean(
this.targetProjectFullPath &&
this.pipeline?.project?.full_path !== `/${this.targetProjectFullPath}`,
);
},
autoDevopsTagId() {
return `pipeline-url-autodevops-${this.pipeline.id}`;
},
autoDevopsHelpPath() {
return helpPagePath('topics/autodevops/index.md');
},
mergeRequestRef() {
return this.pipeline?.merge_request;
},
......@@ -192,130 +166,11 @@ export default {
:title="__('Commit')"
data-testid="commit-icon"
/>
<gl-link :href="commitUrl" class="commit-sha mr-0" data-testid="commit-short-sha">{{
commitShortSha
}}</gl-link>
<!--End of commit row-->
</div>
<div class="label-container gl-mt-1">
<gl-badge
v-if="isScheduled"
v-gl-tooltip
:href="pipelineScheduleUrl"
target="__blank"
:title="__('This pipeline was triggered by a schedule.')"
variant="info"
size="sm"
data-testid="pipeline-url-scheduled"
>{{ __('Scheduled') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.latest"
v-gl-tooltip
:title="__('Latest pipeline for the most recent commit on this branch')"
variant="success"
size="sm"
data-testid="pipeline-url-latest"
>{{ __('latest') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.merge_train_pipeline"
v-gl-tooltip
:title="
s__(
'Pipeline|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch.',
)
"
variant="info"
size="sm"
data-testid="pipeline-url-train"
>{{ s__('Pipeline|merge train') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.yaml_errors"
v-gl-tooltip
:title="pipeline.yaml_errors"
variant="danger"
size="sm"
data-testid="pipeline-url-yaml"
>{{ __('yaml invalid') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.failure_reason"
v-gl-tooltip
:title="pipeline.failure_reason"
variant="danger"
size="sm"
data-testid="pipeline-url-failure"
>{{ __('error') }}</gl-badge
>
<template v-if="pipeline.flags.auto_devops">
<gl-link
:id="autoDevopsTagId"
tabindex="0"
data-testid="pipeline-url-autodevops"
role="button"
>
<gl-badge variant="info" size="sm">
{{ __('Auto DevOps') }}
</gl-badge>
</gl-link>
<gl-popover :target="autoDevopsTagId" triggers="focus" placement="top">
<template #title>
<div class="gl-font-weight-normal gl-line-height-normal">
<gl-sprintf
:message="
__(
'This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}',
)
"
>
<template #strong="{ content }">
<b>{{ content }}</b>
</template>
</gl-sprintf>
</div>
</template>
<gl-link
:href="autoDevopsHelpPath"
data-testid="pipeline-url-autodevops-link"
target="_blank"
>
{{ __('Learn more about Auto DevOps') }}
</gl-link>
</gl-popover>
</template>
<gl-badge
v-if="pipeline.flags.stuck"
variant="warning"
size="sm"
data-testid="pipeline-url-stuck"
>{{ __('stuck') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.detached_merge_request_pipeline"
v-gl-tooltip
:title="
s__(
`Pipeline|This pipeline ran on the contents of this merge request's source branch, not the target branch.`,
)
"
variant="info"
size="sm"
data-testid="pipeline-url-detached"
>{{ s__('Pipeline|merge request') }}</gl-badge
>
<gl-badge
v-if="isInFork"
v-gl-tooltip
:title="__('Pipeline ran in fork of project')"
variant="info"
size="sm"
data-testid="pipeline-url-fork"
>{{ __('fork') }}</gl-badge
>
</div>
<pipeline-labels :pipeline-schedule-url="pipelineScheduleUrl" :pipeline="pipeline" />
</div>
</template>
......@@ -26,6 +26,47 @@ export default {
PipelineTriggerer,
PipelineUrl,
},
tableFields: [
{
key: 'status',
label: s__('Pipeline|Status'),
thClass: DEFAULT_TH_CLASSES,
columnClass: 'gl-w-15p',
tdClass: DEFAULT_TD_CLASS,
thAttr: { 'data-testid': 'status-th' },
},
{
key: 'pipeline',
label: __('Pipeline'),
thClass: DEFAULT_TH_CLASSES,
tdClass: `${DEFAULT_TD_CLASS}`,
columnClass: 'gl-w-30p',
thAttr: { 'data-testid': 'pipeline-th' },
},
{
key: 'triggerer',
label: s__('Pipeline|Triggerer'),
thClass: DEFAULT_TH_CLASSES,
tdClass: `${DEFAULT_TD_CLASS} ${HIDE_TD_ON_MOBILE}`,
columnClass: 'gl-w-10p',
thAttr: { 'data-testid': 'triggerer-th' },
},
{
key: 'stages',
label: s__('Pipeline|Stages'),
thClass: DEFAULT_TH_CLASSES,
tdClass: DEFAULT_TD_CLASS,
columnClass: 'gl-w-quarter',
thAttr: { 'data-testid': 'stages-th' },
},
{
key: 'actions',
thClass: DEFAULT_TH_CLASSES,
tdClass: DEFAULT_TD_CLASS,
columnClass: 'gl-w-15p',
thAttr: { 'data-testid': 'actions-th' },
},
],
directives: {
GlTooltip: GlTooltipDirective,
},
......@@ -61,53 +102,6 @@ export default {
cancelingPipeline: null,
};
},
computed: {
tableFields() {
const fields = [
{
key: 'status',
label: s__('Pipeline|Status'),
thClass: DEFAULT_TH_CLASSES,
columnClass: 'gl-w-15p',
tdClass: DEFAULT_TD_CLASS,
thAttr: { 'data-testid': 'status-th' },
},
{
key: 'pipeline',
label: __('Pipeline'),
thClass: DEFAULT_TH_CLASSES,
tdClass: `${DEFAULT_TD_CLASS}`,
columnClass: 'gl-w-30p',
thAttr: { 'data-testid': 'pipeline-th' },
},
{
key: 'triggerer',
label: s__('Pipeline|Triggerer'),
thClass: DEFAULT_TH_CLASSES,
tdClass: `${DEFAULT_TD_CLASS} ${HIDE_TD_ON_MOBILE}`,
columnClass: 'gl-w-10p',
thAttr: { 'data-testid': 'triggerer-th' },
},
{
key: 'stages',
label: s__('Pipeline|Stages'),
thClass: DEFAULT_TH_CLASSES,
tdClass: DEFAULT_TD_CLASS,
columnClass: 'gl-w-quarter',
thAttr: { 'data-testid': 'stages-th' },
},
{
key: 'actions',
thClass: DEFAULT_TH_CLASSES,
tdClass: DEFAULT_TD_CLASS,
columnClass: 'gl-w-15p',
thAttr: { 'data-testid': 'actions-th' },
},
];
return fields;
},
},
watch: {
pipelines() {
this.cancelingPipeline = null;
......@@ -138,7 +132,7 @@ export default {
<template>
<div class="ci-table">
<gl-table-lite
:fields="tableFields"
:fields="$options.tableFields"
:items="pipelines"
tbody-tr-class="commit"
:tbody-tr-attr="{ 'data-testid': 'pipeline-table-row' }"
......@@ -163,7 +157,6 @@ export default {
:pipeline="item"
:pipeline-schedule-url="pipelineScheduleUrl"
:pipeline-key="pipelineKeyOption.key"
:view-type="viewType"
/>
</template>
......
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { trimText } from 'helpers/text_helper';
import PipelineLabelsComponent from '~/pipelines/components/pipelines_list/pipeline_labels.vue';
import { mockPipeline } from './mock_data';
const projectPath = 'test/test';
describe('Pipeline label component', () => {
let wrapper;
const findScheduledTag = () => wrapper.findByTestId('pipeline-url-scheduled');
const findLatestTag = () => wrapper.findByTestId('pipeline-url-latest');
const findYamlTag = () => wrapper.findByTestId('pipeline-url-yaml');
const findStuckTag = () => wrapper.findByTestId('pipeline-url-stuck');
const findAutoDevopsTag = () => wrapper.findByTestId('pipeline-url-autodevops');
const findAutoDevopsTagLink = () => wrapper.findByTestId('pipeline-url-autodevops-link');
const findDetachedTag = () => wrapper.findByTestId('pipeline-url-detached');
const findFailureTag = () => wrapper.findByTestId('pipeline-url-failure');
const findForkTag = () => wrapper.findByTestId('pipeline-url-fork');
const findTrainTag = () => wrapper.findByTestId('pipeline-url-train');
const defaultProps = mockPipeline(projectPath);
const createComponent = (props) => {
wrapper = shallowMountExtended(PipelineLabelsComponent, {
propsData: { ...defaultProps, ...props },
provide: {
targetProjectFullPath: projectPath,
},
});
};
afterEach(() => {
wrapper.destroy();
});
it('should not render tags when flags are not set', () => {
createComponent();
expect(findStuckTag().exists()).toBe(false);
expect(findLatestTag().exists()).toBe(false);
expect(findYamlTag().exists()).toBe(false);
expect(findAutoDevopsTag().exists()).toBe(false);
expect(findFailureTag().exists()).toBe(false);
expect(findScheduledTag().exists()).toBe(false);
expect(findForkTag().exists()).toBe(false);
expect(findTrainTag().exists()).toBe(false);
});
it('should render the stuck tag when flag is provided', () => {
const stuckPipeline = defaultProps.pipeline;
stuckPipeline.flags.stuck = true;
createComponent({
...stuckPipeline.pipeline,
});
expect(findStuckTag().text()).toContain('stuck');
});
it('should render latest tag when flag is provided', () => {
const latestPipeline = defaultProps.pipeline;
latestPipeline.flags.latest = true;
createComponent({
...latestPipeline,
});
expect(findLatestTag().text()).toContain('latest');
});
it('should render a yaml badge when it is invalid', () => {
const yamlPipeline = defaultProps.pipeline;
yamlPipeline.flags.yaml_errors = true;
createComponent({
...yamlPipeline,
});
expect(findYamlTag().text()).toContain('yaml invalid');
});
it('should render an autodevops badge when flag is provided', () => {
const autoDevopsPipeline = defaultProps.pipeline;
autoDevopsPipeline.flags.auto_devops = true;
createComponent({
...autoDevopsPipeline,
});
expect(trimText(findAutoDevopsTag().text())).toBe('Auto DevOps');
expect(findAutoDevopsTagLink().attributes()).toMatchObject({
href: '/help/topics/autodevops/index.md',
target: '_blank',
});
});
it('should render a detached badge when flag is provided', () => {
const detachedMRPipeline = defaultProps.pipeline;
detachedMRPipeline.flags.detached_merge_request_pipeline = true;
createComponent({
...detachedMRPipeline,
});
expect(findDetachedTag().text()).toBe('merge request');
});
it('should render error badge when pipeline has a failure reason set', () => {
const failedPipeline = defaultProps.pipeline;
failedPipeline.flags.failure_reason = true;
failedPipeline.failure_reason = 'some reason';
createComponent({
...failedPipeline,
});
expect(findFailureTag().text()).toContain('error');
expect(findFailureTag().attributes('title')).toContain('some reason');
});
it('should render scheduled badge when pipeline was triggered by a schedule', () => {
const scheduledPipeline = defaultProps.pipeline;
scheduledPipeline.source = 'schedule';
createComponent({
...scheduledPipeline,
});
expect(findScheduledTag().exists()).toBe(true);
expect(findScheduledTag().text()).toContain('Scheduled');
});
it('should render the fork badge when the pipeline was run in a fork', () => {
const forkedPipeline = defaultProps.pipeline;
forkedPipeline.project.full_path = '/test/forked';
createComponent({
...forkedPipeline,
});
expect(findForkTag().exists()).toBe(true);
expect(findForkTag().text()).toBe('fork');
});
it('should render the train badge when the pipeline is a merge train pipeline', () => {
const mergeTrainPipeline = defaultProps.pipeline;
mergeTrainPipeline.flags.merge_train_pipeline = true;
createComponent({
...mergeTrainPipeline,
});
expect(findTrainTag().text()).toBe('merge train');
});
it('should not render the train badge when the pipeline is not a merge train pipeline', () => {
const mergeTrainPipeline = defaultProps.pipeline;
mergeTrainPipeline.flags.merge_train_pipeline = false;
createComponent({
...mergeTrainPipeline,
});
expect(findTrainTag().exists()).toBe(false);
});
});
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { trimText } from 'helpers/text_helper';
import PipelineUrlComponent from '~/pipelines/components/pipelines_list/pipeline_url.vue';
import { mockPipeline, mockPipelineBranch, mockPipelineTag } from './mock_data';
......@@ -10,16 +9,6 @@ describe('Pipeline Url Component', () => {
const findTableCell = () => wrapper.findByTestId('pipeline-url-table-cell');
const findPipelineUrlLink = () => wrapper.findByTestId('pipeline-url-link');
const findScheduledTag = () => wrapper.findByTestId('pipeline-url-scheduled');
const findLatestTag = () => wrapper.findByTestId('pipeline-url-latest');
const findYamlTag = () => wrapper.findByTestId('pipeline-url-yaml');
const findFailureTag = () => wrapper.findByTestId('pipeline-url-failure');
const findAutoDevopsTag = () => wrapper.findByTestId('pipeline-url-autodevops');
const findAutoDevopsTagLink = () => wrapper.findByTestId('pipeline-url-autodevops-link');
const findStuckTag = () => wrapper.findByTestId('pipeline-url-stuck');
const findDetachedTag = () => wrapper.findByTestId('pipeline-url-detached');
const findForkTag = () => wrapper.findByTestId('pipeline-url-fork');
const findTrainTag = () => wrapper.findByTestId('pipeline-url-train');
const findRefName = () => wrapper.findByTestId('merge-request-ref');
const findCommitShortSha = () => wrapper.findByTestId('commit-short-sha');
const findCommitIcon = () => wrapper.findByTestId('commit-icon');
......@@ -58,138 +47,6 @@ describe('Pipeline Url Component', () => {
expect(findPipelineUrlLink().text()).toBe('#1');
});
it('should not render tags when flags are not set', () => {
createComponent();
expect(findStuckTag().exists()).toBe(false);
expect(findLatestTag().exists()).toBe(false);
expect(findYamlTag().exists()).toBe(false);
expect(findAutoDevopsTag().exists()).toBe(false);
expect(findFailureTag().exists()).toBe(false);
expect(findScheduledTag().exists()).toBe(false);
expect(findForkTag().exists()).toBe(false);
expect(findTrainTag().exists()).toBe(false);
});
it('should render the stuck tag when flag is provided', () => {
const stuckPipeline = defaultProps.pipeline;
stuckPipeline.flags.stuck = true;
createComponent({
...stuckPipeline.pipeline,
});
expect(findStuckTag().text()).toContain('stuck');
});
it('should render latest tag when flag is provided', () => {
const latestPipeline = defaultProps.pipeline;
latestPipeline.flags.latest = true;
createComponent({
...latestPipeline,
});
expect(findLatestTag().text()).toContain('latest');
});
it('should render a yaml badge when it is invalid', () => {
const yamlPipeline = defaultProps.pipeline;
yamlPipeline.flags.yaml_errors = true;
createComponent({
...yamlPipeline,
});
expect(findYamlTag().text()).toContain('yaml invalid');
});
it('should render an autodevops badge when flag is provided', () => {
const autoDevopsPipeline = defaultProps.pipeline;
autoDevopsPipeline.flags.auto_devops = true;
createComponent({
...autoDevopsPipeline,
});
expect(trimText(findAutoDevopsTag().text())).toBe('Auto DevOps');
expect(findAutoDevopsTagLink().attributes()).toMatchObject({
href: '/help/topics/autodevops/index.md',
target: '_blank',
});
});
it('should render a detached badge when flag is provided', () => {
const detachedMRPipeline = defaultProps.pipeline;
detachedMRPipeline.flags.detached_merge_request_pipeline = true;
createComponent({
...detachedMRPipeline,
});
expect(findDetachedTag().text()).toBe('merge request');
});
it('should render error badge when pipeline has a failure reason set', () => {
const failedPipeline = defaultProps.pipeline;
failedPipeline.flags.failure_reason = true;
failedPipeline.failure_reason = 'some reason';
createComponent({
...failedPipeline,
});
expect(findFailureTag().text()).toContain('error');
expect(findFailureTag().attributes('title')).toContain('some reason');
});
it('should render scheduled badge when pipeline was triggered by a schedule', () => {
const scheduledPipeline = defaultProps.pipeline;
scheduledPipeline.source = 'schedule';
createComponent({
...scheduledPipeline,
});
expect(findScheduledTag().exists()).toBe(true);
expect(findScheduledTag().text()).toContain('Scheduled');
});
it('should render the fork badge when the pipeline was run in a fork', () => {
const forkedPipeline = defaultProps.pipeline;
forkedPipeline.project.full_path = '/test/forked';
createComponent({
...forkedPipeline,
});
expect(findForkTag().exists()).toBe(true);
expect(findForkTag().text()).toBe('fork');
});
it('should render the train badge when the pipeline is a merge train pipeline', () => {
const mergeTrainPipeline = defaultProps.pipeline;
mergeTrainPipeline.flags.merge_train_pipeline = true;
createComponent({
...mergeTrainPipeline,
});
expect(findTrainTag().text()).toBe('merge train');
});
it('should not render the train badge when the pipeline is not a merge train pipeline', () => {
const mergeTrainPipeline = defaultProps.pipeline;
mergeTrainPipeline.flags.merge_train_pipeline = false;
createComponent({
...mergeTrainPipeline,
});
expect(findTrainTag().exists()).toBe(false);
});
it('should render the commit title, commit reference and commit-short-sha', () => {
createComponent({}, true);
......
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