pact_broker 2.6.0 → 2.7.0.beta.1

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.
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
@@ -8,6 +8,7 @@ module PactBroker
8
8
 
9
9
  set_primary_key :id
10
10
  associate(:many_to_one, :pact_version, class: "PactBroker::Pacts::PactVersion", key: :pact_version_id, primary_key: :id)
11
+ associate(:many_to_one, :provider_version, class: "PactBroker::Domain::Version", key: :provider_version_id, primary_key: :id)
11
12
 
12
13
  def before_create
13
14
  super
@@ -78,10 +79,13 @@ module PactBroker
78
79
  .limit(1).select(:provider_id))
79
80
  end
80
81
 
82
+ def provider_version_number
83
+ provider_version.number
84
+ end
85
+
81
86
  def latest_pact_publication
82
87
  pact_version.latest_pact_publication
83
88
  end
84
-
85
89
  end
86
90
 
87
91
  Verification.plugin :timestamps
@@ -0,0 +1,51 @@
1
+ require 'pact_broker/repositories/helpers'
2
+
3
+ module PactBroker
4
+ module Matrix
5
+ class Repository
6
+ include PactBroker::Repositories::Helpers
7
+ include PactBroker::Repositories
8
+
9
+ def find pacticipant_1_name, pacticipant_2_name
10
+ find_for_version_ids([], [pacticipant_1_name, pacticipant_2_name])
11
+ .sort{|l1, l2| l2[:consumer_version_order] <=> l1[:consumer_version_order]}
12
+ end
13
+
14
+ ##
15
+ # candidate_versions Hash of pacticipant name => version
16
+ # Ihe value is nil, it means all versions for that pacticipant are to be included
17
+ # Returns a list of matrix lines indicating the compatible versions
18
+ #
19
+ def find_compatible_pacticipant_versions criteria
20
+ version_ids = criteria.reject{ |key, value| !value }.collect do | key, value |
21
+ version_repository.find_by_pacticipant_name_and_number(key, value).id
22
+ end
23
+
24
+ pacticipant_names = criteria.reject{|key, value| value }.keys
25
+
26
+ find_for_version_ids(version_ids, pacticipant_names)
27
+ .group_by{|line| [line[:consumer_version_number], line[:provider_version_number]]}
28
+ .values
29
+ .collect(&:last)
30
+ .select{ |line | line[:success] }
31
+ end
32
+
33
+ def find_for_version_ids version_ids, pacticipant_names = []
34
+ PactBroker::Pacts::LatestPactPublicationsByConsumerVersion
35
+ .select_append(:consumer_version_number, :provider_name, :consumer_name, :provider_version_id, :provider_version_number, :success)
36
+ .select_append(Sequel[:latest_pact_publications_by_consumer_versions][:created_at].as(:pact_created_at))
37
+ .select_append(Sequel[:all_verifications][:number])
38
+ .select_append(Sequel[:all_verifications][:id].as(:verification_id))
39
+ .select_append(Sequel[:execution_date].as(:verification_executed_at))
40
+ .left_outer_join(:all_verifications, pact_version_id: :pact_version_id)
41
+ .where(provider_version_id: version_ids)
42
+ .or(provider_version_id: nil)
43
+ .or(provider_name: pacticipant_names)
44
+ .where(consumer_version_id: version_ids)
45
+ .or(consumer_name: pacticipant_names)
46
+ .order(:execution_date, :verification_id)
47
+ .collect(&:values)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,50 @@
1
+ require 'pact_broker/repositories'
2
+
3
+ module PactBroker
4
+ module Matrix
5
+ module Service
6
+ VERSION_SELECTOR_PATTERN = %r{(^[^/]+)/version/[^/]+$}.freeze
7
+
8
+ extend self
9
+ extend PactBroker::Repositories
10
+ extend PactBroker::Services
11
+
12
+ def find params
13
+ matrix_repository.find params[:consumer_name], params[:provider_name]
14
+ end
15
+
16
+ def find_compatible_pacticipant_versions criteria
17
+ matrix_repository.find_compatible_pacticipant_versions criteria
18
+ end
19
+
20
+ def validate_selectors selectors
21
+ error_messages = []
22
+ selectors.each do | version_selector |
23
+ if !(version_selector =~ VERSION_SELECTOR_PATTERN)
24
+ error_messages << "Invalid version selector '#{version_selector}'. Format must be <pacticipant_name>/version/<version>"
25
+ end
26
+ end
27
+
28
+ selectors.each do | version_selector |
29
+ if match = version_selector.match(VERSION_SELECTOR_PATTERN)
30
+ pacticipant_name = match[1]
31
+ unless pacticipant_service.find_pacticipant_by_name(pacticipant_name)
32
+ error_messages << "Pacticipant '#{pacticipant_name}' not found"
33
+ end
34
+ end
35
+ end
36
+
37
+ if error_messages.empty?
38
+ selected_versions = version_service.find_versions_by_selector(selectors)
39
+ if selected_versions.any?(&:nil?)
40
+ selected_versions.each_with_index do | selected_version, i |
41
+ error_messages << "No pact or verification found for #{selectors[i]}" if selected_version.nil?
42
+ end
43
+ end
44
+ end
45
+
46
+ error_messages
47
+ end
48
+ end
49
+ end
50
+ end
@@ -62,11 +62,27 @@ module PactBroker
62
62
  def self.find_relationships
