pact_broker-client 1.39.0 → 1.44.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +21 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +52 -0
  5. data/Gemfile +4 -0
  6. data/README.md +39 -18
  7. data/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +79 -280
  8. data/lib/pact_broker/client/backports.rb +9 -0
  9. data/lib/pact_broker/client/base_command.rb +95 -0
  10. data/lib/pact_broker/client/can_i_deploy.rb +20 -3
  11. data/lib/pact_broker/client/cli/broker.rb +20 -75
  12. data/lib/pact_broker/client/cli/custom_thor.rb +12 -0
  13. data/lib/pact_broker/client/cli/deployment_commands.rb +74 -0
  14. data/lib/pact_broker/client/cli/environment_commands.rb +70 -0
  15. data/lib/pact_broker/client/cli/pacticipant_commands.rb +53 -0
  16. data/lib/pact_broker/client/cli/record_deployment_long_desc.txt +0 -55
  17. data/lib/pact_broker/client/cli/version_selector_options_parser.rb +4 -0
  18. data/lib/pact_broker/client/colorize_notices.rb +31 -0
  19. data/lib/pact_broker/client/deployments.rb +4 -0
  20. data/lib/pact_broker/client/deployments/record_deployment.rb +38 -0
  21. data/lib/pact_broker/client/deployments/record_release.rb +99 -0
  22. data/lib/pact_broker/client/deployments/record_undeployment.rb +120 -0
  23. data/lib/pact_broker/client/describe_text_formatter.rb +23 -0
  24. data/lib/pact_broker/client/environments.rb +6 -0
  25. data/lib/pact_broker/client/environments/create_environment.rb +31 -0
  26. data/lib/pact_broker/client/environments/delete_environment.rb +27 -0
  27. data/lib/pact_broker/client/environments/describe_environment.rb +26 -0
  28. data/lib/pact_broker/client/environments/environment_command.rb +66 -0
  29. data/lib/pact_broker/client/environments/list_environments.rb +30 -0
  30. data/lib/pact_broker/client/environments/text_formatter.rb +30 -0
  31. data/lib/pact_broker/client/environments/update_environment.rb +31 -0
  32. data/lib/pact_broker/client/generate_display_name.rb +27 -0
  33. data/lib/pact_broker/client/hal/entity.rb +14 -4
  34. data/lib/pact_broker/client/hal/http_client.rb +8 -2
  35. data/lib/pact_broker/client/hal/link.rb +8 -0
  36. data/lib/pact_broker/client/hal_client_methods.rb +1 -3
  37. data/lib/pact_broker/client/matrix.rb +4 -0
  38. data/lib/pact_broker/client/matrix/abbreviate_version_number.rb +15 -0
  39. data/lib/pact_broker/client/matrix/resource.rb +26 -1
  40. data/lib/pact_broker/client/matrix/text_formatter.rb +28 -17
  41. data/lib/pact_broker/client/pacticipants.rb +6 -0
  42. data/lib/pact_broker/client/pacticipants/create.rb +24 -34
  43. data/lib/pact_broker/client/pacticipants/describe.rb +33 -0
  44. data/lib/pact_broker/client/pacticipants/list.rb +34 -0
  45. data/lib/pact_broker/client/pacticipants/text_formatter.rb +41 -0
  46. data/lib/pact_broker/client/publish_pacts.rb +7 -3
  47. data/lib/pact_broker/client/string_refinements.rb +56 -0
  48. data/lib/pact_broker/client/version.rb +1 -1
  49. data/lib/pact_broker/client/versions.rb +4 -1
  50. data/lib/pact_broker/client/versions/describe.rb +3 -1
  51. data/lib/pact_broker/client/versions/formatter.rb +3 -1
  52. data/lib/pact_broker/client/versions/json_formatter.rb +5 -3
  53. data/lib/pact_broker/client/versions/text_formatter.rb +3 -1
  54. data/pact-broker-client.gemspec +2 -0
  55. data/script/approve-all.sh +6 -0
  56. data/script/publish-pact.sh +24 -6
  57. data/script/record-deployments-and-releases.sh +10 -0
  58. data/spec/fixtures/approvals/can_i_deploy_ignore.approved.txt +13 -0
  59. data/spec/fixtures/approvals/describe_environment.approved.txt +7 -0
  60. data/spec/fixtures/approvals/describe_pacticipant.approved.txt +2 -0
  61. data/spec/fixtures/approvals/list_environments.approved.txt +3 -0
  62. data/spec/integration/describe_environment_spec.rb +31 -0
  63. data/spec/lib/pact_broker/client/can_i_deploy_spec.rb +47 -5
  64. data/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb +5 -5
  65. data/spec/lib/pact_broker/client/cli/broker_publish_spec.rb +1 -1
  66. data/spec/lib/pact_broker/client/cli/broker_run_webhook_commands_spec.rb +3 -3
  67. data/spec/lib/pact_broker/client/cli/version_selector_options_parser_spec.rb +21 -0
  68. data/spec/lib/pact_broker/client/deployments/record_deployment_spec.rb +204 -0
  69. data/spec/lib/pact_broker/client/environments/delete_environment_spec.rb +120 -0
  70. data/spec/lib/pact_broker/client/environments/describe_environment_spec.rb +89 -0
  71. data/spec/lib/pact_broker/client/environments/update_environment_spec.rb +167 -0
  72. data/spec/lib/pact_broker/client/generate_display_name_spec.rb +39 -0
  73. data/spec/lib/pact_broker/client/hal/entity_spec.rb +2 -2
  74. data/spec/lib/pact_broker/client/pacticipants/create_spec.rb +2 -2
  75. data/spec/pacts/pact_broker_client-pact_broker.json +88 -287
  76. data/spec/service_providers/create_environment_spec.rb +78 -0
  77. data/spec/service_providers/list_environments_spec.rb +77 -0
  78. data/spec/service_providers/pact_broker_client_matrix_ignore_spec.rb +98 -0
  79. data/spec/service_providers/pacticipants_create_spec.rb +5 -4
  80. data/spec/service_providers/publish_pacts_spec.rb +5 -2
  81. data/spec/service_providers/record_deployment_spec.rb +17 -36
  82. data/spec/service_providers/record_release_spec.rb +135 -0
  83. data/spec/spec_helper.rb +15 -2
  84. data/spec/support/approvals.rb +26 -0
  85. data/spec/support/shared_context.rb +6 -2
  86. data/tasks/pact.rake +19 -1
  87. metadata +93 -7
  88. data/lib/pact_broker/client/versions/record_deployment.rb +0 -109
  89. data/lib/pact_broker/client/versions/record_undeployment.rb +0 -102
  90. data/spec/lib/pact_broker/client/versions/record_deployment_spec.rb +0 -82
