Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
50f703f9
Commit
50f703f9
authored
Oct 25, 2018
by
Steve Azzopardi
Committed by
Kamil Trzciński
Oct 25, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move job stuck status to backend
parent
5726e51a
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
192 additions
and
88 deletions
+192
-88
app/assets/javascripts/jobs/components/job_app.vue
app/assets/javascripts/jobs/components/job_app.vue
+3
-3
app/assets/javascripts/jobs/components/stuck_block.vue
app/assets/javascripts/jobs/components/stuck_block.vue
+8
-8
app/assets/javascripts/jobs/store/getters.js
app/assets/javascripts/jobs/store/getters.js
+2
-9
app/serializers/build_details_entity.rb
app/serializers/build_details_entity.rb
+1
-0
changelogs/unreleased/52202-consider-moving-isjobstuck-verification-to-backend.yml
...02-consider-moving-isjobstuck-verification-to-backend.yml
+5
-0
spec/controllers/projects/jobs_controller_spec.rb
spec/controllers/projects/jobs_controller_spec.rb
+2
-0
spec/features/projects/jobs_spec.rb
spec/features/projects/jobs_spec.rb
+56
-0
spec/fixtures/api/schemas/job/job_details.json
spec/fixtures/api/schemas/job/job_details.json
+2
-1
spec/javascripts/jobs/components/job_app_spec.js
spec/javascripts/jobs/components/job_app_spec.js
+101
-49
spec/javascripts/jobs/store/getters_spec.js
spec/javascripts/jobs/store/getters_spec.js
+12
-18
No files found.
app/assets/javascripts/jobs/components/job_app.vue
View file @
50f703f9
...
...
@@ -77,11 +77,11 @@
'
shouldRenderCalloutMessage
'
,
'
shouldRenderTriggeredLabel
'
,
'
hasEnvironment
'
,
'
isJobStuck
'
,
'
hasTrace
'
,
'
emptyStateIllustration
'
,
'
isScrollingDown
'
,
'
emptyStateAction
'
,
'
hasRunnersForProject
'
,
]),
shouldRenderContent
()
{
...
...
@@ -195,9 +195,9 @@
<!-- Body Section -->
<stuck-block
v-if=
"
isJobS
tuck"
v-if=
"
job.s
tuck"
class=
"js-job-stuck"
:has-no-runners-for-project=
"
job.runners.available
"
:has-no-runners-for-project=
"
hasRunnersForProject
"
:tags=
"job.tags"
:runners-path=
"runnerSettingsUrl"
/>
...
...
app/assets/javascripts/jobs/components/stuck_block.vue
View file @
50f703f9
...
...
@@ -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
...
...
@@ -43,6 +36,13 @@ export default {
{{
tag
}}
</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"
...
...
app/assets/javascripts/jobs/store/getters.js
View file @
50f703f9
...
...
@@ -41,17 +41,10 @@ export const emptyStateIllustration = state =>
(
state
.
job
&&
state
.
job
.
status
&&
state
.
job
.
status
.
illustration
)
||
{};
export
const
emptyStateAction
=
state
=>
(
state
.
job
&&
state
.
job
.
status
&&
state
.
job
.
status
.
action
)
||
{};
/**
* When the job is pending and there are no available runners
* we need to render the stuck block;
*
* @returns {Boolean}
*/
export
const
isJobStuck
=
state
=>
(
!
_
.
isEmpty
(
state
.
job
.
status
)
&&
state
.
job
.
status
.
group
===
'
pending
'
)
&&
(
!
_
.
isEmpty
(
state
.
job
.
runners
)
&&
state
.
job
.
runners
.
available
===
false
);
export
const
isScrollingDown
=
state
=>
isScrolledToBottom
()
&&
!
state
.
isTraceComplete
;
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
()
=>
{};
app/serializers/build_details_entity.rb
View file @
50f703f9
...
...
@@ -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
...
...
changelogs/unreleased/52202-consider-moving-isjobstuck-verification-to-backend.yml
0 → 100644
View file @
50f703f9
---
title
:
Renders stuck block when runners are stuck
merge_request
:
author
:
type
:
fixed
spec/controllers/projects/jobs_controller_spec.rb
View file @
50f703f9
...
...
@@ -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
...
...
spec/features/projects/jobs_spec.rb
View file @
50f703f9
...
...
@@ -721,6 +721,62 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
expect
(
page
).
not_to
have_css
(
'.js-job-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
...
...
spec/fixtures/api/schemas/job/job_details.json
View file @
50f703f9
...
...
@@ -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"
}
}
}
spec/javascripts/jobs/components/job_app_spec.js
View file @
50f703f9
...
...
@@ -88,7 +88,9 @@ describe('Job App ', () => {
describe
(
'
triggered job
'
,
()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
props
.
endpoint
).
replyOnce
(
200
,
Object
.
assign
({},
job
,
{
started
:
'
2017-05-24T10:59:52.000+01:00
'
}));
mock
.
onGet
(
props
.
endpoint
)
.
replyOnce
(
200
,
Object
.
assign
({},
job
,
{
started
:
'
2017-05-24T10:59:52.000+01:00
'
}));
vm
=
mountComponentWithStore
(
Component
,
{
props
,
store
});
});
...
...
@@ -133,57 +135,106 @@ describe('Job App ', () => {
});
describe
(
'
stuck block
'
,
()
=>
{
it
(
'
renders stuck block when there are no runners
'
,
done
=>
{
mock
.
onGet
(
props
.
endpoint
).
replyOnce
(
200
,
Object
.
assign
({},
job
,
{
status
:
{
group
:
'
pending
'
,
icon
:
'
status_pending
'
,
label
:
'
pending
'
,
text
:
'
pending
'
,
details_path
:
'
path
'
,
},
runners
:
{
available
:
false
,
},
}),
);
vm
=
mountComponentWithStore
(
Component
,
{
props
,
store
});
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-job-stuck
'
)).
not
.
toBeNull
();
describe
(
'
without active runners availabl
'
,
()
=>
{
it
(
'
renders stuck block when there are no runners
'
,
done
=>
{
mock
.
onGet
(
props
.
endpoint
).
replyOnce
(
200
,
Object
.
assign
({},
job
,
{
status
:
{
group
:
'
pending
'
,
icon
:
'
status_pending
'
,
label
:
'
pending
'
,
text
:
'
pending
'
,
details_path
:
'
path
'
,
},
stuck
:
true
,
runners
:
{
available
:
false
,
online
:
false
,
},
tags
:
[],
}),
);
vm
=
mountComponentWithStore
(
Component
,
{
props
,
store
});
done
();
},
0
);
setTimeout
(()
=>
{
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.
"
,
);
done
();
},
0
);
});
});
it
(
'
renders tags in stuck block when there are no runners
'
,
done
=>
{
mock
.
onGet
(
props
.
endpoint
).
replyOnce
(
200
,
Object
.
assign
({},
job
,
{
status
:
{
group
:
'
pending
'
,
icon
:
'
status_pending
'
,
label
:
'
pending
'
,
text
:
'
pending
'
,
details_path
:
'
path
'
,
},
runners
:
{
available
:
false
,
},
}),
);
describe
(
'
when available runners can not run specified tag
'
,
()
=>
{
it
(
'
renders tags in stuck block when there are no runners
'
,
done
=>
{
mock
.
onGet
(
props
.
endpoint
).
replyOnce
(
200
,
Object
.
assign
({},
job
,
{
status
:
{
group
:
'
pending
'
,
icon
:
'
status_pending
'
,
label
:
'
pending
'
,
text
:
'
pending
'
,
details_path
:
'
path
'
,
},
stuck
:
true
,
runners
:
{
available
:
false
,
online
:
false
,
},
}),
);
vm
=
mountComponentWithStore
(
Component
,
{
props
,
store
,
vm
=
mountComponentWithStore
(
Component
,
{
props
,
store
,
});
setTimeout
(()
=>
{
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:
"
,
);
done
();
},
0
);
});
});
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-job-stuck
'
).
textContent
).
toContain
(
job
.
tags
[
0
]);
done
();
},
0
);
describe
(
'
when runners are offline and build has tags
'
,
()
=>
{
it
(
'
renders message about job being stuck because of no runners with the specified tags
'
,
done
=>
{
mock
.
onGet
(
props
.
endpoint
).
replyOnce
(
200
,
Object
.
assign
({},
job
,
{
status
:
{
group
:
'
pending
'
,
icon
:
'
status_pending
'
,
label
:
'
pending
'
,
text
:
'
pending
'
,
details_path
:
'
path
'
,
},
stuck
:
true
,
runners
:
{
available
:
true
,
online
:
true
,
},
}),
);
vm
=
mountComponentWithStore
(
Component
,
{
props
,
store
,
});
setTimeout
(()
=>
{
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:
"
,
);
done
();
},
0
);
})
});
it
(
'
does not renders stuck block when there are no runners
'
,
done
=>
{
...
...
@@ -418,10 +469,11 @@ describe('Job App ', () => {
vm
.
$store
.
state
.
trace
=
'
Update
'
;
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-build-trace
'
).
textContent
.
trim
()).
not
.
toContain
(
'
Update
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-build-trace
'
).
textContent
.
trim
()).
toContain
(
'
Different
'
,
expect
(
vm
.
$el
.
querySelector
(
'
.js-build-trace
'
).
textContent
.
trim
()).
not
.
toContain
(
'
Update
'
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-build-trace
'
).
textContent
.
trim
()).
toContain
(
'
Different
'
);
done
();
},
0
);
});
...
...
spec/javascripts/jobs/store/getters_spec.js
View file @
50f703f9
...
...
@@ -175,43 +175,37 @@ describe('Job Store Getters', () => {
});
});
describe
(
'
isJobStuck
'
,
()
=>
{
describe
(
'
w
hen job is pending and runners are not available
'
,
()
=>
{
describe
(
'
hasRunnersForProject
'
,
()
=>
{
describe
(
'
w
ith 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
(
'
w
hen job is not pending
'
,
()
=>
{
describe
(
'
w
ith 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
(
'
w
hen runners are available
'
,
()
=>
{
describe
(
'
w
ith 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
);
});
});
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment