summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Azzopardi <steveazz@outlook.com>2018-10-18 09:36:24 +0200
committerFilipa Lacerda <filipa@gitlab.com>2018-11-02 10:03:41 +0000
commit6d49e882d9f5ab5d397e15221f299c979e030b09 (patch)
tree10d57c37623e0037fedee55f1a6043693f782c9a
parent6ebbd70fbb3bfbda9745ad16ec1cd26ad41366c5 (diff)
downloadgitlab-ce-52202-consider-moving-isjobstuck-verification-to-backend-11-4.tar.gz
Frontend currently defines when a job is stuck, which we already have in the backend, expose `stuck` field in the `Project::JobsController#show.json` so the duplication of the logic is removed. Use `stuck` flag from API Removes isJobStuck check from frontend and uses the flag being provided by the API Renders missing tags message Moves available runners check into a computed prop Fix changelog for stuck job
-rw-r--r--app/assets/javascripts/jobs/components/job_app.vue6
-rw-r--r--app/assets/javascripts/jobs/components/stuck_block.vue16
-rw-r--r--app/assets/javascripts/jobs/store/getters.js11
-rw-r--r--app/serializers/build_details_entity.rb1
-rw-r--r--changelogs/unreleased/52202-consider-moving-isjobstuck-verification-to-backend-11-4.yml5
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb2
-rw-r--r--spec/features/projects/jobs_spec.rb56
-rw-r--r--spec/fixtures/api/schemas/job/job_details.json3
-rw-r--r--spec/javascripts/jobs/components/job_app_spec.js100
-rw-r--r--spec/javascripts/jobs/store/getters_spec.js30
10 files changed, 148 insertions, 82 deletions
diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue
index 4e8d3ad24cc..a32e2d2ac95 100644
--- a/app/assets/javascripts/jobs/components/job_app.vue
+++ b/app/assets/javascripts/jobs/components/job_app.vue
@@ -32,9 +32,9 @@
'shouldRenderCalloutMessage',
'shouldRenderTriggeredLabel',
'hasEnvironment',
- 'isJobStuck',
'hasTrace',
'emptyStateIllustration',
+ 'hasRunnersForProject',
]),
},
};
@@ -72,9 +72,9 @@
<!-- Body Section -->
<stuck-block
- v-if="isJobStuck"
+ v-if="job.stuck"
class="js-job-stuck"
- :has-no-runners-for-project="job.runners.available"
+ :has-no-runners-for-project="hasRunnersForProject"
:tags="job.tags"
:runners-path="runnerSettingsUrl"
/>
diff --git a/app/assets/javascripts/jobs/components/stuck_block.vue b/app/assets/javascripts/jobs/components/stuck_block.vue
index a60643b2c65..1d5789b175a 100644
--- a/app/assets/javascripts/jobs/components/stuck_block.vue
+++ b/app/assets/javascripts/jobs/components/stuck_block.vue
@@ -23,14 +23,7 @@ export default {
<template>
<div class="bs-callout bs-callout-warning">
<p
- v-if="hasNoRunnersForProject"
- class="js-stuck-no-runners append-bottom-0"
- >
- {{ s__(`Job|This job is stuck, because the project
- doesn't have any runners online assigned to it.`) }}
- </p>
- <p
- v-else-if="tags.length"
+ v-if="tags.length"
class="js-stuck-with-tags append-bottom-0"
>
{{ s__(`This job is stuck, because you don't have
@@ -44,6 +37,13 @@ export default {
</span>
</p>
<p
+ v-else-if="hasNoRunnersForProject"
+ class="js-stuck-no-runners append-bottom-0"
+ >
+ {{ s__(`Job|This job is stuck, because the project
+ doesn't have any runners online assigned to it.`) }}
+ </p>
+ <p
v-else
class="js-stuck-no-active-runner append-bottom-0"
>
diff --git a/app/assets/javascripts/jobs/store/getters.js b/app/assets/javascripts/jobs/store/getters.js
index 9f4f372e3d2..e1d163d8eee 100644
--- a/app/assets/javascripts/jobs/store/getters.js
+++ b/app/assets/javascripts/jobs/store/getters.js
@@ -39,15 +39,8 @@ export const hasTrace = state => state.job.has_trace || state.job.status.group =
export const emptyStateIllustration = state =>
(state.job && state.job.status && state.job.status.illustration) || {};
-/**
- * When the job is pending and there are no available runners
- * we need to render the stuck block;
- *
- * @returns {Boolean}
- */
-export const isJobStuck = state =>
- state.job.status.group === 'pending' &&
- (!_.isEmpty(state.job.runners) && state.job.runners.available === false);
+export const hasRunnersForProject = state => state.job.runners.available
+ && !state.job.runners.online;
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb
index 066a5b1885c..9ddce0d2c80 100644
--- a/app/serializers/build_details_entity.rb
+++ b/app/serializers/build_details_entity.rb
@@ -5,6 +5,7 @@ class BuildDetailsEntity < JobEntity
expose :tag_list, as: :tags
expose :has_trace?, as: :has_trace
expose :stage
+ expose :stuck?, as: :stuck
expose :user, using: UserEntity
expose :runner, using: RunnerEntity
expose :pipeline, using: PipelineEntity
diff --git a/changelogs/unreleased/52202-consider-moving-isjobstuck-verification-to-backend-11-4.yml b/changelogs/unreleased/52202-consider-moving-isjobstuck-verification-to-backend-11-4.yml
new file mode 100644
index 00000000000..e32ad09bf94
--- /dev/null
+++ b/changelogs/unreleased/52202-consider-moving-isjobstuck-verification-to-backend-11-4.yml
@@ -0,0 +1,5 @@
+---
+title: Fix stuck job warning message
+merge_request: 8060
+author:
+type: fixed
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 2a32b555863..26272785b25 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -297,6 +297,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(response).to match_response_schema('job/job_details')
expect(json_response['runners']['online']).to be false
expect(json_response['runners']['available']).to be false
+ expect(json_response['stuck']).to be true
end
end
@@ -309,6 +310,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(response).to match_response_schema('job/job_details')
expect(json_response['runners']['online']).to be false
expect(json_response['runners']['available']).to be true
+ expect(json_response['stuck']).to be true
end
end
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index a3a301504ff..24520d0aecb 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -738,6 +738,62 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
expect(page).not_to have_css('.js-build-sidebar.right-sidebar-collpased')
end
end
+
+ context 'stuck', :js do
+ before do
+ visit project_job_path(project, job)
+ wait_for_requests
+ end
+
+ context 'without active runners available' do
+ let(:runner) { create(:ci_runner, :instance, active: false) }
+ let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) }
+
+ it 'renders message about job being stuck because no runners are active' do
+ expect(page).to have_css('.js-stuck-no-active-runner')
+ expect(page).to have_content("This job is stuck, because you don't have any active runners that can run this job.")
+ end
+ end
+
+ context 'when available runners can not run specified tag' do
+ let(:runner) { create(:ci_runner, :instance, active: false) }
+ let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner, tag_list: %w(docker linux)) }
+
+ it 'renders message about job being stuck because of no runners with the specified tags' do
+ expect(page).to have_css('.js-stuck-with-tags')
+ expect(page).to have_content("This job is stuck, because you don't have any active runners online with any of these tags assigned to them:")
+ end
+ end
+
+ context 'when runners are offline and build has tags' do
+ let(:runner) { create(:ci_runner, :instance, active: true) }
+ let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner, tag_list: %w(docker linux)) }
+
+ it 'renders message about job being stuck because of no runners with the specified tags' do
+ expect(page).to have_css('.js-stuck-with-tags')
+ expect(page).to have_content("This job is stuck, because you don't have any active runners online with any of these tags assigned to them:")
+ end
+ end
+
+ context 'without any runners available' do
+ let(:job) { create(:ci_build, :pending, pipeline: pipeline) }
+
+ it 'renders message about job being stuck because not runners are available' do
+ expect(page).to have_css('.js-stuck-no-active-runner')
+ expect(page).to have_content("This job is stuck, because you don't have any active runners that can run this job.")
+ end
+ end
+
+ context 'without available runners online' do
+ let(:runner) { create(:ci_runner, :instance, active: true) }
+ let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) }
+
+ it 'renders message about job being stuck because runners are offline' do
+ expect(page).to have_css('.js-stuck-no-runners')
+ expect(page).to have_content("This job is stuck, because the project doesn't have any runners online assigned to it.")
+ end
+ end
+ end
end
describe "POST /:project/jobs/:id/cancel", :js do
diff --git a/spec/fixtures/api/schemas/job/job_details.json b/spec/fixtures/api/schemas/job/job_details.json
index 8218474705c..cdf7b049ab6 100644
--- a/spec/fixtures/api/schemas/job/job_details.json
+++ b/spec/fixtures/api/schemas/job/job_details.json
@@ -18,6 +18,7 @@
"runner": { "$ref": "runner.json" },
"runners": { "$ref": "runners.json" },
"has_trace": { "type": "boolean" },
- "stage": { "type": "string" }
+ "stage": { "type": "string" },
+ "stuck": { "type": "boolean" }
}
}
diff --git a/spec/javascripts/jobs/components/job_app_spec.js b/spec/javascripts/jobs/components/job_app_spec.js
index 6e0bcf801cd..223c1a3cb1b 100644
--- a/spec/javascripts/jobs/components/job_app_spec.js
+++ b/spec/javascripts/jobs/components/job_app_spec.js
@@ -128,59 +128,73 @@ describe('Job App ', () => {
});
describe('stuck block', () => {
- it('renders stuck block when there are no runners', () => {
- store.dispatch(
- 'receiveJobSuccess',
- Object.assign({}, job, {
- status: {
- group: 'pending',
- icon: 'status_pending',
- label: 'pending',
- text: 'pending',
- details_path: 'path',
- },
- }),
- );
+ describe('without active runners availabl', () => {
+ it('renders stuck block when there are no runners', () => {
+ store.dispatch('receiveJobSuccess',
+ Object.assign({}, job, {
+ stuck: true,
+ runners: {
+ available: false,
+ online: false,
+ },
+ tags: [],
+ }),
+ );
+ vm = mountComponentWithStore(Component, { props, store });
- vm = mountComponentWithStore(Component, {
- props,
- store,
+ expect(vm.$el.querySelector('.js-job-stuck')).not.toBeNull();
+ expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(
+ "This job is stuck, because you don't have any active runners that can run this job.",
+ );
});
-
- expect(vm.$el.querySelector('.js-job-stuck')).not.toBeNull();
});
- it('renders tags in stuck block when there are no runners', () => {
- store.dispatch(
- 'receiveJobSuccess',
- Object.assign({}, job, {
- status: {
- group: 'pending',
- icon: 'status_pending',
- label: 'pending',
- text: 'pending',
- details_path: 'path',
- },
- }),
- );
+ describe('when available runners can not run specified tag', () => {
+ it('renders tags in stuck block when there are no runners', () => {
+ store.dispatch('receiveJobSuccess',
+ Object.assign({}, job, {
+ stuck: true,
+ runners: {
+ available: false,
+ online: false,
+ },
+ }),
+ );
- vm = mountComponentWithStore(Component, {
- props,
- store,
- });
+ vm = mountComponentWithStore(Component, {
+ props,
+ store,
+ });
- expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]);
+ expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]);
+ expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(
+ "This job is stuck, because you don't have any active runners online with any of these tags assigned to them:",
+ );
+ });
});
- it(' does not renders stuck block when there are no runners', () => {
- store.dispatch('receiveJobSuccess', Object.assign({}, job, { runners: { available: true } }));
+ describe('when runners are offline and build has tags', () => {
+ it('renders message about job being stuck because of no runners with the specified tags', () => {
+ store.dispatch('receiveJobSuccess',
+ Object.assign({}, job, {
+ stuck: true,
+ runners: {
+ available: true,
+ online: true,
+ },
+ }),
+ );
- vm = mountComponentWithStore(Component, {
- props,
- store,
- });
+ vm = mountComponentWithStore(Component, {
+ props,
+ store,
+ });
- expect(vm.$el.querySelector('.js-job-stuck')).toBeNull();
+ expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]);
+ expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(
+ "This job is stuck, because you don't have any active runners online with any of these tags assigned to them:",
+ );
+ });
});
});
diff --git a/spec/javascripts/jobs/store/getters_spec.js b/spec/javascripts/jobs/store/getters_spec.js
index e262a47b837..78d3fc9e908 100644
--- a/spec/javascripts/jobs/store/getters_spec.js
+++ b/spec/javascripts/jobs/store/getters_spec.js
@@ -170,43 +170,37 @@ describe('Job Store Getters', () => {
});
});
- describe('isJobStuck', () => {
- describe('when job is pending and runners are not available', () => {
+ describe('hasRunnersForProject', () => {
+ describe('with available and offline runners', () => {
it('returns true', () => {
- localState.job.status = {
- group: 'pending',
- };
localState.job.runners = {
- available: false,
+ available: true,
+ online: false,
};
- expect(getters.isJobStuck(localState)).toEqual(true);
+ expect(getters.hasRunnersForProject(localState)).toEqual(true);
});
});
- describe('when job is not pending', () => {
+ describe('with non available runners', () => {
it('returns false', () => {
- localState.job.status = {
- group: 'running',
- };
localState.job.runners = {
available: false,
+ online: false,
};
- expect(getters.isJobStuck(localState)).toEqual(false);
+ expect(getters.hasRunnersForProject(localState)).toEqual(false);
});
});
- describe('when runners are available', () => {
+ describe('with online runners', () => {
it('returns false', () => {
- localState.job.status = {
- group: 'pending',
- };
localState.job.runners = {
- available: true,
+ available: false,
+ online: true,
};
- expect(getters.isJobStuck(localState)).toEqual(false);
+ expect(getters.hasRunnersForProject(localState)).toEqual(false);
});
});
});