pact_broker 2.52.1 → 2.56.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -0
  3. data/CODE_OF_CONDUCT.md +76 -0
  4. data/README.md +2 -4
  5. data/db/migrations/20180828_create_latest_versions.rb +1 -1
  6. data/lib/pact_broker/api.rb +8 -0
  7. data/lib/pact_broker/api/contracts/webhook_contract.rb +8 -6
  8. data/lib/pact_broker/api/decorators/decorator_context.rb +6 -11
  9. data/lib/pact_broker/api/decorators/reason_decorator.rb +17 -0
  10. data/lib/pact_broker/api/decorators/webhook_execution_result_decorator.rb +6 -1
  11. data/lib/pact_broker/api/pact_broker_urls.rb +6 -2
  12. data/lib/pact_broker/api/renderers/html_pact_renderer.rb +14 -14
  13. data/lib/pact_broker/api/resources/badge.rb +6 -2
  14. data/lib/pact_broker/api/resources/base_resource.rb +3 -3
  15. data/lib/pact_broker/api/resources/matrix_badge.rb +5 -0
  16. data/lib/pact_broker/api/resources/pact.rb +1 -17
  17. data/lib/pact_broker/api/resources/pacticipant.rb +0 -4
  18. data/lib/pact_broker/api/resources/pacticipants.rb +3 -2
  19. data/lib/pact_broker/api/resources/verifications.rb +0 -4
  20. data/lib/pact_broker/app.rb +13 -4
  21. data/lib/pact_broker/badges/service.rb +16 -13
  22. data/lib/pact_broker/db.rb +9 -1
  23. data/lib/pact_broker/doc/controllers/app.rb +11 -1
  24. data/lib/pact_broker/doc/views/layouts/main.haml +1 -1
  25. data/lib/pact_broker/domain/verification.rb +13 -0
  26. data/lib/pact_broker/hash_refinements.rb +4 -0
  27. data/lib/pact_broker/integrations/service.rb +2 -2
  28. data/lib/pact_broker/locale/en.yml +1 -1
  29. data/lib/pact_broker/logging.rb +3 -1
  30. data/lib/pact_broker/matrix/deployment_status_summary.rb +23 -1
  31. data/lib/pact_broker/matrix/reason.rb +9 -0
  32. data/lib/pact_broker/matrix/unresolved_selector.rb +4 -0
  33. data/lib/pact_broker/pacticipants/repository.rb +6 -0
  34. data/lib/pact_broker/pacticipants/service.rb +8 -0
  35. data/lib/pact_broker/pacts/content.rb +26 -2
  36. data/lib/pact_broker/pacts/repository.rb +5 -4
  37. data/lib/pact_broker/tasks/migration_task.rb +20 -1
  38. data/lib/pact_broker/test/test_data_builder.rb +8 -3
  39. data/lib/pact_broker/ui/app.rb +1 -0
  40. data/lib/pact_broker/ui/controllers/base_controller.rb +3 -0
  41. data/lib/pact_broker/ui/controllers/clusters.rb +2 -2
  42. data/lib/pact_broker/ui/controllers/groups.rb +3 -2
  43. data/lib/pact_broker/ui/controllers/index.rb +3 -2
  44. data/lib/pact_broker/ui/controllers/matrix.rb +19 -3
  45. data/lib/pact_broker/ui/helpers/url_helper.rb +4 -4
  46. data/lib/pact_broker/ui/view_models/index_item.rb +16 -11
  47. data/lib/pact_broker/ui/view_models/index_items.rb +2 -2
  48. data/lib/pact_broker/ui/view_models/matrix_line.rb +12 -7
  49. data/lib/pact_broker/ui/view_models/matrix_lines.rb +2 -2
  50. data/lib/pact_broker/ui/views/groups/show.html.erb +3 -3
  51. data/lib/pact_broker/ui/views/index/_css_and_js.haml +9 -9
  52. data/lib/pact_broker/ui/views/index/_navbar.haml +3 -3
  53. data/lib/pact_broker/ui/views/index/_pagination.haml +1 -1
  54. data/lib/pact_broker/ui/views/index/show-with-tags.haml +3 -3
  55. data/lib/pact_broker/ui/views/index/show.haml +3 -3
  56. data/lib/pact_broker/ui/views/layouts/main.haml +4 -4
  57. data/lib/pact_broker/ui/views/matrix/show.haml +14 -11
  58. data/lib/pact_broker/verifications/repository.rb +4 -5
  59. data/lib/pact_broker/version.rb +1 -1
  60. data/lib/pact_broker/webhooks/service.rb +4 -3
  61. data/lib/pact_broker/webhooks/webhook_event.rb +1 -1
  62. data/lib/pact_broker/webhooks/webhook_request_logger.rb +8 -8
  63. data/pact_broker.gemspec +2 -2
  64. data/public/javascripts/pact.js +7 -6
  65. data/public/stylesheets/matrix.css +13 -0
  66. data/script/foo-bar-verification.json +3 -1
  67. data/script/foo-bar.json +11 -0
  68. data/script/seed.rb +1 -1
  69. data/spec/features/create_webhook_spec.rb +1 -1
  70. data/spec/features/delete_integration_spec.rb +2 -2
  71. data/spec/features/get_matrix_badge_spec.rb +9 -0
  72. data/spec/fixtures/webhook_valid.json +1 -1
  73. data/spec/fixtures/webhook_valid_with_pacticipants.json +1 -1
  74. data/spec/integration/ui/index_spec.rb +16 -0
  75. data/spec/integration/ui/matrix_spec.rb +11 -4
  76. data/spec/lib/pact_broker/api/contracts/webhook_contract_spec.rb +12 -0
  77. data/spec/lib/pact_broker/api/decorators/pact_version_decorator_spec.rb +1 -1
  78. data/spec/lib/pact_broker/api/decorators/reason_decorator_spec.rb +18 -1
  79. data/spec/lib/pact_broker/api/decorators/webhooks_decorator_spec.rb +1 -1
  80. data/spec/lib/pact_broker/api/pact_broker_urls_spec.rb +8 -0
  81. data/spec/lib/pact_broker/api/renderers/html_pact_renderer_spec.rb +1 -1
  82. data/spec/lib/pact_broker/api/resources/badge_spec.rb +42 -22
  83. data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +1 -1
  84. data/spec/lib/pact_broker/badges/service_spec.rb +15 -3
  85. data/spec/lib/pact_broker/doc/controllers/app_spec.rb +16 -0
  86. data/spec/lib/pact_broker/domain/version_spec.rb +7 -7
  87. data/spec/lib/pact_broker/integrations/service_spec.rb +6 -0
  88. data/spec/lib/pact_broker/matrix/deployment_status_summary_spec.rb +6 -2
  89. data/spec/lib/pact_broker/matrix/integration_spec.rb +43 -0
  90. data/spec/lib/pact_broker/pacts/content_spec.rb +125 -0
  91. data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +18 -1
  92. data/spec/lib/pact_broker/verifications/repository_spec.rb +20 -0
  93. data/spec/lib/pact_broker/webhooks/webhook_request_logger_spec.rb +4 -1
  94. data/spec/migrations/rollback_spec.rb +6 -0
  95. data/spec/service_consumers/provider_states_for_pact_broker_client.rb +11 -0
  96. data/vendor/hal-browser/README.adoc +169 -0
  97. data/vendor/hal-browser/browser.html +36 -22
  98. data/vendor/hal-browser/js/hal.js +30 -7
  99. data/vendor/hal-browser/js/hal/http/client.js +14 -6
  100. data/vendor/hal-browser/js/hal/resource.js +4 -2
  101. data/vendor/hal-browser/js/hal/views/documentation.js +1 -1
  102. data/vendor/hal-browser/js/hal/views/embedded_resource.js +10 -4
  103. data/vendor/hal-browser/js/hal/views/links.js +3 -2
  104. data/vendor/hal-browser/js/hal/views/non_safe_request_dialog.js +1 -1
  105. data/vendor/hal-browser/js/hal/views/properties.js +101 -2
  106. data/vendor/hal-browser/js/hal/views/query_uri_dialog.js +1 -1
  107. data/vendor/hal-browser/js/hal/views/request_headers.js +1 -1
  108. data/vendor/hal-browser/js/hal/views/resource.js +4 -3
  109. data/vendor/hal-browser/js/hal/views/response_headers.js +12 -1
  110. data/vendor/hal-browser/login.html +76 -0
  111. data/vendor/hal-browser/styles.css +3 -1
  112. data/vendor/hal-browser/vendor/js/URI.min.js +84 -0
  113. metadata +31 -28
  114. data/lib/pact_broker/verifications/all_verifications.rb +0 -41
  115. data/vendor/hal-browser/README.md +0 -41
