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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
f72a1bf0
Commit
f72a1bf0
authored
Oct 03, 2018
by
Filipa Lacerda
Committed by
Phil Hughes
Oct 03, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moves stages dropdown into the new vue app
parent
c4d9f402
Changes
19
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
1727 additions
and
259 deletions
+1727
-259
app/assets/javascripts/job.js
app/assets/javascripts/job.js
+0
-23
app/assets/javascripts/jobs/components/jobs_container.vue
app/assets/javascripts/jobs/components/jobs_container.vue
+22
-8
app/assets/javascripts/jobs/components/sidebar.vue
app/assets/javascripts/jobs/components/sidebar.vue
+297
-0
app/assets/javascripts/jobs/components/stages_dropdown.vue
app/assets/javascripts/jobs/components/stages_dropdown.vue
+58
-58
app/assets/javascripts/jobs/job_details_bundle.js
app/assets/javascripts/jobs/job_details_bundle.js
+18
-8
app/assets/javascripts/jobs/store/actions.js
app/assets/javascripts/jobs/store/actions.js
+20
-8
app/assets/stylesheets/pages/builds.scss
app/assets/stylesheets/pages/builds.scss
+1
-22
app/views/projects/jobs/_sidebar.html.haml
app/views/projects/jobs/_sidebar.html.haml
+0
-38
app/views/projects/jobs/show.html.haml
app/views/projects/jobs/show.html.haml
+1
-1
locale/gitlab.pot
locale/gitlab.pot
+3
-3
spec/features/projects/environments/environment_spec.rb
spec/features/projects/environments/environment_spec.rb
+8
-4
spec/features/projects/jobs/user_browses_job_spec.rb
spec/features/projects/jobs/user_browses_job_spec.rb
+4
-2
spec/features/projects/jobs_spec.rb
spec/features/projects/jobs_spec.rb
+5
-3
spec/javascripts/job_spec.js
spec/javascripts/job_spec.js
+0
-19
spec/javascripts/jobs/components/jobs_container_spec.js
spec/javascripts/jobs/components/jobs_container_spec.js
+14
-9
spec/javascripts/jobs/components/sidebar_spec.js
spec/javascripts/jobs/components/sidebar_spec.js
+196
-0
spec/javascripts/jobs/components/stages_dropdown_spec.js
spec/javascripts/jobs/components/stages_dropdown_spec.js
+19
-13
spec/javascripts/jobs/mock_data.js
spec/javascripts/jobs/mock_data.js
+1040
-7
spec/javascripts/jobs/store/actions_spec.js
spec/javascripts/jobs/store/actions_spec.js
+21
-33
No files found.
app/assets/javascripts/job.js
View file @
f72a1bf0
...
@@ -24,7 +24,6 @@ export default class Job extends LogOutputBehaviours {
...
@@ -24,7 +24,6 @@ export default class Job extends LogOutputBehaviours {
this
.
$document
=
$
(
document
);
this
.
$document
=
$
(
document
);
this
.
$window
=
$
(
window
);
this
.
$window
=
$
(
window
);
this
.
logBytes
=
0
;
this
.
logBytes
=
0
;
this
.
updateDropdown
=
this
.
updateDropdown
.
bind
(
this
);
this
.
$buildTrace
=
$
(
'
#build-trace
'
);
this
.
$buildTrace
=
$
(
'
#build-trace
'
);
this
.
$buildRefreshAnimation
=
$
(
'
.js-build-refresh
'
);
this
.
$buildRefreshAnimation
=
$
(
'
.js-build-refresh
'
);
...
@@ -35,18 +34,12 @@ export default class Job extends LogOutputBehaviours {
...
@@ -35,18 +34,12 @@ export default class Job extends LogOutputBehaviours {
clearTimeout
(
this
.
timeout
);
clearTimeout
(
this
.
timeout
);
this
.
initSidebar
();
this
.
initSidebar
();
this
.
populateJobs
(
this
.
buildStage
);
this
.
updateStageDropdownText
(
this
.
buildStage
);
this
.
sidebarOnResize
();
this
.
sidebarOnResize
();
this
.
$document
this
.
$document
.
off
(
'
click
'
,
'
.js-sidebar-build-toggle
'
)
.
off
(
'
click
'
,
'
.js-sidebar-build-toggle
'
)
.
on
(
'
click
'
,
'
.js-sidebar-build-toggle
'
,
this
.
sidebarOnClick
.
bind
(
this
));
.
on
(
'
click
'
,
'
.js-sidebar-build-toggle
'
,
this
.
sidebarOnClick
.
bind
(
this
));
this
.
$document
.
off
(
'
click
'
,
'
.stage-item
'
)
.
on
(
'
click
'
,
'
.stage-item
'
,
this
.
updateDropdown
);
this
.
scrollThrottled
=
_
.
throttle
(
this
.
toggleScroll
.
bind
(
this
),
100
);
this
.
scrollThrottled
=
_
.
throttle
(
this
.
toggleScroll
.
bind
(
this
),
100
);
this
.
$window
this
.
$window
...
@@ -194,20 +187,4 @@ export default class Job extends LogOutputBehaviours {
...
@@ -194,20 +187,4 @@ export default class Job extends LogOutputBehaviours {
if
(
this
.
shouldHideSidebarForViewport
())
this
.
toggleSidebar
();
if
(
this
.
shouldHideSidebarForViewport
())
this
.
toggleSidebar
();
}
}
// eslint-disable-next-line class-methods-use-this
populateJobs
(
stage
)
{
$
(
'
.build-job
'
).
hide
();
$
(
`.build-job[data-stage="
${
stage
}
"]`
).
show
();
}
// eslint-disable-next-line class-methods-use-this
updateStageDropdownText
(
stage
)
{
$
(
'
.stage-selection
'
).
text
(
stage
);
}
updateDropdown
(
e
)
{
e
.
preventDefault
();
const
stage
=
e
.
currentTarget
.
text
;
this
.
updateStageDropdownText
(
stage
);
this
.
populateJobs
(
stage
);
}
}
}
app/assets/javascripts/jobs/components/jobs_container.vue
View file @
f72a1bf0
<
script
>
<
script
>
import
_
from
'
underscore
'
;
import
CiIcon
from
'
~/vue_shared/components/ci_icon.vue
'
;
import
CiIcon
from
'
~/vue_shared/components/ci_icon.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
...
@@ -16,26 +17,39 @@
...
@@ -16,26 +17,39 @@
type
:
Array
,
type
:
Array
,
required
:
true
,
required
:
true
,
},
},
jobId
:
{
type
:
Number
,
required
:
true
,
},
},
methods
:
{
isJobActive
(
currentJobId
)
{
return
this
.
jobId
===
currentJobId
;
},
tooltipText
(
job
)
{
return
`
${
_
.
escape
(
job
.
name
)}
-
${
job
.
status
.
tooltip
}
`
;
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"builds-container"
>
<div
class=
"
js-jobs-container
builds-container"
>
<div
<div
v-for=
"job in jobs"
:key=
"job.id"
class=
"build-job"
class=
"build-job"
:class=
"
{ retried: job.retried, active: isJobActive(job.id) }"
>
>
<a
<a
v-for=
"job in jobs"
:key=
"job.id"
v-tooltip
v-tooltip
:href=
"job.path"
:href=
"job.
status.details_
path"
:title=
"
job.tooltip
"
:title=
"
tooltipText(job)
"
:class=
"
{ active: job.active, retried: job.retried }
"
data-container=
"body
"
>
>
<icon
<icon
v-if=
"
job.active
"
v-if=
"
isJobActive(job.id)
"
name=
"arrow-right"
name=
"arrow-right"
class=
"js-arrow-right"
class=
"js-arrow-right
icon-arrow-right
"
/>
/>
<ci-icon
:status=
"job.status"
/>
<ci-icon
:status=
"job.status"
/>
...
...
app/assets/javascripts/jobs/components/sidebar
_details_block
.vue
→
app/assets/javascripts/jobs/components/sidebar.vue
View file @
f72a1bf0
This diff is collapsed.
Click to expand it.
app/assets/javascripts/jobs/components/stages_dropdown.vue
View file @
f72a1bf0
<
script
>
<
script
>
import
_
from
'
underscore
'
;
import
CiIcon
from
'
~/vue_shared/components/ci_icon.vue
'
;
import
CiIcon
from
'
~/vue_shared/components/ci_icon.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
sprintf
,
__
}
from
'
~/locale
'
;
export
default
{
export
default
{
components
:
{
components
:
{
...
@@ -10,30 +10,14 @@
...
@@ -10,30 +10,14 @@
Icon
,
Icon
,
},
},
props
:
{
props
:
{
pipelineId
:
{
pipeline
:
{
type
:
Number
,
type
:
Object
,
required
:
true
,
},
pipelinePath
:
{
type
:
String
,
required
:
true
,
},
pipelineRef
:
{
type
:
String
,
required
:
true
,
},
pipelineRefPath
:
{
type
:
String
,
required
:
true
,
required
:
true
,
},
},
stages
:
{
stages
:
{
type
:
Array
,
type
:
Array
,
required
:
true
,
required
:
true
,
},
},
pipelineStatus
:
{
type
:
Object
,
required
:
true
,
},
},
},
data
()
{
data
()
{
return
{
return
{
...
@@ -41,57 +25,73 @@
...
@@ -41,57 +25,73 @@
};
};
},
},
computed
:
{
computed
:
{
pipelineLink
()
{
hasRef
()
{
return
sprintf
(
__
(
'
Pipeline %{pipelineLinkStart} #%{pipelineId} %{pipelineLinkEnd} from %{pipelineLinkRefStart} %{pipelineRef} %{pipelineLinkRefEnd}
'
),
{
return
!
_
.
isEmpty
(
this
.
pipeline
.
ref
);
pipelineLinkStart
:
`<a href=
${
this
.
pipelinePath
}
class="js-pipeline-path link-commit">`
,
},
pipelineId
:
this
.
pipelineId
,
},
pipelineLinkEnd
:
'
</a>
'
,
watch
:
{
pipelineLinkRefStart
:
`<a href=
${
this
.
pipelineRefPath
}
class="link-commit ref-name">`
,
// When the component is initially mounted it may start with an empty stages array.
pipelineRef
:
this
.
pipelineRef
,
// Once the prop is updated, we set the first stage as the selected one
pipelineLinkRefEnd
:
'
</a>
'
,
stages
(
newVal
)
{
},
false
);
if
(
newVal
.
length
)
{
this
.
selectedStage
=
newVal
[
0
].
name
;
}
},
},
},
},
methods
:
{
methods
:
{
onStageClick
(
stage
)
{
onStageClick
(
stage
)
{
// todo: consider moving into store
this
.
selectedStage
=
stage
.
name
;
// update dropdown with jobs
// jobs container is a new component.
this
.
$emit
(
'
requestSidebarStageDropdown
'
,
stage
);
this
.
$emit
(
'
requestSidebarStageDropdown
'
,
stage
);
this
.
selectedStage
=
stage
.
name
;
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"block-last"
>
<div
class=
"block-last dropdown"
>
<ci-icon
:status=
"pipelineStatus"
/>
<ci-icon
:status=
"pipeline.details.status"
class=
"vertical-align-middle"
/>
{{
__
(
'
Pipeline
'
)
}}
<a
:href=
"pipeline.path"
class=
"js-pipeline-path link-commit"
>
#
{{
pipeline
.
id
}}
</a>
<template
v-if=
"hasRef"
>
{{
__
(
'
from
'
)
}}
<a
:href=
"pipeline.ref.path"
class=
"link-commit ref-name"
>
{{
pipeline
.
ref
.
name
}}
</a>
</
template
>
<p
v-html=
"pipelineLink"
></p>
<button
type=
"button"
data-toggle=
"dropdown"
class=
"js-selected-stage dropdown-menu-toggle prepend-top-8"
>
{{ selectedStage }}
<i
class=
"fa fa-chevron-down"
></i>
</button>
<
div
class=
"dropdown
"
>
<
ul
class=
"dropdown-menu
"
>
<
button
<
li
type=
"button
"
v-for=
"stage in stages
"
data-toggle=
"dropdown
"
:key=
"stage.name
"
>
>
{{
selectedStage
}}
<button
<icon
name=
"chevron-down"
/>
type=
"button"
</button>
class=
"js-stage-item stage-item"
<ul
class=
"dropdown-menu"
>
@
click=
"onStageClick(stage)"
<li
v-for=
"(stage, index) in stages"
:key=
"index"
>
>
<button
{{ stage.name }}
type=
"button"
</button>
class=
"stage-item"
</li>
@
click=
"onStageClick(stage)"
</ul>
>
{{
stage
.
name
}}
</button>
</li>
</ul>
</div>
</div>
</div>
</template>
</template>
app/assets/javascripts/jobs/job_details_bundle.js
View file @
f72a1bf0
import
{
mapState
}
from
'
vuex
'
;
import
_
from
'
underscore
'
;
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
Job
from
'
../job
'
;
import
Job
from
'
../job
'
;
import
JobHeader
from
'
./components/header.vue
'
;
import
JobHeader
from
'
./components/header.vue
'
;
import
DetailsBlock
from
'
./components/sidebar_details_block
.vue
'
;
import
Sidebar
from
'
./components/sidebar
.vue
'
;
import
createStore
from
'
./store
'
;
import
createStore
from
'
./store
'
;
export
default
()
=>
{
export
default
()
=>
{
...
@@ -13,6 +14,7 @@ export default () => {
...
@@ -13,6 +14,7 @@ export default () => {
const
store
=
createStore
();
const
store
=
createStore
();
store
.
dispatch
(
'
setJobEndpoint
'
,
dataset
.
endpoint
);
store
.
dispatch
(
'
setJobEndpoint
'
,
dataset
.
endpoint
);
store
.
dispatch
(
'
fetchJob
'
);
store
.
dispatch
(
'
fetchJob
'
);
// Header
// Header
...
@@ -43,17 +45,25 @@ export default () => {
...
@@ -43,17 +45,25 @@ export default () => {
new
Vue
({
new
Vue
({
el
:
detailsBlockElement
,
el
:
detailsBlockElement
,
components
:
{
components
:
{
DetailsBlock
,
Sidebar
,
},
},
store
,
computed
:
{
computed
:
{
...
mapState
([
'
job
'
,
'
isLoading
'
]),
...
mapState
([
'
job
'
]),
},
watch
:
{
job
(
newVal
,
oldVal
)
{
if
(
_
.
isEmpty
(
oldVal
)
&&
!
_
.
isEmpty
(
newVal
.
pipeline
))
{
this
.
fetchStages
();
}
},
},
},
methods
:
{
...
mapActions
([
'
fetchStages
'
]),
},
store
,
render
(
createElement
)
{
render
(
createElement
)
{
return
createElement
(
'
details-block
'
,
{
return
createElement
(
'
sidebar
'
,
{
props
:
{
props
:
{
isLoading
:
this
.
isLoading
,
job
:
this
.
job
,
runnerHelpUrl
:
dataset
.
runnerHelpUrl
,
runnerHelpUrl
:
dataset
.
runnerHelpUrl
,
terminalPath
:
detailsBlockDataset
.
terminalPath
,
terminalPath
:
detailsBlockDataset
.
terminalPath
,
},
},
...
...
app/assets/javascripts/jobs/store/actions.js
View file @
f72a1bf0
...
@@ -62,7 +62,9 @@ export const fetchJob = ({ state, dispatch }) => {
...
@@ -62,7 +62,9 @@ export const fetchJob = ({ state, dispatch }) => {
});
});
};
};
export
const
receiveJobSuccess
=
({
commit
},
data
)
=>
commit
(
types
.
RECEIVE_JOB_SUCCESS
,
data
);
export
const
receiveJobSuccess
=
({
commit
},
data
)
=>
{
commit
(
types
.
RECEIVE_JOB_SUCCESS
,
data
);
};
export
const
receiveJobError
=
({
commit
})
=>
{
export
const
receiveJobError
=
({
commit
})
=>
{
commit
(
types
.
RECEIVE_JOB_ERROR
);
commit
(
types
.
RECEIVE_JOB_ERROR
);
flash
(
__
(
'
An error occurred while fetching the job.
'
));
flash
(
__
(
'
An error occurred while fetching the job.
'
));
...
@@ -137,8 +139,11 @@ export const fetchStages = ({ state, dispatch }) => {
...
@@ -137,8 +139,11 @@ export const fetchStages = ({ state, dispatch }) => {
dispatch
(
'
requestStages
'
);
dispatch
(
'
requestStages
'
);
axios
axios
.
get
(
state
.
stagesEndpoint
)
.
get
(
state
.
job
.
pipeline
.
path
)
.
then
(({
data
})
=>
dispatch
(
'
receiveStagesSuccess
'
,
data
))
.
then
(({
data
})
=>
{
dispatch
(
'
receiveStagesSuccess
'
,
data
.
details
.
stages
);
dispatch
(
'
fetchJobsForStage
'
,
data
.
details
.
stages
[
0
]);
})
.
catch
(()
=>
dispatch
(
'
receiveStagesError
'
));
.
catch
(()
=>
dispatch
(
'
receiveStagesError
'
));
};
};
export
const
receiveStagesSuccess
=
({
commit
},
data
)
=>
export
const
receiveStagesSuccess
=
({
commit
},
data
)
=>
...
@@ -152,16 +157,23 @@ export const receiveStagesError = ({ commit }) => {
...
@@ -152,16 +157,23 @@ export const receiveStagesError = ({ commit }) => {
* Jobs list on sidebar - depend on stages dropdown
* Jobs list on sidebar - depend on stages dropdown
*/
*/
export
const
requestJobsForStage
=
({
commit
})
=>
commit
(
types
.
REQUEST_JOBS_FOR_STAGE
);
export
const
requestJobsForStage
=
({
commit
})
=>
commit
(
types
.
REQUEST_JOBS_FOR_STAGE
);
export
const
setSelectedStage
=
({
commit
},
stage
)
=>
commit
(
types
.
SET_SELECTED_STAGE
,
stage
);
// On stage click, set selected stage + fetch job
// On stage click, set selected stage + fetch job
export
const
fetchJobsForStage
=
({
state
,
dispatch
},
stage
)
=>
{
export
const
fetchJobsForStage
=
({
dispatch
},
stage
)
=>
{
dispatch
(
'
setSelectedStage
'
,
stage
);
dispatch
(
'
requestJobsForStage
'
);
dispatch
(
'
requestJobsForStage
'
);
axios
axios
.
get
(
state
.
stageJobsEndpoint
)
.
get
(
stage
.
dropdown_path
,
{
.
then
(({
data
})
=>
dispatch
(
'
receiveJobsForStageSuccess
'
,
data
))
params
:
{
retried
:
1
,
},
})
.
then
(({
data
})
=>
{
const
retriedJobs
=
data
.
retried
.
map
(
job
=>
Object
.
assign
({},
job
,
{
retried
:
true
}));
const
jobs
=
data
.
latest_statuses
.
concat
(
retriedJobs
);
dispatch
(
'
receiveJobsForStageSuccess
'
,
jobs
);
})
.
catch
(()
=>
dispatch
(
'
receiveJobsForStageError
'
));
.
catch
(()
=>
dispatch
(
'
receiveJobsForStageError
'
));
};
};
export
const
receiveJobsForStageSuccess
=
({
commit
},
data
)
=>
export
const
receiveJobsForStageSuccess
=
({
commit
},
data
)
=>
...
...
app/assets/stylesheets/pages/builds.scss
View file @
f72a1bf0
...
@@ -328,23 +328,6 @@
...
@@ -328,23 +328,6 @@
}
}
}
}
.build-dropdown
{
margin
:
$gl-padding
0
;
padding
:
0
;
.dropdown-menu-toggle
{
margin-top
:
#{
$gl-padding
/
2
}
;
}
svg
{
position
:
relative
;
top
:
3px
;
margin-right
:
3px
;
width
:
14px
;
height
:
14px
;
}
}
.builds-container
{
.builds-container
{
background-color
:
$white-light
;
background-color
:
$white-light
;
border-top
:
1px
solid
$border-color
;
border-top
:
1px
solid
$border-color
;
...
@@ -381,15 +364,11 @@
...
@@ -381,15 +364,11 @@
position
:
absolute
;
position
:
absolute
;
left
:
15px
;
left
:
15px
;
top
:
20px
;
top
:
20px
;
display
:
none
;
display
:
block
;
}
}
&
.active
{
&
.active
{
font-weight
:
$gl-font-weight-bold
;
font-weight
:
$gl-font-weight-bold
;
.icon-arrow-right
{
display
:
block
;
}
}
}
&
.retried
{
&
.retried
{
...
...
app/views/projects/jobs/_sidebar.html.haml
deleted
100644 → 0
View file @
c4d9f402
%aside
.right-sidebar.right-sidebar-expanded.build-sidebar.js-build-sidebar.js-right-sidebar
{
data:
{
"offset-top"
=>
"101"
,
"spy"
=>
"affix"
}
}
.sidebar-container
.blocks-container
#js-details-block-vue
{
data:
{
terminal_path:
can?
(
current_user
,
:create_build_terminal
,
@build
)
&&
@build
.
has_terminal?
?
terminal_project_job_path
(
@project
,
@build
)
:
nil
}
}
-
if
@build
.
pipeline
.
stages_count
>
1
.block-last.dropdown.build-dropdown
%div
%span
{
class:
"ci-status-icon-#{@build.pipeline.status}"
}
=
ci_icon_for_status
(
@build
.
pipeline
.
status
)
Pipeline
=
link_to
"#
#{
@build
.
pipeline
.
id
}
"
,
project_pipeline_path
(
@project
,
@build
.
pipeline
),
class:
'link-commit'
from
=
link_to
"
#{
@build
.
pipeline
.
ref
}
"
,
project_ref_path
(
@project
,
@build
.
pipeline
.
ref
),
class:
'link-commit ref-name'
%button
.dropdown-menu-toggle
{
type:
'button'
,
'data-toggle'
=>
'dropdown'
}
%span
.stage-selection
More
=
icon
(
'chevron-down'
)
%ul
.dropdown-menu
-
@build
.
pipeline
.
legacy_stages
.
each
do
|
stage
|
%li
%a
.stage-item
=
stage
.
name
.builds-container
-
HasStatus
::
ORDERED_STATUSES
.
each
do
|
build_status
|
-
builds
.
select
{
|
build
|
build
.
status
==
build_status
}.
each
do
|
build
|
.build-job
{
class:
sidebar_build_class
(
build
,
@build
),
data:
{
stage:
build
.
stage
}
}
-
tooltip
=
sanitize
(
build
.
tooltip_message
.
dup
)
=
link_to
(
project_job_path
(
@project
,
build
),
data:
{
toggle:
'tooltip'
,
title:
tooltip
,
container:
'body'
})
do
=
sprite_icon
(
'arrow-right'
,
size
:
16
,
css_class:
'icon-arrow-right'
)
%span
{
class:
"ci-status-icon-#{build.status}"
}
=
ci_icon_for_status
(
build
.
status
)
%span
-
if
build
.
name
=
build
.
name
-
else
=
build
.
id
-
if
build
.
retried?
=
sprite_icon
(
'retry'
,
size
:
16
,
css_class:
'icon-retry'
)
app/views/projects/jobs/show.html.haml
View file @
f72a1bf0
...
@@ -93,7 +93,7 @@
...
@@ -93,7 +93,7 @@
-
else
-
else
=
render
"empty_states"
=
render
"empty_states"
=
render
"sidebar"
,
builds:
@builds
#js-details-block-vue
{
data:
{
terminal_path:
can?
(
current_user
,
:create_build_terminal
,
@build
)
&&
@build
.
has_terminal?
?
terminal_project_job_path
(
@project
,
@build
)
:
nil
}
}
.js-build-options
{
data:
javascript_build_options
}
.js-build-options
{
data:
javascript_build_options
}
...
...
locale/gitlab.pot
View file @
f72a1bf0
...
@@ -4310,9 +4310,6 @@ msgstr ""
...
@@ -4310,9 +4310,6 @@ msgstr ""
msgid "Pipeline"
msgid "Pipeline"
msgstr ""
msgstr ""
msgid "Pipeline %{pipelineLinkStart} #%{pipelineId} %{pipelineLinkEnd} from %{pipelineLinkRefStart} %{pipelineRef} %{pipelineLinkRefEnd}"
msgstr ""
msgid "Pipeline Health"
msgid "Pipeline Health"
msgstr ""
msgstr ""
...
@@ -7039,6 +7036,9 @@ msgstr ""
...
@@ -7039,6 +7036,9 @@ msgstr ""
msgid "for this project"
msgid "for this project"
msgstr ""
msgstr ""
msgid "from"
msgstr ""
msgid "here"
msgid "here"
msgstr ""
msgstr ""
...
...
spec/features/projects/environments/environment_spec.rb
View file @
f72a1bf0
...
@@ -60,7 +60,7 @@ describe 'Environment' do
...
@@ -60,7 +60,7 @@ describe 'Environment' do
context
'with manual action'
do
context
'with manual action'
do
let
(
:action
)
do
let
(
:action
)
do
create
(
:ci_build
,
:manual
,
pipeline:
pipeline
,
create
(
:ci_build
,
:manual
,
pipeline:
pipeline
,
name:
'deploy to production'
)
name:
'deploy to production'
,
environment:
environment
.
name
)
end
end
context
'when user has ability to trigger deployment'
do
context
'when user has ability to trigger deployment'
do
...
@@ -73,12 +73,16 @@ describe 'Environment' do
...
@@ -73,12 +73,16 @@ describe 'Environment' do
expect
(
page
).
to
have_link
(
action
.
name
.
humanize
)
expect
(
page
).
to
have_link
(
action
.
name
.
humanize
)
end
end
it
'does allow to play manual action'
do
it
'does allow to play manual action'
,
:js
do
expect
(
action
).
to
be_manual
expect
(
action
).
to
be_manual
find
(
'button.dropdown'
).
click
expect
{
click_link
(
action
.
name
.
humanize
)
}
expect
{
click_link
(
action
.
name
.
humanize
)
}
.
not_to
change
{
Ci
::
Pipeline
.
count
}
.
not_to
change
{
Ci
::
Pipeline
.
count
}
wait_for_all_requests
expect
(
page
).
to
have_content
(
action
.
name
)
expect
(
page
).
to
have_content
(
action
.
name
)
expect
(
action
.
reload
).
to
be_pending
expect
(
action
.
reload
).
to
be_pending
end
end
...
@@ -165,10 +169,10 @@ describe 'Environment' do
...
@@ -165,10 +169,10 @@ describe 'Environment' do
name:
action
.
ref
,
project:
project
)
name:
action
.
ref
,
project:
project
)
end
end
it
'allows to stop environment'
do
it
'allows to stop environment'
,
:js
do
click_button
(
'Stop'
)
click_button
(
'Stop'
)
click_button
(
'Stop environment'
)
# confirm modal
click_button
(
'Stop environment'
)
# confirm modal
wait_for_all_requests
expect
(
page
).
to
have_content
(
'close_app'
)
expect
(
page
).
to
have_content
(
'close_app'
)
end
end
end
end
...
...
spec/features/projects/jobs/user_browses_job_spec.rb
View file @
f72a1bf0
...
@@ -38,9 +38,10 @@ describe 'User browses a job', :js do
...
@@ -38,9 +38,10 @@ describe 'User browses a job', :js do
let!
(
:build
)
{
create
(
:ci_build
,
:failed
,
:trace_artifact
,
pipeline:
pipeline
)
}
let!
(
:build
)
{
create
(
:ci_build
,
:failed
,
:trace_artifact
,
pipeline:
pipeline
)
}
it
'displays the failure reason'
do
it
'displays the failure reason'
do
wait_for_all_requests
within
(
'.builds-container'
)
do
within
(
'.builds-container'
)
do
build_link
=
first
(
'.build-job > a'
)
build_link
=
first
(
'.build-job > a'
)
expect
(
build_link
[
'data-title'
]).
to
eq
(
'test - failed - (unknown failure)'
)
expect
(
build_link
[
'data-
original-
title'
]).
to
eq
(
'test - failed - (unknown failure)'
)
end
end
end
end
end
end
...
@@ -49,9 +50,10 @@ describe 'User browses a job', :js do
...
@@ -49,9 +50,10 @@ describe 'User browses a job', :js do
let!
(
:build
)
{
create
(
:ci_build
,
:failed
,
:retried
,
:trace_artifact
,
pipeline:
pipeline
)
}
let!
(
:build
)
{
create
(
:ci_build
,
:failed
,
:retried
,
:trace_artifact
,
pipeline:
pipeline
)
}
it
'displays the failure reason and retried label'
do
it
'displays the failure reason and retried label'
do
wait_for_all_requests
within
(
'.builds-container'
)
do
within
(
'.builds-container'
)
do
build_link
=
first
(
'.build-job > a'
)
build_link
=
first
(
'.build-job > a'
)
expect
(
build_link
[
'data-title'
]).
to
eq
(
'test - failed - (unknown failure) (retried)'
)
expect
(
build_link
[
'data-
original-
title'
]).
to
eq
(
'test - failed - (unknown failure) (retried)'
)
end
end
end
end
end
end
...
...
spec/features/projects/jobs_spec.rb
View file @
f72a1bf0
...
@@ -134,23 +134,25 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
...
@@ -134,23 +134,25 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
expect
(
page
).
to
have_content
pipeline
.
commit
.
title
expect
(
page
).
to
have_content
pipeline
.
commit
.
title
end
end
it
'shows active job'
do
it
'shows active job'
,
:js
do
visit
project_job_path
(
project
,
job
)
visit
project_job_path
(
project
,
job
)
wait_for_requests
expect
(
page
).
to
have_selector
(
'.build-job.active'
)
expect
(
page
).
to
have_selector
(
'.build-job.active'
)
end
end
end
end
context
'sidebar'
do
context
'sidebar'
,
:js
do
let
(
:job
)
{
create
(
:ci_build
,
:success
,
:trace_live
,
pipeline:
pipeline
,
name:
'<img src=x onerror=alert(document.domain)>'
)
}
let
(
:job
)
{
create
(
:ci_build
,
:success
,
:trace_live
,
pipeline:
pipeline
,
name:
'<img src=x onerror=alert(document.domain)>'
)
}
before
do
before
do
visit
project_job_path
(
project
,
job
)
visit
project_job_path
(
project
,
job
)
wait_for_requests
end
end
it
'renders escaped tooltip name'
do
it
'renders escaped tooltip name'
do
page
.
within
(
'aside.right-sidebar'
)
do
page
.
within
(
'aside.right-sidebar'
)
do
expect
(
find
(
'.active.build-job a'
)[
'data-
title'
]).
to
eq
(
'<img src="x">
- passed'
)
expect
(
find
(
'.active.build-job a'
)[
'data-
original-title'
]).
to
eq
(
'<img src=x onerror=alert(document.domain)>
- passed'
)
end
end
end
end
end
end
...
...
spec/javascripts/job_spec.js
View file @
f72a1bf0
...
@@ -57,25 +57,6 @@ describe('Job', () => {
...
@@ -57,25 +57,6 @@ describe('Job', () => {
expect
(
job
.
buildStage
).
toBe
(
'
test
'
);
expect
(
job
.
buildStage
).
toBe
(
'
test
'
);
expect
(
job
.
state
).
toBe
(
''
);
expect
(
job
.
state
).
toBe
(
''
);
});
});
it
(
'
only shows the jobs matching the current stage
'
,
()
=>
{
expect
(
$
(
'
.build-job[data-stage="build"]
'
).
is
(
'
:visible
'
)).
toBe
(
false
);
expect
(
$
(
'
.build-job[data-stage="test"]
'
).
is
(
'
:visible
'
)).
toBe
(
true
);
expect
(
$
(
'
.build-job[data-stage="deploy"]
'
).
is
(
'
:visible
'
)).
toBe
(
false
);
});
it
(
'
selects the current stage in the build dropdown menu
'
,
()
=>
{
expect
(
$
(
'
.stage-selection
'
).
text
()).
toBe
(
'
test
'
);
});
it
(
'
updates the jobs when the build dropdown changes
'
,
()
=>
{
$
(
'
.stage-item:contains("build")
'
).
click
();
expect
(
$
(
'
.stage-selection
'
).
text
()).
toBe
(
'
build
'
);
expect
(
$
(
'
.build-job[data-stage="build"]
'
).
is
(
'
:visible
'
)).
toBe
(
true
);
expect
(
$
(
'
.build-job[data-stage="test"]
'
).
is
(
'
:visible
'
)).
toBe
(
false
);
expect
(
$
(
'
.build-job[data-stage="deploy"]
'
).
is
(
'
:visible
'
)).
toBe
(
false
);
});
});
});
describe
(
'
running build
'
,
()
=>
{
describe
(
'
running build
'
,
()
=>
{
...
...
spec/javascripts/jobs/components/jobs_container_spec.js
View file @
f72a1bf0
...
@@ -2,7 +2,7 @@ import Vue from 'vue';
...
@@ -2,7 +2,7 @@ import Vue from 'vue';
import
component
from
'
~/jobs/components/jobs_container.vue
'
;
import
component
from
'
~/jobs/components/jobs_container.vue
'
;
import
mountComponent
from
'
../../helpers/vue_mount_component_helper
'
;
import
mountComponent
from
'
../../helpers/vue_mount_component_helper
'
;
describe
(
'
Artifacts
block
'
,
()
=>
{
describe
(
'
Jobs List
block
'
,
()
=>
{
const
Component
=
Vue
.
extend
(
component
);
const
Component
=
Vue
.
extend
(
component
);
let
vm
;
let
vm
;
...
@@ -16,8 +16,7 @@ describe('Artifacts block', () => {
...
@@ -16,8 +16,7 @@ describe('Artifacts block', () => {
text
:
'
passed
'
,
text
:
'
passed
'
,
tooltip
:
'
passed
'
,
tooltip
:
'
passed
'
,
},
},
path
:
'
job/233432756
'
,
id
:
233432756
,
id
:
'
233432756
'
,
tooltip
:
'
build - passed
'
,
tooltip
:
'
build - passed
'
,
retried
:
true
,
retried
:
true
,
};
};
...
@@ -33,8 +32,7 @@ describe('Artifacts block', () => {
...
@@ -33,8 +32,7 @@ describe('Artifacts block', () => {
text
:
'
passed
'
,
text
:
'
passed
'
,
tooltip
:
'
passed
'
,
tooltip
:
'
passed
'
,
},
},
path
:
'
job/2322756
'
,
id
:
2322756
,
id
:
'
2322756
'
,
tooltip
:
'
build - passed
'
,
tooltip
:
'
build - passed
'
,
active
:
true
,
active
:
true
,
};
};
...
@@ -50,8 +48,7 @@ describe('Artifacts block', () => {
...
@@ -50,8 +48,7 @@ describe('Artifacts block', () => {
text
:
'
passed
'
,
text
:
'
passed
'
,
tooltip
:
'
passed
'
,
tooltip
:
'
passed
'
,
},
},
path
:
'
job/232153
'
,
id
:
232153
,
id
:
'
232153
'
,
tooltip
:
'
build - passed
'
,
tooltip
:
'
build - passed
'
,
};
};
...
@@ -62,14 +59,16 @@ describe('Artifacts block', () => {
...
@@ -62,14 +59,16 @@ describe('Artifacts block', () => {
it
(
'
renders list of jobs
'
,
()
=>
{
it
(
'
renders list of jobs
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
vm
=
mountComponent
(
Component
,
{
jobs
:
[
job
,
retried
,
active
],
jobs
:
[
job
,
retried
,
active
],
jobId
:
12313
,
});
});
expect
(
vm
.
$el
.
querySelectorAll
(
'
a
'
).
length
).
toEqual
(
3
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
a
'
).
length
).
toEqual
(
3
);
});
});
it
(
'
renders arrow right when job i
s active
'
,
()
=>
{
it
(
'
renders arrow right when job i
d matches `jobId`
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
vm
=
mountComponent
(
Component
,
{
jobs
:
[
active
],
jobs
:
[
active
],
jobId
:
active
.
id
,
});
});
expect
(
vm
.
$el
.
querySelector
(
'
a .js-arrow-right
'
)).
not
.
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
a .js-arrow-right
'
)).
not
.
toBeNull
();
...
@@ -78,6 +77,7 @@ describe('Artifacts block', () => {
...
@@ -78,6 +77,7 @@ describe('Artifacts block', () => {
it
(
'
does not render arrow right when job is not active
'
,
()
=>
{
it
(
'
does not render arrow right when job is not active
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
vm
=
mountComponent
(
Component
,
{
jobs
:
[
job
],
jobs
:
[
job
],
jobId
:
active
.
id
,
});
});
expect
(
vm
.
$el
.
querySelector
(
'
a .js-arrow-right
'
)).
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
a .js-arrow-right
'
)).
toBeNull
();
...
@@ -86,6 +86,7 @@ describe('Artifacts block', () => {
...
@@ -86,6 +86,7 @@ describe('Artifacts block', () => {
it
(
'
renders job name when present
'
,
()
=>
{
it
(
'
renders job name when present
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
vm
=
mountComponent
(
Component
,
{
jobs
:
[
job
],
jobs
:
[
job
],
jobId
:
active
.
id
,
});
});
expect
(
vm
.
$el
.
querySelector
(
'
a
'
).
textContent
.
trim
()).
toContain
(
job
.
name
);
expect
(
vm
.
$el
.
querySelector
(
'
a
'
).
textContent
.
trim
()).
toContain
(
job
.
name
);
...
@@ -95,6 +96,7 @@ describe('Artifacts block', () => {
...
@@ -95,6 +96,7 @@ describe('Artifacts block', () => {
it
(
'
renders job id when job name is not available
'
,
()
=>
{
it
(
'
renders job id when job name is not available
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
vm
=
mountComponent
(
Component
,
{
jobs
:
[
retried
],
jobs
:
[
retried
],
jobId
:
active
.
id
,
});
});
expect
(
vm
.
$el
.
querySelector
(
'
a
'
).
textContent
.
trim
()).
toContain
(
retried
.
id
);
expect
(
vm
.
$el
.
querySelector
(
'
a
'
).
textContent
.
trim
()).
toContain
(
retried
.
id
);
...
@@ -103,14 +105,16 @@ describe('Artifacts block', () => {
...
@@ -103,14 +105,16 @@ describe('Artifacts block', () => {
it
(
'
links to the job page
'
,
()
=>
{
it
(
'
links to the job page
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
vm
=
mountComponent
(
Component
,
{
jobs
:
[
job
],
jobs
:
[
job
],
jobId
:
active
.
id
,
});
});
expect
(
vm
.
$el
.
querySelector
(
'
a
'
).
getAttribute
(
'
href
'
)).
toEqual
(
job
.
path
);
expect
(
vm
.
$el
.
querySelector
(
'
a
'
).
getAttribute
(
'
href
'
)).
toEqual
(
job
.
status
.
details_
path
);
});
});
it
(
'
renders retry icon when job was retried
'
,
()
=>
{
it
(
'
renders retry icon when job was retried
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
vm
=
mountComponent
(
Component
,
{
jobs
:
[
retried
],
jobs
:
[
retried
],
jobId
:
active
.
id
,
});
});
expect
(
vm
.
$el
.
querySelector
(
'
.js-retry-icon
'
)).
not
.
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
.js-retry-icon
'
)).
not
.
toBeNull
();
...
@@ -119,6 +123,7 @@ describe('Artifacts block', () => {
...
@@ -119,6 +123,7 @@ describe('Artifacts block', () => {
it
(
'
does not render retry icon when job was not retried
'
,
()
=>
{
it
(
'
does not render retry icon when job was not retried
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
vm
=
mountComponent
(
Component
,
{
jobs
:
[
job
],
jobs
:
[
job
],
jobId
:
active
.
id
,
});
});
expect
(
vm
.
$el
.
querySelector
(
'
.js-retry-icon
'
)).
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
.js-retry-icon
'
)).
toBeNull
();
...
...
spec/javascripts/jobs/components/sidebar_
details_block_
spec.js
→
spec/javascripts/jobs/components/sidebar_spec.js
View file @
f72a1bf0
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
sidebarDetailsBlock
from
'
~/jobs/components/sidebar_details_block.vue
'
;
import
sidebarDetailsBlock
from
'
~/jobs/components/sidebar.vue
'
;
import
job
from
'
../mock_data
'
;
import
createStore
from
'
~/jobs/store
'
;
import
mountComponent
from
'
../../helpers/vue_mount_component_helper
'
;
import
job
,
{
stages
,
jobsInStage
}
from
'
../mock_data
'
;
import
{
mountComponentWithStore
}
from
'
../../helpers/vue_mount_component_helper
'
;
import
{
trimText
}
from
'
../../helpers/vue_component_helper
'
;
describe
(
'
Sidebar details block
'
,
()
=>
{
describe
(
'
Sidebar details block
'
,
()
=>
{
let
SidebarComponent
;
const
SidebarComponent
=
Vue
.
extend
(
sidebarDetailsBlock
)
;
let
vm
;
let
vm
;
let
store
;
function
trimWhitespace
(
element
)
{
return
element
.
textContent
.
replace
(
/
\s
+/g
,
'
'
).
trim
();
}
beforeEach
(()
=>
{
beforeEach
(()
=>
{
SidebarComponent
=
Vue
.
extend
(
sidebarDetailsBlock
);
store
=
createStore
(
);
});
});
afterEach
(()
=>
{
afterEach
(()
=>
{
...
@@ -21,19 +20,21 @@ describe('Sidebar details block', () => {
...
@@ -21,19 +20,21 @@ describe('Sidebar details block', () => {
describe
(
'
when it is loading
'
,
()
=>
{
describe
(
'
when it is loading
'
,
()
=>
{
it
(
'
should render a loading spinner
'
,
()
=>
{
it
(
'
should render a loading spinner
'
,
()
=>
{
vm
=
mountComponent
(
SidebarComponent
,
{
store
.
dispatch
(
'
requestJob
'
);
job
:
{},
vm
=
mountComponentWithStore
(
SidebarComponent
,
{
store
});
isLoading
:
true
,
});
expect
(
vm
.
$el
.
querySelector
(
'
.fa-spinner
'
)).
toBeDefined
();
expect
(
vm
.
$el
.
querySelector
(
'
.fa-spinner
'
)).
toBeDefined
();
});
});
});
});
describe
(
'
when there is no retry path retry
'
,
()
=>
{
describe
(
'
when there is no retry path retry
'
,
()
=>
{
it
(
'
should not render a retry button
'
,
()
=>
{
it
(
'
should not render a retry button
'
,
()
=>
{
vm
=
mountComponent
(
SidebarComponent
,
{
const
copy
=
Object
.
assign
({},
job
);
job
:
{},
delete
copy
.
retry_path
;
isLoading
:
false
,
store
.
dispatch
(
'
receiveJobSuccess
'
,
copy
);
vm
=
mountComponentWithStore
(
SidebarComponent
,
{
store
,
});
});
expect
(
vm
.
$el
.
querySelector
(
'
.js-retry-job
'
)).
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
.js-retry-job
'
)).
toBeNull
();
...
@@ -42,10 +43,8 @@ describe('Sidebar details block', () => {
...
@@ -42,10 +43,8 @@ describe('Sidebar details block', () => {
describe
(
'
without terminal path
'
,
()
=>
{
describe
(
'
without terminal path
'
,
()
=>
{
it
(
'
does not render terminal link
'
,
()
=>
{
it
(
'
does not render terminal link
'
,
()
=>
{
vm
=
mountComponent
(
SidebarComponent
,
{
store
.
dispatch
(
'
receiveJobSuccess
'
,
job
);
job
,
vm
=
mountComponentWithStore
(
SidebarComponent
,
{
store
});
isLoading
:
false
,
});
expect
(
vm
.
$el
.
querySelector
(
'
.js-terminal-link
'
)).
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
.js-terminal-link
'
)).
toBeNull
();
});
});
...
@@ -53,10 +52,12 @@ describe('Sidebar details block', () => {
...
@@ -53,10 +52,12 @@ describe('Sidebar details block', () => {
describe
(
'
with terminal path
'
,
()
=>
{
describe
(
'
with terminal path
'
,
()
=>
{
it
(
'
renders terminal link
'
,
()
=>
{
it
(
'
renders terminal link
'
,
()
=>
{
vm
=
mountComponent
(
SidebarComponent
,
{
store
.
dispatch
(
'
receiveJobSuccess
'
,
job
);
job
,
vm
=
mountComponentWithStore
(
SidebarComponent
,
{
isLoading
:
false
,
store
,
terminalPath
:
'
job/43123/terminal
'
,
props
:
{
terminalPath
:
'
job/43123/terminal
'
,
},
});
});
expect
(
vm
.
$el
.
querySelector
(
'
.js-terminal-link
'
)).
not
.
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
.js-terminal-link
'
)).
not
.
toBeNull
();
...
@@ -64,10 +65,8 @@ describe('Sidebar details block', () => {
...
@@ -64,10 +65,8 @@ describe('Sidebar details block', () => {
});
});
beforeEach
(()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
SidebarComponent
,
{
store
.
dispatch
(
'
receiveJobSuccess
'
,
job
);
job
,
vm
=
mountComponentWithStore
(
SidebarComponent
,
{
store
});
isLoading
:
false
,
});
});
});
describe
(
'
actions
'
,
()
=>
{
describe
(
'
actions
'
,
()
=>
{
...
@@ -89,7 +88,7 @@ describe('Sidebar details block', () => {
...
@@ -89,7 +88,7 @@ describe('Sidebar details block', () => {
describe
(
'
information
'
,
()
=>
{
describe
(
'
information
'
,
()
=>
{
it
(
'
should render merge request link
'
,
()
=>
{
it
(
'
should render merge request link
'
,
()
=>
{
expect
(
trim
Whitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-mr
'
)
)).
toEqual
(
'
Merge Request: !2
'
);
expect
(
trim
Text
(
vm
.
$el
.
querySelector
(
'
.js-job-mr
'
).
textContent
)).
toEqual
(
'
Merge Request: !2
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-job-mr a
'
).
getAttribute
(
'
href
'
)).
toEqual
(
expect
(
vm
.
$el
.
querySelector
(
'
.js-job-mr a
'
).
getAttribute
(
'
href
'
)).
toEqual
(
job
.
merge_request
.
path
,
job
.
merge_request
.
path
,
...
@@ -97,43 +96,101 @@ describe('Sidebar details block', () => {
...
@@ -97,43 +96,101 @@ describe('Sidebar details block', () => {
});
});
it
(
'
should render job duration
'
,
()
=>
{
it
(
'
should render job duration
'
,
()
=>
{
expect
(
trim
Whitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-duration
'
)
)).
toEqual
(
expect
(
trim
Text
(
vm
.
$el
.
querySelector
(
'
.js-job-duration
'
).
textContent
)).
toEqual
(
'
Duration: 6 seconds
'
,
'
Duration: 6 seconds
'
,
);
);
});
});
it
(
'
should render erased date
'
,
()
=>
{
it
(
'
should render erased date
'
,
()
=>
{
expect
(
trimWhitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-erased
'
))).
toEqual
(
'
Erased: 3 weeks ago
'
);
expect
(
trimText
(
vm
.
$el
.
querySelector
(
'
.js-job-erased
'
).
textContent
)).
toEqual
(
'
Erased: 3 weeks ago
'
,
);
});
});
it
(
'
should render finished date
'
,
()
=>
{
it
(
'
should render finished date
'
,
()
=>
{
expect
(
trim
Whitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-finished
'
)
)).
toEqual
(
expect
(
trim
Text
(
vm
.
$el
.
querySelector
(
'
.js-job-finished
'
).
textContent
)).
toEqual
(
'
Finished: 3 weeks ago
'
,
'
Finished: 3 weeks ago
'
,
);
);
});
});
it
(
'
should render queued date
'
,
()
=>
{
it
(
'
should render queued date
'
,
()
=>
{
expect
(
trimWhitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-queued
'
))).
toEqual
(
'
Queued: 9 seconds
'
);
expect
(
trimText
(
vm
.
$el
.
querySelector
(
'
.js-job-queued
'
).
textContent
)).
toEqual
(
'
Queued: 9 seconds
'
,
);
});
});
it
(
'
should render runner ID
'
,
()
=>
{
it
(
'
should render runner ID
'
,
()
=>
{
expect
(
trim
Whitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-runner
'
)
)).
toEqual
(
expect
(
trim
Text
(
vm
.
$el
.
querySelector
(
'
.js-job-runner
'
).
textContent
)).
toEqual
(
'
Runner: local ci runner (#1)
'
,
'
Runner: local ci runner (#1)
'
,
);
);
});
});
it
(
'
should render timeout information
'
,
()
=>
{
it
(
'
should render timeout information
'
,
()
=>
{
expect
(
trim
Whitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-timeout
'
)
)).
toEqual
(
expect
(
trim
Text
(
vm
.
$el
.
querySelector
(
'
.js-job-timeout
'
).
textContent
)).
toEqual
(
'
Timeout: 1m 40s (from runner)
'
,
'
Timeout: 1m 40s (from runner)
'
,
);
);
});
});
it
(
'
should render coverage
'
,
()
=>
{
it
(
'
should render coverage
'
,
()
=>
{
expect
(
trimWhitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-coverage
'
))).
toEqual
(
'
Coverage: 20%
'
);
expect
(
trimText
(
vm
.
$el
.
querySelector
(
'
.js-job-coverage
'
).
textContent
)).
toEqual
(
'
Coverage: 20%
'
,
);
});
});
it
(
'
should render tags
'
,
()
=>
{
it
(
'
should render tags
'
,
()
=>
{
expect
(
trimWhitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-tags
'
))).
toEqual
(
'
Tags: tag
'
);
expect
(
trimText
(
vm
.
$el
.
querySelector
(
'
.js-job-tags
'
).
textContent
)).
toEqual
(
'
Tags: tag
'
);
});
});
describe
(
'
stages dropdown
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
dispatch
(
'
receiveJobSuccess
'
,
job
);
});
describe
(
'
while fetching stages
'
,
()
=>
{
it
(
'
renders dropdown with More label
'
,
()
=>
{
vm
=
mountComponentWithStore
(
SidebarComponent
,
{
store
});
expect
(
vm
.
$el
.
querySelector
(
'
.js-selected-stage
'
).
textContent
.
trim
()).
toEqual
(
'
More
'
);
});
});
describe
(
'
with stages
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
dispatch
(
'
receiveStagesSuccess
'
,
stages
);
vm
=
mountComponentWithStore
(
SidebarComponent
,
{
store
});
});
it
(
'
renders first stage as selected
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-selected-stage
'
).
textContent
.
trim
()).
toEqual
(
stages
[
0
].
name
,
);
});
});
describe
(
'
without jobs for stages
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
dispatch
(
'
receiveJobSuccess
'
,
job
);
store
.
dispatch
(
'
receiveStagesSuccess
'
,
stages
);
vm
=
mountComponentWithStore
(
SidebarComponent
,
{
store
});
});
it
(
'
does not render job container
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-jobs-container
'
)).
toBeNull
();
});
});
describe
(
'
with jobs for stages
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
dispatch
(
'
receiveJobSuccess
'
,
job
);
store
.
dispatch
(
'
receiveStagesSuccess
'
,
stages
);
store
.
dispatch
(
'
receiveJobsForStageSuccess
'
,
jobsInStage
.
latest_statuses
);
vm
=
mountComponentWithStore
(
SidebarComponent
,
{
store
});
});
it
(
'
renders list of jobs
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-jobs-container
'
)).
not
.
toBeNull
();
});
});
});
});
});
});
});
spec/javascripts/jobs/components/stages_dropdown_spec.js
View file @
f72a1bf0
...
@@ -8,10 +8,25 @@ describe('Artifacts block', () => {
...
@@ -8,10 +8,25 @@ describe('Artifacts block', () => {
beforeEach
(()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
vm
=
mountComponent
(
Component
,
{
pipelineId
:
28029444
,
pipeline
:
{
pipelinePath
:
'
pipeline/28029444
'
,
id
:
28029444
,
pipelineRef
:
'
50101-truncated-job-information
'
,
details
:
{
pipelineRefPath
:
'
commits/50101-truncated-job-information
'
,
status
:
{
details_path
:
'
/gitlab-org/gitlab-ce/pipelines/28029444
'
,
group
:
'
success
'
,
has_details
:
true
,
icon
:
'
status_success
'
,
label
:
'
passed
'
,
text
:
'
passed
'
,
tooltip
:
'
passed
'
,
},
},
path
:
'
pipeline/28029444
'
,
},
ref
:
{
path
:
'
commits/50101-truncated-job-information
'
,
name
:
'
50101-truncated-job-information
'
,
},
stages
:
[
stages
:
[
{
{
name
:
'
build
'
,
name
:
'
build
'
,
...
@@ -20,15 +35,6 @@ describe('Artifacts block', () => {
...
@@ -20,15 +35,6 @@ describe('Artifacts block', () => {
name
:
'
test
'
,
name
:
'
test
'
,
},
},
],
],
pipelineStatus
:
{
details_path
:
'
/gitlab-org/gitlab-ce/pipelines/28029444
'
,
group
:
'
success
'
,
has_details
:
true
,
icon
:
'
status_success
'
,
label
:
'
passed
'
,
text
:
'
passed
'
,
tooltip
:
'
passed
'
,
},
});
});
});
});
...
...
spec/javascripts/jobs/mock_data.js
View file @
f72a1bf0
This diff is collapsed.
Click to expand it.
spec/javascripts/jobs/store/actions_spec.js
View file @
f72a1bf0
...
@@ -27,7 +27,6 @@ import {
...
@@ -27,7 +27,6 @@ import {
receiveStagesSuccess
,
receiveStagesSuccess
,
receiveStagesError
,
receiveStagesError
,
requestJobsForStage
,
requestJobsForStage
,
setSelectedStage
,
fetchJobsForStage
,
fetchJobsForStage
,
receiveJobsForStageSuccess
,
receiveJobsForStageSuccess
,
receiveJobsForStageError
,
receiveJobsForStageError
,
...
@@ -236,7 +235,8 @@ describe('Job State actions', () => {
...
@@ -236,7 +235,8 @@ describe('Job State actions', () => {
},
},
{
{
payload
:
{
payload
:
{
html
:
'
I, [2018-08-17T22:57:45.707325 #1841] INFO -- :
'
,
complete
:
true
,
html
:
'
I, [2018-08-17T22:57:45.707325 #1841] INFO -- :
'
,
complete
:
true
,
},
},
type
:
'
receiveTraceSuccess
'
,
type
:
'
receiveTraceSuccess
'
,
},
},
...
@@ -421,7 +421,9 @@ describe('Job State actions', () => {
...
@@ -421,7 +421,9 @@ describe('Job State actions', () => {
let
mock
;
let
mock
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mockedState
.
stagesEndpoint
=
`
${
TEST_HOST
}
/endpoint.json`
;
mockedState
.
job
.
pipeline
=
{
path
:
`
${
TEST_HOST
}
/endpoint.json/stages`
,
};
mock
=
new
MockAdapter
(
axios
);
mock
=
new
MockAdapter
(
axios
);
});
});
...
@@ -430,8 +432,10 @@ describe('Job State actions', () => {
...
@@ -430,8 +432,10 @@ describe('Job State actions', () => {
});
});
describe
(
'
success
'
,
()
=>
{
describe
(
'
success
'
,
()
=>
{
it
(
'
dispatches requestStages and receiveStagesSuccess
'
,
done
=>
{
it
(
'
dispatches requestStages and receiveStagesSuccess, fetchJobsForStage
'
,
done
=>
{
mock
.
onGet
(
`
${
TEST_HOST
}
/endpoint.json`
).
replyOnce
(
200
,
[{
id
:
121212
,
name
:
'
build
'
}]);
mock
.
onGet
(
`
${
TEST_HOST
}
/endpoint.json/stages`
)
.
replyOnce
(
200
,
{
details
:
{
stages
:
[{
id
:
121212
,
name
:
'
build
'
}]
}
});
testAction
(
testAction
(
fetchStages
,
fetchStages
,
...
@@ -446,6 +450,10 @@ describe('Job State actions', () => {
...
@@ -446,6 +450,10 @@ describe('Job State actions', () => {
payload
:
[{
id
:
121212
,
name
:
'
build
'
}],
payload
:
[{
id
:
121212
,
name
:
'
build
'
}],
type
:
'
receiveStagesSuccess
'
,
type
:
'
receiveStagesSuccess
'
,
},
},
{
payload
:
{
id
:
121212
,
name
:
'
build
'
},
type
:
'
fetchJobsForStage
'
,
},
],
],
done
,
done
,
);
);
...
@@ -516,24 +524,10 @@ describe('Job State actions', () => {
...
@@ -516,24 +524,10 @@ describe('Job State actions', () => {
});
});
});
});
describe
(
'
setSelectedStage
'
,
()
=>
{
it
(
'
should commit SET_SELECTED_STAGE mutation
'
,
done
=>
{
testAction
(
setSelectedStage
,
{
name
:
'
build
'
},
mockedState
,
[{
type
:
types
.
SET_SELECTED_STAGE
,
payload
:
{
name
:
'
build
'
}
}],
[],
done
,
);
});
});
describe
(
'
fetchJobsForStage
'
,
()
=>
{
describe
(
'
fetchJobsForStage
'
,
()
=>
{
let
mock
;
let
mock
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mockedState
.
stageJobsEndpoint
=
`
${
TEST_HOST
}
/endpoint.json`
;
mock
=
new
MockAdapter
(
axios
);
mock
=
new
MockAdapter
(
axios
);
});
});
...
@@ -542,19 +536,17 @@ describe('Job State actions', () => {
...
@@ -542,19 +536,17 @@ describe('Job State actions', () => {
});
});
describe
(
'
success
'
,
()
=>
{
describe
(
'
success
'
,
()
=>
{
it
(
'
dispatches setSelectedStage, requestJobsForStage and receiveJobsForStageSuccess
'
,
done
=>
{
it
(
'
dispatches requestJobsForStage and receiveJobsForStageSuccess
'
,
done
=>
{
mock
.
onGet
(
`
${
TEST_HOST
}
/endpoint.json`
).
replyOnce
(
200
,
[{
id
:
121212
,
name
:
'
build
'
}]);
mock
.
onGet
(
`
${
TEST_HOST
}
/jobs.json`
)
.
replyOnce
(
200
,
{
latest_statuses
:
[{
id
:
121212
,
name
:
'
build
'
}],
retried
:
[]
});
testAction
(
testAction
(
fetchJobsForStage
,
fetchJobsForStage
,
null
,
{
dropdown_path
:
`
${
TEST_HOST
}
/jobs.json`
}
,
mockedState
,
mockedState
,
[],
[],
[
[
{
type
:
'
setSelectedStage
'
,
payload
:
null
,
},
{
{
type
:
'
requestJobsForStage
'
,
type
:
'
requestJobsForStage
'
,
},
},
...
@@ -570,20 +562,16 @@ describe('Job State actions', () => {
...
@@ -570,20 +562,16 @@ describe('Job State actions', () => {
describe
(
'
error
'
,
()
=>
{
describe
(
'
error
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
`
${
TEST_HOST
}
/
endpoint
.json`
).
reply
(
500
);
mock
.
onGet
(
`
${
TEST_HOST
}
/
jobs
.json`
).
reply
(
500
);
});
});
it
(
'
dispatches
setSelectedStage,
requestJobsForStage and receiveJobsForStageError
'
,
done
=>
{
it
(
'
dispatches requestJobsForStage and receiveJobsForStageError
'
,
done
=>
{
testAction
(
testAction
(
fetchJobsForStage
,
fetchJobsForStage
,
null
,
{
dropdown_path
:
`
${
TEST_HOST
}
/jobs.json`
}
,
mockedState
,
mockedState
,
[],
[],
[
[
{
payload
:
null
,
type
:
'
setSelectedStage
'
,
},
{
{
type
:
'
requestJobsForStage
'
,
type
:
'
requestJobsForStage
'
,
},
},
...
...
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