pact_broker 2.77.0 → 2.78.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/db/migrations/20210210_create_environments_table.rb +16 -0
  4. data/lib/pact_broker/api.rb +5 -0
  5. data/lib/pact_broker/api/contracts/dry_validation_predicates.rb +8 -0
  6. data/lib/pact_broker/api/contracts/environment_schema.rb +49 -0
  7. data/lib/pact_broker/api/decorators/base_decorator.rb +11 -0
  8. data/lib/pact_broker/api/decorators/environment_decorator.rb +30 -0
  9. data/lib/pact_broker/api/decorators/environments_decorator.rb +21 -0
  10. data/lib/pact_broker/api/decorators/version_decorator.rb +12 -1
  11. data/lib/pact_broker/api/pact_broker_urls.rb +8 -0
  12. data/lib/pact_broker/api/resources/default_base_resource.rb +9 -0
  13. data/lib/pact_broker/api/resources/environment.rb +76 -0
  14. data/lib/pact_broker/api/resources/environments.rb +75 -0
  15. data/lib/pact_broker/api/resources/index.rb +14 -0
  16. data/lib/pact_broker/api/resources/version.rb +2 -2
  17. data/lib/pact_broker/configuration.rb +1 -0
  18. data/lib/pact_broker/deployments/environment.rb +15 -0
  19. data/lib/pact_broker/deployments/environment_service.rb +39 -0
  20. data/lib/pact_broker/doc/views/index/environment.markdown +37 -0
  21. data/lib/pact_broker/doc/views/index/environments.markdown +53 -0
  22. data/lib/pact_broker/doc/views/index/latest-pact-versions.markdown +1 -1
  23. data/lib/pact_broker/doc/views/index/pacticipant-version-tag.markdown +1 -0
  24. data/lib/pact_broker/locale/en.yml +3 -1
  25. data/lib/pact_broker/services.rb +9 -0
  26. data/lib/pact_broker/test/test_data_builder.rb +14 -0
  27. data/lib/pact_broker/version.rb +1 -1
  28. data/lib/pact_broker/versions/repository.rb +15 -4
  29. data/lib/pact_broker/versions/service.rb +2 -2
  30. data/lib/pact_broker/webhooks/webhook_execution_result.rb +4 -1
  31. data/spec/features/create_environment_spec.rb +47 -0
  32. data/spec/features/create_tag_spec.rb +32 -0
  33. data/spec/features/create_version_spec.rb +30 -4
  34. data/spec/features/delete_environment_spec.rb +16 -0
  35. data/spec/features/end_deployment_spec.rb +29 -0
  36. data/spec/features/get_environment_spec.rb +19 -0
  37. data/spec/features/get_environments_spec.rb +20 -0
  38. data/spec/features/record_deployment_spec.rb +28 -0
  39. data/spec/features/update_environment_spec.rb +44 -0
  40. data/spec/fixtures/approvals/modifiable_resources.approved.json +6 -0
  41. data/spec/lib/pact_broker/api/contracts/environment_schema_spec.rb +83 -0
  42. data/spec/lib/pact_broker/api/decorators/version_decorator_spec.rb +18 -0
  43. data/spec/lib/pact_broker/api/resources/default_base_resource_approval_spec.rb +1 -1
  44. data/spec/lib/pact_broker/api/resources/webhook_execution_result_spec.rb +56 -0
  45. data/spec/lib/pact_broker/versions/repository_spec.rb +14 -4
  46. data/spec/service_consumers/hal_relation_proxy_app.rb +3 -1
  47. data/spec/service_consumers/provider_states_for_pact_broker_client.rb +16 -0
  48. data/spec/support/shared_examples_for_responses.rb +11 -0
  49. metadata +33 -3