@@ -227,6 +227,131 @@ module PactBroker
227
227
  its(:pact_specification_version) { is_expected.to eq nil }
228
228
  end
229
229
  end
230
+
231
+ describe "with_test_results" do
232
+ let(:test_results) do
233
+ {
234
+ "tests" => [
235
+ {
236
+ "interactionProviderState" => "ps1",
237
+ "interactionDescription" => "desc1"
238
+ },{
239
+ "interactionProviderState" => "ps1",
240
+ "interactionDescription" => "desc1"
241
+ }
242
+ ]
243
+ }
244
+ end
245
+
246
+ let(:pact_content) do
247
+ {
248
+ "interactions" => [
249
+ {
250
+ "providerState" => "ps1",
251
+ "description" => "desc1",
252
+ },
253
+ {
254
+ "providerState" => "ps2",
255
+ "description" => "desc2",
256
+ }
257
+ ]
258
+ }
259
+ end
260
+
261
+ subject { Content.from_hash(pact_content).with_test_results(test_results) }
262
+
263
+ let(:merged) do
264
+ {
265
+ "interactions" => [
266
+ {
267
+ "providerState" => "ps1",
268
+ "description" => "desc1",
269
+ "tests" => [
270
+ {
271
+ "interactionProviderState" => "ps1",
272
+ "interactionDescription" => "desc1",
273
+ },{
274
+ "interactionProviderState" => "ps1",
275
+ "interactionDescription" => "desc1",
276
+ }
277
+ ]
278
+ },{
279
+ "providerState" => "ps2",
280
+ "description" => "desc2",
281
+ "tests" => []
282
+ }
283
+ ]
284
+ }
285
+ end
286
+
287
+ let(:merged_with_empty_tests) do
288
+ {
289
+ "interactions" => [
290
+ {
291
+ "providerState" => "ps1",
292
+ "description" => "desc1",
293
+ "tests" => []
294
+ },{
295
+ "providerState" => "ps2",
296
+ "description" => "desc2",
297
+ "tests" => []
298
+ }
299
+ ]
300
+ }
301
+ end
302
+
303
+ it "merges the contents with the results" do
304
+ expect(subject.to_hash).to eq merged
305
+ end
306
+
307
+ it "returns interactions without test results" do
308
+ expect(subject.interactions_missing_test_results.count).to eq 1
309
+ end
310
+
311
+ context "with nil test results" do
312
+ let(:test_results) { nil }
313
+
314
+ it "does not blow up" do
315
+ expect(subject.to_hash).to eq merged_with_empty_tests
316
+ end
317
+
318
+ it "returns interactions without test results" do
319
+ expect(subject.interactions_missing_test_results.count).to eq 2
320
+ end
321
+ end
322
+
323
+ context "with nil tests" do
324
+ let(:test_results) { {} }
325
+
326
+ it "does not blow up" do
327
+ expect(subject.to_hash).to eq merged_with_empty_tests
328
+ end
329
+ end
330
+
331
+ context "with empty tests" do
332
+ let(:test_results) { { "tests" => [] } }
333
+
334
+ it "does not blow up" do
335
+ expect(subject.to_hash).to eq merged_with_empty_tests
336
+ end
337
+ end
338
+
339
+ context "with tests not an array" do
340
+ let(:test_results) { { "tests" => {} } }
341
+
342
+ it "does not blow up" do
343
+ expect(subject.to_hash).to eq merged_with_empty_tests
344
+ end
345
+ end
346
+
347
+ context "with tests an array of not hashes" do
348
+ let(:test_results) { { "tests" => [1] } }
349
+
350
+ it "does not blow up" do
351
+ expect(subject.to_hash).to eq merged_with_empty_tests
352
+ end
353
+ end
354
+ end
230
355
  end
