Skip to content

Commit

Permalink
[#225] Add statuses for build actions. Clean up instance statuses
Browse files Browse the repository at this point in the history
  • Loading branch information
evheny0 committed May 4, 2020
1 parent 4db9e43 commit 8a22e53
Show file tree
Hide file tree
Showing 20 changed files with 194 additions and 72 deletions.
10 changes: 10 additions & 0 deletions app/constants/build_action_constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ module BuildActionConstants

NEW_INSTANCE_ACTIONS = [CREATE_INSTANCE, RECREATE_INSTANCE].freeze

module Statuses
ALL = [
SCHEDULED = "scheduled",
RUNNING = "running",
SUCCESS = "success",
FAILURE = "failure",
CANCELED = "canceled"
].freeze
end

module Log
STATUSES = [
INFO = "info",
Expand Down
40 changes: 17 additions & 23 deletions app/constants/project_instance_constants.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
# frozen_string_literal: true

module ProjectInstanceConstants
DEPLOYMENT_STATUSES = [
EMPTY_RECORD_FOR_PR = "empty_record_for_pr",
SCHEDULED = "scheduled",
DEPLOYING = "deploying",
UPDATING = "updating",
RUNNING = "running",
FAILURE = "failure",
NOT_DEPLOYED = "not_deployed",
DESTROYING = "destroying_instances",
DESTROYED = "instances_destroyed",
CLOSED = "closed",
CLOSED_NEVER_CREATED = "closed_and_never_created"
].freeze
module Statuses
ALL = [
SCHEDULED = "scheduled",
CREATING = "creating",
RUNNING = "running",

ACTION_STATUSES = {
BuildActionConstants::CREATE_INSTANCE.to_s => { start: DEPLOYING, success: RUNNING, failure: NOT_DEPLOYED },
BuildActionConstants::RECREATE_INSTANCE.to_s => { start: DEPLOYING, success: RUNNING, failure: NOT_DEPLOYED },
BuildActionConstants::UPDATE_INSTANCE.to_s => { start: UPDATING, success: RUNNING, failure: FAILURE },
BuildActionConstants::RELOAD_INSTANCE.to_s => { start: UPDATING, success: RUNNING, failure: RUNNING },
BuildActionConstants::DESTROY_INSTANCE.to_s => { start: DESTROYING, success: DESTROYED, failure: FAILURE }
}.freeze
TERMINATED = "terminated",
FAILED_TO_CREATE = "failed_to_create",

ACTIVE_INSTANCES = [RUNNING, FAILURE, DEPLOYING, UPDATING].freeze
NOT_DEPLOYED_INSTANCES = [EMPTY_RECORD_FOR_PR, NOT_DEPLOYED, DESTROYED, CLOSED, CLOSED_NEVER_CREATED].freeze
HIDDEN_INSTANCES = [EMPTY_RECORD_FOR_PR, CLOSED_NEVER_CREATED].freeze
PULL_REQUEST = "pull_request",
PULL_REQUEST_CLOSED = "pull_request_closed",

STOPPED = "stopped"
].freeze

ALL_ACTIVE = [RUNNING, CREATING].freeze
ALL_NOT_ACTIVE = [TERMINATED, FAILED_TO_CREATE, PULL_REQUEST, PULL_REQUEST_CLOSED].freeze
ALL_HIDDEN = [PULL_REQUEST, PULL_REQUEST_CLOSED].freeze
end
end
2 changes: 1 addition & 1 deletion app/controllers/project_instances_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
class ProjectInstancesController < ApplicationController
def index
@project = find_project
hidden_statuses = params[:show_all] ? ProjectInstanceConstants::HIDDEN_INSTANCES : ProjectInstanceConstants::NOT_DEPLOYED_INSTANCES
hidden_statuses = params[:show_all] ? ProjectInstanceConstants::Statuses::ALL_HIDDEN : ProjectInstanceConstants::Statuses::ALL_NOT_ACTIVE
@project_instances = @project.project_record.project_instances.where.not(deployment_status: hidden_statuses).order(created_at: :desc)
@new_instance_allowed = ProjectPolicy.new(current_user, @project).create_instance?
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/projects_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def find_project
end

def find_projects
statuses = ProjectInstanceConstants::ACTIVE_INSTANCES.map { |status| ProjectInstance.deployment_statuses[status] }.join(", ")
statuses = ProjectInstanceConstants::Statuses::ALL_ACTIVE.map { |status| ProjectInstance.deployment_statuses[status] }.join(", ")

Project
.select("projects.*, COUNT(project_instances) as active_instances")
Expand Down
7 changes: 5 additions & 2 deletions app/domains/project_instance_domain.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,20 @@ def last_action_record
@last_action_record ||= @project_instance_record.build_actions.order(:created_at).last
end

def action_status
last_action_record.status
end

def create_action!(author:, action:, configurations_to_update: nil, docker_deploy_lambda: nil)
previous_action = last_action_record
@last_action_record = BuildAction.create!(project_instance: @project_instance_record, author: author, action: action, configurations: [])
@last_action_record = BuildAction.create!(project_instance: @project_instance_record, author: author, action: action, configurations: [], status: BuildActionConstants::Statuses::SCHEDULED)
@deployment_configurations = if BuildActionConstants::NEW_INSTANCE_ACTIONS.include?(action)
create_configurations(author, @last_action_record.id, docker_deploy_lambda)
else
duplicate_configurations(previous_action, configurations_to_update, @last_action_record)
end

@last_action_record.update!(configurations: @deployment_configurations.map(&:to_project_instance_configuration))
update_status!(ProjectInstanceConstants::SCHEDULED)
@last_action_record
end

Expand Down
24 changes: 16 additions & 8 deletions app/helpers/project_instance_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

module ProjectInstanceHelper
STATUS_BADGE_CLASS_MAPPING = {
ProjectInstanceConstants::UPDATING => "badge-warning",
ProjectInstanceConstants::DEPLOYING => "badge-warning",
ProjectInstanceConstants::RUNNING => "badge-success",
ProjectInstanceConstants::FAILURE => "badge-danger",
ProjectInstanceConstants::NOT_DEPLOYED => "badge-danger",
ProjectInstanceConstants::DESTROYING => "badge-secondary",
ProjectInstanceConstants::DESTROYED => "badge-dark",
ProjectInstanceConstants::CLOSED => "badge-dark"
ProjectInstanceConstants::Statuses::CREATING => "badge-warning",
ProjectInstanceConstants::Statuses::RUNNING => "badge-success",
ProjectInstanceConstants::Statuses::FAILED_TO_CREATE => "badge-danger",
ProjectInstanceConstants::Statuses::TERMINATED => "badge-dark",
ProjectInstanceConstants::Statuses::PULL_REQUEST_CLOSED => "badge-dark"
}.freeze

ACTION_STATUS_BADGE_CLASS_MAPPING = {
BuildActionConstants::Statuses::RUNNING => "badge-warning",
BuildActionConstants::Statuses::SUCCESS => "badge-success",
BuildActionConstants::Statuses::FAILURE => "badge-danger",
BuildActionConstants::Statuses::CANCELED => "badge-dark"
}.freeze

def status_badge_class(status)
STATUS_BADGE_CLASS_MAPPING.fetch(status, "badge-info")
end

def action_status_badge_class(status)
ACTION_STATUS_BADGE_CLASS_MAPPING.fetch(status, "badge-info")
end
end
1 change: 1 addition & 0 deletions app/models/build_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class BuildAction < ApplicationRecord
validates :action, presence: true

enum action: BuildActionConstants::ACTIONS
enum status: BuildActionConstants::Statuses::ALL

attribute :configurations, JSONModels::ProjectInstanceConfiguration.to_array_type
end
2 changes: 1 addition & 1 deletion app/models/project_instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class ProjectInstance < ApplicationRecord
validates :configurations, store_model: true
validates :name, uniqueness: { scope: :project_id }

enum deployment_status: ProjectInstanceConstants::DEPLOYMENT_STATUSES
enum deployment_status: ProjectInstanceConstants::Statuses::ALL

attribute :configurations, JSONModels::ProjectInstanceConfiguration.to_array_type
end
3 changes: 1 addition & 2 deletions app/policies/project_instance_message_policy.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# frozen_string_literal: true

class ProjectInstanceMessagePolicy < ApplicationPolicy
SLACK_EVENTS = [ProjectInstanceConstants::RUNNING, ProjectInstanceConstants::FAILURE].freeze
COMMENTABLE_PROVIDERS = [ProjectsConstants::Providers::GITHUB, ProjectsConstants::Providers::GITLAB].freeze

def slack?
Expand All @@ -18,7 +17,7 @@ def pull_request_comments?
private

def slack_event_enabled?
SLACK_EVENTS.include? record.deployment_status
record.deployment_status == ProjectInstanceConstants::Statuses::RUNNING
end

def project
Expand Down
27 changes: 18 additions & 9 deletions app/policies/project_instance_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,49 @@

class ProjectInstancePolicy < ApplicationPolicy
def dumps?
return false if Features::Accessor.new.docker_deploy_performed?(record)
false
# Dumps aren't working for heroku right now :(

record.deployment_status.in?([ProjectInstanceConstants::RUNNING, ProjectInstanceConstants::UPDATING, ProjectInstanceConstants::FAILURE])
# return false if Features::Accessor.new.docker_deploy_performed?(record)

# record.deployment_status.in?([ProjectInstanceConstants::Statuses::RUNNING])
end

def addons?
record.deployment_status.in?([ProjectInstanceConstants::RUNNING, ProjectInstanceConstants::UPDATING, ProjectInstanceConstants::FAILURE])
record.deployment_status.in?([ProjectInstanceConstants::Statuses::RUNNING])
end

def reload?
record.deployment_status.in?([ProjectInstanceConstants::RUNNING, ProjectInstanceConstants::FAILURE])
record.deployment_status == ProjectInstanceConstants::Statuses::RUNNING && no_active_actions
end

def update_server?
record.deployment_status.in?([ProjectInstanceConstants::RUNNING, ProjectInstanceConstants::FAILURE])
record.deployment_status == ProjectInstanceConstants::Statuses::RUNNING && no_active_actions
end

def terminate?
record.deployment_status.in?([ProjectInstanceConstants::RUNNING, ProjectInstanceConstants::UPDATING, ProjectInstanceConstants::FAILURE])
record.deployment_status == ProjectInstanceConstants::Statuses::RUNNING
end

def edit?
record.deployment_status.in?([ProjectInstanceConstants::RUNNING, ProjectInstanceConstants::FAILURE, ProjectInstanceConstants::NOT_DEPLOYED])
record.deployment_status.in?([ProjectInstanceConstants::Statuses::RUNNING, ProjectInstanceConstants::Statuses::FAILED_TO_CREATE]) && no_active_actions
end

def redeploy?
record.deployment_status.in?([ProjectInstanceConstants::NOT_DEPLOYED])
record.deployment_status == ProjectInstanceConstants::Statuses::FAILED_TO_CREATE
end

def deploy_by_link?
record.deployment_status == ProjectInstanceConstants::EMPTY_RECORD_FOR_PR
record.deployment_status == ProjectInstanceConstants::Statuses::PULL_REQUEST
end

def show_heroku_link?
user.system_role == UserConstants::SystemRoles::ADMIN
end

private

def no_active_actions
record.action_status != BuildActionConstants::Statuses::RUNNING
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def call(project_instance_name:, branches:, attached_repo_path:, attached_pull_r
ProjectInstanceDomain.create(
project_id: @project.id,
name: project_instance_name,
deployment_status: ProjectInstanceConstants::EMPTY_RECORD_FOR_PR,
deployment_status: ProjectInstanceConstants::Statuses::PULL_REQUEST,
attached_pull_request: { repo: attached_repo_path, number: attached_pull_request_number },
branches: branches
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def create_project_instance(project_instance_name, branches)
ProjectInstanceDomain.create(
project_id: @project.id,
name: project_instance_name,
deployment_status: ProjectInstanceConstants::SCHEDULED,
deployment_status: ProjectInstanceConstants::Statuses::SCHEDULED,
branches: branches
)
end
Expand Down
14 changes: 10 additions & 4 deletions app/services/deployment/processes/destroy_project_instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def initialize(project_instance, user_reference)

def call
return if instance_destroyed?
return update_status if @project_instance.deployment_status.in?(ProjectInstanceConstants::NOT_DEPLOYED_INSTANCES)
return update_status if @project_instance.deployment_status.in?(ProjectInstanceConstants::Statuses::ALL_NOT_ACTIVE)

build_action = @project_instance.create_action!(author: @user_reference, action: BuildActionConstants::DESTROY_INSTANCE)

Expand All @@ -24,17 +24,23 @@ def call
private

def instance_destroyed?
@project_instance.deployment_status.in?([ProjectInstanceConstants::DESTROYED, ProjectInstanceConstants::CLOSED, ProjectInstanceConstants::CLOSED_NEVER_CREATED])
@project_instance.deployment_status.in?(
[
ProjectInstanceConstants::Statuses::TERMINATED,
ProjectInstanceConstants::Statuses::PULL_REQUEST_CLOSED,
ProjectInstanceConstants::Statuses::FAILED_TO_CREATE
]
)
end

def update_status
@project_instance.update_status!(closed_status)
end

def closed_status
return ProjectInstanceConstants::CLOSED_NEVER_CREATED if @project_instance.deployment_status == ProjectInstanceConstants::EMPTY_RECORD_FOR_PR
return ProjectInstanceConstants::Statuses::PULL_REQUEST_CLOSED if @project_instance.deployment_status == ProjectInstanceConstants::Statuses::PULL_REQUEST

ProjectInstanceConstants::CLOSED
ProjectInstanceConstants::Statuses::TERMINATED
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def initialize(project_instance, user_reference)

def call
return unless @project_instance.present?
return unless @project_instance.deployment_status.in?(ProjectInstanceConstants::ACTIVE_INSTANCES)
return unless @project_instance.deployment_status.in?(ProjectInstanceConstants::Statuses::ALL_ACTIVE)

build_action = @project_instance.create_action!(author: @user_reference, action: BuildActionConstants::UPDATE_INSTANCE)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@ module Deployment
module Processes
class UpdateProjectInstanceConfiguration
DEPLOYMENT_ACTION_MAPPING = {
ProjectInstanceConstants::NOT_DEPLOYED => {
ProjectInstanceConstants::Statuses::FAILED_TO_CREATE => {
action: BuildActionConstants::RECREATE_INSTANCE,
worker_class: Deployment::ServerActions::Recreate
},
ProjectInstanceConstants::RUNNING => {
action: BuildActionConstants::RELOAD_INSTANCE,
worker_class: Deployment::ServerActions::Restart
},
ProjectInstanceConstants::FAILURE => {
ProjectInstanceConstants::Statuses::RUNNING => {
action: BuildActionConstants::RELOAD_INSTANCE,
worker_class: Deployment::ServerActions::Restart
}
Expand Down
68 changes: 57 additions & 11 deletions app/services/deployment/project_instance_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,75 @@
module Deployment
class ProjectInstanceEvents
COMMENT_MESSAGES = {
ProjectInstanceConstants::DEPLOYING => ->(_comment) { "Deploying..." },
ProjectInstanceConstants::UPDATING => ->(_comment) { "Updating..." },
ProjectInstanceConstants::RUNNING => ->(comment) { comment.deployed },
ProjectInstanceConstants::FAILURE => ->(comment) { comment.failed },
ProjectInstanceConstants::NOT_DEPLOYED => ->(_comment) { "Not deployed" },
ProjectInstanceConstants::DESTROYING => ->(_comment) { "Destroying..." },
ProjectInstanceConstants::DESTROYED => ->(_comment) { "Application has been destroyed" }
deploying: ->(_comment) { "Deploying..." },
updating: ->(_comment) { "Updating..." },
running: ->(comment) { comment.deployed },
failure: ->(comment) { comment.failed },
not_deployed: ->(_comment) { "Not deployed" },
destroying: ->(_comment) { "Destroying..." },
destroyed: ->(_comment) { "Application has been destroyed" }
}.freeze

COMMENT_TYPES = {
BuildActionConstants::CREATE_INSTANCE.to_s => { start: :deploying, success: :running, failure: :not_deployed },
BuildActionConstants::RECREATE_INSTANCE.to_s => { start: :deploying, success: :running, failure: :not_deployed },
BuildActionConstants::UPDATE_INSTANCE.to_s => { start: :updating, success: :running, failure: :failure },
BuildActionConstants::RELOAD_INSTANCE.to_s => { start: :updating, success: :running, failure: :running },
BuildActionConstants::DESTROY_INSTANCE.to_s => { start: :destroying, success: :destroyed, failure: :failure }
}.freeze

INSTANCE_STATUSES = {
BuildActionConstants::CREATE_INSTANCE.to_s => {
start: ProjectInstanceConstants::Statuses::CREATING, success: ProjectInstanceConstants::Statuses::RUNNING, failure: ProjectInstanceConstants::Statuses::FAILED_TO_CREATE
},
BuildActionConstants::RECREATE_INSTANCE.to_s => {
start: ProjectInstanceConstants::Statuses::CREATING, success: ProjectInstanceConstants::Statuses::RUNNING, failure: ProjectInstanceConstants::Statuses::FAILED_TO_CREATE
},
BuildActionConstants::UPDATE_INSTANCE.to_s => {
start: :no_change, success: ProjectInstanceConstants::Statuses::RUNNING, failure: :no_change
},
BuildActionConstants::RELOAD_INSTANCE.to_s => {
start: :no_change, success: ProjectInstanceConstants::Statuses::RUNNING, failure: :no_change
},
BuildActionConstants::DESTROY_INSTANCE.to_s => {
start: :no_change, success: ProjectInstanceConstants::Statuses::TERMINATED, failure: ProjectInstanceConstants::Statuses::RUNNING
}
}.freeze

BUILD_ACTION_STATUSES = {
start: BuildActionConstants::Statuses::RUNNING,
success: BuildActionConstants::Statuses::SUCCESS,
failure: BuildActionConstants::Statuses::FAILURE
}.freeze

def initialize(build_action)
@build_action = build_action
@project_instance = build_action.project_instance
@statuses = ProjectInstanceConstants::ACTION_STATUSES.fetch(build_action.action)
@comment_types = COMMENT_TYPES.fetch(build_action.action)
@instance_statuses = INSTANCE_STATUSES.fetch(build_action.action)
@message_policy = ProjectInstanceMessagePolicy.new(nil, @project_instance)
end

def create_event(event)
status = @statuses.fetch(event.to_sym)
update_status!(event.to_sym)

comment_type = @comment_types.fetch(event.to_sym)
comment = Notifications::Comment.new(@project_instance)
text = COMMENT_MESSAGES.fetch(status).call(comment)
text = COMMENT_MESSAGES.fetch(comment_type).call(comment)

@project_instance.update!(deployment_status: status)
Deployment::PullRequestNotificator.new(@project_instance).call(text) if @message_policy.pull_request_comments?
Slack::Notificator.new(@project_instance).send_message(text) if @message_policy.slack?
end

private

def update_status!(event)
@build_action.update!(status: BUILD_ACTION_STATUSES.fetch(event))

instance_status = @instance_statuses.fetch(event)
return if instance_status == :no_change

ProjectInstanceDomain.new(record: @project_instance).update_status!(instance_status)
end
end
end
Loading

0 comments on commit 8a22e53

Please sign in to comment.