summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShinya Maeda <shinya@gitlab.com>2018-11-07 15:37:25 +0900
committerShinya Maeda <shinya@gitlab.com>2018-11-07 15:37:25 +0900
commit689eca0b0f35528fb4c17f74bdaa90331934e55d (patch)
treef904396eb6d7beeca39ba11907e9db1de194a859
parentd4d073c157444fcb1671b39a9c2f96086ed28f1c (diff)
downloadgitlab-ce-add-action-to-deployments.tar.gz
Revert "Revert add action column changes"add-action-to-deployments
This reverts commit 9c811566f85d18bc9eb4a85c6a343cf1bfa4fbd2.
-rw-r--r--app/controllers/projects/deployments_controller.rb4
-rw-r--r--app/controllers/projects/environments_controller.rb2
-rw-r--r--app/finders/environments_finder.rb2
-rw-r--r--app/models/concerns/deployable.rb5
-rw-r--r--app/models/deployment.rb21
-rw-r--r--app/models/environment.rb15
-rw-r--r--app/models/environment_status.rb2
-rw-r--r--app/models/project.rb2
-rw-r--r--app/services/start_environment_service.rb (renamed from app/services/update_deployment_service.rb)11
-rw-r--r--app/services/stop_environment_service.rb18
-rw-r--r--app/workers/build_success_worker.rb7
-rw-r--r--app/workers/deployments/success_worker.rb8
-rw-r--r--db/fixtures/development/14_pipelines.rb8
-rw-r--r--db/fixtures/development/19_environments.rb20
-rw-r--r--db/migrate/20181030150739_add_action_to_deployments.rb24
-rw-r--r--db/migrate/20181106135939_add_index_to_deployments.rb29
-rw-r--r--db/schema.rb47
-rw-r--r--lib/api/deployments.rb4
-rw-r--r--lib/gitlab/cycle_analytics/summary/deploy.rb2
-rw-r--r--spec/factories/deployments.rb8
-rw-r--r--spec/features/merge_request/user_sees_deployment_widget_spec.rb120
-rw-r--r--spec/features/projects/environments/environment_spec.rb13
-rw-r--r--spec/features/projects/environments/environments_spec.rb17
-rw-r--r--spec/models/concerns/deployable_spec.rb10
-rw-r--r--spec/models/deployment_spec.rb144
-rw-r--r--spec/models/environment_spec.rb44
-rw-r--r--spec/models/environment_status_spec.rb2
-rw-r--r--spec/services/start_environment_service_spec.rb (renamed from spec/services/update_deployment_service_spec.rb)6
-rw-r--r--spec/services/stop_environment_service_spec.rb43
-rw-r--r--spec/workers/build_success_worker_spec.rb13
-rw-r--r--spec/workers/deployments/success_worker_spec.rb51
31 files changed, 542 insertions, 160 deletions
diff --git a/app/controllers/projects/deployments_controller.rb b/app/controllers/projects/deployments_controller.rb
index 0a009477d61..bd4102d4531 100644
--- a/app/controllers/projects/deployments_controller.rb
+++ b/app/controllers/projects/deployments_controller.rb
@@ -6,7 +6,7 @@ class Projects::DeploymentsController < Projects::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def index
- deployments = environment.deployments.reorder(created_at: :desc)
+ deployments = environment.deployments.deployed.reorder(created_at: :desc)
deployments = deployments.where('created_at > ?', params[:after].to_time) if params[:after]&.to_time
render json: { deployments: DeploymentSerializer.new(project: project)
@@ -47,7 +47,7 @@ class Projects::DeploymentsController < Projects::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def deployment
- @deployment ||= environment.deployments.find_by(iid: params[:id])
+ @deployment ||= environment.deployments.deployed.find_by(iid: params[:id])
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index de10783df1a..ab3ad9bf090 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -58,7 +58,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def show
- @deployments = environment.deployments.order(id: :desc).page(params[:page])
+ @deployments = environment.deployments.deployed.order(id: :desc).page(params[:page])
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/environments_finder.rb b/app/finders/environments_finder.rb
index 32f41314359..156d49745c9 100644
--- a/app/finders/environments_finder.rb
+++ b/app/finders/environments_finder.rb
@@ -9,7 +9,7 @@ class EnvironmentsFinder
# rubocop: disable CodeReuse/ActiveRecord
def execute
- deployments = project.deployments.success
+ deployments = project.deployments.deployed
deployments =
if ref
deployments_query = params[:with_tags] ? 'ref = :ref OR tag IS TRUE' : 'ref = :ref'
diff --git a/app/models/concerns/deployable.rb b/app/models/concerns/deployable.rb
index f4f1989f0a9..d85d624fff3 100644
--- a/app/models/concerns/deployable.rb
+++ b/app/models/concerns/deployable.rb
@@ -7,7 +7,7 @@ module Deployable
after_create :create_deployment
def create_deployment
- return unless starts_environment? && !has_deployment?
+ return unless has_environment? && !has_deployment?
environment = project.environments.find_or_create_by(
name: expanded_environment_name
@@ -21,7 +21,8 @@ module Deployable
sha: sha,
user: user,
deployable: self,
- on_stop: on_stop).tap do |_|
+ on_stop: on_stop,
+ action: environment_action).tap do |_|
self.reload # Reload relationships
end
end
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index 305922611a6..322b3139759 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -10,9 +10,7 @@ class Deployment < ActiveRecord::Base
belongs_to :user
belongs_to :deployable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
- has_internal_id :iid, scope: :project, init: ->(s) do
- Deployment.where(project: s.project).maximum(:iid) if s&.project
- end
+ has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.deployments&.maximum(:iid) }
validates :sha, presence: true
validates :ref, presence: true
@@ -20,6 +18,8 @@ class Deployment < ActiveRecord::Base
delegate :name, to: :environment, prefix: true
scope :for_environment, -> (environment) { where(environment_id: environment) }
+ scope :deployed, -> { success.start }
+ scope :stopped, -> { success.stop }
state_machine :status, initial: :created do
event :run do
@@ -57,6 +57,11 @@ class Deployment < ActiveRecord::Base
canceled: 4
}
+ enum action: {
+ start: 1,
+ stop: 2
+ }
+
def self.last_for_environment(environment)
ids = self
.for_environment(environment)
@@ -132,7 +137,7 @@ class Deployment < ActiveRecord::Base
def previous_deployment
@previous_deployment ||=
- project.deployments.success.joins(:environment)
+ project.deployments.deployed.joins(:environment)
.where(environments: { name: self.environment.name }, ref: self.ref)
.where.not(id: self.id)
.take
@@ -177,6 +182,14 @@ class Deployment < ActiveRecord::Base
metrics&.merge(deployment_time: finished_at.to_i) || {}
end
+ def deployed?
+ success? && start?
+ end
+
+ def stopped?
+ success? && stop?
+ end
+
private
def prometheus_adapter
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 581c870b2c5..1a535ba6b18 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -8,9 +8,9 @@ class Environment < ActiveRecord::Base
belongs_to :project, required: true
- has_many :deployments, -> { success }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_many :deployments, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
- has_one :last_deployment, -> { success.order('deployments.id DESC') }, class_name: 'Deployment'
+ has_one :last_deployment, -> { deployed.order('deployments.id DESC') }, class_name: 'Deployment'
before_validation :nullify_external_url
before_validation :generate_slug, if: ->(env) { env.slug.blank? }
@@ -50,7 +50,7 @@ class Environment < ActiveRecord::Base
scope :in_review_folder, -> { where(environment_type: "review") }
scope :for_name, -> (name) { where(name: name) }
scope :for_project, -> (project) { where(project_id: project) }
- scope :with_deployment, -> (sha) { where('EXISTS (?)', Deployment.select(1).where('deployments.environment_id = environments.id').where(sha: sha)) }
+ scope :with_deployment, -> (sha) { where('EXISTS (?)', Deployment.select(1).start.where('deployments.environment_id = environments.id').where(sha: sha)) }
state_machine :state, initial: :available do
event :start do
@@ -103,15 +103,6 @@ class Environment < ActiveRecord::Base
folder_name == "production"
end
- def first_deployment_for(commit_sha)
- ref = project.repository.ref_name_for_sha(ref_path, commit_sha)
-
- return nil unless ref
-
- deployment_iid = ref.split('/').last
- deployments.find_by(iid: deployment_iid)
- end
-
def ref_path
"refs/#{Repository::REF_ENVIRONMENTS}/#{slug}"
end
diff --git a/app/models/environment_status.rb b/app/models/environment_status.rb
index 76fd0241239..b33c4f2738d 100644
--- a/app/models/environment_status.rb
+++ b/app/models/environment_status.rb
@@ -28,7 +28,7 @@ class EnvironmentStatus
def deployment
strong_memoize(:deployment) do
- Deployment.where(environment: environment).find_by_sha(sha)
+ environment.deployments.start.find_by_sha(sha)
end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index d5a4ae79c47..d3b148d0ac0 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -254,7 +254,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, -> { success }
+ has_many :deployments
has_many :pipeline_schedules, class_name: 'Ci::PipelineSchedule'
has_many :project_deploy_tokens
has_many :deploy_tokens, through: :project_deploy_tokens
diff --git a/app/services/update_deployment_service.rb b/app/services/start_environment_service.rb
index aa7fcca1e2a..138ee55f6dc 100644
--- a/app/services/update_deployment_service.rb
+++ b/app/services/start_environment_service.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class UpdateDeploymentService
+class StartEnvironmentService
attr_reader :deployment
attr_reader :deployable
@@ -13,6 +13,8 @@ class UpdateDeploymentService
end
def execute
+ return unless deployment.deployed?
+
deployment.create_ref
deployment.invalidate_cache
@@ -20,10 +22,9 @@ class UpdateDeploymentService
environment.external_url = expanded_environment_url if
expanded_environment_url
- environment.fire_state_event(action)
+ environment.fire_state_event(:start)
break unless environment.save
- break if environment.stopped?
deployment.tap(&:update_merge_request_metrics!)
end
@@ -46,8 +47,4 @@ class UpdateDeploymentService
def environment_url
environment_options[:url]
end
-
- def action
- environment_options[:action] || 'start'
- end
end
diff --git a/app/services/stop_environment_service.rb b/app/services/stop_environment_service.rb
new file mode 100644
index 00000000000..79dbf292123
--- /dev/null
+++ b/app/services/stop_environment_service.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class StopEnvironmentService
+ attr_reader :deployment
+
+ delegate :environment, to: :deployment
+
+ def initialize(deployment)
+ @deployment = deployment
+ end
+
+ def execute
+ return unless deployment.stopped?
+
+ environment.fire_state_event(:stop)
+ environment.expire_etag_cache
+ end
+end
diff --git a/app/workers/build_success_worker.rb b/app/workers/build_success_worker.rb
index 9a865fea621..f3530317090 100644
--- a/app/workers/build_success_worker.rb
+++ b/app/workers/build_success_worker.rb
@@ -10,7 +10,6 @@ class BuildSuccessWorker
def perform(build_id)
Ci::Build.find_by(id: build_id).try do |build|
create_deployment(build) if build.has_environment?
- stop_environment(build) if build.stops_environment?
end
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -27,10 +26,4 @@ class BuildSuccessWorker
deployment.succeed
end
end
-
- ##
- # TODO: This should be processed in DeploymentSuccessWorker once we started storing `action` value in `deployments` records
- def stop_environment(build)
- build.persisted_environment.fire_state_event(:stop)
- end
end
diff --git a/app/workers/deployments/success_worker.rb b/app/workers/deployments/success_worker.rb
index da517f3fb26..68fe8997f12 100644
--- a/app/workers/deployments/success_worker.rb
+++ b/app/workers/deployments/success_worker.rb
@@ -8,9 +8,11 @@ module Deployments
def perform(deployment_id)
Deployment.find_by_id(deployment_id).try do |deployment|
- break unless deployment.success?
-
- UpdateDeploymentService.new(deployment).execute
+ if deployment.deployed?
+ StartEnvironmentService.new(deployment).execute
+ elsif deployment.stopped?
+ StopEnvironmentService.new(deployment).execute
+ end
end
end
end
diff --git a/db/fixtures/development/14_pipelines.rb b/db/fixtures/development/14_pipelines.rb
index 5af77c49913..e4272cbee33 100644
--- a/db/fixtures/development/14_pipelines.rb
+++ b/db/fixtures/development/14_pipelines.rb
@@ -43,12 +43,14 @@ class Gitlab::Seeder::Pipelines
# deploy stage
{ name: 'staging', stage: 'deploy', environment: 'staging', status_event: :success,
- options: { environment: { action: 'start', on_stop: 'stop staging' } },
+ options: { environment: { name: 'staging', action: 'start', on_stop: 'stop staging' } },
queued_at: 7.hour.ago, started_at: 6.hour.ago, finished_at: 4.hour.ago },
{ name: 'stop staging', stage: 'deploy', environment: 'staging',
- when: 'manual', status: :skipped },
+ when: 'manual', status: :skipped,
+ options: { environment: { name: 'staging', action: 'stop' } } },
{ name: 'production', stage: 'deploy', environment: 'production',
- when: 'manual', status: :skipped },
+ when: 'manual', status: :skipped,
+ options: { environment: { name: 'production' } } },
# notify stage
{ name: 'slack', stage: 'notify', when: 'manual', status: :success },
diff --git a/db/fixtures/development/19_environments.rb b/db/fixtures/development/19_environments.rb
index 3e227928a29..031a04ac76b 100644
--- a/db/fixtures/development/19_environments.rb
+++ b/db/fixtures/development/19_environments.rb
@@ -45,14 +45,18 @@ class Gitlab::Seeder::Environments
end
def create_deployment!(project, name, ref, sha)
- environment = find_or_create_environment!(project, name)
- environment.deployments.create!(
- project: project,
- ref: ref,
- sha: sha,
- tag: false,
- deployable: find_deployable(project, name)
- )
+ find_deployable(project, name).try do |deployable|
+ environment = find_or_create_environment!(project, name)
+ environment.deployments.create!(
+ project: project,
+ ref: ref,
+ sha: sha,
+ tag: false,
+ deployable: deployable
+ ).tap do |deployment|
+ deployment.succeed!
+ end
+ end
end
def find_or_create_environment!(project, name)
diff --git a/db/migrate/20181030150739_add_action_to_deployments.rb b/db/migrate/20181030150739_add_action_to_deployments.rb
new file mode 100644
index 00000000000..a8c3a8ee69c
--- /dev/null
+++ b/db/migrate/20181030150739_add_action_to_deployments.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class AddActionToDeployments < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DEPLOYMENT_ACTION_START = 1 # Equivalent to Deployment.actions['start']
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default(:deployments,
+ :action,
+ :integer,
+ limit: 2,
+ default: DEPLOYMENT_ACTION_START,
+ allow_null: false)
+ end
+
+ def down
+ remove_column(:deployments, :action)
+ end
+end
diff --git a/db/migrate/20181106135939_add_index_to_deployments.rb b/db/migrate/20181106135939_add_index_to_deployments.rb
index 999c4a9e575..47c704a03ae 100644
--- a/db/migrate/20181106135939_add_index_to_deployments.rb
+++ b/db/migrate/20181106135939_add_index_to_deployments.rb
@@ -4,26 +4,27 @@ class AddIndexToDeployments < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
+ SHORT_INDEX_NAME_FOR_ENVIRONMENT_ID = 'index_deployments_on_env_deployed_for_id'
+ SHORT_INDEX_NAME_FOR_ENVIRONMENT_IID = 'index_deployments_on_env_deployed_for_iid'
+ SHORT_INDEX_NAME_FOR_PROJECT_FINISHED_AT = 'index_deployments_on_prj_deployed_for_finished_at'
disable_ddl_transaction!
def up
- remove_concurrent_index :deployments, [:project_id, :status]
- remove_concurrent_index :deployments, [:environment_id, :status]
- add_concurrent_index :deployments, [:project_id, :status, :id]
- add_concurrent_index :deployments, [:project_id, :status, :iid]
- add_concurrent_index :deployments, [:environment_id, :status, :id]
- add_concurrent_index :deployments, [:environment_id, :status, :iid]
- add_concurrent_index :deployments, [:environment_id, :sha]
+ add_concurrent_index :deployments, [:project_id, :action, :status, :id]
+ add_concurrent_index :deployments, [:project_id, :action, :status, :iid]
+ add_concurrent_index :deployments, [:project_id, :action, :status, :finished_at], name: SHORT_INDEX_NAME_FOR_PROJECT_FINISHED_AT
+ add_concurrent_index :deployments, [:environment_id, :action, :status, :id], name: SHORT_INDEX_NAME_FOR_ENVIRONMENT_ID
+ add_concurrent_index :deployments, [:environment_id, :action, :status, :iid], name: SHORT_INDEX_NAME_FOR_ENVIRONMENT_IID
+ add_concurrent_index :deployments, [:environment_id, :action, :sha]
end
def down
- add_concurrent_index :deployments, [:project_id, :status]
- add_concurrent_index :deployments, [:environment_id, :status]
- remove_concurrent_index :deployments, [:project_id, :status, :id]
- remove_concurrent_index :deployments, [:project_id, :status, :iid]
- remove_concurrent_index :deployments, [:environment_id, :status, :id]
- remove_concurrent_index :deployments, [:environment_id, :status, :iid]
- remove_concurrent_index :deployments, [:environment_id, :sha]
+ remove_concurrent_index :deployments, [:project_id, :action, :status, :id]
+ remove_concurrent_index :deployments, [:project_id, :action, :status, :iid]
+ remove_concurrent_index_by_name(:deployments, SHORT_INDEX_NAME_FOR_PROJECT_FINISHED_AT)
+ remove_concurrent_index_by_name(:deployments, SHORT_INDEX_NAME_FOR_ENVIRONMENT_ID)
+ remove_concurrent_index_by_name(:deployments, SHORT_INDEX_NAME_FOR_ENVIRONMENT_IID)
+ remove_concurrent_index :deployments, [:environment_id, :action, :sha]
end
end
diff --git a/db/schema.rb b/db/schema.rb
index d31f6f09b78..ae9b1f24a4b 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -827,19 +827,23 @@ ActiveRecord::Schema.define(version: 20181106135939) do
t.string "on_stop"
t.integer "status", limit: 2, default: 2, null: false
t.datetime_with_timezone "finished_at"
+ t.integer "action", limit: 2, default: 1, null: false
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", "action", "sha"], name: "index_deployments_on_environment_id_and_action_and_sha", using: :btree
+ add_index "deployments", ["environment_id", "action", "status", "id"], name: "index_deployments_on_env_deployed_for_id", using: :btree
+ add_index "deployments", ["environment_id", "action", "status", "iid"], name: "index_deployments_on_env_deployed_for_iid", 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", "sha"], name: "index_deployments_on_environment_id_and_sha", using: :btree
- add_index "deployments", ["environment_id", "status", "id"], name: "index_deployments_on_environment_id_and_status_and_id", using: :btree
- add_index "deployments", ["environment_id", "status", "iid"], name: "index_deployments_on_environment_id_and_status_and_iid", 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", "action", "status", "finished_at"], name: "index_deployments_on_prj_deployed_for_finished_at", using: :btree
+ add_index "deployments", ["project_id", "action", "status", "id"], name: "index_deployments_on_project_id_and_action_and_status_and_id", using: :btree
+ add_index "deployments", ["project_id", "action", "status", "iid"], name: "index_deployments_on_project_id_and_action_and_status_and_iid", 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", "id"], name: "index_deployments_on_project_id_and_status_and_id", using: :btree
- add_index "deployments", ["project_id", "status", "iid"], name: "index_deployments_on_project_id_and_status_and_iid", using: :btree
+ add_index "deployments", ["project_id", "status"], name: "index_deployments_on_project_id_and_status", using: :btree
create_table "emails", force: :cascade do |t|
t.integer "user_id", null: false
@@ -927,6 +931,35 @@ ActiveRecord::Schema.define(version: 20181106135939) do
add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree
+ create_table "gcp_clusters", force: :cascade do |t|
+ t.integer "project_id", null: false
+ t.integer "user_id"
+ t.integer "service_id"
+ t.integer "status"
+ t.integer "gcp_cluster_size", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.boolean "enabled", default: true
+ t.text "status_reason"
+ t.string "project_namespace"
+ t.string "endpoint"
+ t.text "ca_cert"
+ t.text "encrypted_kubernetes_token"
+ t.string "encrypted_kubernetes_token_iv"
+ t.string "username"
+ t.text "encrypted_password"
+ t.string "encrypted_password_iv"
+ t.string "gcp_project_id", null: false
+ t.string "gcp_cluster_zone", null: false
+ t.string "gcp_cluster_name", null: false
+ t.string "gcp_machine_type"
+ t.string "gcp_operation_id"
+ t.text "encrypted_gcp_token"
+ t.string "encrypted_gcp_token_iv"
+ end
+
+ add_index "gcp_clusters", ["project_id"], name: "index_gcp_clusters_on_project_id", unique: true, using: :btree
+
create_table "gpg_key_subkeys", force: :cascade do |t|
t.integer "gpg_key_id", null: false
t.binary "keyid"
@@ -1827,7 +1860,6 @@ ActiveRecord::Schema.define(version: 20181106135939) do
end
add_index "redirect_routes", ["path"], name: "index_redirect_routes_on_path", unique: true, using: :btree
- add_index "redirect_routes", ["path"], name: "index_redirect_routes_on_path_text_pattern_ops", using: :btree, opclasses: {"path"=>"varchar_pattern_ops"}
add_index "redirect_routes", ["source_type", "source_id"], name: "index_redirect_routes_on_source_type_and_source_id", using: :btree
create_table "releases", force: :cascade do |t|
@@ -2411,6 +2443,9 @@ ActiveRecord::Schema.define(version: 20181106135939) do
add_foreign_key "fork_network_members", "projects", on_delete: :cascade
add_foreign_key "fork_networks", "projects", column: "root_project_id", name: "fk_e7b436b2b5", on_delete: :nullify
add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade
+ add_foreign_key "gcp_clusters", "projects", on_delete: :cascade
+ add_foreign_key "gcp_clusters", "services", on_delete: :nullify
+ add_foreign_key "gcp_clusters", "users", on_delete: :nullify
add_foreign_key "gpg_key_subkeys", "gpg_keys", on_delete: :cascade
add_foreign_key "gpg_keys", "users", on_delete: :cascade
add_foreign_key "gpg_signatures", "gpg_key_subkeys", on_delete: :nullify
diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb
index 6747e2e5005..2fb8551543a 100644
--- a/lib/api/deployments.rb
+++ b/lib/api/deployments.rb
@@ -24,7 +24,7 @@ module API
get ':id/deployments' do
authorize! :read_deployment, user_project
- present paginate(user_project.deployments.order(params[:order_by] => params[:sort])), with: Entities::Deployment
+ present paginate(user_project.deployments.deployed.order(params[:order_by] => params[:sort])), with: Entities::Deployment
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -38,7 +38,7 @@ module API
get ':id/deployments/:deployment_id' do
authorize! :read_deployment, user_project
- deployment = user_project.deployments.find(params[:deployment_id])
+ deployment = user_project.deployments.deployed.find(params[:deployment_id])
present deployment, with: Entities::Deployment
end
diff --git a/lib/gitlab/cycle_analytics/summary/deploy.rb b/lib/gitlab/cycle_analytics/summary/deploy.rb
index 39fdf5074da..b1c644f77f3 100644
--- a/lib/gitlab/cycle_analytics/summary/deploy.rb
+++ b/lib/gitlab/cycle_analytics/summary/deploy.rb
@@ -7,7 +7,7 @@ module Gitlab
end
def value
- @value ||= @project.deployments.success.where("created_at > ?", @from).count
+ @value ||= @project.deployments.deployed.where("finished_at > ?", @from).count
end
end
end
diff --git a/spec/factories/deployments.rb b/spec/factories/deployments.rb
index 011c98599a3..483a906e31f 100644
--- a/spec/factories/deployments.rb
+++ b/spec/factories/deployments.rb
@@ -47,5 +47,13 @@ FactoryBot.define do
deployment.succeed!
end
end
+
+ trait :start do
+ action :start
+ end
+
+ trait :stop do
+ action :stop
+ end
end
end
diff --git a/spec/features/merge_request/user_sees_deployment_widget_spec.rb b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
index 74290c0fff9..53598b10fb1 100644
--- a/spec/features/merge_request/user_sees_deployment_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
@@ -18,55 +18,107 @@ describe 'Merge request > User sees deployment widget', :js do
sign_in(user)
end
- context 'when deployment succeeded' do
- let(:build) { create(:ci_build, :success, pipeline: pipeline) }
- let!(:deployment) { create(:deployment, :succeed, environment: environment, sha: sha, ref: ref, deployable: build) }
+ context 'when deployment is to start an environment' do
+ context 'when deployment succeeded' do
+ let(:build) { create(:ci_build, :success, pipeline: pipeline) }
+ let!(:deployment) { create(:deployment, :succeed, environment: environment, sha: sha, ref: ref, deployable: build) }
- it 'displays that the environment is deployed' do
- visit project_merge_request_path(project, merge_request)
- wait_for_requests
+ it 'displays that the environment is deployed' do
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
- expect(page).to have_content("Deployed to #{environment.name}")
- expect(find('.js-deploy-time')['data-original-title']).to eq(deployment.created_at.to_time.in_time_zone.to_s(:medium))
+ expect(page).to have_content("Deployed to #{environment.name}")
+ expect(find('.js-deploy-time')['data-original-title']).to eq(deployment.created_at.to_time.in_time_zone.to_s(:medium))
+ end
end
- end
- context 'when deployment failed' do
- let(:build) { create(:ci_build, :failed, pipeline: pipeline) }
- let!(:deployment) { create(:deployment, :failed, environment: environment, sha: sha, ref: ref, deployable: build) }
+ context 'when deployment failed' do
+ let(:build) { create(:ci_build, :failed, pipeline: pipeline) }
+ let!(:deployment) { create(:deployment, :failed, environment: environment, sha: sha, ref: ref, deployable: build) }
- it 'displays that the deployment failed' do
- visit project_merge_request_path(project, merge_request)
- wait_for_requests
+ it 'displays that the deployment failed' do
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
+
+ expect(page).to have_content("Failed to deploy to #{environment.name}")
+ expect(page).not_to have_css('.js-deploy-time')
+ end
+ end
+
+ context 'when deployment running' do
+ let(:build) { create(:ci_build, :running, pipeline: pipeline) }
+ let!(:deployment) { create(:deployment, :running, environment: environment, sha: sha, ref: ref, deployable: build) }
- expect(page).to have_content("Failed to deploy to #{environment.name}")
- expect(page).not_to have_css('.js-deploy-time')
+ it 'displays that the running deployment' do
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
+
+ expect(page).to have_content("Deploying to #{environment.name}")
+ expect(page).not_to have_css('.js-deploy-time')
+ end
end
- end
- context 'when deployment running' do
- let(:build) { create(:ci_build, :running, pipeline: pipeline) }
- let!(:deployment) { create(:deployment, :running, environment: environment, sha: sha, ref: ref, deployable: build) }
+ context 'when deployment will happen' do
+ let(:build) { create(:ci_build, :created, pipeline: pipeline) }
+ let!(:deployment) { create(:deployment, environment: environment, sha: sha, ref: ref, deployable: build) }
- it 'displays that the running deployment' do
- visit project_merge_request_path(project, merge_request)
- wait_for_requests
+ it 'displays that the environment name' do
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
- expect(page).to have_content("Deploying to #{environment.name}")
- expect(page).not_to have_css('.js-deploy-time')
+ expect(page).to have_content("Deploying to #{environment.name}")
+ expect(page).not_to have_css('.js-deploy-time')
+ end
end
end
- context 'when deployment will happen' do
- let(:build) { create(:ci_build, :created, pipeline: pipeline) }
- let!(:deployment) { create(:deployment, environment: environment, sha: sha, ref: ref, deployable: build) }
+ context 'when deployment is to stop an environment' do
+ context 'when the stop action succeeded' do
+ let(:build) { create(:ci_build, :success, pipeline: pipeline) }
+ let!(:deployment) { create(:deployment, :succeed, :stop, environment: environment, sha: sha, ref: ref, deployable: build) }
- it 'displays that the environment name' do
- visit project_merge_request_path(project, merge_request)
- wait_for_requests
+ it 'does not display deployment info' do
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
+
+ expect(page).not_to have_css('.deployment-info')
+ end
+ end
+
+ context 'when the stop action failed' do
+ let(:build) { create(:ci_build, :failed, pipeline: pipeline) }
+ let!(:deployment) { create(:deployment, :failed, :stop, environment: environment, sha: sha, ref: ref, deployable: build) }
+
+ it 'does not display deployment info' do
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
+
+ expect(page).not_to have_css('.deployment-info')
+ end
+ end
+
+ context 'when the stop action is running' do
+ let(:build) { create(:ci_build, :running, pipeline: pipeline) }
+ let!(:deployment) { create(:deployment, :running, :stop, environment: environment, sha: sha, ref: ref, deployable: build) }
+
+ it 'does not display deployment info' do
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
- expect(page).to have_content("Deploying to #{environment.name}")
- expect(page).not_to have_css('.js-deploy-time')
+ expect(page).not_to have_css('.deployment-info')
+ end
+ end
+
+ context 'when the stop action will happen' do
+ let(:build) { create(:ci_build, :created, pipeline: pipeline) }
+ let!(:deployment) { create(:deployment, :stop, environment: environment, sha: sha, ref: ref, deployable: build) }
+
+ it 'does not display deployment info' do
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
+
+ expect(page).not_to have_css('.deployment-info')
+ end
end
end
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index 0d82df6dc8e..d12fe24714b 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -82,6 +82,19 @@ describe 'Environment' do
end
end
+ context 'when there is a successful stop action' do
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:build) { create(:ci_build, :success, pipeline: pipeline) }
+
+ let(:deployment) do
+ create(:deployment, :success, :stop, environment: environment, deployable: build)
+ end
+
+ it 'does show no deployments' do
+ expect(page).to have_content('You don\'t have any deployments right now.')
+ end
+ end
+
context 'with related deployable present' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 89954d35f91..b3eabcb7903 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -344,6 +344,23 @@ describe 'Environments page', :js do
expect(page).to have_content('No deployments yet')
end
end
+
+ context 'when there is a successful stop action' do
+ let(:project) { create(:project, :repository) }
+
+ let!(:deployment) do
+ create(:deployment, :success,
+ :stop,
+ environment: environment,
+ sha: project.commit.id)
+ end
+
+ it 'does not show deployments' do
+ visit_environments(project)
+
+ expect(page).to have_content('No deployments yet')
+ end
+ end
end
it 'does have a new environment button' do
diff --git a/spec/models/concerns/deployable_spec.rb b/spec/models/concerns/deployable_spec.rb
index ac79c75a55e..9551ff4b13b 100644
--- a/spec/models/concerns/deployable_spec.rb
+++ b/spec/models/concerns/deployable_spec.rb
@@ -22,13 +22,17 @@ describe Deployable do
expect(deployment.on_stop).to eq('stop_review_app')
expect(environment.name).to eq('review/master')
end
+
+ it 'updates action column to start' do
+ expect(deployment).to be_start
+ end
end
- context 'when the deployable object will stop an environment' do
+ context 'when the deployable object will stop the review app' do
let!(:job) { create(:ci_build, :stop_review_app) }
- it 'does not create a deployment record' do
- expect(deployment).to be_nil
+ it 'updates action column to stop' do
+ expect(deployment).to be_stop
end
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index 270b2767c68..b5696c73339 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -191,6 +191,150 @@ describe Deployment do
end
end
+ describe '.deployed' do
+ subject { described_class.deployed }
+
+ context 'when deployment starts an environment' do
+ context 'when the action was successful' do
+ let!(:deployment) { create(:deployment, :start, :success) }
+
+ it 'returns the deployment' do
+ is_expected.to eq([deployment])
+ end
+ end
+
+ context 'when the action failed' do
+ let!(:deployment) { create(:deployment, :start, :failed) }
+
+ it 'returns nothing' do
+ is_expected.to be_empty
+ end
+ end
+ end
+
+ context 'when deployment stops an environment' do
+ context 'when the action was successful' do
+ let!(:deployment) { create(:deployment, :stop, :success) }
+
+ it 'returns nothing' do
+ is_expected.to be_empty
+ end
+ end
+
+ context 'when the action failed' do
+ let!(:deployment) { create(:deployment, :stop, :failed) }
+
+ it 'returns nothing' do
+ is_expected.to be_empty
+ end
+ end
+ end
+ end
+
+ describe '.stopped' do
+ subject { described_class.stopped }
+
+ context 'when deployment starts an environment' do
+ context 'when the action was successful' do
+ let!(:deployment) { create(:deployment, :start, :success) }
+
+ it 'returns nothing' do
+ is_expected.to be_empty
+ end
+ end
+
+ context 'when the action failed' do
+ let!(:deployment) { create(:deployment, :start, :failed) }
+
+ it 'returns nothing' do
+ is_expected.to be_empty
+ end
+ end
+ end
+
+ context 'when deployment stops an environment' do
+ context 'when the action was successful' do
+ let!(:deployment) { create(:deployment, :stop, :success) }
+
+ it 'returns the deployment' do
+ is_expected.to eq([deployment])
+ end
+ end
+
+ context 'when the action failed' do
+ let!(:deployment) { create(:deployment, :stop, :failed) }
+
+ it 'returns nothing' do
+ is_expected.to be_empty
+ end
+ end
+ end
+ end
+
+ describe '#deployed?' do
+ subject { deployment.deployed? }
+
+ context 'when deployment starts an environment' do
+ context 'when the action was successful' do
+ let!(:deployment) { create(:deployment, :start, :success) }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the action failed' do
+ let!(:deployment) { create(:deployment, :start, :failed) }
+
+ it { is_expected.to be_falsy }
+ end
+ end
+
+ context 'when deployment stops an environment' do
+ context 'when the action was successful' do
+ let!(:deployment) { create(:deployment, :stop, :success) }
+
+ it { is_expected.to be_falsy }
+ end
+
+ context 'when the action failed' do
+ let!(:deployment) { create(:deployment, :stop, :failed) }
+
+ it { is_expected.to be_falsy }
+ end
+ end
+ end
+
+ describe '#stopped?' do
+ subject { deployment.stopped? }
+
+ context 'when deployment starts an environment' do
+ context 'when the action was successful' do
+ let!(:deployment) { create(:deployment, :start, :success) }
+
+ it { is_expected.to be_falsy }
+ end
+
+ context 'when the action failed' do
+ let!(:deployment) { create(:deployment, :start, :failed) }
+
+ it { is_expected.to be_falsy }
+ end
+ end
+
+ context 'when deployment stops an environment' do
+ context 'when the action was successful' do
+ let!(:deployment) { create(:deployment, :stop, :success) }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the action failed' do
+ let!(:deployment) { create(:deployment, :stop, :failed) }
+
+ it { is_expected.to be_falsy }
+ end
+ end
+ end
+
describe '#deployed_at' do
subject { deployment.deployed_at }
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index ac814c85c3c..55ec1bc9e90 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -59,14 +59,22 @@ describe Environment do
let(:environment) { create(:environment) }
let(:sha) { RepoHelpers.sample_commit.id }
- context 'when deployment has the specified sha' do
- let!(:deployment) { create(:deployment, environment: environment, sha: sha) }
+ context 'when deployment starts environment' do
+ context 'when deployment has the specified sha' do
+ let!(:deployment) { create(:deployment, :start, environment: environment, sha: sha) }
- it { is_expected.to eq([environment]) }
+ it { is_expected.to eq([environment]) }
+ end
+
+ context 'when deployment does not have the specified sha' do
+ let!(:deployment) { create(:deployment, :start, environment: environment, sha: 'abc') }
+
+ it { is_expected.to be_empty }
+ end
end
- context 'when deployment does not have the specified sha' do
- let!(:deployment) { create(:deployment, environment: environment, sha: 'abc') }
+ context 'when deployment stops environment' do
+ let!(:deployment) { create(:deployment, :stop, environment: environment) }
it { is_expected.to be_empty }
end
@@ -77,20 +85,28 @@ describe Environment do
let(:environment) { create(:environment) }
- context 'when the latest deployment is successful' do
- let!(:deployment) { create(:deployment, :success, environment: environment) }
+ context 'when the latest deployment is for starting an environment' do
+ context 'when the latest deployment is successful' do
+ let!(:deployment) { create(:deployment, :start, :success, environment: environment) }
- it { expect(subject).to be_within(1.second).of(deployment.finished_at) }
- end
+ it { expect(subject).to be_within(1.second).of(deployment.finished_at) }
+ end
- context 'when the latest deployment failed' do
- let!(:deployment) { create(:deployment, :failed, environment: environment) }
+ context 'when the latest deployment failed' do
+ let!(:deployment) { create(:deployment, :start, :failed, environment: environment) }
- it { is_expected.to be_nil }
+ it { is_expected.to be_nil }
+ end
+
+ context 'when the latest deployment is running' do
+ let!(:deployment) { create(:deployment, :start, :running, environment: environment) }
+
+ it { is_expected.to be_nil }
+ end
end
- context 'when the latest deployment is running' do
- let!(:deployment) { create(:deployment, :running, environment: environment) }
+ context 'when the latest deployment is for stopping environment' do
+ let!(:deployment) { create(:deployment, :stop, :success, environment: environment) }
it { is_expected.to be_nil }
end
diff --git a/spec/models/environment_status_spec.rb b/spec/models/environment_status_spec.rb
index 9fc8c5c6357..a88c6203b52 100644
--- a/spec/models/environment_status_spec.rb
+++ b/spec/models/environment_status_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe EnvironmentStatus do
include ProjectForksHelper
- let(:deployment) { create(:deployment, :succeed, :review_app) }
+ let(:deployment) { create(:deployment, :succeed, :start, :review_app) }
let(:environment) { deployment.environment }
let(:project) { deployment.project }
let(:merge_request) { create(:merge_request, :deployed_review_app, deployment: deployment) }
diff --git a/spec/services/update_deployment_service_spec.rb b/spec/services/start_environment_service_spec.rb
index 3c55dd9659a..105d69c6b8e 100644
--- a/spec/services/update_deployment_service_spec.rb
+++ b/spec/services/start_environment_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe UpdateDeploymentService do
+describe StartEnvironmentService do
let(:user) { create(:user) }
let(:options) { { name: 'production' } }
@@ -84,8 +84,8 @@ describe UpdateDeploymentService do
it 'updates external url' do
subject
- expect(subject.environment.name).to eq('review-apps/master')
- expect(subject.environment.external_url).to eq('http://master.review-apps.gitlab.com')
+ expect(environment.reload.name).to eq('review-apps/master')
+ expect(environment.reload.external_url).to eq('http://master.review-apps.gitlab.com')
end
end
end
diff --git a/spec/services/stop_environment_service_spec.rb b/spec/services/stop_environment_service_spec.rb
new file mode 100644
index 00000000000..c41e010d717
--- /dev/null
+++ b/spec/services/stop_environment_service_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe StopEnvironmentService do
+ let(:service) { described_class.new(deployment) }
+
+ describe '#execute' do
+ subject { service.execute }
+
+ context 'when environment is available' do
+ let(:environment) { create(:environment, state: :available) }
+
+ context 'when deployment was successful' do
+ let(:deployment) { create(:deployment, :success, :stop, environment: environment) }
+
+ it 'stops the environment' do
+ subject
+
+ expect(environment.reload).to be_stopped
+ end
+ end
+
+ context 'when deployment failed' do
+ let(:deployment) { create(:deployment, :failed, :stop, environment: environment) }
+
+ it 'does not stop the environment' do
+ subject
+
+ expect(environment.reload).to be_available
+ end
+ end
+ end
+
+ context 'when environment is stopped' do
+ let(:deployment) { create(:deployment, :success, :stop, environment: environment) }
+ let(:environment) { create(:environment, state: :stopped) }
+
+ it 'does not raise an error' do
+ expect { subject }.not_to raise_error
+ expect(environment.reload).to be_stopped
+ end
+ end
+ end
+end
diff --git a/spec/workers/build_success_worker_spec.rb b/spec/workers/build_success_worker_spec.rb
index 5eb9709ded9..8e9b178728e 100644
--- a/spec/workers/build_success_worker_spec.rb
+++ b/spec/workers/build_success_worker_spec.rb
@@ -47,19 +47,6 @@ describe BuildSuccessWorker do
expect(build.reload).not_to be_has_deployment
end
end
-
- context 'when the build will stop an environment' do
- let!(:build) { create(:ci_build, :stop_review_app, environment: environment.name, project: environment.project) }
- let(:environment) { create(:environment, state: :available) }
-
- it 'stops the environment' do
- expect(environment).to be_available
-
- subject
-
- expect(environment.reload).to be_stopped
- end
- end
end
context 'when build does not exist' do
diff --git a/spec/workers/deployments/success_worker_spec.rb b/spec/workers/deployments/success_worker_spec.rb
index ba7d45eca01..57aaa929a37 100644
--- a/spec/workers/deployments/success_worker_spec.rb
+++ b/spec/workers/deployments/success_worker_spec.rb
@@ -3,34 +3,51 @@ require 'spec_helper'
describe Deployments::SuccessWorker do
subject { described_class.new.perform(deployment&.id) }
- context 'when successful deployment' do
- let(:deployment) { create(:deployment, :success) }
+ context 'when deployment starts environment' do
+ context 'when deployment was successful' do
+ let(:deployment) { create(:deployment, :start, :success) }
- it 'executes UpdateDeploymentService' do
- expect(UpdateDeploymentService)
- .to receive(:new).with(deployment).and_call_original
+ it 'executes StartEnvironmentService' do
+ expect(StartEnvironmentService)
+ .to receive(:new).with(deployment).and_call_original
- subject
+ subject
+ end
end
- end
- context 'when canceled deployment' do
- let(:deployment) { create(:deployment, :canceled) }
+ context 'when deployment failed' do
+ let(:deployment) { create(:deployment, :start, :failed) }
- it 'does not execute UpdateDeploymentService' do
- expect(UpdateDeploymentService).not_to receive(:new)
+ it 'does not execute StartEnvironmentService' do
+ expect(StartEnvironmentService)
+ .not_to receive(:new).with(deployment).and_call_original
- subject
+ subject
+ end
end
end
- context 'when deploy record does not exist' do
- let(:deployment) { nil }
+ context 'when deployment stops environment' do
+ context 'when deployment was successful' do
+ let(:deployment) { create(:deployment, :stop, :success) }
+
+ it 'executes StopEnvironmentService' do
+ expect(StopEnvironmentService)
+ .to receive(:new).with(deployment).and_call_original
+
+ subject
+ end
+ end
+
+ context 'when deployment failed' do
+ let(:deployment) { create(:deployment, :stop, :failed) }
- it 'does not execute UpdateDeploymentService' do
- expect(UpdateDeploymentService).not_to receive(:new)
+ it 'does not execute StopEnvironmentService' do
+ expect(StopEnvironmentService)
+ .not_to receive(:new).with(deployment).and_call_original
- subject
+ subject
+ end
end
end
end