Skip to content

Commit

Permalink
feat: add badges for can-i-deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Sep 25, 2020
1 parent 98f2e71 commit 887a9ca
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 7 deletions.
1 change: 1 addition & 0 deletions lib/pact_broker/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ module PactBroker
add ['pacticipants', :pacticipant_name, 'versions'], Api::Resources::Versions, {resource_name: "pacticipant_versions"}
add ['pacticipants', :pacticipant_name, 'versions', :pacticipant_version_number], Api::Resources::Version, {resource_name: "pacticipant_version"}
add ['pacticipants', :pacticipant_name, 'latest-version', :tag], Api::Resources::Version, {resource_name: "latest_tagged_pacticipant_version"}
add ['pacticipants', :pacticipant_name, 'latest-version', :tag, 'can-i-deploy', 'to', :to, 'badge'], Api::Resources::CanIDeployBadge, { resource_name: "can_i_deploy_badge" }
add ['pacticipants', :pacticipant_name, 'latest-version'], Api::Resources::Version, {resource_name: "latest_pacticipant_version"}
add ['pacticipants', :pacticipant_name, 'versions', :pacticipant_version_number, 'tags', :tag_name], Api::Resources::Tag, {resource_name: "pacticipant_version_tag"}
add ['pacticipants', :pacticipant_name, 'labels', :label_name], Api::Resources::Label, {resource_name: "pacticipant_label"}
Expand Down
16 changes: 16 additions & 0 deletions lib/pact_broker/api/decorators/pacticipant_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ class PacticipantDecorator < BaseDecorator
}
end

link :'pb:can-i-deploy-badge' do | options |
{
title: "Can I Deploy #{represented.name} badge",
href: templated_can_i_deploy_badge_url(represented.name, options[:base_url]),
templated: true
}
end

curies do | options |
[{
name: :pb,
href: options[:base_url] + '/doc/{rel}?context=pacticipant',
templated: true
}]
end

def to_hash options
h = super
dasherized = DasherizedVersionDecorator.new(represented).to_hash(options)
Expand Down
8 changes: 6 additions & 2 deletions lib/pact_broker/api/pact_broker_urls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,15 @@ def tag_url base_url, tag
end

def templated_tag_url_for_pacticipant pacticipant_name, base_url = ""
pacticipant_url_from_params({pacticipant_name: pacticipant_name}, base_url) + "/versions/{version}/tags/{tag}"
pacticipant_url_from_params({ pacticipant_name: pacticipant_name }, base_url) + "/versions/{version}/tags/{tag}"
end

def templated_label_url_for_pacticipant pacticipant_name, base_url = ""
pacticipant_url_from_params({pacticipant_name: pacticipant_name}, base_url) + "/labels/{label}"
pacticipant_url_from_params({ pacticipant_name: pacticipant_name }, base_url) + "/labels/{label}"
end

def templated_can_i_deploy_badge_url pacticipant_name, base_url = ""
pacticipant_url_from_params({ pacticipant_name: pacticipant_name }, base_url) + "/latest-version/{tag}/can-i-deploy/to/{environmentTag}/badge"
end

def label_url label, base_url
Expand Down
80 changes: 80 additions & 0 deletions lib/pact_broker/api/resources/can_i_deploy_badge.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
require 'pact_broker/matrix/can_i_deploy_query_schema'
require 'pact_broker/matrix/parse_can_i_deploy_query'

module PactBroker
module Api
module Resources
class CanIDeployBadge < BaseResource
def initialize
super
selector = PactBroker::Matrix::UnresolvedSelector.new(pacticipant_name: pacticipant_name, latest: true, tag: identifier_from_path[:tag])
@options = {
latestby: 'cvp',
latest: true,
tag: identifier_from_path[:to]
}
@selectors = [selector]
end

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

def content_types_provided
[['image/svg+xml', :to_svg]]
end

def resource_exists?
false
end

# Only called if resource_exists? returns false
def previously_existed?
true
end

def is_authorized?(authorization_header)
super || PactBroker.configuration.enable_public_badge_access
end

def forbidden?
false
end

def moved_temporarily?
response.headers['Cache-Control'] = 'no-cache'
begin
if pacticipant
if version
badge_service.can_i_deploy_badge_url(selectors.first.pacticipant_name, options[:tag], results.deployable?)
else
badge_service.error_badge_url("version", "not found")
end
else
badge_service.error_badge_url(selectors.first.pacticipant_name, "not found")
end
rescue StandardError => e
# Want to render a badge, even if there's an error
badge_service.error_badge_url("error", ErrorHandler.display_message(e, "reference: #{ErrorHandler.generate_error_reference}"))
end
end

def policy_name
:'badges::badge'
end

private

attr_reader :selectors, :options

def results
@results ||= matrix_service.find(selectors, options)
end

def version
@version ||= version_service.find_by_pacticipant_name_and_latest_tag(identifier_from_path[:pacticipant_name], identifier_from_path[:tag])
end
end
end
end
end
8 changes: 4 additions & 4 deletions lib/pact_broker/api/resources/error_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ def self.log_as_warning?(e)
PactBroker.configuration.warning_error_classes.any? { |clazz| e.is_a?(clazz) }
end

def self.display_message(e, error_reference)
def self.display_message(e, obfuscated_message)
if PactBroker.configuration.show_backtrace_in_error_response?
e.message || obfuscated_error_message(error_reference)
e.message || obfuscated_message
else
reportable?(e) ? obfuscated_error_message(error_reference) : e.message
reportable?(e) ? obfuscated_message : e.message
end
end

