pact_broker 2.77.0 → 2.78.0

Sign up to get free protection for your applications and to get access to all the features.
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'