pact_broker-client 1.44.0 → 1.47.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +15 -1
  3. data/CHANGELOG.md +36 -0
  4. data/README.md +54 -54
  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/base_command.rb +3 -0
  9. data/lib/pact_broker/client/can_i_deploy.rb +40 -5
  10. data/lib/pact_broker/client/cli/broker.rb +7 -137
  11. data/lib/pact_broker/client/cli/custom_thor.rb +0 -16
  12. data/lib/pact_broker/client/cli/deployment_commands.rb +25 -5
  13. data/lib/pact_broker/client/cli/matrix_commands.rb +93 -0
  14. data/lib/pact_broker/client/cli/webhook_commands.rb +122 -0
  15. data/lib/pact_broker/client/deployments.rb +4 -4
  16. data/lib/pact_broker/client/deployments/record_support_ended.rb +103 -0
  17. data/lib/pact_broker/client/deployments/record_undeployment.rb +43 -36
  18. data/lib/pact_broker/client/hal/entity.rb +17 -2
  19. data/lib/pact_broker/client/matrix/resource.rb +4 -0
  20. data/lib/pact_broker/client/pacticipants/create.rb +1 -1
  21. data/lib/pact_broker/client/verification_required.rb +34 -0
  22. data/lib/pact_broker/client/version.rb +1 -1
  23. data/lib/pact_broker/client/webhooks/create.rb +14 -8
  24. data/script/record-deployment.sh +1 -1
  25. data/script/record-deployments-and-releases.sh +11 -5
  26. data/script/record-undeployment.sh +1 -1
  27. data/script/webhook-commands.sh +12 -0
  28. data/spec/fixtures/approvals/can_i_deploy_failure_dry_run.approved.txt +7 -0
  29. data/spec/fixtures/approvals/can_i_deploy_success_dry_run.approved.txt +7 -0
  30. data/spec/lib/pact_broker/client/can_i_deploy_spec.rb +62 -2
  31. data/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb +15 -2
  32. data/spec/lib/pact_broker/client/cli/broker_run_webhook_commands_spec.rb +4 -2
  33. data/spec/lib/pact_broker/client/deployments/record_support_ended_spec.rb +208 -0
  34. data/spec/lib/pact_broker/client/deployments/record_undeployment_spec.rb +219 -0
  35. data/spec/pacts/pact_broker_client-pact_broker.json +317 -1
  36. data/spec/pacts/pact_broker_client-pactflow.json +118 -0
  37. data/spec/service_providers/pact_broker_client_register_repository_spec.rb +2 -2
  38. data/spec/service_providers/pact_helper.rb +15 -10
  39. data/spec/service_providers/pactflow_webhooks_create_spec.rb +86 -0
  40. data/spec/service_providers/record_deployment_spec.rb +1 -3
  41. data/spec/service_providers/record_release_spec.rb +2 -7
  42. data/spec/service_providers/record_undeployment_spec.rb +164 -0
  43. data/spec/service_providers/webhooks_create_spec.rb +1 -1
  44. data/spec/spec_helper.rb +1 -0
  45. data/spec/support/shared_context.rb +2 -1
  46. data/tasks/pact.rake +8 -6
  47. metadata +23 -3
