Skip to content

Commit

Permalink
feat: support deployments and releases as separate concepts (#426)
Browse files Browse the repository at this point in the history
Also allow multiple versions of an application to be deployed to the same environment, differentiated by a "target".
  • Loading branch information
bethesque authored May 10, 2021
1 parent a33792b commit 58d173d
Show file tree
Hide file tree
Showing 31 changed files with 766 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Sequel.migration do
change do
create_table(:currently_deployed_version_ids, charset: 'utf8') do
primary_key :id
String :target_for_index, null: false
foreign_key :pacticipant_id, :pacticipants, null: false, on_delete: :cascade
foreign_key :environment_id, :environments, null: false, on_delete: :cascade
foreign_key :version_id, :versions, null: false, on_delete: :cascade
foreign_key :deployed_version_id, null: false, on_delete: :cascade
index [:pacticipant_id, :environment_id, :target_for_index], unique: true, name: "currently_deployed_version_pacticipant_environment_target_index"
end
end
end
21 changes: 21 additions & 0 deletions db/migrations/20210415_add_target_column_to_deployed_version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Sequel.migration do
up do
alter_table(:deployed_versions) do
add_column(:target, String)
add_column(:target_for_index, String, default: "", null: false)
set_column_allow_null(:replaced_previous_deployed_version)
set_column_allow_null(:currently_deployed)
drop_index [:pacticipant_id, :currently_deployed], name: "deployed_versions_pacticipant_id_currently_deployed_index"
end
end

down do
alter_table(:deployed_versions) do
drop_column(:target)
drop_column(:target_for_index)
set_column_not_null(:replaced_previous_deployed_version)
set_column_not_null(:currently_deployed)
add_index [:pacticipant_id, :currently_deployed], name: "deployed_versions_pacticipant_id_currently_deployed_index"
end
end
end
17 changes: 17 additions & 0 deletions db/migrations/20210419_create_released_versions_table.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Sequel.migration do
change do
create_table(:released_versions, charset: 'utf8') do
primary_key :id
String :uuid, null: false
foreign_key :version_id, :versions, null: false
Integer :pacticipant_id, null: false
foreign_key :environment_id, :environments, null: false
DateTime :created_at
DateTime :updated_at
DateTime :support_ended_at
index [:uuid], unique: true, name: "released_versions_uuid_index"
index [:version_id, :environment_id], unique: true, name: "released_versions_version_id_environment_id_index"
index [:support_ended_at], name: "released_version_support_ended_at_index"
end
end
end
2 changes: 2 additions & 0 deletions lib/pact_broker/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ def self.build_api(application_context = PactBroker::ApplicationContext.default_
add ['environments'], Api::Resources::Environments, { resource_name: "environments" }
add ['environments', :environment_uuid], Api::Resources::Environment, { resource_name: "environment" }
add ['pacticipants', :pacticipant_name, 'versions', :pacticipant_version_number, 'deployed-versions', 'environment', :environment_uuid], Api::Resources::DeployedVersionsForVersionAndEnvironment, { resource_name: "deployed_versions_for_version_and_environment" }
add ['pacticipants', :pacticipant_name, 'versions', :pacticipant_version_number, 'released-versions', 'environment', :environment_uuid], Api::Resources::ReleasedVersionsForVersionAndEnvironment, { resource_name: "released_versions_for_version_and_environment" }
add ['released-versions', :uuid], Api::Resources::ReleasedVersion, { resource_name: "released_version" }
end

add ['integrations'], Api::Resources::Integrations, {resource_name: "integrations"}
Expand Down
3 changes: 2 additions & 1 deletion lib/pact_broker/api/decorators/deployed_version_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ module PactBroker
module Api
module Decorators
class DeployedVersionDecorator < BaseDecorator
property :uuid
property :version, :extend => EmbeddedVersionDecorator, writeable: false, embedded: true
property :environment, :extend => EnvironmentDecorator, writeable: false, embedded: true
property :currently_deployed, camelize: true
property :replaced_previous_deployed_version, camelize: true
property :target, camelize: true
include Timestamps
property :undeployedAt, getter: lambda { |_| undeployed_at ? FormatDateTime.call(undeployed_at) : nil }, writeable: false
end
Expand Down
14 changes: 14 additions & 0 deletions lib/pact_broker/api/decorators/released_version_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'pact_broker/api/decorators/base_decorator'

module PactBroker
module Api
module Decorators
class ReleasedVersionDecorator < BaseDecorator
property :uuid
property :currently_supported, camelize: true

include Timestamps
end
end
end
end
10 changes: 10 additions & 0 deletions lib/pact_broker/api/decorators/version_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ class VersionDecorator < BaseDecorator
end
end

links :'pb:record-release' do | context |
context.fetch(:environments, []).collect do | environment |
{
title: "Record release to #{environment.display_name}",
name: environment.name,
href: released_versions_for_version_and_environment_url(represented, environment, context.fetch(:base_url))
}
end
end

curies do | options |
[{
name: :pb,
Expand Down
8 changes: 8 additions & 0 deletions lib/pact_broker/api/pact_broker_urls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,18 @@ def deployed_versions_for_version_and_environment_url(version, environment, base
"#{version_url(base_url, version)}/deployed-versions/environment/#{environment.uuid}"
end

def released_versions_for_version_and_environment_url(version, environment, base_url = '')
"#{version_url(base_url, version)}/released-versions/environment/#{environment.uuid}"
end

def deployed_version_url(deployed_version, base_url = '')
"/deployed-versions/#{deployed_version.uuid}"
end

def released_version_url(released_version, base_url = '')
"/released-versions/#{released_version.uuid}"
end

def hal_browser_url target_url, base_url = ''
"#{base_url}/hal-browser/browser.html#" + target_url
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ module PactBroker
module Api
module Resources
class DeployedVersionsForVersionAndEnvironment < BaseResource
def initialize
super
@existing_deployed_version = version && environment && deployed_version_service.find_currently_deployed_version_for_version_and_environment_and_target(version, environment, target)
end

def content_types_accepted
[["application/json", :from_json]]
end
Expand All @@ -25,20 +30,12 @@ def post_is_create?
true
end

def malformed_request?
if request.post?
malformed_post_request?
else
false
end
end

def create_path
deployed_version_url(OpenStruct.new(uuid: deployed_version_uuid), base_url)
deployed_version_url(existing_deployed_version || OpenStruct.new(uuid: deployed_version_uuid), base_url)
end

def from_json
@deployed_version = deployed_version_service.create(deployed_version_uuid, version, environment, replaced_previous_deployed_version)
@deployed_version = existing_deployed_version || deployed_version_service.create(deployed_version_uuid, version, environment, target)
response.body = decorator_class(:deployed_version_decorator).new(deployed_version).to_json(decorator_options)
end

Expand All @@ -52,7 +49,7 @@ def policy_name

private

attr_reader :deployed_version
attr_reader :deployed_version, :existing_deployed_version

def version
@version ||= version_service.find_by_pacticipant_name_and_number(identifier_from_path)
Expand All @@ -74,22 +71,14 @@ def deployed_version_uuid
@deployed_version_uuid ||= deployed_version_service.next_uuid
end

def replaced_previous_deployed_version
params(default: {})[:replacedPreviousDeployedVersion]
# TODO disallow an empty string because that is used as a NULL indicator in the database
def target
params(default: {})[:target]&.to_s
end

def title
"Deployed versions for #{pacticipant_name} version #{pacticipant_version_number}"
end

def malformed_post_request?
if ![true, false].include?(replaced_previous_deployed_version)
set_json_validation_error_messages({ replacedPreviousDeployedVersion: ["must be one of true, false"] })
true
else
false
end
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/pact_broker/api/resources/environments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def from_json
end

def policy_name
:'deployments::environment'
:'deployments::environments'
end

def to_json
Expand Down
52 changes: 52 additions & 0 deletions lib/pact_broker/api/resources/released_version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require 'pact_broker/api/resources/base_resource'
require 'pact_broker/api/decorators/released_version_decorator'

module PactBroker
module Api
module Resources
class ReleasedVersion < BaseResource
def content_types_provided
[["application/hal+json", :to_json]]
end

def allowed_methods
["GET", "OPTIONS"]
end

def resource_exists?
!!released_version
end

def to_json
decorator_class(:released_version_decorator).new(released_version).to_json(decorator_options)
end

def policy_name
:'versions::versions'
end

# For PF
def policy_record_context
# Not sure whether the context should be empty or the pacticipant should be nil
if released_version
{ pacticipant: released_version.pacticipant }
else
{}
end
end

private

attr_reader :released_version

def released_version
@released_version ||= released_version_service.find_by_uuid(uuid)
end

def uuid
identifier_from_path[:uuid]
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
require 'pact_broker/api/resources/base_resource'
require 'pact_broker/api/decorators/versions_decorator'

module PactBroker
module Api
module Resources
class ReleasedVersionsForVersionAndEnvironment < BaseResource
def initialize
super
@existing_released_version = version && environment && released_version_service.find_released_version_for_version_and_environment(version, environment)
end

def content_types_accepted
[["application/json", :from_json]]
end

def content_types_provided
[["application/hal+json", :to_json]]
end

def allowed_methods
["GET", "POST", "OPTIONS"]
end

def resource_exists?
!!version && !!environment
end

def post_is_create?
true
end

def create_path
released_version_url(existing_released_version || OpenStruct.new(uuid: next_released_version_uuid), base_url)
end

def from_json
@released_version = existing_released_version || released_version_service.create(next_released_version_uuid, version, environment)
response.body = decorator_class(:released_version_decorator).new(released_version).to_json(decorator_options)
true
end

def to_json
decorator_class(:released_versions_decorator).new(released_versions).to_json(decorator_options(title: title))
end

def policy_name
:'versions::versions'
end

def finish_request
if request.post? && existing_released_version
response.code = 200
end
super
end

private

attr_reader :released_version, :existing_released_version

def version
@version ||= version_service.find_by_pacticipant_name_and_number(identifier_from_path)
end

def environment
@environment ||= environment_service.find(environment_uuid)
end

def released_versions
@released_versions ||= begin
if existing_released_version
[existing_released_version]
else
[]
end
end
end

def environment_uuid
identifier_from_path[:environment_uuid]
end

def next_released_version_uuid
@released_version_uuid ||= released_version_service.next_uuid
end

def title
"Released versions for #{pacticipant.display_name} version #{pacticipant_version_number} in #{environment.display_name}"
end
end
end
end
end
14 changes: 14 additions & 0 deletions lib/pact_broker/deployments/currently_deployed_version_id.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'sequel'
require 'pact_broker/repositories/helpers'

module PactBroker
module Deployments
class CurrentlyDeployedVersionId < Sequel::Model
plugin :upsert, identifying_columns: [:pacticipant_id, :environment_id, :target_for_index]

dataset_module do
include PactBroker::Repositories::Helpers
end
end
end
end
Loading

0 comments on commit 58d173d

Please sign in to comment.