Skip to content

Commit

Permalink
feat: automatically set main branch (#483)
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque authored Aug 6, 2021
1 parent a086214 commit 63e287e
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 160 deletions.
15 changes: 1 addition & 14 deletions lib/pact_broker/api/resources/tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def from_json
# Make it return a 201 by setting the Location header
response.headers["Location"] = tag_url(base_url, tag)
end
create_deployed_version
deployed_version_service.maybe_create_deployed_version_for_tag(tag.version, identifier_from_path[:tag_name])
response.body = to_json
end

Expand All @@ -47,19 +47,6 @@ def delete_resource
def policy_name
:'tags::tag'
end

def create_deployed_version
if create_deployed_versions_for_tags?
if (environment = environment_service.find_by_name(identifier_from_path[:tag_name]))
deployed_version_service.find_or_create(deployed_version_service.next_uuid, tag.version, environment, nil)
end
end
end

# Come up with a cleaner way to abstract this for PF so it can be configured per tenant
def create_deployed_versions_for_tags?
PactBroker.configuration.create_deployed_versions_for_tags
end
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/pact_broker/config/runtime_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class RuntimeConfiguration < Anyway::Config
create_deployed_versions_for_tags: true,
use_first_tag_as_branch: true,
use_first_tag_as_branch_time_limit: 10,
auto_detect_main_branch: true,
main_branch_candidates: ["develop", "main", "master"],
semver_formats: ["%M.%m.%p%s%d", "%M.%m", "%M"],
features: []
)
Expand Down
11 changes: 11 additions & 0 deletions lib/pact_broker/deployments/deployed_version_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
module PactBroker
module Deployments
class DeployedVersionService
include PactBroker::Logging
extend PactBroker::Repositories::Scopes
extend PactBroker::Services

def self.next_uuid
SecureRandom.uuid
Expand Down Expand Up @@ -70,6 +72,15 @@ def self.record_version_undeployed(deployed_version)
deployed_version.record_undeployed
end

def self.maybe_create_deployed_version_for_tag(version, environment_name)
if PactBroker.configuration.create_deployed_versions_for_tags
if (environment = environment_service.find_by_name(environment_name))
logger.info("Creating deployed version for #{version.pacticipant.name} version #{version.number} in environment #{environment_name} (because create_deployed_versions_for_tags=true)")
find_or_create(next_uuid, version, environment, nil)
end
end
end

