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
@@ -66,6 +66,7 @@ module PactBroker
66
66
  add ['matrix', 'provider', :provider_name, 'latest', :provider_tag, 'consumer', :consumer_name, 'latest', :tag, 'badge'], Api::Resources::MatrixBadge, {resource_name: "matrix_tag_badge"}
67
67
  add ['matrix'], Api::Resources::Matrix, {resource_name: "matrix"}
68
68
 
69
+ add ['dashboard'], Api::Resources::Dashboard, {resource_name: "dashboard"}
69
70
  add [], Api::Resources::Index, {resource_name: "index"}
70
71
  end
71
72
  end
@@ -0,0 +1,163 @@
1
+ require 'ostruct'
2
+ require 'pact_broker/api/pact_broker_urls'
3
+
4
+ module PactBroker
5
+ module Api
6
+ module Decorators
7
+ class DashboardDecorator
8
+ include PactBroker::Api::PactBrokerUrls
9
+
10
+ def initialize(index_items)
11
+ @index_items = index_items
12
+ end
13
+
14
+ def to_json(options)
15
+ to_hash(options).to_json
16
+ end
17
+
18
+ def to_hash(options)
19
+ {
20
+ items: items(index_items, options[:user_options][:base_url])
21
+ }
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :index_items
27
+
28
+ def items(index_items, base_url)
29
+ index_items.collect do | index_item |
30
+ index_item_hash(index_item.consumer, index_item.provider, index_item.consumer_version, index_item, base_url)
31
+ end
32
+ end
33
+
34
+ def index_item_hash(consumer, provider, consumer_version, index_item, base_url)
35
+ {
36
+ consumer: consumer_hash(index_item, consumer, consumer_version, base_url),
37
+ provider: provider_hash(index_item, provider, base_url),
38
+ pact: pact_hash(index_item, base_url),
39
+ pactTags: pact_tags(index_item, base_url),
40
+ latestVerificationResult: verification_hash(index_item, base_url),
41
+ latestVerificationResultTags: verification_tags(index_item, base_url),
42
+ verificationStatus: index_item.verification_status.to_s,
43
+ webhookStatus: index_item.webhook_status.to_s,
44
+ latestWebhookExecution: latest_webhook_execution(index_item, base_url),
45
+ _links: links(index_item, base_url)
46
+
47
+ }
48
+ end
49
+
50
+ def consumer_hash(index_item, consumer, consumer_version, base_url)
51
+ {
52
+ name: index_item.consumer_name,
53
+ version: {
54
+ number: index_item.consumer_version_number,
55
+ _links: {
56
+ self: {
57
+ href: version_url(base_url, index_item.consumer_version)
58
+ }
59
+ }
60
+ },
61
+ _links: {
62
+ self: {
63
+ href: pacticipant_url(base_url, index_item.consumer)
64
+ }
65
+ }
66
+ }
67
+ end
68
+
69
+ def provider_hash(index_item, provider, base_url)
70
+ hash = {
71
+ name: index_item.provider_name,
72
+ version: nil,
73
+ _links: {
74
+ self: {
75
+ href: pacticipant_url(base_url, index_item.provider)
76
+ }
77
+ }
78
+ }
79
+
80
+ if index_item.latest_verification
81
+ hash[:version] = { number: index_item.provider_version_number }
82
+ end
83
+
84
+ hash
85
+ end
86
+
87
+ def pact_hash(index_item, base_url)
88
+ {
89
+ createdAt: index_item.latest_pact.created_at.to_datetime.xmlschema,
90
+ _links: {
91
+ self: {
92
+ href: pact_url(base_url, index_item.latest_pact)
93
+ }
94
+ }
95
+ }
96
+ end
97
+
98
+ def verification_hash(index_item, base_url)
99
+ if index_item.latest_verification
100
+ {
101
+ success: index_item.latest_verification.success,
102
+ verifiedAt: index_item.latest_verification.created_at.to_datetime.xmlschema,
103
+ _links: {
104
+ self: {
105
+ href: verification_url(index_item.latest_verification, base_url)
106
+ }
107
+ }
108
+ }
109
+ else
110
+ nil
111
+ end
112
+ end
113
+
114
+ def pact_tags(index_item, base_url)
115
+ index_item.tag_names.collect do | tag_name |
116
+ fake_tag = OpenStruct.new(name: tag_name, version: index_item.consumer_version)
117
+ {
118
+ name: tag_name,
119
+ latest: true,
120
+ _links: {
121
+ self: {
122
+ href: tag_url(base_url, fake_tag)
123
+ }
124
+ }
125
+ }
126
+ end
127
+ end
128
+
129
+ def verification_tags(index_item, base_url)
130
+ index_item.latest_verification_latest_tags.collect do | tag |
131
+ fake_tag = OpenStruct.new(name: tag.name, version: index_item.provider_version)
132
+ {
133
+ name: tag.name,
134
+ latest: tag.latest?,
135
+ _links: {
136
+ self: {
137
+ href: tag_url(base_url, fake_tag)
138
+ }
139
+ }
140
+ }
141
+ end
142
+ end
143
+
144
+ def latest_webhook_execution(index_item, base_url)
145
+ if index_item.last_webhook_execution_date
146
+ {
147
+ triggeredAt: index_item.last_webhook_execution_date.to_datetime.xmlschema
148
+ }
149
+ end
150
+ end
151
+
152
+ def links(index_item, base_url)
153
+ {
154
+ 'pb:webhook-status' => {
155
+ title: "Status of webhooks for #{index_item.consumer_name}/#{index_item.provider_name} pact",
156
+ href: webhooks_status_url(index_item.consumer, index_item.provider, base_url)
157
+ }
158
+ }
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,50 @@
1
+ require 'ostruct'
2
+ require 'pact_broker/api/pact_broker_urls'
3
+
4
+ module PactBroker
5
+ module Api
6
+ module Decorators
7
+ class DashboardTextDecorator
8
+ include PactBroker::Api::PactBrokerUrls
9
+
10
+ Line = Struct.new(:consumer_name, :c_version, :c_tags , :provider_name, :p_version, :p_tags, :success)
11
+
12
+ def initialize(index_items)
13
+ @index_items = index_items
14
+ end
15
+
16
+ def to_json(options)
17
+ to_hash(options).to_json
18
+ end
19
+
20
+ def to_text(options)
21
+ data = items(index_items, options[:user_options][:base_url])
22
+ printer = TablePrint::Printer.new(data)
23
+ printer.table_print + "\n"
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :index_items
29
+
30
+ def items(index_items, base_url)
31
+ index_items.collect do | index_item |
32
+ index_item_object(index_item)
33
+ end
34
+ end
35
+
36
+ def index_item_object(index_item)
37
+ Line.new(
38
+ index_item.consumer_name,
39
+ index_item.consumer_version_number,
40
+ index_item.tag_names.join(", "),
41
+ index_item.provider_name,
42
+ index_item.provider_version_number,
43
+ index_item.latest_verification_latest_tags.collect(&:name).join(", "),
44
+ index_item.verification_status.to_s
45
+ )
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -27,8 +27,8 @@ module PactBroker
27
27
 
