pact_broker 1.2.0 → 1.3.0
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.
- checksums.yaml +13 -5
- data/.gitignore +2 -0
- data/CHANGELOG.md +5 -0
- data/README.md +2 -1
- data/Rakefile +1 -3
- data/db/migrations/07_increase_json_content_length.rb +6 -1
- data/db/migrations/08_create_latest_pact_view.rb +7 -5
- data/db/migrations/14_add_timestamps_to_pact_views.rb +28 -0
- data/lib/pact_broker/api.rb +0 -4
- data/lib/pact_broker/api/decorators/latest_pact_decorator.rb +4 -1
- data/lib/pact_broker/api/decorators/pact_decorator.rb +2 -2
- data/lib/pact_broker/api/decorators/pact_version_decorator.rb +3 -4
- data/lib/pact_broker/api/decorators/pact_versions_decorator.rb +4 -4
- data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +3 -2
- data/lib/pact_broker/api/decorators/tag_decorator.rb +2 -2
- data/lib/pact_broker/api/decorators/timestamps.rb +24 -0
- data/lib/pact_broker/api/decorators/webhook_decorator.rb +2 -2
- data/lib/pact_broker/api/decorators/webhooks_decorator.rb +4 -4
- data/lib/pact_broker/api/renderers/html_pact_renderer.rb +16 -4
- data/lib/pact_broker/api/resources/base_resource.rb +0 -1
- data/lib/pact_broker/api/resources/group.rb +11 -6
- data/lib/pact_broker/api/resources/index.rb +5 -6
- data/lib/pact_broker/api/resources/latest_pact.rb +8 -5
- data/lib/pact_broker/api/resources/latest_pacts.rb +3 -3
- data/lib/pact_broker/api/resources/pact.rb +9 -5
- data/lib/pact_broker/api/resources/pact_webhooks.rb +9 -5
- data/lib/pact_broker/api/resources/pacticipant.rb +10 -5
- data/lib/pact_broker/api/resources/relationships.rb +3 -3
- data/lib/pact_broker/api/resources/tag.rb +8 -7
- data/lib/pact_broker/api/resources/webhook.rb +1 -1
- data/lib/pact_broker/api/resources/webhook_execution.rb +1 -1
- data/lib/pact_broker/app.rb +8 -57
- data/lib/pact_broker/logging.rb +1 -0
- data/lib/pact_broker/models/pact.rb +6 -8
- data/lib/pact_broker/repositories/pact.rb +29 -0
- data/lib/pact_broker/repositories/pact_content.rb +0 -0
- data/lib/pact_broker/repositories/pact_repository.rb +66 -21
- data/lib/pact_broker/repositories/tag_repository.rb +1 -1
- data/lib/pact_broker/repositories/version_repository.rb +2 -1
- data/lib/pact_broker/services/pact_service.rb +14 -16
- data/lib/pact_broker/ui.rb +2 -0
- data/lib/pact_broker/ui/app.rb +81 -0
- data/lib/pact_broker/ui/controllers/groups.rb +1 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/rack/pact_broker/convert_file_extension_to_accept_header.rb +44 -0
- data/pact_broker.gemspec +1 -0
- data/public/javascripts/highlight.pack.js +1 -0
- data/public/stylesheets/github-json.css +127 -0
- data/public/stylesheets/pact.css +4 -0
- data/spec/fixtures/consumer-provider.json +21 -0
- data/spec/integration/app_spec.rb +165 -0
- data/spec/integration/endpoints/pact_put_spec.rb +43 -0
- data/spec/lib/pact_broker/api/decorators/latest_pact_decorator_spec.rb +42 -0
- data/spec/lib/pact_broker/api/decorators/pact_version_decorator_spec.rb +5 -0
- data/spec/lib/pact_broker/api/decorators/pacticipant_decorator_spec.rb +2 -1
- data/spec/lib/pact_broker/api/decorators/webhook_decorator_spec.rb +9 -2
- data/spec/lib/pact_broker/api/renderers/html_pact_renderer_spec.rb +14 -3
- data/spec/lib/pact_broker/repositories/pact_repository_spec.rb +88 -4
- data/spec/lib/pact_broker/repositories/tag_repository_spec.rb +2 -0
- data/spec/lib/pact_broker/repositories/version_repository_spec.rb +20 -2
- data/spec/lib/pact_broker/services/pacticipant_service_spec.rb +1 -1
- data/spec/service_consumers/pact_helper.rb +2 -17
- data/spec/spec_helper.rb +4 -22
- data/spec/support/database_cleaner.rb +18 -0
- data/spec/support/fixture_helpers.rb +10 -0
- data/spec/support/provider_state_builder.rb +4 -15
- metadata +82 -47
@@ -11,7 +11,7 @@ module PactBroker
|
|
11
11
|
|
12
12
|
def find args
|
13
13
|
PactBroker::Models::Tag
|
14
|
-
.select(:tags__name, :tags__version_id)
|
14
|
+
.select(:tags__name, :tags__version_id, :tags__created_at, :tags__updated_at)
|
15
15
|
.join(:versions, {id: :version_id})
|
16
16
|
.join(:pacticipants, {pacticipants__id: :versions__pacticipant_id})
|
17
17
|
.where(:tags__name => args.fetch(:tag_name))
|
@@ -19,7 +19,8 @@ module PactBroker
|
|
19
19
|
|
20
20
|
def create args
|
21
21
|
PactBroker.logger.info "Creating version #{args[:number]} for pacticipant_id=#{args[:pacticipant_id]}"
|
22
|
-
PactBroker::Models::Version.new(number: args[:number], pacticipant_id: args[:pacticipant_id]).save
|
22
|
+
version = PactBroker::Models::Version.new(number: args[:number], pacticipant_id: args[:pacticipant_id]).save
|
23
|
+
PactBroker::Models::Version.find(id: version.id) # Need to reload with populated order
|
23
24
|
end
|
24
25
|
|
25
26
|
def find_by_pacticipant_id_and_number_or_create pacticipant_id, number
|
@@ -26,14 +26,13 @@ module PactBroker
|
|
26
26
|
provider = pacticipant_repository.find_by_name_or_create params[:provider_name]
|
27
27
|
consumer = pacticipant_repository.find_by_name_or_create params[:consumer_name]
|
28
28
|
consumer_version = version_repository.find_by_pacticipant_id_and_number_or_create consumer.id, params[:consumer_version_number]
|
29
|
-
|
29
|
+
existing_pact = pact_repository.find_by_version_and_provider(consumer_version.id, provider.id)
|
30
30
|
|
31
|
-
if
|
32
|
-
|
31
|
+
if existing_pact
|
32
|
+
update_pact params, existing_pact
|
33
33
|
else
|
34
|
-
|
34
|
+
create_pact params, consumer_version, provider
|
35
35
|
end
|
36
|
-
|
37
36
|
end
|
38
37
|
|
39
38
|
def find_all_pacts_between consumer, options
|
@@ -63,24 +62,23 @@ module PactBroker
|
|
63
62
|
|
64
63
|
private
|
65
64
|
|
66
|
-
def update_pact params,
|
67
|
-
|
68
|
-
|
69
|
-
if
|
70
|
-
webhook_service.execute_webhooks
|
65
|
+
def update_pact params, existing_pact
|
66
|
+
updated_pact = pact_repository.update existing_pact.id, params
|
67
|
+
|
68
|
+
if existing_pact.json_content != updated_pact.json_content
|
69
|
+
webhook_service.execute_webhooks updated_pact
|
71
70
|
end
|
72
|
-
|
71
|
+
|
72
|
+
updated_pact
|
73
73
|
end
|
74
74
|
|
75
75
|
def create_pact params, version, provider
|
76
76
|
pact = pact_repository.create json_content: params[:json_content], version_id: version.id, provider_id: provider.id
|
77
|
-
|
78
|
-
|
77
|
+
trigger_webhooks pact
|
78
|
+
pact
|
79
79
|
end
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
def execute_webhooks pact
|
81
|
+
def trigger_webhooks pact
|
84
82
|
if pact_has_changed_since_previous_version? pact
|
85
83
|
webhook_service.execute_webhooks pact
|
86
84
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'pact_broker/ui'
|
2
|
+
require 'pact_broker/doc/controllers/app'
|
3
|
+
|
4
|
+
module PactBroker
|
5
|
+
module UI
|
6
|
+
class App
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@app = ::Rack::Builder.new {
|
10
|
+
|
11
|
+
use HtmlFilter
|
12
|
+
|
13
|
+
map "/ui/relationships" do
|
14
|
+
run PactBroker::UI::Controllers::Relationships
|
15
|
+
end
|
16
|
+
|
17
|
+
map "/groups" do
|
18
|
+
run PactBroker::UI::Controllers::Groups
|
19
|
+
end
|
20
|
+
|
21
|
+
map "/doc" do
|
22
|
+
run PactBroker::Doc::Controllers::App
|
23
|
+
end
|
24
|
+
|
25
|
+
map "/" do
|
26
|
+
run RedirectRootToRelationships
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def call env
|
32
|
+
@app.call(env)
|
33
|
+
end
|
34
|
+
|
35
|
+
class RedirectRootToRelationships
|
36
|
+
|
37
|
+
def self.call env
|
38
|
+
# A request for the root path in the browser (not the json index) should
|
39
|
+
# redirect to ui/relationships
|
40
|
+
if (env['PATH_INFO'].chomp("/") == "")
|
41
|
+
[303, {'Location' => 'ui/relationships'},[]]
|
42
|
+
else
|
43
|
+
[404, {},[]]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
class HtmlFilter
|
50
|
+
|
51
|
+
def initialize app
|
52
|
+
@app = app
|
53
|
+
end
|
54
|
+
|
55
|
+
def call env
|
56
|
+
if accepts_html_and_not_json_or_csv env
|
57
|
+
@app.call(env)
|
58
|
+
else
|
59
|
+
[404, {},[]]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def accepts_html_and_not_json_or_csv env
|
64
|
+
accept = env['HTTP_ACCEPT'] || ''
|
65
|
+
accepts_html(accept) && !accepts_json_or_csv(accept)
|
66
|
+
end
|
67
|
+
|
68
|
+
def accepts_html(accept)
|
69
|
+
accept.include?("html")
|
70
|
+
end
|
71
|
+
|
72
|
+
def accepts_json_or_csv accept
|
73
|
+
accept.include?("json") || accept.include?("csv")
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
data/lib/pact_broker/version.rb
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
module Rack
|
2
|
+
module PactBroker
|
3
|
+
|
4
|
+
# If the HTML and the CSV group resources are both requested by the browser,
|
5
|
+
# Chrome gets confused by the content types, and when you click back, it tries to load the CSV
|
6
|
+
# instead of the HTML page. So we have to give the CSV resource a different URL (.csv)
|
7
|
+
|
8
|
+
class ConvertFileExtensionToAcceptHeader
|
9
|
+
|
10
|
+
EXTENSIONS = {".csv" => "text/csv"}
|
11
|
+
EXTENSION_REGEXP = /\.\w+$/
|
12
|
+
|
13
|
+
def initialize app
|
14
|
+
@app = app
|
15
|
+
end
|
16
|
+
|
17
|
+
def call env
|
18
|
+
file_extension = extension(env)
|
19
|
+
if convert_to_accept_header? file_extension
|
20
|
+
@app.call(set_accept_header_and_path_info(env, file_extension))
|
21
|
+
else
|
22
|
+
@app.call(env)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def convert_to_accept_header? file_extension
|
27
|
+
EXTENSIONS[file_extension]
|
28
|
+
end
|
29
|
+
|
30
|
+
def extension env
|
31
|
+
env["PATH_INFO"] =~ EXTENSION_REGEXP && $~[0]
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_accept_header_and_path_info env, file_extension
|
35
|
+
env.merge(
|
36
|
+
"PATH_INFO" => env["PATH_INFO"].gsub(EXTENSION_REGEXP, ''),
|
37
|
+
"HTTP_ACCEPT" => EXTENSIONS[file_extension]
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/pact_broker.gemspec
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
var hljs=new function(){function j(v){return v.replace(/&/gm,"&").replace(/</gm,"<").replace(/>/gm,">")}function t(v){return v.nodeName.toLowerCase()}function h(w,x){var v=w&&w.exec(x);return v&&v.index==0}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^lang(uage)?-/,"")});return v.filter(function(x){return i(x)||/no(-?)highlight/.test(x)})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);if(!t(A).match(/br|hr|img|input/)){v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset<y[0].offset)?w:y}return y[0].event=="start"?w:y}function A(H){function G(I){return" "+I.nodeName+'="'+j(I.value)+'"'}F+="<"+t(H)+Array.prototype.map.call(H.attributes,G).join("")+">"}function E(G){F+="</"+t(G)+">"}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=j(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+j(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};var E=function(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})};if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b="\\b("+D.bK.split(" ").join("|")+")\\b"}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?("+F.b+")\\.?":F.b}).concat([D.tE,D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}}}x(y)}function c(T,L,J,R){function v(V,W){for(var U=0;U<W.c.length;U++){if(h(W.c[U].bR,V)){return W.c[U]}}}function z(V,U){if(h(V.eR,U)){return V}if(V.eW){return z(V.parent,U)}}function A(U,V){return !J&&h(V.iR,U)}function E(W,U){var V=M.cI?U[0].toLowerCase():U[0];return W.k.hasOwnProperty(V)&&W.k[V]}function w(aa,Y,X,W){var U=W?"":b.classPrefix,V='<span class="'+U,Z=X?"":"</span>";V+=aa+'">';return V+Y+Z}function N(){if(!I.k){return j(C)}var U="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(C);while(V){U+=j(C.substr(X,V.index-X));var W=E(I,V);if(W){H+=W[1];U+=w(W[0],j(V[0]))}else{U+=j(V[0])}X=I.lR.lastIndex;V=I.lR.exec(C)}return U+j(C.substr(X))}function F(){if(I.sL&&!f[I.sL]){return j(C)}var U=I.sL?c(I.sL,C,true,S):e(C);if(I.r>0){H+=U.r}if(I.subLanguageMode=="continuous"){S=U.top}return w(U.language,U.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(W,V){var U=W.cN?w(W.cN,"",true):"";if(W.rB){D+=U;C=""}else{if(W.eB){D+=j(V)+U;C=""}else{D+=U;C=V}}I=Object.create(W,{parent:{value:I}})}function G(U,Y){C+=U;if(Y===undefined){D+=Q();return 0}var W=v(Y,I);if(W){D+=Q();P(W,Y);return W.rB?0:Y.length}var X=z(I,Y);if(X){var V=I;if(!(V.rE||V.eE)){C+=Y}D+=Q();do{if(I.cN){D+="</span>"}H+=I.r;I=I.parent}while(I!=X.parent);if(V.eE){D+=j(Y)}C="";if(X.starts){P(X.starts,"")}return V.rE?0:Y.length}if(A(Y,I)){throw new Error('Illegal lexeme "'+Y+'" for mode "'+(I.cN||"<unnamed>")+'"')}C+=Y;return Y.length||1}var M=i(T);if(!M){throw new Error('Unknown language: "'+T+'"')}m(M);var I=R||M;var S;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,"",true)+D}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+="</span>"}}return{r:H,value:D,language:T,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:j(L)}}else{throw O}}}function e(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:j(y)};var w=v;x.forEach(function(z){if(!i(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function g(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"<br>")}return v}function p(A){var B=r(A);if(/no(-?)highlight/.test(B)){return}var y;if(b.useBR){y=document.createElementNS("http://www.w3.org/1999/xhtml","div");y.innerHTML=A.innerHTML.replace(/\n/g,"").replace(/<br[ \/]*>/g,"\n")}else{y=A}var z=y.textContent;var v=B?c(B,z,true):e(z);var x=u(y);if(x.length){var w=document.createElementNS("http://www.w3.org/1999/xhtml","div");w.innerHTML=v.value;v.value=q(x,u(w),z)}v.value=g(v.value);A.innerHTML=v.value;A.className+=" hljs "+(!B&&v.language||"");A.result={language:v.language,re:v.r};if(v.second_best){A.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function d(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function k(){return Object.keys(f)}function i(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=e;this.fixMarkup=g;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=d;this.listLanguages=k;this.getLanguage=i;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/};this.CLCM={cN:"comment",b:"//",e:"$",c:[this.PWM]};this.CBCM={cN:"comment",b:"/\\*",e:"\\*/",c:[this.PWM]};this.HCM={cN:"comment",b:"#",e:"$",c:[this.PWM]};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.CSSNM={cN:"number",b:this.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0};this.RM={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}});
|
@@ -0,0 +1,127 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
4
|
+
|
5
|
+
*/
|
6
|
+
|
7
|
+
.hljs {
|
8
|
+
display: block;
|
9
|
+
overflow-x: auto;
|
10
|
+
padding: 0.5em;
|
11
|
+
color: #333;
|
12
|
+
background: #f8f8f8;
|
13
|
+
-webkit-text-size-adjust: none;
|
14
|
+
}
|
15
|
+
|
16
|
+
.hljs-comment,
|
17
|
+
.hljs-template_comment,
|
18
|
+
.diff .hljs-header,
|
19
|
+
.hljs-javadoc {
|
20
|
+
color: #998;
|
21
|
+
font-style: italic;
|
22
|
+
}
|
23
|
+
|
24
|
+
.hljs-keyword,
|
25
|
+
.css .rule .hljs-keyword,
|
26
|
+
.hljs-winutils,
|
27
|
+
.javascript .hljs-title,
|
28
|
+
.nginx .hljs-title,
|
29
|
+
.hljs-subst,
|
30
|
+
.hljs-request,
|
31
|
+
.hljs-status {
|
32
|
+
color: #333;
|
33
|
+
font-weight: bold;
|
34
|
+
}
|
35
|
+
|
36
|
+
.hljs-number,
|
37
|
+
.hljs-hexcolor,
|
38
|
+
.ruby .hljs-constant {
|
39
|
+
color: #008080;
|
40
|
+
}
|
41
|
+
|
42
|
+
.hljs-string,
|
43
|
+
.hljs-tag .hljs-value,
|
44
|
+
.hljs-phpdoc,
|
45
|
+
.hljs-dartdoc,
|
46
|
+
.tex .hljs-formula {
|
47
|
+
color: #d14;
|
48
|
+
}
|
49
|
+
|
50
|
+
.hljs-title,
|
51
|
+
.hljs-id,
|
52
|
+
.scss .hljs-preprocessor {
|
53
|
+
color: #900;
|
54
|
+
font-weight: bold;
|
55
|
+
}
|
56
|
+
|
57
|
+
.javascript .hljs-title,
|
58
|
+
.hljs-list .hljs-keyword,
|
59
|
+
.hljs-subst {
|
60
|
+
font-weight: normal;
|
61
|
+
}
|
62
|
+
|
63
|
+
.hljs-class .hljs-title,
|
64
|
+
.hljs-type,
|
65
|
+
.vhdl .hljs-literal,
|
66
|
+
.tex .hljs-command {
|
67
|
+
color: #458;
|
68
|
+
font-weight: bold;
|
69
|
+
}
|
70
|
+
|
71
|
+
.hljs-tag,
|
72
|
+
.hljs-tag .hljs-title,
|
73
|
+
.hljs-rules .hljs-property,
|
74
|
+
.django .hljs-tag .hljs-keyword {
|
75
|
+
color: #000080;
|
76
|
+
font-weight: normal;
|
77
|
+
}
|
78
|
+
|
79
|
+
.hljs-attribute,
|
80
|
+
.hljs-variable,
|
81
|
+
.lisp .hljs-body {
|
82
|
+
color: #000080;
|
83
|
+
}
|
84
|
+
|
85
|
+
.hljs-regexp {
|
86
|
+
color: #009926;
|
87
|
+
}
|
88
|
+
|
89
|
+
.hljs-symbol,
|
90
|
+
.ruby .hljs-symbol .hljs-string,
|
91
|
+
.lisp .hljs-keyword,
|
92
|
+
.clojure .hljs-keyword,
|
93
|
+
.scheme .hljs-keyword,
|
94
|
+
.tex .hljs-special,
|
95
|
+
.hljs-prompt {
|
96
|
+
color: #990073;
|
97
|
+
}
|
98
|
+
|
99
|
+
.hljs-built_in {
|
100
|
+
color: #0086b3;
|
101
|
+
}
|
102
|
+
|
103
|
+
.hljs-preprocessor,
|
104
|
+
.hljs-pragma,
|
105
|
+
.hljs-pi,
|
106
|
+
.hljs-doctype,
|
107
|
+
.hljs-shebang,
|
108
|
+
.hljs-cdata {
|
109
|
+
color: #999;
|
110
|
+
font-weight: bold;
|
111
|
+
}
|
112
|
+
|
113
|
+
.hljs-deletion {
|
114
|
+
background: #fdd;
|
115
|
+
}
|
116
|
+
|
117
|
+
.hljs-addition {
|
118
|
+
background: #dfd;
|
119
|
+
}
|
120
|
+
|
121
|
+
.diff .hljs-change {
|
122
|
+
background: #0086b3;
|
123
|
+
}
|
124
|
+
|
125
|
+
.hljs-chunk {
|
126
|
+
color: #aaa;
|
127
|
+
}
|
data/public/stylesheets/pact.css
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"consumer": {
|
3
|
+
"name": "A Consumer"
|
4
|
+
},
|
5
|
+
"provider": {
|
6
|
+
"name": "A Provider"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"request": {
|
11
|
+
"description" : "a request for something",
|
12
|
+
"method": "get",
|
13
|
+
"path" : "/something"
|
14
|
+
},
|
15
|
+
"response": {
|
16
|
+
"status": 200,
|
17
|
+
"body" : "something"
|
18
|
+
}
|
19
|
+
}
|
20
|
+
]
|
21
|
+
}
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pact_broker/app'
|
3
|
+
require 'db'
|
4
|
+
|
5
|
+
module PactBroker
|
6
|
+
|
7
|
+
describe App do
|
8
|
+
|
9
|
+
before do
|
10
|
+
ProviderStateBuilder.new.create_pact_with_hierarchy 'Some Consumer', '1.0', 'Some Provider'
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:hal_browser_enabled) { true }
|
14
|
+
let(:group_url) { '/groups/Some%20Consumer' }
|
15
|
+
|
16
|
+
let(:app) do
|
17
|
+
app = PactBroker::App.new do | config |
|
18
|
+
config.auto_migrate_db = false
|
19
|
+
config.use_hal_browser = hal_browser_enabled
|
20
|
+
config.database_connection = ::DB::PACT_BROKER_DB
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when Accept includes text/html" do
|
26
|
+
let(:env) { {'HTTP_ACCEPT' => 'text/html'} }
|
27
|
+
|
28
|
+
subject { get path, '', env; last_response }
|
29
|
+
|
30
|
+
describe "a request for root" do
|
31
|
+
|
32
|
+
let(:path) { '/' }
|
33
|
+
|
34
|
+
it "redirects to /ui/relationships" do
|
35
|
+
expect(subject.status).to eq 303
|
36
|
+
expect(subject.headers['Location']).to eq 'ui/relationships'
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "a request for /ui/relationships" do
|
42
|
+
let(:path) { '/ui/relationships/' }
|
43
|
+
|
44
|
+
it "returns the relationships page" do
|
45
|
+
expect(subject.status).to eq 200
|
46
|
+
expect(subject.headers['Content-Type']).to include 'text/html'
|
47
|
+
expect(subject.body).to include 'Relationships'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "a request for /groups/:pacticipant_name" do
|
52
|
+
let(:path) { '/groups/Some%20Consumer' }
|
53
|
+
|
54
|
+
it "returns the group page" do
|
55
|
+
expect(subject.status).to eq 200
|
56
|
+
expect(subject.headers['Content-Type']).to include 'text/html'
|
57
|
+
expect(subject.body).to include 'Network graph'
|
58
|
+
expect(subject.body).to include 'Some Consumer'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "a request for /doc/:rel_name" do
|
63
|
+
let(:path) { '/doc/webhooks' }
|
64
|
+
|
65
|
+
it "returns the HAL docs for the given rel" do
|
66
|
+
expect(subject.status).to eq 200
|
67
|
+
expect(subject.headers['Content-Type']).to include 'text/html'
|
68
|
+
expect(subject.body).to include 'Webhooks'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "a request the group containing a pacticipant" do
|
73
|
+
let(:path) { group_url }
|
74
|
+
|
75
|
+
it "returns the HTML representation of the group" do
|
76
|
+
expect(subject.status).to eq 200
|
77
|
+
expect(subject.headers['Content-Type']).to include 'text/html'
|
78
|
+
expect(subject.body).to include 'Network graph'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "a request for a path that does not exist" do
|
83
|
+
let(:path) { '/foo' }
|
84
|
+
|
85
|
+
it "returns a 404" do
|
86
|
+
expect(subject.status).to eq 404
|
87
|
+
expect(subject.headers['Content-Type']).to include 'text/html'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when the HALBrowser is enabled" do
|
92
|
+
context "when application/hal+json is also specified as an Accept" do
|
93
|
+
|
94
|
+
let(:env) { {'HTTP_ACCEPT' => 'text/html;application/hal+json'} }
|
95
|
+
let(:path) { '/something' }
|
96
|
+
|
97
|
+
it "redirects to the HAL Browser" do
|
98
|
+
expect(subject.status).to eq 303
|
99
|
+
expect(subject.headers['Location']).to eq '/hal-browser/browser.html#/something'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "when the HALBrowser is not enabled" do
|
105
|
+
context "when application/hal+json is also specified as an Accept" do
|
106
|
+
|
107
|
+
let(:hal_browser_enabled) { false }
|
108
|
+
let(:env) { {'HTTP_ACCEPT' => 'text/html;application/hal+json'} }
|
109
|
+
let(:path) { '/something' }
|
110
|
+
|
111
|
+
it "does not redirect to the HAL Browser" do
|
112
|
+
expect(subject.status).to_not eq 303
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when a .csv extension is specified" do
|
118
|
+
|
119
|
+
let(:path) { '/groups/Some%20Consumer.csv' }
|
120
|
+
|
121
|
+
it "returns the CSV Content-Type" do
|
122
|
+
expect(subject.status).to eq 200
|
123
|
+
expect(subject.headers['Content-Type']).to eq "text/csv"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
context "when no Accept header is specified" do
|
130
|
+
|
131
|
+
let(:env) { {} }
|
132
|
+
subject { get path, '', env; last_response }
|
133
|
+
|
134
|
+
describe "a request for root" do
|
135
|
+
let(:path) { "/" }
|
136
|
+
|
137
|
+
it "returns an API response" do
|
138
|
+
expect(subject.status).to eq 200
|
139
|
+
expect(subject.headers['Content-Type']).to_not include 'html'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "a request the group containing a pacticipant" do
|
144
|
+
let(:path) { group_url }
|
145
|
+
|
146
|
+
it "returns the API representation of the group" do
|
147
|
+
expect(subject.status).to eq 200
|
148
|
+
expect(subject.headers['Content-Type']).to_not include 'html'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "a request for a stylesheet" do
|
153
|
+
let(:path) { '/stylesheets/pact.css' }
|
154
|
+
|
155
|
+
it "returns the stylesheet" do
|
156
|
+
expect(subject.status).to eq 200
|
157
|
+
expect(subject.headers['Content-Type']).to include 'text/css'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|