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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/db/migrations/20210210_create_environments_table.rb +16 -0
- data/lib/pact_broker/api.rb +5 -0
- data/lib/pact_broker/api/contracts/dry_validation_predicates.rb +8 -0
- data/lib/pact_broker/api/contracts/environment_schema.rb +49 -0
- data/lib/pact_broker/api/decorators/base_decorator.rb +11 -0
- data/lib/pact_broker/api/decorators/environment_decorator.rb +30 -0
- data/lib/pact_broker/api/decorators/environments_decorator.rb +21 -0
- data/lib/pact_broker/api/decorators/version_decorator.rb +12 -1
- data/lib/pact_broker/api/pact_broker_urls.rb +8 -0
- data/lib/pact_broker/api/resources/default_base_resource.rb +9 -0
- data/lib/pact_broker/api/resources/environment.rb +76 -0
- data/lib/pact_broker/api/resources/environments.rb +75 -0
- data/lib/pact_broker/api/resources/index.rb +14 -0
- data/lib/pact_broker/api/resources/version.rb +2 -2
- data/lib/pact_broker/configuration.rb +1 -0
- data/lib/pact_broker/deployments/environment.rb +15 -0
- data/lib/pact_broker/deployments/environment_service.rb +39 -0
- data/lib/pact_broker/doc/views/index/environment.markdown +37 -0
- data/lib/pact_broker/doc/views/index/environments.markdown +53 -0
- data/lib/pact_broker/doc/views/index/latest-pact-versions.markdown +1 -1
- data/lib/pact_broker/doc/views/index/pacticipant-version-tag.markdown +1 -0
- data/lib/pact_broker/locale/en.yml +3 -1
- data/lib/pact_broker/services.rb +9 -0
- data/lib/pact_broker/test/test_data_builder.rb +14 -0
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/versions/repository.rb +15 -4
- data/lib/pact_broker/versions/service.rb +2 -2
- data/lib/pact_broker/webhooks/webhook_execution_result.rb +4 -1
- data/spec/features/create_environment_spec.rb +47 -0
- data/spec/features/create_tag_spec.rb +32 -0
- data/spec/features/create_version_spec.rb +30 -4
- data/spec/features/delete_environment_spec.rb +16 -0
- data/spec/features/end_deployment_spec.rb +29 -0
- data/spec/features/get_environment_spec.rb +19 -0
- data/spec/features/get_environments_spec.rb +20 -0
- data/spec/features/record_deployment_spec.rb +28 -0
- data/spec/features/update_environment_spec.rb +44 -0
- data/spec/fixtures/approvals/modifiable_resources.approved.json +6 -0
- data/spec/lib/pact_broker/api/contracts/environment_schema_spec.rb +83 -0
- data/spec/lib/pact_broker/api/decorators/version_decorator_spec.rb +18 -0
- data/spec/lib/pact_broker/api/resources/default_base_resource_approval_spec.rb +1 -1
- data/spec/lib/pact_broker/api/resources/webhook_execution_result_spec.rb +56 -0
- data/spec/lib/pact_broker/versions/repository_spec.rb +14 -4
- data/spec/service_consumers/hal_relation_proxy_app.rb +3 -1
- data/spec/service_consumers/provider_states_for_pact_broker_client.rb +16 -0
- data/spec/support/shared_examples_for_responses.rb +11 -0
- 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")
|
@@ -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 "#
|
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(:
|
136
|
+
let(:tags) { nil }
|
137
|
+
let(:open_struct_version) { OpenStruct.new(branch: "new-branch", tags: tags) }
|
137
138
|
|
138
|
-
subject { Repository.new.
|
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) {
|
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'
|