Skip to content

Commit 7666863

Browse files
committed
feat: add content type to return pact with extra metadata (eg tags)
1 parent 2e9611a commit 7666863

File tree

10 files changed

+147
-13
lines changed

10 files changed

+147
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
require 'pact_broker/api/decorators/pact_decorator'
2+
3+
module PactBroker
4+
module Api
5+
module Decorators
6+
class ExtendedPactDecorator < PactDecorator
7+
class TagDecorator < BaseDecorator
8+
property :name
9+
property :latest, getter: ->(_) { true }
10+
11+
link "pb:latest-pact" do | opts |
12+
{
13+
name: "The latest pact with the tag #{represented.name}",
14+
href: latest_tagged_pact_url(represented.pact, represented.name, opts[:base_url])
15+
}
16+
end
17+
end
18+
19+
property :content_hash, as: :contract
20+
collection :head_tags, exec_context: :decorator, as: :tags, embedded: true, extend: TagDecorator
21+
22+
# TODO rather than remove the contract keys that we added in the super class,
23+
# it would be better to inherit from a shared super class
24+
def to_hash(options = {})
25+
keys_to_remove = represented.content_hash.keys
26+
super.each_with_object({}) do | (key, value), new_hash |
27+
new_hash[key] = value unless keys_to_remove.include?(key)
28+
end
29+
end
30+
31+
def head_tags
32+
represented.head_tag_names.collect do | tag_name |
33+
OpenStruct.new(name: tag_name, pact: represented)
34+
end
35+
end
36+
end
37+
end
38+
end
39+
end

lib/pact_broker/api/decorators/pact_decorator.rb

-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@
33
require 'pact_broker/api/decorators/timestamps'
44

55
module PactBroker
6-
76
module Api
8-
97
module Decorators
10-
118
class PactDecorator < BaseDecorator
129

1310
include Timestamps

lib/pact_broker/api/pact_broker_urls.rb

+4
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ def latest_untagged_pact_url pact, base_url
9090
"#{pactigration_base_url(base_url, pact)}/latest-untagged"
9191
end
9292

93+
def latest_tagged_pact_url pact, tag_name, base_url
94+
"#{latest_pact_url(base_url, pact)}/#{url_encode(tag_name)}"
95+
end
96+
9397
def latest_pacts_url base_url
9498
"#{base_url}/pacts/latest"
9599
end

lib/pact_broker/api/resources/pact.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require 'pact_broker/api/resources/base_resource'
33
require 'pact_broker/api/resources/pacticipant_resource_methods'
44
require 'pact_broker/api/decorators/pact_decorator'
5+
require 'pact_broker/api/decorators/extended_pact_decorator'
56
require 'pact_broker/json'
67
require 'pact_broker/pacts/pact_params'
78
require 'pact_broker/api/contracts/put_pact_params_contract'
@@ -26,7 +27,9 @@ class Pact < BaseResource
2627
def content_types_provided
2728
[["application/hal+json", :to_json],
2829
["application/json", :to_json],
29-
["text/html", :to_html]]
30+
["text/html", :to_html],
31+
["application/vnd.pactbroker.pact.v1+json", :to_extended_json]
32+
]
3033
end
3134

3235
def content_types_accepted
@@ -78,6 +81,10 @@ def to_json
7881
PactBroker::Api::Decorators::PactDecorator.new(pact).to_json(user_options: decorator_context(metadata: identifier_from_path[:metadata]))
7982
end
8083

84+
def to_extended_json
85+
PactBroker::Api::Decorators::ExtendedPactDecorator.new(pact).to_json(user_options: decorator_context(metadata: identifier_from_path[:metadata]))
86+
end
87+
8188
def to_html
8289
PactBroker.configuration.html_pact_renderer.call(
8390
pact, {

lib/pact_broker/domain/pact.rb

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module PactBroker
66
module Domain
77
class Pact
88

9-
attr_accessor :id, :provider, :consumer_version, :consumer, :created_at, :json_content, :consumer_version_number, :revision_number, :pact_version_sha, :latest_verification
9+
attr_accessor :id, :provider, :consumer_version, :consumer, :created_at, :json_content, :consumer_version_number, :revision_number, :pact_version_sha, :latest_verification, :head_tag_names
1010

1111
def initialize attributes
1212
attributes.each_pair do | key, value |
@@ -54,6 +54,5 @@ def pact_publication_id
5454
id
5555
end
5656
end
57-
5857
end
5958
end

lib/pact_broker/pacts/all_pact_publications.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,14 @@ def to_domain_without_tags
101101
consumer_version_number: consumer_version_number,
102102
revision_number: revision_number,
103103
pact_version_sha: pact_version_sha,
104-
created_at: created_at)
104+
created_at: created_at,
105+
head_tag_names: head_tag_names)
106+
end
107+
108+
def head_tag_names
109+
# Avoid circular dependency
110+
require 'pact_broker/pacts/latest_tagged_pact_publications'
111+
LatestTaggedPactPublications.where(id: id).select(:tag_name).collect{|t| t[:tag_name]}
105112
end
106113

107114
def to_domain_with_content

lib/pact_broker/pacts/pact_publication.rb

+7-2
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@ def before_create
3131
self.revision_number ||= 1
3232
end
3333

