Skip to content

Commit

Permalink
feat: add deployed version resource, supporting marking deployed vers…
Browse files Browse the repository at this point in the history
…ion as undeployed
  • Loading branch information
bethesque committed Jun 6, 2021
1 parent cf6ba6e commit 3dd1995
Show file tree
Hide file tree
Showing 15 changed files with 292 additions and 24 deletions.
2 changes: 2 additions & 0 deletions lib/pact_broker/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,11 @@ def self.build_api(application_context = PactBroker::ApplicationContext.default_
if PactBroker.feature_enabled?(:environments)
add ["environments"], Api::Resources::Environments, { resource_name: "environments" }
add ["environments", :environment_uuid], Api::Resources::Environment, { resource_name: "environment" }
add ["environments", :environment_uuid, "currently-deployed-versions"], Api::Resources::CurrentlyDeployedVersionsForEnvironment, { resource_name: "environment_deployed_versions" }
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" }
add ["deployed-versions", :uuid], Api::Resources::DeployedVersion, { resource_name: "deployed_version" }
end

add ["integrations"], Api::Resources::Integrations, {resource_name: "integrations"}
Expand Down
6 changes: 6 additions & 0 deletions lib/pact_broker/api/decorators/deployed_version_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ class DeployedVersionDecorator < BaseDecorator
property :target, camelize: true
include Timestamps
property :undeployedAt, getter: lambda { |_| undeployed_at ? FormatDateTime.call(undeployed_at) : nil }, writeable: false

link :self do | user_options |
{
href: deployed_version_url(represented, user_options.fetch(:base_url))
}
end
end
end
end
Expand Down
11 changes: 9 additions & 2 deletions lib/pact_broker/api/decorators/environment_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@ class EnvironmentDecorator < BaseDecorator

include Timestamps

link :self do | options |
link :self do | user_options |
{
title: "Environment",
name: represented.name,
href: environment_url(represented, options[:base_url])
href: environment_url(represented, user_options.fetch(:base_url))
}
end

link :'pb:currently-deployed-versions' do | user_options |
{
title: "Versions currently deployed to #{represented.display_name} environment",
href: currently_deployed_versions_for_environment_url(represented, user_options.fetch(:base_url))
}
end

Expand Down
16 changes: 12 additions & 4 deletions lib/pact_broker/api/pact_broker_urls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -318,16 +318,24 @@ def deployed_versions_for_version_and_environment_url(version, environment, base
"#{version_url(base_url, version)}/deployed-versions/environment/#{environment.uuid}"
end

def currently_deployed_versions_for_environment_url(environment, base_url = "")
"#{base_url}/environments/#{environment.uuid}/currently-deployed-versions"
end

def record_undeployment_url(deployed_version, base_url = "")
"#{deployed_version_url(deployed_version, base_url)}/record-undeployment"
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}"
def deployed_version_url(deployed_version, base_url = "")
"#{base_url}/deployed-versions/#{deployed_version.uuid}"
end

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

def hal_browser_url target_url, base_url = ""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
require "pact_broker/api/resources/base_resource"
require "pact_broker/api/decorators/versions_decorator"
require "pact_broker/string_refinements"

module PactBroker
module Api
module Resources
class DeployedVersionsForEnvironment < BaseResource
class CurrentlyDeployedVersionsForEnvironment < BaseResource
using PactBroker::StringRefinements

def content_types_accepted
[["application/json", :from_json]]
end
Expand All @@ -26,7 +29,7 @@ def to_json
end

def policy_name
:'versions::versions'
:'deployments::environments'
end

private
Expand All @@ -36,15 +39,26 @@ def environment
end

def deployed_versions
@deployed_versions ||= deployed_version_service.find_deployed_versions_for_environment(environment)
@deployed_versions ||= deployed_version_service.find_currently_deployed_versions_for_environment(environment, query_params)
end

def environment_uuid
identifier_from_path[:environment_uuid]
end

def query_params
q = {}
if request.query["pacticipant"]
q[:pacticipant_name] = request.query["pacticipant"]
end
if request.query["target"]
q[:target] = request.query["target"].blank? ? nil : request.query["target"]
end
q
end

def title
"Deployed versions for #{environment.display_name}"
"Currently deployed versions for #{environment.display_name}"
end
end
end
Expand Down
94 changes: 94 additions & 0 deletions lib/pact_broker/api/resources/deployed_version.rb
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/deployed_version_decorator'
require 'pact_broker/messages'

module PactBroker
module Api
module Resources
class DeployedVersion < BaseResource
include PactBroker::Messages

def initialize
super
@currently_deployed_param = params(default: {})[:currentlyDeployed]
end

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

def content_types_accepted
[
["application/merge-patch+json", :from_merge_patch_json]
]
end

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

def resource_exists?
!!deployed_version
end

def malformed_request?
if request.patch?
return invalid_json?
else
false
end
end

def to_json
decorator_class(:deployed_version_decorator).new(deployed_version).to_json(decorator_options)
end

def from_merge_patch_json
if request.patch?
if resource_exists?
process_currently_deployed_param
else
404
end
else
415
end
end

def policy_name
:'versions::version'
end

def policy_record
deployed_version&.version
end

private

attr_reader :currently_deployed_param

def process_currently_deployed_param
if currently_deployed_param == false
@deployed_version = deployed_version_service.record_version_undeployed(deployed_version)
response.body = to_json
elsif currently_deployed_param == true
set_json_validation_error_messages(currentlyDeployed: [message("errors.validation.cannot_set_currently_deployed_true")])
422
else
response.body = to_json
end
end

def deployed_version
@deployed_version ||= deployed_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
Expand Up @@ -44,7 +44,11 @@ def to_json
end

def policy_name
:'versions::versions'
:'versions::version'
end

def policy_record
version
end

private
Expand Down
7 changes: 6 additions & 1 deletion lib/pact_broker/deployments/deployed_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def order_by_date_desc
end

def record_undeployed
update(undeployed_at: Sequel.datetime_class.now)
where(undeployed_at: nil).update(undeployed_at: Sequel.datetime_class.now)
end
end

Expand All @@ -88,6 +88,11 @@ def currently_deployed
def version_number
version.number
end

def record_undeployed
self.class.where(id: id).record_undeployed
self.refresh
end
end
end
end
36 changes: 26 additions & 10 deletions lib/pact_broker/deployments/deployed_version_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@
module PactBroker
module Deployments
class DeployedVersionService

def self.next_uuid
SecureRandom.uuid
end

# Policy applied at resource level to Version
def self.find_by_uuid(uuid)
DeployedVersion.where(uuid: uuid).single_record
end

def self.create(uuid, version, environment, target)
record_previous_version_undeployed(version.pacticipant, environment, target)
DeployedVersion.create(
Expand All @@ -19,28 +25,33 @@ def self.create(uuid, version, environment, target)
end

def self.find_deployed_versions_for_version_and_environment(version, environment)
DeployedVersion
scope_for(DeployedVersion)
.for_version_and_environment(version, environment)
.order_by_date_desc
.all
end

# Policy applied at resource level to Version
def self.find_currently_deployed_version_for_version_and_environment_and_target(version, environment, target)
DeployedVersion
.currently_deployed
.for_version_and_environment_and_target(version, environment, target)
.single_record
end

def self.find_deployed_versions_for_environment(environment)
DeployedVersion
def self.find_currently_deployed_versions_for_environment(environment, pacticipant_name: nil, target: nil)
query = scope_for(DeployedVersion)
.currently_deployed
.for_environment(environment)
.order_by_date_desc
.all

query = query.for_pacticipant_name(pacticipant_name) if pacticipant_name
query = query.for_target(target) if target
query.all
end

def self.find_currently_deployed_versions_for_pacticipant(pacticipant)
DeployedVersion
scope_for(DeployedVersion)
.currently_deployed
.where(pacticipant_id: pacticipant.id)
.eager(:version)
Expand All @@ -49,13 +60,10 @@ def self.find_currently_deployed_versions_for_pacticipant(pacticipant)
end

def self.record_version_undeployed(deployed_version)
deployed_version.currently_deployed_version_id.delete
# CurrentlyDeployedVersionId.where(pacticipant_id: pacticipant.id, environment_id: environment.id, target: target).delete
record_previous_version_undeployed(deployed_version.version.pacticipant, deployed_version.environment, deployed_version.target)
deployed_version.currently_deployed_version_id&.delete
deployed_version.record_undeployed
end

# private

def self.record_previous_version_undeployed(pacticipant, environment, target)
DeployedVersion.where(
undeployed_at: nil,
Expand All @@ -64,6 +72,14 @@ def self.record_previous_version_undeployed(pacticipant, environment, target)
target: target
).record_undeployed
end

private_class_method :record_previous_version_undeployed

def self.scope_for(scope)
PactBroker.policy_scope!(scope)
end

private_class_method :scope_for
end
end
end
1 change: 1 addition & 0 deletions lib/pact_broker/locale/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ en:
environment_with_name_not_found: "Environment with name '%{name}' does not exist"
cannot_modify_version_branch: "The branch for a pacticipant version cannot be changed once set (currently '%{old_branch}', proposed value '%{new_branch}'). Your pact publication/verification publication configurations may be in conflict with each other if you are seeing this error. If the current branch value is incorrect, you must delete the pacticipant version resource at %{version_url} and publish the pacts/verification results again with a consistent branch name."
invalid_content_for_content_type: "The content could not be parsed as %{content_type}"
cannot_set_currently_deployed_true: The currentlyDeployed property cannot be set back to true. Please record a new deployment.
duplicate_pacticipant: |
This is the first time a pact has been published for "%{new_name}".
The name "%{new_name}" is very similar to the following existing consumers/providers:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
RSpec.describe "Get currently deployed versions for environment" do
let!(:version) { td.create_consumer("Foo").create_consumer_version("1").and_return(:consumer_version) }
let!(:test_environment) { td.create_environment("test").and_return(:environment) }
let!(:prod_environment) { td.create_environment("prod").and_return(:environment) }
let!(:deployed_version) do
td.create_deployed_version_for_consumer_version(environment_name: "test", target: "customer-1", created_at: DateTime.now - 2)
.create_deployed_version_for_consumer_version(environment_name: "prod", created_at: DateTime.now - 1)
.create_provider("Bar")
.create_provider_version("4")
.create_deployed_version_for_provider_version(environment_name: "test", target: "customer-1")
.create_provider_version("5")
.create_deployed_version_for_provider_version(environment_name: "test", target: "customer-2")

end

let(:path) do
PactBroker::Api::PactBrokerUrls.currently_deployed_versions_for_environment_url(
test_environment
)
end

let(:response_body_hash) { JSON.parse(subject.body, symbolize_names: true) }

subject { get(path, nil, { "HTTP_ACCEPT" => "application/hal+json" }) }

it "returns a list of deployed versions" do
expect(response_body_hash[:_embedded][:deployedVersions]).to be_a(Array)
expect(response_body_hash[:_embedded][:deployedVersions].size).to eq 3
expect(response_body_hash[:_links][:self][:title]).to eq "Currently deployed versions for Test"
expect(response_body_hash[:_links][:self][:href]).to end_with(path)
end

context "with query params" do
subject { get(path, { pacticipant: "Bar", target: "customer-1" }, { "HTTP_ACCEPT" => "application/hal+json" }) }

it "returns a list of matching deployed versions" do
expect(response_body_hash[:_embedded][:deployedVersions].size).to eq 1
expect(response_body_hash[:_embedded][:deployedVersions].first[:_embedded][:version][:number]).to eq "4"
end
end
end
Loading

0 comments on commit 3dd1995

Please sign in to comment.