pact_broker-client 1.45.0 → 1.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +15 -1
  3. data/CHANGELOG.md +31 -0
  4. data/README.md +51 -47
  5. data/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +315 -1
  6. data/doc/pacts/markdown/Pact Broker Client - Pactflow.md +94 -0
  7. data/doc/pacts/markdown/README.md +1 -0
  8. data/lib/pact_broker/client/cli/broker.rb +9 -139
  9. data/lib/pact_broker/client/cli/custom_thor.rb +0 -16
  10. data/lib/pact_broker/client/cli/matrix_commands.rb +93 -0
  11. data/lib/pact_broker/client/cli/webhook_commands.rb +122 -0
  12. data/lib/pact_broker/client/deployments/record_support_ended.rb +1 -1
  13. data/lib/pact_broker/client/deployments/record_undeployment.rb +1 -1
  14. data/lib/pact_broker/client/matrix/resource.rb +4 -0
  15. data/lib/pact_broker/client/verification_required.rb +34 -0
  16. data/lib/pact_broker/client/version.rb +1 -1
  17. data/lib/pact_broker/client/webhooks/create.rb +14 -8
  18. data/script/record-deployment.sh +1 -1
  19. data/script/record-deployments-and-releases.sh +0 -2
  20. data/script/record-undeployment.sh +1 -1
  21. data/script/webhook-commands.sh +12 -0
  22. data/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb +1 -1
  23. data/spec/lib/pact_broker/client/cli/broker_run_webhook_commands_spec.rb +4 -2
  24. data/spec/lib/pact_broker/client/deployments/record_support_ended_spec.rb +1 -1
  25. data/spec/lib/pact_broker/client/deployments/record_undeployment_spec.rb +1 -1
  26. data/spec/pacts/pact_broker_client-pact_broker.json +317 -1
  27. data/spec/pacts/pact_broker_client-pactflow.json +118 -0
  28. data/spec/service_providers/pact_helper.rb +15 -10
  29. data/spec/service_providers/pactflow_webhooks_create_spec.rb +86 -0
  30. data/spec/service_providers/record_deployment_spec.rb +1 -3
  31. data/spec/service_providers/record_release_spec.rb +1 -3
  32. data/spec/service_providers/record_undeployment_spec.rb +2 -4
  33. data/spec/service_providers/webhooks_create_spec.rb +1 -1
  34. data/spec/spec_helper.rb +1 -0
  35. metadata +12 -3