231
356
  end
232
357
  end
@@ -6,7 +6,6 @@ module PactBroker
6
6
  let(:td) { TestDataBuilder.new }
7
7
 
8
8
  describe "#find_for_verification" do
9
-
10
9
  def find_by_consumer_version_number(consumer_version_number)
11
10
  subject.find{ |pact| pact.consumer_version_number == consumer_version_number }
12
11
  end
@@ -189,6 +188,24 @@ module PactBroker
189
188
  expect(find_by_consumer_version_number("foo-latest-dev-version").overall_latest?).to be true
190
189
  end
191
190
  end
191
+
192
+ context "when two consumers have exactly the same json content" do
193
+ before do
194
+ td.create_consumer
195
+ .create_provider("Bar")
196
+ .create_consumer_version
197
+ .create_pact(json_content: { interactions: ['foo'] }.to_json )
198
+ .create_consumer
199
+ .create_consumer_version
200
+ .create_pact(json_content: { interactions: ['foo'] }.to_json )
201
+ end
202
+
203
+ let(:consumer_version_selectors) { Selectors.new }
204
+
205
+ it "returns a pact for each consumer" do
206
+ expect(subject.size).to eq 2
207
+ end
208
+ end
192
209
  end
193
210
  end
194
211
  end
@@ -295,6 +295,26 @@ module PactBroker
295
295
  expect(subject.number).to eq 2
