pact_broker 1.3.2.rc1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +76 -17
- data/db/migrations/16_add_pact_content_foreign_key_to_pacts.rb +6 -0
- data/db/migrations/migration_helper.rb +11 -1
- data/example/Gemfile +1 -1
- data/example/pact_broker_database.sqlite3 +0 -0
- data/lib/db.rb +1 -0
- data/lib/pact_broker/api.rb +11 -2
- data/lib/pact_broker/api/decorators.rb +1 -1
- data/lib/pact_broker/api/decorators/base_decorator.rb +3 -3
- data/lib/pact_broker/api/decorators/basic_pacticipant_decorator.rb +0 -1
- data/lib/pact_broker/api/decorators/embedded_tag_decorator.rb +26 -0
- data/lib/pact_broker/api/decorators/embedded_version_decorator.rb +20 -0
- data/lib/pact_broker/api/decorators/pact_collection_decorator.rb +9 -3
- data/lib/pact_broker/api/decorators/pact_decorator.rb +70 -6
- data/lib/pact_broker/api/decorators/pact_pacticipant_decorator.rb +2 -2
- data/lib/pact_broker/api/decorators/pacticipant_collection_decorator.rb +4 -28
- data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +2 -2
- data/lib/pact_broker/api/decorators/representable_pact.rb +4 -1
- data/lib/pact_broker/api/decorators/tag_decorator.rb +24 -1
- data/lib/pact_broker/api/decorators/timestamps.rb +2 -2
- data/lib/pact_broker/api/decorators/version_decorator.rb +27 -3
- data/lib/pact_broker/api/decorators/webhooks_decorator.rb +1 -1
- data/lib/pact_broker/api/pact_broker_urls.rb +10 -3
- data/lib/pact_broker/api/resources/index.rb +5 -5
- data/lib/pact_broker/api/resources/pact_content_diff.rb +40 -0
- data/lib/pact_broker/api/resources/previous_distinct_pact_version.rb +39 -0
- data/lib/pact_broker/api/resources/version.rb +36 -0
- data/lib/pact_broker/app.rb +2 -2
- data/lib/pact_broker/date_helper.rb +93 -0
- data/lib/pact_broker/doc/controllers/app.rb +1 -1
- data/lib/pact_broker/doc/views/consumer.markdown +7 -0
- data/lib/pact_broker/doc/views/diff-previous-distinct.markdown +5 -0
- data/lib/pact_broker/doc/views/latest-pact-version.markdown +7 -0
- data/lib/pact_broker/doc/views/latest-pact-versions.markdown +5 -0
- data/lib/pact_broker/doc/views/pact-versions.markdown +3 -0
- data/lib/pact_broker/doc/views/pact-webhooks.markdown +50 -0
- data/lib/pact_broker/doc/views/pacticipants.markdown +2 -0
- data/lib/pact_broker/doc/views/provider.markdown +7 -0
- data/lib/pact_broker/doc/views/tag-prod-version.markdown +7 -0
- data/lib/pact_broker/doc/views/tag-version.markdown +4 -0
- data/lib/pact_broker/doc/views/webhooks.markdown +2 -0
- data/lib/pact_broker/domain/pact.rb +6 -1
- data/lib/pact_broker/domain/tag.rb +0 -1
- data/lib/pact_broker/locale/en.yml +37 -1
- data/lib/pact_broker/pacts/all_pacts.rb +8 -0
- data/lib/pact_broker/pacts/create_formatted_diff.rb +20 -0
- data/lib/pact_broker/pacts/diff.rb +105 -0
- data/lib/pact_broker/pacts/repository.rb +43 -7
- data/lib/pact_broker/repositories/version_repository.rb +1 -0
- data/lib/pact_broker/services.rb +6 -1
- data/lib/pact_broker/services/pact_service.rb +6 -0
- data/lib/pact_broker/services/version_service.rb +2 -2
- data/lib/pact_broker/ui.rb +8 -3
- data/lib/pact_broker/ui/app.rb +2 -1
- data/lib/pact_broker/ui/controllers/base_controller.rb +1 -1
- data/lib/pact_broker/ui/controllers/clusters.rb +1 -1
- data/lib/pact_broker/ui/views/relationships/show.haml +11 -4
- data/lib/pact_broker/version.rb +1 -1
- data/pact_broker.gemspec +6 -4
- data/public/images/doc-text.svg +1 -0
- data/public/stylesheets/relationships.css +43 -1
- data/script/publish-2.sh +3 -0
- data/script/publish.sh +3 -0
- data/spec/features/delete_pact_spec.rb +1 -1
- data/spec/features/get_diff.rb +52 -0
- data/spec/features/get_previous_distinct_version.rb +51 -0
- data/spec/features/get_version.rb +45 -0
- data/spec/features/publish_pact_spec.rb +1 -1
- data/spec/fixtures/a_consumer-a_provider-2.json +22 -0
- data/spec/fixtures/a_consumer-a_provider.json +22 -0
- data/spec/fixtures/consumer-provider.json +4 -3
- data/spec/integration/app_spec.rb +6 -1
- data/spec/lib/pact_broker/api/decorators/embedded_tag_decorator_spec.rb +40 -0
- data/spec/lib/pact_broker/api/decorators/embedded_version_decorator_spec.rb +39 -0
- data/spec/lib/pact_broker/api/decorators/pact_decorator_spec.rb +52 -10
- data/spec/lib/pact_broker/api/decorators/pact_version_decorator_spec.rb +9 -1
- data/spec/lib/pact_broker/api/decorators/pacticipant_collection_decorator_spec.rb +36 -0
- data/spec/lib/pact_broker/api/decorators/tag_decorator_spec.rb +57 -0
- data/spec/lib/pact_broker/api/decorators/version_decorator_spec.rb +49 -0
- data/spec/lib/pact_broker/api/decorators/webhooks_decorator_spec.rb +2 -2
- data/spec/lib/pact_broker/pacts/create_formatted_diff_spec.rb +33 -0
- data/spec/lib/pact_broker/pacts/diff_spec.rb +72 -0
- data/spec/lib/pact_broker/pacts/pact_params_spec.rb +2 -2
- data/spec/lib/pact_broker/pacts/repository_spec.rb +90 -0
- data/spec/lib/pact_broker/repositories/version_repository_spec.rb +10 -2
- data/spec/lib/pact_broker/ui/controllers/relationships_spec.rb +1 -1
- data/vendor/hal-browser/README.md +6 -0
- data/vendor/hal-browser/browser.html +5 -3
- data/vendor/hal-browser/js/hal.js +3 -0
- data/vendor/hal-browser/js/hal/resource.js +1 -0
- data/vendor/hal-browser/js/hal/views/embedded_resource.js +1 -0
- data/vendor/hal-browser/js/hal/views/query_uri_dialog.js +12 -2
- data/vendor/hal-browser/js/hal/views/resource.js +6 -1
- data/vendor/hal-browser/styles.css +10 -0
- data/vendor/hal-browser/vendor/js/{jquery-1.9.1.js → jquery-1.10.2.js} +4394 -4202
- data/vendor/hal-browser/vendor/js/jquery-1.10.2.min.js +6 -0
- data/vendor/hal-browser/vendor/js/jquery-1.10.2.min.map +1 -0
- metadata +90 -18
- data/db/migrations/15_add_value_to_tag.rb.wip +0 -5
- data/lib/pact_broker/doc/views/latest-pacts.markdown +0 -3
@@ -0,0 +1,5 @@
|
|
1
|
+
# Diff with previous distinct version
|
2
|
+
|
3
|
+
Allowed methods: GET
|
4
|
+
|
5
|
+
This resource displays the difference between the current pact, and the previous "distinct" version. Given that the pact file does not change every time it is published, the previous distinct version is the most recent version published before the current one where the content is actually different.
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Webhooks
|
2
|
+
|
3
|
+
Allowed methods: GET, POST, DELETE
|
4
|
+
|
5
|
+
### Creating
|
6
|
+
|
7
|
+
1. To create a webhook, in the HAL Browser, navigate to the pact you want to create the webhook for
|
8
|
+
(Click "Go to Entry Point", then select "latest-pacts", then select the pact you want to create the webhook for.)
|
9
|
+
2. Click the "NON-GET" button for the "pact-webhooks" relation.
|
10
|
+
3. Paste in the webhook JSON (example shown below) in the body section and click "Make Request".
|
11
|
+
|
12
|
+
An example webhook to trigger a Bamboo job.
|
13
|
+
|
14
|
+
{
|
15
|
+
"request": {
|
16
|
+
"method": "POST",
|
17
|
+
"url": "http://master.ci.my.domain:8085/rest/api/latest/queue/SOME-PROJECT?os_authType=basic",
|
18
|
+
"username": "username",
|
19
|
+
"password": "password",
|
20
|
+
"headers": {
|
21
|
+
"Accept": "application/json"
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
A request body can be specified as well.
|
27
|
+
|
28
|
+
{
|
29
|
+
"request": {
|
30
|
+
"method": "POST",
|
31
|
+
"url": "http://example.org/something",
|
32
|
+
"body": {
|
33
|
+
"some" : "json"
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
**BEWARE** The password can be reverse engineered from the database, so make a separate account for the Pact Broker to use, don't use your personal account!
|
39
|
+
|
40
|
+
### Testing
|
41
|
+
|
42
|
+
To test a webhook, navigate to the webhook in the HAL browser, then make a POST request to the "execute" relation. The response or error will be shown in the window.
|
43
|
+
|
44
|
+
### Deleting
|
45
|
+
|
46
|
+
Send a DELETE request to the webhook URL.
|
47
|
+
|
48
|
+
### Updating
|
49
|
+
|
50
|
+
Currently not implemented. You will need to delete and re-create the webhook.
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'pact_broker/db'
|
2
|
+
require 'pact_broker/json'
|
2
3
|
|
3
4
|
module PactBroker
|
4
5
|
|
@@ -18,7 +19,7 @@ module PactBroker
|
|
18
19
|
end
|
19
20
|
|
20
21
|
def to_s
|
21
|
-
"Pact:
|
22
|
+
"Pact: consumer=#{consumer.name} provider=#{provider.name}"
|
22
23
|
end
|
23
24
|
|
24
25
|
def to_json options = {}
|
@@ -32,6 +33,10 @@ module PactBroker
|
|
32
33
|
def version_and_updated_date
|
33
34
|
"Version #{consumer_version_number} - #{updated_at.to_time.localtime.strftime("%d/%m/%Y")}"
|
34
35
|
end
|
36
|
+
|
37
|
+
def content_hash
|
38
|
+
JSON.parse(json_content, PACT_PARSING_OPTIONS)
|
39
|
+
end
|
35
40
|
end
|
36
41
|
|
37
42
|
end
|
@@ -34,4 +34,40 @@ en:
|
|
34
34
|
"503":
|
35
35
|
title: 503 Service Unavailable
|
36
36
|
message: The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.
|
37
|
-
|
37
|
+
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
38
|
+
datetime:
|
39
|
+
distance_in_words:
|
40
|
+
half_a_minute: "half a minute"
|
41
|
+
less_than_x_seconds:
|
42
|
+
one: "less than 1 second"
|
43
|
+
other: "less than %{count} seconds"
|
44
|
+
x_seconds:
|
45
|
+
one: "1 second"
|
46
|
+
other: "%{count} seconds"
|
47
|
+
less_than_x_minutes:
|
48
|
+
one: "less than a minute"
|
49
|
+
other: "less than %{count} minutes"
|
50
|
+
x_minutes:
|
51
|
+
one: "1 minute"
|
52
|
+
other: "%{count} minutes"
|
53
|
+
about_x_hours:
|
54
|
+
one: "about 1 hour"
|
55
|
+
other: "about %{count} hours"
|
56
|
+
x_days:
|
57
|
+
one: "1 day"
|
58
|
+
other: "%{count} days"
|
59
|
+
about_x_months:
|
60
|
+
one: "about 1 month"
|
61
|
+
other: "about %{count} months"
|
62
|
+
x_months:
|
63
|
+
one: "1 month"
|
64
|
+
other: "%{count} months"
|
65
|
+
about_x_years:
|
66
|
+
one: "about 1 year"
|
67
|
+
other: "about %{count} years"
|
68
|
+
over_x_years:
|
69
|
+
one: "over 1 year"
|
70
|
+
other: "over %{count} years"
|
71
|
+
almost_x_years:
|
72
|
+
one: "almost 1 year"
|
73
|
+
other: "almost %{count} years"
|
@@ -46,9 +46,17 @@ module PactBroker
|
|
46
46
|
where('consumer_version_order < ?', order)
|
47
47
|
end
|
48
48
|
|
49
|
+
def consumer_version_order_after order
|
50
|
+
where('consumer_version_order > ?', order)
|
51
|
+
end
|
52
|
+
|
49
53
|
def latest
|
50
54
|
reverse_order(:consumer_version_order).limit(1)
|
51
55
|
end
|
56
|
+
|
57
|
+
def earliest
|
58
|
+
order(:consumer_version_order).limit(1)
|
59
|
+
end
|
52
60
|
end
|
53
61
|
|
54
62
|
def to_domain
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'pact/matchers'
|
2
|
+
require 'pact_broker/json'
|
3
|
+
require 'pact/matchers/unix_diff_formatter'
|
4
|
+
|
5
|
+
module PactBroker
|
6
|
+
module Pacts
|
7
|
+
class CreateFormattedDiff
|
8
|
+
|
9
|
+
extend Pact::Matchers
|
10
|
+
|
11
|
+
def self.call pact_json_content, previous_pact_json_content
|
12
|
+
pact_hash = JSON.load(pact_json_content, nil, PactBroker::PACT_PARSING_OPTIONS)
|
13
|
+
previous_pact_hash = JSON.load(previous_pact_json_content, nil, PactBroker::PACT_PARSING_OPTIONS)
|
14
|
+
difference = diff(previous_pact_hash, pact_hash)
|
15
|
+
Pact::Matchers::UnixDiffFormatter.call(difference, colour: false, include_explanation: false)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'trailblazer/operation'
|
2
|
+
require 'pact_broker/repositories'
|
3
|
+
require 'pact_broker/pacts/create_formatted_diff'
|
4
|
+
require 'pact_broker/api/pact_broker_urls'
|
5
|
+
require 'yaml'
|
6
|
+
require 'pact_broker/date_helper'
|
7
|
+
|
8
|
+
|
9
|
+
module PactBroker
|
10
|
+
module Pacts
|
11
|
+
|
12
|
+
class Diff < Trailblazer::Operation
|
13
|
+
|
14
|
+
include PactBroker::Repositories
|
15
|
+
attr_reader :params, :options
|
16
|
+
|
17
|
+
def process params, options
|
18
|
+
pact = pact_repository.find_pact(params.consumer_name, params.consumer_version_number, params.provider_name)
|
19
|
+
previous_distinct_pact = pact_repository.find_previous_distinct_pact pact
|
20
|
+
if previous_distinct_pact
|
21
|
+
next_pact = pact_repository.find_next_pact previous_distinct_pact
|
22
|
+
DiffDecorator.new(pact, previous_distinct_pact, next_pact, options[:base_url]).to_text
|
23
|
+
else
|
24
|
+
no_previous_version_message pact
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def no_previous_version_message pact
|
29
|
+
"No previous distinct version was found for #{pact.name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# The next pact version after the previous distinct version.
|
35
|
+
# Eg. v1 (previous distinct) -> pactContentA
|
36
|
+
# v2 (next pact) -> pactContentB
|
37
|
+
# v3 -> pactContentB
|
38
|
+
# v4 (current) -> pactContentB
|
39
|
+
# If we are at v4, then the previous distinct pact version is
|
40
|
+
# v1, and the next pact after that is v2.
|
41
|
+
# The timestamps on v2 are the ones we want - that's when
|
42
|
+
# the latest distinct version content was first created.
|
43
|
+
|
44
|
+
class DiffDecorator
|
45
|
+
|
46
|
+
attr_reader :pact, :previous_distinct_pact, :next_pact, :base_url
|
47
|
+
|
48
|
+
def initialize pact, previous_distinct_pact, next_pact, base_url
|
49
|
+
@pact = pact
|
50
|
+
@previous_distinct_pact = previous_distinct_pact
|
51
|
+
@next_pact = next_pact
|
52
|
+
@base_url = base_url
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_text
|
56
|
+
header + "\n\n" + diff + "\n\n" + links
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def change_date_in_words
|
62
|
+
DateHelper.local_date_in_words next_pact.updated_at
|
63
|
+
end
|
64
|
+
|
65
|
+
def now
|
66
|
+
Time.now
|
67
|
+
end
|
68
|
+
|
69
|
+
def header
|
70
|
+
title = "# Diff between versions #{previous_distinct_pact.consumer_version_number} and #{pact.consumer_version_number} of the pact between #{pact.consumer.name} and #{pact.provider.name}"
|
71
|
+
description = "The following changes were made #{change_date_ago_in_words} ago (#{change_date_in_words})"
|
72
|
+
title + "\n\n" + description
|
73
|
+
end
|
74
|
+
|
75
|
+
def links
|
76
|
+
self_url = PactBroker::Api::PactBrokerUrls.pact_url base_url, pact
|
77
|
+
previous_distinct_url = PactBroker::Api::PactBrokerUrls.pact_url base_url, previous_distinct_pact
|
78
|
+
|
79
|
+
links = {
|
80
|
+
"current-pact-version" => {
|
81
|
+
"title" => "Pact",
|
82
|
+
"name" => pact.name,
|
83
|
+
"href" => self_url
|
84
|
+
},
|
85
|
+
"previous-distinct-pact-version" => {
|
86
|
+
"title" => "Pact",
|
87
|
+
"name" => previous_distinct_pact.name,
|
88
|
+
"href" => previous_distinct_url
|
89
|
+
}
|
90
|
+
}
|
91
|
+
"## Links\n" + YAML.dump(links).gsub(/---/,'')
|
92
|
+
end
|
93
|
+
|
94
|
+
def diff
|
95
|
+
CreateFormattedDiff.(pact.json_content, previous_distinct_pact.json_content)
|
96
|
+
end
|
97
|
+
|
98
|
+
def change_date_ago_in_words
|
99
|
+
DateHelper.distance_of_time_in_words next_pact.updated_at, now
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -5,6 +5,7 @@ require 'pact_broker/logging'
|
|
5
5
|
require 'pact_broker/pacts/database_model'
|
6
6
|
require 'pact_broker/pacts/all_pacts'
|
7
7
|
require 'pact_broker/pacts/latest_pacts'
|
8
|
+
require 'pact/shared/json_differ'
|
8
9
|
|
9
10
|
module PactBroker
|
10
11
|
module Pacts
|
@@ -49,7 +50,7 @@ module PactBroker
|
|
49
50
|
AllPacts
|
50
51
|
.eager(:tags)
|
51
52
|
.where(consumer_version_id: version_id, provider_id: provider_id)
|
52
|
-
.limit(1).collect(&:
|
53
|
+
.limit(1).collect(&:to_domain_with_content)[0]
|
53
54
|
end
|
54
55
|
|
55
56
|
def find_latest_pacts
|
@@ -79,11 +80,51 @@ module PactBroker
|
|
79
80
|
.consumer(pact.consumer.name)
|
80
81
|
.provider(pact.provider.name)
|
81
82
|
.consumer_version_order_before(pact.consumer_version.order)
|
82
|
-
.latest.collect(&:
|
83
|
+
.latest.collect(&:to_domain_with_content)[0]
|
84
|
+
end
|
85
|
+
|
86
|
+
def find_next_pact pact
|
87
|
+
AllPacts
|
88
|
+
.eager(:tags)
|
89
|
+
.consumer(pact.consumer.name)
|
90
|
+
.provider(pact.provider.name)
|
91
|
+
.consumer_version_order_after(pact.consumer_version.order)
|
92
|
+
.earliest.collect(&:to_domain_with_content)[0]
|
93
|
+
end
|
94
|
+
|
95
|
+
def find_previous_distinct_pact pact
|
96
|
+
previous, current = nil, pact
|
97
|
+
loop do
|
98
|
+
previous = find_previous_distinct_pact_by_sha current
|
99
|
+
return previous if previous.nil? || different?(current, previous)
|
100
|
+
current = previous
|
101
|
+
end
|
83
102
|
end
|
84
103
|
|
85
104
|
private
|
86
105
|
|
106
|
+
def find_previous_distinct_pact_by_sha pact
|
107
|
+
current_pact_content_sha =
|
108
|
+
AllPacts.select(:pact_version_content_sha)
|
109
|
+
.consumer(pact.consumer.name)
|
110
|
+
.provider(pact.provider.name)
|
111
|
+
.consumer_version_number(pact.consumer_version_number)
|
112
|
+
.limit(1)
|
113
|
+
|
114
|
+
AllPacts
|
115
|
+
.eager(:tags)
|
116
|
+
.consumer(pact.consumer.name)
|
117
|
+
.provider(pact.provider.name)
|
118
|
+
.consumer_version_order_before(pact.consumer_version.order)
|
119
|
+
.where('pact_version_content_sha != ?', current_pact_content_sha)
|
120
|
+
.latest
|
121
|
+
.collect(&:to_domain_with_content)[0]
|
122
|
+
end
|
123
|
+
|
124
|
+
def different? pact, other_pact
|
125
|
+
Pact::JsonDiffer.(pact.content_hash, other_pact.content_hash, allow_unexpected_keys: false).any?
|
126
|
+
end
|
127
|
+
|
87
128
|
def find_or_create_pact_version_content json_content
|
88
129
|
sha = Digest::SHA1.hexdigest(json_content)
|
89
130
|
PactVersionContent.find(sha: sha) || create_pact_version_content(sha, json_content)
|
@@ -96,11 +137,6 @@ module PactBroker
|
|
96
137
|
pact_version_content.save
|
97
138
|
end
|
98
139
|
|
99
|
-
def to_domain
|
100
|
-
database_model = yield
|
101
|
-
database_model ? database_model.to_domain : nil
|
102
|
-
end
|
103
|
-
|
104
140
|
end
|
105
141
|
end
|
106
142
|
end
|
@@ -11,6 +11,7 @@ module PactBroker
|
|
11
11
|
|
12
12
|
def find_by_pacticipant_name_and_number pacticipant_name, number
|
13
13
|
PactBroker::Domain::Version
|
14
|
+
.select(:versions__id, :versions__number, :versions__pacticipant_id, :versions__order, :versions__created_at, :versions__updated_at)
|
14
15
|
.where(number: number)
|
15
16
|
.join(:pacticipants, {id: :pacticipant_id})
|
16
17
|
.where(name: pacticipant_name)
|