63
63
  pact_repository.find_latest_pacts
64
64
  .collect do | pact|
65
- latest_verification = verification_service.find_latest_verification_for(pact.consumer, pact.provider)
66
- webhooks = webhook_service.find_by_consumer_and_provider pact.consumer, pact.provider
67
- triggered_webhooks = webhook_service.find_latest_triggered_webhooks pact.consumer, pact.provider
68
- PactBroker::Domain::Relationship.create pact.consumer, pact.provider, pact, latest_verification, webhooks, triggered_webhooks
69
- end
65
+ latest_relationship = build_latest_pact_relationship(pact)
66
+ prod_relationship = build_relationship_for_tagged_pact(pact, 'prod')
67
+ production_relationship = build_relationship_for_tagged_pact(pact, 'production')
68
+ [latest_relationship, prod_relationship, production_relationship].compact
69
+ end.flatten
70
+ end
71
+
72
+ def self.build_latest_pact_relationship pact
73
+ latest_verification = verification_service.find_latest_verification_for(pact.consumer, pact.provider)
74
+ webhooks = webhook_service.find_by_consumer_and_provider pact.consumer, pact.provider
75
+ triggered_webhooks = webhook_service.find_latest_triggered_webhooks pact.consumer, pact.provider
76
+ tag_names = pact.consumer_version_tag_names.select{ |name| name == 'prod' || name == 'production' }
77
+ PactBroker::Domain::Relationship.create pact.consumer, pact.provider, pact, true, latest_verification, webhooks, triggered_webhooks, tag_names
78
+ end
79
+
80
+ def self.build_relationship_for_tagged_pact latest_pact, tag
81
+ pact = pact_service.find_latest_pact consumer_name: latest_pact.consumer_name, provider_name: latest_pact.provider_name, tag: tag
82
+ return nil unless pact
83
+ return nil if pact.id == latest_pact.id
84
+ verification = verification_repository.find_latest_verification_for pact.consumer_name, pact.provider_name, tag
85
+ PactBroker::Domain::Relationship.create pact.consumer, pact.provider, pact, false, verification, [], [], [tag]
70
86
  end
71
87
 
72
88
  def self.update params
@@ -28,6 +28,17 @@ module PactBroker
28
28
  where(name_like(:provider_name, provider_name))
29
29
  end
30
30
 
31
+ # must be exactly correct names
32
+ def pacticipants pacticipant_1, pacticipant_2
33
+ where(
34
+ consumer_name: pacticipant_1,
35
+ provider_name: pacticipant_2
36
+ ).or(
37
+ consumer_name: pacticipant_2,
38
+ provider_name: pacticipant_1
39
+ )
40
+ end
41
+
31
42
  def tag tag_name
32
43
  filter = name_like(Sequel.qualify(:tags, :name), tag_name)
33
44
  join(:tags, {version_id: :consumer_version_id}).where(filter)
@@ -22,6 +22,10 @@ module PactBroker
22
22
  self.revision_number ||= 1
23
23
  end
24
24
 
25
+ def latest_tag_names
26
+ LatestTaggedPactPublications.where(id: id).select(:tag_name).collect{|t| t[:tag_name]}
27
+ end
28
+
25
29
  def to_domain
