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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +7 -3
  3. data/CHANGELOG.md +53 -0
  4. data/DEVELOPER_DOCUMENTATION.md +28 -1
  5. data/DEVELOPER_SETUP.md +1 -1
  6. data/README.md +8 -5
  7. data/db/migrations/000004_create_tags_table.rb +1 -1
  8. data/db/migrations/000050_create_latest_matrix.rb +1 -0
  9. data/db/migrations/20180122_create_head_pact_publications.rb +21 -0
  10. data/db/migrations/20180123_create_tags_with_latest_flag.rb +28 -0
  11. data/db/migrations/20180129_create_latest_matrix_for_cv_and_pv.rb +91 -0
  12. data/db/migrations/20180130_create_materialized_matrix.rb +35 -0
  13. data/db/migrations/20180131_create_materialized_latest_matrix.rb +35 -0
  14. data/db/migrations/20180201_create_head_matrix.rb +33 -0
  15. data/db/migrations/20180202_create_materialized_head_matrix.rb +34 -0
  16. data/db/migrations/20180203_fix_head_matrix.rb +36 -0
  17. data/db/migrations/20180204_fix_latest_matrix_for_cv_and_pv.rb +57 -0
  18. data/db/migrations/20180205_drop_materialized_latest_matrix.rb +36 -0
  19. data/db/migrations/20180206_recreate_head_matrix_rename_consumer_tag_name.rb +68 -0
  20. data/db/migrations/20180207_recreate_head_matrix_union_all.rb +60 -0
  21. data/db/migrations/20180208_add_cv_tag_name_index_to_mat_head_matrix.rb +7 -0
  22. data/db/migrations/20180209_recreate_latest_matrix_for_cv_and_pv_union_all.rb +54 -0
  23. data/db/migrations/20180210_fix_latest_matrix_for_cv_and_pv_again.rb +53 -0
  24. data/db/migrations/migration_helper.rb +8 -0
  25. data/db/test/backwards_compatibility/Rakefile +1 -1
  26. data/example/pact_broker_database.sqlite3 +0 -0
  27. data/lib/pact_broker/api.rb +1 -0
  28. data/lib/pact_broker/api/decorators/dashboard_decorator.rb +163 -0
  29. data/lib/pact_broker/api/decorators/dashboard_text_decorator.rb +50 -0
  30. data/lib/pact_broker/api/decorators/matrix_decorator.rb +21 -16
  31. data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +1 -0
  32. data/lib/pact_broker/api/pact_broker_urls.rb +29 -0
  33. data/lib/pact_broker/api/resources/base_resource.rb +3 -0
  34. data/lib/pact_broker/api/resources/dashboard.rb +38 -0
  35. data/lib/pact_broker/api/resources/label.rb +0 -1
  36. data/lib/pact_broker/api/resources/tag.rb +0 -1
  37. data/lib/pact_broker/dashboard/service.rb +0 -0
  38. data/lib/pact_broker/domain/index_item.rb +16 -5
  39. data/lib/pact_broker/index/service.rb +69 -4
  40. data/lib/pact_broker/matrix/head_row.rb +11 -0
  41. data/lib/pact_broker/matrix/latest_row.rb +2 -16
  42. data/lib/pact_broker/matrix/repository.rb +56 -11
  43. data/lib/pact_broker/matrix/row.rb +166 -6
  44. data/lib/pact_broker/matrix/service.rb +5 -0
  45. data/lib/pact_broker/tags/tag_with_latest_flag.rb +18 -0
  46. data/lib/pact_broker/ui/controllers/index.rb +5 -2
  47. data/lib/pact_broker/ui/controllers/matrix.rb +3 -3
  48. data/lib/pact_broker/ui/view_models/index_item.rb +13 -5
  49. data/lib/pact_broker/ui/view_models/matrix_line.rb +77 -8
  50. data/lib/pact_broker/ui/view_models/matrix_lines.rb +17 -0
  51. data/lib/pact_broker/ui/view_models/matrix_tag.rb +42 -0
  52. data/lib/pact_broker/ui/views/index/show-with-tags.haml +26 -14
  53. data/lib/pact_broker/ui/views/index/show.haml +9 -8
  54. data/lib/pact_broker/ui/views/matrix/show.haml +46 -15
  55. data/lib/pact_broker/verifications/latest_verifications_by_consumer_version.rb +1 -0
  56. data/lib/pact_broker/verifications/repository.rb +4 -4
  57. data/lib/pact_broker/version.rb +1 -1
  58. data/lib/pact_broker/versions/abbreviate_number.rb +14 -0
  59. data/pact_broker.gemspec +3 -2
  60. data/public/images/logo@2x.png +0 -0
  61. data/public/javascripts/matrix.js +5 -0
  62. data/public/stylesheets/index.css +33 -1
  63. data/public/stylesheets/matrix.css +9 -0
  64. data/script/db-spec.sh +1 -1
  65. data/spec/features/get_dashboard_spec.rb +29 -0
  66. data/spec/fixtures/dashboard.json +83 -0
  67. data/spec/lib/pact_broker/api/decorators/dashboard_decorator_spec.rb +89 -0
  68. data/spec/lib/pact_broker/api/decorators/matrix_decorator_spec.rb +30 -26
  69. data/spec/lib/pact_broker/api/resources/dashboard_spec.rb +16 -0
  70. data/spec/lib/pact_broker/api/resources/group_spec.rb +1 -0
  71. data/spec/lib/pact_broker/index/service_spec.rb +146 -32
  72. data/spec/lib/pact_broker/matrix/repository_spec.rb +48 -1
  73. data/spec/lib/pact_broker/matrix/row_spec.rb +59 -0
  74. data/spec/lib/pact_broker/ui/view_models/index_item_spec.rb +17 -12
  75. data/spec/lib/pact_broker/versions/abbreviate_number_spec.rb +22 -0
  76. data/spec/migrations/20180201_create_head_matrix_spec.rb +132 -0
  77. data/spec/migrations/23_pact_versions_spec.rb +2 -2
  78. data/spec/migrations/50_create_latest_matrix_spec.rb +84 -16
  79. data/spec/migrations/change_migration_strategy_spec.rb +1 -1
  80. data/spec/service_consumers/pact_helper.rb +4 -1
  81. data/spec/spec_helper.rb +1 -0
  82. data/spec/support/migration_helpers.rb +1 -1
  83. data/spec/support/rspec_match_hash.rb +6 -2
  84. data/spec/support/shared_examples_for_responses.rb +1 -1
  85. data/spec/support/test_data_builder.rb +61 -11
  86. metadata +57 -6
