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
dadc046d
Commit
dadc046d
authored
Oct 29, 2018
by
Alessio Caiazza
Committed by
Nick Thomas
Oct 29, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
post merge pipeline and environments status
parent
289651e2
Changes
22
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
588 additions
and
118 deletions
+588
-118
app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
...cripts/vue_merge_request_widget/components/deployment.vue
+12
-3
app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
...avascripts/vue_merge_request_widget/mr_widget_options.vue
+75
-20
app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
...ts/vue_merge_request_widget/services/mr_widget_service.js
+6
-2
app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
...cripts/vue_merge_request_widget/stores/mr_widget_store.js
+2
-0
app/controllers/projects/merge_requests_controller.rb
app/controllers/projects/merge_requests_controller.rb
+9
-3
app/models/deployment.rb
app/models/deployment.rb
+4
-0
app/models/environment_status.rb
app/models/environment_status.rb
+35
-6
app/models/merge_request.rb
app/models/merge_request.rb
+6
-0
app/serializers/environment_status_entity.rb
app/serializers/environment_status_entity.rb
+1
-0
app/serializers/merge_request_widget_entity.rb
app/serializers/merge_request_widget_entity.rb
+1
-0
changelogs/unreleased/ac-post-merge-pipeline.yml
changelogs/unreleased/ac-post-merge-pipeline.yml
+5
-0
locale/gitlab.pot
locale/gitlab.pot
+15
-0
spec/controllers/projects/merge_requests_controller_spec.rb
spec/controllers/projects/merge_requests_controller_spec.rb
+43
-8
spec/features/merge_request/user_sees_deployment_widget_spec.rb
...eatures/merge_request/user_sees_deployment_widget_spec.rb
+9
-10
spec/features/merge_request/user_sees_merge_widget_spec.rb
spec/features/merge_request/user_sees_merge_widget_spec.rb
+8
-3
spec/fixtures/api/schemas/entities/merge_request_widget.json
spec/fixtures/api/schemas/entities/merge_request_widget.json
+1
-0
spec/javascripts/vue_mr_widget/components/deployment_spec.js
spec/javascripts/vue_mr_widget/components/deployment_spec.js
+82
-60
spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+187
-1
spec/models/environment_status_spec.rb
spec/models/environment_status_spec.rb
+31
-1
spec/models/merge_request_spec.rb
spec/models/merge_request_spec.rb
+20
-0
spec/serializers/environment_status_entity_spec.rb
spec/serializers/environment_status_entity_spec.rb
+2
-1
spec/serializers/merge_request_widget_entity_spec.rb
spec/serializers/merge_request_widget_entity_spec.rb
+34
-0
No files found.
app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
View file @
dadc046d
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
TooltipOnTruncate
from
'
~/vue_shared/components/tooltip_on_truncate.vue
'
;
import
TooltipOnTruncate
from
'
~/vue_shared/components/tooltip_on_truncate.vue
'
;
import
FilteredSearchDropdown
from
'
~/vue_shared/components/filtered_search_dropdown.vue
'
;
import
FilteredSearchDropdown
from
'
~/vue_shared/components/filtered_search_dropdown.vue
'
;
import
{
__
}
from
'
~/locale
'
;
import
timeagoMixin
from
'
../../vue_shared/mixins/timeago
'
;
import
timeagoMixin
from
'
../../vue_shared/mixins/timeago
'
;
import
tooltip
from
'
../../vue_shared/directives/tooltip
'
;
import
tooltip
from
'
../../vue_shared/directives/tooltip
'
;
import
LoadingButton
from
'
../../vue_shared/components/loading_button.vue
'
;
import
LoadingButton
from
'
../../vue_shared/components/loading_button.vue
'
;
...
@@ -31,6 +32,11 @@ export default {
...
@@ -31,6 +32,11 @@ export default {
required
:
true
,
required
:
true
,
},
},
},
},
deployedTextMap
:
{
running
:
__
(
'
Deploying to
'
),
success
:
__
(
'
Deployed to
'
),
failed
:
__
(
'
Failed to deploy to
'
),
},
data
()
{
data
()
{
const
features
=
window
.
gon
.
features
||
{};
const
features
=
window
.
gon
.
features
||
{};
return
{
return
{
...
@@ -54,10 +60,13 @@ export default {
...
@@ -54,10 +60,13 @@ export default {
hasMetrics
()
{
hasMetrics
()
{
return
!!
this
.
deployment
.
metrics_url
;
return
!!
this
.
deployment
.
metrics_url
;
},
},
deployedText
()
{
return
this
.
$options
.
deployedTextMap
[
this
.
deployment
.
status
];
},
},
},
methods
:
{
methods
:
{
stopEnvironment
()
{
stopEnvironment
()
{
const
msg
=
'
Are you sure you want to stop this environment?
'
;
const
msg
=
__
(
'
Are you sure you want to stop this environment?
'
)
;
const
isConfirmed
=
confirm
(
msg
);
// eslint-disable-line
const
isConfirmed
=
confirm
(
msg
);
// eslint-disable-line
if
(
isConfirmed
)
{
if
(
isConfirmed
)
{
...
@@ -87,10 +96,10 @@ export default {
...
@@ -87,10 +96,10 @@ export default {
<div
class=
"ci-widget media"
>
<div
class=
"ci-widget media"
>
<div
class=
"media-body"
>
<div
class=
"media-body"
>
<div
class=
"deploy-body"
>
<div
class=
"deploy-body"
>
<div
class=
"deployment-info"
>
<div
class=
"
js-deployment-info
deployment-info"
>
<template
v-if=
"hasDeploymentMeta"
>
<template
v-if=
"hasDeploymentMeta"
>
<span>
<span>
Deployed to
{{
deployedText
}}
</span>
</span>
<tooltip-on-truncate
<tooltip-on-truncate
:title=
"deployment.name"
:title=
"deployment.name"
...
...
app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
View file @
dadc046d
<
script
>
<
script
>
import
_
from
'
underscore
'
;
import
{
__
}
from
'
~/locale
'
;
import
Project
from
'
~/pages/projects/project
'
;
import
Project
from
'
~/pages/projects/project
'
;
import
SmartInterval
from
'
~/smart_interval
'
;
import
SmartInterval
from
'
~/smart_interval
'
;
import
createFlash
from
'
../flash
'
;
import
createFlash
from
'
../flash
'
;
...
@@ -80,6 +82,7 @@ export default {
...
@@ -80,6 +82,7 @@ export default {
const
service
=
this
.
createService
(
store
);
const
service
=
this
.
createService
(
store
);
return
{
return
{
mr
:
store
,
mr
:
store
,
state
:
store
.
state
,
service
,
service
,
};
};
},
},
...
@@ -103,6 +106,17 @@ export default {
...
@@ -103,6 +106,17 @@ export default {
(
!
this
.
mr
.
isNothingToMergeState
&&
!
this
.
mr
.
isMergedState
)
(
!
this
.
mr
.
isNothingToMergeState
&&
!
this
.
mr
.
isMergedState
)
);
);
},
},
shouldRenderMergedPipeline
()
{
return
this
.
mr
.
state
===
'
merged
'
&&
!
_
.
isEmpty
(
this
.
mr
.
mergePipeline
);
},
},
watch
:
{
state
(
newVal
,
oldVal
)
{
if
(
newVal
!==
oldVal
&&
this
.
shouldRenderMergedPipeline
)
{
// init polling
this
.
initPostMergeDeploymentsPolling
();
}
}
},
},
created
()
{
created
()
{
this
.
initPolling
();
this
.
initPolling
();
...
@@ -112,11 +126,19 @@ export default {
...
@@ -112,11 +126,19 @@ export default {
mounted
()
{
mounted
()
{
this
.
setFaviconHelper
();
this
.
setFaviconHelper
();
this
.
initDeploymentsPolling
();
this
.
initDeploymentsPolling
();
if
(
this
.
shouldRenderMergedPipeline
)
{
this
.
initPostMergeDeploymentsPolling
();
}
},
},
beforeDestroy
()
{
beforeDestroy
()
{
eventHub
.
$off
(
'
mr.discussion.updated
'
,
this
.
checkStatus
);
eventHub
.
$off
(
'
mr.discussion.updated
'
,
this
.
checkStatus
);
this
.
pollingInterval
.
destroy
();
this
.
pollingInterval
.
destroy
();
this
.
deploymentsInterval
.
destroy
();
this
.
deploymentsInterval
.
destroy
();
if
(
this
.
postMergeDeploymentsInterval
)
{
this
.
postMergeDeploymentsInterval
.
destroy
();
}
},
},
methods
:
{
methods
:
{
createService
(
store
)
{
createService
(
store
)
{
...
@@ -146,7 +168,13 @@ export default {
...
@@ -146,7 +168,13 @@ export default {
cb
.
call
(
null
,
data
);
cb
.
call
(
null
,
data
);
}
}
})
})
.
catch
(()
=>
createFlash
(
'
Something went wrong. Please try again.
'
));
.
catch
(()
=>
createFlash
(
__
(
'
Something went wrong. Please try again.
'
)));
},
setFaviconHelper
()
{
if
(
this
.
mr
.
ciStatusFaviconPath
)
{
return
setFaviconOverlay
(
this
.
mr
.
ciStatusFaviconPath
);
}
return
Promise
.
resolve
();
},
},
initPolling
()
{
initPolling
()
{
this
.
pollingInterval
=
new
SmartInterval
({
this
.
pollingInterval
=
new
SmartInterval
({
...
@@ -158,8 +186,14 @@ export default {
...
@@ -158,8 +186,14 @@ export default {
});
});
},
},
initDeploymentsPolling
()
{
initDeploymentsPolling
()
{
this
.
deploymentsInterval
=
new
SmartInterval
({
this
.
deploymentsInterval
=
this
.
deploymentsPoll
(
this
.
fetchPreMergeDeployments
);
callback
:
this
.
fetchDeployments
,
},
initPostMergeDeploymentsPolling
()
{
this
.
postMergeDeploymentsInterval
=
this
.
deploymentsPoll
(
this
.
fetchPostMergeDeployments
);
},
deploymentsPoll
(
callback
)
{
return
new
SmartInterval
({
callback
,
startingInterval
:
30000
,
startingInterval
:
30000
,
maxInterval
:
120000
,
maxInterval
:
120000
,
hiddenInterval
:
240000
,
hiddenInterval
:
240000
,
...
@@ -167,26 +201,29 @@ export default {
...
@@ -167,26 +201,29 @@ export default {
immediateExecution
:
true
,
immediateExecution
:
true
,
});
});
},
},
setFaviconHelper
()
{
fetchDeployments
(
target
)
{
if
(
this
.
mr
.
ciStatusFaviconPath
)
{
return
this
.
service
.
fetchDeployments
(
target
);
return
setFaviconOverlay
(
this
.
mr
.
ciStatusFaviconPath
);
}
return
Promise
.
resolve
();
},
},
fetchDeployments
()
{
fetchPreMergeDeployments
()
{
return
this
.
service
return
this
.
fetchDeployments
()
.
fetchDeployments
()
.
then
(({
data
})
=>
{
.
then
(
res
=>
res
.
data
)
.
then
(
data
=>
{
if
(
data
.
length
)
{
if
(
data
.
length
)
{
this
.
mr
.
deployments
=
data
;
this
.
mr
.
deployments
=
data
;
}
}
})
})
.
catch
(()
=>
{
.
catch
(()
=>
this
.
throwDeploymentsError
());
createFlash
(
},
'
Something went wrong while fetching the environments for this merge request. Please try again.
'
,
fetchPostMergeDeployments
(){
);
return
this
.
fetchDeployments
(
'
merge_commit
'
)
});
.
then
(({
data
})
=>
{
if
(
data
.
length
)
{
this
.
mr
.
postMergeDeployments
=
data
;
}
})
.
catch
(()
=>
this
.
throwDeploymentsError
());
},
throwDeploymentsError
()
{
createFlash
(
__
(
'
Something went wrong while fetching the environments for this merge request. Please try again.
'
));
},
},
fetchActionsContent
()
{
fetchActionsContent
()
{
this
.
service
this
.
service
...
@@ -199,7 +236,7 @@ export default {
...
@@ -199,7 +236,7 @@ export default {
Project
.
initRefSwitcher
();
Project
.
initRefSwitcher
();
}
}
})
})
.
catch
(()
=>
createFlash
(
'
Something went wrong. Please try again.
'
));
.
catch
(()
=>
createFlash
(
__
(
'
Something went wrong. Please try again.
'
)
));
},
},
handleNotification
(
data
)
{
handleNotification
(
data
)
{
if
(
data
.
ci_status
===
this
.
mr
.
ciStatus
)
return
;
if
(
data
.
ci_status
===
this
.
mr
.
ciStatus
)
return
;
...
@@ -267,7 +304,8 @@ export default {
...
@@ -267,7 +304,8 @@ export default {
/>
/>
<deployment
<deployment
v-for=
"deployment in mr.deployments"
v-for=
"deployment in mr.deployments"
:key=
"deployment.id"
:key=
"`pre-merge-deploy-$
{deployment.id}`"
class="js-pre-merge-deploy"
:deployment="deployment"
:deployment="deployment"
/>
/>
<div
class=
"mr-section-container"
>
<div
class=
"mr-section-container"
>
...
@@ -308,5 +346,22 @@ export default {
...
@@ -308,5 +346,22 @@ export default {
<mr-widget-merge-help
/>
<mr-widget-merge-help
/>
</div>
</div>
</div>
</div>
<template
v-if=
"shouldRenderMergedPipeline"
>
<mr-widget-pipeline
class=
"js-post-merge-pipeline prepend-top-default"
:pipeline=
"mr.mergePipeline"
:ci-status=
"mr.ciStatus"
:has-ci=
"mr.hasCI"
:source-branch=
"mr.targetBranch"
:source-branch-link=
"mr.targetBranch"
/>
<deployment
v-for=
"postMergeDeployment in mr.postMergeDeployments"
:key=
"`post-merge-deploy-$
{postMergeDeployment.id}`"
:deployment="postMergeDeployment"
class="js-post-deployment"
/>
</
template
>
</div>
</div>
</template>
</template>
app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
View file @
dadc046d
...
@@ -21,8 +21,12 @@ export default class MRWidgetService {
...
@@ -21,8 +21,12 @@ export default class MRWidgetService {
return
axios
.
delete
(
this
.
endpoints
.
sourceBranchPath
);
return
axios
.
delete
(
this
.
endpoints
.
sourceBranchPath
);
}
}
fetchDeployments
()
{
fetchDeployments
(
targetParam
)
{
return
axios
.
get
(
this
.
endpoints
.
ciEnvironmentsStatusPath
);
return
axios
.
get
(
this
.
endpoints
.
ciEnvironmentsStatusPath
,
{
params
:
{
environment_target
:
targetParam
}
});
}
}
poll
()
{
poll
()
{
...
...
app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
View file @
dadc046d
...
@@ -32,7 +32,9 @@ export default class MergeRequestStore {
...
@@ -32,7 +32,9 @@ 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
.
mergePipeline
=
data
.
merge_pipeline
||
{};
this
.
deployments
=
this
.
deployments
||
data
.
deployments
||
[];
this
.
deployments
=
this
.
deployments
||
data
.
deployments
||
[];
this
.
postMergeDeployments
=
this
.
postMergeDeployments
||
[];
this
.
initRebase
(
data
);
this
.
initRebase
(
data
);
if
(
data
.
issues_links
)
{
if
(
data
.
issues_links
)
{
...
...
app/controllers/projects/merge_requests_controller.rb
View file @
dadc046d
...
@@ -201,8 +201,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
...
@@ -201,8 +201,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
end
def
ci_environments_status
def
ci_environments_status
environments
=
@merge_request
.
environments_for
(
current_user
).
map
do
|
environment
|
environments
=
if
ci_environments_status_on_merge_result?
EnvironmentStatus
.
new
(
environment
,
@merge_request
)
EnvironmentStatus
.
after_merge_request
(
@merge_request
,
current_user
)
else
EnvironmentStatus
.
for_merge_request
(
@merge_request
,
current_user
)
end
end
render
json:
EnvironmentStatusSerializer
.
new
(
current_user:
current_user
).
represent
(
environments
)
render
json:
EnvironmentStatusSerializer
.
new
(
current_user:
current_user
).
represent
(
environments
)
...
@@ -241,6 +243,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
...
@@ -241,6 +243,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
private
private
def
ci_environments_status_on_merge_result?
params
[
:environment_target
]
==
'merge_commit'
end
def
target_branch_missing?
def
target_branch_missing?
@merge_request
.
has_no_commits?
&&
!
@merge_request
.
target_branch_exists?
@merge_request
.
has_no_commits?
&&
!
@merge_request
.
target_branch_exists?
end
end
...
...
app/models/deployment.rb
View file @
dadc046d
...
@@ -127,6 +127,10 @@ class Deployment < ActiveRecord::Base
...
@@ -127,6 +127,10 @@ class Deployment < ActiveRecord::Base
metrics
&
.
merge
(
deployment_time:
created_at
.
to_i
)
||
{}
metrics
&
.
merge
(
deployment_time:
created_at
.
to_i
)
||
{}
end
end
def
status
'success'
end
private
private
def
prometheus_adapter
def
prometheus_adapter
...
...
app/models/environment_status.rb
View file @
dadc046d
...
@@ -3,21 +3,33 @@
...
@@ -3,21 +3,33 @@
class
EnvironmentStatus
class
EnvironmentStatus
include
Gitlab
::
Utils
::
StrongMemoize
include
Gitlab
::
Utils
::
StrongMemoize
attr_reader
:environment
,
:merge_request
attr_reader
:environment
,
:merge_request
,
:sha
delegate
:id
,
to: :environment
delegate
:id
,
to: :environment
delegate
:name
,
to: :environment
delegate
:name
,
to: :environment
delegate
:project
,
to: :environment
delegate
:project
,
to: :environment
delegate
:deployed_at
,
to: :deployment
,
allow_nil:
true
delegate
:deployed_at
,
to: :deployment
,
allow_nil:
true
delegate
:status
,
to: :deployment
def
initialize
(
environment
,
merge_request
)
def
self
.
for_merge_request
(
mr
,
user
)
build_environments_status
(
mr
,
user
,
mr
.
head_pipeline
)
end
def
self
.
after_merge_request
(
mr
,
user
)
return
[]
unless
mr
.
merged?
build_environments_status
(
mr
,
user
,
mr
.
merge_pipeline
)
end
def
initialize
(
environment
,
merge_request
,
sha
)
@environment
=
environment
@environment
=
environment
@merge_request
=
merge_request
@merge_request
=
merge_request
@sha
=
sha
end
end
def
deployment
def
deployment
strong_memoize
(
:deployment
)
do
strong_memoize
(
:deployment
)
do
environment
.
first_deployment_for
(
merge_request
.
diff_head_
sha
)
environment
.
first_deployment_for
(
sha
)
end
end
end
end
...
@@ -26,10 +38,9 @@ class EnvironmentStatus
...
@@ -26,10 +38,9 @@ class EnvironmentStatus
end
end
def
changes
def
changes
sha
=
merge_request
.
diff_head_sha
return
[]
if
project
.
route_map_for
(
sha
).
nil?
return
[]
if
project
.
route_map_for
(
sha
).
nil?
changed_files
.
map
{
|
file
|
build_change
(
file
,
sha
)
}.
compact
changed_files
.
map
{
|
file
|
build_change
(
file
)
}.
compact
end
end
def
changed_files
def
changed_files
...
@@ -41,7 +52,7 @@ class EnvironmentStatus
...
@@ -41,7 +52,7 @@ class EnvironmentStatus
PAGE_EXTENSIONS
=
/\A\.(s?html?|php|asp|cgi|pl)\z/i
.
freeze
PAGE_EXTENSIONS
=
/\A\.(s?html?|php|asp|cgi|pl)\z/i
.
freeze
def
build_change
(
file
,
sha
)
def
build_change
(
file
)
public_path
=
project
.
public_path_for_source_path
(
file
.
new_path
,
sha
)
public_path
=
project
.
public_path_for_source_path
(
file
.
new_path
,
sha
)
return
if
public_path
.
nil?
return
if
public_path
.
nil?
...
@@ -53,4 +64,22 @@ class EnvironmentStatus
...
@@ -53,4 +64,22 @@ class EnvironmentStatus
external_url:
environment
.
external_url_for
(
file
.
new_path
,
sha
)
external_url:
environment
.
external_url_for
(
file
.
new_path
,
sha
)
}
}
end
end
def
self
.
build_environments_status
(
mr
,
user
,
pipeline
)
return
[]
unless
pipeline
.
present?
find_environments
(
user
,
pipeline
).
map
do
|
environment
|
EnvironmentStatus
.
new
(
environment
,
mr
,
pipeline
.
sha
)
end
end
private_class_method
:build_environments_status
def
self
.
find_environments
(
user
,
pipeline
)
env_ids
=
Deployment
.
where
(
deployable:
pipeline
.
builds
).
select
(
:environment_id
)
Environment
.
available
.
where
(
id:
env_ids
).
select
do
|
environment
|
Ability
.
allowed?
(
user
,
:read_environment
,
environment
)
end
end
private_class_method
:find_environments
end
end
app/models/merge_request.rb
View file @
dadc046d
...
@@ -204,6 +204,12 @@ class MergeRequest < ActiveRecord::Base
...
@@ -204,6 +204,12 @@ class MergeRequest < ActiveRecord::Base
head_pipeline
&
.
sha
==
diff_head_sha
?
head_pipeline
:
nil
head_pipeline
&
.
sha
==
diff_head_sha
?
head_pipeline
:
nil
end
end
def
merge_pipeline
return
unless
merged?
target_project
.
pipeline_for
(
target_branch
,
merge_commit_sha
)
end
# Pattern used to extract `!123` merge request references from text
# Pattern used to extract `!123` merge request references from text
#
#
# This pattern supports cross-project references.
# This pattern supports cross-project references.
...
...
app/serializers/environment_status_entity.rb
View file @
dadc046d
...
@@ -5,6 +5,7 @@ class EnvironmentStatusEntity < Grape::Entity
...
@@ -5,6 +5,7 @@ class EnvironmentStatusEntity < Grape::Entity
expose
:id
expose
:id
expose
:name
expose
:name
expose
:status
expose
:url
do
|
es
|
expose
:url
do
|
es
|
project_environment_path
(
es
.
project
,
es
.
environment
)
project_environment_path
(
es
.
project
,
es
.
environment
)
...
...
app/serializers/merge_request_widget_entity.rb
View file @
dadc046d
...
@@ -55,6 +55,7 @@ class MergeRequestWidgetEntity < IssuableEntity
...
@@ -55,6 +55,7 @@ class MergeRequestWidgetEntity < IssuableEntity
expose
:merge_commit_message
expose
:merge_commit_message
expose
:actual_head_pipeline
,
with:
PipelineDetailsEntity
,
as: :pipeline
expose
:actual_head_pipeline
,
with:
PipelineDetailsEntity
,
as: :pipeline
expose
:merge_pipeline
,
with:
PipelineDetailsEntity
,
if:
->
(
mr
,
_
)
{
mr
.
merged?
&&
can?
(
request
.
current_user
,
:read_pipeline
,
mr
.
target_project
)}
# Booleans
# Booleans
expose
:merge_ongoing?
,
as: :merge_ongoing
expose
:merge_ongoing?
,
as: :merge_ongoing
...
...
changelogs/unreleased/ac-post-merge-pipeline.yml
0 → 100644
View file @
dadc046d
---
title
:
Show post-merge pipeline in merge request page
merge_request
:
22292
author
:
type
:
added
locale/gitlab.pot
View file @
dadc046d
...
@@ -648,6 +648,9 @@ msgstr ""
...
@@ -648,6 +648,9 @@ msgstr ""
msgid "Are you sure you want to reset the health check token?"
msgid "Are you sure you want to reset the health check token?"
msgstr ""
msgstr ""
msgid "Are you sure you want to stop this environment?"
msgstr ""
msgid "Are you sure?"
msgid "Are you sure?"
msgstr ""
msgstr ""
...
@@ -2324,6 +2327,12 @@ msgstr ""
...
@@ -2324,6 +2327,12 @@ msgstr ""
msgid "DeployTokens|Your new project deploy token has been created."
msgid "DeployTokens|Your new project deploy token has been created."
msgstr ""
msgstr ""
msgid "Deployed to"
msgstr ""
msgid "Deploying to"
msgstr ""
msgid "Deprioritize label"
msgid "Deprioritize label"
msgstr ""
msgstr ""
...
@@ -2750,6 +2759,9 @@ msgstr ""
...
@@ -2750,6 +2759,9 @@ msgstr ""
msgid "Failed to check related branches."
msgid "Failed to check related branches."
msgstr ""
msgstr ""
msgid "Failed to deploy to"
msgstr ""
msgid "Failed to load emoji list."
msgid "Failed to load emoji list."
msgstr ""
msgstr ""
...
@@ -5604,6 +5616,9 @@ msgstr ""
...
@@ -5604,6 +5616,9 @@ msgstr ""
msgid "Something went wrong while fetching comments. Please try again."
msgid "Something went wrong while fetching comments. Please try again."
msgstr ""
msgstr ""
msgid "Something went wrong while fetching the environments for this merge request. Please try again."
msgstr ""
msgid "Something went wrong while fetching the projects."
msgid "Something went wrong while fetching the projects."
msgstr ""
msgstr ""
...
...
spec/controllers/projects/merge_requests_controller_spec.rb
View file @
dadc046d
...
@@ -749,13 +749,15 @@ describe Projects::MergeRequestsController do
...
@@ -749,13 +749,15 @@ describe Projects::MergeRequestsController do
describe
'GET ci_environments_status'
do
describe
'GET ci_environments_status'
do
context
'the environment is from a forked project'
do
context
'the environment is from a forked project'
do
let!
(
:forked
)
{
fork_project
(
project
,
user
,
repository:
true
)
}
let
(
:forked
)
{
fork_project
(
project
,
user
,
repository:
true
)
}
let!
(
:environment
)
{
create
(
:environment
,
project:
forked
)
}
let
(
:sha
)
{
forked
.
commit
.
sha
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
sha:
forked
.
commit
.
id
,
ref:
'master'
)
}
let
(
:environment
)
{
create
(
:environment
,
project:
forked
)
}
let
(
:admin
)
{
create
(
:admin
)
}
let
(
:pipeline
)
{
create
(
:ci_pipeline
,
sha:
sha
,
project:
forked
)
}
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
sha:
sha
,
ref:
'master'
,
deployable:
build
)
}
let
(
:merge_request
)
do
let
(
:merge_request
)
do
create
(
:merge_request
,
source_project:
forked
,
target_project:
project
)
create
(
:merge_request
,
source_project:
forked
,
target_project:
project
,
target_branch:
'master'
,
head_pipeline:
pipeline
)
end
end
it
'links to the environment on that project'
do
it
'links to the environment on that project'
do
...
@@ -764,6 +766,35 @@ describe Projects::MergeRequestsController do
...
@@ -764,6 +766,35 @@ describe Projects::MergeRequestsController do
expect
(
json_response
.
first
[
'url'
]).
to
match
/
#{
forked
.
full_path
}
/
expect
(
json_response
.
first
[
'url'
]).
to
match
/
#{
forked
.
full_path
}
/
end
end
context
"when environment_target is 'merge_commit'"
do
it
'returns nothing'
do
get_ci_environments_status
(
environment_target:
'merge_commit'
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
).
to
be_empty
end
context
'when is merged'
do
let
(
:source_environment
)
{
create
(
:environment
,
project:
project
)
}
let
(
:merge_commit_sha
)
{
project
.
repository
.
merge
(
user
,
forked
.
commit
.
id
,
merge_request
,
"merged in test"
)
}
let
(
:post_merge_pipeline
)
{
create
(
:ci_pipeline
,
sha:
merge_commit_sha
,
project:
project
)
}
let
(
:post_merge_build
)
{
create
(
:ci_build
,
pipeline:
post_merge_pipeline
)
}
let!
(
:source_deployment
)
{
create
(
:deployment
,
environment:
source_environment
,
sha:
merge_commit_sha
,
ref:
'master'
,
deployable:
post_merge_build
)
}
before
do
merge_request
.
update!
(
merge_commit_sha:
merge_commit_sha
)
merge_request
.
mark_as_merged!
end
it
'returns the enviroment on the source project'
do
get_ci_environments_status
(
environment_target:
'merge_commit'
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
.
first
[
'url'
]).
to
match
/
#{
project
.
full_path
}
/
end
end
end
# we're trying to reduce the overall number of queries for this method.
# we're trying to reduce the overall number of queries for this method.
# set a hard limit for now. https://gitlab.com/gitlab-org/gitlab-ce/issues/52287
# set a hard limit for now. https://gitlab.com/gitlab-org/gitlab-ce/issues/52287
it
'keeps queries in check'
do
it
'keeps queries in check'
do
...
@@ -772,11 +803,15 @@ describe Projects::MergeRequestsController do
...
@@ -772,11 +803,15 @@ describe Projects::MergeRequestsController do
expect
(
control_count
).
to
be
<=
137
expect
(
control_count
).
to
be
<=
137
end
end
def
get_ci_environments_status
def
get_ci_environments_status
(
extra_params
=
{})
get
:ci_environments_status
,
params
=
{
namespace_id:
merge_request
.
project
.
namespace
.
to_param
,
namespace_id:
merge_request
.
project
.
namespace
.
to_param
,
project_id:
merge_request
.
project
,
project_id:
merge_request
.
project
,
id:
merge_request
.
iid
,
format:
'json'
id:
merge_request
.
iid
,
format:
'json'
}
get
:ci_environments_status
,
params
.
merge
(
extra_params
)
end
end
end
end
end
end
...
...
spec/features/merge_request/user_sees_deployment_widget_spec.rb
View file @
dadc046d
...
@@ -3,15 +3,19 @@ require 'rails_helper'
...
@@ -3,15 +3,19 @@ require 'rails_helper'
describe
'Merge request > User sees deployment widget'
,
:js
do
describe
'Merge request > User sees deployment widget'
,
:js
do
describe
'when deployed to an environment'
do
describe
'when deployed to an environment'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:project
)
{
merge_request
.
target_project
}
let
(
:project
)
{
create
(
:project
,
:repository
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:merged
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:merged
,
source_project:
project
)
}
let
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
let
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
let
(
:role
)
{
:developer
}
let
(
:role
)
{
:developer
}
let
(
:sha
)
{
project
.
commit
(
'master'
).
id
}
let
(
:ref
)
{
merge_request
.
target_branch
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
sha:
sha
)
}
let
(
:sha
)
{
project
.
commit
(
ref
).
id
}
let
(
:pipeline
)
{
create
(
:ci_pipeline_without_jobs
,
sha:
sha
,
project:
project
,
ref:
ref
)
}
let
(
:build
)
{
create
(
:ci_build
,
:success
,
pipeline:
pipeline
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
sha:
sha
,
ref:
ref
,
deployable:
build
)
}
let!
(
:manual
)
{
}
let!
(
:manual
)
{
}
before
do
before
do
merge_request
.
update!
(
merge_commit_sha:
sha
)
project
.
add_user
(
user
,
role
)
project
.
add_user
(
user
,
role
)
sign_in
(
user
)
sign_in
(
user
)
visit
project_merge_request_path
(
project
,
merge_request
)
visit
project_merge_request_path
(
project
,
merge_request
)
...
@@ -26,15 +30,10 @@ describe 'Merge request > User sees deployment widget', :js do
...
@@ -26,15 +30,10 @@ describe 'Merge request > User sees deployment widget', :js do
end
end
context
'with stop action'
do
context
'with stop action'
do
let
(
:pipeline
)
{
create
(
:ci_pipeline
,
project:
project
)
}
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let
(
:manual
)
{
create
(
:ci_build
,
:manual
,
pipeline:
pipeline
,
name:
'close_app'
)
}
let
(
:manual
)
{
create
(
:ci_build
,
:manual
,
pipeline:
pipeline
,
name:
'close_app'
)
}
let
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
ref:
merge_request
.
target_branch
,
sha:
sha
,
deployable:
build
,
on_stop:
'close_app'
)
end
before
do
before
do
deployment
.
update!
(
on_stop:
manual
.
name
)
wait_for_requests
wait_for_requests
end
end
...
...
spec/features/merge_request/user_sees_merge_widget_spec.rb
View file @
dadc046d
...
@@ -40,21 +40,26 @@ describe 'Merge request > User sees merge widget', :js do
...
@@ -40,21 +40,26 @@ describe 'Merge request > User sees merge widget', :js do
context
'view merge request'
do
context
'view merge request'
do
let!
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
let!
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
let
(
:sha
)
{
project
.
commit
(
merge_request
.
source_branch
).
sha
}
let
(
:pipeline
)
{
create
(
:ci_pipeline_without_jobs
,
status:
'success'
,
sha:
sha
,
project:
project
,
ref:
merge_request
.
source_branch
)
}
let
(
:build
)
{
create
(
:ci_build
,
:success
,
pipeline:
pipeline
)
}
let!
(
:deployment
)
do
let!
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
create
(
:deployment
,
environment:
environment
,
ref:
'feature'
,
ref:
merge_request
.
source_branch
,
sha:
merge_request
.
diff_head_sha
)
deployable:
build
,
sha:
sha
)
end
end
before
do
before
do
merge_request
.
update!
(
head_pipeline:
pipeline
)
visit
project_merge_request_path
(
project
,
merge_request
)
visit
project_merge_request_path
(
project
,
merge_request
)
end
end
it
'shows environments link'
do
it
'shows environments link'
do
wait_for_requests
wait_for_requests
page
.
within
(
'.
mr-widget-heading
'
)
do
page
.
within
(
'.
js-pre-merge-deploy
'
)
do
expect
(
page
).
to
have_content
(
"Deployed to
#{
environment
.
name
}
"
)
expect
(
page
).
to
have_content
(
"Deployed to
#{
environment
.
name
}
"
)
expect
(
find
(
'.js-deploy-url'
)[
:href
]).
to
include
(
environment
.
formatted_external_url
)
expect
(
find
(
'.js-deploy-url'
)[
:href
]).
to
include
(
environment
.
formatted_external_url
)
end
end
...
...
spec/fixtures/api/schemas/entities/merge_request_widget.json
View file @
dadc046d
...
@@ -46,6 +46,7 @@
...
@@ -46,6 +46,7 @@
"diff_head_commit_short_id"
:
{
"type"
:
[
"string"
,
"null"
]
},
"diff_head_commit_short_id"
:
{
"type"
:
[
"string"
,
"null"
]
},
"merge_commit_message"
:
{
"type"
:
[
"string"
,
"null"
]
},
"merge_commit_message"
:
{
"type"
:
[
"string"
,
"null"
]
},
"pipeline"
:
{
"type"
:
[
"object"
,
"null"
]
},
"pipeline"
:
{
"type"
:
[
"object"
,
"null"
]
},
"merge_pipeline"
:
{
"type"
:
[
"object"
,
"null"
]
},
"work_in_progress"
:
{
"type"
:
"boolean"
},
"work_in_progress"
:
{
"type"
:
"boolean"
},
"source_branch_exists"
:
{
"type"
:
"boolean"
},
"source_branch_exists"
:
{
"type"
:
"boolean"
},
"mergeable_discussions_state"
:
{
"type"
:
"boolean"
},
"mergeable_discussions_state"
:
{
"type"
:
"boolean"
},
...
...
spec/javascripts/vue_mr_widget/components/deployment_spec.js
View file @
dadc046d
...
@@ -2,16 +2,19 @@ import Vue from 'vue';
...
@@ -2,16 +2,19 @@ import Vue from 'vue';
import
deploymentComponent
from
'
~/vue_merge_request_widget/components/deployment.vue
'
;
import
deploymentComponent
from
'
~/vue_merge_request_widget/components/deployment.vue
'
;
import
MRWidgetService
from
'
~/vue_merge_request_widget/services/mr_widget_service
'
;
import
MRWidgetService
from
'
~/vue_merge_request_widget/services/mr_widget_service
'
;
import
{
getTimeago
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
getTimeago
}
from
'
~/lib/utils/datetime_utility
'
;
import
mountComponent
from
'
../../helpers/vue_mount_component_helper
'
;
const
deploymentMockData
=
{
describe
(
'
Deployment component
'
,
()
=>
{
const
Component
=
Vue
.
extend
(
deploymentComponent
);
const
deploymentMockData
=
{
id
:
15
,
id
:
15
,
name
:
'
review/diplo
'
,
name
:
'
review/diplo
'
,
url
:
'
/root/acets-
review-apps/environments/15
'
,
url
:
'
/root/
review-apps/environments/15
'
,
stop_url
:
'
/root/acets-
review-apps/environments/15/stop
'
,
stop_url
:
'
/root/
review-apps/environments/15/stop
'
,
metrics_url
:
'
/root/acets-
review-apps/environments/15/deployments/1/metrics
'
,
metrics_url
:
'
/root/
review-apps/environments/15/deployments/1/metrics
'
,
metrics_monitoring_url
:
'
/root/acets-
review-apps/environments/15/metrics
'
,
metrics_monitoring_url
:
'
/root/
review-apps/environments/15/metrics
'
,
external_url
:
'
http://diplo
.
'
,
external_url
:
'
http://gitlab.com
.
'
,
external_url_formatted
:
'
diplo.
'
,
external_url_formatted
:
'
gitlab
'
,
deployed_at
:
'
2017-03-22T22:44:42.258Z
'
,
deployed_at
:
'
2017-03-22T22:44:42.258Z
'
,
deployed_at_formatted
:
'
Mar 22, 2017 10:44pm
'
,
deployed_at_formatted
:
'
Mar 22, 2017 10:44pm
'
,
changes
:
[
changes
:
[
...
@@ -28,28 +31,19 @@ const deploymentMockData = {
...
@@ -28,28 +31,19 @@ const deploymentMockData = {
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/about/
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/about/
'
,
},
},
],
],
};
};
const
createComponent
=
()
=>
{
const
Component
=
Vue
.
extend
(
deploymentComponent
);
return
new
Component
({
el
:
document
.
createElement
(
'
div
'
),
propsData
:
{
deployment
:
{
...
deploymentMockData
}
},
});
};
describe
(
'
Deployment component
'
,
()
=>
{
let
vm
;
let
vm
;
beforeEach
(()
=>
{
vm
=
createComponent
();
});
afterEach
(()
=>
{
afterEach
(()
=>
{
vm
.
$destroy
();
vm
.
$destroy
();
});
});
describe
(
'
computed
'
,
()
=>
{
describe
(
''
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
deployment
:
{
...
deploymentMockData
}
});
});
describe
(
'
deployTimeago
'
,
()
=>
{
describe
(
'
deployTimeago
'
,
()
=>
{
it
(
'
return formatted date
'
,
()
=>
{
it
(
'
return formatted date
'
,
()
=>
{
const
readable
=
getTimeago
().
format
(
deploymentMockData
.
deployed_at
);
const
readable
=
getTimeago
().
format
(
deploymentMockData
.
deployed_at
);
...
@@ -111,9 +105,7 @@ describe('Deployment component', () => {
...
@@ -111,9 +105,7 @@ describe('Deployment component', () => {
expect
(
vm
.
hasDeploymentMeta
).
toEqual
(
false
);
expect
(
vm
.
hasDeploymentMeta
).
toEqual
(
false
);
});
});
});
});
});
describe
(
'
methods
'
,
()
=>
{
describe
(
'
stopEnvironment
'
,
()
=>
{
describe
(
'
stopEnvironment
'
,
()
=>
{
const
url
=
'
/foo/bar
'
;
const
url
=
'
/foo/bar
'
;
const
returnPromise
=
()
=>
const
returnPromise
=
()
=>
...
@@ -152,42 +144,33 @@ describe('Deployment component', () => {
...
@@ -152,42 +144,33 @@ describe('Deployment component', () => {
expect
(
MRWidgetService
.
stopEnvironment
).
not
.
toHaveBeenCalled
();
expect
(
MRWidgetService
.
stopEnvironment
).
not
.
toHaveBeenCalled
();
});
});
});
});
});
describe
(
'
template
'
,
()
=>
{
let
el
;
beforeEach
(()
=>
{
vm
=
createComponent
(
deploymentMockData
);
el
=
vm
.
$el
;
});
it
(
'
renders deployment name
'
,
()
=>
{
it
(
'
renders deployment name
'
,
()
=>
{
expect
(
el
.
querySelector
(
'
.js-deploy-meta
'
).
getAttribute
(
'
href
'
)).
toEqual
(
expect
(
vm
.
$
el
.
querySelector
(
'
.js-deploy-meta
'
).
getAttribute
(
'
href
'
)).
toEqual
(
deploymentMockData
.
url
,
deploymentMockData
.
url
,
);
);
expect
(
el
.
querySelector
(
'
.js-deploy-meta
'
).
innerText
).
toContain
(
deploymentMockData
.
name
);
expect
(
vm
.
$
el
.
querySelector
(
'
.js-deploy-meta
'
).
innerText
).
toContain
(
deploymentMockData
.
name
);
});
});
it
(
'
renders external URL
'
,
()
=>
{
it
(
'
renders external URL
'
,
()
=>
{
expect
(
el
.
querySelector
(
'
.js-deploy-url
'
).
getAttribute
(
'
href
'
)).
toEqual
(
expect
(
vm
.
$
el
.
querySelector
(
'
.js-deploy-url
'
).
getAttribute
(
'
href
'
)).
toEqual
(
deploymentMockData
.
external_url
,
deploymentMockData
.
external_url
,
);
);
expect
(
el
.
querySelector
(
'
.js-deploy-url
'
).
innerText
).
toContain
(
'
View app
'
);
expect
(
vm
.
$
el
.
querySelector
(
'
.js-deploy-url
'
).
innerText
).
toContain
(
'
View app
'
);
});
});
it
(
'
renders stop button
'
,
()
=>
{
it
(
'
renders stop button
'
,
()
=>
{
expect
(
el
.
querySelector
(
'
.btn
'
)).
not
.
toBeNull
();
expect
(
vm
.
$
el
.
querySelector
(
'
.btn
'
)).
not
.
toBeNull
();
});
});
it
(
'
renders deployment time
'
,
()
=>
{
it
(
'
renders deployment time
'
,
()
=>
{
expect
(
el
.
querySelector
(
'
.js-deploy-time
'
).
innerText
).
toContain
(
vm
.
deployTimeago
);
expect
(
vm
.
$
el
.
querySelector
(
'
.js-deploy-time
'
).
innerText
).
toContain
(
vm
.
deployTimeago
);
});
});
it
(
'
renders metrics component
'
,
()
=>
{
it
(
'
renders metrics component
'
,
()
=>
{
expect
(
el
.
querySelector
(
'
.js-mr-memory-usage
'
)).
not
.
toBeNull
();
expect
(
vm
.
$
el
.
querySelector
(
'
.js-mr-memory-usage
'
)).
not
.
toBeNull
();
});
});
});
});
...
@@ -196,8 +179,7 @@ describe('Deployment component', () => {
...
@@ -196,8 +179,7 @@ describe('Deployment component', () => {
window
.
gon
=
window
.
gon
||
{};
window
.
gon
=
window
.
gon
||
{};
window
.
gon
.
features
=
window
.
gon
.
features
||
{};
window
.
gon
.
features
=
window
.
gon
.
features
||
{};
window
.
gon
.
features
.
ciEnvironmentsStatusChanges
=
true
;
window
.
gon
.
features
.
ciEnvironmentsStatusChanges
=
true
;
vm
=
mountComponent
(
Component
,
{
deployment
:
{
...
deploymentMockData
}
});
vm
=
createComponent
(
deploymentMockData
);
});
});
afterEach
(()
=>
{
afterEach
(()
=>
{
...
@@ -216,7 +198,7 @@ describe('Deployment component', () => {
...
@@ -216,7 +198,7 @@ describe('Deployment component', () => {
window
.
gon
.
features
=
window
.
gon
.
features
||
{};
window
.
gon
.
features
=
window
.
gon
.
features
||
{};
window
.
gon
.
features
.
ciEnvironmentsStatusChanges
=
false
;
window
.
gon
.
features
.
ciEnvironmentsStatusChanges
=
false
;
vm
=
createComponent
(
deploymentMockData
);
vm
=
mountComponent
(
Component
,
{
deployment
:
{
...
deploymentMockData
}
}
);
});
});
afterEach
(()
=>
{
afterEach
(()
=>
{
...
@@ -228,4 +210,44 @@ describe('Deployment component', () => {
...
@@ -228,4 +210,44 @@ describe('Deployment component', () => {
expect
(
vm
.
$el
.
querySelector
(
'
.js-deploy-url-feature-flag
'
)).
not
.
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
.js-deploy-url-feature-flag
'
)).
not
.
toBeNull
();
});
});
});
});
describe
(
'
deployment status
'
,
()
=>
{
describe
(
'
running
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
deployment
:
Object
.
assign
({},
deploymentMockData
,
{
status
:
'
running
'
}),
});
});
it
(
'
renders information about running deployment
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-deployment-info
'
).
textContent
).
toContain
(
'
Deploying to
'
);
});
});
describe
(
'
success
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
deployment
:
Object
.
assign
({},
deploymentMockData
,
{
status
:
'
success
'
}),
});
});
it
(
'
renders information about finished deployment
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-deployment-info
'
).
textContent
).
toContain
(
'
Deployed to
'
);
});
});
describe
(
'
failed
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
deployment
:
Object
.
assign
({},
deploymentMockData
,
{
status
:
'
failed
'
}),
});
});
it
(
'
renders information about finished deployment
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-deployment-info
'
).
textContent
).
toContain
(
'
Failed to deploy to
'
,
);
});
});
});
});
});
spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
View file @
dadc046d
...
@@ -189,7 +189,7 @@ describe('mrWidgetOptions', () => {
...
@@ -189,7 +189,7 @@ describe('mrWidgetOptions', () => {
it
(
'
should fetch deployments
'
,
done
=>
{
it
(
'
should fetch deployments
'
,
done
=>
{
spyOn
(
vm
.
service
,
'
fetchDeployments
'
).
and
.
returnValue
(
returnPromise
([{
id
:
1
}]));
spyOn
(
vm
.
service
,
'
fetchDeployments
'
).
and
.
returnValue
(
returnPromise
([{
id
:
1
}]));
vm
.
fetchDeployments
();
vm
.
fetch
PreMerge
Deployments
();
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
vm
.
service
.
fetchDeployments
).
toHaveBeenCalled
();
expect
(
vm
.
service
.
fetchDeployments
).
toHaveBeenCalled
();
...
@@ -454,6 +454,7 @@ describe('mrWidgetOptions', () => {
...
@@ -454,6 +454,7 @@ describe('mrWidgetOptions', () => {
deployed_at
:
'
2017-03-22T22:44:42.258Z
'
,
deployed_at
:
'
2017-03-22T22:44:42.258Z
'
,
deployed_at_formatted
:
'
Mar 22, 2017 10:44pm
'
,
deployed_at_formatted
:
'
Mar 22, 2017 10:44pm
'
,
changes
,
changes
,
status
:
'
success
'
};
};
beforeEach
(
done
=>
{
beforeEach
(
done
=>
{
...
@@ -486,4 +487,189 @@ describe('mrWidgetOptions', () => {
...
@@ -486,4 +487,189 @@ describe('mrWidgetOptions', () => {
).
toEqual
(
changes
.
length
);
).
toEqual
(
changes
.
length
);
});
});
});
});
describe
(
'
pipeline for target branch after merge
'
,
()
=>
{
describe
(
'
with information for target branch pipeline
'
,
()
=>
{
beforeEach
(
done
=>
{
vm
.
mr
.
state
=
'
merged
'
;
vm
.
mr
.
mergePipeline
=
{
id
:
127
,
user
:
{
id
:
1
,
name
:
'
Administrator
'
,
username
:
'
root
'
,
state
:
'
active
'
,
avatar_url
:
null
,
web_url
:
'
http://localhost:3000/root
'
,
status_tooltip_html
:
null
,
path
:
'
/root
'
,
},
active
:
true
,
coverage
:
null
,
source
:
'
push
'
,
created_at
:
'
2018-10-22T11:41:35.186Z
'
,
updated_at
:
'
2018-10-22T11:41:35.433Z
'
,
path
:
'
/root/ci-web-terminal/pipelines/127
'
,
flags
:
{
latest
:
true
,
stuck
:
true
,
auto_devops
:
false
,
yaml_errors
:
false
,
retryable
:
false
,
cancelable
:
true
,
failure_reason
:
false
,
},
details
:
{
status
:
{
icon
:
'
status_pending
'
,
text
:
'
pending
'
,
label
:
'
pending
'
,
group
:
'
pending
'
,
tooltip
:
'
pending
'
,
has_details
:
true
,
details_path
:
'
/root/ci-web-terminal/pipelines/127
'
,
illustration
:
null
,
favicon
:
'
/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png
'
,
},
duration
:
null
,
finished_at
:
null
,
stages
:
[
{
name
:
'
test
'
,
title
:
'
test: pending
'
,
status
:
{
icon
:
'
status_pending
'
,
text
:
'
pending
'
,
label
:
'
pending
'
,
group
:
'
pending
'
,
tooltip
:
'
pending
'
,
has_details
:
true
,
details_path
:
'
/root/ci-web-terminal/pipelines/127#test
'
,
illustration
:
null
,
favicon
:
'
/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png
'
,
},
path
:
'
/root/ci-web-terminal/pipelines/127#test
'
,
dropdown_path
:
'
/root/ci-web-terminal/pipelines/127/stage.json?stage=test
'
,
},
],
artifacts
:
[],
manual_actions
:
[],
scheduled_actions
:
[],
},
ref
:
{
name
:
'
master
'
,
path
:
'
/root/ci-web-terminal/commits/master
'
,
tag
:
false
,
branch
:
true
,
},
commit
:
{
id
:
'
aa1939133d373c94879becb79d91828a892ee319
'
,
short_id
:
'
aa193913
'
,
title
:
"
Merge branch 'master-test' into 'master'
"
,
created_at
:
'
2018-10-22T11:41:33.000Z
'
,
parent_ids
:
[
'
4622f4dd792468993003caf2e3be978798cbe096
'
,
'
76598df914cdfe87132d0c3c40f80db9fa9396a4
'
,
],
message
:
"
Merge branch 'master-test' into 'master'
\n\n
Update .gitlab-ci.yml
\n\n
See merge request root/ci-web-terminal!1
"
,
author_name
:
'
Administrator
'
,
author_email
:
'
admin@example.com
'
,
authored_date
:
'
2018-10-22T11:41:33.000Z
'
,
committer_name
:
'
Administrator
'
,
committer_email
:
'
admin@example.com
'
,
committed_date
:
'
2018-10-22T11:41:33.000Z
'
,
author
:
{
id
:
1
,
name
:
'
Administrator
'
,
username
:
'
root
'
,
state
:
'
active
'
,
avatar_url
:
null
,
web_url
:
'
http://localhost:3000/root
'
,
status_tooltip_html
:
null
,
path
:
'
/root
'
,
},
author_gravatar_url
:
null
,
commit_url
:
'
http://localhost:3000/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319
'
,
commit_path
:
'
/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319
'
,
},
cancel_path
:
'
/root/ci-web-terminal/pipelines/127/cancel
'
,
};
vm
.
$nextTick
(
done
);
});
it
(
'
renders pipeline block
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-post-merge-pipeline
'
)).
not
.
toBeNull
();
});
describe
(
'
with post merge deployments
'
,
()
=>
{
beforeEach
(
done
=>
{
vm
.
mr
.
postMergeDeployments
=
[{
id
:
15
,
name
:
'
review/diplo
'
,
url
:
'
/root/acets-review-apps/environments/15
'
,
stop_url
:
'
/root/acets-review-apps/environments/15/stop
'
,
metrics_url
:
'
/root/acets-review-apps/environments/15/deployments/1/metrics
'
,
metrics_monitoring_url
:
'
/root/acets-review-apps/environments/15/metrics
'
,
external_url
:
'
http://diplo.
'
,
external_url_formatted
:
'
diplo.
'
,
deployed_at
:
'
2017-03-22T22:44:42.258Z
'
,
deployed_at_formatted
:
'
Mar 22, 2017 10:44pm
'
,
changes
:
[
{
path
:
'
index.html
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/index.html
'
,
},
{
path
:
'
imgs/gallery.html
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/imgs/gallery.html
'
,
},
{
path
:
'
about/
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/about/
'
,
},
],
status
:
'
success
'
}];
vm
.
$nextTick
(
done
);
});
it
(
'
renders post deployment information
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-post-deployment
'
)).
not
.
toBeNull
();
});
});
});
describe
(
'
without information for target branch pipeline
'
,
()
=>
{
beforeEach
(
done
=>
{
vm
.
mr
.
state
=
'
merged
'
;
vm
.
$nextTick
(
done
);
});
it
(
'
does not render pipeline block
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-post-merge-pipeline
'
)).
toBeNull
();
});
});
describe
(
'
when state is not merged
'
,
()
=>
{
beforeEach
(
done
=>
{
vm
.
mr
.
state
=
'
archived
'
;
vm
.
$nextTick
(
done
);
});
it
(
'
does not render pipeline block
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-post-merge-pipeline
'
)).
toBeNull
();
});
it
(
'
does not render post deployment information
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-post-deployment
'
)).
toBeNull
();
});
});
});
});
});
spec/models/environment_status_spec.rb
View file @
dadc046d
...
@@ -5,13 +5,15 @@ describe EnvironmentStatus do
...
@@ -5,13 +5,15 @@ describe EnvironmentStatus do
let
(
:environment
)
{
deployment
.
environment
}
let
(
:environment
)
{
deployment
.
environment
}
let
(
:project
)
{
deployment
.
project
}
let
(
:project
)
{
deployment
.
project
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:deployed_review_app
,
deployment:
deployment
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:deployed_review_app
,
deployment:
deployment
)
}
let
(
:sha
)
{
deployment
.
sha
}
subject
(
:environment_status
)
{
described_class
.
new
(
environment
,
merge_request
)
}
subject
(
:environment_status
)
{
described_class
.
new
(
environment
,
merge_request
,
sha
)
}
it
{
is_expected
.
to
delegate_method
(
:id
).
to
(
:environment
)
}
it
{
is_expected
.
to
delegate_method
(
:id
).
to
(
:environment
)
}
it
{
is_expected
.
to
delegate_method
(
:name
).
to
(
:environment
)
}
it
{
is_expected
.
to
delegate_method
(
:name
).
to
(
:environment
)
}
it
{
is_expected
.
to
delegate_method
(
:project
).
to
(
:environment
)
}
it
{
is_expected
.
to
delegate_method
(
:project
).
to
(
:environment
)
}
it
{
is_expected
.
to
delegate_method
(
:deployed_at
).
to
(
:deployment
).
as
(
:created_at
)
}
it
{
is_expected
.
to
delegate_method
(
:deployed_at
).
to
(
:deployment
).
as
(
:created_at
)
}
it
{
is_expected
.
to
delegate_method
(
:status
).
to
(
:deployment
)
}
describe
'#project'
do
describe
'#project'
do
subject
{
environment_status
.
project
}
subject
{
environment_status
.
project
}
...
@@ -58,4 +60,32 @@ describe EnvironmentStatus do
...
@@ -58,4 +60,32 @@ describe EnvironmentStatus do
)
)
end
end
end
end
describe
'.for_merge_request'
do
let
(
:admin
)
{
create
(
:admin
)
}
let
(
:pipeline
)
{
create
(
:ci_pipeline
,
sha:
sha
)
}
it
'is based on merge_request.head_pipeline'
do
expect
(
merge_request
).
to
receive
(
:head_pipeline
).
and_return
(
pipeline
)
expect
(
merge_request
).
not_to
receive
(
:merge_pipeline
)
described_class
.
for_merge_request
(
merge_request
,
admin
)
end
end
describe
'.after_merge_request'
do
let
(
:admin
)
{
create
(
:admin
)
}
let
(
:pipeline
)
{
create
(
:ci_pipeline
,
sha:
sha
)
}
before
do
merge_request
.
mark_as_merged!
end
it
'is based on merge_request.merge_pipeline'
do
expect
(
merge_request
).
to
receive
(
:merge_pipeline
).
and_return
(
pipeline
)
expect
(
merge_request
).
not_to
receive
(
:head_pipeline
)
described_class
.
after_merge_request
(
merge_request
,
admin
)
end
end
end
end
spec/models/merge_request_spec.rb
View file @
dadc046d
...
@@ -1058,6 +1058,26 @@ describe MergeRequest do
...
@@ -1058,6 +1058,26 @@ describe MergeRequest do
end
end
end
end
describe
'#merge_pipeline'
do
it
'returns nil when not merged'
do
expect
(
subject
.
merge_pipeline
).
to
be_nil
end
context
'when the MR is merged'
do
let
(
:sha
)
{
subject
.
target_project
.
commit
.
id
}
let
(
:pipeline
)
{
create
(
:ci_empty_pipeline
,
sha:
sha
,
ref:
subject
.
target_branch
,
project:
subject
.
target_project
)
}
before
do
subject
.
mark_as_merged!
subject
.
update_attribute
(
:merge_commit_sha
,
pipeline
.
sha
)
end
it
'returns the post-merge pipeline'
do
expect
(
subject
.
merge_pipeline
).
to
eq
(
pipeline
)
end
end
end
describe
'#has_ci?'
do
describe
'#has_ci?'
do
let
(
:merge_request
)
{
build_stubbed
(
:merge_request
)
}
let
(
:merge_request
)
{
build_stubbed
(
:merge_request
)
}
...
...
spec/serializers/environment_status_entity_spec.rb
View file @
dadc046d
...
@@ -9,7 +9,7 @@ describe EnvironmentStatusEntity do
...
@@ -9,7 +9,7 @@ describe EnvironmentStatusEntity do
let
(
:project
)
{
deployment
.
project
}
let
(
:project
)
{
deployment
.
project
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:deployed_review_app
,
deployment:
deployment
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:deployed_review_app
,
deployment:
deployment
)
}
let
(
:environment_status
)
{
EnvironmentStatus
.
new
(
environment
,
merge_request
)
}
let
(
:environment_status
)
{
EnvironmentStatus
.
new
(
environment
,
merge_request
,
merge_request
.
diff_head_sha
)
}
let
(
:entity
)
{
described_class
.
new
(
environment_status
,
request:
request
)
}
let
(
:entity
)
{
described_class
.
new
(
environment_status
,
request:
request
)
}
subject
{
entity
.
as_json
}
subject
{
entity
.
as_json
}
...
@@ -26,6 +26,7 @@ describe EnvironmentStatusEntity do
...
@@ -26,6 +26,7 @@ describe EnvironmentStatusEntity do
it
{
is_expected
.
to
include
(
:deployed_at
)
}
it
{
is_expected
.
to
include
(
:deployed_at
)
}
it
{
is_expected
.
to
include
(
:deployed_at_formatted
)
}
it
{
is_expected
.
to
include
(
:deployed_at_formatted
)
}
it
{
is_expected
.
to
include
(
:changes
)
}
it
{
is_expected
.
to
include
(
:changes
)
}
it
{
is_expected
.
to
include
(
:status
)
}
it
{
is_expected
.
not_to
include
(
:stop_url
)
}
it
{
is_expected
.
not_to
include
(
:stop_url
)
}
it
{
is_expected
.
not_to
include
(
:metrics_url
)
}
it
{
is_expected
.
not_to
include
(
:metrics_url
)
}
...
...
spec/serializers/merge_request_widget_entity_spec.rb
View file @
dadc046d
...
@@ -52,6 +52,40 @@ describe MergeRequestWidgetEntity do
...
@@ -52,6 +52,40 @@ describe MergeRequestWidgetEntity do
end
end
end
end
describe
'merge_pipeline'
do
it
'returns nil'
do
expect
(
subject
[
:merge_pipeline
]).
to
be_nil
end
context
'when is merged'
do
let
(
:resource
)
{
create
(
:merged_merge_request
,
source_project:
project
,
merge_commit_sha:
project
.
commit
.
id
)
}
let
(
:pipeline
)
{
create
(
:ci_empty_pipeline
,
project:
project
,
ref:
resource
.
target_branch
,
sha:
resource
.
merge_commit_sha
)
}
before
do
project
.
add_maintainer
(
user
)
end
it
'returns merge_pipeline'
do
pipeline
.
reload
pipeline_payload
=
PipelineDetailsEntity
.
represent
(
pipeline
,
request:
request
)
.
as_json
expect
(
subject
[
:merge_pipeline
]).
to
eq
(
pipeline_payload
)
end
context
'when user cannot read pipelines on target project'
do
before
do
project
.
add_guest
(
user
)
end
it
'returns nil'
do
expect
(
subject
[
:merge_pipeline
]).
to
be_nil
end
end
end
end
describe
'metrics'
do
describe
'metrics'
do
context
'when metrics record exists with merged data'
do
context
'when metrics record exists with merged data'
do
before
do
before
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