pact_broker 2.6.0 → 2.7.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/db/migrations/42_delete_orphan_webhook_data.rb +0 -2
  4. data/db/migrations/43_add_provider_version_to_verification.rb +12 -0
  5. data/db/migrations/44_populate_verifications_provider_version_id.rb +25 -0
  6. data/db/migrations/45_set_verification_provider_number_nullable.rb +7 -0
  7. data/db/migrations/46_recreate_latest_verifications.rb +18 -0
  8. data/db/migrations/47_create_all_verifications.rb +19 -0
  9. data/lib/pact_broker/api.rb +4 -0
  10. data/lib/pact_broker/api/decorators/matrix_decorator.rb +114 -0
  11. data/lib/pact_broker/api/decorators/verification_decorator.rb +1 -1
  12. data/lib/pact_broker/api/pact_broker_urls.rb +2 -2
  13. data/lib/pact_broker/api/resources/index.rb +3 -5
  14. data/lib/pact_broker/api/resources/matrix.rb +48 -0
  15. data/lib/pact_broker/api/resources/matrix_for_consumer_and_provider.rb +42 -0
  16. data/lib/pact_broker/domain/relationship.rb +26 -6
  17. data/lib/pact_broker/domain/verification.rb +5 -1
  18. data/lib/pact_broker/matrix/repository.rb +51 -0
  19. data/lib/pact_broker/matrix/service.rb +50 -0
  20. data/lib/pact_broker/pacticipants/service.rb +21 -5
  21. data/lib/pact_broker/pacts/all_pact_publications.rb +11 -0
  22. data/lib/pact_broker/pacts/pact_publication.rb +4 -0
  23. data/lib/pact_broker/pacts/repository.rb +1 -1
  24. data/lib/pact_broker/repositories.rb +5 -0
  25. data/lib/pact_broker/services.rb +5 -0
  26. data/lib/pact_broker/tags/service.rb +0 -1
  27. data/lib/pact_broker/ui/app.rb +5 -0
  28. data/lib/pact_broker/ui/controllers/matrix.rb +27 -0
  29. data/lib/pact_broker/ui/controllers/relationships.rb +2 -2
  30. data/lib/pact_broker/ui/view_models/matrix_line.rb +79 -0
  31. data/lib/pact_broker/ui/view_models/relationship.rb +22 -4
  32. data/lib/pact_broker/ui/views/matrix/show.haml +42 -0
  33. data/lib/pact_broker/ui/views/relationships/show-prod-tags.haml +83 -0
  34. data/lib/pact_broker/ui/views/relationships/show.haml +1 -1
  35. data/lib/pact_broker/verifications/repository.rb +8 -1
  36. data/lib/pact_broker/verifications/service.rb +2 -1
  37. data/lib/pact_broker/version.rb +1 -1
  38. data/lib/pact_broker/versions/service.rb +7 -0
  39. data/lib/pact_broker/webhooks/status.rb +1 -1
  40. data/lib/rack/pact_broker/convert_file_extension_to_accept_header.rb +1 -1
  41. data/script/seed.rb +5 -0
  42. data/spec/features/get_matrix_for_consumer_and_provider_spec.rb +25 -0
  43. data/spec/features/get_matrix_spec.rb +31 -0
  44. data/spec/lib/pact_broker/api/decorators/matrix_decorator_spec.rb +133 -0
  45. data/spec/lib/pact_broker/api/decorators/verification_decorator_spec.rb +2 -8
  46. data/spec/lib/pact_broker/api/decorators/verification_summary_decorator_spec.rb +3 -2
  47. data/spec/lib/pact_broker/api/resources/matrix_spec.rb +38 -0
  48. data/spec/lib/pact_broker/domain/relationship_spec.rb +1 -1
  49. data/spec/lib/pact_broker/matrix/repository_spec.rb +153 -0
  50. data/spec/lib/pact_broker/matrix/service_spec.rb +46 -0
  51. data/spec/lib/pact_broker/pacticipants/service_spec.rb +78 -4
  52. data/spec/lib/pact_broker/pacts/pact_publication_spec.rb +35 -0
  53. data/spec/lib/pact_broker/pacts/repository_spec.rb +16 -14
  54. data/spec/lib/pact_broker/ui/view_models/relationship_spec.rb +5 -6
  55. data/spec/lib/pact_broker/verifications/repository_spec.rb +7 -7
  56. data/spec/lib/pact_broker/verifications/service_spec.rb +6 -0
  57. data/spec/lib/pact_broker/versions/service_spec.rb +37 -0
  58. data/spec/lib/pact_broker/webhooks/status_spec.rb +6 -0
  59. data/spec/migrations/44_add_provider_version_to_verification_spec.rb +60 -0
  60. data/spec/service_consumers/provider_states_for_pact_broker_client.rb +12 -0
  61. data/spec/support/shared_examples_for_responses.rb +4 -0
  62. data/spec/support/test_data_builder.rb +26 -3
  63. metadata +34 -4