296
296
  end
297
297
  end
298
+
299
+ context "when the consumer does not exist" do
300
+ subject { Repository.new.find_latest_verification_for_tags("Foo", "Bar", "feat-x", "feat-y") }
301
+
302
+ it "raises an error" do
303
+ expect{ subject }.to raise_error PactBroker::Error, /Foo/
304
+ end
305
+ end
306
+
307
+ context "when the provider does not exist" do
308
+ before do
309
+ td.create_consumer("Foo")
310
+ end
311
+
312
+ subject { Repository.new.find_latest_verification_for_tags("Foo", "Bar", "feat-x", "feat-y") }
313
+
314
+ it "raises an error" do
315
+ expect{ subject }.to raise_error PactBroker::Error, /Bar/
316
+ end
317
+ end
298
318
  end
299
319
 
300
320
  describe "delete_by_provider_version_id" do
@@ -50,7 +50,8 @@ module PactBroker
50
50
  }
51
51
  end
52
52
 
53
- let(:webhook_context) { { consumer_version_number: "123" } }
53
+ let(:base_url) { "http://example.org" }
54
+ let(:webhook_context) { { consumer_version_number: "123", base_url: base_url } }
54
55
 
55
56
  let(:webhook_request_logger) { WebhookRequestLogger.new(options) }
56
57
 
@@ -117,6 +118,7 @@ module PactBroker
117
118
  end
118
119
 
119
120
  it "logs a message about why the response is hidden" do
121
+ expect(logs).to include base_url
120
122
  expect(logs).to include "security purposes"
121
123
  end
122
124
  end
@@ -192,6 +194,7 @@ module PactBroker
192
194
  end
193
195
 
194
196
  it "logs a message about why the response is hidden" do
197
+ expect(logs).to include base_url
195
198
  expect(logs).to include "security purposes"
196
199
  end
197
200
  end