@@ -0,0 +1,16 @@
1
+ require 'pact_broker/api/pact_broker_urls'
2
+
3
+ describe "Deleting an environment" do
4
+ before do
5
+ td.create_environment("test", uuid: "1234")
6
+ end
7
+
8
+ let(:path) { PactBroker::Api::PactBrokerUrls.environment_url(td.and_return(:environment)) }
9
+
10
+ subject { delete(path, nil) }
11
+
12
+ it "returns a 204 response" do
13
+ subject
14
+ expect(last_response.status).to be 204
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ #
2
+ # RPC style seems cleaner than REST here, as setting the endedAt parameter directly
3
+ # seems likely to end in Timezone tears
4
+ # This endpoint would be called by the pact broker client during `record-deployment` if the
5
+ # --end-previous-deployment (on by default) was specified.
6
+ # This allows us to know exactly what is deployed to a particular environment at a given time,
7
+ # (eg. /environments/test/deployments/current)
8
+ # and provides first class support for mobile clients that have multiple versions in prod
9
+ # at once.
10
+
11
+ describe "Record deployment ended", skip: "Not yet implemented" do
12
+ before do
13
+ td.create_environment("test")
14
+ .create_pacticipant("Foo")
15
+ .create_pacticipant_version("1")
16
+ .create_deployment("test")
17
+ end
18
+ let(:path) { "/pacticipants/Foo/deployments/test/latest/end" }
19
+ let(:headers) { {} }
20
+ let(:response_body) { JSON.parse(last_response.body, symbolize_names: true) }
21
+
22
+ subject { post(path, nil, headers) }
23
+
24
+ it { is_expected.be_a_hal_json_success_response }
25
+
26
+ it "returns the updated deployment" do
27
+ expect(subject[:endedAt]).to_not be nil
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ require 'pact_broker/api/pact_broker_urls'
2
+
3
+ describe "Get an environment" do
4
+ before do
5
+ td.create_environment("test", display_name: "Test", uuid: "1234", contacts: [ { name: "Foo" } ] )
6
+ end
7
+ let(:path) { PactBroker::Api::PactBrokerUrls.environment_url(td.and_return(:environment)) }
8
+ let(:headers) { {'HTTP_ACCEPT' => 'application/hal+json'} }
9
+ let(:response_body) { JSON.parse(subject.body, symbolize_names: true)}
10
+
11
+ subject { get(path, nil, headers) }
12
+
13
+ it { is_expected.to be_a_hal_json_success_response }
14
+
15
+ it "returns the environment" do
16
+ expect(response_body[:uuid]).to eq "1234"
17
+ expect(response_body[:name]).to eq "test"
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ require 'pact_broker/api/pact_broker_urls'
2
+
3
+ describe "Get all environments" do
4
+ before do
5
+ td.create_environment("test", display_name: "Test", uuid: "1234", contacts: [ { name: "Foo" } ] )
6
+ .create_environment("prod", display_name: "Production", uuid: "5678", contacts: [ { name: "Foo" } ] )
7
+ end
8
+ let(:path) { PactBroker::Api::PactBrokerUrls.environments_url }
9
+ let(:headers) { {'HTTP_ACCEPT' => 'application/hal+json'} }
10
+ let(:response_body) { JSON.parse(last_response.body, symbolize_names: true)}
11
+
12
+ subject { get(path, nil, headers) }
13
+
14
+ it { is_expected.to be_a_hal_json_success_response }
15
+
16
+ it "returns the environments" do
17
+ subject
18
+ expect(response_body[:_embedded][:environments].size).to be 2
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ #
2
+ # pact-broker record-deployment --pacticipant Foo --version 1 --environment test --end-previous-deployment
3
+ #
4
+
5
+ describe "Record deployment", skip: "Not yet implemented" do
6
+ before do
7
+ td.create_environment("test")
8
+ .create_pacticipant("Foo")
9
+ .create_pacticipant_version("1")
10
+ end
11
+ let(:path) { "/pacticipants/Foo/versions/1/deployments/test" }
12
+ let(:headers) { {"CONTENT_TYPE" => "application/json"} }
13
+ let(:response_body) { JSON.parse(last_response.body, symbolize_names: true)}
14
+
15
+ subject { post(path, nil, headers) }
16
+
17
+ it { is_expected.to be_a_hal_json_created_response }
18
+
19
+ it "returns the Location header" do
20
+ subject
21
+ expect(last_response.headers["Location"]).to eq "http://example.org/deployments/123456"
22
+ end
23
+
24
+ it "returns the newly created deployment" do
25
+ subject
26
+ expect(response_body).to include_key(:createdAt)
27
+ end
28
+ end
@@ -0,0 +1,44 @@
1
+ require 'pact_broker/api/pact_broker_urls'
2
+
3
+ describe "Updating an environment" do
4
+ before do
5
+ td.create_environment("test", uuid: "1234", contacts: [ { name: "Foo" } ] )
6
+ end
7
+ let(:path) { PactBroker::Api::PactBrokerUrls.environment_url(td.and_return(:environment)) }
8
+ let(:headers) { {'CONTENT_TYPE' => 'application/json'} }
9
+ let(:response_body) { JSON.parse(last_response.body, symbolize_names: true)}
10
+ let(:environment_hash) do
11
+ {
12
+ name: "test",
13
+ production: false,
14
+ displayName: "Testing"
15
+ }
16
+ end
17
+
18
+ subject { put(path, environment_hash.to_json, headers) }
19
+
20
+ it { is_expected.to be_a_hal_json_success_response }
21
+
22
+ it "returns the updated environment" do
23
+ subject
24
+ expect(response_body[:displayName]).to eq "Testing"
25
+ expect(response_body[:contacts]).to be nil
26
+ end
27
+
28
+ context "when the environment doesn't exist" do
29
+ let(:path) { "/environments/5678" }
30
+
31
+ it "returns a 404" do
32
+ expect(subject.status).to eq 404
33
+ end
34
+ end
35
+
36
+ context "with invalid params" do
37
+ let(:environment_hash) { {} }
38
+
39
+ it "returns a 400 response" do
40
+ expect(subject.status).to be 400
41
+ expect(response_body[:errors]).to_not be nil
42
+ end
43
+ end
44
+ end
@@ -6,6 +6,12 @@
6
6
  {
7
7
  "resource_class_name": "PactBroker::Api::Resources::Clean"
8
8
  },