34-
def latest_tag_names
34+
def head_tag_names
3535
LatestTaggedPactPublications.where(id: id).select(:tag_name).collect{|t| t[:tag_name]}
3636
end
3737

38+
def consumer_version_tags
39+
consumer_version.tags
40+
end
41+
3842
def latest_verification
3943
pact_version.latest_verification
4044
end
@@ -50,7 +54,8 @@ def to_domain
5054
json_content: pact_version.content,
5155
pact_version_sha: pact_version.sha,
5256
latest_verification: latest_verification,
53-
created_at: created_at
57+
created_at: created_at,
58+
head_tag_names: head_tag_names
5459
)
5560
end
5661

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
require 'pact_broker/api/decorators/extended_pact_decorator'
2+
3+
module PactBroker
4+
module Api
5+
module Decorators
6+
describe ExtendedPactDecorator do
7+
before do
8+
allow(decorator).to receive(:templated_diff_url).and_return('templated-diff-url')
9+
allow(decorator).to receive(:verification_publication_url).and_return('verification-publication-url')
10+
end
11+
let(:content_hash) {
12+
{
13+
'consumer' => {'name' => 'Consumer'},
14+
'provider' => {'name' => 'Provider'},
15+
'interactions' => [],
16+
'metadata' => {}
17+
}
18+
}
19+
20+
let(:base_url) { 'http://example.org' }
21+
let(:created_at) { Time.new(2014, 3, 4) }
22+
let(:pact) { double('pact',
23+
content_hash: content_hash,
24+
created_at: created_at,
25+
consumer: consumer,
26+
provider: provider,
27+
consumer_version: consumer_version,
28+
consumer_version_number: '1234',
29+
pact_version_sha: '9999',
30+
revision_number: 2,
31+
name: 'A Pact',
32+
head_tag_names: head_tag_names
33+
)}
34+
let(:head_tag_names) { ['prod'] }
35+
let(:consumer) { instance_double(PactBroker::Domain::Pacticipant, name: 'A Consumer')}
36+
let(:provider) { instance_double(PactBroker::Domain::Pacticipant, name: 'A Provider')}
37+
let(:consumer_version) { instance_double(PactBroker::Domain::Version, number: '1234', pacticipant: consumer)}
38+
let(:metadata) { "abcd" }
39+
let(:decorator) { ExtendedPactDecorator.new(pact) }
40+
let(:json) { decorator.to_json(user_options: { base_url: base_url, metadata: metadata }) }
41+
subject { JSON.parse(json, symbolize_names: true) }
42+
43+
it "includes an array of tags" do
44+
expect(subject[:_embedded][:tags].first).to include name: 'prod', latest: true
45+
# Can't seem to stub the verification_publication_url method on the TagDecorator
46+
expect(subject[:_embedded][:tags].first[:_links][:'pb:latest-pact'][:href]).to eq "http://example.org/pacts/provider/A%20Provider/consumer/A%20Consumer/latest/prod"
47+
end
48+
49+
it "includes the pact contents under the contract key" do
50+
expect(subject[:contract]).to eq JSON.parse(content_hash.to_json, symbolize_names: true)
51+
end
52+
53+
it "does not include the contract contents in the root" do
54+
expect(subject).to_not have_key(:interactions)
55+
end
56+
end
57+
end
58+
end
59+
end

spec/lib/pact_broker/api/decorators/pact_decorator_spec.rb

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ module PactBroker
55
module Api
66
module Decorators
77
describe PactDecorator do
8-
98
before do
109
allow(decorator).to receive(:templated_diff_url).and_return('templated-diff-url')
1110
allow(decorator).to receive(:verification_publication_url).and_return('verification-publication-url')

spec/lib/pact_broker/pacts/pact_publication_spec.rb

+21-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,25 @@ module Pacts
6464
end
6565
end
6666

67-
describe "#latest_tag_names" do
67+
describe "#consumer_version_tags" do
68+
before do
69+
td.create_pact_with_hierarchy("Foo", "1.2.3", "Bar")
70+
.create_consumer_version_tag("no")
71+
.create_consumer_version("3.4.5")
72+
.create_consumer_version_tag("yes")
73+
.create_pact
74+
.create_consumer_version("5.6.7")
75+
.create_consumer_version_tag("no")
76+
end
77+
78+
let(:pact_publication) { PactPublication.find(id: td.pact.id) }
79+
80+
it "" do
81+
expect(pact_publication.consumer_version_tags.collect(&:name)).to eq ["yes"]
82+
end
83+
end
84+
85+
describe "#head_tag_names" do
6886
before do
6987
td.create_pact_with_hierarchy("Foo", "1.2.3", "Bar")
7088
.create_consumer_version_tag("no")
@@ -80,13 +98,13 @@ module Pacts
8098

8199
context "when the pact is the latest for a tag" do
82100
it "returns the relevant tag names" do
83-
expect(pact_publication.latest_tag_names).to eq ["yes"]
101+
expect(pact_publication.head_tag_names).to eq ["yes"]
84102
end
85103
end
86104

87105
context "when the pact is not the latest for a tag" do
88106
it "returns the relevant tag names" do
89-
expect(pact_publication.latest_tag_names).to eq ["yes"]
107+
expect(pact_publication.head_tag_names).to eq ["yes"]
90108
end
91109
end
92110
end

0 commit comments

Comments
 (0)