@@ -0,0 +1,83 @@
1
+ %body
2
+ %link{rel: 'stylesheet', href: '/css/bootstrap.min.css'}
3
+ %link{rel: 'stylesheet', href: '/stylesheets/relationships.css'}
4
+ %script{type: 'text/javascript', src:'/javascripts/jquery-2.1.1.min.js'}
5
+ %script{type: 'text/javascript', src:'/javascripts/jquery.tablesorter.min.js'}
6
+ %script{type: 'text/javascript', src:'/js/bootstrap.min.js'}
7
+ %nav.navbase-default.navbar-right{role: "navigation"}
8
+ .container
9
+ %ul
10
+ %li.navbar-right
11
+ %a{href: '/hal-browser/browser.html'}
12
+ HAL Browser
13
+ .container
14
+ %h1.page-header
15
+ Pacts
16
+ %table.table.table-bordered.table-striped{id: 'relationships'}
17
+ %thead
18
+ %th.consumer
19
+ Consumer
20
+ %span.glyphicon.glyphicon-sort.relationships-sort
21
+ %th.tag
22
+ Version
23
+ %span.glyphicon.glyphicon-sort.relationships-sort
24
+ %th.pact
25
+ %th.provider
26
+ Provider
27
+ %span.glyphicon.glyphicon-sort.relationships-sort
28
+ %th.tag
29
+ Version
30
+ %span.glyphicon.glyphicon-sort.relationships-sort
31
+ %th
32
+ Published
33
+ %th
34
+ Webhook<br>status
35
+ %th
36
+ Last<br>verified
37
+ %tbody
38
+
39
+ - relationships.each do | relationship |
40
+ %tr
41
+ %td.consumer
42
+ %a{:href => relationship.consumer_group_url}
43
+ = relationship.consumer_name
44
+ %td
45
+ = relationship.consumer_version_number
46
+ %span{style: 'color:gray'}
47
+ = relationship.tag_names
48
+ %td.pact
49
+ %a{:href => relationship.pact_url, :title => "View pact"}
50
+ %span.pact
51
+ %td.provider
52
+ %a{:href => relationship.provider_group_url}
53
+ = relationship.provider_name
54
+ %td
55
+ = relationship.provider_version_number
56
+ %td
57
+ = relationship.publication_date_of_latest_pact.gsub("about ", "")
58
+ %td{class: relationship.webhook_status}
59
+ - if relationship.show_webhook_status?
60
+ %a{:href => relationship.webhook_url}
61
+ = relationship.webhook_label
62
+
63
+ %td{class: relationship.verification_status, title: relationship.verification_tooltip, "data-toggle": "tooltip", "data-placement": "left"}
64
+ %div
65
+ = relationship.last_verified_date.gsub("about ", "")
66
+ - if relationship.warning?
67
+ %span.glyphicon.glyphicon-warning-sign{'aria-hidden':true}
68
+ %div.relationships-size
69
+ = relationships.size_label
70
+
71
+ :javascript
72
+ $(function(){
73
+ $("#relationships").tablesorter();
74
+ });
75
+
76
+ $(document).ready(function(){
77
+ $("span.pact").load("/images/doc-text.svg");
78
+ $('td[data-toggle="tooltip"]').each(function(index, td){
79
+ //appended tooltip div screws up table if it's appended after a
80
+ //td, so need to append it to a div
81
+ $(td).tooltip({container: $(td).first()});
82
+ });
83
+ });
@@ -40,7 +40,7 @@
40
40
  %a{:href => relationship.consumer_group_url}
41
41
  = relationship.consumer_name
42
42
  %td.pact
43
- %a{:href => relationship.latest_pact_url, :title => "View pact"}
43
+ %a{:href => relationship.pact_url, :title => "View pact"}
44
44
  %span.pact
45
45
  %td.provider
46
46
  %a{:href => relationship.provider_group_url}
@@ -7,9 +7,13 @@ module PactBroker
7
7
  class Repository
8
8
 
9
9
  include PactBroker::Repositories::Helpers
10
+ include PactBroker::Repositories
10
11
 
11
- def create verification, pact
12
+ def create verification, provider_version_number, pact
13
+ provider = pacticipant_repository.find_by_name(pact.provider_name)
14
+ version = version_repository.find_by_pacticipant_id_and_number_or_create(provider.id, provider_version_number)
12
15
  verification.pact_version_id = pact_version_id_for(pact)
16
+ verification.provider_version = version
13
17
  verification.save
14
18
  end
15
19
 
@@ -39,6 +43,9 @@ module PactBroker
39
43
  .all
40
44
  end
41
45
 
46
+ # The most recent verification for the latest revision of the pact
47
+ # belonging to the version with the largest consumer_version_order.
48
+
42
49
  def find_latest_verification_for consumer_name, provider_name, tag = nil
43
50
  query = LatestVerificationsByConsumerVersion
44
51
  .select_all_qualified
@@ -19,9 +19,10 @@ module PactBroker
19
19
  def create next_verification_number, params, pact
20
20
  PactBroker.logger.info "Creating verification #{next_verification_number} for pact_id=#{pact.id} from params #{params}"
21
21
  verification = PactBroker::Domain::Verification.new
22
+ provider_version_number = params.fetch('providerApplicationVersion')
22
23
  PactBroker::Api::Decorators::VerificationDecorator.new(verification).from_hash(params)
23
24
  verification.number = next_verification_number
24
- verification_repository.create(verification, pact)
25
+ verification_repository.create(verification, provider_version_number, pact)
25
26
  end
26
27
 
27
28
  def errors params
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = '2.6.0'
2
+ VERSION = '2.7.0.beta.1'
3
3
  end
@@ -16,6 +16,13 @@ module PactBroker
16
16
  pact_repository.delete_by_version_id version.id
17
17
  version_repository.delete_by_id version.id
18
18
  end
19
+
20
+ def self.find_versions_by_selector selectors
21
+ selectors.collect do | selector |
22
+ pacticipant_name, type, number = selector.split("/")
23
+ version_repository.find_by_pacticipant_name_and_number pacticipant_name, number
24
+ end
25
+ end
19
26
  end
20
27
  end
21
28
  end
@@ -13,7 +13,7 @@ module PactBroker
13
13
 
14
14
  def to_sym
15
15
  return :none if webhooks.empty?
16
- return :not_run if latest_triggered_webhooks.empty?
16
+ return :not_run if latest_triggered_webhooks.empty? || latest_triggered_webhooks.all?{|w| w.status == "not_run"}
17
17
  if latest_triggered_webhooks.any?{|w| w.status == "retrying" }
18
18
  return :retrying
19
19
  end
@@ -7,7 +7,7 @@ module Rack
7
7
 
8
8
  class ConvertFileExtensionToAcceptHeader
9
9
 
10
- EXTENSIONS = {".csv" => "text/csv", ".svg" => "image/svg+xml"}
10
+ EXTENSIONS = {".csv" => "text/csv", ".svg" => "image/svg+xml", ".json" => "application/hal+json"}
11
11
  EXTENSION_REGEXP = /\.\w+$/
12
12
 
13
13
  def initialize app
data/script/seed.rb CHANGED
@@ -59,9 +59,12 @@ TestDataBuilder.new
59
59
  .create_verification(provider_version: "1.4.234", success: true, execution_date: DateTime.now - 15)
60
60
  .revise_pact
61
61
  .create_consumer_version("1.2.101")
62
+ .create_consumer_version_tag('prod')
62
63
  .publish_pact
64
+ .create_verification(provider_version: "9.9.10", success: false, execution_date: DateTime.now - 15)
63
65
  .create_consumer_version("1.2.102")
64
66
  .publish_pact(created_at: (Date.today - 7).to_datetime)
67
+ .create_verification(provider_version: "9.9.9", success: true, execution_date: DateTime.now - 14)
65
68
  .create_provider("Animals")
66
69
  .create_webhook(method: 'GET', url: 'http://localhost:9393/')
67
70
  .publish_pact(created_at: (Time.now - 140).to_datetime)
@@ -76,6 +79,8 @@ TestDataBuilder.new
76
79
  .create_provider("The back end")
77
80
  .create_webhook(method: 'GET', url: 'http://localhost:9393/')
78
81
  .create_consumer_version("1.2.106")
82
+ .create_consumer_version_tag("production")
83
+ .create_consumer_version_tag("feat-x")
79
84
  .publish_pact
80
85
  .create_consumer("Some other app")
81
86
  .create_provider("A service")
@@ -0,0 +1,25 @@
1
+ require 'spec/support/test_data_builder'
2
+
3
+ describe "Get matrix for consumer and provider" do
4
+ before do
5
+ TestDataBuilder.new
6
+ .create_pact_with_hierarchy('Consumer', '1.0.0', 'Provider')
7
+ .create_verification(provider_version: '4.5.6')
8
+ end
9
+
10
+ let(:path) { "/matrix/provider/Provider/consumer/Consumer" }
11
+ let(:last_response_body) { JSON.parse(subject.body, symbolize_names: true) }
12
+
13
+ subject { get path; last_response }
14
+
15
+ it "returns a 200 HAL JSON response" do
16
+ expect(subject).to be_a_hal_json_success_response
17
+ end
18
+
19
+ it "returns the JSON representation of the matrix" do
20
+ expect(last_response_body[:matrix][0][:consumer]).to be_instance_of(Hash)
21
+ expect(last_response_body[:matrix][0][:provider]).to be_instance_of(Hash)
22
+ expect(last_response_body[:matrix][0][:pact]).to be_instance_of(Hash)
23
+ expect(last_response_body[:matrix][0][:verificationResult]).to be_instance_of(Hash)
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec/support/test_data_builder'
2
+
3
+ describe "Get matrix for consumer and provider" do
4
+ before do
5
+ TestDataBuilder.new
6
+ .create_pact_with_hierarchy('Consumer', '1.0.0', 'Provider')
7
+ .create_verification(provider_version: '4.5.6')
8
+ end
9
+
10
+ let(:path) { "/matrix" }
11
+ let(:params) do
12
+ {
13
+ selectors: ['Consumer/version/1.0.0','Provider/version/4.5.6']
14
+ }
15
+ end
16
+ let(:last_response_body) { JSON.parse(subject.body, symbolize_names: true) }
17
+
18
+ subject { get path, params; last_response }
19
+
20
+ it "returns a 200 HAL JSON response" do
21
+ expect(subject).to be_a_hal_json_success_response
22
+ end
23
+
24
+ it "returns the JSON representation of the matrix" do
25
+ expect(last_response_body[:matrix][0][:consumer]).to be_instance_of(Hash)
26
+ expect(last_response_body[:matrix][0][:provider]).to be_instance_of(Hash)
27
+ expect(last_response_body[:matrix][0][:pact]).to be_instance_of(Hash)
28
+ expect(last_response_body[:matrix][0][:verificationResult]).to be_instance_of(Hash)
29
+ end
30
+ end
31
+
@@ -0,0 +1,133 @@
1
+ require 'pact_broker/api/decorators/matrix_decorator'
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Decorators
6
+ describe MatrixPactDecorator do
7
+ describe "to_json" do
8
+ let(:verification_date) { DateTime.new(2017, 12, 31) }
9
+ let(:pact_created_at) { DateTime.new(2017, 1, 1) }
10
+ let(:line_1) do
11
+ {
12
+ consumer_name: "Consumer",
13
+ consumer_version_number: "1.0.0",
14
+ pact_version_sha: "1234",
15
+ pact_created_at: pact_created_at,
16
+ provider_version_number: "4.5.6",
17
+ provider_name: "Provider",
18
+ success: true,
19
+ number: 1,
20
+ build_url: nil,
21
+ verification_executed_at: verification_date
22
+ }
23
+ end
24
+
25
+ let(:line_2) do
26
+ {
27
+ consumer_name: "Consumer",
28
+ consumer_version_number: "1.0.0",
29
+ pact_version_sha: "1234",
30
+ pact_created_at: pact_created_at,
31
+ provider_version_number: nil,
32
+ provider_name: "Provider",
33
+ success: nil,
34
+ number: nil,
35
+ build_url: nil,
36
+ verification_executed_at: nil
37
+ }
38
+ end
39
+
40
+ let(:consumer_hash) do
41
+ {
42
+ name: 'Consumer',
43
+ _links: {
44
+ self: {
45
+ href: 'http://example.org/pacticipants/Consumer'
46
+ }
47
+ },
48
+ version: {
49
+ number: '1.0.0',
50
+ _links: {
51
+ self: {
52
+ href: 'http://example.org/pacticipants/Consumer/versions/1.0.0'
53
+ }
54
+ }
55
+ }
56
+ }
57
+ end
58
+
59
+ let(:provider_hash) do
60
+ {
61
+ name: 'Provider',
62
+ _links: {
63
+ self: {
64
+ href: 'http://example.org/pacticipants/Provider'
65
+ }
66
+ },
67
+ version: {
68
+ number: '4.5.6'
69
+ }
70
+ }
71
+ end
72
+
73
+ let(:verification_hash) do
74
+ {
75
+ success: true,
76
+ verifiedAt: "2017-12-31T00:00:00+00:00",
77
+ _links: {
78
+ self: {
79
+ href: "http://example.org/pacts/provider/Provider/consumer/Consumer/pact-version/1234/verification-results/1"
80
+ }
81
+ }
82
+ }
83
+ end
84
+
85
+ let(:pact_hash) do
86
+ {
87
+ createdAt: "2017-01-01T00:00:00+00:00",
88
+ _links: {
89
+ self: {
90
+ href: "http://example.org/pacts/provider/Provider/consumer/Consumer/version/1.0.0"
91
+ }
92
+ }
93
+ }
94
+ end
95
+
96
+ let(:lines){ [line_1, line_2]}
97
+ let(:json) { MatrixPactDecorator.new(lines).to_json(user_options: { base_url: 'http://example.org' }) }
98
+ let(:parsed_json) { JSON.parse(json, symbolize_names: true) }
99
+
100
+ it "includes the consumer details" do
101
+ expect(parsed_json[:matrix][0][:consumer]).to eq consumer_hash
102
+ end
103
+
104
+ it "includes the provider details" do
105
+ expect(parsed_json[:matrix][0][:provider]).to eq provider_hash
106
+ end
107
+
108
+ it "includes the verification details" do
109
+ expect(parsed_json[:matrix][0][:verificationResult]).to eq verification_hash
110
+ end
111
+
112
+ it "includes the pact details" do
113
+ expect(parsed_json[:matrix][0][:pact]).to eq pact_hash
114
+ end
115
+
116
+ context "when the pact has not been verified" do
117
+ let(:verification_hash) do
118
+ nil
119
+ end
120
+
121
+ it "has empty provider details" do
122
+ expect(parsed_json[:matrix][1][:provider]).to eq provider_hash.merge(version: nil)
123
+ end
124
+
125
+ it "has a nil verificationResult" do
126
+ expect(parsed_json[:matrix][1][:verificationResult]).to eq verification_hash
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -9,21 +9,15 @@ module PactBroker
9
9
  instance_double('PactBroker::Domain::Verification',
10
10
  number: 1,
11
11
  success: true,
12
- provider_version: "4.5.6",
12
+ provider_version_number: "4.5.6",
13
13
  provider_name: 'Provider',
14
14
  consumer_name: 'Consumer',
15
15
  build_url: 'http://build-url',
16
- pact_version: pact_version,
16
+ pact_version_sha: '1234',
17
17
  latest_pact_publication: pact_publication,
18
18
  execution_date: DateTime.now)
19
19
  end
20
20
 
21
- let(:pact_version) do
22
- instance_double('PactBroker::Pacts::PactVersion',
23
- sha: '1234'
24
- )
25
- end
26
-
27
21
  let(:pact_publication) do
28
22
  instance_double('PactBroker::Pacts::PactPublication',
29
23
  name: 'A name',
@@ -12,16 +12,17 @@ module PactBroker
12
12
  let(:verification) do
13
13
  instance_double("PactBroker::Domain::Verification",
14
14
  success: true, number: 1,
15
- provider_version: '4.5.6',
15
+ provider_version_number: '4.5.6',
16
16
  build_url: 'http://some-build',
17
17
  provider_name: 'Provider',
18
18
  consumer_name: 'Consumer',
19
19
  pact_version: pact_version,
20
+ pact_version_sha: '1234',
20
21
  latest_pact_publication: pact,
21
22
  execution_date: DateTime.now)
22
23
  end
23
24
  let(:pact_version) do
24
- instance_double("PactBroker::Pacts::PactVersion", sha: '1234', name: 'Name')
25
+ instance_double("PactBroker::Pacts::PactVersion", name: 'Name')
25
26
  end
26
27
 
27
28
  let(:pact) { instance_double("PactBroker::Domain::Pact", name: "Some pact", consumer_name: "Foo", provider_name: "Bar", consumer_version_number: "1.2.3") }
@@ -0,0 +1,38 @@
1
+ require 'pact_broker/api/resources/matrix'
2
+ require 'pact_broker/matrix/service'
3
+
4
+ module PactBroker
5
+ module Api
6
+ module Resources
7
+ describe Matrix do
8
+ before do
9
+ allow(PactBroker::Matrix::Service).to receive(:validate_selectors).and_return(error_messages)
10
+ end
11
+
12
+ let(:td) { TestDataBuilder.new }
13
+ let(:path) { "/matrix" }
14
+ let(:json_response_body) { JSON.parse(subject.body, symbolize_names: true) }
15
+ let(:params) { { selectors: ['Foo/version/1', 'Bar/version/2'] } }
16
+ let(:error_messages) { [] }
17
+
18
+ subject { get path, params, {'Content-Type' => 'application/hal+json'}; last_response }
19
+
20
+ it "validates the selectors" do
21
+ expect(PactBroker::Matrix::Service).to receive(:validate_selectors).with(['Foo/version/1', 'Bar/version/2'])
22
+ subject
23
+ end
24
+
25
+ context "when a validation error occurs" do
26
+ let(:error_messages) { ['foo'] }
27
+ it "returns a 400 status" do
28
+ expect(subject.status).to eq 400
29
+ end
30
+
31
+ it "returns error messages" do
32
+ expect(json_response_body[:errors]).to eq ['foo']
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end