9
+ {
10
+ "resource_class_name": "PactBroker::Api::Resources::Environment"
11
+ },
12
+ {
13
+ "resource_class_name": "PactBroker::Api::Resources::Environments"
14
+ },
9
15
  {
10
16
  "resource_class_name": "PactBroker::Api::Resources::ErrorTest"
11
17
  },
@@ -0,0 +1,83 @@
1
+ require 'pact_broker/api/contracts/environment_schema'
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Contracts
6
+ describe EnvironmentSchema do
7
+ before do
8
+ allow(PactBroker::Deployments::EnvironmentService).to receive(:find_by_name).and_return(existing_environment)
9
+ end
10
+ let(:existing_environment) { nil }
11
+ let(:name) { "test" }
12
+
13
+ let(:params) do
14
+ {
15
+ uuid: "1234",
16
+ name: name,
17
+ displayName: "Test",
18
+ production: false,
19
+ contacts: contacts
20
+ }
21
+ end
22
+
23
+ let(:contacts) do
24
+ [{
25
+ name: "Foo",
26
+ details: { email: "foo@bar.com" }
27
+ }]
28
+ end
29
+
30
+ subject { EnvironmentSchema.call(params) }
31
+
32
+ context "with valid params" do
33
+ it { is_expected.to be_empty }
34
+ end
35
+
36
+ context "with a name with a new line" do
37
+ let(:name) { "test 1" }
38
+
39
+ it { is_expected.to_not be_empty }
40
+ end
41
+
42
+ context "with empty params" do
43
+ let(:params) { {} }
44
+
45
+ it { is_expected.to_not be_empty }
46
+ end
47
+
48
+ context "when there is another environment with the same name but a different uuid" do
49
+ let(:existing_environment) { instance_double("PactBroker::Deployments::Environment", uuid: "5678")}
50
+
51
+ its([:name]) { is_expected.to eq ["Another environment with name 'test' already exists."] }
52
+ end
53
+
54
+ context "when there is another environment with the same name and same uuid" do
55
+ let(:existing_environment) { instance_double("PactBroker::Deployments::Environment", uuid: "1234")}
56
+
57
+ it { is_expected.to be_empty }
58
+ end
59
+
60
+ context "with no owner name" do
61
+ let(:contacts) do
62
+ [{
63
+ details: { email: "foo@bar.com" }
64
+ }]
65
+ end
66
+
67
+ its([:contacts, 0]) { is_expected.to eq "name is missing at index 0" }
68
+ end
69
+
70
+ context "with string contact details" do
71
+ let(:contacts) do
72
+ [{
73
+ name: "foo",
74
+ details: "foo"
75
+ }]
76
+ end
77
+
78
+ its([:contacts, 0]) { is_expected.to eq "details must be a hash at index 0" }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -6,6 +6,24 @@ module PactBroker
6
6
  module Decorators