@@ -0,0 +1,118 @@
1
+ {
2
+ "consumer": {
3
+ "name": "Pact Broker Client"
4
+ },
5
+ "provider": {
6
+ "name": "Pactflow"
7
+ },
8
+ "interactions": [
9
+ {
10
+ "description": "a request for the index resource",
11
+ "request": {
12
+ "method": "get",
13
+ "path": "/",
14
+ "headers": {
15
+ "Accept": "application/hal+json"
16
+ }
17
+ },
18
+ "response": {
19
+ "status": 200,
20
+ "headers": {
21
+ "Content-Type": "application/hal+json;charset=utf-8"
22
+ },
23
+ "body": {
24
+ "_links": {
25
+ "pb:webhooks": {
26
+ "href": "http://localhost:1235/HAL-REL-PLACEHOLDER-PB-WEBHOOKS"
27
+ },
28
+ "pb:pacticipants": {
29
+ "href": "http://localhost:1235/HAL-REL-PLACEHOLDER-PB-PACTICIPANTS"
30
+ },
31
+ "pb:pacticipant": {
32
+ "href": "http://localhost:1235/HAL-REL-PLACEHOLDER-PB-PACTICIPANT-{pacticipant}"
33
+ }
34
+ }
35
+ },
36
+ "matchingRules": {
37
+ "$.body._links.pb:webhooks.href": {
38
+ "match": "regex",
39
+ "regex": "http:\\/\\/.*"
40
+ },
41
+ "$.body._links.pb:pacticipants.href": {
42
+ "match": "regex",
43
+ "regex": "http:\\/\\/.*"
44
+ },
45
+ "$.body._links.pb:pacticipant.href": {
46
+ "match": "regex",
47
+ "regex": "http:\\/\\/.*{pacticipant}"
48
+ }
49
+ }
50
+ }
51
+ },
52
+ {
53
+ "description": "a request to create a webhook for a team",
54
+ "providerState": "a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists",
55
+ "request": {
56
+ "method": "post",
57
+ "path": "/HAL-REL-PLACEHOLDER-PB-WEBHOOKS",
58
+ "headers": {
59
+ "Content-Type": "application/json",
60
+ "Accept": "application/hal+json"
61
+ },
62
+ "body": {
63
+ "description": "a webhook",
64
+ "events": [
65
+ {
66
+ "name": "contract_content_changed"
67
+ }
68
+ ],
69
+ "request": {
70
+ "url": "https://webhook",
71
+ "method": "POST",
72
+ "headers": {
73
+ "Foo": "bar",
74
+ "Bar": "foo"
75
+ },
76
+ "body": {
77
+ "some": "body"
78
+ }
79
+ },
80
+ "teamUuid": "2abbc12a-427d-432a-a521-c870af1739d9"
81
+ }
82
+ },
83
+ "response": {
84
+ "status": 201,
85
+ "headers": {
86
+ "Content-Type": "application/hal+json;charset=utf-8"
87
+ },
88
+ "body": {
89
+ "description": "a webhook",
90
+ "teamUuid": "2abbc12a-427d-432a-a521-c870af1739d9",
91
+ "_links": {
92
+ "self": {
93
+ "href": "http://localhost:1234/some-url",
94
+ "title": "A title"
95
+ }
96
+ }
97
+ },
98
+ "matchingRules": {
99
+ "$.body.description": {
100
+ "match": "type"
101
+ },
102
+ "$.body._links.self.href": {
103
+ "match": "regex",
104
+ "regex": "http:\\/\\/.*"
105
+ },
106
+ "$.body._links.self.title": {
107
+ "match": "type"
108
+ }
109
+ }
110
+ }
111
+ }
112
+ ],
113
+ "metadata": {
114
+ "pactSpecification": {
115
+ "version": "2.0.0"
116
+ }
117
+ }
118
+ }
@@ -14,7 +14,7 @@ module PactBroker::Client
14
14
  with(
15
15
  method: :patch,
16
16
  path: '/pacticipants/Pricing%20Service',
17
- headers: patch_request_headers,
17
+ headers: old_patch_request_headers,
18
18
  body: {repository_url: repository_url} ).