@@ -0,0 +1,53 @@
1
+ module PactBroker
2
+ module Client
3
+ module CLI
4
+ module PacticipantCommands
5
+ PACTICIPANT_PARAM_NAMES = [:name, :display_name, :repository_url]
6
+
7
+ def self.included(thor)
8
+ thor.class_eval do
9
+ desc 'create-or-update-pacticipant', 'Create or update pacticipant by name'
10
+ method_option :name, type: :string, required: true, desc: "Pacticipant name"
11
+ method_option :display_name, type: :string, desc: "Display name"
12
+ method_option :repository_url, type: :string, required: false, desc: "The repository URL of the pacticipant"
13
+ output_option_json_or_text
14
+ shared_authentication_options
15
+ verbose_option
16
+
17
+ def create_or_update_pacticipant(*required_but_ignored)
18
+ raise ::Thor::RequiredArgumentMissingError, "Pacticipant name cannot be blank" if options.name.strip.size == 0
19
+ execute_pacticipant_command(params_from_options(PACTICIPANT_PARAM_NAMES), 'Create')
20
+ end
21
+
22
+ desc 'list-pacticipants', 'List pacticipants'
23
+ output_option_json_or_text
24
+ shared_authentication_options
25
+ verbose_option
26
+ def list_pacticipants
27
+ execute_pacticipant_command(params_from_options(PACTICIPANT_PARAM_NAMES), 'List')
28
+ end
29
+
30
+ desc 'describe-pacticipant', "Describe a pacticipant"
31
+ method_option :name, type: :string, required: true, desc: "Pacticipant name"
32
+ output_option_json_or_text
33
+ shared_authentication_options
34
+ verbose_option
35
+ def describe_pacticipant
36
+ execute_pacticipant_command({ name: options.name }, 'Describe')
37
+ end
38
+
39
+ no_commands do
40
+ def execute_pacticipant_command(params, command_class_name)
41
+ require 'pact_broker/client/pacticipants'
42
+ command_options = { verbose: options.verbose, output: options.output }
43
+ result = PactBroker::Client::Pacticipants2.const_get(command_class_name).call(params, command_options, pact_broker_client_options)
44
+ $stdout.puts result.message
45
+ exit(1) unless result.success
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,55 +0,0 @@
1
- The record-deployment command is used to allow the Pact Broker to keep track of which version(s) of an application are currently deployed in each environment. It is used to keep track of applications that are deployed to known instances. If you are releasing a client library or mobile application to a repository or application store, please use record-release instead.
2
-
3
- ## Examples
4
-
5
-
6
- record-deployment --pacticipant Foo --version 6897aa95e --environment production
7
- record-deployment --pacticipant Foo --version 6897aa95e --environment production --target blue
8
- record-deployment --pacticipant Foo --version 6897aa95e --environment production --target green
9
-
10
- ## Target
11
-
12
- The "target" field is used to distinguish between deployed versions of an application within the same environment, and most importantly, to identify which previously deployed version has been replaced by the current deployment. The Pact Broker only allows one unique combination of pacticipant/environment/target to be considered the "currently deployed" one, and any call to record a deployment will cause the previously deployed version with the same pacticipant/environment/target to be automatically marked as undeployed (mimicking the real world process of "deploying over" a previous version).
13
-
14
- ### Use cases
15
-
16
- #### There is a single instance of an application deployed within an environment and deployments of integrated applications are NOT likely to happen during the deployment window of this application
17
-
18
- eg.
19
-
20
- * the window of time when there are multiple versions in prod is small
21
- * or there aren't many other integrations
22
- * or deployments happen rarely
23
- * or the same team controls all the deployments and generally only runs one deployment at a time
24
-
25
- In this case, there is no need to specify a target. The call to record deployment should be done at the end of the deployment and it will automatically mark the version of Foo that was previously the currently deployed version as undeployed. Only one version of the pacticipant is ever considered to be currently deployed at a time.
26
-
27
- eg.
28
-
29
- # actual call to deploy here...
30
- record-deployment --pacticipant Foo --version 6897aa95e --environment production
31
-
32
- #### There is a single instance of an application deployed within an environment and but deployments of integrated applications ARE likely to happen during the deployment window of this application
33
-
34
- eg.
35
- * the window of time when there are multiple versions in prod is large
36
- * or there are many integrations
37
- * or deployments happen often
38
- * or there are many different teams deploying and deployments aren't coordinated
39
-
40
- To allow multiple versions to be considered currently deployed at the same time, use two different targets, and call the first record-deployment at the start of the deployment process and a second one at the end.
41
-
42
- eg.
43
-
44
- This will use the targets "blue" and "green" to model stages of the deployment.
45
-
46
- record-deployment --pacticipant Foo --version 6897aa95e --environment production --target blue
47
- # actual call to deploy here...
48
- record-deployment --pacticipant Foo --version 6897aa95e --environment production --target green
49
-
50
- After the first call to record-deployment, there will be two versions considered currently deployed - the "blue" one that was just recorded, and the one from the previous "green" deployment. After the second call to record-deployment, there is only one version considered currently deployed - both "blue" and "green" targets will be have version 6897aa95e deployed to them.
51
-
52
-
53
- #### There are multiple permanent application versions deployed to the same environment
54
-
55
- TBC
@@ -12,6 +12,8 @@ module PactBroker
12
12
  case word
