diff --git a/lib/pact_broker/api.rb b/lib/pact_broker/api.rb index c2f0bafa2..a2ac3b45b 100644 --- a/lib/pact_broker/api.rb +++ b/lib/pact_broker/api.rb @@ -88,6 +88,7 @@ module PactBroker add ['matrix', 'provider', :provider_name, 'consumer', :consumer_name], Api::Resources::MatrixForConsumerAndProvider, {resource_name: "matrix_consumer_provider"} add ['matrix', 'provider', :provider_name, 'latest', :provider_tag, 'consumer', :consumer_name, 'latest', :tag, 'badge'], Api::Resources::MatrixBadge, {resource_name: "matrix_tag_badge"} add ['matrix'], Api::Resources::Matrix, {resource_name: "matrix"} + add ['can-i-deploy'], Api::Resources::CanIDeploy, {resource_name: "can-i-deploy"} add ['dashboard'], Api::Resources::Dashboard, {resource_name: "dashboard"} add ['dashboard', 'provider', :provider_name, 'consumer', :consumer_name ], Api::Resources::Dashboard, {resource_name: "integration_dashboard"} diff --git a/lib/pact_broker/api/resources/can_i_deploy.rb b/lib/pact_broker/api/resources/can_i_deploy.rb new file mode 100644 index 000000000..c4e82411e --- /dev/null +++ b/lib/pact_broker/api/resources/can_i_deploy.rb @@ -0,0 +1,41 @@ +require 'pact_broker/api/resources/matrix' +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 CanIDeploy < Matrix + def initialize + @query_params = JSON.parse(Rack::Utils.parse_nested_query(request.uri.query).to_json, symbolize_names: true) + @selectors, @options = PactBroker::Matrix::ParseCanIDeployQuery.call(query_params) + end + + def malformed_request? + if (errors = query_schema.call(query_params)).any? + set_json_validation_error_messages(errors) + true + else + false + end + end + + private + + attr_reader :query_params + + def query_schema + PactBroker::Api::Contracts::CanIDeployQuerySchema + end + + def selectors + @selectors + end + + def options + @options + end + end + end + end +end diff --git a/lib/pact_broker/api/resources/index.rb b/lib/pact_broker/api/resources/index.rb index 76c190c57..984bc463b 100644 --- a/lib/pact_broker/api/resources/index.rb +++ b/lib/pact_broker/api/resources/index.rb @@ -110,6 +110,12 @@ def links href: base_url + '/metrics', title: "Get Pact Broker metrics", }, + 'pb:can-i-deploy-pacticipant-version-to-tag' => + { + href: base_url + '/can-i-deploy?pacticipant={pacticipant}&version={version}&to={tag}', + title: "Determine if an application can be safely deployed to an environment identified by the given tag", + templated: true + }, 'curies' => [{ name: 'pb', diff --git a/lib/pact_broker/doc/controllers/app.rb b/lib/pact_broker/doc/controllers/app.rb index 4d50c7b92..68e5d8af8 100644 --- a/lib/pact_broker/doc/controllers/app.rb +++ b/lib/pact_broker/doc/controllers/app.rb @@ -13,7 +13,9 @@ class App < Padrino::Application MAPPINGS = { 'webhooks-create' => 'webhooks', - 'webhooks-webhooks' => 'webhooks' + 'webhooks-webhooks' => 'webhooks', + 'can-i-deploy-pacticipant-version-to-tag' => 'can-i-deploy', + 'pacticipant' => 'pacticipants' }.freeze helpers do diff --git a/lib/pact_broker/matrix/can_i_deploy_query_schema.rb b/lib/pact_broker/matrix/can_i_deploy_query_schema.rb new file mode 100644 index 000000000..130924ca7 --- /dev/null +++ b/lib/pact_broker/matrix/can_i_deploy_query_schema.rb @@ -0,0 +1,25 @@ +require 'dry-validation' + +module PactBroker + module Api + module Contracts + class CanIDeployQuerySchema + SCHEMA = Dry::Validation.Schema do + required(:pacticipant).filled(:str?) + required(:version).filled(:str?) + optional(:to).filled(:str?) + end + + def self.call(params) + select_first_message(SCHEMA.call(params).messages(full: true)) + end + + def self.select_first_message(messages) + messages.each_with_object({}) do | (key, value), new_messages | + new_messages[key] = [value.first] + end + end + end + end + end +end diff --git a/lib/pact_broker/matrix/parse_can_i_deploy_query.rb b/lib/pact_broker/matrix/parse_can_i_deploy_query.rb new file mode 100644 index 000000000..ef511d1eb --- /dev/null +++ b/lib/pact_broker/matrix/parse_can_i_deploy_query.rb @@ -0,0 +1,29 @@ +require 'rack/utils' + +module PactBroker + module Matrix + class ParseCanIDeployQuery + def self.call params + selector = {} + options = { + latestby: 'cvp', + latest: true + } + + if params[:pacticipant].is_a?(String) + selector[:pacticipant_name] = params[:pacticipant] + end + + if params[:version].is_a?(String) + selector[:pacticipant_version_number] = params[:version] + end + + if params[:to].is_a?(String) + options[:tag] = params[:to] + end + + return [selector], options + end + end + end +end diff --git a/spec/features/can_i_deploy_spec.rb b/spec/features/can_i_deploy_spec.rb new file mode 100644 index 000000000..289de1756 --- /dev/null +++ b/spec/features/can_i_deploy_spec.rb @@ -0,0 +1,31 @@ +RSpec.describe "can i deploy" do + before do + td.create_pact_with_hierarchy("Foo", "1.2.3", "Bar") + end + + let(:query) do + { + pacticipant: "Foo", + version: "1.2.3", + to: "prod" + } + end + + let(:response_body) { JSON.parse(subject.body, symbolize_names: true) } + + subject { get("/can-i-deploy", query, { 'HTTP_ACCEPT' => 'application/hal+json'}) } + + it "returns the matrix response" do + expect(subject).to be_a_hal_json_success_response + expect(response_body[:matrix]).to be_instance_of(Array) + end + + context "with a validation error" do + let(:query) { {} } + + it "returns an error response" do + expect(subject.status).to eq 400 + expect(response_body[:errors]).to be_instance_of(Hash) + end + end +end