26
30
  PactBroker::Domain::Pact.new(
27
31
  id: id,
@@ -86,7 +86,7 @@ module PactBroker
86
86
  end
87
87
 
88
88
  def find_latest_pacts
89
- LatestPactPublications.order(:consumer_name, :provider_name).collect(&:to_domain_without_tags)
89
+ LatestPactPublications.order(:consumer_name, :provider_name).collect(&:to_domain)
90
90
  end
91
91
 
92
92
  def find_latest_pact(consumer_name, provider_name, tag = nil)
@@ -37,6 +37,11 @@ module PactBroker
37
37
  Verifications::Repository.new
38
38
  end
39
39
 
40
+ def matrix_repository
41
+ require 'pact_broker/matrix/repository'
42
+ Matrix::Repository.new
43
+ end
44
+
40
45
  extend self
41
46
  end
42
47
  end
@@ -46,5 +46,10 @@ module PactBroker
46
46
  require 'pact_broker/badges/service'
47
47
  Badges::Service
48
48
  end
49
+
50
+ def matrix_service
51
+ require 'pact_broker/matrix/service'
52
+ Matrix::Service
53
+ end
49
54
  end
50
55
  end
@@ -27,5 +27,4 @@ module PactBroker
27
27
 
28
28
  end
29
29
  end
30
-
31
30
  end
@@ -1,5 +1,6 @@
1
1
  require 'pact_broker/ui/controllers/relationships'
2
2
  require 'pact_broker/ui/controllers/groups'
3
+ require 'pact_broker/ui/controllers/matrix'
3
4
  require 'pact_broker/doc/controllers/app'
4
5
 
5
6
  module PactBroker
@@ -21,6 +22,10 @@ module PactBroker
21
22
  run PactBroker::Doc::Controllers::App
22
23
  end
23
24
 
25
+ map "/matrix" do
26
+ run PactBroker::UI::Controllers::Matrix
27
+ end
28
+
24
29
  map "/" do
25
30
  run PactBroker::UI::Controllers::Relationships
26
31
  end
@@ -0,0 +1,27 @@
1
+ require 'pact_broker/ui/controllers/base_controller'
2
+ require 'pact_broker/ui/view_models/matrix_line'
3
+ require 'haml'
4
+
5
+ module PactBroker
6
+ module UI
7
+ module Controllers
8
+ class Matrix < Base
9
+
10
+ include PactBroker::Services
11
+
12
+ get "/provider/:provider_name/consumer/:consumer_name" do
13
+ lines = matrix_service.find consumer_name: params[:consumer_name], provider_name: params[:provider_name]
14
+ lines = lines.collect{|line| PactBroker::UI::ViewDomain::MatrixLine.new(line)}
15
+ locals = {
16
+ lines: lines,
17
+ title: "The Matrix",
18
+ consumer_name: params[:consumer_name],
19
+ provider_name: params[:provider_name]
20
+ }
21
+ haml :'matrix/show', {locals: locals, layout: :'layouts/main'}
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+ end
@@ -11,8 +11,8 @@ module PactBroker
11
11
 
12
12
  get "/" do
13
13
  view_model = ViewDomain::Relationships.new(pacticipant_service.find_relationships)
14
-
15
- haml :'relationships/show', {locals: {relationships: view_model, title: "Pacts"}, layout: :'layouts/main'}
14
+ page = params[:showProdPacts] == 'true' ? :'relationships/show-prod-tags' : :'relationships/show'
15
+ haml page, {locals: {relationships: view_model, title: "Pacts"}, layout: :'layouts/main'}
16
16
  end
17
17
 
18
18
  end
@@ -0,0 +1,79 @@
1
+ require 'pact_broker/api/pact_broker_urls'
2
+ require 'pact_broker/ui/helpers/url_helper'
3
+ require 'pact_broker/date_helper'
4
+
5
+ module PactBroker
6
+ module UI
7
+ module ViewDomain
8
+ class MatrixLine
9
+
10
+ include PactBroker::Api::PactBrokerUrls
11
+
12
+ def initialize line
13
+ @line = line
14
+ end
15
+
16
+ def provider_name
17
+ @line[:provider_name]
18
+ end
19
+
20
+ def consumer_name
21
+ @line[:consumer_name]
22
+ end
23
+
24
+ def pact_version_sha
25
+ @line[:pact_version_sha]
26
+ end
27
+
28
+ # verification number
29
+ def number
30
+ @line[:number]
31
+ end
32
+
33
+ def consumer_version_number
34
+ @line[:consumer_version_number]
35
+ end
36
+
37
+ def consumer_version_number_url
38
+ pact_url_from_params('', @line)
39
+ end
40
+
41
+ def consumer_version_order
42
+ @line[:consumer_version_order]
43
+ end
44
+
45
+ def provider_version_number
46
+ @line[:provider_version]
47
+ end
48
+
49
+ def provider_version_number_url
50
+ hal_browser_url(verification_url(self))
51
+ end
52
+
53
+ def provider_version_order
54
+ if @line[:execution_date]
55
+ @line[:execution_date].to_time.to_i
56
+ else
57
+ 0
58
+ end
59
+ end
60
+
61
+ def verification_status
62
+ case @line[:success]
63
+ when true then "Verified"
64
+ when false then "Failed"
65
+ else ''
66
+ end
67
+ end
68
+
69
+ def verification_status_class
70
+ case @line[:success]
71
+ when true then 'success'
72
+ when false then 'danger'
73
+ else ''
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -21,6 +21,18 @@ module PactBroker
21
21
  @relationship.provider_name
22
22
  end
23
23
 
24
+ def consumer_version_number
25
+ @relationship.consumer_version_number
26
+ end
27
+
28
+ def provider_version_number
29
+ @relationship.provider_version_number
30
+ end
31
+
32
+ def tag_names
33
+ @relationship.tag_names.any? ? " (#{@relationship.tag_names.join(', ')}) ": ""
34
+ end
35
+
24
36
  def consumer_group_url
25
37
  Helpers::URLHelper.group_url consumer_name
26
38
  end
@@ -29,7 +41,7 @@ module PactBroker
29
41
  Helpers::URLHelper.group_url provider_name
30
42
  end
31
43
 
32
- def latest_pact_url
44
+ def pact_url
33
45
  "#{pactigration_base_url('', @relationship)}/latest"
34
46
  end
35
47
 
@@ -38,6 +50,7 @@ module PactBroker
38
50
  end
39
51
 
40
52
  def webhook_label
53
+ return "" unless show_webhook_status?
41
54
  case @relationship.webhook_status
42
55
  when :none then "Create"
43
56
  when :success, :failure then webhook_last_execution_date
@@ -47,6 +60,7 @@ module PactBroker
47
60
  end
48
61
 
49
62
  def webhook_status
63
+ return "" unless show_webhook_status?
50
64
  case @relationship.webhook_status
51
65
  when :success then "success"
52
66
  when :failure then "danger"
@@ -55,6 +69,10 @@ module PactBroker
55
69
  end
56
70
  end
57
71
 
72
+ def show_webhook_status?
73
+ @relationship.latest?
74
+ end
75
+
58
76
  def webhook_last_execution_date
59
77
  PactBroker::DateHelper.distance_of_time_in_words(@relationship.last_webhook_execution_date, DateTime.now) + " ago"
60
78
  end
@@ -99,11 +117,11 @@ module PactBroker
99
117
  def verification_tooltip
100
118
  case @relationship.verification_status
101
119
  when :success
102
- "Successfully verified by #{provider_name} (v#{@relationship.latest_verification_provider_version})"
120
+ "Successfully verified by #{provider_name} (v#{@relationship.latest_verification_provider_version_number})"
103
121
  when :stale
104
- "Pact has changed since last successful verification by #{provider_name} (v#{@relationship.latest_verification_provider_version})"
122
+ "Pact has changed since last successful verification by #{provider_name} (v#{@relationship.latest_verification_provider_version_number})"
105
123
  when :failed
106
- "Verification by #{provider_name} (v#{@relationship.latest_verification_provider_version}) failed"
124
+ "Verification by #{provider_name} (v#{@relationship.latest_verification_provider_version_number}) failed"
107
125
  else
108
126
  nil
109
127
  end
@@ -0,0 +1,42 @@
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
+
8
+ .container
9
+ %h1.page-header
10
+ = title
11
+ %table.table.table-bordered.table-striped{id: 'matrix'}
12
+ %thead
13
+ %th.consumer
14
+ = "#{consumer_name} version"
15
+ %span.glyphicon.glyphicon-sort.sort
16
+ %th.provider
17
+ = "#{provider_name} version"
18
+ %span.glyphicon.glyphicon-sort.sort
19
+ %th.verification-result
20
+ Verification
21
+ %span.glyphicon.glyphicon-sort.sort
22
+ %tbody
23
+ - lines.each do | line |
24
+ %tr
25
+ %td.consumer-version{'data-sort-value' => line.consumer_version_order}
26
+ %a{href: line.consumer_version_number_url}
27
+ = line.consumer_version_number
28
+ %td.provider{'data-sort-value' => line.provider_version_order}
29
+ %a{href: line.provider_version_number_url}
30
+ = line.provider_version_number
31
+ %td.verification-result{class: line.verification_status_class}
32
+ = line.verification_status
33
+
34
+ :javascript
35
+ $(function(){
36
+ $("#matrix").tablesorter({
37
+ textExtraction : function(node, table, cellIndex){
38
+ n = $(node);
39
+ return n.attr('data-sort-value') || n.text();
40
+ }
41
+ });
42
+ });