@@ -0,0 +1,6 @@
1
+ describe "migrate and rollback", migration: true do
2
+ it "doesn't blow up" do
3
+ PactBroker::Database.migrate
4
+ PactBroker::Database.migrate(20190509) # previous migration uses an irreversible migration
5
+ end
6
+ end
@@ -244,4 +244,15 @@ Pact.provider_states_for "Pact Broker Client" do
244
244
  .create_webhook(uuid: "696c5f93-1b7f-44bc-8d03-59440fcaa9a0")
245
245
  end
246
246
  end
247
+
248
+ provider_state "the pacticipant relations are present" do
249
+ no_op
250
+ end
251
+
252
+ provider_state "a pacticipant with name Foo exists" do
253
+ set_up do
254
+ TestDataBuilder.new
255
+ .create_consumer("Foo")
256
+ end
257
+ end
247
258
  end
@@ -0,0 +1,169 @@
1
+ = HAL-browser
2
+
3
+ An API browser for the hal+json media type
4
+
5
+ == Example Usage
6
+
7
+ Here is an example of a hal+json API using the browser:
8
+
9
+ http://haltalk.herokuapp.com/explorer/browser.html[http://haltalk.herokuapp.com/explorer/browser.html]
10
+
11
+ == About HAL
12
+
13
+ HAL is a format based on json that establishes conventions for
14
+ representing links. For example:
15
+
16
+ [source,javascript]
17
+ ----
18
+ {
19
+ "_links": {
20
+ "self": { "href": "/orders" },
21
+ "next": { "href": "/orders?page=2" }
22
+ }
23
+ }
24
+ ----
25
+
26
+ More detail about HAL can be found at
27
+ http://stateless.co/hal_specification.html[http://stateless.co/hal_specification.html].
28
+
29
+ == Customizing the POST form
30
+
31
+ By default, the HAL Browser can't assume there is any metadata. When you click on the non-GET request button (to create a new resource), the user must enter the JSON document to submit. If your service includes metadata you can access, it's possible to plugin a custom view that makes use of it.
32
+
33
+ . Define your custom view.
34
+ +
35
+ Here is an example that leverages Spring Data REST's JSON Schema metadata found at */{entity}/schema*.
36
+ +
37
+ [source,javascript]
38
+ ----
39
+ var CustomPostForm = Backbone.View.extend({
40
+ initialize: function (opts) {
41
+ this.href = opts.href.split('{')[0];
42
+ this.vent = opts.vent;
43
+ _.bindAll(this, 'createNewResource');
44
+ },
45
+
46
+ events: {
47
+ 'submit form': 'createNewResource'
48
+ },
49
+
50
+ className: 'modal fade',
51
+
52
+ createNewResource: function (e) {
53
+ e.preventDefault();
54
+
55
+ var self = this;
56
+
57
+ var data = {}
58
+ Object.keys(this.schema.properties).forEach(function(property) {
59
+ if (!("format" in self.schema.properties[property])) {
60
+ data[property] = self.$('input[name=' + property + ']').val();
61
+ }
62
+ });
63
+
64
+ var opts = {
65
+ url: this.$('.url').val(),
66
+ headers: HAL.parseHeaders(this.$('.headers').val()),
67
+ method: this.$('.method').val(),
68
+ data: JSON.stringify(data)
69
+ };
70
+
71
+ var request = HAL.client.request(opts);
72
+ request.done(function (response) {
73
+ self.vent.trigger('response', {resource: response, jqxhr: jqxhr});
74
+ }).fail(function (response) {
75
+ self.vent.trigger('fail-response', {jqxhr: jqxhr});
76
+ }).always(function () {
77
+ self.vent.trigger('response-headers', {jqxhr: jqxhr});
78
+ window.location.hash = 'NON-GET:' + opts.url;
79
+ });
80
+
81
+ this.$el.modal('hide');
82
+ },
83
+
84
+ render: function (opts) {
85
+ var headers = HAL.client.getHeaders();
86
+ var headersString = '';
87
+
88
+ _.each(headers, function (value, name) {
89
+ headersString += name + ': ' + value + '\n';
90
+ });
91
+
92
+ var request = HAL.client.request({
93
+ url: this.href + '/schema',
94
+ method: 'GET'
95
+ });
96
+
97
+ var self = this;
98
+ request.done(function (schema) {
99
+ self.schema = schema;
100
+ self.$el.html(self.template({
101
+ href: self.href,
102
+ schema: self.schema,
103
+ user_defined_headers: headersString}));
104
+ self.$el.modal();
105
+ });
106
+
107
+ return this;
108
+ },
109
+ template: _.template($('#dynamic-request-template').html())
110
+ });
111
+ ----
112
+ +
113
+ . Register it by assigning to `HAL.customPostForm`
114
+ +
115
+ [source,javascript]
116
+ ----
117
+ HAL.customPostForm = CustomPostForm;
118
+ ----
119
+ +
120
+ . Load your custom JavaScript component and define your custom HTML template.
121
+ +
122
+ [source,html,indent=0]
123
+ ----
124
+ <script id="dynamic-request-template" type="text/template">
125
+ <div class="modal-header">
126
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
127
+ <h3>Make a non-GET request</h3>
128
+ </div>
129
+
130
+ <form class="non-safe" action="<%= href %>">
131
+ <div class="modal-body">
132
+ <p>Target URI</p>
133
+ <input name="url" type="text" class="url" value="<%= href %>" />
134
+ <p>Method:</p>
135
+ <input name="method" type="text" class="method" value="POST" />
136
+ <p>Headers:</p>
137
+ <textarea name="headers" class="headers" style="height: 100px">
138
+ Content-Type: application/json
139
+ <%= user_defined_headers %>
140
+ </textarea>
141
+ </div>
142
+ <% _.each(schema.properties, function(value, name) { %>
143
+ <% if (!("format" in value)) { %>
144
+ <input type="text" placeholder="<%= name %>" name="<%= name %>" />
145
+ <% } %>
146
+ <% }); %>
147
+ <div class="modal-footer">
148
+ <button type="submit" class="btn btn-primary">Make Request</button>
149
+ </div>
150
+ </form>
151
+ </script>
152
+ ----
153
+
154
+ NOTE: To load a custom JavaScript module AND a custom HTML template, you will probably need to create a customized version of `browser.html`.
155
+
156
+ NOTE: The HAL Browser uses a global `HAL` object, so there is no need to deal with JavaScript packages.
157
+
158
+ == Usage Instructions
159
+
160
+ All you should need to do is copy the files into your webroot.
161
+ It is OK to put it in a subdirectory; it does not need to be in the root.
162
+
163
+ All the JS and CSS dependencies come included in the vendor directory.
164
+
165
+ == TODO
166
+
167
+ * Provide feedback to user when there are issues with response (missing
168
+ self link, wrong media type identifier)
169
+ * Give 'self' and 'curies' links special treatment
@@ -26,7 +26,7 @@
26
26
  <ul class="nav">