19
19
  will_respond_with(
20
20
  status: 201,
@@ -33,7 +33,7 @@ module PactBroker::Client
33
33
  with(
34
34
  method: :patch,
35
35
  path: '/pacticipants/Pricing%20Service',
36
- headers: patch_request_headers,
36
+ headers: old_patch_request_headers,
37
37
  body: { repository_url: repository_url }).
38
38
  will_respond_with(
39
39
  status: 200,
@@ -8,7 +8,6 @@ Pact.configure do | config |
8
8
  end
9
9
 
10
10
  Pact.service_consumer 'Pact Broker Client' do
11
-
12
11
  has_pact_with "Pact Broker" do
13
12
  mock_service :pact_broker do
14
13
  port 1234
@@ -16,6 +15,12 @@ Pact.service_consumer 'Pact Broker Client' do
16
15
  end
17
16
  end
18
17
 
18
+ has_pact_with "Pactflow" do
19
+ mock_service :pactflow do
20
+ port 1235
21
+ pact_specification_version "2.0"
22
+ end
23
+ end
19
24
  end
20
25
 
21
26
  module PactBrokerPactHelperMethods
@@ -30,22 +35,22 @@ module PactBrokerPactHelperMethods
30
35
  path
31
36
  end
32
37
 
33
- def placeholder_url(relation, params = [])
34
- "#{pact_broker.mock_service_base_url}#{placeholder_path(relation, params)}"
38
+ def placeholder_url(relation, params = [], mock_service = pact_broker)
39
+ "#{mock_service.mock_service_base_url}#{placeholder_path(relation, params)}"
35
40
  end
36
41
 
37
- def placeholder_url_term(relation, params = [])
42
+ def placeholder_url_term(relation, params = [], mock_service = pact_broker)
38
43
  regexp = "http:\/\/.*"
39
44
  if params.any?
40
45
  joined_params_for_regexp = params.collect{ |param| "{#{param}}"}.join(".*")
41
46
  regexp = "#{regexp}#{joined_params_for_regexp}"
42
47
  end
43
48
 
44
- Pact.term(placeholder_url(relation, params), /#{regexp}/)
49
+ Pact.term(placeholder_url(relation, params, mock_service), /#{regexp}/)
45
50
  end
46
51
 
47
- def mock_pact_broker_index(context)
48
- pact_broker
52
+ def mock_pact_broker_index(context, mock_service = pact_broker)
53
+ mock_service
49
54
  .upon_receiving("a request for the index resource")
50
55
  .with(
51
56
  method: :get,
@@ -57,13 +62,13 @@ module PactBrokerPactHelperMethods
57
62
  body: {
58
63
  _links: {
59
64
  :'pb:webhooks' => {
60
- href: placeholder_url_term('pb:webhooks')
65
+ href: placeholder_url_term('pb:webhooks', [], mock_service)
61
66
  },
62
67
  :'pb:pacticipants' => {
63
- href: placeholder_url_term('pb:pacticipants')
68
+ href: placeholder_url_term('pb:pacticipants', [], mock_service)
64
69
  },
65
70
  :'pb:pacticipant' => {
66
- href: placeholder_url_term('pb:pacticipant', ['pacticipant'])
71
+ href: placeholder_url_term('pb:pacticipant', ['pacticipant'], mock_service)
67
72
  }
68
73
  }
69
74
  }
@@ -0,0 +1,86 @@
1
+ require_relative 'pact_helper'
2
+ require 'pact_broker/client/webhooks/create'
3
+
4
+ RSpec.describe "creating a webhook in Pactflow", pact: true do
5
+
6
+ include_context "pact broker"
7
+ include PactBrokerPactHelperMethods
8
+
9
+ let(:params) do
10
+ {
11
+ description: "a webhook",
12
+ events: %w{contract_content_changed},
13
+ http_method: "POST",
14
+ url: "https://webhook",
15
+ headers: { "Foo" => "bar", "Bar" => "foo"},
16
+ body: body,
17
+ team_uuid: "2abbc12a-427d-432a-a521-c870af1739d9"
18
+ }
19
+ end
20
+
21
+ let(:body) { { some: "body" }.to_json }
22
+
23
+ let(:request_body) do
24
+ {
25
+ "description" => "a webhook",
26
+ "events" => [
27
+ "name" => "contract_content_changed"
28
+ ],
29
+ "request" => {
30
+ "url" => "https://webhook",
31
+ "method" => "POST",
32
+ "headers" => {
33
+ "Foo" => "bar",
34
+ "Bar" => "foo"
35
+ },
36
+ "body" => {
37
+ "some" => "body"
38
+ },
39
+ },
40
+ "teamUuid" => "2abbc12a-427d-432a-a521-c870af1739d9"
41
+ }
42
+ end
43
+
44
+ let(:response_status) { 201 }
45
+ let(:success_response) do
46
+ {
47
+ status: response_status,
48
+ headers: pact_broker_response_headers,
49
+ body: {
50
+ description: Pact.like("a webhook"),
51
+ teamUuid: "2abbc12a-427d-432a-a521-c870af1739d9",
52
+ _links: {
53
+ self: {
54
+ href: Pact.term('http://localhost:1234/some-url', %r{http://.*}),
55
+ title: Pact.like("A title")
56
+ }
57
+ }
58
+ }
59
+ }
60
+ end
61
+
62
+ let(:pact_broker_client_options) { {} }
63
+
64
+ subject { PactBroker::Client::Webhooks::Create.call(params, pactflow.mock_service_base_url, pact_broker_client_options) }
65
+
66
+ context "when a valid webhook with a team specified is submitted" do
67
+ before do
68
+ mock_pact_broker_index(self, pactflow)
69
+ pactflow
70
+ .given("a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists")
71
+ .upon_receiving("a request to create a webhook for a team")
72
+ .with(
73
+ method: :post,
74
+ path: '/HAL-REL-PLACEHOLDER-PB-WEBHOOKS',
75
+ headers: post_request_headers,
76
+ body: request_body)
77
+ .will_respond_with(success_response)
78
+ end
79
+
80
+ it "returns a CommandResult with success = true" do
81
+ expect(subject).to be_a PactBroker::Client::CommandResult
82
+ expect(subject.success).to be true
83
+ expect(subject.message).to eq "Webhook \"a webhook\" created"
84
+ end
85
+ end
86
+ end
@@ -1,9 +1,7 @@
1
1
  require 'service_providers/pact_helper'
2
2
  require 'pact_broker/client/deployments/record_deployment'
3
3
 
4
- deployment_feature_on = ENV.fetch('PACT_BROKER_FEATURES', '').include?("deployments")
5
-
6
- RSpec.describe "recording a deployment", pact: true, skip: !deployment_feature_on do
4
+ RSpec.describe "recording a deployment", pact: true do
7
5
  include_context "pact broker"
8
6
  include PactBrokerPactHelperMethods
9
7
 
@@ -1,9 +1,7 @@
1
1
  require 'service_providers/pact_helper'
2
2
  require 'pact_broker/client/deployments/record_deployment'
3
3
 
4
- deployment_feature_on = ENV.fetch('PACT_BROKER_FEATURES', '').include?("deployments")
5
-
6
- RSpec.describe "recording a release", pact: true, skip: !deployment_feature_on do
4
+ RSpec.describe "recording a release", pact: true do
7
5
  include_context "pact broker"
8
6
  include PactBrokerPactHelperMethods
9
7
 
@@ -113,10 +111,7 @@ RSpec.describe "recording a release", pact: true, skip: !deployment_feature_on d
113
111
  )
114
112
  .will_respond_with(
115
113
  status: 201,
116
- headers: pact_broker_response_headers,
117
- body: {
118
- target: target
119
- }
114
+ headers: pact_broker_response_headers
120
115
  )
121
116
  end
122
117
 
@@ -0,0 +1,164 @@
1
+ require 'service_providers/pact_helper'
2
+ require 'pact_broker/client/deployments/record_undeployment'
3
+
4
+ RSpec.describe "recording an undeployment", pact: true do
5
+ include_context "pact broker"
6
+ include PactBrokerPactHelperMethods
7
+
8
+ let(:pacticipant_name) { "Foo" }
9
+ let(:environment_name) { "test" }
10
+ let(:output) { "text" }
11
+ let(:target) { "customer-1" }
12
+ let(:params) do
13
+ {
14
+ pacticipant_name: pacticipant_name,
15
+ environment_name: environment_name,
16
+ target: target
17
+ }
18
+ end
19
+ let(:options) do
20
+ {
21
+ output: output,
22
+ verbose: true
23
+ }
24
+ end
25
+ let(:webmock_base_url) { "http://broker" }
26
+ let(:pact_broker_client_options) { { pact_broker_base_url: webmock_base_url } }
27
+ let(:test_environment_placeholder_path) { "/HAL-REL-PLACEHOLDER-PB-ENVIRONMENT-16926ef3-590f-4e3f-838e-719717aa88c9" }
28
+ let(:currently_deployed_versions_placeholder_path) { "/PLACEHOLDER-ENVIRONMENT-CURRENTLY-DEPLOYED-16926ef3-590f-4e3f-838e-719717aa88c9" }
29
+ let(:deployed_version_placeholder_path) { "/PLACEHOLDER-DEPLOYED-VERSION-ff3adecf-cfc5-4653-a4e3-f1861092f8e0"}
30
+
31
+ subject { PactBroker::Client::Deployments::RecordUndeployment.call(params, options, pact_broker_client_options) }
32
+
33
+ let(:index_body_hash) do
34
+ {
35
+ _links: {
36
+ :'pb:environments' => {
37
+ href: "#{webmock_base_url}/environments"
38
+ }
39
+ }
40
+ }
41
+ end
42
+
43
+ let(:environments_hash) do
44
+ {
45
+ _links: {
46
+ :'pb:environments' => [
47
+ {
48
+ name: "test",
49
+ href: pact_broker.mock_service_base_url + test_environment_placeholder_path
50
+ }
51
+ ]
52
+ }
53
+ }
54
+ end
55
+
56
+ let!(:index_request) do
57
+ stub_request(:get, "http://broker").to_return(status: 200, body: index_body_hash.to_json, headers: { "Content-Type" => "application/hal+json" } )
58
+ end
59
+
60
+ let!(:environments_request) do
61
+ stub_request(:get, "http://broker/environments").to_return(status: 200, body: environments_hash.to_json, headers: { "Content-Type" => "application/hal+json" } )
62
+ end
63
+
64
+ def mock_test_environment
65
+ pact_broker
66
+ .given("an environment with name test and UUID 16926ef3-590f-4e3f-838e-719717aa88c9 exists")
67
+ .upon_receiving("a request for an environment")
68
+ .with(
69
+ method: "GET",
70
+ path: test_environment_placeholder_path,
71
+ headers: get_request_headers
72
+ )
73
+ .will_respond_with(
74
+ status: 200,
75
+ headers: pact_broker_response_headers,
76
+ body: {
77
+ _links: {
78
+ :'pb:currently-deployed-deployed-versions' => {
79
+ href: Pact.term( pact_broker.mock_service_base_url + currently_deployed_versions_placeholder_path, /^http.*/)
80
+ }
81
+ }
82
+ }
83
+ )
84
+ end
85
+
86
+ def mock_deployed_versions_search_results
87
+ pact_broker
88
+ .given("an version is deployed to environment with UUID 16926ef3-590f-4e3f-838e-719717aa88c9 with target customer-1")
89
+ .upon_receiving("a request to list the versions deployed to an environment for a pacticipant name and target")
90
+ .with(
91
+ method: "GET",
92
+ path: currently_deployed_versions_placeholder_path,
93
+ query: { pacticipant: pacticipant_name },
94
+ headers: get_request_headers
95
+ )
96
+ .will_respond_with(
97
+ status: 200,
98
+ headers: pact_broker_response_headers,
99
+ body: {
100
+ _embedded: {
101
+ deployedVersions: [
102
+ {
103
+ target: target,
104
+ _links: {
105
+ self: {
106
+ href: Pact.term(pact_broker.mock_service_base_url + deployed_version_placeholder_path, /^http/)
107
+ }
108
+ }
109
+ }
110
+ ]
111
+ }
112
+ }
113
+ )
114
+ end
115
+
116
+ def mock_mark_deployed_version_as_undeployed
117
+ pact_broker
118
+ .given("a currently deployed version exists")
119
+ .upon_receiving("a request to mark a deployed version as not currently deploye")
120
+ .with(
121
+ method: "PATCH",
122
+ path: deployed_version_placeholder_path,
123
+ body: { currentlyDeployed: false },
124
+ headers: patch_request_headers
125
+ )
126
+ .will_respond_with(
127
+ status: 200,
128
+ headers: pact_broker_response_headers,
129
+ body: deployed_version_hash
130
+ )
131
+ end
132
+
133
+ let(:deployed_version_hash) do
134
+ {
135
+ "currentlyDeployed" => false,
136
+ "_embedded" => {
137
+ "version" => {
138
+ "number" => Pact.like("2")
139
+ }
140
+ }
141
+ }
142
+ end
143
+
144
+ context "when the deployment is recorded successfully" do
145
+ before do
146
+ mock_test_environment
147
+ mock_deployed_versions_search_results
148
+ mock_mark_deployed_version_as_undeployed
149
+ end
150
+
151
+ it "returns a success message" do
152
+ expect(subject.success).to be true
153
+ expect(subject.message).to include "Recorded undeployment of Foo version 2 from test environment (target customer-1) in the Pact Broker"
154
+ end
155
+
156
+ context "when the output is json" do
157
+ let(:output) { "json" }
158
+
159
+ it "returns the JSON payload" do
160
+ expect(JSON.parse(subject.message)).to eq [Pact::Reification.from_term(deployed_version_hash)]
161
+ end
162
+ end
163
+ end
164
+ end