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
18fa8041
Commit
18fa8041
authored
Nov 05, 2018
by
Shinya Maeda
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit '
d1b59cf6
' into stateful_deployments-ee
parents
ef250e65
d1b59cf6
Changes
53
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
53 changed files
with
1079 additions
and
333 deletions
+1079
-333
app/models/ci/build.rb
app/models/ci/build.rb
+27
-12
app/models/concerns/deployable.rb
app/models/concerns/deployable.rb
+29
-0
app/models/deployment.rb
app/models/deployment.rb
+60
-16
app/models/environment.rb
app/models/environment.rb
+2
-2
app/models/environment_status.rb
app/models/environment_status.rb
+1
-5
app/models/project.rb
app/models/project.rb
+1
-1
app/services/update_deployment_service.rb
app/services/update_deployment_service.rb
+53
-0
app/workers/all_queues.yml
app/workers/all_queues.yml
+2
-0
app/workers/build_success_worker.rb
app/workers/build_success_worker.rb
+8
-1
app/workers/deployments/success_worker.rb
app/workers/deployments/success_worker.rb
+17
-0
changelogs/unreleased/stateful_deployments.yml
changelogs/unreleased/stateful_deployments.yml
+5
-0
config/sidekiq_queues.yml
config/sidekiq_queues.yml
+1
-0
db/fixtures/development/17_cycle_analytics.rb
db/fixtures/development/17_cycle_analytics.rb
+4
-6
db/migrate/20181015155839_add_finished_at_to_deployments.rb
db/migrate/20181015155839_add_finished_at_to_deployments.rb
+15
-0
db/migrate/20181016141739_add_status_to_deployments.rb
db/migrate/20181016141739_add_status_to_deployments.rb
+29
-0
db/migrate/20181022135539_add_index_on_status_to_deployments.rb
...rate/20181022135539_add_index_on_status_to_deployments.rb
+19
-0
db/migrate/20181023144439_add_partial_index_for_legacy_successful_deployments.rb
...39_add_partial_index_for_legacy_successful_deployments.rb
+18
-0
db/post_migrate/20181030135124_fill_empty_finished_at_in_deployments.rb
...e/20181030135124_fill_empty_finished_at_in_deployments.rb
+27
-0
db/schema.rb
db/schema.rb
+5
-0
lib/gitlab/ci/pipeline/chain/create.rb
lib/gitlab/ci/pipeline/chain/create.rb
+1
-16
spec/controllers/projects/deployments_controller_spec.rb
spec/controllers/projects/deployments_controller_spec.rb
+6
-6
spec/controllers/projects/jobs_controller_spec.rb
spec/controllers/projects/jobs_controller_spec.rb
+1
-1
spec/controllers/projects/merge_requests_controller_spec.rb
spec/controllers/projects/merge_requests_controller_spec.rb
+2
-2
spec/factories/ci/builds.rb
spec/factories/ci/builds.rb
+24
-0
spec/factories/deployments.rb
spec/factories/deployments.rb
+26
-0
spec/factories/environments.rb
spec/factories/environments.rb
+1
-0
spec/features/merge_request/user_sees_deployment_widget_spec.rb
...eatures/merge_request/user_sees_deployment_widget_spec.rb
+1
-1
spec/features/merge_request/user_sees_merge_widget_spec.rb
spec/features/merge_request/user_sees_merge_widget_spec.rb
+2
-1
spec/features/projects/environments/environment_spec.rb
spec/features/projects/environments/environment_spec.rb
+5
-4
spec/features/projects/environments/environments_spec.rb
spec/features/projects/environments/environments_spec.rb
+7
-4
spec/features/projects/jobs_spec.rb
spec/features/projects/jobs_spec.rb
+8
-6
spec/features/projects/view_on_env_spec.rb
spec/features/projects/view_on_env_spec.rb
+1
-1
spec/finders/environments_finder_spec.rb
spec/finders/environments_finder_spec.rb
+8
-8
spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
+3
-3
spec/lib/gitlab/slash_commands/command_spec.rb
spec/lib/gitlab/slash_commands/command_spec.rb
+1
-1
spec/lib/gitlab/slash_commands/deploy_spec.rb
spec/lib/gitlab/slash_commands/deploy_spec.rb
+1
-1
spec/migrations/delete_inconsistent_internal_id_records_spec.rb
...igrations/delete_inconsistent_internal_id_records_spec.rb
+15
-0
spec/migrations/fill_empty_finished_at_in_deployments_spec.rb
.../migrations/fill_empty_finished_at_in_deployments_spec.rb
+70
-0
spec/models/ci/build_spec.rb
spec/models/ci/build_spec.rb
+103
-23
spec/models/concerns/deployable_spec.rb
spec/models/concerns/deployable_spec.rb
+45
-0
spec/models/deployment_spec.rb
spec/models/deployment_spec.rb
+167
-9
spec/models/environment_spec.rb
spec/models/environment_spec.rb
+76
-10
spec/models/environment_status_spec.rb
spec/models/environment_status_spec.rb
+2
-2
spec/models/merge_request_spec.rb
spec/models/merge_request_spec.rb
+4
-4
spec/models/project_spec.rb
spec/models/project_spec.rb
+34
-0
spec/requests/api/deployments_spec.rb
spec/requests/api/deployments_spec.rb
+6
-6
spec/serializers/environment_serializer_spec.rb
spec/serializers/environment_serializer_spec.rb
+2
-1
spec/serializers/environment_status_entity_spec.rb
spec/serializers/environment_status_entity_spec.rb
+2
-2
spec/services/ci/retry_build_service_spec.rb
spec/services/ci/retry_build_service_spec.rb
+1
-1
spec/services/update_deployment_service_spec.rb
spec/services/update_deployment_service_spec.rb
+60
-163
spec/support/helpers/cycle_analytics_helpers.rb
spec/support/helpers/cycle_analytics_helpers.rb
+3
-5
spec/workers/build_success_worker_spec.rb
spec/workers/build_success_worker_spec.rb
+32
-9
spec/workers/deployments/success_worker_spec.rb
spec/workers/deployments/success_worker_spec.rb
+36
-0
No files found.
app/models/ci/build.rb
View file @
18fa8041
...
...
@@ -9,6 +9,7 @@ module Ci
include
Presentable
include
Importable
include
Gitlab
::
Utils
::
StrongMemoize
include
Deployable
prepend
EE
::
Ci
::
Build
...
...
@@ -19,13 +20,11 @@ module Ci
has_many
:sourced_pipelines
,
class_name:
Ci
::
Sources
::
Pipeline
,
foreign_key: :source_job_id
has_many
:deployments
,
as: :deployable
RUNNER_FEATURES
=
{
upload_multiple_artifacts:
->
(
build
)
{
build
.
publishes_artifacts_reports?
}
}.
freeze
has_one
:
last_deployment
,
->
{
order
(
'deployments.id DESC'
)
}
,
as: :deployable
,
class_name:
'Deployment'
has_one
:
deployment
,
as: :deployable
,
class_name:
'Deployment'
has_many
:trace_sections
,
class_name:
'Ci::BuildTraceSection'
has_many
:trace_chunks
,
class_name:
'Ci::BuildTraceChunk'
,
foreign_key: :build_id
...
...
@@ -199,6 +198,8 @@ module Ci
end
after_transition
pending: :running
do
|
build
|
build
.
deployment
&
.
run
build
.
run_after_commit
do
BuildHooksWorker
.
perform_async
(
id
)
end
...
...
@@ -211,14 +212,18 @@ module Ci
end
after_transition
any
=>
[
:success
]
do
|
build
|
build
.
deployment
&
.
succeed
build
.
run_after_commit
do
BuildSuccessWorker
.
perform_async
(
id
)
PagesWorker
.
perform_async
(
:deploy
,
id
)
if
build
.
pages_generator?
end
end
before_transition
any
=>
[
:failed
]
do
|
build
|
next
unless
build
.
project
build
.
deployment
&
.
drop
next
if
build
.
retries_max
.
zero?
if
build
.
retries_count
<
build
.
retries_max
...
...
@@ -237,6 +242,10 @@ module Ci
after_transition
running:
any
do
|
build
|
Ci
::
BuildRunnerSession
.
where
(
build:
build
).
delete_all
end
after_transition
any
=>
[
:skipped
,
:canceled
]
do
|
build
|
build
.
deployment
&
.
cancel
end
end
def
ensure_metadata
...
...
@@ -326,8 +335,12 @@ module Ci
self
.
options
.
fetch
(
:environment
,
{}).
fetch
(
:action
,
'start'
)
if
self
.
options
end
def
has_deployment?
!!
self
.
deployment
end
def
outdated_deployment?
success?
&&
!
last_
deployment
.
try
(
:last?
)
success?
&&
!
deployment
.
try
(
:last?
)
end
def
depends_on_builds
...
...
@@ -342,6 +355,10 @@ module Ci
user
==
current_user
end
def
on_stop
options
&
.
dig
(
:environment
,
:on_stop
)
end
# A slugified version of the build ref, suitable for inclusion in URLs and
# domain names. Rules:
#
...
...
@@ -709,7 +726,7 @@ module Ci
if
success?
return
successful_deployment_status
elsif
complete?
&&
!
success
?
elsif
failed
?
return
:failed
end
...
...
@@ -726,13 +743,11 @@ module Ci
end
def
successful_deployment_status
if
success?
&&
last_
deployment
&
.
last?
return
:last
els
if
success?
&&
last_deployment
.
present?
return
:out_of_date
if
deployment
&
.
last?
:last
els
e
:out_of_date
end
:creating
end
def
each_report
(
report_types
)
...
...
app/models/concerns/deployable.rb
0 → 100644
View file @
18fa8041
# frozen_string_literal: true
module
Deployable
extend
ActiveSupport
::
Concern
included
do
after_create
:create_deployment
def
create_deployment
return
unless
has_environment?
&&
!
has_deployment?
environment
=
project
.
environments
.
find_or_create_by
(
name:
expanded_environment_name
)
environment
.
deployments
.
create!
(
project_id:
environment
.
project_id
,
environment:
environment
,
ref:
ref
,
tag:
tag
,
sha:
sha
,
user:
user
,
deployable:
self
,
on_stop:
on_stop
).
tap
do
|
_
|
self
.
reload
# Reload relationships
end
end
end
end
app/models/deployment.rb
View file @
18fa8041
...
...
@@ -3,6 +3,7 @@
class
Deployment
<
ActiveRecord
::
Base
include
AtomicInternalId
include
IidRoutes
include
AfterCommitQueue
belongs_to
:project
,
required:
true
belongs_to
:environment
,
required:
true
...
...
@@ -16,11 +17,44 @@ class Deployment < ActiveRecord::Base
delegate
:name
,
to: :environment
,
prefix:
true
after_create
:create_ref
after_create
:invalidate_cache
scope
:for_environment
,
->
(
environment
)
{
where
(
environment_id:
environment
)
}
state_machine
:status
,
initial: :created
do
event
:run
do
transition
created: :running
end
event
:succeed
do
transition
any
-
[
:success
]
=>
:success
end
event
:drop
do
transition
any
-
[
:failed
]
=>
:failed
end
event
:cancel
do
transition
any
-
[
:canceled
]
=>
:canceled
end
before_transition
any
=>
[
:success
,
:failed
,
:canceled
]
do
|
deployment
|
deployment
.
finished_at
=
Time
.
now
end
after_transition
any
=>
:success
do
|
deployment
|
deployment
.
run_after_commit
do
Deployments
::
SuccessWorker
.
perform_async
(
id
)
end
end
end
enum
status:
{
created:
0
,
running:
1
,
success:
2
,
failed:
3
,
canceled:
4
}
def
self
.
last_for_environment
(
environment
)
ids
=
self
.
for_environment
(
environment
)
...
...
@@ -65,15 +99,15 @@ class Deployment < ActiveRecord::Base
end
def
update_merge_request_metrics!
return
unless
environment
.
update_merge_request_metrics?
return
unless
environment
.
update_merge_request_metrics?
&&
success?
merge_requests
=
project
.
merge_requests
.
joins
(
:metrics
)
.
where
(
target_branch:
self
.
ref
,
merge_request_metrics:
{
first_deployed_to_production_at:
nil
})
.
where
(
"merge_request_metrics.merged_at <= ?"
,
self
.
creat
ed_at
)
.
where
(
"merge_request_metrics.merged_at <= ?"
,
finish
ed_at
)
if
previous_deployment
merge_requests
=
merge_requests
.
where
(
"merge_request_metrics.merged_at >= ?"
,
previous_deployment
.
creat
ed_at
)
merge_requests
=
merge_requests
.
where
(
"merge_request_metrics.merged_at >= ?"
,
previous_deployment
.
finish
ed_at
)
end
# Need to use `map` instead of `select` because MySQL doesn't allow `SELECT`ing from the same table
...
...
@@ -87,7 +121,7 @@ class Deployment < ActiveRecord::Base
MergeRequest
::
Metrics
.
where
(
merge_request_id:
merge_request_ids
,
first_deployed_to_production_at:
nil
)
.
update_all
(
first_deployed_to_production_at:
self
.
creat
ed_at
)
.
update_all
(
first_deployed_to_production_at:
finish
ed_at
)
end
def
previous_deployment
...
...
@@ -105,8 +139,18 @@ class Deployment < ActiveRecord::Base
@stop_action
||=
manual_actions
.
find_by
(
name:
on_stop
)
end
def
finished_at
read_attribute
(
:finished_at
)
||
legacy_finished_at
end
def
deployed_at
return
unless
success?
finished_at
end
def
formatted_deployment_time
created_at
.
to_time
.
in_time_zone
.
to_s
(
:medium
)
deployed_at
&
.
to_time
&
.
in_time_zone
&
.
to_s
(
:medium
)
end
def
has_metrics?
...
...
@@ -114,21 +158,17 @@ class Deployment < ActiveRecord::Base
end
def
metrics
return
{}
unless
has_metrics?
return
{}
unless
has_metrics?
&&
success?
metrics
=
prometheus_adapter
.
query
(
:deployment
,
self
)
metrics
&
.
merge
(
deployment_time:
creat
ed_at
.
to_i
)
||
{}
metrics
&
.
merge
(
deployment_time:
finish
ed_at
.
to_i
)
||
{}
end
def
additional_metrics
return
{}
unless
has_metrics?
return
{}
unless
has_metrics?
&&
success?
metrics
=
prometheus_adapter
.
query
(
:additional_metrics_deployment
,
self
)
metrics
&
.
merge
(
deployment_time:
created_at
.
to_i
)
||
{}
end
def
status
'success'
metrics
&
.
merge
(
deployment_time:
finished_at
.
to_i
)
||
{}
end
private
...
...
@@ -140,4 +180,8 @@ class Deployment < ActiveRecord::Base
def
ref_path
File
.
join
(
environment
.
ref_path
,
'deployments'
,
iid
.
to_s
)
end
def
legacy_finished_at
self
.
created_at
if
success?
&&
!
read_attribute
(
:finished_at
)
end
end
app/models/environment.rb
View file @
18fa8041
...
...
@@ -10,9 +10,9 @@ class Environment < ActiveRecord::Base
belongs_to
:project
,
required:
true
has_many
:deployments
,
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
has_many
:deployments
,
->
{
success
},
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
has_one
:last_deployment
,
->
{
order
(
'deployments.id DESC'
)
},
class_name:
'Deployment'
has_one
:last_deployment
,
->
{
success
.
order
(
'deployments.id DESC'
)
},
class_name:
'Deployment'
before_validation
:nullify_external_url
before_validation
:generate_slug
,
if:
->
(
env
)
{
env
.
slug
.
blank?
}
...
...
app/models/environment_status.rb
View file @
18fa8041
...
...
@@ -8,8 +8,8 @@ class EnvironmentStatus
delegate
:id
,
to: :environment
delegate
:name
,
to: :environment
delegate
:project
,
to: :environment
delegate
:deployed_at
,
to: :deployment
,
allow_nil:
true
delegate
:status
,
to: :deployment
delegate
:deployed_at
,
to: :deployment
def
self
.
for_merge_request
(
mr
,
user
)
build_environments_status
(
mr
,
user
,
mr
.
head_pipeline
)
...
...
@@ -33,10 +33,6 @@ class EnvironmentStatus
end
end
def
deployed_at
deployment
&
.
created_at
end
def
changes
return
[]
if
project
.
route_map_for
(
sha
).
nil?
...
...
app/models/project.rb
View file @
18fa8041
...
...
@@ -257,7 +257,7 @@ class Project < ActiveRecord::Base
has_many
:variables
,
class_name:
'Ci::Variable'
has_many
:triggers
,
class_name:
'Ci::Trigger'
has_many
:environments
has_many
:deployments
has_many
:deployments
,
->
{
success
}
has_many
:pipeline_schedules
,
class_name:
'Ci::PipelineSchedule'
has_many
:project_deploy_tokens
has_many
:deploy_tokens
,
through: :project_deploy_tokens
...
...
app/services/
cre
ate_deployment_service.rb
→
app/services/
upd
ate_deployment_service.rb
View file @
18fa8041
# frozen_string_literal: true
class
CreateDeploymentService
attr_reader
:job
class
UpdateDeploymentService
attr_reader
:deployment
attr_reader
:deployable
delegate
:expanded_environment_name
,
:variables
,
:project
,
to: :job
delegate
:environment
,
to: :deployment
delegate
:variables
,
to: :deployable
def
initialize
(
job
)
@job
=
job
def
initialize
(
deployment
)
@deployment
=
deployment
@deployable
=
deployment
.
deployable
end
def
execute
return
unless
executable?
deployment
.
create_ref
deployment
.
invalidate_cache
ActiveRecord
::
Base
.
transaction
do
environment
.
external_url
=
expanded_environment_url
if
...
...
@@ -24,50 +25,28 @@ class CreateDeploymentService
break
unless
environment
.
save
break
if
environment
.
stopped?
deploy
.
tap
(
&
:update_merge_request_metrics!
)
deploy
ment
.
tap
(
&
:update_merge_request_metrics!
)
end
end
private
def
executable?
project
&&
job
.
environment
.
present?
&&
environment
end
def
deploy
project
.
deployments
.
create
(
environment:
environment
,
ref:
job
.
ref
,
tag:
job
.
tag
,
sha:
job
.
sha
,
user:
job
.
user
,
deployable:
job
,
on_stop:
on_stop
)
end
def
environment
@environment
||=
job
.
persisted_environment
end
def
environment_options
@environment_options
||=
job
.
options
&
.
dig
(
:environment
)
||
{}
@environment_options
||=
deployable
.
options
&
.
dig
(
:environment
)
||
{}
end
def
expanded_environment_url
return
@expanded_environment_url
if
defined?
(
@expanded_environment_url
)
return
unless
environment_url
@expanded_environment_url
=
ExpandVariables
.
expand
(
environment_url
,
variables
)
if
environment_url
ExpandVariables
.
expand
(
environment_url
,
variables
)
end
def
environment_url
environment_options
[
:url
]
end
def
on_stop
environment_options
[
:on_stop
]
end
def
action
environment_options
[
:action
]
||
'start'
end
...
...
app/workers/all_queues.yml
View file @
18fa8041
...
...
@@ -75,6 +75,8 @@
-
pipeline_processing:update_head_pipeline_for_merge_request
-
pipeline_processing:ci_build_schedule
-
deployment:deployments_success
-
repository_check:repository_check_clear
-
repository_check:repository_check_batch
-
repository_check:repository_check_single_repository
...
...
app/workers/build_success_worker.rb
View file @
18fa8041
...
...
@@ -16,7 +16,14 @@ class BuildSuccessWorker
private
##
# Deprecated:
# As of 11.5, we started creating a deployment record when ci_builds record is created.
# Therefore we no longer need to create a deployment, after a build succeeded.
# We're leaving this code for the transition period, but we can remove this code in 11.6.
def
create_deployment
(
build
)
CreateDeploymentService
.
new
(
build
).
execute
build
.
create_deployment
.
try
do
|
deployment
|
deployment
.
succeed
end
end
end
app/workers/deployments/success_worker.rb
0 → 100644
View file @
18fa8041
# frozen_string_literal: true
module
Deployments
class
SuccessWorker
include
ApplicationWorker
queue_namespace
:deployment
def
perform
(
deployment_id
)
Deployment
.
find_by_id
(
deployment_id
).
try
do
|
deployment
|
break
unless
deployment
.
success?
UpdateDeploymentService
.
new
(
deployment
).
execute
end
end
end
end
changelogs/unreleased/stateful_deployments.yml
0 → 100644
View file @
18fa8041
---
title
:
Add status to Deployment
merge_request
:
22380
author
:
type
:
changed
config/sidekiq_queues.yml
View file @
18fa8041
...
...
@@ -29,6 +29,7 @@
- [pipeline_creation, 4]
- [pipeline_default, 3]
- [pipeline_cache, 3]
- [deployment, 3]
- [pipeline_hooks, 2]
- [gitlab_shell, 2]
- [email_receiver, 2]
...
...
db/fixtures/development/17_cycle_analytics.rb
View file @
18fa8041
...
...
@@ -180,11 +180,8 @@ class Gitlab::Seeder::CycleAnalytics
ref:
"refs/heads/
#{
merge_request
.
source_branch
}
"
)
pipeline
=
service
.
execute
(
:push
,
ignore_skip_ci:
true
,
save_on_errors:
false
)
pipeline
.
run!
Timecop
.
travel
rand
(
1
..
6
).
hours
.
from_now
pipeline
.
succeed!
PipelineMetricsWorker
.
new
.
perform
(
pipeline
.
id
)
pipeline
.
builds
.
map
(
&
:run!
)
pipeline
.
update_status
end
end
...
...
@@ -204,7 +201,8 @@ class Gitlab::Seeder::CycleAnalytics
job
=
merge_request
.
head_pipeline
.
builds
.
where
.
not
(
environment:
nil
).
last
CreateDeploymentService
.
new
(
job
).
execute
job
.
success!
pipeline
.
update_status
end
end
end
...
...
db/migrate/20181015155839_add_finished_at_to_deployments.rb
0 → 100644
View file @
18fa8041
# frozen_string_literal: true
class
AddFinishedAtToDeployments
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
def
up
add_column
:deployments
,
:finished_at
,
:datetime_with_timezone
end
def
down
remove_column
:deployments
,
:finished_at
,
:datetime_with_timezone
end
end
db/migrate/20181016141739_add_status_to_deployments.rb
0 → 100644
View file @
18fa8041
# frozen_string_literal: true
class
AddStatusToDeployments
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DEPLOYMENT_STATUS_SUCCESS
=
2
# Equivalent to Deployment.state_machine.states['success'].value
DOWNTIME
=
false
disable_ddl_transaction!
##
# NOTE:
# Ideally, `status` column should not have default value because it should be leveraged by state machine (i.e. application level).
# However, we have to use the default value for avoiding `NOT NULL` violation during the transition period.
# The default value should be removed in the future release.
def
up
add_column_with_default
(
:deployments
,
:status
,
:integer
,
limit:
2
,
default:
DEPLOYMENT_STATUS_SUCCESS
,
allow_null:
false
)
end
def
down
remove_column
(
:deployments
,
:status
)
end
end
db/migrate/20181022135539_add_index_on_status_to_deployments.rb
0 → 100644
View file @
18fa8041
# frozen_string_literal: true
class
AddIndexOnStatusToDeployments
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
disable_ddl_transaction!
def
up
add_concurrent_index
:deployments
,
[
:project_id
,
:status
]
add_concurrent_index
:deployments
,
[
:environment_id
,
:status
]
end
def
down
remove_concurrent_index
:deployments
,
[
:project_id
,
:status
]
remove_concurrent_index
:deployments
,
[
:environment_id
,
:status
]
end
end
db/migrate/20181023144439_add_partial_index_for_legacy_successful_deployments.rb
0 → 100644
View file @
18fa8041
# frozen_string_literal: true
class
AddPartialIndexForLegacySuccessfulDeployments
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
INDEX_NAME
=
'partial_index_deployments_for_legacy_successful_deployments'
.
freeze
disable_ddl_transaction!
def
up
add_concurrent_index
(
:deployments
,
:id
,
where:
"finished_at IS NULL AND status = 2"
,
name:
INDEX_NAME
)
end
def
down
remove_concurrent_index_by_name
(
:deployments
,
INDEX_NAME
)
end
end
db/post_migrate/20181030135124_fill_empty_finished_at_in_deployments.rb
0 → 100644
View file @
18fa8041
# frozen_string_literal: true
class
FillEmptyFinishedAtInDeployments
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
DEPLOYMENT_STATUS_SUCCESS
=
2
# Equivalent to Deployment.statuses[:success]
class
Deployments
<
ActiveRecord
::
Base
self
.
table_name
=
'deployments'
include
EachBatch
end
def
up
FillEmptyFinishedAtInDeployments
::
Deployments
.
where
(
'finished_at IS NULL'
)
.
where
(
'status = ?'
,
DEPLOYMENT_STATUS_SUCCESS
)
.
each_batch
(
of:
10_000
)
do
|
relation
|
relation
.
update_all
(
'finished_at=created_at'
)
end
end
def
down
# no-op
end
end
db/schema.rb
View file @
18fa8041
...
...
@@ -943,13 +943,18 @@ ActiveRecord::Schema.define(version: 20181101144347) do
t
.
datetime
"created_at"
t
.
datetime
"updated_at"
t
.
string
"on_stop"
t
.
integer
"status"
,
limit:
2
,
default:
2
,
null:
false
t
.
datetime_with_timezone
"finished_at"
end
add_index
"deployments"
,
[
"created_at"
],
name:
"index_deployments_on_created_at"
,
using: :btree
add_index
"deployments"
,
[
"deployable_type"
,
"deployable_id"
],
name:
"index_deployments_on_deployable_type_and_deployable_id"
,
using: :btree
add_index
"deployments"
,
[
"environment_id"
,
"id"
],
name:
"index_deployments_on_environment_id_and_id"
,
using: :btree
add_index
"deployments"
,
[
"environment_id"
,
"iid"
,
"project_id"
],
name:
"index_deployments_on_environment_id_and_iid_and_project_id"
,
using: :btree
add_index
"deployments"
,
[
"environment_id"
,
"status"
],
name:
"index_deployments_on_environment_id_and_status"
,
using: :btree
add_index
"deployments"
,
[
"id"
],
name:
"partial_index_deployments_for_legacy_successful_deployments"
,
where:
"((finished_at IS NULL) AND (status = 2))"
,
using: :btree
add_index
"deployments"
,
[
"project_id"
,
"iid"
],
name:
"index_deployments_on_project_id_and_iid"
,
unique:
true
,
using: :btree
add_index
"deployments"
,
[
"project_id"
,
"status"
],
name:
"index_deployments_on_project_id_and_status"
,
using: :btree
create_table
"draft_notes"
,
id: :bigserial
,
force: :cascade
do
|
t
|
t
.
integer
"merge_request_id"
,
null:
false
...
...
lib/gitlab/ci/pipeline/chain/create.rb
View file @
18fa8041
...
...
@@ -7,26 +7,11 @@ module Gitlab
class
Create
<
Chain
::
Base
include
Chain
::
Helpers
# rubocop: disable CodeReuse/ActiveRecord
def
perform!
::
Ci
::
Pipeline
.
transaction
do
pipeline
.
save!
##
# Create environments before the pipeline starts.
#
pipeline
.
builds
.
each
do
|
build
|
if
build
.
has_environment?
project
.
environments
.
find_or_create_by
(
name:
build
.
expanded_environment_name
)
end
end
end
pipeline
.
save!
rescue
ActiveRecord
::
RecordInvalid
=>
e
error
(
"Failed to persist the pipeline:
#{
e
}
"
)
end
# rubocop: enable CodeReuse/ActiveRecord
def
break?
!
pipeline
.
persisted?
...
...
spec/controllers/projects/deployments_controller_spec.rb
View file @
18fa8041
...
...
@@ -15,9 +15,9 @@ describe Projects::DeploymentsController do
describe
'GET #index'
do
it
'returns list of deployments from last 8 hours'
do
create
(
:deployment
,
environment:
environment
,
created_at:
9
.
hours
.
ago
)
create
(
:deployment
,
environment:
environment
,
created_at:
7
.
hours
.
ago
)
create
(
:deployment
,
environment:
environment
)
create
(
:deployment
,
:success
,
environment:
environment
,
created_at:
9
.
hours
.
ago
)
create
(
:deployment
,
:success
,
environment:
environment
,
created_at:
7
.
hours
.
ago
)
create
(
:deployment
,
:success
,
environment:
environment
)
get
:index
,
deployment_params
(
after:
8
.
hours
.
ago
)
...
...
@@ -27,7 +27,7 @@ describe Projects::DeploymentsController do
end
it
'returns a list with deployments information'
do
create
(
:deployment
,
environment:
environment
)
create
(
:deployment
,
:success
,
environment:
environment
)
get
:index
,
deployment_params
...
...
@@ -37,7 +37,7 @@ describe Projects::DeploymentsController do
end
describe
'GET #metrics'
do
let
(
:deployment
)
{
create
(
:deployment
,
project:
project
,
environment:
environment
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:success
,
project:
project
,
environment:
environment
)
}
before
do
allow
(
controller
).
to
receive
(
:deployment
).
and_return
(
deployment
)
...
...
@@ -110,7 +110,7 @@ describe Projects::DeploymentsController do
end
describe
'GET #additional_metrics'
do
let
(
:deployment
)
{
create
(
:deployment
,
project:
project
,
environment:
environment
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:success
,
project:
project
,
environment:
environment
)
}
before
do
allow
(
controller
).
to
receive
(
:deployment
).
and_return
(
deployment
)
...
...
spec/controllers/projects/jobs_controller_spec.rb
View file @
18fa8041
...
...
@@ -231,7 +231,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
context
'with deployment'
do
let
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
project
)
}
let
(
:environment
)
{
create
(
:environment
,
project:
project
,
name:
'staging'
,
state: :available
)
}
let
(
:job
)
{
create
(
:ci_build
,
:
success
,
environment:
environment
.
name
,
pipeline:
pipeline
)
}
let
(
:job
)
{
create
(
:ci_build
,
:
running
,
environment:
environment
.
name
,
pipeline:
pipeline
)
}
it
'exposes the deployment information'
do
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
...
...
spec/controllers/projects/merge_requests_controller_spec.rb
View file @
18fa8041
...
...
@@ -755,7 +755,7 @@ describe Projects::MergeRequestsController do
let
(
:environment
)
{
create
(
:environment
,
project:
forked
)
}
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!
(
:deployment
)
{
create
(
:deployment
,
:succeed
,
environment:
environment
,
sha:
sha
,
ref:
'master'
,
deployable:
build
)
}
let
(
:merge_request
)
do
create
(
:merge_request
,
source_project:
forked
,
target_project:
project
,
target_branch:
'master'
,
head_pipeline:
pipeline
)
...
...
@@ -780,7 +780,7 @@ describe Projects::MergeRequestsController do
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
)
}
let!
(
:source_deployment
)
{
create
(
:deployment
,
:succeed
,
environment:
source_environment
,
sha:
merge_commit_sha
,
ref:
'master'
,
deployable:
post_merge_build
)
}
before
do
merge_request
.
update!
(
merge_commit_sha:
merge_commit_sha
)
...
...
spec/factories/ci/builds.rb
View file @
18fa8041
...
...
@@ -94,6 +94,30 @@ FactoryBot.define do
url:
'http://staging.example.com/$CI_JOB_NAME'
}
end
trait
:deploy_to_production
do
environment
'production'
options
environment:
{
name:
'production'
,
url:
'http://prd.example.com/$CI_JOB_NAME'
}
end
trait
:start_review_app
do
environment
'review/$CI_COMMIT_REF_NAME'
options
environment:
{
name:
'review/$CI_COMMIT_REF_NAME'
,
url:
'http://staging.example.com/$CI_JOB_NAME'
,
on_stop:
'stop_review_app'
}
end
trait
:stop_review_app
do
name
'stop_review_app'
environment
'review/$CI_COMMIT_REF_NAME'
options
environment:
{
name:
'review/$CI_COMMIT_REF_NAME'
,
url:
'http://staging.example.com/$CI_JOB_NAME'
,
action:
'stop'
}
end
trait
:allowed_to_fail
do
allow_failure
true
end
...
...
spec/factories/deployments.rb
View file @
18fa8041
...
...
@@ -21,5 +21,31 @@ FactoryBot.define do
sha
{
TestEnv
::
BRANCH_SHA
[
'pages-deploy'
]
}
ref
'pages-deploy'
end
trait
:running
do
status
:running
end
trait
:success
do
status
:success
finished_at
{
Time
.
now
}
end
trait
:failed
do
status
:failed
finished_at
{
Time
.
now
}
end
trait
:canceled
do
status
:canceled
finished_at
{
Time
.
now
}
end
# This trait hooks the state maechine's events
trait
:succeed
do
after
(
:create
)
do
|
deployment
,
evaluator
|
deployment
.
succeed!
end
end
end
end
spec/factories/environments.rb
View file @
18fa8041
...
...
@@ -22,6 +22,7 @@ FactoryBot.define do
pipeline:
pipeline
)
deployment
=
create
(
:deployment
,
:success
,
environment:
environment
,
project:
environment
.
project
,
deployable:
deployable
,
...
...
spec/features/merge_request/user_sees_deployment_widget_spec.rb
View file @
18fa8041
...
...
@@ -11,7 +11,7 @@ describe 'Merge request > User sees deployment widget', :js do
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!
(
:deployment
)
{
create
(
:deployment
,
:succeed
,
environment:
environment
,
sha:
sha
,
ref:
ref
,
deployable:
build
)
}
let!
(
:manual
)
{
}
before
do
...
...
spec/features/merge_request/user_sees_merge_widget_spec.rb
View file @
18fa8041
...
...
@@ -45,7 +45,8 @@ describe 'Merge request > User sees merge widget', :js do
let
(
:build
)
{
create
(
:ci_build
,
:success
,
pipeline:
pipeline
)
}
let!
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
create
(
:deployment
,
:succeed
,
environment:
environment
,
ref:
merge_request
.
source_branch
,
deployable:
build
,
sha:
sha
)
...
...
spec/features/projects/environments/environment_spec.rb
View file @
18fa8041
...
...
@@ -33,7 +33,7 @@ describe 'Environment' do
context
'with deployments'
do
context
'when there is no related deployable'
do
let
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
deployable:
nil
)
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
nil
)
end
it
'does show deployment SHA'
do
...
...
@@ -48,7 +48,7 @@ describe 'Environment' do
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
deployable:
build
)
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
build
)
end
it
'does show build name'
do
...
...
@@ -97,7 +97,7 @@ describe 'Environment' do
context
'with external_url'
do
let
(
:environment
)
{
create
(
:environment
,
project:
project
,
external_url:
'https://git.gitlab.com'
)
}
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
deployable:
build
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
build
)
}
it
'does show an external link button'
do
expect
(
page
).
to
have_link
(
nil
,
href:
environment
.
external_url
)
...
...
@@ -158,7 +158,8 @@ describe 'Environment' do
end
let
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
build
,
on_stop:
'close_app'
)
end
...
...
spec/features/projects/environments/environments_spec.rb
View file @
18fa8041
...
...
@@ -132,7 +132,8 @@ describe 'Environments page', :js do
let
(
:project
)
{
create
(
:project
,
:repository
)
}
let!
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
create
(
:deployment
,
:success
,
environment:
environment
,
sha:
project
.
commit
.
id
)
end
...
...
@@ -152,7 +153,8 @@ describe 'Environments page', :js do
end
let!
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
build
,
sha:
project
.
commit
.
id
)
end
...
...
@@ -196,7 +198,7 @@ describe 'Environments page', :js do
context
'with external_url'
do
let
(
:environment
)
{
create
(
:environment
,
project:
project
,
external_url:
'https://git.gitlab.com'
)
}
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
deployable:
build
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
build
)
}
it
'shows an external link button'
do
expect
(
page
).
to
have_link
(
nil
,
href:
environment
.
external_url
)
...
...
@@ -209,7 +211,8 @@ describe 'Environments page', :js do
end
let
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
build
,
on_stop:
'close_app'
)
end
...
...
spec/features/projects/jobs_spec.rb
View file @
18fa8041
...
...
@@ -396,8 +396,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end
context
'job is successful and has deployment'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
,
:trace_live
,
environment:
environment
.
name
,
pipeline:
pipeline
)
}
let
!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
project:
environment
.
project
,
deployable:
build
)
}
let
(
:build
)
{
create
(
:ci_build
,
:success
,
:trace_live
,
environment:
environment
.
name
,
pipeline:
pipeline
,
deployment:
deployment
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
project:
environment
.
project
)
}
it
'shows a link for the job'
do
expect
(
page
).
to
have_link
environment
.
name
...
...
@@ -419,7 +419,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end
context
'deployment still not finished'
do
let
(
:build
)
{
create
(
:ci_build
,
:
success
,
environment:
environment
.
name
,
pipeline:
pipeline
)
}
let
(
:build
)
{
create
(
:ci_build
,
:
running
,
environment:
environment
.
name
,
pipeline:
pipeline
)
}
it
'shows a link to latest deployment'
do
expect
(
page
).
to
have_link
environment
.
name
...
...
@@ -456,6 +456,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
describe
'environment info in job view'
,
:js
do
before
do
allow_any_instance_of
(
Ci
::
Build
).
to
receive
(
:create_deployment
)
visit
project_job_path
(
project
,
job
)
wait_for_requests
end
...
...
@@ -464,8 +466,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
let
(
:job
)
{
create
(
:ci_build
,
:success
,
:trace_artifact
,
environment:
'staging'
,
pipeline:
pipeline
)
}
let
(
:second_build
)
{
create
(
:ci_build
,
:success
,
:trace_artifact
,
environment:
'staging'
,
pipeline:
pipeline
)
}
let
(
:environment
)
{
create
(
:environment
,
name:
'staging'
,
project:
project
)
}
let!
(
:first_deployment
)
{
create
(
:deployment
,
environment:
environment
,
deployable:
job
)
}
let!
(
:second_deployment
)
{
create
(
:deployment
,
environment:
environment
,
deployable:
second_build
)
}
let!
(
:first_deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
job
)
}
let!
(
:second_deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
second_build
)
}
it
'shows deployment message'
do
expected_text
=
'This job is an out-of-date deployment '
\
...
...
@@ -505,7 +507,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end
context
'when it has deployment'
do
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
)
}
it
'shows that deployment will be overwritten'
do
expected_text
=
'This job is creating a deployment to staging'
...
...
spec/features/projects/view_on_env_spec.rb
View file @
18fa8041
...
...
@@ -44,7 +44,7 @@ describe 'View on environment', :js do
context
'and an active deployment'
do
let
(
:sha
)
{
project
.
commit
(
branch_name
).
sha
}
let
(
:environment
)
{
create
(
:environment
,
project:
project
,
name:
'review/feature'
,
external_url:
'http://feature.review.example.com'
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
ref:
branch_name
,
sha:
sha
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
branch_name
,
sha:
sha
)
}
context
'when visiting the diff of a merge request for the branch'
do
let
(
:merge_request
)
{
create
(
:merge_request
,
:simple
,
source_project:
project
,
source_branch:
branch_name
)
}
...
...
spec/finders/environments_finder_spec.rb
View file @
18fa8041
...
...
@@ -12,7 +12,7 @@ describe EnvironmentsFinder do
context
'tagged deployment'
do
before
do
create
(
:deployment
,
environment:
environment
,
ref:
'v1.1.0'
,
tag:
true
,
sha:
project
.
commit
.
id
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'v1.1.0'
,
tag:
true
,
sha:
project
.
commit
.
id
)
end
it
'returns environment when with_tags is set'
do
...
...
@@ -33,7 +33,7 @@ describe EnvironmentsFinder do
context
'branch deployment'
do
before
do
create
(
:deployment
,
environment:
environment
,
ref:
'master'
,
sha:
project
.
commit
.
id
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'master'
,
sha:
project
.
commit
.
id
)
end
it
'returns environment when ref is set'
do
...
...
@@ -59,7 +59,7 @@ describe EnvironmentsFinder do
context
'commit deployment'
do
before
do
create
(
:deployment
,
environment:
environment
,
ref:
'master'
,
sha:
project
.
commit
.
id
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'master'
,
sha:
project
.
commit
.
id
)
end
it
'returns environment'
do
...
...
@@ -71,7 +71,7 @@ describe EnvironmentsFinder do
context
'recently updated'
do
context
'when last deployment to environment is the most recent one'
do
before
do
create
(
:deployment
,
environment:
environment
,
ref:
'feature'
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'feature'
)
end
it
'finds recently updated environment'
do
...
...
@@ -82,8 +82,8 @@ describe EnvironmentsFinder do
context
'when last deployment to environment is not the most recent'
do
before
do
create
(
:deployment
,
environment:
environment
,
ref:
'feature'
)
create
(
:deployment
,
environment:
environment
,
ref:
'master'
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'feature'
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'master'
)
end
it
'does not find environment'
do
...
...
@@ -96,8 +96,8 @@ describe EnvironmentsFinder do
let
(
:second_environment
)
{
create
(
:environment
,
project:
project
)
}
before
do
create
(
:deployment
,
environment:
environment
,
ref:
'feature'
)
create
(
:deployment
,
environment:
second_environment
,
ref:
'feature'
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'feature'
)
create
(
:deployment
,
:success
,
environment:
second_environment
,
ref:
'feature'
)
end
it
'finds both environments'
do
...
...
spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
View file @
18fa8041
...
...
@@ -44,15 +44,15 @@ describe Gitlab::CycleAnalytics::StageSummary do
describe
"#deploys"
do
it
"finds the number of deploys made created after the 'from date'"
do
Timecop
.
freeze
(
5
.
days
.
ago
)
{
create
(
:deployment
,
project:
project
)
}
Timecop
.
freeze
(
5
.
days
.
from_now
)
{
create
(
:deployment
,
project:
project
)
}
Timecop
.
freeze
(
5
.
days
.
ago
)
{
create
(
:deployment
,
:success
,
project:
project
)
}
Timecop
.
freeze
(
5
.
days
.
from_now
)
{
create
(
:deployment
,
:success
,
project:
project
)
}
expect
(
subject
.
third
[
:value
]).
to
eq
(
1
)
end
it
"doesn't find commits from other projects"
do
Timecop
.
freeze
(
5
.
days
.
from_now
)
do
create
(
:deployment
,
project:
create
(
:project
,
:repository
))
create
(
:deployment
,
:success
,
project:
create
(
:project
,
:repository
))
end
expect
(
subject
.
third
[
:value
]).
to
eq
(
0
)
...
...
spec/lib/gitlab/slash_commands/command_spec.rb
View file @
18fa8041
...
...
@@ -44,7 +44,7 @@ describe Gitlab::SlashCommands::Command do
let!
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let!
(
:pipeline
)
{
create
(
:ci_pipeline
,
project:
project
)
}
let!
(
:staging
)
{
create
(
:environment
,
name:
'staging'
,
project:
project
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
staging
,
deployable:
build
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
staging
,
deployable:
build
)
}
let!
(
:manual
)
do
create
(
:ci_build
,
:manual
,
pipeline:
pipeline
,
...
...
spec/lib/gitlab/slash_commands/deploy_spec.rb
View file @
18fa8041
...
...
@@ -31,7 +31,7 @@ describe Gitlab::SlashCommands::Deploy do
let!
(
:staging
)
{
create
(
:environment
,
name:
'staging'
,
project:
project
)
}
let!
(
:pipeline
)
{
create
(
:ci_pipeline
,
project:
project
)
}
let!
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
staging
,
deployable:
build
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
staging
,
deployable:
build
)
}
context
'without actions'
do
it
'does not execute an action'
do
...
...
spec/migrations/delete_inconsistent_internal_id_records_spec.rb
View file @
18fa8041
...
...
@@ -65,6 +65,21 @@ describe DeleteInconsistentInternalIdRecords, :migration do
context
'for deployments'
do
let
(
:scope
)
{
:deployment
}
let
(
:deployments
)
{
table
(
:deployments
)
}
let
(
:internal_ids
)
{
table
(
:internal_ids
)
}
before
do
internal_ids
.
create!
(
project_id:
project1
.
id
,
usage:
2
,
last_value:
2
)
internal_ids
.
create!
(
project_id:
project2
.
id
,
usage:
2
,
last_value:
2
)
internal_ids
.
create!
(
project_id:
project3
.
id
,
usage:
2
,
last_value:
2
)
end
let
(
:create_models
)
do
3
.
times
{
|
i
|
deployments
.
create!
(
project_id:
project1
.
id
,
iid:
i
,
environment_id:
1
,
ref:
'master'
,
sha:
'a'
,
tag:
false
)
}
3
.
times
{
|
i
|
deployments
.
create!
(
project_id:
project2
.
id
,
iid:
i
,
environment_id:
1
,
ref:
'master'
,
sha:
'a'
,
tag:
false
)
}
3
.
times
{
|
i
|
deployments
.
create!
(
project_id:
project3
.
id
,
iid:
i
,
environment_id:
1
,
ref:
'master'
,
sha:
'a'
,
tag:
false
)
}
end
it_behaves_like
'deleting inconsistent internal_id records'
end
...
...
spec/migrations/fill_empty_finished_at_in_deployments_spec.rb
0 → 100644
View file @
18fa8041
require
'spec_helper'
require
Rails
.
root
.
join
(
'db'
,
'post_migrate'
,
'20181030135124_fill_empty_finished_at_in_deployments'
)
describe
FillEmptyFinishedAtInDeployments
,
:migration
do
let
(
:namespaces
)
{
table
(
:namespaces
)
}
let
(
:projects
)
{
table
(
:projects
)
}
let
(
:environments
)
{
table
(
:environments
)
}
let
(
:deployments
)
{
table
(
:deployments
)
}
context
'when a deployment row does not have a value on finished_at'
do
context
'when a deployment succeeded'
do
before
do
namespaces
.
create!
(
id:
123
,
name:
'gitlab1'
,
path:
'gitlab1'
)
projects
.
create!
(
id:
1
,
name:
'gitlab1'
,
path:
'gitlab1'
,
namespace_id:
123
)
environments
.
create!
(
id:
1
,
name:
'production'
,
slug:
'production'
,
project_id:
1
)
deployments
.
create!
(
id:
1
,
iid:
1
,
project_id:
1
,
environment_id:
1
,
ref:
'master'
,
sha:
'xxx'
,
tag:
false
)
end
it
'correctly replicates finished_at by created_at'
do
expect
(
deployments
.
last
.
created_at
).
not_to
be_nil
expect
(
deployments
.
last
.
finished_at
).
to
be_nil
migrate!
expect
(
deployments
.
last
.
created_at
).
not_to
be_nil
expect
(
deployments
.
last
.
finished_at
).
to
eq
(
deployments
.
last
.
created_at
)
end
end
context
'when a deployment is running'
do
before
do
namespaces
.
create!
(
id:
123
,
name:
'gitlab1'
,
path:
'gitlab1'
)
projects
.
create!
(
id:
1
,
name:
'gitlab1'
,
path:
'gitlab1'
,
namespace_id:
123
)
environments
.
create!
(
id:
1
,
name:
'production'
,
slug:
'production'
,
project_id:
1
)
deployments
.
create!
(
id:
1
,
iid:
1
,
project_id:
1
,
environment_id:
1
,
ref:
'master'
,
sha:
'xxx'
,
tag:
false
,
status:
1
)
end
it
'does not fill finished_at'
do
expect
(
deployments
.
last
.
created_at
).
not_to
be_nil
expect
(
deployments
.
last
.
finished_at
).
to
be_nil
migrate!
expect
(
deployments
.
last
.
created_at
).
not_to
be_nil
expect
(
deployments
.
last
.
finished_at
).
to
be_nil
end
end
end
context
'when a deployment row does has a value on finished_at'
do
let
(
:finished_at
)
{
'2018-10-30 11:12:02 UTC'
}
before
do
namespaces
.
create!
(
id:
123
,
name:
'gitlab1'
,
path:
'gitlab1'
)
projects
.
create!
(
id:
1
,
name:
'gitlab1'
,
path:
'gitlab1'
,
namespace_id:
123
)
environments
.
create!
(
id:
1
,
name:
'production'
,
slug:
'production'
,
project_id:
1
)
deployments
.
create!
(
id:
1
,
iid:
1
,
project_id:
1
,
environment_id:
1
,
ref:
'master'
,
sha:
'xxx'
,
tag:
false
,
finished_at:
finished_at
)
end
it
'does not affect existing value'
do
expect
(
deployments
.
last
.
created_at
).
not_to
be_nil
expect
(
deployments
.
last
.
finished_at
).
not_to
be_nil
migrate!
expect
(
deployments
.
last
.
created_at
).
not_to
be_nil
expect
(
deployments
.
last
.
finished_at
).
to
eq
(
finished_at
)
end
end
end
spec/models/ci/build_spec.rb
View file @
18fa8041
...
...
@@ -17,9 +17,9 @@ describe Ci::Build do
it
{
is_expected
.
to
belong_to
(
:runner
)
}
it
{
is_expected
.
to
belong_to
(
:trigger_request
)
}
it
{
is_expected
.
to
belong_to
(
:erased_by
)
}
it
{
is_expected
.
to
have_many
(
:deployments
)
}
it
{
is_expected
.
to
have_many
(
:sourced_pipelines
)
}
it
{
is_expected
.
to
have_many
(
:trace_sections
)}
it
{
is_expected
.
to
have_one
(
:deployment
)
}
it
{
is_expected
.
to
have_one
(
:runner_session
)}
it
{
is_expected
.
to
validate_presence_of
(
:ref
)
}
it
{
is_expected
.
to
respond_to
(
:has_trace?
)
}
...
...
@@ -800,17 +800,100 @@ describe Ci::Build do
end
end
describe
'state transition as a deployable'
do
let!
(
:build
)
{
create
(
:ci_build
,
:start_review_app
)
}
let
(
:deployment
)
{
build
.
deployment
}
let
(
:environment
)
{
deployment
.
environment
}
it
'has deployments record with created status'
do
expect
(
deployment
).
to
be_created
expect
(
environment
.
name
).
to
eq
(
'review/master'
)
end
context
'when transits to running'
do
before
do
build
.
run!
end
it
'transits deployment status to running'
do
expect
(
deployment
).
to
be_running
end
end
context
'when transits to success'
do
before
do
allow
(
Deployments
::
SuccessWorker
).
to
receive
(
:perform_async
)
build
.
success!
end
it
'transits deployment status to success'
do
expect
(
deployment
).
to
be_success
end
end
context
'when transits to failed'
do
before
do
build
.
drop!
end
it
'transits deployment status to failed'
do
expect
(
deployment
).
to
be_failed
end
end
context
'when transits to skipped'
do
before
do
build
.
skip!
end
it
'transits deployment status to canceled'
do
expect
(
deployment
).
to
be_canceled
end
end
context
'when transits to canceled'
do
before
do
build
.
cancel!
end
it
'transits deployment status to canceled'
do
expect
(
deployment
).
to
be_canceled
end
end
end
describe
'#on_stop'
do
subject
{
build
.
on_stop
}
context
'when a job has a specification that it can be stopped from the other job'
do
let
(
:build
)
{
create
(
:ci_build
,
:start_review_app
)
}
it
'returns the other job name'
do
is_expected
.
to
eq
(
'stop_review_app'
)
end
end
context
'when a job does not have environment information'
do
let
(
:build
)
{
create
(
:ci_build
)
}
it
'returns nil'
do
is_expected
.
to
be_nil
end
end
end
describe
'deployment'
do
describe
'#last_deployment'
do
subject
{
build
.
last_deployment
}
describe
'#has_deployment?'
do
subject
{
build
.
has_deployment?
}
context
'when build has a deployment'
do
let!
(
:deployment
)
{
create
(
:deployment
,
deployable:
build
)
}
context
'when multiple deployments are created'
do
let!
(
:deployment1
)
{
create
(
:deployment
,
deployable:
build
)
}
let!
(
:deployment2
)
{
create
(
:deployment
,
deployable:
build
)
}
it
{
is_expected
.
to
be_truthy
}
end
it
'returns the latest one'
do
is_expected
.
to
eq
(
deployment2
)
end
context
'when build does not have a deployment'
do
it
{
is_expected
.
to
be_falsy
}
end
end
...
...
@@ -819,14 +902,14 @@ describe Ci::Build do
context
'when build succeeded'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
deployable:
build
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
deployable:
build
)
}
context
'current deployment is latest'
do
it
{
is_expected
.
to
be_falsey
}
end
context
'current deployment is not latest on environment'
do
let!
(
:deployment2
)
{
create
(
:deployment
,
environment:
deployment
.
environment
)
}
let!
(
:deployment2
)
{
create
(
:deployment
,
:success
,
environment:
deployment
.
environment
)
}
it
{
is_expected
.
to
be_truthy
}
end
...
...
@@ -3147,10 +3230,14 @@ describe Ci::Build do
end
describe
'#deployment_status'
do
before
do
allow_any_instance_of
(
described_class
).
to
receive
(
:create_deployment
)
end
context
'when build is a last deployment'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
,
environment:
'production'
)
}
let
(
:environment
)
{
create
(
:environment
,
name:
'production'
,
project:
build
.
project
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
project:
environment
.
project
,
deployable:
build
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
project:
environment
.
project
,
deployable:
build
)
}
it
{
expect
(
build
.
deployment_status
).
to
eq
(
:last
)
}
end
...
...
@@ -3158,8 +3245,8 @@ describe Ci::Build do
context
'when there is a newer build with deployment'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
,
environment:
'production'
)
}
let
(
:environment
)
{
create
(
:environment
,
name:
'production'
,
project:
build
.
project
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
project:
environment
.
project
,
deployable:
build
)
}
let!
(
:last_deployment
)
{
create
(
:deployment
,
environment:
environment
,
project:
environment
.
project
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
project:
environment
.
project
,
deployable:
build
)
}
let!
(
:last_deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
project:
environment
.
project
)
}
it
{
expect
(
build
.
deployment_status
).
to
eq
(
:out_of_date
)
}
end
...
...
@@ -3167,7 +3254,7 @@ describe Ci::Build do
context
'when build with deployment has failed'
do
let
(
:build
)
{
create
(
:ci_build
,
:failed
,
environment:
'production'
)
}
let
(
:environment
)
{
create
(
:environment
,
name:
'production'
,
project:
build
.
project
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
project:
environment
.
project
,
deployable:
build
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
project:
environment
.
project
,
deployable:
build
)
}
it
{
expect
(
build
.
deployment_status
).
to
eq
(
:failed
)
}
end
...
...
@@ -3175,14 +3262,7 @@ describe Ci::Build do
context
'when build with deployment is running'
do
let
(
:build
)
{
create
(
:ci_build
,
environment:
'production'
)
}
let
(
:environment
)
{
create
(
:environment
,
name:
'production'
,
project:
build
.
project
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
project:
environment
.
project
,
deployable:
build
)
}
it
{
expect
(
build
.
deployment_status
).
to
eq
(
:creating
)
}
end
context
'when build is successful but deployment is not ready yet'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
,
environment:
'production'
)
}
let
(
:environment
)
{
create
(
:environment
,
name:
'production'
,
project:
build
.
project
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
project:
environment
.
project
,
deployable:
build
)
}
it
{
expect
(
build
.
deployment_status
).
to
eq
(
:creating
)
}
end
...
...
spec/models/concerns/deployable_spec.rb
0 → 100644
View file @
18fa8041
require
'rails_helper'
describe
Deployable
do
describe
'#create_deployment'
do
let
(
:deployment
)
{
job
.
deployment
}
let
(
:environment
)
{
deployment
&
.
environment
}
before
do
job
.
reload
end
context
'when the deployable object will deploy to production'
do
let!
(
:job
)
{
create
(
:ci_build
,
:start_review_app
)
}
it
'creates a deployment and environment record'
do
expect
(
deployment
.
project
).
to
eq
(
job
.
project
)
expect
(
deployment
.
ref
).
to
eq
(
job
.
ref
)
expect
(
deployment
.
tag
).
to
eq
(
job
.
tag
)
expect
(
deployment
.
sha
).
to
eq
(
job
.
sha
)
expect
(
deployment
.
user
).
to
eq
(
job
.
user
)
expect
(
deployment
.
deployable
).
to
eq
(
job
)
expect
(
deployment
.
on_stop
).
to
eq
(
'stop_review_app'
)
expect
(
environment
.
name
).
to
eq
(
'review/master'
)
end
end
context
'when the deployable object has already had a deployment'
do
let!
(
:job
)
{
create
(
:ci_build
,
:start_review_app
,
deployment:
race_deployment
)
}
let!
(
:race_deployment
)
{
create
(
:deployment
,
:success
)
}
it
'does not create a new deployment'
do
expect
(
deployment
).
to
eq
(
race_deployment
)
end
end
context
'when the deployable object will not deploy'
do
let!
(
:job
)
{
create
(
:ci_build
)
}
it
'does not create a deployment and environment record'
do
expect
(
deployment
).
to
be_nil
expect
(
environment
).
to
be_nil
end
end
end
end
spec/models/deployment_spec.rb
View file @
18fa8041
...
...
@@ -26,16 +26,174 @@ describe Deployment do
end
end
describe
'after_create callbacks'
do
let
(
:environment
)
{
create
(
:environment
)
}
let
(
:store
)
{
Gitlab
::
EtagCaching
::
Store
.
new
}
describe
'.success'
do
subject
{
described_class
.
success
}
it
'invalidates the environment etag cache
'
do
old_value
=
store
.
get
(
environment
.
etag_cache_key
)
context
'when deployment status is success
'
do
let
(
:deployment
)
{
create
(
:deployment
,
:success
)
}
create
(
:deployment
,
environment:
environment
)
it
{
is_expected
.
to
eq
([
deployment
])
}
end
context
'when deployment status is created'
do
let
(
:deployment
)
{
create
(
:deployment
,
:created
)
}
it
{
is_expected
.
to
be_empty
}
end
context
'when deployment status is running'
do
let
(
:deployment
)
{
create
(
:deployment
,
:running
)
}
it
{
is_expected
.
to
be_empty
}
end
end
describe
'state machine'
do
context
'when deployment runs'
do
let
(
:deployment
)
{
create
(
:deployment
)
}
before
do
deployment
.
run!
end
it
'starts running'
do
Timecop
.
freeze
do
expect
(
deployment
).
to
be_running
expect
(
deployment
.
finished_at
).
to
be_nil
end
end
end
context
'when deployment succeeded'
do
let
(
:deployment
)
{
create
(
:deployment
,
:running
)
}
it
'has correct status'
do
Timecop
.
freeze
do
deployment
.
succeed!
expect
(
deployment
).
to
be_success
expect
(
deployment
.
finished_at
).
to
eq
(
Time
.
now
)
end
end
it
'executes Deployments::SuccessWorker asynchronously'
do
expect
(
Deployments
::
SuccessWorker
)
.
to
receive
(
:perform_async
).
with
(
deployment
.
id
)
expect
(
store
.
get
(
environment
.
etag_cache_key
)).
not_to
eq
(
old_value
)
deployment
.
succeed!
end
end
context
'when deployment failed'
do
let
(
:deployment
)
{
create
(
:deployment
,
:running
)
}
it
'has correct status'
do
Timecop
.
freeze
do
deployment
.
drop!
expect
(
deployment
).
to
be_failed
expect
(
deployment
.
finished_at
).
to
eq
(
Time
.
now
)
end
end
end
context
'when deployment was canceled'
do
let
(
:deployment
)
{
create
(
:deployment
,
:running
)
}
it
'has correct status'
do
Timecop
.
freeze
do
deployment
.
cancel!
expect
(
deployment
).
to
be_canceled
expect
(
deployment
.
finished_at
).
to
eq
(
Time
.
now
)
end
end
end
end
describe
'#success?'
do
subject
{
deployment
.
success?
}
context
'when deployment status is success'
do
let
(
:deployment
)
{
create
(
:deployment
,
:success
)
}
it
{
is_expected
.
to
be_truthy
}
end
context
'when deployment status is failed'
do
let
(
:deployment
)
{
create
(
:deployment
,
:failed
)
}
it
{
is_expected
.
to
be_falsy
}
end
end
describe
'#status_name'
do
subject
{
deployment
.
status_name
}
context
'when deployment status is success'
do
let
(
:deployment
)
{
create
(
:deployment
,
:success
)
}
it
{
is_expected
.
to
eq
(
:success
)
}
end
context
'when deployment status is failed'
do
let
(
:deployment
)
{
create
(
:deployment
,
:failed
)
}
it
{
is_expected
.
to
eq
(
:failed
)
}
end
end
describe
'#finished_at'
do
subject
{
deployment
.
finished_at
}
context
'when deployment status is created'
do
let
(
:deployment
)
{
create
(
:deployment
)
}
it
{
is_expected
.
to
be_nil
}
end
context
'when deployment status is success'
do
let
(
:deployment
)
{
create
(
:deployment
,
:success
)
}
it
{
is_expected
.
to
eq
(
deployment
.
read_attribute
(
:finished_at
))
}
end
context
'when deployment status is success'
do
let
(
:deployment
)
{
create
(
:deployment
,
:success
,
finished_at:
nil
)
}
before
do
deployment
.
update_column
(
:finished_at
,
nil
)
end
it
{
is_expected
.
to
eq
(
deployment
.
read_attribute
(
:created_at
))
}
end
context
'when deployment status is running'
do
let
(
:deployment
)
{
create
(
:deployment
,
:running
)
}
it
{
is_expected
.
to
be_nil
}
end
end
describe
'#deployed_at'
do
subject
{
deployment
.
deployed_at
}
context
'when deployment status is created'
do
let
(
:deployment
)
{
create
(
:deployment
)
}
it
{
is_expected
.
to
be_nil
}
end
context
'when deployment status is success'
do
let
(
:deployment
)
{
create
(
:deployment
,
:success
)
}
it
{
is_expected
.
to
eq
(
deployment
.
read_attribute
(
:finished_at
))
}
end
context
'when deployment status is running'
do
let
(
:deployment
)
{
create
(
:deployment
,
:running
)
}
it
{
is_expected
.
to
be_nil
}
end
end
...
...
@@ -96,7 +254,7 @@ describe Deployment do
end
describe
'#metrics'
do
let
(
:deployment
)
{
create
(
:deployment
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:success
)
}
let
(
:prometheus_adapter
)
{
double
(
'prometheus_adapter'
,
can_query?:
true
)
}
subject
{
deployment
.
metrics
}
...
...
@@ -125,7 +283,7 @@ describe Deployment do
describe
'#additional_metrics'
do
let
(
:project
)
{
create
(
:project
,
:repository
)
}
let
(
:deployment
)
{
create
(
:deployment
,
project:
project
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:succeed
,
project:
project
)
}
subject
{
deployment
.
additional_metrics
}
...
...
spec/models/environment_spec.rb
View file @
18fa8041
...
...
@@ -95,7 +95,7 @@ describe Environment do
context
'with a last deployment'
do
let!
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
sha:
project
.
commit
(
'master'
).
id
)
create
(
:deployment
,
:success
,
environment:
environment
,
sha:
project
.
commit
(
'master'
).
id
)
end
context
'in the same branch'
do
...
...
@@ -136,8 +136,8 @@ describe Environment do
describe
'#first_deployment_for'
do
let
(
:project
)
{
create
(
:project
,
:repository
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
,
ref:
commit
.
parent
.
id
)
}
let!
(
:deployment1
)
{
create
(
:deployment
,
environment:
environment
,
ref:
commit
.
id
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:succeed
,
environment:
environment
,
ref:
commit
.
parent
.
id
)
}
let!
(
:deployment1
)
{
create
(
:deployment
,
:succeed
,
environment:
environment
,
ref:
commit
.
id
)
}
let
(
:head_commit
)
{
project
.
commit
}
let
(
:commit
)
{
project
.
commit
.
parent
}
...
...
@@ -181,7 +181,8 @@ describe Environment do
let
(
:build
)
{
create
(
:ci_build
)
}
let!
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
build
,
on_stop:
'close_app'
)
end
...
...
@@ -249,7 +250,8 @@ describe Environment do
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let!
(
:deployment
)
do
create
(
:deployment
,
environment:
environment
,
create
(
:deployment
,
:success
,
environment:
environment
,
deployable:
build
,
on_stop:
'close_app'
)
end
...
...
@@ -304,7 +306,7 @@ describe Environment do
context
'when last deployment to environment is the most recent one'
do
before
do
create
(
:deployment
,
environment:
environment
,
ref:
'feature'
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'feature'
)
end
it
{
is_expected
.
to
be
true
}
...
...
@@ -312,8 +314,8 @@ describe Environment do
context
'when last deployment to environment is not the most recent'
do
before
do
create
(
:deployment
,
environment:
environment
,
ref:
'feature'
)
create
(
:deployment
,
environment:
environment
,
ref:
'master'
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'feature'
)
create
(
:deployment
,
:success
,
environment:
environment
,
ref:
'master'
)
end
it
{
is_expected
.
to
be
false
}
...
...
@@ -321,7 +323,7 @@ describe Environment do
end
describe
'#actions_for'
do
let
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
)
}
let
(
:pipeline
)
{
deployment
.
deployable
.
pipeline
}
let!
(
:review_action
)
{
create
(
:ci_build
,
:manual
,
name:
'review-apps'
,
pipeline:
pipeline
,
environment:
'review/$CI_COMMIT_REF_NAME'
)}
let!
(
:production_action
)
{
create
(
:ci_build
,
:manual
,
name:
'production'
,
pipeline:
pipeline
,
environment:
'production'
)}
...
...
@@ -331,6 +333,70 @@ describe Environment do
end
end
describe
'.deployments'
do
subject
{
environment
.
deployments
}
context
'when there is a deployment record with created status'
do
let
(
:deployment
)
{
create
(
:deployment
,
:created
,
environment:
environment
)
}
it
'does not return the record'
do
is_expected
.
to
be_empty
end
end
context
'when there is a deployment record with running status'
do
let
(
:deployment
)
{
create
(
:deployment
,
:running
,
environment:
environment
)
}
it
'does not return the record'
do
is_expected
.
to
be_empty
end
end
context
'when there is a deployment record with success status'
do
let
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
)
}
it
'returns the record'
do
is_expected
.
to
eq
([
deployment
])
end
end
end
describe
'.last_deployment'
do
subject
{
environment
.
last_deployment
}
before
do
allow_any_instance_of
(
Deployment
).
to
receive
(
:create_ref
)
end
context
'when there is an old deployment record'
do
let!
(
:previous_deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
)
}
context
'when there is a deployment record with created status'
do
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
)
}
it
'returns the previous deployment'
do
is_expected
.
to
eq
(
previous_deployment
)
end
end
context
'when there is a deployment record with running status'
do
let!
(
:deployment
)
{
create
(
:deployment
,
:running
,
environment:
environment
)
}
it
'returns the previous deployment'
do
is_expected
.
to
eq
(
previous_deployment
)
end
end
context
'when there is a deployment record with success status'
do
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
)
}
it
'returns the latest successful deployment'
do
is_expected
.
to
eq
(
deployment
)
end
end
end
end
describe
'#has_terminals?'
do
subject
{
environment
.
has_terminals?
}
...
...
@@ -338,7 +404,7 @@ describe Environment do
context
'with a deployment service'
do
shared_examples
'same behavior between KubernetesService and Platform::Kubernetes'
do
context
'and a deployment'
do
let!
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
)
}
it
{
is_expected
.
to
be_truthy
}
end
...
...
spec/models/environment_status_spec.rb
View file @
18fa8041
require
'spec_helper'
describe
EnvironmentStatus
do
let
(
:deployment
)
{
create
(
:deployment
,
:review_app
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:
succeed
,
:
review_app
)
}
let
(
:environment
)
{
deployment
.
environment
}
let
(
:project
)
{
deployment
.
project
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:deployed_review_app
,
deployment:
deployment
)
}
...
...
@@ -12,7 +12,7 @@ describe EnvironmentStatus do
it
{
is_expected
.
to
delegate_method
(
:id
).
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
(
:deployed_at
).
to
(
:deployment
)
.
as
(
:created_at
)
}
it
{
is_expected
.
to
delegate_method
(
:deployed_at
).
to
(
:deployment
)
}
it
{
is_expected
.
to
delegate_method
(
:status
).
to
(
:deployment
)
}
describe
'#project'
do
...
...
spec/models/merge_request_spec.rb
View file @
18fa8041
...
...
@@ -1987,8 +1987,8 @@ describe MergeRequest do
let
(
:environments
)
{
create_list
(
:environment
,
3
,
project:
project
)
}
before
do
create
(
:deployment
,
environment:
environments
.
first
,
ref:
'master'
,
sha:
project
.
commit
(
'master'
).
id
)
create
(
:deployment
,
environment:
environments
.
second
,
ref:
'feature'
,
sha:
project
.
commit
(
'feature'
).
id
)
create
(
:deployment
,
:success
,
environment:
environments
.
first
,
ref:
'master'
,
sha:
project
.
commit
(
'master'
).
id
)
create
(
:deployment
,
:success
,
environment:
environments
.
second
,
ref:
'feature'
,
sha:
project
.
commit
(
'feature'
).
id
)
end
it
'selects deployed environments'
do
...
...
@@ -2008,7 +2008,7 @@ describe MergeRequest do
let
(
:source_environment
)
{
create
(
:environment
,
project:
source_project
)
}
before
do
create
(
:deployment
,
environment:
source_environment
,
ref:
'feature'
,
sha:
merge_request
.
diff_head_sha
)
create
(
:deployment
,
:success
,
environment:
source_environment
,
ref:
'feature'
,
sha:
merge_request
.
diff_head_sha
)
end
it
'selects deployed environments'
do
...
...
@@ -2019,7 +2019,7 @@ describe MergeRequest do
let
(
:target_environment
)
{
create
(
:environment
,
project:
project
)
}
before
do
create
(
:deployment
,
environment:
target_environment
,
tag:
true
,
sha:
merge_request
.
diff_head_sha
)
create
(
:deployment
,
:success
,
environment:
target_environment
,
tag:
true
,
sha:
merge_request
.
diff_head_sha
)
end
it
'selects deployed environments'
do
...
...
spec/models/project_spec.rb
View file @
18fa8041
...
...
@@ -4289,6 +4289,40 @@ describe Project do
end
end
describe
'.deployments'
do
subject
{
project
.
deployments
}
let
(
:project
)
{
create
(
:project
)
}
before
do
allow_any_instance_of
(
Deployment
).
to
receive
(
:create_ref
)
end
context
'when there is a deployment record with created status'
do
let
(
:deployment
)
{
create
(
:deployment
,
:created
,
project:
project
)
}
it
'does not return the record'
do
is_expected
.
to
be_empty
end
end
context
'when there is a deployment record with running status'
do
let
(
:deployment
)
{
create
(
:deployment
,
:running
,
project:
project
)
}
it
'does not return the record'
do
is_expected
.
to
be_empty
end
end
context
'when there is a deployment record with success status'
do
let
(
:deployment
)
{
create
(
:deployment
,
:success
,
project:
project
)
}
it
'returns the record'
do
is_expected
.
to
eq
([
deployment
])
end
end
end
def
rugged_config
rugged_repo
(
project
.
repository
).
config
end
...
...
spec/requests/api/deployments_spec.rb
View file @
18fa8041
...
...
@@ -10,9 +10,9 @@ describe API::Deployments do
describe
'GET /projects/:id/deployments'
do
let
(
:project
)
{
create
(
:project
)
}
let!
(
:deployment_1
)
{
create
(
:deployment
,
project:
project
,
iid:
11
,
ref:
'master'
,
created_at:
Time
.
now
)
}
let!
(
:deployment_2
)
{
create
(
:deployment
,
project:
project
,
iid:
12
,
ref:
'feature'
,
created_at:
1
.
day
.
ago
)
}
let!
(
:deployment_3
)
{
create
(
:deployment
,
project:
project
,
iid:
8
,
ref:
'feature
'
,
created_at:
2
.
days
.
ago
)
}
let!
(
:deployment_1
)
{
create
(
:deployment
,
:success
,
project:
project
,
iid:
11
,
ref:
'master'
,
created_at:
Time
.
now
)
}
let!
(
:deployment_2
)
{
create
(
:deployment
,
:success
,
project:
project
,
iid:
12
,
ref:
'feature'
,
created_at:
1
.
day
.
ago
)
}
let!
(
:deployment_3
)
{
create
(
:deployment
,
:success
,
project:
project
,
iid:
8
,
ref:
'patch
'
,
created_at:
2
.
days
.
ago
)
}
context
'as member of the project'
do
it
'returns projects deployments sorted by id asc'
do
...
...
@@ -53,8 +53,8 @@ describe API::Deployments do
'id'
|
'desc'
|
[
:deployment_3
,
:deployment_2
,
:deployment_1
]
'iid'
|
'asc'
|
[
:deployment_3
,
:deployment_1
,
:deployment_2
]
'iid'
|
'desc'
|
[
:deployment_2
,
:deployment_1
,
:deployment_3
]
'ref'
|
'asc'
|
[
:deployment_2
,
:deployment_
3
,
:deployment_1
]
'ref'
|
'desc'
|
[
:deployment_
1
,
:deployment_2
,
:deployment_3
]
'ref'
|
'asc'
|
[
:deployment_2
,
:deployment_
1
,
:deployment_3
]
'ref'
|
'desc'
|
[
:deployment_
3
,
:deployment_1
,
:deployment_2
]
end
with_them
do
...
...
@@ -76,7 +76,7 @@ describe API::Deployments do
describe
'GET /projects/:id/deployments/:deployment_id'
do
let
(
:project
)
{
deployment
.
environment
.
project
}
let!
(
:deployment
)
{
create
(
:deployment
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
:success
)
}
context
'as a member of the project'
do
it
'returns the projects deployment'
do
...
...
spec/serializers/environment_serializer_spec.rb
View file @
18fa8041
...
...
@@ -14,7 +14,8 @@ describe EnvironmentSerializer do
let
(
:project
)
{
create
(
:project
,
:repository
)
}
let
(
:deployable
)
{
create
(
:ci_build
)
}
let
(
:deployment
)
do
create
(
:deployment
,
deployable:
deployable
,
create
(
:deployment
,
:success
,
deployable:
deployable
,
user:
user
,
project:
project
,
sha:
project
.
commit
.
id
)
...
...
spec/serializers/environment_status_entity_spec.rb
View file @
18fa8041
...
...
@@ -4,8 +4,8 @@ describe EnvironmentStatusEntity do
let
(
:user
)
{
create
(
:user
)
}
let
(
:request
)
{
double
(
'request'
)
}
let
(
:deployment
)
{
create
(
:deployment
,
:review_app
)
}
let
(
:environment
)
{
deployment
.
environment
}
let
(
:deployment
)
{
create
(
:deployment
,
:
succeed
,
:
review_app
)
}
let
(
:environment
)
{
deployment
.
environment
}
let
(
:project
)
{
deployment
.
project
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:deployed_review_app
,
deployment:
deployment
)
}
...
...
spec/services/ci/retry_build_service_spec.rb
View file @
18fa8041
...
...
@@ -32,7 +32,7 @@ describe Ci::RetryBuildService do
IGNORE_ACCESSORS
=
%i[type lock_version target_url base_tags trace_sections
commit_id deployment
s erased_by_id last_deployment
project_id
commit_id deployment
erased_by_id
project_id
runner_id tag_taggings taggings tags trigger_request_id
user_id auto_canceled_by_id retried failure_reason
sourced_pipelines artifacts_file_store artifacts_metadata_store
...
...
spec/services/
cre
ate_deployment_service_spec.rb
→
spec/services/
upd
ate_deployment_service_spec.rb
View file @
18fa8041
This diff is collapsed.
Click to expand it.
spec/support/helpers/cycle_analytics_helpers.rb
View file @
18fa8041
...
...
@@ -85,7 +85,7 @@ module CycleAnalyticsHelpers
raise
ArgumentError
end
CreateDeploymentService
.
new
(
dummy_job
).
execute
dummy_job
.
success!
# State machine automatically update associated deployment/environment record
end
def
dummy_production_job
(
user
,
project
)
...
...
@@ -97,7 +97,7 @@ module CycleAnalyticsHelpers
end
def
dummy_pipeline
(
project
)
Ci
::
Pipeline
.
new
(
create
(
:ci_pipeline
,
sha:
project
.
repository
.
commit
(
'master'
).
sha
,
ref:
'master'
,
source: :push
,
...
...
@@ -106,9 +106,7 @@ module CycleAnalyticsHelpers
end
def
new_dummy_job
(
user
,
project
,
environment
)
project
.
environments
.
find_or_create_by
(
name:
environment
)
Ci
::
Build
.
new
(
create
(
:ci_build
,
project:
project
,
user:
user
,
environment:
environment
,
...
...
spec/workers/build_success_worker_spec.rb
View file @
18fa8041
...
...
@@ -2,15 +2,39 @@ require 'spec_helper'
describe
BuildSuccessWorker
do
describe
'#perform'
do
subject
{
described_class
.
new
.
perform
(
build
.
id
)
}
before
do
allow_any_instance_of
(
Deployment
).
to
receive
(
:create_ref
)
end
context
'when build exists'
do
context
'when build belogs to the environment'
do
let!
(
:build
)
{
create
(
:ci_build
,
environment:
'production'
)
}
context
'when deployment was not created with the build creation'
do
# An edge case during the transition period
let!
(
:build
)
{
create
(
:ci_build
,
:deploy_to_production
)
}
before
do
Deployment
.
delete_all
build
.
reload
end
it
'creates a successful deployment'
do
expect
(
build
).
not_to
be_has_deployment
subject
build
.
reload
expect
(
build
).
to
be_has_deployment
expect
(
build
.
deployment
).
to
be_success
end
end
context
'when deployment was created with the build creation'
do
# Counter part of the above edge case
let!
(
:build
)
{
create
(
:ci_build
,
:deploy_to_production
)
}
it
'executes deployment service'
do
expect_any_instance_of
(
CreateDeploymentService
)
.
to
receive
(
:execute
)
it
'does not create a new deployment'
do
expect
(
build
).
to
be_has_deployment
described_class
.
new
.
perform
(
build
.
id
)
expect
{
subject
}.
not_to
change
{
Deployment
.
count
}
end
end
...
...
@@ -18,10 +42,9 @@ describe BuildSuccessWorker do
let!
(
:build
)
{
create
(
:ci_build
,
project:
nil
)
}
it
'does not create deployment'
do
expect_any_instance_of
(
CreateDeploymentService
)
.
not_to
receive
(
:execute
)
subject
described_class
.
new
.
perform
(
build
.
id
)
expect
(
build
.
reload
).
not_to
be_has_deployment
end
end
end
...
...
spec/workers/deployments/success_worker_spec.rb
0 → 100644
View file @
18fa8041
require
'spec_helper'
describe
Deployments
::
SuccessWorker
do
subject
{
described_class
.
new
.
perform
(
deployment
&
.
id
)
}
context
'when successful deployment'
do
let
(
:deployment
)
{
create
(
:deployment
,
:success
)
}
it
'executes UpdateDeploymentService'
do
expect
(
UpdateDeploymentService
)
.
to
receive
(
:new
).
with
(
deployment
).
and_call_original
subject
end
end
context
'when canceled deployment'
do
let
(
:deployment
)
{
create
(
:deployment
,
:canceled
)
}
it
'does not execute UpdateDeploymentService'
do
expect
(
UpdateDeploymentService
).
not_to
receive
(
:new
)
subject
end
end
context
'when deploy record does not exist'
do
let
(
:deployment
)
{
nil
}
it
'does not execute UpdateDeploymentService'
do
expect
(
UpdateDeploymentService
).
not_to
receive
(
:new
)
subject
end
end
end
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