def self.record_previous_version_undeployed(pacticipant, environment, target)
DeployedVersion.where(
undeployed_at: nil,
Expand Down
4 changes: 4 additions & 0 deletions lib/pact_broker/pacticipants/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ def search_by_name(pacticipant_name)
string_match_query = Sequel.|( *terms.map { |term| Sequel.ilike(Sequel[:pacticipants][:name], "%#{term}%") })
PactBroker::Domain::Pacticipant.where(string_match_query)
end

def set_main_branch(pacticipant, main_branch)
pacticipant.update(main_branch: main_branch)
end
end
end
end
10 changes: 9 additions & 1 deletion lib/pact_broker/pacticipants/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
require "pact_broker/pacticipants/find_potential_duplicate_pacticipant_names"

module PactBroker

module Pacticipants
class Service

Expand Down Expand Up @@ -90,6 +89,15 @@ def self.delete_if_orphan(pacticipant)
def self.pacticipant_names
pacticipant_repository.pacticipant_names
end

def self.maybe_set_main_branch(pacticipant, potential_main_branch)
if pacticipant.main_branch.nil? && PactBroker.configuration.auto_detect_main_branch && PactBroker.configuration.main_branch_candidates.include?(potential_main_branch)
logger.info "Setting #{pacticipant.name} main_branch to '#{potential_main_branch}' (because the #{pacticipant.name} main_branch was nil and auto_detect_main_branch=true)"
pacticipant_repository.set_main_branch(pacticipant, potential_main_branch)
else
pacticipant
end
end
end
end
end
19 changes: 4 additions & 15 deletions lib/pact_broker/tags/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@ module Tags
module Service
extend self
extend PactBroker::Repositories
extend PactBroker::Services
include PactBroker::Logging

def create args
tag_name = args.fetch(:tag_name)
pacticipant = pacticipant_repository.find_by_name_or_create args.fetch(:pacticipant_name)
version = version_repository.find_by_pacticipant_id_and_number_or_create pacticipant.id, args.fetch(:pacticipant_version_number)
if use_tag_as_branch?(version) && !version.branch
logger.info "Setting #{version.pacticipant.name} version #{version.number} branch to '#{tag_name}' from first tag (because use_first_tag_as_branch=true)"
version_repository.set_branch_if_unset(version, tag_name)
end
tag_repository.create version: version, name: tag_name
version_service.maybe_set_version_branch_from_tag(version, tag_name)
pacticipant_service.maybe_set_main_branch(version.pacticipant, tag_name)
tag_repository.create(version: version, name: tag_name)
end

def find args
Expand All @@ -33,16 +32,6 @@ def delete args
def find_all_tag_names_for_pacticipant pacticipant_name
tag_repository.find_all_tag_names_for_pacticipant pacticipant_name
end

def use_tag_as_branch?(version)
version.tags.count == 0 &&
PactBroker.configuration.use_first_tag_as_branch &&
((now - version.created_at.to_datetime) * 24 * 60 * 60) <= PactBroker.configuration.use_first_tag_as_branch_time_limit
end

def now
Time.now.utc.to_datetime
end
end
end
end
30 changes: 28 additions & 2 deletions lib/pact_broker/versions/service.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require "pact_broker/logging"
require "pact_broker/repositories"
require "pact_broker/messages"

Expand All @@ -6,6 +7,8 @@ module Versions
class Service
extend PactBroker::Messages
extend PactBroker::Repositories
extend PactBroker::Services
include PactBroker::Logging

def self.conflict_errors(_existing_version, _open_struct_version, _version_url)
# This validation is causing problems in the PF build when branches are merged
Expand Down Expand Up @@ -38,12 +41,16 @@ def self.find_by_pacticipant_name_and_latest_tag(pacticipant_name, tag)

def self.create_or_overwrite(pacticipant_name, version_number, version)
pacticipant = pacticipant_repository.find_by_name_or_create(pacticipant_name)
version_repository.create_or_overwrite(pacticipant, version_number, version)
version = version_repository.create_or_overwrite(pacticipant, version_number, version)
pacticipant_service.maybe_set_main_branch(pacticipant, version.branch)
version
end

def self.create_or_update(pacticipant_name, version_number, version)
pacticipant = pacticipant_repository.find_by_name_or_create(pacticipant_name)
version_repository.create_or_update(pacticipant, version_number, version)
version = version_repository.create_or_update(pacticipant, version_number, version)
pacticipant_service.maybe_set_main_branch(pacticipant, version.branch)
version
end

def self.find_latest_version_from_main_branch(pacticipant)
Expand All @@ -57,6 +64,25 @@ def self.delete version
verification_repository.delete_by_provider_version_id version.id
version_repository.delete_by_id version.id
end

def self.maybe_set_version_branch_from_tag(version, tag_name)
if use_tag_as_branch?(version) && !version.branch
logger.info "Setting #{version.pacticipant.name} version #{version.number} branch to '#{tag_name}' from first tag (because use_first_tag_as_branch=true)"
version_repository.set_branch_if_unset(version, tag_name)
end
end

def self.use_tag_as_branch?(version)
version.tags.count == 0 &&
PactBroker.configuration.use_first_tag_as_branch &&
((now - version.created_at.to_datetime) * 24 * 60 * 60) <= PactBroker.configuration.use_first_tag_as_branch_time_limit
end
private_class_method :use_tag_as_branch?

def self.now
Time.now.utc.to_datetime
end
private_class_method :now
end
end
end
19 changes: 19 additions & 0 deletions script/data/auto-create-things-for-tags.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env ruby
begin

$LOAD_PATH << "#{Dir.pwd}/lib"
require "pact_broker/test/http_test_data_builder"
base_url = ENV["PACT_BROKER_BASE_URL"] || "http://localhost:9292"

td = PactBroker::Test::HttpTestDataBuilder.new(base_url)
td.delete_pacticipant("AutoDetectTestProvider")
.create_environment(name: "prod", production: true)
.create_pacticipant("AutoDetectTestProvider")
.create_tagged_pacticipant_version(pacticipant: "AutoDetectTestProvider", version: "1", tag: "main")
.deploy_to_prod(pacticipant: "AutoDetectTestProvider", version: "1")

rescue StandardError => e
puts "#{e.class} #{e.message}"
puts e.backtrace
exit 1
end
11 changes: 6 additions & 5 deletions script/data/contract-published-requiring-verification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@

td = PactBroker::Test::HttpTestDataBuilder.new(base_url)
td.create_global_webhook_for_event(uuid: "7a5da39c-8e50-4cc9-ae16-dfa5be043e8c", event_name: "contract_requiring_verification_published")
.delete_by_pacticipant("NewWebhookTestConsumer")
.delete_by_pacticipant("NewWebhookTestProvider")
.delete_pacticipant("NewWebhookTestConsumer")
.delete_pacticipant("NewWebhookTestProvider")
.create_environment(name: "test")
.create_environment(name: "prod", production: true)
.create_pacticipant("NewWebhookTestConsumer", main_branch: "main")
.create_pacticipant("NewWebhookTestProvider", main_branch: "main")
.create_version(pacticipant: "NewWebhookTestProvider", version: "1", branch: "main")
.create_pacticipant("NewWebhookTestConsumer")
.create_pacticipant("NewWebhookTestProvider")
.create_tagged_pacticipant_version(pacticipant: "NewWebhookTestProvider", version: "1", tag: "main")
.deploy_to_prod(pacticipant: "NewWebhookTestProvider")
.record_deployment(pacticipant: "NewWebhookTestProvider", version: "1", environment_name: "test")
.record_deployment(pacticipant: "NewWebhookTestProvider", version: "1", environment_name: "prod")
.create_version(pacticipant: "NewWebhookTestProvider", version: "2", branch: "main")
Expand Down
53 changes: 14 additions & 39 deletions spec/lib/pact_broker/api/resources/tag_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ module PactBroker
module Api
module Resources
describe Tag do
let(:tag) { double("PactBroker::Domain::Tag") }
let(:tag) { double("PactBroker::Domain::Tag", version: version) }
let(:version) { double("version") }
let(:tag_decorator) { instance_double("PactBroker::Api::Decorators::TagDecorator", :to_json => tag_json) }
let(:tag_json) { {"some" => "tag"}.to_json }
let(:tag_attributes) {
Expand Down Expand Up @@ -99,9 +100,10 @@ module Resources
allow_any_instance_of(PactBroker::Api::Resources::Tag).to receive(:tag_url).and_return(tag_url)
allow(Tags::Service).to receive(:find).and_return(tag)
allow(PactBroker::Api::Decorators::TagDecorator).to receive(:new).and_return(tag_decorator)
allow_any_instance_of(described_class).to receive(:create_deployed_versions_for_tags?).and_return(create_deployed_versions_for_tags)
allow(deployed_version_service).to receive(:maybe_create_deployed_version_for_tag).and_return("uuid")
end

let(:deployed_version_service) { class_double("PactBroker::Deployments::DeployedVersionService").as_stubbed_const }
let(:tag_url) { "http://example.org/tag/url"}
let(:create_deployed_versions_for_tags) { false }

Expand All @@ -118,12 +120,16 @@ module Resources
expect(last_response.status).to be 200
end

it "maybe creates a deployed version" do
expect(deployed_version_service).to receive(:maybe_create_deployed_version_for_tag).with(version, "prod")
subject
end

it "renders the tag" do
expect(tag_decorator).to receive(:to_json).with(user_options: hash_including(base_url: "http://example.org"))
subject
expect(last_response.body).to eq tag_json
end

end

context "when the tag does not exist" do
Expand All @@ -137,6 +143,11 @@ module Resources
subject
end

it "maybe creates a deployed version" do
expect(deployed_version_service).to receive(:maybe_create_deployed_version_for_tag).with(version, "prod")
subject
end

it "returns a 201" do
subject
expect(last_response.status).to be 201
Expand All @@ -148,42 +159,6 @@ module Resources
expect(last_response.body).to eq tag_json
end
end

context "when create_deployed_versions_for_tags is true" do
before do
allow_any_instance_of(described_class).to receive(:environment_service).and_return(environment_service)
allow_any_instance_of(described_class).to receive(:deployed_version_service).and_return(deployed_version_service)
allow(environment_service).to receive(:find_by_name).and_return(environment)
allow(deployed_version_service).to receive(:next_uuid).and_return("uuid")
allow(tag).to receive(:version).and_return(version)
end
let(:environment_service) { class_double("PactBroker::Environments::Service").as_stubbed_const }
let(:deployed_version_service) { class_double("PactBroker::Deployments::DeployedVersionService").as_stubbed_const }
let(:environment) { nil }
let(:create_deployed_versions_for_tags) { true }
let(:version) { double("version") }

it "looks for a matching environment" do
expect(environment_service).to receive(:find_by_name).with("prod")
subject
end

context "when the tag name matches an existing environment" do
let(:environment) { double("environment") }

it "creates a deployed version" do
expect(deployed_version_service).to receive(:find_or_create).with(anything, version, environment, nil)
subject
end
end

context "when the tag name does not match an existing environment" do
it "does not create a deployed version" do
expect_any_instance_of(described_class).to_not receive(:deployed_version_service)
subject
end
end
end
end
end
end
Expand Down
33 changes: 28 additions & 5 deletions spec/lib/pact_broker/pacticipants/service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ module Pacticipants
allow(Service).to receive(:logger).and_return(logger)
end

let(:td) { TestDataBuilder.new }
let(:logger) { double("logger").as_null_object }

subject{ Service }
subject { Service }

describe ".messages_for_potential_duplicate_pacticipants" do

Expand Down Expand Up @@ -100,10 +99,35 @@ module Pacticipants
end
end

describe ".maybe_set_main_branch" do
before do
allow(PactBroker.configuration).to receive(:auto_detect_main_branch).and_return(true)
allow(PactBroker.configuration).to receive(:main_branch_candidates).and_return(["foo", "bar"])
td.create_pacticipant("Foo", main_branch: main_branch)
end

let(:main_branch) { nil }

subject { Service.maybe_set_main_branch(td.find_pacticipant("Foo"), "bar") }

context "when the main branch is nil and auto_detect_main_branch=true and the potential branch is in the list of candidate main branch names" do
it "sets the main branch" do
expect(subject.main_branch).to eq "bar"
end
end

context "when the branch is already set" do
let(:main_branch) { "main" }

it "does not overwrite it" do
expect(subject.main_branch).to eq "main"
end
end
end

describe "delete" do
before do
TestDataBuilder.new
.create_consumer("Consumer")
td.create_consumer("Consumer")
.create_label("finance")
.create_consumer_version("2.3.4")
.create_provider("Provider")
Expand Down Expand Up @@ -186,7 +210,6 @@ module Pacticipants
it "deletes the verifications" do
expect{ delete_provider }.to change{ PactBroker::Domain::Verification.count }.by(-1)
end

end
end
end
Expand Down
Loading

0 comments on commit 63e287e

Please sign in to comment.