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
@@ -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
+ });