Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-06-28 21:10:10 +00:00
parent d12d801795
commit 59223e71ad
44 changed files with 1030 additions and 191 deletions

View File

@ -10,8 +10,6 @@ export default {
},
components: {
PipelineMiniGraph,
LinkedPipelinesMiniList: () =>
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
},
inject: ['projectFullPath'],
props: {
@ -47,9 +45,6 @@ export default {
downstreamPipelines() {
return this.linkedPipelines?.downstream?.nodes || [];
},
hasDownstreamPipelines() {
return this.downstreamPipelines.length > 0;
},
hasPipelineStages() {
return this.pipelineStages.length > 0;
},
@ -87,23 +82,11 @@ export default {
</script>
<template>
<div
<pipeline-mini-graph
v-if="hasPipelineStages"
class="gl-align-items-center gl-display-inline-flex gl-flex-wrap stage-cell gl-mr-5"
>
<linked-pipelines-mini-list
v-if="upstreamPipeline"
:triggered-by="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
upstreamPipeline,
] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
data-testid="pipeline-editor-mini-graph-upstream"
/>
<pipeline-mini-graph :stages="pipelineStages" />
<linked-pipelines-mini-list
v-if="hasDownstreamPipelines"
:triggered="downstreamPipelines"
:pipeline-path="pipelinePath"
data-testid="pipeline-editor-mini-graph-downstream"
/>
</div>
:downstream-pipelines="downstreamPipelines"
:pipeline-path="pipelinePath"
:stages="pipelineStages"
:upstream-pipeline="upstreamPipeline"
/>
</template>

View File

@ -174,7 +174,7 @@ export default {
<div class="gl-display-flex gl-flex-wrap">
<pipeline-editor-mini-graph :pipeline="pipeline" v-on="$listeners" />
<gl-button
class="gl-mt-2 gl-md-mt-0"
class="gl-ml-3"
category="secondary"
variant="confirm"
:href="status.detailsPath"

View File

@ -1,32 +1,60 @@
<script>
import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue';
import { GlIcon } from '@gitlab/ui';
import PipelineStages from '~/pipelines/components/pipelines_list/pipeline_stages.vue';
/**
* Renders the pipeline mini graph.
*/
export default {
components: {
PipelineStage,
GlIcon,
PipelineStages,
LinkedPipelinesMiniList: () =>
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
},
arrowStyles: [
'arrow-icon gl-display-inline-block gl-mx-1 gl-text-gray-500 gl-vertical-align-middle!',
],
props: {
stages: {
downstreamPipelines: {
type: Array,
required: true,
required: false,
default: () => [],
},
updateDropdown: {
isMergeTrain: {
type: Boolean,
required: false,
default: false,
},
pipelinePath: {
type: String,
required: false,
default: '',
},
stages: {
type: Array,
required: true,
default: () => [],
},
stagesClass: {
type: [Array, Object, String],
required: false,
default: '',
},
isMergeTrain: {
updateDropdown: {
type: Boolean,
required: false,
default: false,
},
upstreamPipeline: {
type: Object,
required: false,
default: () => {},
},
},
computed: {
hasDownstreamPipelines() {
return Boolean(this.downstreamPipelines.length);
},
},
methods: {
onPipelineActionRequestComplete() {
@ -36,19 +64,39 @@ export default {
};
</script>
<template>
<div data-testid="pipeline-mini-graph" class="gl-display-inline gl-vertical-align-middle">
<div
v-for="stage in stages"
:key="stage.name"
:class="stagesClass"
class="dropdown gl-display-inline-block gl-mr-2 gl-my-2 gl-vertical-align-middle stage-container"
>
<pipeline-stage
:stage="stage"
:update-dropdown="updateDropdown"
:is-merge-train="isMergeTrain"
@pipelineActionRequestComplete="onPipelineActionRequestComplete"
/>
</div>
<div class="stage-cell" data-testid="pipeline-mini-graph">
<linked-pipelines-mini-list
v-if="upstreamPipeline"
:triggered-by="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
upstreamPipeline,
] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
data-testid="pipeline-mini-graph-upstream"
/>
<gl-icon
v-if="upstreamPipeline"
:class="$options.arrowStyles"
name="long-arrow"
data-testid="upstream-arrow-icon"
/>
<pipeline-stages
:is-merge-train="isMergeTrain"
:stages="stages"
:update-dropdown="updateDropdown"
:stages-class="stagesClass"
data-testid="pipeline-stages"
@pipelineActionRequestComplete="onPipelineActionRequestComplete"
/>
<gl-icon
v-if="hasDownstreamPipelines"
:class="$options.arrowStyles"
name="long-arrow"
data-testid="downstream-arrow-icon"
/>
<linked-pipelines-mini-list
v-if="hasDownstreamPipelines"
:triggered="downstreamPipelines"
:pipeline-path="pipelinePath"
data-testid="pipeline-mini-graph-downstream"
/>
</div>
</template>

View File

@ -0,0 +1,54 @@
<script>
import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue';
/**
* Renders the pipeline stages portion of the pipeline mini graph.
*/
export default {
components: {
PipelineStage,
},
props: {
stages: {
type: Array,
required: true,
},
updateDropdown: {
type: Boolean,
required: false,
default: false,
},
stagesClass: {
type: [Array, Object, String],
required: false,
default: '',
},
isMergeTrain: {
type: Boolean,
required: false,
default: false,
},
},
methods: {
onPipelineActionRequestComplete() {
this.$emit('pipelineActionRequestComplete');
},
},
};
</script>
<template>
<div data-testid="pipeline-stages" class="gl-display-inline gl-vertical-align-middle">
<div
v-for="stage in stages"
:key="stage.name"
:class="stagesClass"
class="dropdown gl-display-inline-block gl-mr-2 gl-my-2 gl-vertical-align-middle stage-container"
>
<pipeline-stage
:stage="stage"
:update-dropdown="updateDropdown"
:is-merge-train="isMergeTrain"
@pipelineActionRequestComplete="onPipelineActionRequestComplete"
/>
</div>
</div>
</template>

View File

@ -17,8 +17,6 @@ const DEFAULT_TH_CLASSES =
export default {
components: {
GlTableLite,
LinkedPipelinesMiniList: () =>
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
PipelineMiniGraph,
PipelineOperations,
PipelinesStatusBadge,
@ -169,29 +167,14 @@ export default {
</template>
<template #cell(stages)="{ item }">
<div class="stage-cell">
<!-- This empty div should be removed, see https://gitlab.com/gitlab-org/gitlab/-/issues/323488 -->
<div></div>
<linked-pipelines-mini-list
v-if="item.triggered_by"
:triggered-by="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
item.triggered_by,
] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
data-testid="mini-graph-upstream"
/>
<pipeline-mini-graph
v-if="item.details && item.details.stages && item.details.stages.length > 0"
:stages="item.details.stages"
:update-dropdown="updateGraphDropdown"
@pipelineActionRequestComplete="onPipelineActionRequestComplete"
/>
<linked-pipelines-mini-list
v-if="item.triggered.length"
:triggered="item.triggered"
:pipeline-path="item.path"
data-testid="mini-graph-downstream"
/>
</div>
<pipeline-mini-graph
:downstream-pipelines="item.triggered"
:pipeline-path="item.path"
:stages="item.details.stages"
:update-dropdown="updateGraphDropdown"
:upstream-pipeline="item.triggered_by"
@pipelineActionRequestComplete="onPipelineActionRequestComplete"
/>
</template>
<template #cell(actions)="{ item }">

View File

@ -2,11 +2,11 @@
import { GlLoadingIcon } from '@gitlab/ui';
import createFlash from '~/flash';
import { __ } from '~/locale';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import {
getQueryHeaders,
toggleQueryPollingByVisibility,
} from '~/pipelines/components/graph/utils';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import { formatStages } from '../utils';
import getLinkedPipelinesQuery from '../graphql/queries/get_linked_pipelines.query.graphql';
import getPipelineStagesQuery from '../graphql/queries/get_pipeline_stages.query.graphql';
@ -21,8 +21,6 @@ export default {
components: {
GlLoadingIcon,
PipelineMiniGraph,
LinkedPipelinesMiniList: () =>
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
},
inject: {
fullPath: {
@ -92,12 +90,12 @@ export default {
};
},
computed: {
hasDownstream() {
return this.pipeline?.downstream?.nodes.length > 0;
},
downstreamPipelines() {
return this.pipeline?.downstream?.nodes;
},
pipelinePath() {
return this.pipeline?.path ?? '';
},
upstreamPipeline() {
return this.pipeline?.upstream;
},
@ -128,23 +126,13 @@ export default {
<template>
<div class="gl-pt-2">
<gl-loading-icon v-if="$apollo.queries.pipeline.loading" />
<div v-else class="gl-align-items-center gl-display-flex">
<linked-pipelines-mini-list
v-if="upstreamPipeline"
:triggered-by="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
upstreamPipeline,
] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
data-testid="commit-box-mini-graph-upstream"
/>
<pipeline-mini-graph :stages="formattedStages" data-testid="commit-box-mini-graph" />
<linked-pipelines-mini-list
v-if="hasDownstream"
:triggered="downstreamPipelines"
:pipeline-path="pipeline.path"
data-testid="commit-box-mini-graph-downstream"
/>
</div>
<pipeline-mini-graph
v-else
data-testid="commit-box-pipeline-mini-graph"
:downstream-pipelines="downstreamPipelines"
:pipeline-path="pipelinePath"
:stages="formattedStages"
:upstream-pipeline="upstreamPipeline"
/>
</div>
</template>

View File

@ -11,8 +11,8 @@ import {
} from '@gitlab/ui';
import mrWidgetPipelineMixin from 'ee_else_ce/vue_merge_request_widget/mixins/mr_widget_pipeline';
import { s__, n__ } from '~/locale';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
@ -31,8 +31,6 @@ export default {
PipelineMiniGraph,
TimeAgoTooltip,
TooltipOnTruncate,
LinkedPipelinesMiniList: () =>
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
},
directives: {
GlTooltip: GlTooltipDirective,
@ -276,17 +274,15 @@ export default {
</div>
</div>
<div>
<span class="gl-align-items-center gl-display-inline-flex mr-widget-pipeline-graph">
<span class="gl-align-items-center gl-display-inline-flex gl-flex-wrap stage-cell">
<linked-pipelines-mini-list v-if="triggeredBy.length" :triggered-by="triggeredBy" />
<pipeline-mini-graph
v-if="hasStages"
stages-class="mr-widget-pipeline-stages"
:stages="pipeline.details.stages"
:is-merge-train="isMergeTrain"
/>
</span>
<linked-pipelines-mini-list v-if="triggered.length" :triggered="triggered" />
<span class="gl-align-items-center gl-display-inline-flex">
<pipeline-mini-graph
v-if="pipeline.details.stages"
:downstream-pipelines="triggered"
:is-merge-train="isMergeTrain"
:stages="pipeline.details.stages"
:upstream-pipeline="triggeredBy[0]"
stages-class="mr-widget-pipeline-stages"
/>
<pipeline-artifacts :pipeline-id="pipeline.id" :artifacts="artifacts" class="gl-ml-3" />
</span>
</div>

View File

@ -400,12 +400,6 @@ $tabs-holder-z-index: 250;
display: block;
}
.mr-widget-pipeline-graph {
.dropdown-menu {
z-index: $zindex-dropdown-menu;
}
}
.normal {
flex: 1;
flex-basis: auto;

View File

@ -33,12 +33,6 @@
height: 22px;
}
}
.mr-widget-pipeline-graph {
.dropdown-menu {
margin-top: 11px;
}
}
}
.branch-info .commit-icon {

View File

@ -793,19 +793,9 @@ Plan.default.actual_limits.update!(dotenv_size: 5.kilobytes)
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17859) in GitLab 12.5.
You can limit the number of inbound alerts for [incidents](../operations/incident_management/incidents.md)
that can be created in a period of time. The inbound [incident management](../operations/incident_management/index.md)
alert limit can help prevent overloading your incident responders by reducing the
number of alerts or duplicate issues.
This setting limits the number of inbound alert payloads over a period of time.
To set inbound incident management alert limits:
1. On the top bar, select **Menu > Admin**.
1. On the left sidebar, select **Settings > Network**.
1. Expand General **Incident Management Limits**.
1. Select the **Enable Incident Management inbound alert limit** checkbox.
1. Optional. Input a custom value for **Maximum requests per project per rate limit period**. Default is 3600.
1. Optional. Input a custom value for **Rate limit period**. Default is 3600 seconds.
Read more about [incident management rate limits](../user/admin_area/settings/rate_limit_on_pipelines_creation.md).
### Prometheus Alert JSON payloads

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
type: reference, api

View File

@ -190,6 +190,10 @@ Everything in `app/finders`, typically used for retrieving data from a database.
Finders can not reuse other finders in an attempt to better control the SQL
queries they produce.
Finders' `execute` method should return `ActiveRecord::Relation`. Exceptions
can be added to `spec/support/finder_collection_allowlist.yml`.
See [`#298771`](https://gitlab.com/gitlab-org/gitlab/-/issues/298771) for more details.
### Presenters
Everything in `app/presenters`, used for exposing complex data to a Rails view,

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -43,6 +43,7 @@ You can set these rate limits in the Admin Area of your instance:
- [Deprecated API rate limits](../user/admin_area/settings/deprecated_api_rate_limits.md)
- [GitLab Pages rate limits](../administration/pages/index.md#rate-limits)
- [Pipeline rate limits](../user/admin_area/settings/rate_limit_on_pipelines_creation.md)
- [Incident management rate limits](../user/admin_area/settings/incident_management_rate_limits.md)
You can set these rate limits using the Rails console:

View File

@ -0,0 +1,38 @@
---
type: reference
stage: Monitor
group: Respond
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Incident management rate limits **(ULTIMATE SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17859) in GitLab 12.5.
You can limit the number of inbound alerts for [incidents](../../../operations/incident_management/incidents.md)
that can be created in a period of time. The inbound [incident management](../../../operations/incident_management/index.md)
alert limit can help prevent overloading your incident responders by reducing the
number of alerts or duplicate issues.
As an example, if you set a limit of `10` requests every `60` seconds,
and `11` requests are sent to an [alert integration endpoint](../../../operations/incident_management/integrations.md) within one minute,
the eleventh request is blocked. Access to the endpoint is allowed again after one minute.
This limit is:
- Applied independently per project.
- Not applied per IP address.
- Disabled by default.
Requests that exceed the limit are logged into `auth.log`.
## Set a limit on inbound alerts
To set inbound incident management alert limits:
1. On the top bar, select **Menu > Admin**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Incident Management Limits**.
1. Select the **Enable Incident Management inbound alert limit** checkbox.
1. Optional. Input a custom value for **Maximum requests per project per rate limit period**. Default is 3600.
1. Optional. Input a custom value for **Rate limit period**. Default is 3600 seconds.

View File

@ -1,5 +1,5 @@
---
stage: Growth
stage: Analytics
group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -344,6 +344,7 @@ after the limits change in January, 2021:
| **GitLab Pages** requests (for a given **IP address**) | | **1000** requests per **50 seconds** |
| **GitLab Pages** requests (for a given **GitLab Pages domain**) | | **5000** requests per **10 seconds** |
| **Pipeline creation** requests (for a given **project, user, and commit**) | | **25** requests per minute |
| **Alert integration endpoint** requests (for a given **project**) | | **3600** requests per hour |
More details are available on the rate limits for [protected
paths](#protected-paths-throttle) and [raw

View File

@ -27,7 +27,7 @@ RSpec.describe 'Mini Pipeline Graph in Commit View', :js do
end
it 'displays a mini pipeline graph' do
expect(page).to have_selector('[data-testid="commit-box-mini-graph"]')
expect(page).to have_selector('[data-testid="commit-box-pipeline-mini-graph"]')
first('[data-testid="mini-pipeline-graph-dropdown"]').click

View File

@ -167,14 +167,14 @@ RSpec.describe 'Projects > Settings > Repository settings' do
expect(project.remote_mirrors.first.only_protected_branches).to eq(false)
end
it 'creates a push mirror that only mirrors protected branches', :js do
it 'creates a push mirror that only mirrors protected branches', :js,
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/337394' do
find('#only_protected_branches').click
expect(find('.js-mirror-protected-hidden', visible: false).value).to eq('1')
fill_in 'url', with: 'ssh://user@localhost/project.git'
select 'SSH public key', from: 'Authentication method'
select_direction
Sidekiq::Testing.fake! do

View File

@ -6,6 +6,7 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import CommitBoxPipelineMiniGraph from '~/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
import getPipelineStagesQuery from '~/projects/commit_box/info/graphql/queries/get_pipeline_stages.query.graphql';
import { mockPipelineStagesQueryResponse, mockStages } from './mock_data';
@ -17,9 +18,7 @@ Vue.use(VueApollo);
describe('Commit box pipeline mini graph', () => {
let wrapper;
const findMiniGraph = () => wrapper.findByTestId('commit-box-mini-graph');
const findUpstream = () => wrapper.findByTestId('commit-box-mini-graph-upstream');
const findDownstream = () => wrapper.findByTestId('commit-box-mini-graph-downstream');
const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
const stagesHandler = jest.fn().mockResolvedValue(mockPipelineStagesQueryResponse);
@ -51,13 +50,16 @@ describe('Commit box pipeline mini graph', () => {
await createComponent();
});
it('should display the mini pipeine graph', () => {
expect(findMiniGraph().exists()).toBe(true);
it('should display the pipeline mini graph', () => {
expect(findPipelineMiniGraph().exists()).toBe(true);
});
it('should not display linked pipelines', () => {
expect(findUpstream().exists()).toBe(false);
expect(findDownstream().exists()).toBe(false);
const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
expect(downstreamPipelines).toHaveLength(0);
expect(upstreamPipeline).toEqual(undefined);
});
});

View File

@ -0,0 +1,109 @@
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
import { PIPELINE_FAILURE } from '~/pipeline_editor/constants';
import { mockLinkedPipelines, mockProjectFullPath, mockProjectPipeline } from '../../mock_data';
Vue.use(VueApollo);
describe('Pipeline Status', () => {
let wrapper;
let mockApollo;
let mockLinkedPipelinesQuery;
const createComponent = ({ hasStages = true, options } = {}) => {
wrapper = shallowMount(PipelineEditorMiniGraph, {
provide: {
dataMethod: 'graphql',
projectFullPath: mockProjectFullPath,
},
propsData: {
pipeline: mockProjectPipeline({ hasStages }).pipeline,
},
...options,
});
};
const createComponentWithApollo = (hasStages = true) => {
const handlers = [[getLinkedPipelinesQuery, mockLinkedPipelinesQuery]];
mockApollo = createMockApollo(handlers);
createComponent({
hasStages,
options: {
apolloProvider: mockApollo,
},
});
};
const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
beforeEach(() => {
mockLinkedPipelinesQuery = jest.fn();
});
afterEach(() => {
mockLinkedPipelinesQuery.mockReset();
wrapper.destroy();
});
describe('when there are stages', () => {
beforeEach(() => {
createComponent();
});
it('renders pipeline mini graph', () => {
expect(findPipelineMiniGraph().exists()).toBe(true);
});
});
describe('when there are no stages', () => {
beforeEach(() => {
createComponent({ hasStages: false });
});
it('does not render pipeline mini graph', () => {
expect(findPipelineMiniGraph().exists()).toBe(false);
});
});
describe('when querying upstream and downstream pipelines', () => {
describe('when query succeeds', () => {
beforeEach(() => {
mockLinkedPipelinesQuery.mockResolvedValue(mockLinkedPipelines());
createComponentWithApollo();
});
it('should call the query with the correct variables', () => {
expect(mockLinkedPipelinesQuery).toHaveBeenCalledTimes(1);
expect(mockLinkedPipelinesQuery).toHaveBeenCalledWith({
fullPath: mockProjectFullPath,
iid: mockProjectPipeline().pipeline.iid,
});
});
});
describe('when query fails', () => {
beforeEach(async () => {
mockLinkedPipelinesQuery.mockRejectedValue(new Error());
createComponentWithApollo();
await waitForPromises();
});
it('should emit an error event when query fails', async () => {
expect(wrapper.emitted('showError')).toHaveLength(1);
expect(wrapper.emitted('showError')[0]).toEqual([
{
type: PIPELINE_FAILURE,
reasons: [wrapper.vm.$options.i18n.linkedPipelinesFetchError],
},
]);
});
});
});
});

View File

@ -1,18 +1,18 @@
import { shallowMount } from '@vue/test-utils';
import { pipelines } from 'test_fixtures/pipelines/pipelines.json';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue';
import PipelineStages from '~/pipelines/components/pipelines_list/pipeline_stages.vue';
const mockStages = pipelines[0].details.stages;
describe('Pipeline Mini Graph', () => {
describe('Pipeline Stages', () => {
let wrapper;
const findPipelineStages = () => wrapper.findAll(PipelineStage);
const findPipelineStagesAt = (i) => findPipelineStages().at(i);
const createComponent = (props = {}) => {
wrapper = shallowMount(PipelineMiniGraph, {
wrapper = shallowMount(PipelineStages, {
propsData: {
stages: mockStages,
...props,

View File

@ -0,0 +1,407 @@
export default {
triggered_by: {
id: 129,
active: true,
path: '/gitlab-org/gitlab-foss/-/pipelines/129',
project: {
name: 'GitLabCE',
},
details: {
status: {
icon: 'status_running',
text: 'running',
label: 'running',
group: 'running',
has_details: true,
details_path: '/gitlab-org/gitlab-foss/-/pipelines/129',
favicon:
'/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
},
},
flags: {
latest: false,
triggered: false,
stuck: false,
yaml_errors: false,
retryable: true,
cancelable: true,
},
ref: {
name: '7-5-stable',
path: '/gitlab-org/gitlab-foss/commits/7-5-stable',
tag: false,
branch: true,
},
commit: {
id: '23433d4d8b20d7e45c103d0b6048faad38a130ab',
short_id: '23433d4d',
title: 'Version 7.5.0.rc1',
created_at: '2014-11-17T15:44:14.000+01:00',
parent_ids: ['30ac909f30f58d319b42ed1537664483894b18cd'],
message: 'Version 7.5.0.rc1\n',
author_name: 'Jacob Vosmaer',
author_email: 'contact@jacobvosmaer.nl',
authored_date: '2014-11-17T15:44:14.000+01:00',
committer_name: 'Jacob Vosmaer',
committer_email: 'contact@jacobvosmaer.nl',
committed_date: '2014-11-17T15:44:14.000+01:00',
author_gravatar_url:
'http://www.gravatar.com/avatar/e66d11c0eedf8c07b3b18fca46599807?s=80&d=identicon',
commit_url:
'http://localhost:3000/gitlab-org/gitlab-foss/commit/23433d4d8b20d7e45c103d0b6048faad38a130ab',
commit_path: '/gitlab-org/gitlab-foss/commit/23433d4d8b20d7e45c103d0b6048faad38a130ab',
},
retry_path: '/gitlab-org/gitlab-foss/-/pipelines/129/retry',
cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/129/cancel',
created_at: '2017-05-24T14:46:20.090Z',
updated_at: '2017-05-24T14:46:29.906Z',
},
triggered: [
{
id: 132,
active: true,
path: '/gitlab-org/gitlab-foss/-/pipelines/132',
project: {
name: 'GitLabCE',
},
details: {
status: {
icon: 'status_running',
text: 'running',
label: 'running',
group: 'running',
has_details: true,
details_path: '/gitlab-org/gitlab-foss/-/pipelines/132',
favicon:
'/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
},
},
flags: {
latest: false,
triggered: false,
stuck: false,
yaml_errors: false,
retryable: true,
cancelable: true,
},
ref: {
name: 'crowd',
path: '/gitlab-org/gitlab-foss/commits/crowd',
tag: false,
branch: true,
},
commit: {
id: 'b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
short_id: 'b9d58c4c',
title: 'getting user keys publically through http without any authentication, the github…',
created_at: '2013-10-03T12:50:33.000+05:30',
parent_ids: ['e219cf7246c6a0495e4507deaffeba11e79f13b8'],
message:
'getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n\nchangelog updated to include ssh key retrieval feature update\n',
author_name: 'devaroop',
author_email: 'devaroop123@yahoo.co.in',
authored_date: '2013-10-02T20:39:29.000+05:30',
committer_name: 'devaroop',
committer_email: 'devaroop123@yahoo.co.in',
committed_date: '2013-10-03T12:50:33.000+05:30',
author_gravatar_url:
'http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon',
commit_url:
'http://localhost:3000/gitlab-org/gitlab-foss/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
commit_path: '/gitlab-org/gitlab-foss/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
},
retry_path: '/gitlab-org/gitlab-foss/-/pipelines/132/retry',
cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/132/cancel',
created_at: '2017-05-24T14:46:24.644Z',
updated_at: '2017-05-24T14:48:55.226Z',
},
{
id: 133,
active: true,
path: '/gitlab-org/gitlab-foss/-/pipelines/133',
project: {
name: 'GitLabCE',
},
details: {
status: {
icon: 'status_running',
text: 'running',
label: 'running',
group: 'running',
has_details: true,
details_path: '/gitlab-org/gitlab-foss/-/pipelines/133',
favicon:
'/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
},
},
flags: {
latest: false,
triggered: false,
stuck: false,
yaml_errors: false,
retryable: true,
cancelable: true,
},
ref: {
name: 'crowd',
path: '/gitlab-org/gitlab-foss/commits/crowd',
tag: false,
branch: true,
},
commit: {
id: 'b6bd4856a33df3d144be66c4ed1f1396009bb08b',
short_id: 'b6bd4856',
title: 'getting user keys publically through http without any authentication, the github…',
created_at: '2013-10-02T20:39:29.000+05:30',
parent_ids: ['e219cf7246c6a0495e4507deaffeba11e79f13b8'],
message:
'getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n',
author_name: 'devaroop',
author_email: 'devaroop123@yahoo.co.in',
authored_date: '2013-10-02T20:39:29.000+05:30',
committer_name: 'devaroop',
committer_email: 'devaroop123@yahoo.co.in',
committed_date: '2013-10-02T20:39:29.000+05:30',
author_gravatar_url:
'http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon',
commit_url:
'http://localhost:3000/gitlab-org/gitlab-foss/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b',
commit_path: '/gitlab-org/gitlab-foss/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b',
},
retry_path: '/gitlab-org/gitlab-foss/-/pipelines/133/retry',
cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/133/cancel',
created_at: '2017-05-24T14:46:24.648Z',
updated_at: '2017-05-24T14:48:59.673Z',
},
{
id: 130,
active: true,
path: '/gitlab-org/gitlab-foss/-/pipelines/130',
project: {
name: 'GitLabCE',
},
details: {
status: {
icon: 'status_running',
text: 'running',
label: 'running',
group: 'running',
has_details: true,
details_path: '/gitlab-org/gitlab-foss/-/pipelines/130',
favicon:
'/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
},
},
flags: {
latest: false,
triggered: false,
stuck: false,
yaml_errors: false,
retryable: true,
cancelable: true,
},
ref: {
name: 'crowd',
path: '/gitlab-org/gitlab-foss/commits/crowd',
tag: false,
branch: true,
},
commit: {
id: '6d7ced4a2311eeff037c5575cca1868a6d3f586f',
short_id: '6d7ced4a',
title: 'Whitespace fixes to patch',
created_at: '2013-10-08T13:53:22.000-05:00',
parent_ids: ['1875141a963a4238bda29011d8f7105839485253'],
message: 'Whitespace fixes to patch\n',
author_name: 'Dale Hamel',
author_email: 'dale.hamel@srvthe.net',
authored_date: '2013-10-08T13:53:22.000-05:00',
committer_name: 'Dale Hamel',
committer_email: 'dale.hamel@invenia.ca',
committed_date: '2013-10-08T13:53:22.000-05:00',
author_gravatar_url:
'http://www.gravatar.com/avatar/cd08930e69fa5ad1a669206e7bafe476?s=80&d=identicon',
commit_url:
'http://localhost:3000/gitlab-org/gitlab-foss/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f',
commit_path: '/gitlab-org/gitlab-foss/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f',
},
retry_path: '/gitlab-org/gitlab-foss/-/pipelines/130/retry',
cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/130/cancel',
created_at: '2017-05-24T14:46:24.630Z',
updated_at: '2017-05-24T14:49:45.091Z',
},
{
id: 131,
active: true,
path: '/gitlab-org/gitlab-foss/-/pipelines/132',
project: {
name: 'GitLabCE',
},
details: {
status: {
icon: 'status_running',
text: 'running',
label: 'running',
group: 'running',
has_details: true,
details_path: '/gitlab-org/gitlab-foss/-/pipelines/132',
favicon:
'/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
},
},
flags: {
latest: false,
triggered: false,
stuck: false,
yaml_errors: false,
retryable: true,
cancelable: true,
},
ref: {
name: 'crowd',
path: '/gitlab-org/gitlab-foss/commits/crowd',
tag: false,
branch: true,
},
commit: {
id: 'b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
short_id: 'b9d58c4c',
title: 'getting user keys publically through http without any authentication, the github…',
created_at: '2013-10-03T12:50:33.000+05:30',
parent_ids: ['e219cf7246c6a0495e4507deaffeba11e79f13b8'],
message:
'getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n\nchangelog updated to include ssh key retrieval feature update\n',
author_name: 'devaroop',
author_email: 'devaroop123@yahoo.co.in',
authored_date: '2013-10-02T20:39:29.000+05:30',
committer_name: 'devaroop',
committer_email: 'devaroop123@yahoo.co.in',
committed_date: '2013-10-03T12:50:33.000+05:30',
author_gravatar_url:
'http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon',
commit_url:
'http://localhost:3000/gitlab-org/gitlab-foss/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
commit_path: '/gitlab-org/gitlab-foss/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
},
retry_path: '/gitlab-org/gitlab-foss/-/pipelines/132/retry',
cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/132/cancel',
created_at: '2017-05-24T14:46:24.644Z',
updated_at: '2017-05-24T14:48:55.226Z',
},
{
id: 134,
active: true,
path: '/gitlab-org/gitlab-foss/-/pipelines/133',
project: {
name: 'GitLabCE',
},
details: {
status: {
icon: 'status_running',
text: 'running',
label: 'running',
group: 'running',
has_details: true,
details_path: '/gitlab-org/gitlab-foss/-/pipelines/133',
favicon:
'/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
},
},
flags: {
latest: false,
triggered: false,
stuck: false,
yaml_errors: false,
retryable: true,
cancelable: true,
},
ref: {
name: 'crowd',
path: '/gitlab-org/gitlab-foss/commits/crowd',
tag: false,
branch: true,
},
commit: {
id: 'b6bd4856a33df3d144be66c4ed1f1396009bb08b',
short_id: 'b6bd4856',
title: 'getting user keys publically through http without any authentication, the github…',
created_at: '2013-10-02T20:39:29.000+05:30',
parent_ids: ['e219cf7246c6a0495e4507deaffeba11e79f13b8'],
message:
'getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n',
author_name: 'devaroop',
author_email: 'devaroop123@yahoo.co.in',
authored_date: '2013-10-02T20:39:29.000+05:30',
committer_name: 'devaroop',
committer_email: 'devaroop123@yahoo.co.in',
committed_date: '2013-10-02T20:39:29.000+05:30',
author_gravatar_url:
'http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon',
commit_url:
'http://localhost:3000/gitlab-org/gitlab-foss/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b',
commit_path: '/gitlab-org/gitlab-foss/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b',
},
retry_path: '/gitlab-org/gitlab-foss/-/pipelines/133/retry',
cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/133/cancel',
created_at: '2017-05-24T14:46:24.648Z',
updated_at: '2017-05-24T14:48:59.673Z',
},
{
id: 135,
active: true,
path: '/gitlab-org/gitlab-foss/-/pipelines/130',
project: {
name: 'GitLabCE',
},
details: {
status: {
icon: 'status_running',
text: 'running',
label: 'running',
group: 'running',
has_details: true,
details_path: '/gitlab-org/gitlab-foss/-/pipelines/130',
favicon:
'/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
},
},
flags: {
latest: false,
triggered: false,
stuck: false,
yaml_errors: false,
retryable: true,
cancelable: true,
},
ref: {
name: 'crowd',
path: '/gitlab-org/gitlab-foss/commits/crowd',
tag: false,
branch: true,
},
commit: {
id: '6d7ced4a2311eeff037c5575cca1868a6d3f586f',
short_id: '6d7ced4a',
title: 'Whitespace fixes to patch',
created_at: '2013-10-08T13:53:22.000-05:00',
parent_ids: ['1875141a963a4238bda29011d8f7105839485253'],
message: 'Whitespace fixes to patch\n',
author_name: 'Dale Hamel',
author_email: 'dale.hamel@srvthe.net',
authored_date: '2013-10-08T13:53:22.000-05:00',
committer_name: 'Dale Hamel',
committer_email: 'dale.hamel@invenia.ca',
committed_date: '2013-10-08T13:53:22.000-05:00',
author_gravatar_url:
'http://www.gravatar.com/avatar/cd08930e69fa5ad1a669206e7bafe476?s=80&d=identicon',
commit_url:
'http://localhost:3000/gitlab-org/gitlab-foss/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f',
commit_path: '/gitlab-org/gitlab-foss/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f',
},
retry_path: '/gitlab-org/gitlab-foss/-/pipelines/130/retry',
cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/130/cancel',
created_at: '2017-05-24T14:46:24.630Z',
updated_at: '2017-05-24T14:49:45.091Z',
},
],
};

View File

@ -0,0 +1,149 @@
import { mount } from '@vue/test-utils';
import { pipelines } from 'test_fixtures/pipelines/pipelines.json';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import PipelineStages from '~/pipelines/components/pipelines_list/pipeline_stages.vue';
import mockLinkedPipelines from './linked_pipelines_mock_data';
const mockStages = pipelines[0].details.stages;
describe('Pipeline Mini Graph', () => {
let wrapper;
const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
const findPipelineStages = () => wrapper.findComponent(PipelineStages);
const findLinkedPipelineUpstream = () =>
wrapper.findComponent('[data-testid="pipeline-mini-graph-upstream"]');
const findLinkedPipelineDownstream = () =>
wrapper.findComponent('[data-testid="pipeline-mini-graph-downstream"]');
const findDownstreamArrowIcon = () => wrapper.find('[data-testid="downstream-arrow-icon"]');
const findUpstreamArrowIcon = () => wrapper.find('[data-testid="upstream-arrow-icon"]');
const createComponent = (props = {}) => {
wrapper = mount(PipelineMiniGraph, {
propsData: {
stages: mockStages,
...props,
},
});
};
describe('rendered state without upstream or downstream pipelines', () => {
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('should render the pipeline stages', () => {
expect(findPipelineStages().exists()).toBe(true);
});
it('should have the correct props', () => {
expect(findPipelineMiniGraph().props()).toMatchObject({
downstreamPipelines: [],
isMergeTrain: false,
pipelinePath: '',
stages: expect.any(Array),
stagesClass: '',
updateDropdown: false,
upstreamPipeline: undefined,
});
});
it('should have no linked pipelines', () => {
expect(findLinkedPipelineDownstream().exists()).toBe(false);
expect(findLinkedPipelineUpstream().exists()).toBe(false);
});
it('should not render arrow icons', () => {
expect(findUpstreamArrowIcon().exists()).toBe(false);
expect(findDownstreamArrowIcon().exists()).toBe(false);
});
it('triggers events in "action request complete"', () => {
createComponent();
findPipelineMiniGraph(0).vm.$emit('pipelineActionRequestComplete');
findPipelineMiniGraph(1).vm.$emit('pipelineActionRequestComplete');
expect(wrapper.emitted('pipelineActionRequestComplete')).toHaveLength(2);
});
});
describe('rendered state with upstream pipeline', () => {
beforeEach(() => {
createComponent({
upstreamPipeline: mockLinkedPipelines.triggered_by,
});
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('should have the correct props', () => {
expect(findPipelineMiniGraph().props()).toMatchObject({
downstreamPipelines: [],
isMergeTrain: false,
pipelinePath: '',
stages: expect.any(Array),
stagesClass: '',
updateDropdown: false,
upstreamPipeline: expect.any(Object),
});
});
it('should render the upstream linked pipelines mini list only', () => {
expect(findLinkedPipelineUpstream().exists()).toBe(true);
expect(findLinkedPipelineDownstream().exists()).toBe(false);
});
it('should render an upstream arrow icon only', () => {
expect(findDownstreamArrowIcon().exists()).toBe(false);
expect(findUpstreamArrowIcon().exists()).toBe(true);
expect(findUpstreamArrowIcon().props('name')).toBe('long-arrow');
});
});
describe('rendered state with downstream pipelines', () => {
beforeEach(() => {
createComponent({
downstreamPipelines: mockLinkedPipelines.triggered,
pipelinePath: 'my/pipeline/path',
});
});
it('should have the correct props', () => {
expect(findPipelineMiniGraph().props()).toMatchObject({
downstreamPipelines: expect.any(Array),
isMergeTrain: false,
pipelinePath: 'my/pipeline/path',
stages: expect.any(Array),
stagesClass: '',
updateDropdown: false,
upstreamPipeline: undefined,
});
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('should render the downstream linked pipelines mini list only', () => {
expect(findLinkedPipelineDownstream().exists()).toBe(true);
expect(findLinkedPipelineUpstream().exists()).toBe(false);
});
it('should render a downstream arrow icon only', () => {
expect(findUpstreamArrowIcon().exists()).toBe(false);
expect(findDownstreamArrowIcon().exists()).toBe(true);
expect(findDownstreamArrowIcon().props('name')).toBe('long-arrow');
});
});
});

View File

@ -113,40 +113,28 @@ describe('Pipelines Table', () => {
});
describe('stages cell', () => {
it('should render a pipeline mini graph', () => {
it('should render pipeline mini graph', () => {
expect(findPipelineMiniGraph().exists()).toBe(true);
});
it('should render the right number of stages', () => {
const stagesLength = pipeline.details.stages.length;
expect(
findPipelineMiniGraph().findAll('[data-testid="mini-pipeline-graph-dropdown"]'),
).toHaveLength(stagesLength);
expect(findPipelineMiniGraph().props('stages').length).toBe(stagesLength);
});
describe('when pipeline does not have stages', () => {
beforeEach(() => {
pipeline = createMockPipeline();
pipeline.details.stages = null;
pipeline.details.stages = [];
createComponent({ pipelines: [pipeline] });
});
it('stages are not rendered', () => {
expect(findPipelineMiniGraph().exists()).toBe(false);
expect(findPipelineMiniGraph().props('stages')).toHaveLength(0);
});
});
it('should not update dropdown', () => {
expect(findPipelineMiniGraph().props('updateDropdown')).toBe(false);
});
it('when update graph dropdown is set, should update graph dropdown', () => {
createComponent({ pipelines: [pipeline], updateGraphDropdown: true });
expect(findPipelineMiniGraph().props('updateDropdown')).toBe(true);
});
it('when action request is complete, should refresh table', () => {
findPipelineMiniGraph().vm.$emit('pipelineActionRequestComplete');

View File

@ -4,9 +4,8 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { trimText } from 'helpers/text_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import MRWidgetPipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue';
import PipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
import { SUCCESS } from '~/vue_merge_request_widget/constants';
import mockData from '../mock_data';
@ -30,14 +29,13 @@ describe('MRWidgetPipeline', () => {
const findPipelineInfoContainer = () => wrapper.findByTestId('pipeline-info-container');
const findCommitLink = () => wrapper.findByTestId('commit-link');
const findPipelineFinishedAt = () => wrapper.findByTestId('finished-at');
const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
const findAllPipelineStages = () => wrapper.findAllComponents(PipelineStage);
const findPipelineCoverage = () => wrapper.findByTestId('pipeline-coverage');
const findPipelineCoverageDelta = () => wrapper.findByTestId('pipeline-coverage-delta');
const findPipelineCoverageTooltipText = () =>
wrapper.findByTestId('pipeline-coverage-tooltip').text();
const findPipelineCoverageDeltaTooltipText = () =>
wrapper.findByTestId('pipeline-coverage-delta-tooltip').text();
const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
const findMonitoringPipelineMessage = () => wrapper.findByTestId('monitoring-pipeline-message');
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
@ -45,7 +43,7 @@ describe('MRWidgetPipeline', () => {
const createWrapper = (props = {}, mountFn = shallowMount) => {
wrapper = extendedWrapper(
mountFn(PipelineComponent, {
mountFn(MRWidgetPipelineComponent, {
propsData: {
...defaultProps,
...props,
@ -106,8 +104,10 @@ describe('MRWidgetPipeline', () => {
});
it('should render pipeline graph', () => {
const stagesCount = mockData.pipeline.details.stages.length;
expect(findPipelineMiniGraph().exists()).toBe(true);
expect(findAllPipelineStages()).toHaveLength(mockData.pipeline.details.stages.length);
expect(findPipelineMiniGraph().props('stages')).toHaveLength(stagesCount);
});
describe('should render pipeline coverage information', () => {
@ -176,15 +176,11 @@ describe('MRWidgetPipeline', () => {
expect(findPipelineInfoContainer().text()).toMatch(mockData.pipeline.details.status.label);
});
it('should render pipeline graph with correct styles', () => {
it('should render pipeline graph', () => {
const stagesCount = mockData.pipeline.details.stages.length;
expect(findPipelineMiniGraph().exists()).toBe(true);
expect(findPipelineMiniGraph().findAll('.mr-widget-pipeline-stages')).toHaveLength(
stagesCount,
);
expect(findAllPipelineStages()).toHaveLength(stagesCount);
expect(findPipelineMiniGraph().props('stages')).toHaveLength(stagesCount);
});
it('should render coverage information', () => {

View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
require 'set'
module Support
# Ensure that finders' `execute` method always returns
# `ActiveRecord::Relation`.
#
# See https://gitlab.com/gitlab-org/gitlab/-/issues/298771
module FinderCollection
def self.install_check(finder_class)
return unless check?(finder_class)
finder_class.prepend CheckResult
end
ALLOWLIST_YAML = File.join(__dir__, 'finder_collection_allowlist.yml')
def self.check?(finder_class)
@allowlist ||= YAML.load_file(ALLOWLIST_YAML).to_set
@allowlist.exclude?(finder_class.name)
end
module CheckResult
def execute(...)
result = super
unless result.is_a?(ActiveRecord::Relation)
raise <<~MESSAGE
#{self.class}#execute returned `#{result.class}` instead of `ActiveRecord::Relation`.
All finder classes are expected to return `ActiveRecord::Relation`.
Read more at https://docs.gitlab.com/ee/development/reusing_abstractions.html#finders
MESSAGE
end
result
end
end
end
end
RSpec.configure do |config|
config.before(:all, type: :finder) do
Support::FinderCollection.install_check(described_class)
end
end

View File

@ -0,0 +1,66 @@
# Allow list for spec/support/finder_collection.rb
# Permenant excludes
# For example:
# FooFinder # Reason: It uses a memory backend
# Temporary excludes (aka TODOs)
# For example:
# BarFinder # See <ISSUE_URL>
- AccessRequestsFinder
- Admin::PlansFinder
- Analytics::CycleAnalytics::StageFinder
- ApplicationsFinder
- Autocomplete::GroupFinder
- Autocomplete::ProjectFinder
- Autocomplete::UsersFinder
- BilledUsersFinder
- Boards::BoardsFinder
- Boards::VisitsFinder
- BranchesFinder
- Ci::AuthJobFinder
- Ci::CommitStatusesFinder
- Ci::DailyBuildGroupReportResultsFinder
- ClusterAncestorsFinder
- Clusters::AgentAuthorizationsFinder
- Clusters::KubernetesNamespaceFinder
- ComplianceManagement::MergeRequests::ComplianceViolationsFinder
- ContainerRepositoriesFinder
- ContextCommitsFinder
- Environments::EnvironmentNamesFinder
- Environments::EnvironmentsByDeploymentsFinder
- EventsFinder
- GroupDescendantsFinder
- Groups::ProjectsRequiringAuthorizationsRefresh::OnDirectMembershipFinder
- Groups::ProjectsRequiringAuthorizationsRefresh::OnTransferFinder
- KeysFinder
- LfsPointersFinder
- LicenseTemplateFinder
- MergeRequests::OldestPerCommitFinder
- NotesFinder
- Packages::BuildInfosFinder
- Packages::Conan::PackageFileFinder
- Packages::Go::ModuleFinder
- Packages::Go::PackageFinder
- Packages::Go::VersionFinder
- Packages::PackageFileFinder
- Packages::PackageFinder
- Packages::Pypi::PackageFinder
- Projects::Integrations::Jira::ByIdsFinder
- Projects::Integrations::Jira::IssuesFinder
- Releases::EvidencePipelineFinder
- Repositories::BranchNamesFinder
- Repositories::ChangelogTagFinder
- Repositories::TreeFinder
- Security::FindingsFinder
- Security::PipelineVulnerabilitiesFinder
- Security::ScanExecutionPoliciesFinder
- Security::TrainingProviders::BaseUrlFinder
- Security::TrainingUrlsFinder
- SentryIssueFinder
- ServerlessDomainFinder
- TagsFinder
- TemplateFinder
- UploaderFinder
- UserGroupNotificationSettingsFinder
- UserGroupsCounter