7
7
  describe VersionDecorator do
8
8
 
9
+ describe "from_json" do
10
+ let(:hash) do
11
+ {
12
+ branch: "branch",
13
+ buildUrl: "buildUrl",
14
+ tags: [{ name: "main" }]
15
+ }
16
+ end
17
+
18
+ subject { VersionDecorator.new(OpenStruct.new).from_json(hash.to_json) }
19
+
20
+ it "sets the properties" do
21
+ expect(subject.branch).to eq "branch"
22
+ expect(subject.build_url).to eq "buildUrl"
23
+ expect(subject.tags.first.name).to eq "main"
24
+ end
25
+ end
26
+
9
27
  let(:version) do
10
28
  TestDataBuilder.new
11
29
  .create_consumer("Consumer")
@@ -45,7 +45,7 @@ module PactBroker
45
45
  if resource.respond_to?(:policy_pacticipant)
46
46
  resource_class_data[:resource_class_data] = resource.policy_pacticipant
47
47
  end
48
- resource_class_data
48
+ resource_class_data
49
49
  else
50
50
  nil
51
51
  end
@@ -0,0 +1,56 @@
1
+ module PactBroker
2
+ module Webhooks
3
+ describe WebhookExecutionResult do
4
+ subject { WebhookExecutionResult::new(request, response, nil) }
5
+ let(:request) do
6
+ Net::HTTP::Get.new("http://example.org?foo=bar")
7
+ end
8
+
9
+ context "When 'webhook_http_code_success' has [200, 201]" do
10
+ before do
11
+ allow(PactBroker.configuration).to receive(:webhook_http_code_success).and_return([200, 201])
12
+ end
13
+
14
+ context "and response is '200'" do
15
+ let(:response) { double(code: '200') }
16
+
17
+ it "then it should be success" do
18
+ expect(subject.success?).to be_truthy
19
+ end
20
+ end
21
+
22
+ context "and response is '400'" do
23
+ let(:response) { double(code: '400') }
24
+
25
+ it "then it should fail" do
26
+ expect(subject.success?).to be_falsey
27
+ end
28
+ end
29
+ end
30
+
31
+
32
+ context "When 'webhook_http_code_success' has [400, 401]" do
33
+ before do
34
+ allow(PactBroker.configuration).to receive(:webhook_http_code_success).and_return([400, 401])
35
+ end
36
+
37
+ context "and response is '200'" do
38
+ let(:response) { double(code: '200') }
39
+
40
+ it "then it should fail" do
41
+ expect(subject.success?).to be_falsey
42
+ end
43
+ end
44
+
45
+ context "and response is '400'" do
46
+ let(:response) { double(code: '400') }
47
+
48
+ it "then it should be success" do
49
+ expect(subject.success?).to be_truthy
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -123,7 +123,7 @@ module PactBroker
123
123
  end
124
124
  end
125
125
 
126
- describe "#create_or_update" do
126
+ describe "#create_or_overwrite" do
127
127
  before do
128
128
  td.subtract_day
129
129
  .create_consumer("Foo")
@@ -133,9 +133,10 @@ module PactBroker
133
133
 
134
134
  let(:pacticipant) { td.and_return(:consumer) }
135
135
  let(:version_number) { "1234" }
