Commit 7e894559 authored by Sarah Groff Hennigh-Palermo's avatar Sarah Groff Hennigh-Palermo

Merge branch 'pipeline/fix-header-status-update' into 'master'

Update pipeline header status when retrying jobs

See merge request gitlab-org/gitlab!66764
parents ea31f75a 5dd7a0a3
...@@ -7,6 +7,7 @@ import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; ...@@ -7,6 +7,7 @@ import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants'; import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants';
import DismissPipelineGraphCallout from '../../graphql/mutations/dismiss_pipeline_notification.graphql'; import DismissPipelineGraphCallout from '../../graphql/mutations/dismiss_pipeline_notification.graphql';
import getPipelineQuery from '../../graphql/queries/get_pipeline_header_data.query.graphql';
import { reportToSentry, reportMessageToSentry } from '../../utils'; import { reportToSentry, reportMessageToSentry } from '../../utils';
import { listByLayers } from '../parsing_utils'; import { listByLayers } from '../parsing_utils';
import { IID_FAILURE, LAYER_VIEW, STAGE_VIEW, VIEW_TYPE_KEY } from './constants'; import { IID_FAILURE, LAYER_VIEW, STAGE_VIEW, VIEW_TYPE_KEY } from './constants';
...@@ -51,6 +52,7 @@ export default { ...@@ -51,6 +52,7 @@ export default {
alertType: null, alertType: null,
callouts: [], callouts: [],
currentViewType: STAGE_VIEW, currentViewType: STAGE_VIEW,
canRefetchHeaderPipeline: false,
pipeline: null, pipeline: null,
pipelineLayers: null, pipelineLayers: null,
showAlert: false, showAlert: false,
...@@ -78,6 +80,26 @@ export default { ...@@ -78,6 +80,26 @@ export default {
); );
}, },
}, },
headerPipeline: {
query: getPipelineQuery,
// this query is already being called in header_component.vue, which shares the same cache as this component
// the skip here is to prevent sending double network requests on page load
skip() {
return !this.canRefetchHeaderPipeline;
},
variables() {
return {
fullPath: this.pipelineProjectPath,
iid: this.pipelineIid,
};
},
update(data) {
return data.project?.pipeline || {};
},
error() {
this.reportFailure({ type: LOAD_FAILURE, skipSentry: true });
},
},
pipeline: { pipeline: {
context() { context() {
return getQueryHeaders(this.graphqlResourceEtag); return getQueryHeaders(this.graphqlResourceEtag);
...@@ -217,6 +239,10 @@ export default { ...@@ -217,6 +239,10 @@ export default {
}, },
refreshPipelineGraph() { refreshPipelineGraph() {
this.$apollo.queries.pipeline.refetch(); this.$apollo.queries.pipeline.refetch();
// this will update the status in header_component since they share the same cache
this.canRefetchHeaderPipeline = true;
this.$apollo.queries.headerPipeline.refetch();
}, },
/* eslint-disable @gitlab/require-i18n-strings */ /* eslint-disable @gitlab/require-i18n-strings */
reportFailure({ type, err = 'No error string passed.', skipSentry = false }) { reportFailure({ type, err = 'No error string passed.', skipSentry = false }) {
......
...@@ -143,13 +143,6 @@ export default { ...@@ -143,13 +143,6 @@ export default {
return cancelable && userPermissions.updatePipeline; return cancelable && userPermissions.updatePipeline;
}, },
}, },
watch: {
isFinished(finished) {
if (finished) {
this.$apollo.queries.pipeline.stopPolling();
}
},
},
methods: { methods: {
reportFailure(errorType) { reportFailure(errorType) {
this.failureType = errorType; this.failureType = errorType;
...@@ -218,7 +211,7 @@ export default { ...@@ -218,7 +211,7 @@ export default {
}; };
</script> </script>
<template> <template>
<div class="pipeline-header-container"> <div class="js-pipeline-header-container">
<gl-alert v-if="hasError" :variant="failure.variant">{{ failure.text }}</gl-alert> <gl-alert v-if="hasError" :variant="failure.variant">{{ failure.text }}</gl-alert>
<ci-header <ci-header
v-if="shouldRenderContent" v-if="shouldRenderContent"
......
...@@ -240,10 +240,14 @@ RSpec.describe 'Pipeline', :js do ...@@ -240,10 +240,14 @@ RSpec.describe 'Pipeline', :js do
end end
end end
it 'is possible to retry the success job' do it 'is possible to retry the success job', :sidekiq_might_not_need_inline do
find('#ci-badge-build .ci-action-icon-container').click find('#ci-badge-build .ci-action-icon-container').click
wait_for_requests
expect(page).not_to have_content('Retry job') expect(page).not_to have_content('Retry job')
within('.js-pipeline-header-container') do
expect(page).to have_selector('.js-ci-status-icon-running')
end
end end
end end
...@@ -282,10 +286,14 @@ RSpec.describe 'Pipeline', :js do ...@@ -282,10 +286,14 @@ RSpec.describe 'Pipeline', :js do
end end
end end
it 'is possible to retry the failed build' do it 'is possible to retry the failed build', :sidekiq_might_not_need_inline do
find('#ci-badge-test .ci-action-icon-container').click find('#ci-badge-test .ci-action-icon-container').click
wait_for_requests
expect(page).not_to have_content('Retry job') expect(page).not_to have_content('Retry job')
within('.js-pipeline-header-container') do
expect(page).to have_selector('.js-ci-status-icon-running')
end
end end
it 'includes the failure reason' do it 'includes the failure reason' do
...@@ -308,10 +316,14 @@ RSpec.describe 'Pipeline', :js do ...@@ -308,10 +316,14 @@ RSpec.describe 'Pipeline', :js do
end end
end end
it 'is possible to play the manual job' do it 'is possible to play the manual job', :sidekiq_might_not_need_inline do
find('#ci-badge-manual-build .ci-action-icon-container').click find('#ci-badge-manual-build .ci-action-icon-container').click
wait_for_requests
expect(page).not_to have_content('Play job') expect(page).not_to have_content('Play job')
within('.js-pipeline-header-container') do
expect(page).to have_selector('.js-ci-status-icon-running')
end
end end
end end
...@@ -411,11 +423,18 @@ RSpec.describe 'Pipeline', :js do ...@@ -411,11 +423,18 @@ RSpec.describe 'Pipeline', :js do
context 'when retrying' do context 'when retrying' do
before do before do
find('[data-testid="retryPipeline"]').click find('[data-testid="retryPipeline"]').click
wait_for_requests
end end
it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do
expect(page).not_to have_content('Retry') expect(page).not_to have_content('Retry')
end end
it 'shows running status in pipeline header', :sidekiq_might_not_need_inline do
within('.js-pipeline-header-container') do
expect(page).to have_selector('.js-ci-status-icon-running')
end
end
end end
end end
...@@ -770,7 +789,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -770,7 +789,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as created' do it 'shows deploy job as created' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('pending') expect(page).to have_content('pending')
end end
...@@ -795,7 +814,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -795,7 +814,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as pending' do it 'shows deploy job as pending' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('running') expect(page).to have_content('running')
end end
...@@ -817,7 +836,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -817,7 +836,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as created' do it 'shows deploy job as created' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('pending') expect(page).to have_content('pending')
end end
...@@ -842,7 +861,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -842,7 +861,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as pending' do it 'shows deploy job as pending' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('running') expect(page).to have_content('running')
end end
...@@ -871,7 +890,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -871,7 +890,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as waiting for resource' do it 'shows deploy job as waiting for resource' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('waiting') expect(page).to have_content('waiting')
end end
...@@ -893,7 +912,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -893,7 +912,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as waiting for resource' do it 'shows deploy job as waiting for resource' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('waiting') expect(page).to have_content('waiting')
end end
...@@ -914,7 +933,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -914,7 +933,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as pending' do it 'shows deploy job as pending' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('running') expect(page).to have_content('running')
end end
...@@ -936,7 +955,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -936,7 +955,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as pending' do it 'shows deploy job as pending' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('running') expect(page).to have_content('running')
end end
...@@ -959,7 +978,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -959,7 +978,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as waiting for resource' do it 'shows deploy job as waiting for resource' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('waiting') expect(page).to have_content('waiting')
end end
...@@ -981,7 +1000,7 @@ RSpec.describe 'Pipeline', :js do ...@@ -981,7 +1000,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows deploy job as waiting for resource' do it 'shows deploy job as waiting for resource' do
subject subject
within('.pipeline-header-container') do within('.js-pipeline-header-container') do
expect(page).to have_content('waiting') expect(page).to have_content('waiting')
end end
......
...@@ -18,6 +18,8 @@ import GraphViewSelector from '~/pipelines/components/graph/graph_view_selector. ...@@ -18,6 +18,8 @@ import GraphViewSelector from '~/pipelines/components/graph/graph_view_selector.
import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue'; import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue'; import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue';
import * as parsingUtils from '~/pipelines/components/parsing_utils'; import * as parsingUtils from '~/pipelines/components/parsing_utils';
import getPipelineHeaderData from '~/pipelines/graphql/queries/get_pipeline_header_data.query.graphql';
import { mockRunningPipelineHeaderData } from '../mock_data';
import { mapCallouts, mockCalloutsResponse, mockPipelineResponse } from './mock_data'; import { mapCallouts, mockCalloutsResponse, mockPipelineResponse } from './mock_data';
const defaultProvide = { const defaultProvide = {
...@@ -72,8 +74,10 @@ describe('Pipeline graph wrapper', () => { ...@@ -72,8 +74,10 @@ describe('Pipeline graph wrapper', () => {
} = {}) => { } = {}) => {
const callouts = mapCallouts(calloutsList); const callouts = mapCallouts(calloutsList);
const getUserCalloutsHandler = jest.fn().mockResolvedValue(mockCalloutsResponse(callouts)); const getUserCalloutsHandler = jest.fn().mockResolvedValue(mockCalloutsResponse(callouts));
const getPipelineHeaderDataHandler = jest.fn().mockResolvedValue(mockRunningPipelineHeaderData);
const requestHandlers = [ const requestHandlers = [
[getPipelineHeaderData, getPipelineHeaderDataHandler],
[getPipelineDetails, getPipelineDetailsHandler], [getPipelineDetails, getPipelineDetailsHandler],
[getUserCallouts, getUserCalloutsHandler], [getUserCallouts, getUserCalloutsHandler],
]; ];
...@@ -111,6 +115,11 @@ describe('Pipeline graph wrapper', () => { ...@@ -111,6 +115,11 @@ describe('Pipeline graph wrapper', () => {
createComponentWithApollo(); createComponentWithApollo();
expect(getGraph().exists()).toBe(false); expect(getGraph().exists()).toBe(false);
}); });
it('skips querying headerPipeline', () => {
createComponentWithApollo();
expect(wrapper.vm.$apollo.queries.headerPipeline.skip).toBe(true);
});
}); });
describe('when data has loaded', () => { describe('when data has loaded', () => {
...@@ -190,12 +199,15 @@ describe('Pipeline graph wrapper', () => { ...@@ -190,12 +199,15 @@ describe('Pipeline graph wrapper', () => {
describe('when refresh action is emitted', () => { describe('when refresh action is emitted', () => {
beforeEach(async () => { beforeEach(async () => {
createComponentWithApollo(); createComponentWithApollo();
jest.spyOn(wrapper.vm.$apollo.queries.headerPipeline, 'refetch');
jest.spyOn(wrapper.vm.$apollo.queries.pipeline, 'refetch'); jest.spyOn(wrapper.vm.$apollo.queries.pipeline, 'refetch');
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
getGraph().vm.$emit('refreshPipelineGraph'); getGraph().vm.$emit('refreshPipelineGraph');
}); });
it('calls refetch', () => { it('calls refetch', () => {
expect(wrapper.vm.$apollo.queries.headerPipeline.skip).toBe(false);
expect(wrapper.vm.$apollo.queries.headerPipeline.refetch).toHaveBeenCalled();
expect(wrapper.vm.$apollo.queries.pipeline.refetch).toHaveBeenCalled(); expect(wrapper.vm.$apollo.queries.pipeline.refetch).toHaveBeenCalled();
}); });
}); });
......
...@@ -99,24 +99,6 @@ describe('Pipeline details header', () => { ...@@ -99,24 +99,6 @@ describe('Pipeline details header', () => {
); );
}); });
describe('polling', () => {
it('is stopped when pipeline is finished', async () => {
wrapper = createComponent({ ...mockRunningPipelineHeader });
await wrapper.setData({
pipeline: { ...mockCancelledPipelineHeader },
});
expect(wrapper.vm.$apollo.queries.pipeline.stopPolling).toHaveBeenCalled();
});
it('is not stopped when pipeline is not finished', () => {
wrapper = createComponent();
expect(wrapper.vm.$apollo.queries.pipeline.stopPolling).not.toHaveBeenCalled();
});
});
describe('actions', () => { describe('actions', () => {
describe('Retry action', () => { describe('Retry action', () => {
beforeEach(() => { beforeEach(() => {
......
...@@ -127,6 +127,28 @@ export const mockSuccessfulPipelineHeader = { ...@@ -127,6 +127,28 @@ export const mockSuccessfulPipelineHeader = {
}, },
}; };
export const mockRunningPipelineHeaderData = {
data: {
project: {
pipeline: {
...mockRunningPipelineHeader,
iid: '28',
user: {
name: 'Foo',
username: 'foobar',
webPath: '/foo',
email: 'foo@bar.com',
avatarUrl: 'link',
status: null,
__typename: 'UserCore',
},
__typename: 'Pipeline',
},
__typename: 'Project',
},
},
};
export const stageReply = { export const stageReply = {
name: 'deploy', name: 'deploy',
title: 'deploy: running', title: 'deploy: running',
......
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