diff --git a/README.md b/README.md index 2cbba687..0cf9404e 100644 --- a/README.md +++ b/README.md @@ -482,8 +482,8 @@ Description: support for environments, deployments and releases. For documentation on how to use can-i-deploy with tags, please see https://docs.pact.io/pact_broker/client_cli/can_i_deploy_usage_with_tags/ - Before `can-i-deploy` can be used, the relevant environment resources must first be created in the Pact Broker using the `create-environment` command. The - "test" and "production" environments will have been seeded for you. You can check the existing environments by running `pact-broker list-environments`. See + Before `can-i-deploy` can be used, the relevant environment resources must first be created in the Pact Broker using the `create-environment` command. The "test" + and "production" environments will have been seeded for you. You can check the existing environments by running `pact-broker list-environments`. See https://docs.pact.io/pact_broker/client_cli/readme#environments for more information. $ pact-broker create-environment --name "uat" --display-name "UAT" --no-production @@ -493,8 +493,8 @@ Description: $ pact-broker record-deployment --pacticipant Foo --version 173153ae0 --environment uat - Before an application is deployed or released to an environment, the can-i-deploy command must be run to check that the application version is safe to deploy - with the versions of each integrated application that are already in that environment. + Before an application is deployed or released to an environment, the can-i-deploy command must be run to check that the application version is safe to deploy with + the versions of each integrated application that are already in that environment. $ pact-broker can-i-deploy --pacticipant PACTICIPANT --version VERSION --to-environment ENVIRONMENT @@ -502,8 +502,8 @@ Description: $ pact-broker can-i-deploy --pacticipant Foo --version 173153ae0 --to-environment test - Can-i-deploy can also be used to check if arbitrary versions have a successful verification. When asking "Can I deploy this application version with the - latest version from the main branch of another application" it functions as a "can I merge" check. + Can-i-deploy can also be used to check if arbitrary versions have a successful verification. When asking "Can I deploy this application version with the latest version + from the main branch of another application" it functions as a "can I merge" check. $ pact-broker can-i-deploy --pacticipant Foo 173153ae0 \ --pacticipant Bar --latest main @@ -650,8 +650,8 @@ Options: ``` Description: - Create a curl command that executes the request that you want your webhook to execute, then replace "curl" with "pact-broker create-webhook" and add the - consumer, provider, event types and broker details. Note that the URL must be the first parameter when executing create-webhook. + Create a curl command that executes the request that you want your webhook to execute, then replace "curl" with "pact-broker create-webhook" and add the consumer, + provider, event types and broker details. Note that the URL must be the first parameter when executing create-webhook. Note that the -u option from the curl command clashes with the -u option from the pact-broker CLI. When used in this command, the -u will be used as a curl option. Please use the --broker-username or environment variable for the Pact Broker username. @@ -715,9 +715,9 @@ Options: ``` Description: - Create a curl command that executes the request that you want your webhook to execute, then replace "curl" with "pact-broker create-or-update-webhook" and - add the consumer, provider, event types and broker details. Note that the URL must be the first parameter when executing create-or-update-webhook and a uuid - must also be provided. You can generate a valid UUID by using the `generate-uuid` command. + Create a curl command that executes the request that you want your webhook to execute, then replace "curl" with "pact-broker create-or-update-webhook" and add the + consumer, provider, event types and broker details. Note that the URL must be the first parameter when executing create-or-update-webhook and a uuid must + also be provided. You can generate a valid UUID by using the `generate-uuid` command. Note that the -u option from the curl command clashes with the -u option from the pact-broker CLI. When used in this command, the -u will be used as a curl option. Please use the --broker-username or environment variable for the Pact Broker username. @@ -814,6 +814,39 @@ Options: Describes a pacticipant version. If no version or tag is specified, the latest version is described. +#### create-or-update-version + +``` +Usage: + pact-broker create-or-update-version -a, --pacticipant=PACTICIPANT -b, --broker-base-url=BROKER_BASE_URL -e, --version=VERSION + +Options: + -a, --pacticipant=PACTICIPANT + # The pacticipant name + -e, --version=VERSION + # The pacticipant version number + [--branch=BRANCH] + # The repository branch name + -t, [--tag=TAG] + # Tag name for pacticipant version. Can be specified multiple + times. + -b, --broker-base-url=BROKER_BASE_URL + # The base URL of the Pact Broker + -u, [--broker-username=BROKER_USERNAME] + # Pact Broker basic auth username + -p, [--broker-password=BROKER_PASSWORD] + # Pact Broker basic auth password + -k, [--broker-token=BROKER_TOKEN] + # Pact Broker bearer token + -v, [--verbose], [--no-verbose] + # Verbose output. Default: false + -o, [--output=OUTPUT] + # json or text + # Default: text +``` + +Create or update pacticipant version by version number + ### Miscellaneous #### generate-uuid diff --git a/lib/pact_broker/client/cli/broker.rb b/lib/pact_broker/client/cli/broker.rb index 423f4c85..4e597e8d 100644 --- a/lib/pact_broker/client/cli/broker.rb +++ b/lib/pact_broker/client/cli/broker.rb @@ -4,6 +4,7 @@ require 'pact_broker/client/cli/environment_commands' require 'pact_broker/client/cli/deployment_commands' require 'pact_broker/client/cli/pacticipant_commands' +require 'pact_broker/client/cli/version_commands' require 'pact_broker/client/cli/webhook_commands' require "pact_broker/client/cli/matrix_commands" @@ -22,6 +23,7 @@ class Broker < CustomThor include PactBroker::Client::CLI::DeploymentCommands include PactBroker::Client::CLI::MatrixCommands include PactBroker::Client::CLI::PacticipantCommands + include PactBroker::Client::CLI::VersionCommands include PactBroker::Client::CLI::WebhookCommands desc 'publish PACT_DIRS_OR_FILES ...', "Publish pacts to a Pact Broker." diff --git a/lib/pact_broker/client/cli/version_commands.rb b/lib/pact_broker/client/cli/version_commands.rb new file mode 100644 index 00000000..043c74ee --- /dev/null +++ b/lib/pact_broker/client/cli/version_commands.rb @@ -0,0 +1,51 @@ +module PactBroker + module Client + module CLI + module VersionCommands + def self.included(thor) + thor.class_eval do + desc "create-or-update-version", "Create or update pacticipant version by version number" + method_option :pacticipant, required: true, aliases: "-a", desc: "The pacticipant name" + method_option :version, required: true, aliases: "-e", desc: "The pacticipant version number" + method_option :branch, required: false, desc: "The repository branch name" + method_option :tag, aliases: "-t", type: :array, banner: "TAG", desc: "Tag name for pacticipant version. Can be specified multiple times." + shared_authentication_options + output_option_json_or_text + verbose_option + + def create_or_update_version(*required_but_ignored) + validate_create_version_params + + params = { + pacticipant_name: options.pacticipant.strip, + version_number: options.version.strip, + branch_name: options.branch&.strip, + tags: options.tag&.collect(&:strip) + } + + execute_version_command(params, "Create") + end + + + no_commands do + def execute_version_command(params, command_class_name) + require "pact_broker/client/versions" + command_options = { verbose: options.verbose, output: options.output } + result = PactBroker::Client::Versions.const_get(command_class_name).call(params, command_options, pact_broker_client_options) + $stdout.puts result.message + exit(1) unless result.success + end + + def validate_create_version_params + raise ::Thor::RequiredArgumentMissingError, "Pacticipant name cannot be blank" if options.pacticipant.strip.size == 0 + raise ::Thor::RequiredArgumentMissingError, "Pacticipant version cannot be blank" if options.version.strip.size == 0 + raise ::Thor::RequiredArgumentMissingError, "Version branch cannot be blank" if options.branch && options.branch.strip.size == 0 + raise ::Thor::RequiredArgumentMissingError, "Version tag cannot be blank" if options.tag && options.tag.any?{ | tag | tag.strip.size == 0 } + end + end + end + end + end + end + end +end diff --git a/lib/pact_broker/client/pacticipants/create.rb b/lib/pact_broker/client/pacticipants/create.rb index b7253a8b..5578e3f4 100644 --- a/lib/pact_broker/client/pacticipants/create.rb +++ b/lib/pact_broker/client/pacticipants/create.rb @@ -30,7 +30,7 @@ def result_message if json_output? response_entity.response.raw_body else - green(message = "Pacticipant \"#{params[:name]}\" #{action} in #{pact_broker_name}") + green("Pacticipant \"#{params[:name]}\" #{action} in #{pact_broker_name}") end end diff --git a/lib/pact_broker/client/versions.rb b/lib/pact_broker/client/versions.rb index 65e63c20..5a14c758 100644 --- a/lib/pact_broker/client/versions.rb +++ b/lib/pact_broker/client/versions.rb @@ -1,5 +1,6 @@ require 'pact_broker/client/base_client' require 'pact_broker/client/versions/describe' +require 'pact_broker/client/versions/create' # Old code require 'pact_broker/client/pacts' diff --git a/lib/pact_broker/client/versions/create.rb b/lib/pact_broker/client/versions/create.rb new file mode 100644 index 00000000..47bd3028 --- /dev/null +++ b/lib/pact_broker/client/versions/create.rb @@ -0,0 +1,110 @@ +require "pact_broker/client/base_command" + +module PactBroker + module Client + class Versions + class Create < PactBroker::Client::BaseCommand + + def do_call + if branch_name + if branch_versions_supported? + create_branch_version + else + raise PactBroker::Client::Error.new("This version of #{pact_broker_name} does not support branch versions,or you do not have the required permissions to create one. Please ensure you have upgraded to version 2.82.0 or later for branch support.") + end + end + + if tags + create_version_tags + end + + if !branch_name && !tags.any? + create_version + end + + PactBroker::Client::CommandResult.new(true, result_message) + end + + private + + def pacticipant_name + params.fetch(:pacticipant_name) + end + + def version_number + params.fetch(:version_number) + end + + def branch_name + params[:branch_name] + end + + def tags + params[:tags] || [] + end + + def branch_versions_supported? + index_resource._link("pb:pacticipant-branch-version") + end + + def create_branch_version + branch_params = { + "pacticipant" => pacticipant_name, + "version" => version_number, + "branch" => branch_name + } + branch_version_entity = index_resource + ._link("pb:pacticipant-branch-version") + .expand(branch_params) + .put! + end + + def create_version_tags + tags.each do | tag | + tag_params = { + "pacticipant" => pacticipant_name, + "version" => version_number, + "tag" => tag + } + index_resource + ._link("pb:pacticipant-version-tag") + .expand(tag_params) + .put! + end + end + + def create_version + @version_resource ||= expanded_version_relation.put! + end + + def expanded_version_relation + version_params = { + "pacticipant" => pacticipant_name, + "version" => version_number + } + index_resource + ._link("pb:pacticipant-version") + .expand(version_params) + end + + def result_message + if json_output? + (@version_resource || expanded_version_relation.get).response.raw_body + else + message = "Created/updated pacticipant version #{version_number}" + if branch_name && tags.any? + message = message + " with branch #{branch_name} and tag(s) #{tags.join(", ")}" + elsif branch_name + message = message + " with branch #{branch_name}" + elsif tags.any? + message = message + " with tag(s) #{tags.join(", ")}" + end + + message = message + " in #{pact_broker_name}" + green(message) + end + end + end + end + end +end diff --git a/script/update-cli-usage-in-readme.rb b/script/update-cli-usage-in-readme.rb index 04f4ae25..f0d60c9c 100755 --- a/script/update-cli-usage-in-readme.rb +++ b/script/update-cli-usage-in-readme.rb @@ -58,7 +58,7 @@ def generate_thor_docs ["Pacticipants", %w[create-or-update-pacticipant describe-pacticipant list-pacticipants]], ["Webhooks", %w[create-webhook create-or-update-webhook test-webhook]], ["Tags", %w[create-version-tag]], - ["Versions", %w[describe-version]], + ["Versions", %w[describe-version create-or-update-version]], ["Miscellaneous", %w[generate-uuid]] ] diff --git a/spec/lib/pact_broker/client/versions/create_spec.rb b/spec/lib/pact_broker/client/versions/create_spec.rb new file mode 100644 index 00000000..b44a5c38 --- /dev/null +++ b/spec/lib/pact_broker/client/versions/create_spec.rb @@ -0,0 +1,174 @@ +require "pact_broker/client/versions/create" + +module PactBroker + module Client + describe Versions::Create do + describe "#call" do + let(:index_body) do + { + "_links" => { + "pb:pacticipant-branch-version" => { + "href" => "http://broker/pacticipants/{pacticipant}/branches/{branch}/versions/{version}" + }, + "pb:pacticipant-version-tag" => { + "href" => "http://broker/pacticipants/{pacticipant}/versions/{version}/tags/{tag}" + }, + "pb:pacticipant-version" => { + "href" => "http://broker/pacticipants/{pacticipant}/versions/{version}" + } + } + } + end + + let!(:index_request) do + stub_request(:get, "http://broker").to_return(status: 200, body: index_body.to_json, headers: { "Content-Type" => "application/hal+json" } ) + end + + let!(:branch_request) do + stub_request(:put, "http://broker/pacticipants/Foo/branches/main/versions/1").to_return(status: 200, body: "{}", headers: { "Content-Type" => "application/hal+json" } ) + end + + let!(:tag_request) do + stub_request(:put, "http://broker/pacticipants/Foo/versions/1/tags/dev").to_return(status: 200, body: "{}", headers: { "Content-Type" => "application/hal+json" } ) + end + + let!(:create_version_request) do + stub_request(:put, "http://broker/pacticipants/Foo/versions/1").to_return(status: 200, body: { version: "created" }.to_json, headers: { "Content-Type" => "application/hal+json" } ) + end + + let!(:get_version_request) do + stub_request(:get, "http://broker/pacticipants/Foo/versions/1").to_return(status: 200, body: { version: "got" }.to_json, headers: { "Content-Type" => "application/hal+json" } ) + end + + let(:params) do + { + pacticipant_name: "Foo", + version_number: "1", + branch_name: branch_name, + tags: tags + } + end + + let(:branch_name) { "main" } + let(:tags) { ["dev"] } + + let(:options) do + { + verbose: "verbose", + output: output + } + end + + let(:output) { "text" } + + let(:pact_broker_client_options) do + { + token: "token", + pact_broker_base_url: "http://broker" + } + end + + subject { PactBroker::Client::Versions::Create.call(params, options, pact_broker_client_options)} + + context "with a branch and tags" do + it "creates a branch version" do + subject + expect(branch_request).to have_been_made + end + + it "creates the tag" do + subject + expect(tag_request).to have_been_made + end + + it "returns a message" do + expect(subject.message).to include "Created/updated pacticipant version 1 with branch main and tag(s) dev in the Pact Broker" + expect(subject.success).to be true + end + + context "without output json" do + let(:output) { "json" } + + it "returns a json message" do + expect(subject.message).to eq({ version: "got" }.to_json) + end + end + end + + context "with only tags" do + let(:branch_name) { nil } + + it "returns a message" do + expect(subject.message).to include "Created/updated pacticipant version 1 with tag(s) dev in the Pact Broker" + expect(subject.success).to be true + end + + context "without output json" do + let(:output) { "json" } + + it "returns a json message" do + expect(subject.message).to eq({ version: "got" }.to_json) + end + end + end + + context "with only a branch" do + let(:tags) { nil } + + it "returns a message" do + expect(subject.message).to include "Created/updated pacticipant version 1 with branch main in the Pact Broker" + expect(subject.success).to be true + end + + context "without output json" do + let(:output) { "json" } + + it "returns a json message" do + expect(subject.message).to eq({ version: "got" }.to_json) + end + end + end + + context "with no branch or tags" do + let(:tags) { nil } + let(:branch_name) { nil } + + it "creates a version" do + subject + expect(create_version_request).to have_been_made + end + + it "returns a message" do + expect(subject.message).to include "Created/updated pacticipant version 1 in the Pact Broker" + expect(subject.success).to be true + end + + context "without output json" do + let(:output) { "json" } + + it "returns a json message" do + expect(subject.message).to eq({ version: "created" }.to_json) + end + end + end + + context "when the Pact Broker does not support branch versions" do + before do + index_body["_links"].delete("pb:pacticipant-branch-version") + end + + let(:index_body) do + { + "_links" => {} + } + end + + it "returns an error" do + expect(subject.message).to include "does not support branch versions" + expect(subject.success).to be false + end + end + end + end + end +end