@@ -6,6 +6,7 @@ module PactBroker
6
6
 
7
7
  include PactBroker::Repositories::Helpers
8
8
 
9
+ # TODO rename this to LatestVerificationsByPactVersion
9
10
  class LatestVerificationsByConsumerVersion < PactBroker::Domain::Verification
10
11
  set_dataset(:latest_verifications)
11
12
  end
@@ -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, tag = nil
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 tag == :untagged
56
+ if consumer_version_tag == :untagged
57
57
  query = query.untagged
58
- elsif tag
59
- query = query.tag(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],
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = '2.15.0'
2
+ VERSION = '2.16.0'
3
3
  end
@@ -0,0 +1,14 @@
1
+ module PactBroker
2
+ module Versions
3
+ class AbbreviateNumber
4
+
5
+ def self.call version_number
6
+ if version_number
7
+ version_number.gsub(/[A-Za-z0-9]{40}/) do | val |
8
+ val[0..6]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
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', '~> 4.23'
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', '~>4.0'
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
@@ -57,4 +57,9 @@ $(document).ready(function(){
57
57
  return n.attr('data-sort-value') || n.text();
58
58
  }
59
59
  });
60
+
61
+
62
+ $('[data-toggle="tooltip"]').each(function(index, el){
63
+ $(el).tooltip({container: $(el)});
64
+ });
60
65
  });
@@ -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
+ }
@@ -10,3 +10,12 @@ input[type="radio"] {
10
10
  div.top-of-group {
11
11
  margin-top: 10px;
12
12
  }
13
+
14
+ div.tag-parent {
15
+ margin-top: 5px;
16
+ margin-bottom: 1px;
17
+ }
18
+
19
+ div.tag {
20
+ display: inline-block;
21
+ }
data/script/db-spec.sh CHANGED
@@ -9,6 +9,6 @@ bundle exec appraisal install
9
9
  set +e
10
10
  bundle exec rake
11
11
  rake_exit_code=$?
12
- if [[ $rake_exit_code -ne 0 && -n "$TRAVIS" ]]; then
12
+ if [ $rake_exit_code -ne 0 ] && [ -n "$TRAVIS" ]; then
13
13
  cat log/pact_broker.log
14
14
  fi
@@ -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
- consumer_name: "Consumer",
15
- consumer_version_number: "1.0.0",
16
- pact_version_sha: "1234",
17
- pact_created_at: pact_created_at,
18
- provider_version_number: "4.5.6",
19
- provider_name: "Provider",
20
- success: line_1_success,
21
- verification_number: 1,
22
- verification_build_url: nil,
23
- verification_executed_at: verification_date
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
- consumer_name: "Consumer",
30
- consumer_version_number: "1.0.0",
31
- pact_version_sha: "1234",
32
- pact_created_at: pact_created_at,
33
- provider_version_number: nil,
34
- provider_name: "Provider",
35
- success: line_2_success,
36
- verification_number: nil,
37
- verification_build_url: nil,
38
- verification_executed_at: verification_date
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[:success] = nil
126
- line_2[:verification_executed_at] = nil
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 }
@@ -0,0 +1,16 @@
1
+ require 'pact_broker/api/resources/dashboard'
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Resources
6
+
7
+ describe Dashboard do
8
+
9
+ let(:path) { "/dashboard" }
10
+ subject { get path; last_response }
11
+
12
+
13
+ end
14
+ end
15
+ end
16
+ end