Commit 11f2ddf0 authored by jerasmus's avatar jerasmus Committed by Tiger

Display error for unmet prerequisites

Added the ability to display an error for unmet prerequisites
parent 02b9b5fa
......@@ -49,7 +49,7 @@ export default {
<div class="text-content">
<h4 class="js-job-empty-state-title text-center">{{ title }}</h4>
<p v-if="content" class="js-job-empty-state-content">{{ content }}</p>
<p v-if="content" class="js-job-empty-state-content text-center">{{ content }}</p>
<div v-if="action" class="text-center">
<gl-link
......
......@@ -15,6 +15,7 @@ import ErasedBlock from './erased_block.vue';
import Log from './job_log.vue';
import LogTopBar from './job_log_controllers.vue';
import StuckBlock from './stuck_block.vue';
import UnmetPrerequisitesBlock from './unmet_prerequisites_block.vue';
import Sidebar from './sidebar.vue';
import { sprintf } from '~/locale';
import delayedJobMixin from '../mixins/delayed_job_mixin';
......@@ -32,6 +33,7 @@ export default {
Log,
LogTopBar,
StuckBlock,
UnmetPrerequisitesBlock,
Sidebar,
GlLoadingIcon,
SharedRunner: () => import('ee_component/jobs/components/shared_runner_limit_block.vue'),
......@@ -48,6 +50,11 @@ export default {
required: false,
default: null,
},
deploymentHelpUrl: {
type: String,
required: false,
default: null,
},
endpoint: {
type: String,
required: true,
......@@ -82,6 +89,7 @@ export default {
]),
...mapGetters([
'headerTime',
'hasUnmetPrerequisitesFailure',
'shouldRenderCalloutMessage',
'shouldRenderTriggeredLabel',
'hasEnvironment',
......@@ -223,6 +231,12 @@ export default {
:runners-path="runnerSettingsUrl"
/>
<unmet-prerequisites-block
v-if="hasUnmetPrerequisitesFailure"
class="js-job-failed"
:help-path="deploymentHelpUrl"
/>
<shared-runner
v-if="shouldRenderSharedRunnerLimitWarning"
class="js-shared-runner-limit"
......
<script>
import { GlLink } from '@gitlab/ui';
/**
* Renders Unmet Prerequisites block for job's view.
*/
export default {
components: {
GlLink,
},
props: {
helpPath: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="bs-callout bs-callout-danger">
<p class="js-failed-unmet-prerequisites append-bottom-0">
{{
s__(`Job|This job failed because the necessary resources were not successfully created.`)
}}
<gl-link :href="helpPath" class="js-help-path">
<strong> {{ __('More information') }} </strong>
</gl-link>
</p>
</div>
</template>
......@@ -12,6 +12,7 @@ export default () => {
render(createElement) {
return createElement('job-app', {
props: {
deploymentHelpUrl: element.dataset.deploymentHelpUrl,
runnerHelpUrl: element.dataset.runnerHelpUrl,
runnerSettingsUrl: element.dataset.runnerSettingsUrl,
endpoint: element.dataset.endpoint,
......
......@@ -3,8 +3,13 @@ import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
export const headerTime = state => (state.job.started ? state.job.started : state.job.created_at);
export const hasUnmetPrerequisitesFailure = state =>
state.job && state.job.failure_reason && state.job.failure_reason === 'unmet_prerequisites';
export const shouldRenderCalloutMessage = state =>
!_.isEmpty(state.job.status) && !_.isEmpty(state.job.callout_message);
!_.isEmpty(state.job.status) &&
!_.isEmpty(state.job.callout_message) &&
!hasUnmetPrerequisitesFailure;
/**
* When job has not started the key will be null
......
......@@ -28,6 +28,10 @@
background-color: $red-100;
border-color: $red-200;
color: $red-700;
a {
color: $red-700;
}
}
.bs-callout-warning {
......
......@@ -8,6 +8,7 @@
%div{ class: container_class }
#js-job-vue-app{ data: { endpoint: project_job_path(@project, @build, format: :json),
deployment_help_url: help_page_path('user/project/clusters/index.html', anchor: 'troubleshooting-failed-deployment-jobs'),
runner_help_url: help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner'),
runner_settings_url: project_runners_path(@build.project, anchor: 'js-runners-settings'),
build_options: javascript_build_options } }
---
title: Show error when namespace/svc account missing
merge_request: 26362
author:
type: added
......@@ -7,10 +7,10 @@ module Gitlab
class FailedUnmetPrerequisites < Status::Extended
def illustration
{
image: 'illustrations/skipped-job_empty.svg',
image: 'illustrations/pipelines_failed.svg',
size: 'svg-430',
title: _('Failed to create resources'),
content: _('Retry this job in order to create the necessary resources')
content: _('Retry this job in order to create the necessary resources.')
}
end
......
......@@ -3568,6 +3568,9 @@ msgstr ""
msgid "Failed to check related branches."
msgstr ""
msgid "Failed to create resources"
msgstr ""
msgid "Failed to deploy to"
msgstr ""
......@@ -4589,6 +4592,9 @@ msgstr ""
msgid "Job|The artifacts will be removed"
msgstr ""
msgid "Job|This job failed because the necessary resources were not successfully created."
msgstr ""
msgid "Job|This job is stuck because the project doesn't have any runners online assigned to it."
msgstr ""
......@@ -6825,6 +6831,9 @@ msgstr ""
msgid "Retry this job"
msgstr ""
msgid "Retry this job in order to create the necessary resources."
msgstr ""
msgid "Retry verification"
msgstr ""
......
......@@ -17,6 +17,7 @@ describe('Job App ', () => {
const props = {
endpoint: `${gl.TEST_HOST}jobs/123.json`,
runnerHelpUrl: 'help/runner',
deploymentHelpUrl: 'help/deployment',
runnerSettingsUrl: 'settings/ci-cd/runners',
terminalPath: 'jobs/123/terminal',
pagePath: `${gl.TEST_HOST}jobs/123`,
......@@ -253,6 +254,41 @@ describe('Job App ', () => {
});
});
describe('unmet prerequisites block', () => {
it('renders unmet prerequisites block when there is an unmet prerequisites failure', done => {
mock.onGet(props.endpoint).replyOnce(
200,
Object.assign({}, job, {
status: {
group: 'failed',
icon: 'status_failed',
label: 'failed',
text: 'failed',
details_path: 'path',
illustration: {
content: 'Retry this job in order to create the necessary resources.',
image: 'path',
size: 'svg-430',
title: 'Failed to create resources',
},
},
has_trace: false,
unmet_prerequisites: true,
runners: {
available: true,
},
tags: [],
}),
);
vm = mountComponentWithStore(Component, { props, store });
setTimeout(() => {
expect(vm.$el.querySelector('.js-job-failed')).not.toBeNull();
done();
}, 0);
});
});
describe('environments block', () => {
it('renders environment block when job has environment', done => {
mock.onGet(props.endpoint).replyOnce(
......
import Vue from 'vue';
import component from '~/jobs/components/unmet_prerequisites_block.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('Unmet Prerequisites Block Job component', () => {
const Component = Vue.extend(component);
let vm;
const helpPath = '/user/project/clusters/index.html#troubleshooting-failed-deployment-jobs';
beforeEach(() => {
vm = mountComponent(Component, {
hasNoRunnersForProject: true,
helpPath,
});
});
afterEach(() => {
vm.$destroy();
});
it('renders an alert with the correct message', () => {
const container = vm.$el.querySelector('.js-failed-unmet-prerequisites');
const alertMessage =
'This job failed because the necessary resources were not successfully created.';
expect(container).not.toBeNull();
expect(container.innerHTML).toContain(alertMessage);
});
it('renders link to help page', () => {
const helpLink = vm.$el.querySelector('.js-help-path');
expect(helpLink).not.toBeNull();
expect(helpLink.innerHTML).toContain('More information');
expect(helpLink.getAttribute('href')).toEqual(helpPath);
});
});
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