27
27
  <li><a href="#/" id="entryPointLink">Go To Entry Point</a></li>
28
28
  <li><a href="https://github.com/mikekelly/hal-browser">About The HAL Browser</a></li>
29
- <li><a href="/">Pact Broker Home</a></li>
29
+ <li><a href="/" id="pactBrokerHomeLink">Pact Broker Home</a></li> <!-- pact_broker -->
30
30
  </ul>
31
31
  </div>
32
32
  </div>
@@ -38,7 +38,7 @@
38
38
  <script id="location-bar-template" type="text/template">
39
39
  <form>
40
40
  <div class="input-append span12 location-bar-container">
41
- <input class="span11" id="appendedInputButton" type="text" value="<%= url %>">
41
+ <input class="span11" id="appendedInputButton" type="text" value="<%= _.escape(url) %>">
42
42
  <button class="btn" type="submit">Go!</button>
43
43
  <span class="ajax-loader"></span>
44
44
  </div>
@@ -63,46 +63,47 @@
63
63
  <% if ($.isArray(obj)) { %>
64
64
  <% _.each(obj, function(link, i) { %>
65
65
  <tr>
66
- <% tdStyle = i > 0 ? "border-top:none" : "" %>
67
- <td style="<%= tdStyle %>"><strong><%= i === 0 ? HAL.truncateIfUrl(rel) : '' %></strong></td>
68
- <td><%= link.title || '' %></td>
69
- <td><%= link.name ? 'name: ' + link.name : 'index: ' + i %></a></td>
66
+ <!-- pact_broker escaping -->
67
+ <td><strong><%= HAL.truncateIfUrl(rel) %></strong></td>
68
+ <td><%- link.title || '' %></td>
69
+ <td><%- link.name ? 'name: ' + link.name : 'index: ' + i %></a></td>
70
70
  <td>
71
71
  <% if (HAL.isUrl(rel)) { %>
72
- <a class="dox" href="<%= HAL.buildUrl(rel) %>"><i class="icon-book"></i></a>
72
+ <a class="dox" href="<%= HAL.normalizeUrl(HAL.buildUrl(rel)) %>"><i class="icon-book"></i></a>
73
73
  <% } %>
74
74
  </td>
75
75
  <td>
76
76
  <% if (link.templated === true) { %>
77
- <a class="query btn btn-success" href="<%= link.href %>" title="Query URI template"><i class="icon-question-sign"></i></a>
77
+ <a class="query btn btn-success" href="<%= HAL.normalizeUrl(link.href) %>" title="Query URI template"><i class="icon-question-sign"></i></a>
78
78
  <% } else { %>
79
- <a class="follow btn btn-success" href="<%= link.href %>" title="Follow link"><i class="icon-arrow-right"></i></a>
79
+ <a class="follow btn btn-success" href="<%= HAL.normalizeUrl(link.href) %>" title="Follow link"><i class="icon-arrow-right"></i></a>
80
80
  <% } %>
81
81
  </td>
82
82
  <td>
83
- <a class="non-get btn btn-warning" href="<%= link.href %>" title="Perform non-GET request">!</a>
83
+ <a class="non-get btn btn-warning" href="<%= HAL.normalizeUrl(link.href) %>" title="Perform non-GET request">!</a>
84
84
  </td>
85
85
  </tr>
86
86
  <% }); %>
87
87
  <% } else { %>
88
88
  <tr>
89
89
  <td><strong><%= HAL.truncateIfUrl(rel) %></strong></td>
90
- <td><%= obj.title || '' %></td>
91
- <td><%= obj.name || '' %></td>
90
+ <!-- pact_broker escaping -->
91
+ <td><%- obj.title || '' %></td>
92
+ <td><%- obj.name || '' %></td>
92
93
  <td>
93
94
  <% if (HAL.isUrl(rel)) { %>
94
- <a class="dox" href="<%= HAL.buildUrl(rel) %>"><i class="icon-book"></i></a>
95
+ <a class="dox" href="<%= HAL.normalizeUrl(HAL.buildUrl(rel)) %>"><i class="icon-book"></i></a>
95
96
  <% } %>
96
97
  </td>
97
98
  <td>
98
99
  <% if (obj.templated === true) { %>
99
- <a class="query btn btn-success" href="<%= obj.href %>" title="Query URI template"><i class="icon-question-sign"></i></a>
100
+ <a class="query btn btn-success" href="<%= HAL.normalizeUrl(obj.href) %>" title="Query URI template"><i class="icon-question-sign"></i></a>
100
101
  <% } else { %>
101
- <a class="follow btn btn-success" href="<%= obj.href %>" title="Follow link"><i class="icon-arrow-right"></i></a>
102
+ <a class="follow btn btn-success" href="<%= HAL.normalizeUrl(obj.href) %>" title="Follow link"><i class="icon-arrow-right"></i></a>
102
103
  <% } %>
103
104
  </td>
104
105
  <td>
105
- <a class="non-get btn btn-warning" href="<%= obj.href %>" title="Perform non-GET request">!</a>
106
+ <a class="non-get btn btn-warning" href="<%= HAL.normalizeUrl(obj.href) %>" title="Perform non-GET request">!</a>
106
107
  </td>
107
108
  </tr>
108
109
  <% } %>