28
28
  def deployable
29
29
  return nil if lines.empty?
30
- return nil if lines.any?{ |line| line[:success].nil? }
31
- lines.any? && lines.all?{ |line| line[:success] }
30
+ return nil if lines.any?{ |line| line.success.nil? }
31
+ lines.any? && lines.all?{ |line| line.success }
32
32
  end
33
33
 
34
34
  def reason
@@ -47,9 +47,9 @@ module PactBroker
47
47
 
48
48
  def matrix(lines, base_url)
49
49
  lines.collect do | line |
50
- provider = OpenStruct.new(name: line[:provider_name])
51
- consumer = OpenStruct.new(name: line[:consumer_name])
52
- consumer_version = OpenStruct.new(number: line[:consumer_version_number], pacticipant: consumer)
50
+ provider = OpenStruct.new(name: line.provider_name)
51
+ consumer = OpenStruct.new(name: line.consumer_name)
52
+ consumer_version = OpenStruct.new(number: line.consumer_version_number, pacticipant: consumer)
53
53
  line_hash(consumer, provider, consumer_version, line, base_url)
54
54
  end
55
55
  end
@@ -65,9 +65,9 @@ module PactBroker
65
65
 
66
66
  def consumer_hash(line, consumer, consumer_version, base_url)
67
67
  {
68
- name: line[:consumer_name],
68
+ name: line.consumer_name,
69
69
  version: {
70
- number: line[:consumer_version_number],
70
+ number: line.consumer_version_number,
71
71
  _links: {
72
72
  self: {
73
73
  href: version_url(base_url, consumer_version)
@@ -84,7 +84,7 @@ module PactBroker
84
84
 
85
85
  def provider_hash(line, provider, base_url)
86
86
  hash = {
87
- name: line[:provider_name],
87
+ name: line.provider_name,
88
88
  version: nil,
89
89
  _links: {
90
90
  self: {
@@ -93,8 +93,8 @@ module PactBroker
93
93
  }
94
94
  }
95
95
 
96
- if !line[:provider_version_number].nil?
97
- hash[:version] = { number: line[:provider_version_number] }
96
+ if !line.provider_version_number.nil?
97
+ hash[:version] = { number: line.provider_version_number }
98
98
  end
99
99
 
100
100
  hash
@@ -102,23 +102,28 @@ module PactBroker
102
102
 
103
103
  def pact_hash(line, base_url)
104
104
  {
105
- createdAt: line[:pact_created_at].to_datetime.xmlschema,
105
+ createdAt: line.pact_created_at.to_datetime.xmlschema,
106
106
  _links: {
107
107
  self: {
108
- href: pact_url_from_params(base_url, line)
108
+ href: pact_url(base_url, line)
109
109
  }
110
110
  }
111
111
  }
112
112
  end
113
113
 
114
114
  def verification_hash(line, base_url)
115
- if !line[:success].nil?
115
+ if !line.success.nil?
116
+ url_params = { consumer_name: line.consumer_name,
117
+ provider_name: line.provider_name,
118
+ pact_version_sha: line.pact_version_sha,
119
+ verification_number: line.verification_number
120
+ }
116
121
  {
117
- success: line[:success],
118
- verifiedAt: line[:verification_executed_at].to_datetime.xmlschema,
122
+ success: line.success,
123
+ verifiedAt: line.verification_executed_at.to_datetime.xmlschema,
119
124
  _links: {
120
125
  self: {
121
- href: verification_url(OpenStruct.new(line.merge(number: line[:verification_number])), base_url)
126
+ href: verification_url_from_params(url_params, base_url)
122
127
  }
123
128
  }
124
129
  }
@@ -48,6 +48,7 @@ module PactBroker
48
48
  if dasherized['_embedded']
49
49
  if dasherized['_embedded']['latest-version']
50
50
  dasherized['_embedded']['latest-version']['title'] = 'DEPRECATED - please use latestVersion'
51
+ dasherized['_embedded']['latest-version']['name'] = 'DEPRECATED - please use latestVersion'
51
52
  end
52
53
  h['_embedded'] ||= {}
53
54
  h['_embedded'].merge!(dasherized['_embedded'])
@@ -4,6 +4,8 @@ module PactBroker
4
4
  module Api
5
5
  module PactBrokerUrls
6
6
 
7
+ # TODO make base_url the last and optional argument for all methods, defaulting to ''
8
+
7
9
  extend self
8
10
 
9
11
  def pacticipants_url base_url
@@ -14,6 +16,14 @@ module PactBroker
14
16
  "#{pacticipants_url(base_url)}/#{url_encode(pacticipant.name)}"
15
17
  end
16
18
 
19
+ def pacticipant_url_from_params params, base_url = ''
20
+ [
21
+ base_url,
22
+ 'pacticipants',
23
+ url_encode(params.fetch(:pacticipant_name))
24
+ ].join("/")
25
+ end
26
+
17
27
  def latest_version_url base_url, pacticipant
18
28
  "#{pacticipant_url(base_url, pacticipant)}/versions/latest"
19
29
  end
@@ -26,6 +36,16 @@ module PactBroker
26
36
  "#{pacticipant_url(base_url, version.pacticipant)}/versions/#{version.number}"
27
37
  end
28
38
 
39
+ def version_url_from_params params, base_url = ''
40
+ [
41
+ base_url,
42
+ 'pacticipants',
43
+ url_encode(params.fetch(:pacticipant_name)),
44
+ 'versions',
45
+ url_encode(params.fetch(:version_number)),
46
+ ].join("/")
47
+ end
48
+
29
49
  def pact_url base_url, pact
30
50
  "#{pactigration_base_url(base_url, pact)}/version/#{pact.consumer_version_number}"
31
51
  end
@@ -87,6 +107,15 @@ module PactBroker
87
107
  ].join('/')
88
108
  end
89
109
 
110
+ def verification_url_from_params params, base_url = ''
111
+ [ base_url, 'pacts',
112
+ 'provider', url_encode(params.fetch(:provider_name)),
113
+ 'consumer', url_encode(params.fetch(:consumer_name)),
114
+ 'pact-version', params.fetch(:pact_version_sha),
115
+ 'verification-results', params.fetch(:verification_number)
116
+ ].join('/')
117
+ end
118
+
90
119
  def latest_verifications_for_consumer_version_url version, base_url
91
120
  "#{base_url}/verification-results/consumer/#{url_encode(version.pacticipant.name)}/version/#{version.number}/latest"
92
121
  end
@@ -41,6 +41,9 @@ module PactBroker
41
41
  end
42
42
 
43
43
  def finish_request
44
+ if !request.get? && !request.head?
45
+ matrix_service.refresh(identifier_from_path)
46
+ end
44
47
  PactBroker.configuration.after_resource.call(self)
45
48
  end
46
49
 
@@ -0,0 +1,38 @@
1
+ require 'pact_broker/api/resources/base_resource'
2
+ require 'pact_broker/api/decorators/dashboard_decorator'
3
+ require 'pact_broker/api/decorators/dashboard_text_decorator'
4
+
5
+ module PactBroker
6
+ module Api
7
+ module Resources
8
+
9
+ class Dashboard < BaseResource
10
+
11
+ def content_types_provided
12
+ [
13
+ ["application/hal+json", :to_json],
14
+ ["text/plain", :to_text],
15
+ ]
16
+ end
17
+
18
+ def allowed_methods
19
+ ["GET"]
20
+ end
21
+
22
+ def to_json
23
+ PactBroker::Api::Decorators::DashboardDecorator.new(index_items).to_json(user_options: decorator_context)
24
+ end
25
+
26
+ def to_text
27
+ PactBroker::Api::Decorators::DashboardTextDecorator.new(index_items).to_text(user_options: decorator_context)
28
+ end
29
+
30
+ private
31
+
32
+ def index_items
33
+ index_service.find_index_items(tags: true)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -4,7 +4,6 @@ require 'pact_broker/api/decorators/label_decorator'
4
4
  module PactBroker
5
5
  module Api
6
6
  module Resources
7
-
8
7
  class Label < BaseResource
9
8
 
10
9
  def content_types_provided
@@ -3,7 +3,6 @@ require 'pact_broker/api/resources/base_resource'
3
3
  module PactBroker
4
4
  module Api
5
5
  module Resources
6
-
7
6
  class Tag < BaseResource
8
7
 
9
8
  def content_types_provided