Expand All @@ -47,7 +47,7 @@ def self.obfuscated_error_message error_reference
def self.response_body_hash e, error_reference
response_body = {
error: {
message: display_message(e, error_reference),
message: display_message(e, obfuscated_error_message(error_reference)),
reference: error_reference
}
}
Expand Down
11 changes: 11 additions & 0 deletions lib/pact_broker/badges/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ def pact_verification_badge_url(pact, label, initials, pseudo_branch_verificatio
build_shield_io_uri(title, status, color)
end

def can_i_deploy_badge_url(pacticipant_name, environment_tag, deployable)
title = "Can I deploy #{pacticipant_name} to #{environment_tag}?"
status = deployable ? "yes" : "no"
color = deployable ? "brightgreen" : "red"
build_shield_io_uri(title, status, color)
end

def error_badge_url(left_text, right_text)
build_shield_io_uri(left_text, right_text, "lightgrey")
end

def clear_cache
CACHE.clear
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Can I Deploy Badge

Allowed methods: `GET`

Path: `/pacticipants/{pacticipant}/latest-version/{tag}/can-i-deploy/to/{environmentTag}/badge`

Returns a status badge that can be displayed in a README file that indicates whether the specified version of a pacticipant can be deployed to the specified environment.
13 changes: 13 additions & 0 deletions spec/features/get_can_i_deploy_badge_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
RSpec.describe "can i deploy badge" do
before do
td.create_pact_with_hierarchy("Foo", "1.2.3", "Bar")
.create_consumer_version_tag("main")
end

subject { get("/pacticipants/Foo/latest-version/main/can-i-deploy/to/prod/badge", nil, { 'HTTP_ACCEPT' => 'image/svg+xml'}) }

it "returns a redirect response" do
expect(subject.status).to eq 307
expect(subject.headers['Location']).to start_with "https://img.shields.io/badge"
end
end
2 changes: 1 addition & 1 deletion spec/features/get_matrix_badge_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# In the full app, the .svg extension is turned into an Accept header
# by ConvertFileExtensionToAcceptHeader

subject { get path, nil, {'HTTP_ACCEPT' => "image/svg+xml"}; last_response }
subject { get(path, nil, {'HTTP_ACCEPT' => "image/svg+xml"}) }

it "returns a 200 status" do
expect(subject.status).to eq 200
Expand Down
71 changes: 71 additions & 0 deletions spec/lib/pact_broker/api/resources/can_i_deploy_badge_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
require 'pact_broker/api/resources/can_i_deploy_badge'

module PactBroker
module Api
module Resources
describe CanIDeployBadge do
before do
allow_any_instance_of(described_class).to receive(:badge_service).and_return(badge_service)
allow_any_instance_of(described_class).to receive(:matrix_service).and_return(matrix_service)
allow_any_instance_of(described_class).to receive(:pacticipant_service).and_return(pacticipant_service)
allow_any_instance_of(described_class).to receive(:version_service).and_return(version_service)
allow(badge_service).to receive(:can_i_deploy_badge_url).and_return("http://badge")
allow(badge_service).to receive(:error_badge_url).and_return("http://error")
allow(matrix_service).to receive(:find).and_return(results)
allow(pacticipant_service).to receive(:find_pacticipant_by_name).and_return(pacticipant)
allow(version_service).to receive(:find_by_pacticipant_name_and_latest_tag).and_return(version)
allow(PactBroker.configuration).to receive(:show_backtrace_in_error_response?).and_return(false)
allow(ErrorHandler).to receive(:generate_error_reference).and_return("abcd")
end

let(:pacticipant_service) { class_double("PactBroker::Pacticipant::Service").as_stubbed_const }
let(:badge_service) { class_double("PactBroker::Badges::Service").as_stubbed_const }
let(:matrix_service) { class_double("PactBroker::Matrix::Service").as_stubbed_const }
let(:version_service) { class_double("PactBroker::Version::Service").as_stubbed_const }
let(:results) { double('results', deployable?: true) }
let(:pacticipant) { double('pacticipant') }
let(:version) { double('version') }

let(:path) { "/pacticipants/Foo/latest-version/main/can-i-deploy/to/prod/badge"}

subject { get(path) }

context "when the pacticipant exists" do
it "returns a redirect to the badge" do
expect(badge_service).to receive(:can_i_deploy_badge_url).with("Foo", "prod", true)
expect(subject.status).to eq 307
end
end

context "when the pacticipant does not exist" do
let(:pacticipant) { nil }

it "returns a redirect to a 'not found' badge" do
expect(badge_service).to receive(:error_badge_url).with("Foo", "not found")
expect(subject.status).to eq 307
end
end

context "when the version does not exist" do
let(:version) { nil }

it "returns a redirect to a 'not found' badge" do
expect(badge_service).to receive(:error_badge_url).with("version", "not found")
expect(subject.status).to eq 307
end
end

context "when there is an error" do
before do
allow(matrix_service).to receive(:find).and_raise("foo error")
end

it "returns a redirect to a badge with an error message" do
expect(badge_service).to receive(:error_badge_url).with("error", "reference: abcd")
expect(subject.status).to eq 307
end
end
end
end
end
end

0 comments on commit 887a9ca

Please sign in to comment.