pact_broker 2.15.0 → 2.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +7 -3
- data/CHANGELOG.md +53 -0
- data/DEVELOPER_DOCUMENTATION.md +28 -1
- data/DEVELOPER_SETUP.md +1 -1
- data/README.md +8 -5
- data/db/migrations/000004_create_tags_table.rb +1 -1
- data/db/migrations/000050_create_latest_matrix.rb +1 -0
- data/db/migrations/20180122_create_head_pact_publications.rb +21 -0
- data/db/migrations/20180123_create_tags_with_latest_flag.rb +28 -0
- data/db/migrations/20180129_create_latest_matrix_for_cv_and_pv.rb +91 -0
- data/db/migrations/20180130_create_materialized_matrix.rb +35 -0
- data/db/migrations/20180131_create_materialized_latest_matrix.rb +35 -0
- data/db/migrations/20180201_create_head_matrix.rb +33 -0
- data/db/migrations/20180202_create_materialized_head_matrix.rb +34 -0
- data/db/migrations/20180203_fix_head_matrix.rb +36 -0
- data/db/migrations/20180204_fix_latest_matrix_for_cv_and_pv.rb +57 -0
- data/db/migrations/20180205_drop_materialized_latest_matrix.rb +36 -0
- data/db/migrations/20180206_recreate_head_matrix_rename_consumer_tag_name.rb +68 -0
- data/db/migrations/20180207_recreate_head_matrix_union_all.rb +60 -0
- data/db/migrations/20180208_add_cv_tag_name_index_to_mat_head_matrix.rb +7 -0
- data/db/migrations/20180209_recreate_latest_matrix_for_cv_and_pv_union_all.rb +54 -0
- data/db/migrations/20180210_fix_latest_matrix_for_cv_and_pv_again.rb +53 -0
- data/db/migrations/migration_helper.rb +8 -0
- data/db/test/backwards_compatibility/Rakefile +1 -1
- data/example/pact_broker_database.sqlite3 +0 -0
- data/lib/pact_broker/api.rb +1 -0
- data/lib/pact_broker/api/decorators/dashboard_decorator.rb +163 -0
- data/lib/pact_broker/api/decorators/dashboard_text_decorator.rb +50 -0
- data/lib/pact_broker/api/decorators/matrix_decorator.rb +21 -16
- data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +1 -0
- data/lib/pact_broker/api/pact_broker_urls.rb +29 -0
- data/lib/pact_broker/api/resources/base_resource.rb +3 -0
- data/lib/pact_broker/api/resources/dashboard.rb +38 -0
- data/lib/pact_broker/api/resources/label.rb +0 -1
- data/lib/pact_broker/api/resources/tag.rb +0 -1
- data/lib/pact_broker/dashboard/service.rb +0 -0
- data/lib/pact_broker/domain/index_item.rb +16 -5
- data/lib/pact_broker/index/service.rb +69 -4
- data/lib/pact_broker/matrix/head_row.rb +11 -0
- data/lib/pact_broker/matrix/latest_row.rb +2 -16
- data/lib/pact_broker/matrix/repository.rb +56 -11
- data/lib/pact_broker/matrix/row.rb +166 -6
- data/lib/pact_broker/matrix/service.rb +5 -0
- data/lib/pact_broker/tags/tag_with_latest_flag.rb +18 -0
- data/lib/pact_broker/ui/controllers/index.rb +5 -2
- data/lib/pact_broker/ui/controllers/matrix.rb +3 -3
- data/lib/pact_broker/ui/view_models/index_item.rb +13 -5
- data/lib/pact_broker/ui/view_models/matrix_line.rb +77 -8
- data/lib/pact_broker/ui/view_models/matrix_lines.rb +17 -0
- data/lib/pact_broker/ui/view_models/matrix_tag.rb +42 -0
- data/lib/pact_broker/ui/views/index/show-with-tags.haml +26 -14
- data/lib/pact_broker/ui/views/index/show.haml +9 -8
- data/lib/pact_broker/ui/views/matrix/show.haml +46 -15
- data/lib/pact_broker/verifications/latest_verifications_by_consumer_version.rb +1 -0
- data/lib/pact_broker/verifications/repository.rb +4 -4
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/versions/abbreviate_number.rb +14 -0
- data/pact_broker.gemspec +3 -2
- data/public/images/logo@2x.png +0 -0
- data/public/javascripts/matrix.js +5 -0
- data/public/stylesheets/index.css +33 -1
- data/public/stylesheets/matrix.css +9 -0
- data/script/db-spec.sh +1 -1
- data/spec/features/get_dashboard_spec.rb +29 -0
- data/spec/fixtures/dashboard.json +83 -0
- data/spec/lib/pact_broker/api/decorators/dashboard_decorator_spec.rb +89 -0
- data/spec/lib/pact_broker/api/decorators/matrix_decorator_spec.rb +30 -26
- data/spec/lib/pact_broker/api/resources/dashboard_spec.rb +16 -0
- data/spec/lib/pact_broker/api/resources/group_spec.rb +1 -0
- data/spec/lib/pact_broker/index/service_spec.rb +146 -32
- data/spec/lib/pact_broker/matrix/repository_spec.rb +48 -1
- data/spec/lib/pact_broker/matrix/row_spec.rb +59 -0
- data/spec/lib/pact_broker/ui/view_models/index_item_spec.rb +17 -12
- data/spec/lib/pact_broker/versions/abbreviate_number_spec.rb +22 -0
- data/spec/migrations/20180201_create_head_matrix_spec.rb +132 -0
- data/spec/migrations/23_pact_versions_spec.rb +2 -2
- data/spec/migrations/50_create_latest_matrix_spec.rb +84 -16
- data/spec/migrations/change_migration_strategy_spec.rb +1 -1
- data/spec/service_consumers/pact_helper.rb +4 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/support/migration_helpers.rb +1 -1
- data/spec/support/rspec_match_hash.rb +6 -2
- data/spec/support/shared_examples_for_responses.rb +1 -1
- data/spec/support/test_data_builder.rb +61 -11
- metadata +57 -6
@@ -47,16 +47,16 @@ module PactBroker
|
|
47
47
|
# The most recent verification for the latest revision of the pact
|
48
48
|
# belonging to the version with the largest consumer_version_order.
|
49
49
|
|
50
|
-
def find_latest_verification_for consumer_name, provider_name,
|
50
|
+
def find_latest_verification_for consumer_name, provider_name, consumer_version_tag = nil
|
51
51
|
query = LatestVerificationsByConsumerVersion
|
52
52
|
.select_all_qualified
|
53
53
|
.join(:all_pact_publications, pact_version_id: :pact_version_id)
|
54
54
|
.consumer(consumer_name)
|
55
55
|
.provider(provider_name)
|
56
|
-
if
|
56
|
+
if consumer_version_tag == :untagged
|
57
57
|
query = query.untagged
|
58
|
-
elsif
|
59
|
-
query = query.tag(
|
58
|
+
elsif consumer_version_tag
|
59
|
+
query = query.tag(consumer_version_tag)
|
60
60
|
end
|
61
61
|
query.reverse_order(
|
62
62
|
Sequel[:all_pact_publications][:consumer_version_order],
|
data/lib/pact_broker/version.rb
CHANGED
data/pact_broker.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |gem|
|
|
26
26
|
gem.add_runtime_dependency 'roar', '~> 1.1'
|
27
27
|
gem.add_runtime_dependency 'reform', '~> 2.2'
|
28
28
|
gem.add_runtime_dependency 'dry-validation', '~> 0.10.5'
|
29
|
-
gem.add_runtime_dependency 'sequel', '~>
|
29
|
+
gem.add_runtime_dependency 'sequel', '~> 5.6'
|
30
30
|
gem.add_runtime_dependency 'webmachine', '1.5.0'
|
31
31
|
gem.add_runtime_dependency 'semver2', '~> 3.4.2'
|
32
32
|
gem.add_runtime_dependency 'rack', '~>2.0'
|
@@ -34,13 +34,14 @@ Gem::Specification.new do |gem|
|
|
34
34
|
gem.add_runtime_dependency 'pact-support'
|
35
35
|
gem.add_runtime_dependency 'padrino-core', '>= 0.14.3', '~> 0.14'
|
36
36
|
gem.add_runtime_dependency 'sinatra', '>= 2.0.1'
|
37
|
-
gem.add_runtime_dependency 'haml', '~>
|
37
|
+
gem.add_runtime_dependency 'haml', '~>5.0'
|
38
38
|
gem.add_runtime_dependency 'sucker_punch', '~>2.0'
|
39
39
|
gem.add_runtime_dependency 'rack-protection', '~>2.0'
|
40
40
|
gem.add_runtime_dependency 'dry-types', '~> 0.10.3' # https://travis-ci.org/pact-foundation/pact_broker/jobs/249448621
|
41
41
|
gem.add_runtime_dependency 'table_print', '~> 1.5'
|
42
42
|
|
43
43
|
gem.add_development_dependency 'pact', '~>1.14'
|
44
|
+
gem.add_development_dependency 'rspec-pact-matchers', '~>0.1'
|
44
45
|
gem.add_development_dependency 'bundler-audit', '~>0.4'
|
45
46
|
gem.add_development_dependency 'sqlite3', '~>1.3'
|
46
47
|
gem.add_development_dependency 'pry-byebug'
|
Binary file
|
@@ -12,7 +12,7 @@
|
|
12
12
|
}
|
13
13
|
|
14
14
|
table#relationships {
|
15
|
-
table-layout: fixed
|
15
|
+
/*table-layout: fixed;*/
|
16
16
|
}
|
17
17
|
|
18
18
|
table#relationships td,
|
@@ -76,9 +76,41 @@ span.pact:hover svg path, span.pact-matrix:hover svg path {
|
|
76
76
|
stroke: #2a6496;
|
77
77
|
}
|
78
78
|
|
79
|
+
#navigation .container-fluid {
|
80
|
+
padding-left: 0px;
|
81
|
+
display: flex;
|
82
|
+
justify-content: space-between;
|
83
|
+
align-items: center;
|
84
|
+
}
|
85
|
+
|
86
|
+
#navigation .container-fluid .navbar-brand {
|
87
|
+
padding: 0px;
|
88
|
+
display: flex;
|
89
|
+
align-items: center;
|
90
|
+
}
|
91
|
+
|
92
|
+
#navigation .container-fluid:before {
|
93
|
+
content: '' !important;
|
94
|
+
display: none;
|
95
|
+
}
|
96
|
+
|
97
|
+
#navigation .container-fluid:after {
|
98
|
+
content: '' !important;
|
99
|
+
display: none;
|
100
|
+
}
|
101
|
+
|
79
102
|
#top-left-menu li a{
|
80
103
|
padding-left: 10px
|
81
104
|
}
|
82
105
|
#top-left-menu li{
|
83
106
|
list-style: none;
|
84
107
|
}
|
108
|
+
|
109
|
+
table#relationships .label {
|
110
|
+
word-wrap: break-word;
|
111
|
+
white-space: normal;
|
112
|
+
}
|
113
|
+
|
114
|
+
div.tag {
|
115
|
+
display: inline-block;
|
116
|
+
}
|
data/script/db-spec.sh
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
describe "Get dashboard" do
|
2
|
+
|
3
|
+
let(:path) { "/dashboard" }
|
4
|
+
let(:last_response_body) { JSON.parse(subject.body, symbolize_names: true) }
|
5
|
+
|
6
|
+
before do
|
7
|
+
TestDataBuilder.new
|
8
|
+
.create_consumer("Foo")
|
9
|
+
.create_provider("Bar")
|
10
|
+
.create_consumer_version("1.2.3")
|
11
|
+
.create_consumer_version_tag("prod")
|
12
|
+
.create_pact
|
13
|
+
.create_verification(provider_version: "4.5.6", tag_names: "dev")
|
14
|
+
.create_webhook
|
15
|
+
.create_triggered_webhook
|
16
|
+
.create_webhook_execution
|
17
|
+
end
|
18
|
+
|
19
|
+
subject { get path; last_response }
|
20
|
+
|
21
|
+
it "returns a 200 HAL JSON response" do
|
22
|
+
expect(subject).to be_a_hal_json_success_response
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns a list of items" do
|
26
|
+
items = JSON.parse(subject.body)['items']
|
27
|
+
expect(items).to be_instance_of(Array)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
{
|
2
|
+
"items": [
|
3
|
+
{
|
4
|
+
"_links": {
|
5
|
+
"pb:webhook-status": {
|
6
|
+
"href": "webhooks_status_url",
|
7
|
+
"title": "Status of webhooks for Foo/Bar pact"
|
8
|
+
}
|
9
|
+
},
|
10
|
+
"consumer": {
|
11
|
+
"_links": {
|
12
|
+
"self": {
|
13
|
+
"href": "consumer_url"
|
14
|
+
}
|
15
|
+
},
|
16
|
+
"name": "Foo",
|
17
|
+
"version": {
|
18
|
+
"_links": {
|
19
|
+
"self": {
|
20
|
+
"href": "consumer_version_url"
|
21
|
+
}
|
22
|
+
},
|
23
|
+
"number": "1"
|
24
|
+
}
|
25
|
+
},
|
26
|
+
"latestVerificationResult": {
|
27
|
+
"_links": {
|
28
|
+
"self": {
|
29
|
+
"href": "verification_url"
|
30
|
+
}
|
31
|
+
},
|
32
|
+
"success": true,
|
33
|
+
"verifiedAt": "2018-01-01T00:00:00+00:00"
|
34
|
+
},
|
35
|
+
"latestWebhookExecution": {
|
36
|
+
"triggeredAt": "2018-01-01T00:00:00+00:00"
|
37
|
+
},
|
38
|
+
"pactTags": [
|
39
|
+
{
|
40
|
+
"name": "prod",
|
41
|
+
"latest": true,
|
42
|
+
"_links": {
|
43
|
+
"self": {
|
44
|
+
"href": "pact_prod_tag_url"
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
],
|
49
|
+
"latestVerificationResultTags": [
|
50
|
+
{
|
51
|
+
"name": "dev",
|
52
|
+
"latest": true,
|
53
|
+
"_links": {
|
54
|
+
"self": {
|
55
|
+
"href": "verification_dev_tag_url"
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
],
|
60
|
+
"pact": {
|
61
|
+
"_links": {
|
62
|
+
"self": {
|
63
|
+
"href": "pact_url"
|
64
|
+
}
|
65
|
+
},
|
66
|
+
"createdAt": "2018-01-01T00:00:00+00:00"
|
67
|
+
},
|
68
|
+
"provider": {
|
69
|
+
"_links": {
|
70
|
+
"self": {
|
71
|
+
"href": "provider_url"
|
72
|
+
}
|
73
|
+
},
|
74
|
+
"name": "Bar",
|
75
|
+
"version": {
|
76
|
+
"number": "2"
|
77
|
+
}
|
78
|
+
},
|
79
|
+
"verificationStatus": "wiffle",
|
80
|
+
"webhookStatus": "blah"
|
81
|
+
}
|
82
|
+
]
|
83
|
+
}
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'pact_broker/api/decorators/dashboard_decorator'
|
2
|
+
require 'pact_broker/domain/index_item'
|
3
|
+
|
4
|
+
module PactBroker
|
5
|
+
module Api
|
6
|
+
module Decorators
|
7
|
+
describe DashboardDecorator do
|
8
|
+
let(:index_item) do
|
9
|
+
instance_double('PactBroker::Domain::IndexItem',
|
10
|
+
consumer: consumer,
|
11
|
+
provider: provider,
|
12
|
+
consumer_name: consumer.name,
|
13
|
+
provider_name: provider.name,
|
14
|
+
latest_pact: pact,
|
15
|
+
latest_verification: verification,
|
16
|
+
provider_version: provider_version,
|
17
|
+
consumer_version: consumer_version,
|
18
|
+
last_webhook_execution_date: last_webhook_execution_date,
|
19
|
+
webhook_status: 'blah',
|
20
|
+
verification_status: 'wiffle',
|
21
|
+
provider_version_number: provider_version.number,
|
22
|
+
consumer_version_number: consumer_version.number,
|
23
|
+
tag_names: ['prod'],
|
24
|
+
latest_verification_latest_tags: [double('tag', name: 'dev', latest?: true)]
|
25
|
+
)
|
26
|
+
end
|
27
|
+
let(:consumer) { instance_double('PactBroker::Domain::Pacticipant', name: 'Foo') }
|
28
|
+
let(:provider) { instance_double('PactBroker::Domain::Pacticipant', name: 'Bar') }
|
29
|
+
let(:pact) { instance_double('PactBroker::Domain::Pact', created_at: DateTime.new(2018)) }
|
30
|
+
let(:verification) { instance_double('PactBroker::Domain::Verification', success: true, created_at: DateTime.new(2018)) }
|
31
|
+
let(:consumer_version) { instance_double('PactBroker::Domain::Version', number: '1', pacticipant: consumer) }
|
32
|
+
let(:provider_version) { instance_double('PactBroker::Domain::Version', number: '2', pacticipant: provider) }
|
33
|
+
let(:last_webhook_execution_date) { Date.new(2018) }
|
34
|
+
let(:base_url) { 'http://example.org' }
|
35
|
+
let(:options) { { user_options: { base_url: base_url } } }
|
36
|
+
let(:dashboard_json) { DashboardDecorator.new([index_item]).to_json(options) }
|
37
|
+
|
38
|
+
before do
|
39
|
+
allow_any_instance_of(DashboardDecorator).to receive(:pact_url).with(base_url, pact).and_return('pact_url')
|
40
|
+
allow_any_instance_of(DashboardDecorator).to receive(:verification_url).with(verification, base_url).and_return('verification_url')
|
41
|
+
allow_any_instance_of(DashboardDecorator).to receive(:pacticipant_url).with(base_url, consumer).and_return('consumer_url')
|
42
|
+
allow_any_instance_of(DashboardDecorator).to receive(:pacticipant_url).with(base_url, provider).and_return('provider_url')
|
43
|
+
allow_any_instance_of(DashboardDecorator).to receive(:version_url).with(base_url, consumer_version).and_return('consumer_version_url')
|
44
|
+
allow_any_instance_of(DashboardDecorator).to receive(:webhooks_status_url).with(consumer, provider, base_url).and_return('webhooks_status_url')
|
45
|
+
allow_any_instance_of(DashboardDecorator).to receive(:tag_url) do | instance, base_url, tag |
|
46
|
+
if tag.version == consumer_version
|
47
|
+
expect(tag.name).to eq 'prod'
|
48
|
+
expect(tag.version).to be consumer_version
|
49
|
+
expect(base_url).to eq base_url
|
50
|
+
'pact_prod_tag_url'
|
51
|
+
else
|
52
|
+
expect(tag.name).to eq 'dev'
|
53
|
+
expect(tag.version).to be provider_version
|
54
|
+
expect(base_url).to eq base_url
|
55
|
+
'verification_dev_tag_url'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
let(:expected_hash) { JSON.parse(File.read('spec/fixtures/dashboard.json')) }
|
61
|
+
|
62
|
+
subject { JSON.parse(dashboard_json) }
|
63
|
+
|
64
|
+
it "creates some json" do
|
65
|
+
expect(subject).to match_pact(expected_hash, {allow_unexpected_keys: false})
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when the pact has never been verified" do
|
69
|
+
let(:verification) { nil }
|
70
|
+
|
71
|
+
it "has a null last verification and provider version" do
|
72
|
+
expected_hash['items'][0]['latestVerificationResult'] = nil
|
73
|
+
expected_hash['items'][0]['provider']['version'] = nil
|
74
|
+
expect(subject).to match_pact(expected_hash, {allow_unexpected_keys: false})
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when no webhooks have been executed" do
|
79
|
+
let(:last_webhook_execution_date) { nil }
|
80
|
+
|
81
|
+
it "has a null latestWebhookExecution" do
|
82
|
+
expected_hash['items'][0]['latestWebhookExecution'] = nil
|
83
|
+
expect(subject).to match_pact(expected_hash, {allow_unexpected_keys: false})
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -10,33 +10,37 @@ module PactBroker
|
|
10
10
|
let(:line_1_success) { true }
|
11
11
|
let(:line_2_success) { true }
|
12
12
|
let(:line_1) do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
double('PactBroker::Matrix::Row',
|
14
|
+
{
|
15
|
+
consumer_name: "Consumer",
|
16
|
+
consumer_version_number: "1.0.0",
|
17
|
+
pact_version_sha: "1234",
|
18
|
+
pact_created_at: pact_created_at,
|
19
|
+
provider_version_number: "4.5.6",
|
20
|
+
provider_name: "Provider",
|
21
|
+
success: line_1_success,
|
22
|
+
verification_number: 1,
|
23
|
+
verification_build_url: nil,
|
24
|
+
verification_executed_at: verification_date
|
25
|
+
}
|
26
|
+
)
|
25
27
|
end
|
26
28
|
|
27
29
|
let(:line_2) do
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
30
|
+
double('PactBroker::Matrix::Row',
|
31
|
+
{
|
32
|
+
consumer_name: "Consumer",
|
33
|
+
consumer_version_number: "1.0.0",
|
34
|
+
pact_version_sha: "1234",
|
35
|
+
pact_created_at: pact_created_at,
|
36
|
+
provider_version_number: nil,
|
37
|
+
provider_name: "Provider",
|
38
|
+
success: line_2_success,
|
39
|
+
verification_number: nil,
|
40
|
+
verification_build_url: nil,
|
41
|
+
verification_executed_at: verification_date
|
42
|
+
}
|
43
|
+
)
|
40
44
|
end
|
41
45
|
|
42
46
|
let(:consumer_hash) do
|
@@ -122,8 +126,8 @@ module PactBroker
|
|
122
126
|
|
123
127
|
context "when the pact has not been verified" do
|
124
128
|
before do
|
125
|
-
line_2
|
126
|
-
line_2
|
129
|
+
allow(line_2).to receive(:success).and_return(nil)
|
130
|
+
allow(line_2).to receive(:verification_executed_at).and_return(nil)
|
127
131
|
end
|
128
132
|
|
129
133
|
let(:verification_hash) { nil }
|