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
f7783545
Commit
f7783545
authored
Dec 11, 2019
by
Fabio Huser
Committed by
Grzegorz Bizon
Dec 11, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(merge-request): visualize coverage delta on MR widget
parent
050f57d9
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
139 additions
and
0 deletions
+139
-0
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
...ue_merge_request_widget/components/mr_widget_pipeline.vue
+22
-0
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
...equest_widget/components/mr_widget_pipeline_container.vue
+1
-0
app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
...cripts/vue_merge_request_widget/stores/mr_widget_store.js
+1
-0
app/models/merge_request.rb
app/models/merge_request.rb
+6
-0
app/serializers/merge_request_poll_widget_entity.rb
app/serializers/merge_request_poll_widget_entity.rb
+4
-0
changelogs/unreleased/feat-merge-request-coverage-delta.yml
changelogs/unreleased/feat-merge-request-coverage-delta.yml
+5
-0
spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_container_spec.js
...mr_widget/components/mr_widget_pipeline_container_spec.js
+2
-0
spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
...ripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
+40
-0
spec/javascripts/vue_mr_widget/mock_data.js
spec/javascripts/vue_mr_widget/mock_data.js
+1
-0
spec/models/merge_request_spec.rb
spec/models/merge_request_spec.rb
+57
-0
No files found.
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
View file @
f7783545
...
@@ -28,6 +28,10 @@ export default {
...
@@ -28,6 +28,10 @@ export default {
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
pipelineCoverageDelta
:
{
type
:
String
,
required
:
false
,
},
// This prop needs to be camelCase, html attributes are case insensive
// This prop needs to be camelCase, html attributes are case insensive
// https://vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case
// https://vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case
hasCi
:
{
hasCi
:
{
...
@@ -92,6 +96,16 @@ export default {
...
@@ -92,6 +96,16 @@ export default {
showSourceBranch
()
{
showSourceBranch
()
{
return
Boolean
(
this
.
pipeline
.
ref
.
branch
);
return
Boolean
(
this
.
pipeline
.
ref
.
branch
);
},
},
coverageDeltaClass
()
{
const
delta
=
this
.
pipelineCoverageDelta
;
if
(
delta
&&
parseFloat
(
delta
)
>
0
)
{
return
'
text-success
'
;
}
if
(
delta
&&
parseFloat
(
delta
)
<
0
)
{
return
'
text-danger
'
;
}
return
''
;
},
},
},
};
};
</
script
>
</
script
>
...
@@ -142,6 +156,14 @@ export default {
...
@@ -142,6 +156,14 @@ export default {
</div>
</div>
<div
v-if=
"pipeline.coverage"
class=
"coverage"
>
<div
v-if=
"pipeline.coverage"
class=
"coverage"
>
{{ s__('Pipeline|Coverage') }} {{ pipeline.coverage }}%
{{ s__('Pipeline|Coverage') }} {{ pipeline.coverage }}%
<span
v-if=
"pipelineCoverageDelta"
class=
"js-pipeline-coverage-delta"
:class=
"coverageDeltaClass"
>
({{ pipelineCoverageDelta }}%)
</span>
</div>
</div>
</div>
</div>
</div>
</div>
...
...
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
View file @
f7783545
...
@@ -76,6 +76,7 @@ export default {
...
@@ -76,6 +76,7 @@ export default {
<mr-widget-container>
<mr-widget-container>
<mr-widget-pipeline
<mr-widget-pipeline
:pipeline=
"pipeline"
:pipeline=
"pipeline"
:pipeline-coverage-delta=
"mr.pipelineCoverageDelta"
:ci-status=
"mr.ciStatus"
:ci-status=
"mr.ciStatus"
:has-ci=
"mr.hasCI"
:has-ci=
"mr.hasCI"
:source-branch=
"branch"
:source-branch=
"branch"
...
...
app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
View file @
f7783545
...
@@ -42,6 +42,7 @@ export default class MergeRequestStore {
...
@@ -42,6 +42,7 @@ export default class MergeRequestStore {
this
.
commitsCount
=
data
.
commits_count
;
this
.
commitsCount
=
data
.
commits_count
;
this
.
divergedCommitsCount
=
data
.
diverged_commits_count
;
this
.
divergedCommitsCount
=
data
.
diverged_commits_count
;
this
.
pipeline
=
data
.
pipeline
||
{};
this
.
pipeline
=
data
.
pipeline
||
{};
this
.
pipelineCoverageDelta
=
data
.
pipeline_coverage_delta
;
this
.
mergePipeline
=
data
.
merge_pipeline
||
{};
this
.
mergePipeline
=
data
.
merge_pipeline
||
{};
this
.
deployments
=
this
.
deployments
||
data
.
deployments
||
[];
this
.
deployments
=
this
.
deployments
||
data
.
deployments
||
[];
this
.
postMergeDeployments
=
this
.
postMergeDeployments
||
[];
this
.
postMergeDeployments
=
this
.
postMergeDeployments
||
[];
...
...
app/models/merge_request.rb
View file @
f7783545
...
@@ -1423,6 +1423,12 @@ class MergeRequest < ApplicationRecord
...
@@ -1423,6 +1423,12 @@ class MergeRequest < ApplicationRecord
true
true
end
end
def
pipeline_coverage_delta
if
base_pipeline
&
.
coverage
&&
head_pipeline
&
.
coverage
'%.2f'
%
(
head_pipeline
.
coverage
.
to_f
-
base_pipeline
.
coverage
.
to_f
)
end
end
def
base_pipeline
def
base_pipeline
@base_pipeline
||=
project
.
ci_pipelines
@base_pipeline
||=
project
.
ci_pipelines
.
order
(
id: :desc
)
.
order
(
id: :desc
)
...
...
app/serializers/merge_request_poll_widget_entity.rb
View file @
f7783545
...
@@ -57,6 +57,10 @@ class MergeRequestPollWidgetEntity < Grape::Entity
...
@@ -57,6 +57,10 @@ class MergeRequestPollWidgetEntity < Grape::Entity
presenter
(
merge_request
).
ci_status
presenter
(
merge_request
).
ci_status
end
end
expose
:pipeline_coverage_delta
do
|
merge_request
|
presenter
(
merge_request
).
pipeline_coverage_delta
end
expose
:cancel_auto_merge_path
do
|
merge_request
|
expose
:cancel_auto_merge_path
do
|
merge_request
|
presenter
(
merge_request
).
cancel_auto_merge_path
presenter
(
merge_request
).
cancel_auto_merge_path
end
end
...
...
changelogs/unreleased/feat-merge-request-coverage-delta.yml
0 → 100644
View file @
f7783545
---
title
:
Add coverage difference visualization to merge request page
merge_request
:
20676
author
:
Fabio Huser
type
:
added
spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_container_spec.js
View file @
f7783545
...
@@ -34,6 +34,7 @@ describe('MrWidgetPipelineContainer', () => {
...
@@ -34,6 +34,7 @@ describe('MrWidgetPipelineContainer', () => {
expect
(
wrapper
.
find
(
MrWidgetPipeline
).
props
()).
toEqual
(
expect
(
wrapper
.
find
(
MrWidgetPipeline
).
props
()).
toEqual
(
jasmine
.
objectContaining
({
jasmine
.
objectContaining
({
pipeline
:
mockStore
.
pipeline
,
pipeline
:
mockStore
.
pipeline
,
pipelineCoverageDelta
:
mockStore
.
pipelineCoverageDelta
,
ciStatus
:
mockStore
.
ciStatus
,
ciStatus
:
mockStore
.
ciStatus
,
hasCi
:
mockStore
.
hasCI
,
hasCi
:
mockStore
.
hasCI
,
sourceBranch
:
mockStore
.
sourceBranch
,
sourceBranch
:
mockStore
.
sourceBranch
,
...
@@ -68,6 +69,7 @@ describe('MrWidgetPipelineContainer', () => {
...
@@ -68,6 +69,7 @@ describe('MrWidgetPipelineContainer', () => {
expect
(
wrapper
.
find
(
MrWidgetPipeline
).
props
()).
toEqual
(
expect
(
wrapper
.
find
(
MrWidgetPipeline
).
props
()).
toEqual
(
jasmine
.
objectContaining
({
jasmine
.
objectContaining
({
pipeline
:
mockStore
.
mergePipeline
,
pipeline
:
mockStore
.
mergePipeline
,
pipelineCoverageDelta
:
mockStore
.
pipelineCoverageDelta
,
ciStatus
:
mockStore
.
ciStatus
,
ciStatus
:
mockStore
.
ciStatus
,
hasCi
:
mockStore
.
hasCI
,
hasCi
:
mockStore
.
hasCI
,
sourceBranch
:
mockStore
.
targetBranch
,
sourceBranch
:
mockStore
.
targetBranch
,
...
...
spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
View file @
f7783545
...
@@ -62,6 +62,38 @@ describe('MRWidgetPipeline', () => {
...
@@ -62,6 +62,38 @@ describe('MRWidgetPipeline', () => {
expect
(
vm
.
hasCIError
).
toEqual
(
true
);
expect
(
vm
.
hasCIError
).
toEqual
(
true
);
});
});
});
});
describe
(
'
coverageDeltaClass
'
,
()
=>
{
it
(
'
should return no class if there is no coverage change
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
pipeline
:
mockData
.
pipeline
,
pipelineCoverageDelta
:
'
0
'
,
troubleshootingDocsPath
:
'
help
'
,
});
expect
(
vm
.
coverageDeltaClass
).
toEqual
(
''
);
});
it
(
'
should return text-success if the coverage increased
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
pipeline
:
mockData
.
pipeline
,
pipelineCoverageDelta
:
'
10
'
,
troubleshootingDocsPath
:
'
help
'
,
});
expect
(
vm
.
coverageDeltaClass
).
toEqual
(
'
text-success
'
);
});
it
(
'
should return text-danger if the coverage decreased
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
pipeline
:
mockData
.
pipeline
,
pipelineCoverageDelta
:
'
-12
'
,
troubleshootingDocsPath
:
'
help
'
,
});
expect
(
vm
.
coverageDeltaClass
).
toEqual
(
'
text-danger
'
);
});
});
});
});
describe
(
'
rendered output
'
,
()
=>
{
describe
(
'
rendered output
'
,
()
=>
{
...
@@ -96,6 +128,7 @@ describe('MRWidgetPipeline', () => {
...
@@ -96,6 +128,7 @@ describe('MRWidgetPipeline', () => {
pipeline
:
mockData
.
pipeline
,
pipeline
:
mockData
.
pipeline
,
hasCi
:
true
,
hasCi
:
true
,
ciStatus
:
'
success
'
,
ciStatus
:
'
success
'
,
pipelineCoverageDelta
:
mockData
.
pipelineCoverageDelta
,
troubleshootingDocsPath
:
'
help
'
,
troubleshootingDocsPath
:
'
help
'
,
});
});
});
});
...
@@ -132,6 +165,13 @@ describe('MRWidgetPipeline', () => {
...
@@ -132,6 +165,13 @@ describe('MRWidgetPipeline', () => {
`Coverage
${
mockData
.
pipeline
.
coverage
}
`
,
`Coverage
${
mockData
.
pipeline
.
coverage
}
`
,
);
);
});
});
it
(
'
should render pipeline coverage delta information
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-pipeline-coverage-delta.text-danger
'
)).
toBeDefined
();
expect
(
vm
.
$el
.
querySelector
(
'
.js-pipeline-coverage-delta
'
).
textContent
).
toContain
(
`(
${
mockData
.
pipelineCoverageDelta
}
%)`
,
);
});
});
});
describe
(
'
without commit path
'
,
()
=>
{
describe
(
'
without commit path
'
,
()
=>
{
...
...
spec/javascripts/vue_mr_widget/mock_data.js
View file @
f7783545
...
@@ -185,6 +185,7 @@ export default {
...
@@ -185,6 +185,7 @@ export default {
created_at
:
'
2017-04-07T12:27:19.520Z
'
,
created_at
:
'
2017-04-07T12:27:19.520Z
'
,
updated_at
:
'
2017-04-07T15:28:44.800Z
'
,
updated_at
:
'
2017-04-07T15:28:44.800Z
'
,
},
},
pipelineCoverageDelta
:
'
15.25
'
,
work_in_progress
:
false
,
work_in_progress
:
false
,
source_branch_exists
:
false
,
source_branch_exists
:
false
,
mergeable_discussions_state
:
true
,
mergeable_discussions_state
:
true
,
...
...
spec/models/merge_request_spec.rb
View file @
f7783545
...
@@ -2821,6 +2821,63 @@ describe MergeRequest do
...
@@ -2821,6 +2821,63 @@ describe MergeRequest do
end
end
end
end
describe
'#pipeline_coverage_delta'
do
let!
(
:project
)
{
create
(
:project
,
:repository
)
}
let!
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
project
)
}
let!
(
:source_pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
ref:
merge_request
.
source_branch
,
sha:
merge_request
.
diff_head_sha
)
end
let!
(
:target_pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
ref:
merge_request
.
target_branch
,
sha:
merge_request
.
diff_base_sha
)
end
def
create_build
(
pipeline
,
coverage
,
name
)
create
(
:ci_build
,
:success
,
pipeline:
pipeline
,
coverage:
coverage
,
name:
name
)
merge_request
.
update_head_pipeline
end
context
'when both source and target branches have coverage information'
do
it
'returns the appropriate coverage delta'
do
create_build
(
source_pipeline
,
60.2
,
'test:1'
)
create_build
(
target_pipeline
,
50
,
'test:2'
)
expect
(
merge_request
.
pipeline_coverage_delta
).
to
eq
(
'10.20'
)
end
end
context
'when target branch does not have coverage information'
do
it
'returns nil'
do
create_build
(
source_pipeline
,
50
,
'test:1'
)
expect
(
merge_request
.
pipeline_coverage_delta
).
to
be_nil
end
end
context
'when source branch does not have coverage information'
do
it
'returns nil for coverage_delta'
do
create_build
(
target_pipeline
,
50
,
'test:1'
)
expect
(
merge_request
.
pipeline_coverage_delta
).
to
be_nil
end
end
context
'neither source nor target branch has coverage information'
do
it
'returns nil for coverage_delta'
do
expect
(
merge_request
.
pipeline_coverage_delta
).
to
be_nil
end
end
end
describe
'#base_pipeline'
do
describe
'#base_pipeline'
do
let
(
:pipeline_arguments
)
do
let
(
:pipeline_arguments
)
do
{
{
...
...
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