@@ -0,0 +1,94 @@
1
+ ### A pact between Pact Broker Client and Pactflow
2
+
3
+ #### Requests from Pact Broker Client to Pactflow
4
+
5
+ * [A request for the index resource](#a_request_for_the_index_resource)
6
+
7
+ * [A request to create a webhook for a team](#a_request_to_create_a_webhook_for_a_team_given_a_team_with_UUID_2abbc12a-427d-432a-a521-c870af1739d9_exists) given a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists
8
+
9
+ #### Interactions
10
+
11
+ <a name="a_request_for_the_index_resource"></a>
12
+ Upon receiving **a request for the index resource** from Pact Broker Client, with
13
+ ```json
14
+ {
15
+ "method": "get",
16
+ "path": "/",
17
+ "headers": {
18
+ "Accept": "application/hal+json"
19
+ }
20
+ }
21
+ ```
22
+ Pactflow will respond with:
23
+ ```json
24
+ {
25
+ "status": 200,
26
+ "headers": {
27
+ "Content-Type": "application/hal+json;charset=utf-8"
28
+ },
29
+ "body": {
30
+ "_links": {
31
+ "pb:webhooks": {
32
+ "href": "http://localhost:1235/HAL-REL-PLACEHOLDER-PB-WEBHOOKS"
33
+ },
34
+ "pb:pacticipants": {
35
+ "href": "http://localhost:1235/HAL-REL-PLACEHOLDER-PB-PACTICIPANTS"
36
+ },
37
+ "pb:pacticipant": {
38
+ "href": "http://localhost:1235/HAL-REL-PLACEHOLDER-PB-PACTICIPANT-{pacticipant}"
39
+ }
40
+ }
41
+ }
42
+ }
43
+ ```
44
+ <a name="a_request_to_create_a_webhook_for_a_team_given_a_team_with_UUID_2abbc12a-427d-432a-a521-c870af1739d9_exists"></a>
45
+ Given **a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists**, upon receiving **a request to create a webhook for a team** from Pact Broker Client, with
46
+ ```json
47
+ {
48
+ "method": "post",
49
+ "path": "/HAL-REL-PLACEHOLDER-PB-WEBHOOKS",
50
+ "headers": {
51
+ "Content-Type": "application/json",
52
+ "Accept": "application/hal+json"
53
+ },
54
+ "body": {
55
+ "description": "a webhook",
56
+ "events": [
57
+ {
58
+ "name": "contract_content_changed"
59
+ }
60
+ ],
61
+ "request": {
62
+ "url": "https://webhook",
63
+ "method": "POST",
64
+ "headers": {
65
+ "Foo": "bar",
66
+ "Bar": "foo"
67
+ },
68
+ "body": {
69
+ "some": "body"
70
+ }
71
+ },
72
+ "teamUuid": "2abbc12a-427d-432a-a521-c870af1739d9"
73
+ }
74
+ }
75
+ ```
76
+ Pactflow will respond with:
77
+ ```json
78
+ {
79
+ "status": 201,
80
+ "headers": {
81
+ "Content-Type": "application/hal+json;charset=utf-8"
82
+ },
83
+ "body": {
84
+ "description": "a webhook",
85
+ "teamUuid": "2abbc12a-427d-432a-a521-c870af1739d9",
86
+ "_links": {
87
+ "self": {
88
+ "href": "http://localhost:1234/some-url",
89
+ "title": "A title"
90
+ }
91
+ }
92
+ }
93
+ }
94
+ ```
@@ -1,3 +1,4 @@
1
1
  ### Pacts for Pact Broker Client
2
2
 
3
3
  * [Pact Broker](Pact%20Broker%20Client%20-%20Pact%20Broker.md)
4
+ * [Pactflow](Pact%20Broker%20Client%20-%20Pactflow.md)
@@ -4,61 +4,25 @@ require 'thor/error'
4
4
  require 'pact_broker/client/cli/environment_commands'
5
5
  require 'pact_broker/client/cli/deployment_commands'
6
6
  require 'pact_broker/client/cli/pacticipant_commands'
7
+ require 'pact_broker/client/cli/webhook_commands'
8
+ require "pact_broker/client/cli/matrix_commands"
7
9
 
8
10
  module PactBroker
9
11
  module Client
10
12
  module CLI
11
13
  # Thor::Error will have its backtrace hidden
12
14
  class PactPublicationError < ::Thor::Error; end
13
- class WebhookCreationError < ::Thor::Error; end
14
15
  class AuthError < ::Thor::Error; end
15
16
  class VersionCreationError < ::Thor::Error; end
16
17
 
17
18
  class Broker < CustomThor
18
19
  using PactBroker::Client::HashRefinements
19
- if ENV.fetch("PACT_BROKER_FEATURES", "").include?("deployments")
20
- include PactBroker::Client::CLI::EnvironmentCommands
21
- include PactBroker::Client::CLI::DeploymentCommands
22
- end
23
- include PactBroker::Client::CLI::PacticipantCommands
24
-
25
-
26
- desc 'can-i-deploy', ''
27
- long_desc File.read(File.join(__dir__, 'can_i_deploy_long_desc.txt'))
28
-
29
- method_option :pacticipant, required: true, aliases: "-a", desc: "The pacticipant name. Use once for each pacticipant being checked."
30
- method_option :version, required: false, aliases: "-e", desc: "The pacticipant version. Must be entered after the --pacticipant that it relates to."
31
- method_option :ignore, required: false, desc: "The pacticipant name to ignore. Use once for each pacticipant being ignored. A specific version can be ignored by also specifying a --version after the pacticipant name option."
32
- method_option :latest, required: false, aliases: "-l", banner: '[TAG]', desc: "Use the latest pacticipant version. Optionally specify a TAG to use the latest version with the specified tag."
33
- method_option :to, required: false, banner: 'TAG', desc: "This is too hard to explain in a short sentence. Look at the examples.", default: nil
34
- method_option :to_environment, required: false, banner: 'ENVIRONMENT', desc: "The environment into which the pacticipant(s) are to be deployed", default: nil, hide: true
35
- method_option :output, aliases: "-o", desc: "json or table", default: 'table'
36
- method_option :retry_while_unknown, banner: 'TIMES', type: :numeric, default: 0, required: false, desc: "The number of times to retry while there is an unknown verification result (ie. the provider verification is likely still running)"
37
- method_option :retry_interval, banner: 'SECONDS', type: :numeric, default: 10, required: false, desc: "The time between retries in seconds. Use in conjuction with --retry-while-unknown"
38
- # Allow limit to be set manually until https://github.com/pact-foundation/pact_broker-client/issues/53 is fixed
39
- method_option :limit, hide: true
40
- method_option :dry_run, type: :boolean, default: false, desc: "When dry-run is enabled, always exit process with a success code. Can also be enabled by setting the environment variable PACT_BROKER_CAN_I_DEPLOY_DRY_RUN=true."
41
- shared_authentication_options
42
20
 
43
- def can_i_deploy(*ignored_but_necessary)
44
- require 'pact_broker/client/cli/version_selector_options_parser'
45
- require 'pact_broker/client/can_i_deploy'
46
-
47
- validate_credentials
48
- selectors = VersionSelectorOptionsParser.call(ARGV).select { |s| !s[:ignore] }
49
- ignore_selectors = if ENV.fetch("PACT_BROKER_FEATURES", "").include?("ignore")
50
- VersionSelectorOptionsParser.call(ARGV).select { |s| s[:ignore] }
51
- else
52
- []
53
- end
54
- validate_can_i_deploy_selectors(selectors)
55
- dry_run = options.dry_run || ENV["PACT_BROKER_CAN_I_DEPLOY_DRY_RUN"] == "true"
56
- can_i_deploy_options = { output: options.output, retry_while_unknown: options.retry_while_unknown, retry_interval: options.retry_interval, dry_run: dry_run }
57
- result = CanIDeploy.call(options.broker_base_url, selectors, { to_tag: options.to, to_environment: options.to_environment, limit: options.limit, ignore_selectors: ignore_selectors }, can_i_deploy_options, pact_broker_client_options)
58
- $stdout.puts result.message
59
- $stdout.flush
60
- exit(can_i_deploy_exit_status) unless result.success
61
- end
21
+ include PactBroker::Client::CLI::EnvironmentCommands
22
+ include PactBroker::Client::CLI::DeploymentCommands
23
+ include PactBroker::Client::CLI::MatrixCommands
24
+ include PactBroker::Client::CLI::PacticipantCommands
25
+ include PactBroker::Client::CLI::WebhookCommands
62
26
 
63
27
  desc 'publish PACT_DIRS_OR_FILES ...', "Publish pacts to a Pact Broker."
64
28
  method_option :consumer_app_version, required: true, aliases: "-a", desc: "The consumer application version"
@@ -67,7 +31,9 @@ module PactBroker
67
31
  method_option :tag, aliases: "-t", type: :array, banner: "TAG", desc: "Tag name for consumer version. Can be specified multiple times."
68
32
  method_option :tag_with_git_branch, aliases: "-g", type: :boolean, default: false, required: false, desc: "Tag consumer version with the name of the current git branch. Default: false"
69
33
  method_option :build_url, desc: "The build URL that created the pact"
34
+ method_option :on_conflict, desc: "If a pact already exists for this consumer version and provider with different content, specify what action should be taken. Options are "
70
35
  method_option :merge, type: :boolean, default: false, require: false, desc: "If a pact already exists for this consumer version and provider, merge the contents. Useful when running Pact tests concurrently on different build nodes."
36
+
71
37
  output_option_json_or_text
72
38
  shared_authentication_options
73
39
 
@@ -131,31 +97,7 @@ module PactBroker
131
97
  exit(1) unless result.success
132
98
  end
133
99
 
134
- shared_options_for_webhook_commands
135
-
136
- desc 'create-webhook URL', 'Creates a webhook using the same switches as a curl request.'
137
- long_desc File.read(File.join(File.dirname(__FILE__), 'create_webhook_long_desc.txt'))
138
- def create_webhook webhook_url
139
- run_webhook_commands webhook_url
140
- end
141
-
142
- shared_options_for_webhook_commands
143
- method_option :uuid, type: :string, required: true, desc: "Specify the uuid for the webhook"
144
100
 
145
- desc 'create-or-update-webhook URL', 'Creates or updates a webhook with a provided uuid and using the same switches as a curl request.'
146
- long_desc File.read(File.join(File.dirname(__FILE__), 'create_or_update_webhook_long_desc.txt'))
147
- def create_or_update_webhook webhook_url
148
- run_webhook_commands webhook_url
149
- end
150
-
151
- desc 'test-webhook', 'Test the execution of a webhook'
152
- method_option :uuid, type: :string, required: true, desc: "Specify the uuid for the webhook"
153
- shared_authentication_options
154
- def test_webhook
155
- require 'pact_broker/client/webhooks/test'
156
- result = PactBroker::Client::Webhooks::Test.call(options, pact_broker_client_options)
157
- $stdout.puts result.message
158
- end
159
101
 
160
102
  ignored_and_hidden_potential_options_from_environment_variables
161
103
  desc 'generate-uuid', 'Generate a UUID for use when calling create-or-update-webhook'
@@ -189,16 +131,6 @@ module PactBroker
189
131
  true
190
132
  end
191
133
 
192
- def can_i_deploy_exit_status
193
- exit_code_string = ENV.fetch('PACT_BROKER_CAN_I_DEPLOY_EXIT_CODE_BETA', '')
194
- if exit_code_string =~ /^\d+$/
195
- $stderr.puts "Exiting can-i-deploy with configured exit code #{exit_code_string}"
196
- exit_code_string.to_i
197
- else
198
- 1
199
- end
200
- end
201
-
202
134
  def validate_credentials
203
135
  if options.broker_username && options.broker_token
204
136
  raise AuthError, "You cannot provide both a username/password and a bearer token. If your Pact Broker uses a bearer token, please remove the username and password configuration."
@@ -211,10 +143,6 @@ module PactBroker
211
143
  end
212
144
  end
213
145
 
214
- def validate_can_i_deploy_selectors selectors
215
- pacticipants_without_versions = selectors.select{ |s| s[:version].nil? && s[:latest].nil? && s[:tag].nil? }.collect{ |s| s[:pacticipant] }
216
- raise ::Thor::RequiredArgumentMissingError, "The version must be specified using `--version VERSION`, `--latest`, `--latest TAG`, or `--all TAG` for pacticipant #{pacticipants_without_versions.join(", ")}" if pacticipants_without_versions.any?
217
- end
218
146
 
219
147
  def publish_pacts pact_files
220
148
  require 'pact_broker/client/publish_pacts'
@@ -297,64 +225,6 @@ module PactBroker
297
225
 
298
226
  client_options.compact
299
227
  end
300
-
301
- def parse_webhook_events
302
- events = []
303
- events << 'contract_content_changed' if options.contract_content_changed
304
- events << 'contract_published' if options.contract_published
305
- events << 'provider_verification_published' if options.provider_verification_published
306
- events << 'provider_verification_succeeded' if options.provider_verification_succeeded
307
- events << 'provider_verification_failed' if options.provider_verification_failed
308
- events
309
- end
310
-
311
- def parse_webhook_options(webhook_url)
312
- events = parse_webhook_events
313
-
314
- if events.size == 0
315
- raise WebhookCreationError.new("You must specify at least one of --contract-content-changed, --contract-published, --provider-verification-published, --provider-verification-succeeded or --provider-verification-failed")
316
- end
317
-
318
- username = options.user ? options.user.split(":", 2).first : nil
319
- password = options.user ? options.user.split(":", 2).last : nil
320
-
321
- headers = (options.header || []).each_with_object({}) { | header, headers | headers[header.split(":", 2).first.strip] = header.split(":", 2).last.strip }
322
-
323
- body = options.data
324
- if body && body.start_with?("@")
325
- filepath = body[1..-1]
326
- begin
327
- body = File.read(filepath)
328
- rescue StandardError => e
329
- raise WebhookCreationError.new("Couldn't read data from file \"#{filepath}\" due to #{e.class} #{e.message}")
330
- end
331
- end
332
-
333
- {
334
- uuid: options.uuid,
335
- description: options.description,
336
- http_method: options.request,
337
- url: webhook_url,
338
- headers: headers,
339
- username: username,
340
- password: password,
341
- body: body,
342
- consumer: options.consumer,
343
- provider: options.provider,
344
- events: events
345
- }
346
- end
347
-
348
- def run_webhook_commands webhook_url
349
- require 'pact_broker/client/webhooks/create'
350
-
351
- validate_credentials
352
- result = PactBroker::Client::Webhooks::Create.call(parse_webhook_options(webhook_url), options.broker_base_url, pact_broker_client_options)
353
- $stdout.puts result.message
354
- exit(1) unless result.success
355
- rescue PactBroker::Client::Error => e
356
- raise WebhookCreationError, "#{e.class} - #{e.message}"
357
- end
358
228
  end
359
229
  end
360
230
  end
@@ -91,22 +91,6 @@ module PactBroker
91
91
  method_option :verbose, aliases: "-v", type: :boolean, default: false, required: false, desc: "Verbose output. Default: false"
92
92
  end
93
93
 
94
- def self.shared_options_for_webhook_commands
95
- method_option :request, banner: "METHOD", aliases: "-X", desc: "Webhook HTTP method", required: true
96
- method_option :header, aliases: "-H", type: :array, desc: "Webhook Header"
97
- method_option :data, aliases: "-d", desc: "Webhook payload (file or string)"
98
- method_option :user, aliases: "-u", desc: "Webhook basic auth username and password eg. username:password"
99
- method_option :consumer, desc: "Consumer name"
100
- method_option :provider, desc: "Provider name"
101
- method_option :description, desc: "Wwebhook description"
102
- method_option :contract_content_changed, type: :boolean, desc: "Trigger this webhook when the pact content changes"
103
- method_option :contract_published, type: :boolean, desc: "Trigger this webhook when a pact is published"
104
- method_option :provider_verification_published, type: :boolean, desc: "Trigger this webhook when a provider verification result is published"
105
- method_option :provider_verification_failed, type: :boolean, desc: "Trigger this webhook when a failed provider verification result is published"
106
- method_option :provider_verification_succeeded, type: :boolean, desc: "Trigger this webhook when a successful provider verification result is published"
107
- shared_authentication_options
108
- end
109
-
110
94
  def self.verbose_option
111
95
  method_option :verbose, aliases: "-v", type: :boolean, default: false, required: false, desc: "Verbose output. Default: false"
112
96
  end
@@ -0,0 +1,93 @@
1
+ module PactBroker
2
+ module Client
3
+ module CLI
4
+ module MatrixCommands
5
+
6
+ def self.included(thor)
7
+ thor.class_eval do
8
+ desc "can-i-deploy", ""
9
+ long_desc File.read(File.join(__dir__, "can_i_deploy_long_desc.txt"))
10
+
11
+ method_option :pacticipant, required: true, aliases: "-a", desc: "The pacticipant name. Use once for each pacticipant being checked."
12
+ method_option :version, required: false, aliases: "-e", desc: "The pacticipant version. Must be entered after the --pacticipant that it relates to."
13
+ method_option :ignore, required: false, desc: "The pacticipant name to ignore. Use once for each pacticipant being ignored. A specific version can be ignored by also specifying a --version after the pacticipant name option."
14
+ method_option :latest, required: false, aliases: "-l", banner: "[TAG]", desc: "Use the latest pacticipant version. Optionally specify a TAG to use the latest version with the specified tag."
15
+ method_option :to, required: false, banner: "TAG", desc: "This is too hard to explain in a short sentence. Look at the examples.", default: nil
16
+ method_option :to_environment, required: false, banner: "ENVIRONMENT", desc: "The environment into which the pacticipant(s) are to be deployed", default: nil, hide: true
17
+ method_option :output, aliases: "-o", desc: "json or table", default: "table"
18
+ method_option :retry_while_unknown, banner: "TIMES", type: :numeric, default: 0, required: false, desc: "The number of times to retry while there is an unknown verification result (ie. the provider verification is likely still running)"
19
+ method_option :retry_interval, banner: "SECONDS", type: :numeric, default: 10, required: false, desc: "The time between retries in seconds. Use in conjuction with --retry-while-unknown"
20
+ # Allow limit to be set manually until https://github.com/pact-foundation/pact_broker-client/issues/53 is fixed
21
+ method_option :limit, hide: true
22
+ method_option :dry_run, type: :boolean, default: false, desc: "When dry-run is enabled, always exit process with a success code. Can also be enabled by setting the environment variable PACT_BROKER_CAN_I_DEPLOY_DRY_RUN=true."
23
+ shared_authentication_options
24
+
25
+ def can_i_deploy(*ignored_but_necessary)
26
+ require "pact_broker/client/cli/version_selector_options_parser"
27
+ require "pact_broker/client/can_i_deploy"
28
+
29
+ validate_credentials
30
+ selectors = VersionSelectorOptionsParser.call(ARGV).select { |s| !s[:ignore] }
31
+ ignore_selectors = if ENV.fetch("PACT_BROKER_FEATURES", "").include?("ignore")
32
+ VersionSelectorOptionsParser.call(ARGV).select { |s| s[:ignore] }
33
+ else
34
+ []
35
+ end
36
+ validate_can_i_deploy_selectors(selectors)
37
+ dry_run = options.dry_run || ENV["PACT_BROKER_CAN_I_DEPLOY_DRY_RUN"] == "true"
38
+ can_i_deploy_options = { output: options.output, retry_while_unknown: options.retry_while_unknown, retry_interval: options.retry_interval, dry_run: dry_run, verbose: options.verbose }
39
+ result = CanIDeploy.call(options.broker_base_url, selectors, { to_tag: options.to, to_environment: options.to_environment, limit: options.limit, ignore_selectors: ignore_selectors }, can_i_deploy_options, pact_broker_client_options)
40
+ $stdout.puts result.message
41
+ $stdout.flush
42
+ exit(can_i_deploy_exit_status) unless result.success
43
+ end
44
+
45
+ if ENV.fetch("PACT_BROKER_FEATURES", "").include?("verification_required")
46
+
47
+ method_option :pacticipant, required: true, aliases: "-a", desc: "The pacticipant name. Use once for each pacticipant being checked."
48
+ method_option :version, required: false, aliases: "-e", desc: "The pacticipant version. Must be entered after the --pacticipant that it relates to."
49
+ method_option :latest, required: false, aliases: "-l", banner: "[TAG]", desc: "Use the latest pacticipant version. Optionally specify a TAG to use the latest version with the specified tag."
50
+ method_option :to, required: false, banner: "TAG", desc: "This is too hard to explain in a short sentence. Look at the examples.", default: nil
51
+ method_option :in_environment, required: false, banner: "ENVIRONMENT", desc: "The environment into which the pacticipant(s) are to be deployed", default: nil, hide: true
52
+ method_option :output, aliases: "-o", desc: "json or table", default: "table"
53
+
54
+ shared_authentication_options
55
+ desc "verification-required", "Checks if there is a verification required between the given pacticipant versions"
56
+ def verification_required(*ignored_but_necessary)
57
+ require "pact_broker/client/cli/version_selector_options_parser"
58
+ require "pact_broker/client/verification_required"
59
+
60
+ validate_credentials
61
+ selectors = VersionSelectorOptionsParser.call(ARGV)
62
+ validate_can_i_deploy_selectors(selectors)
63
+ verification_required_options = { output: options.output, verbose: options.verbose, retry_while_unknown: 0 }
64
+ result = VerificationRequired.call(options.broker_base_url, selectors, { to_tag: options.to, to_environment: options.in_environment, ignore_selectors: [] }, verification_required_options, pact_broker_client_options)
65
+ $stdout.puts result.message
66
+ $stdout.flush
67
+ exit(1) unless result.success
68
+ end
69
+
70
+ end
71
+
72
+ no_commands do
73
+ def can_i_deploy_exit_status
74
+ exit_code_string = ENV.fetch("PACT_BROKER_CAN_I_DEPLOY_EXIT_CODE_BETA", "")
75
+ if exit_code_string =~ /^\d+$/
76
+ $stderr.puts "Exiting can-i-deploy with configured exit code #{exit_code_string}"
77
+ exit_code_string.to_i
78
+ else
79
+ 1
80
+ end
81
+ end
82
+
83
+ def validate_can_i_deploy_selectors selectors
84
+ pacticipants_without_versions = selectors.select{ |s| s[:version].nil? && s[:latest].nil? && s[:tag].nil? }.collect{ |s| s[:pacticipant] }
85
+ raise ::Thor::RequiredArgumentMissingError, "The version must be specified using `--version VERSION`, `--latest`, `--latest TAG`, or `--all TAG` for pacticipant #{pacticipants_without_versions.join(", ")}" if pacticipants_without_versions.any?
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,122 @@
1
+ module PactBroker
2
+ module Client
3
+ module CLI
4
+ # Thor::Error will have its backtrace hidden
5
+ class WebhookCreationError < ::Thor::Error; end
6
+
7
+ module WebhookCommands
8
+ def self.included(thor)
9
+ thor.class_eval do
10
+
11
+ no_commands do
12
+ def self.shared_options_for_webhook_commands
13
+ method_option :request, banner: "METHOD", aliases: "-X", desc: "Webhook HTTP method", required: true
14
+ method_option :header, aliases: "-H", type: :array, desc: "Webhook Header"
15
+ method_option :data, aliases: "-d", desc: "Webhook payload (file or string)"
16
+ method_option :user, aliases: "-u", desc: "Webhook basic auth username and password eg. username:password"
17
+ method_option :consumer, desc: "Consumer name"
18
+ method_option :provider, desc: "Provider name"
19
+ method_option :description, desc: "Webhook description"
20
+ method_option :contract_content_changed, type: :boolean, desc: "Trigger this webhook when the pact content changes"
21
+ method_option :contract_published, type: :boolean, desc: "Trigger this webhook when a pact is published"
22
+ method_option :provider_verification_published, type: :boolean, desc: "Trigger this webhook when a provider verification result is published"
23
+ method_option :provider_verification_failed, type: :boolean, desc: "Trigger this webhook when a failed provider verification result is published"
24
+ method_option :provider_verification_succeeded, type: :boolean, desc: "Trigger this webhook when a successful provider verification result is published"
25
+ method_option :team_uuid, banner: "UUID", desc: "UUID of the Pactflow team to which the webhook should be assigned (Pactflow only)"
26
+ shared_authentication_options
27
+ end
28
+ end
29
+
30
+ shared_options_for_webhook_commands
31
+
32
+ desc 'create-webhook URL', 'Creates a webhook using the same switches as a curl request.'
33
+ long_desc File.read(File.join(File.dirname(__FILE__), 'create_webhook_long_desc.txt'))
34
+ def create_webhook webhook_url
35
+ run_webhook_commands webhook_url
36
+ end
37
+
38
+ shared_options_for_webhook_commands
39
+ method_option :uuid, type: :string, required: true, desc: "Specify the uuid for the webhook"
40
+
41
+ desc 'create-or-update-webhook URL', 'Creates or updates a webhook with a provided uuid and using the same switches as a curl request.'
42
+ long_desc File.read(File.join(File.dirname(__FILE__), 'create_or_update_webhook_long_desc.txt'))
43
+ def create_or_update_webhook webhook_url
44
+ run_webhook_commands webhook_url
45
+ end
46
+
47
+ desc 'test-webhook', 'Test the execution of a webhook'
48
+ method_option :uuid, type: :string, required: true, desc: "Specify the uuid for the webhook"
49
+ shared_authentication_options
50
+ def test_webhook
51
+ require 'pact_broker/client/webhooks/test'
52
+ result = PactBroker::Client::Webhooks::Test.call(options, pact_broker_client_options)
53
+ $stdout.puts result.message
54
+ end
55
+
56
+ no_commands do
57
+
58
+ def parse_webhook_events
59
+ events = []
60
+ events << 'contract_content_changed' if options.contract_content_changed
61
+ events << 'contract_published' if options.contract_published
62
+ events << 'provider_verification_published' if options.provider_verification_published
63
+ events << 'provider_verification_succeeded' if options.provider_verification_succeeded
64
+ events << 'provider_verification_failed' if options.provider_verification_failed
65
+ events
66
+ end
67
+
68
+ def parse_webhook_options(webhook_url)
69
+ events = parse_webhook_events
70
+
71
+ if events.size == 0
72
+ raise WebhookCreationError.new("You must specify at least one of --contract-content-changed, --contract-published, --provider-verification-published, --provider-verification-succeeded or --provider-verification-failed")
73
+ end
74
+
75
+ username = options.user ? options.user.split(":", 2).first : nil
76
+ password = options.user ? options.user.split(":", 2).last : nil
77
+
78
+ headers = (options.header || []).each_with_object({}) { | header, headers | headers[header.split(":", 2).first.strip] = header.split(":", 2).last.strip }
79
+
80
+ body = options.data
81
+ if body && body.start_with?("@")
82
+ filepath = body[1..-1]
83
+ begin
84
+ body = File.read(filepath)
85
+ rescue StandardError => e
86
+ raise WebhookCreationError.new("Couldn't read data from file \"#{filepath}\" due to #{e.class} #{e.message}")
87
+ end
88
+ end
89
+
90
+ {
91
+ uuid: options.uuid,
92
+ description: options.description,
93
+ http_method: options.request,
94
+ url: webhook_url,
95
+ headers: headers,
96
+ username: username,
97
+ password: password,
98
+ body: body,
99
+ consumer: options.consumer,
100
+ provider: options.provider,
101
+ events: events,
102
+ team_uuid: options.team_uuid
103
+ }
104
+ end
105
+
106
+ def run_webhook_commands webhook_url
107
+ require 'pact_broker/client/webhooks/create'
108
+
109
+ validate_credentials
110
+ result = PactBroker::Client::Webhooks::Create.call(parse_webhook_options(webhook_url), options.broker_base_url, pact_broker_client_options)
111
+ $stdout.puts result.message
112
+ exit(1) unless result.success
113
+ rescue PactBroker::Client::Error => e
114
+ raise WebhookCreationError, "#{e.class} - #{e.message}"
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end