136
- let(:version) { PactBroker::Domain::Version.new(branch: "new-branch") }
136
+ let(:tags) { nil }
137
+ let(:open_struct_version) { OpenStruct.new(branch: "new-branch", tags: tags) }
137
138
 
138
- subject { Repository.new.create_or_update(pacticipant, version_number, version) }
139
+ subject { Repository.new.create_or_overwrite(pacticipant, version_number, open_struct_version) }
139
140
 
140
141
  it "overwrites the values" do
141
142
  expect(subject.branch).to eq "new-branch"
@@ -146,6 +147,15 @@ module PactBroker
146
147
  expect { subject }.to_not change { PactBroker::Domain::Version.for("Foo", "1234").tags }
147
148
  end
148
149
 
150
+ context "when there are tags specified" do
151
+ let(:tags) { [ OpenStruct.new(name: "main")] }
152
+
153
+ it "overwrites the tags" do
154
+ expect(subject.tags.count).to eq 1
155
+ expect(subject.tags.first.name).to eq "main"
156
+ end
157
+ end
158
+
149
159
  it "does not change the created date" do
150
160
  expect { subject }.to_not change { PactBroker::Domain::Version.for("Foo", "1234").created_at }
151
161
  end
@@ -159,7 +169,7 @@ module PactBroker
159
169
  end
160
170
 
161
171
  context "when the version does not already exist" do
162
- let(:version) { PactBroker::Domain::Version.new(number: "555", branch: "new-branch") }
172
+ let(:version) { OpenStruct.new(number: "555", branch: "new-branch") }
163
173
 
164
174
  it "sets the order" do
165
175
  expect(subject.order).to_not be nil
@@ -9,7 +9,9 @@ class HalRelationProxyApp
9
9
  '/HAL-REL-PLACEHOLDER-INDEX-PB-LATEST-VERSION-Condor' =>
10
10
  '/pacticipants/Condor/latest-version',
11
11
  '/HAL-REL-PLACEHOLDER-PB-WEBHOOKS' =>
12
- '/webhooks'
12
+ '/webhooks',
13
+ '/HAL-REL-PLACEHOLDER-INDEX-PB-PACTICIPANT-VERSION-Foo-26f353580936ad3b9baddb17b00e84f33c69e7cb' =>
14
+ '/pacticipants/Foo/versions/26f353580936ad3b9baddb17b00e84f33c69e7cb'
13
15
  }
14
16
 
15
17
  RESPONSE_BODY_REPLACEMENTS = {
@@ -255,4 +255,20 @@ Pact.provider_states_for "Pact Broker Client" do
255
255
  .create_consumer("Foo")
256
256
  end
257
257
  end
258
+
259
+ provider_state "the pb:pacticipant-version relation exists in the index resource" do
260
+ no_op
261
+ end
262
+
263
+ provider_state "version 26f353580936ad3b9baddb17b00e84f33c69e7cb of pacticipant Foo does not exist" do
264
+ no_op
265
+ end
266
+
267
+ provider_state "version 26f353580936ad3b9baddb17b00e84f33c69e7cb of pacticipant Foo does exist" do
268
+ set_up do
269
+ TestDataBuilder.new
270
+ .create_consumer("Foo")
271
+ .create_consumer_version("26f353580936ad3b9baddb17b00e84f33c69e7cb")
272
+ end
273
+ end
258
274
  end
@@ -22,6 +22,17 @@ RSpec::Matchers.define :be_a_hal_json_success_response do
22
22
  end
23
23
  end
24
24
 
25
+ RSpec::Matchers.define :be_a_hal_json_created_response do
26
+ match do | actual |
27
+ expect(actual.status).to be 201
28
+ expect(actual.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
29
+ end
30
+
31
+ failure_message do
32
+ "Expected creation successful json response, got #{actual.status} #{actual.headers['Content-Type']} with body #{actual.body}"
33
+ end
34
+ end
35
+
25
36
  RSpec::Matchers.define :be_a_json_response do
26
37
  match do | actual |
27
38
  expect(actual.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'