@@ -113,7 +114,7 @@
113
114
 
114
115
  <script id="properties-template" type="text/template">
115
116
  <h2>Properties</h2>
116
- <pre><%= _.escape(JSON.stringify(properties, null, HAL.jsonIndent)) %></pre>
117
+ <pre><%= properties %></pre>
117
118
  </script>
118
119
 
119
120
  <script id="request-headers-template" type="text/template">
@@ -125,7 +126,16 @@
125
126
  <h2>Response Headers</h2>
126
127
  <pre><%= status.code %> <%= status.text %>
127
128
 
128
- <%= _.escape(headers) %></pre>
129
+ <% _.each(headers, function(value, name) {
130
+ %><%= _.escape(name) %>: <%
131
+ if(HAL.isFollowableHeader(name)) {
132
+ %><a href="<%= HAL.normalizeUrl(value) %>" class="follow"><%
133
+ }
134
+ %><%= _.escape(value)
135
+ %><% if(HAL.isFollowableHeader(name)) {
136
+ %></a><%
137
+ } %>
138
+ <% }) %></pre>
129
139
  </script>
130
140
 
131
141
  <script id="response-body-template" type="text/template">
@@ -142,7 +152,7 @@
142
152
  <form id="query" action="<%= href %>">
143
153
  <div class="modal-body">