13
13
  when "--pacticipant", "-a"
14
14
  selectors << {}
15
+ when "--ignore"
16
+ selectors << { ignore: true }
15
17
  when "--latest", "-l"
16
18
  selectors << { pacticipant: nil } if selectors.empty?
17
19
  selectors.last[:latest] = true
@@ -21,6 +23,8 @@ module PactBroker
21
23
  case previous_option
22
24
  when "--pacticipant", "-a"
23
25
  selectors.last[:pacticipant] = word
26
+ when "--ignore"
27
+ selectors.last[:pacticipant] = word
24
28
  when "--version", "-e"
25
29
  selectors << { pacticipant: nil } if selectors.empty?
26
30
  selectors.last[:version] = word
@@ -0,0 +1,31 @@
1
+ require 'term/ansicolor'
2
+
3
+ module PactBroker
4
+ module Client
5
+ class ColorizeNotices
6
+ def self.call(notices)
7
+ notices.collect do | notice |
8
+ colorized_message(notice)
9
+ end
10
+ end
11
+
12
+ def self.colorized_message(notice)
13
+ color = color_for_type(notice.type)
14
+ if color
15
+ ::Term::ANSIColor.color(color, notice.text || '')
16
+ else
17
+ notice.text
18
+ end
19
+ end
20
+
21
+ def self.color_for_type(type)
22
+ case type
23
+ when "warning", "prompt" then "yellow"
24
+ when "error", "danger" then :red
25
+ when "success" then :green
26
+ else nil
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,4 @@
1
+ require 'pact_broker/client/deployments/record_deployment'
2
+ require 'pact_broker/client/deployments/record_release'
3
+ require 'pact_broker/client/deployments/record_undeployment'
4
+
@@ -0,0 +1,38 @@
1
+ require 'pact_broker/client/deployments/record_release'
2
+
3
+ module PactBroker
4
+ module Client
5
+ module Deployments
6
+ class RecordDeployment < PactBroker::Client::Deployments::RecordRelease
7
+ def initialize(params, options, pact_broker_client_options)
8
+ super
9
+ @target = params.fetch(:target)
10
+ end
11
+
12
+ private
13
+
14
+ attr_reader :target
15
+
16
+ def action
17
+ "deployment"
18
+ end
19
+
20
+ def action_relation_name
21
+ "pb:record-deployment"
22
+ end
23
+
24
+ def record_action_request_body
25
+ { target: target }.compact
26
+ end
27
+
28
+ def result_text_message
29
+ if target
30
+ "#{super} (target #{target})"
31
+ else
32
+ super
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,99 @@
1
+ require 'pact_broker/client/base_command'
2
+
3
+ module PactBroker
4
+ module Client
5
+ module Deployments
6
+ class RecordRelease < PactBroker::Client::BaseCommand
7
+ def initialize(params, options, pact_broker_client_options)
8
+ super
9
+ @pacticipant_name = params.fetch(:pacticipant_name)
10
+ @version_number = params.fetch(:version_number)
11
+ @environment_name = params.fetch(:environment_name)
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :pacticipant_name, :version_number, :environment_name
17
+ attr_reader :deployed_version_resource
18
+
19
+ def do_call
20
+ record_action
21
+ PactBroker::Client::CommandResult.new(true, result_message)
22
+ end
23
+
24
+ def action
25
+ "release"
26
+ end
27
+
28
+ def action_relation_name
29
+ "pb:record-release"
30
+ end
31
+
32
+ def not_supported_message
33
+ "This version of the Pact Broker does not support recording #{action}s. Please upgrade to version 2.80.0 or later."
34
+ end
35
+
36
+ def environment_exists?
37
+ index_resource
38
+ ._link!("pb:environments")
39
+ .get!
40
+ ._links("pb:environments")
41
+ .find(environment_name)
42
+ end
43
+
44
+ def record_action
45
+ @deployed_version_resource =
46
+ get_record_action_relation
47
+ .post(record_action_request_body)
48
+ .assert_success!
49
+ end
50
+
51
+ def record_action_links
52
+ get_pacticipant_version._links(action_relation_name) or raise PactBroker::Client::Error.new(not_supported_message)
53
+ end
54
+
55
+ def get_record_action_relation
56
+ record_action_links.find(environment_name) or record_action_links.find!(environment_name, environment_relation_not_found_error_message)
57
+ end
58
+
59
+ def environment_relation_not_found_error_message
60
+ if environment_exists?
61
+ "Environment '#{environment_name}' is not an available option for recording a deployment of #{pacticipant_name}."
62
+ else
63
+ "No environment found with name '#{environment_name}'."
64
+ end
65
+ end
66
+
67
+ def get_pacticipant_version
68
+ index_resource
69
+ ._link!("pb:pacticipant-version")
70
+ .expand(pacticipant: pacticipant_name, version: version_number)
71
+ .get
72
+ .assert_success!(404 => "#{pacticipant_name} version #{version_number} not found")
73
+ end
74
+
75
+ def record_action_request_body
76
+ {}
77
+ end
78
+
79
+ def result_message
80
+ if json_output?
81
+ deployed_version_resource.response.raw_body
82
+ else
83
+ green("#{result_text_message} in #{pact_broker_name}.")
84
+ end
85
+ end
86
+
87
+ def result_text_message
88
+ "Recorded #{action} of #{pacticipant_name} version #{version_number} to #{environment_name} environment"
89
+ end
90
+
91
+ def check_if_command_supported
92
+ unless index_resource.can?("pb:environments")
93
+ raise PactBroker::Client::Error.new(not_supported_message)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,120 @@
1
+ require 'pact_broker/client/base_command'
2
+
3
+ module PactBroker
4
+ module Client
5
+ module Deployments
6
+ class RecordUndeployment < PactBroker::Client::BaseCommand
7
+
8
+
9
+
10
+ def initialize(params, pact_broker_base_url, pact_broker_client_options)
11
+ super
12
+ @pacticipant_name = params.fetch(:pacticipant_name)
13
+ @environment_name = params.fetch(:environment_name)
14
+ @target = params.fetch(:target)
15
+ end
16
+
17
+ private
18
+
19
+ def do_call
20
+ if undeployed_versions_resources.empty?
21
+ check_pacticipant_exists!
22
+ PactBroker::Client::CommandResult.new(false, deployed_version_not_found_error_message)
23
+ else
24
+ PactBroker::Client::CommandResult.new(undeployed_versions_resources.all?(:success?), result_message)
25
+ end
26
+ end
27
+
28
+ attr_reader :pacticipant_name, :version_number, :environment_name, :target, :output
29
+ attr_reader :deployed_version_resource, :undeployment_entities
30
+
31
+ def currently_deployed_versions_link
32
+ environment_resource._link("pb:currently-deployed-versions") or raise PactBroker::Client::Error.new(not_supported_message)
33
+ end
34
+
35
+ def currently_deployed_versions_resource
36
+ @deployed_version_links ||= currently_deployed_versions_link.get!(pacticipant: pacticipant_name, target: target)
37
+ end
38
+
39
+ def undeployed_versions_resources
40
+ @undeployed_versions_resources ||= currently_deployed_versions_resource.embedded_entities("deployedVersions").collect do | entity |
41
+ entity._link!("self").patch(currentlyDeployed: false)
42
+ end
43
+ end
44
+
45
+ def action
46
+ "undeployment"
47
+ end
48
+
49
+ def environment_resource
50
+ index_resource
51
+ ._link!("pb:environments")
52
+ .get!
53
+ ._links("pb:environments")
54
+ .find!(environment_name, "No environment found with name '#{environment_name}'")
55
+ .get!
56
+ end
57
+
58
+ def check_pacticipant_exists!
59
+ if index_resource._link!("pb:pacticipant").expand(pacticipant: pacticipant_name).get.does_not_exist?
60
+ raise PactBroker::Client::Error.new("No pacticipant with name '#{pacticipant_name}' found")
61
+ end
62
+ end
63
+
64
+ def result_message
65
+ if json_output?
66
+ undeployed_versions_resources.collect{ | resource | resource.response.body }.to_a.to_json
67
+ else
68
+ undeployed_versions_resources.collect do | undeployed_versions_resource |
69
+ if undeployed_versions_resource.success?
70
+ green("#{success_result_text_message(undeployed_versions_resource)} in #{pact_broker_name}.")
71
+ else
72
+ red(undeployed_versions_resource.error_message)
73
+ end
74
+ end.join("\n")
75
+ end
76
+ end
77
+
78
+ def success_result_text_message(undeployed_versions_resource)
79
+ version_number = undeployed_versions_resource.embedded_entity{ | embedded_entity| embedded_entity['version'] }.number
80
+ message = "Recorded #{action} of #{pacticipant_name} version #{version_number} from #{environment_name} environment"
81
+ if target
82
+ message + " (target #{target})"
83
+ else
84
+ message
85
+ end
86
+ end
87
+
88
+ def deployed_version_not_found_error_message
89
+ target_bit = target ? " with target '#{target}'" : ""
90
+ message = "#{pacticipant_name} is not currently deployed to #{environment_name}#{target_bit}. Cannot record undeployment."
91
+
92
+ if json_output?
93
+ { error: message }.to_json
94
+ else
95
+ red(message)
96
+ end
97
+ end
98
+
99
+
100
+ def deployed_version_not_found_message
101
+ if (env_names = deployed_version_links.names).any?
102
+ "#{pacticipant_name} version #{version_number} is not currently deployed to #{environment_name}. It is currently deployed to: #{env_names.join(", ")}"
103
+ else
104
+ "#{pacticipant_name} version #{version_number} is not currently deployed to any environment."
105
+ end
106
+ end
107
+
108
+ def not_supported_message
109
+ "This version of the Pact Broker does not support recording undeployments. Please upgrade to version 2.80.0 or later."
110
+ end
111
+
112
+ def check_if_command_supported
113
+ unless index_resource.can?("pb:environments")
114
+ raise PactBroker::Client::Error.new(not_supported_message)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,23 @@
1
+ require 'yaml'
2
+ require 'pact_broker/client/generate_display_name'
3
+
4
+ module PactBroker
5
+ module Client
6
+ class DescribeTextFormatter
7
+ extend GenerateDisplayName
8
+
9
+ def self.call(properties)
10
+ YAML.dump(displayify_keys(properties)).gsub("---\n", "")
11
+ end
12
+
13
+ def self.displayify_keys(thing)
14
+ case thing
15
+ when Hash then thing.each_with_object({}) { | (key, value), new_hash | new_hash[generate_display_name(key)] = displayify_keys(value) }
16
+ when Array then thing.collect{ | value | displayify_keys(value) }
17
+ else
18
+ thing
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end