144
154
  <p>URI Template:</p>
145
- <pre><%= href %></pre>
155
+ <pre><%- href %></pre>
146
156
  <p>Input (JSON):</p>
147
157
  <textarea><%= input %></textarea>
148
158
  <p>Expanded URI:</p>
@@ -193,9 +203,10 @@ Content-Type: application/json
193
203
 
194
204
  <script id="embedded-resource-template" type="text/template">
195
205
  <div class="accordion-heading">
206
+ <!-- pact_broker -->
196
207
  <a class="accordion-toggle" href="#"><%= resource.identifier %><% if (resource.name || resource.title) { %>: <span class="embedded-resource-title"><%- resource.name || resource.title %></span><% } %>
197
208
  <% if (HAL.isUrl(resource.embed_rel)) { %>
198
- <span class="dox pull-right" data-href="<%= HAL.buildUrl(resource.embed_rel) %>">
209
+ <span class="dox pull-right" data-href="<%= HAL.normalizeUrl(HAL.buildUrl(resource.embed_rel)) %>">
199
210
  <i class="icon-book"></i>
200
211
  </span>
201
212
  <% } %>
@@ -203,11 +214,11 @@ Content-Type: application/json
203
214
  </div>
204
215
  </script>
205
216
 
206
-
207
217
  <script src="vendor/js/jquery-1.10.2.min.js"></script>
208
218
  <script src="vendor/js/underscore.js"></script>
209
219
  <script src="vendor/js/backbone.js"></script>
210
220
  <script src="vendor/js/uritemplates.js"></script>
221
+ <script src="vendor/js/URI.min.js"></script>
211
222
  <script src="vendor/js/bootstrap.js"></script>
212
223
 
213
224
  <script src="js/hal.js"></script>
@@ -240,10 +251,13 @@ Content-Type: application/json
240
251
  <script src="js/hal/views/documentation.js"></script>
241
252
 
242
253
  <script>
254
+ var baseUrl = window.location.href.split('/hal-browser/')[0]; //pact_broker
243
255
  var browser = new HAL.Browser({
244
256
  container: $('#browser'),
245
- entryPoint: '/'
257
+ entryPoint: baseUrl //pact_broker
246
258
  });
247
259
  Backbone.history.start();
260
+
261
+ $('#pactBrokerHomeLink').attr('href', baseUrl); //pact_broker
248
262
  </script>
249
263
  </body>