pact_broker 2.58.0 → 2.59.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release_gem.yml +45 -0
  3. data/.travis.yml +5 -3
  4. data/CHANGELOG.md +37 -0
  5. data/DEVELOPER_SETUP.md +46 -16
  6. data/Dockerfile +23 -2
  7. data/Gemfile +29 -2
  8. data/config.ru +32 -12
  9. data/config/database.yml +7 -0
  10. data/docker-compose-dev-postgres.yml +35 -0
  11. data/docker-compose-test.yml +100 -0
  12. data/lib/pact_broker/api/decorators/decorator_context.rb +1 -1
  13. data/lib/pact_broker/api/decorators/version_decorator.rb +2 -0
  14. data/lib/pact_broker/api/pact_broker_urls.rb +4 -4
  15. data/lib/pact_broker/api/paths.rb +15 -0
  16. data/lib/pact_broker/api/renderers/html_pact_renderer.rb +26 -8
  17. data/lib/pact_broker/api/resources/all_webhooks.rb +12 -3
  18. data/lib/pact_broker/api/resources/badge.rb +4 -0
  19. data/lib/pact_broker/api/resources/base_resource.rb +2 -174
  20. data/lib/pact_broker/api/resources/can_i_deploy.rb +8 -0
  21. data/lib/pact_broker/api/resources/dashboard.rb +4 -0
  22. data/lib/pact_broker/api/resources/default_base_resource.rb +211 -0
  23. data/lib/pact_broker/api/resources/error_handler.rb +3 -5
  24. data/lib/pact_broker/api/resources/group.rb +7 -11
  25. data/lib/pact_broker/api/resources/index.rb +4 -0
  26. data/lib/pact_broker/api/resources/integration.rb +12 -0
  27. data/lib/pact_broker/api/resources/integrations.rb +9 -1
  28. data/lib/pact_broker/api/resources/label.rb +16 -6
  29. data/lib/pact_broker/api/resources/latest_pact.rb +8 -0
  30. data/lib/pact_broker/api/resources/latest_pacts.rb +9 -4
  31. data/lib/pact_broker/api/resources/latest_verifications_for_consumer_version.rb +16 -2
  32. data/lib/pact_broker/api/resources/matrix.rb +2 -2
  33. data/lib/pact_broker/api/resources/matrix_for_consumer_and_provider.rb +1 -1
  34. data/lib/pact_broker/api/resources/pact.rb +8 -0
  35. data/lib/pact_broker/api/resources/pact_content_diff.rb +1 -2
  36. data/lib/pact_broker/api/resources/pact_triggered_webhooks.rb +1 -7
  37. data/lib/pact_broker/api/resources/pact_versions.rb +1 -3
  38. data/lib/pact_broker/api/resources/pact_webhooks.rb +2 -5
  39. data/lib/pact_broker/api/resources/pact_webhooks_status.rb +1 -17
  40. data/lib/pact_broker/api/resources/pacticipant.rb +11 -14
  41. data/lib/pact_broker/api/resources/pacticipants.rb +15 -1
  42. data/lib/pact_broker/api/resources/pacticipants_for_label.rb +1 -1
  43. data/lib/pact_broker/api/resources/previous_distinct_pact_version.rb +8 -1
  44. data/lib/pact_broker/api/resources/provider_pacts.rb +9 -1
  45. data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +1 -1
  46. data/lib/pact_broker/api/resources/tag.rb +5 -1
  47. data/lib/pact_broker/api/resources/tagged_pact_versions.rb +1 -2
  48. data/lib/pact_broker/api/resources/triggered_webhook_logs.rb +4 -0
  49. data/lib/pact_broker/api/resources/verification.rb +7 -3
  50. data/lib/pact_broker/api/resources/verification_triggered_webhooks.rb +5 -1
  51. data/lib/pact_broker/api/resources/verifications.rb +7 -3
  52. data/lib/pact_broker/api/resources/version.rb +4 -1
  53. data/lib/pact_broker/api/resources/versions.rb +1 -3
  54. data/lib/pact_broker/api/resources/webhook.rb +6 -2
  55. data/lib/pact_broker/api/resources/webhook_execution.rb +4 -0
  56. data/lib/pact_broker/api/resources/webhooks.rb +3 -18
  57. data/lib/pact_broker/app.rb +1 -0
  58. data/lib/pact_broker/badges/service.rb +3 -2
  59. data/lib/pact_broker/configuration.rb +21 -2
  60. data/lib/pact_broker/db/clean.rb +0 -6
  61. data/lib/pact_broker/doc/views/layouts/main.haml +1 -1
  62. data/lib/pact_broker/domain/pacticipant.rb +7 -2
  63. data/lib/pact_broker/domain/version.rb +3 -0
  64. data/lib/pact_broker/groups/service.rb +1 -1
  65. data/lib/pact_broker/index/service.rb +9 -43
  66. data/lib/pact_broker/matrix/deployment_status_summary.rb +1 -1
  67. data/lib/pact_broker/pacticipants/repository.rb +2 -2
  68. data/lib/pact_broker/pacts/content.rb +2 -1
  69. data/lib/pact_broker/pacts/latest_pact_publication_id_for_consumer_version.rb +2 -5
  70. data/lib/pact_broker/pacts/pact_publication.rb +11 -9
  71. data/lib/pact_broker/pacts/pact_version.rb +3 -4
  72. data/lib/pact_broker/pacts/repository.rb +53 -39
  73. data/lib/pact_broker/pacts/verifiable_pact.rb +8 -0
  74. data/lib/pact_broker/policies.rb +53 -0
  75. data/lib/pact_broker/repositories/helpers.rb +3 -20
  76. data/lib/pact_broker/test/test_data_builder.rb +4 -4
  77. data/lib/pact_broker/ui/controllers/clusters.rb +1 -1
  78. data/lib/pact_broker/ui/controllers/groups.rb +2 -2
  79. data/lib/pact_broker/ui/controllers/index.rb +1 -3
  80. data/lib/pact_broker/ui/controllers/matrix.rb +2 -2
  81. data/lib/pact_broker/ui/views/groups/show.html.erb +3 -3
  82. data/lib/pact_broker/ui/views/index/show-with-tags.haml +10 -10
  83. data/lib/pact_broker/ui/views/index/show.haml +6 -6
  84. data/lib/pact_broker/ui/views/layouts/main.haml +1 -1
  85. data/lib/pact_broker/ui/views/matrix/show.haml +4 -5
  86. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +3 -5
  87. data/lib/pact_broker/version.rb +1 -1
  88. data/lib/pact_broker/versions/repository.rb +2 -4
  89. data/lib/rack/pact_broker/request_target.rb +6 -1
  90. data/lib/sequel/plugins/insert_ignore.rb +69 -0
  91. data/lib/sequel/plugins/upsert.rb +103 -0
  92. data/pact_broker.gemspec +22 -41
  93. data/public/javascripts/pact.js +6 -2
  94. data/script/docker/db-execute-sql-file.sh +2 -0
  95. data/script/issues/consumer-version-selectors-docs/issue-text.txt +11 -0
  96. data/script/issues/consumer-version-selectors-docs/issues.txt +6 -0
  97. data/script/issues/consumer-version-selectors-docs/raise-issue-in-client-repos.sh +10 -0
  98. data/script/prod/redact-data.sql +1 -0
  99. data/script/release-via-github-action.sh +7 -0
  100. data/script/seed.rb +5 -7
  101. data/script/trigger-release.sh +30 -0
  102. data/spec/features/get_versions_spec.rb +1 -6
  103. data/spec/lib/pact_broker/api/decorators/version_decorator_spec.rb +4 -0
  104. data/spec/lib/pact_broker/api/pact_broker_urls_spec.rb +2 -2
  105. data/spec/lib/pact_broker/api/renderers/html_pact_renderer_spec.rb +24 -6
  106. data/spec/lib/pact_broker/api/resources/all_webhooks_spec.rb +1 -1
  107. data/spec/lib/pact_broker/api/resources/default_base_resource_spec.rb +158 -0
  108. data/spec/lib/pact_broker/api/resources/error_handler_spec.rb +18 -1
  109. data/spec/lib/pact_broker/api/resources/tag_spec.rb +2 -2
  110. data/spec/lib/pact_broker/api/resources/webhook_spec.rb +1 -1
  111. data/spec/lib/pact_broker/api/resources/webhooks_spec.rb +1 -1
  112. data/spec/lib/pact_broker/badges/service_spec.rb +6 -6
  113. data/spec/lib/pact_broker/db/clean_old_spec.rb +125 -0
  114. data/spec/lib/pact_broker/db/clean_spec.rb +45 -11
  115. data/spec/lib/pact_broker/index/service_spec.rb +2 -3
  116. data/spec/lib/pact_broker/pacts/content_spec.rb +8 -0
  117. data/spec/lib/pact_broker/pacts/repository_find_wip_pact_versions_for_provider_spec.rb +36 -0
  118. data/spec/lib/pact_broker/versions/repository_spec.rb +8 -0
  119. data/spec/lib/rack/pact_broker/request_target_spec.rb +7 -0
  120. data/spec/lib/sequel/plugins/insert_ignore_spec.rb +82 -0
  121. data/spec/lib/sequel/plugins/upsert_spec.rb +125 -0
  122. data/spec/spec_helper.rb +1 -0
  123. data/tasks/audit.rake +6 -2
  124. data/tasks/development.rake +2 -2
  125. metadata +46 -284
  126. data/spec/lib/pact_broker/api/resources/base_resource_spec.rb +0 -78
@@ -0,0 +1,103 @@
1
+
2
+ module Sequel
3
+ module Plugins
4
+ module Upsert
5
+ def self.configure(model, opts=OPTS)
6
+ model.instance_exec do
7
+ @upsert_plugin_identifying_columns = opts.fetch(:identifying_columns)
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ attr_reader :upsert_plugin_identifying_columns
13
+ end
14
+
15
+ module InstanceMethods
16
+ # dirty stateful attribute because we can't pass any opts through to the _insert_dataset method
17
+ attr_reader :upsert_plugin_upserting
18
+
19
+ def upsert(opts = {})
20
+ @upsert_plugin_upserting = true
21
+ if postgres? || mysql?
22
+ save(opts)
23
+ else
24
+ manual_upsert(opts)
25
+ end
26
+ load_values_from_previously_inserted_object unless id
27
+ self
28
+ rescue Sequel::NoExistingObject
29
+ load_values_from_previously_inserted_object
30
+ ensure
31
+ @upsert_plugin_upserting = false
32
+ end
33
+
34
+ private
35
+
36
+ def load_values_from_previously_inserted_object
37
+ set_primary_key_columns_from_previously_inserted_object
38
+ refresh
39
+ end
40
+
41
+ def set_primary_key_columns_from_previously_inserted_object
42
+ if !primary_key_columns_are_same_as_identifying_columns
43
+ existing_record = find_previously_inserted_object
44
+ upsert_primary_key_columns.each do | column |
45
+ self.send("#{column}=".to_sym, existing_record[column])
46
+ end
47
+ end
48
+ end
49
+
50
+ def find_previously_inserted_object
51
+ query = self.class.upsert_plugin_identifying_columns.each_with_object({}) do | column_name, q |
52
+ q[column_name] = values[column_name]
53
+ end
54
+ model.where(query).single_record
55
+ end
56
+
57
+ def upsert_primary_key_columns
58
+ @upsert_primary_key_columns ||= [*primary_key].sort
59
+ end
60
+
61
+ def primary_key_columns_are_same_as_identifying_columns
62
+ upsert_primary_key_columns == self.class.upsert_plugin_identifying_columns.sort
63
+ end
64
+
65
+ def manual_upsert(opts)
66
+ # Can use slice when we drop support for Ruby 2.4
67
+ query = values.select{ |k, _| self.class.upsert_plugin_identifying_columns.include?(k) }
68
+ existing_record = model.where(query).single_record
69
+ if existing_record
70
+ existing_record.update(values)
71
+ else
72
+ save(opts)
73
+ end
74
+ end
75
+
76
+ # naughty override of Sequel private method to
77
+ # avoid having to rewrite the whole save method logic
78
+ def _insert_dataset
79
+ if upsert_plugin_upserting
80
+ if postgres?
81
+ super.insert_conflict(update: values, target: self.class.upsert_plugin_identifying_columns)
82
+ elsif mysql?
83
+ columns_to_update = values.keys - self.class.upsert_plugin_identifying_columns
84
+ super.on_duplicate_key_update(*columns_to_update)
85
+ else
86
+ super
87
+ end
88
+ else
89
+ super
90
+ end
91
+ end
92
+
93
+ def mysql?
94
+ model.db.adapter_scheme.to_s =~ /mysql/
95
+ end
96
+
97
+ def postgres?
98
+ model.db.adapter_scheme.to_s == "postgres"
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -3,29 +3,9 @@ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'pact_broker/version'
5
5
 
6
- def gem_files
7
- if Dir.exist?(".git")
8
- `git ls-files`.split($/)
9
- else
10
- root_path = File.dirname(__FILE__)
11
- all_files = Dir.chdir(root_path) { Dir.glob("**/{*,.*}") }
12
- all_files.reject! { |file| [".", ".."].include?(File.basename(file)) || File.directory?(file)}
13
- gitignore_path = File.join(root_path, ".gitignore")
14
- gitignore = File.readlines(gitignore_path)
15
- gitignore.map! { |line| line.chomp.strip }
16
- gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
17
-
18
- all_files.reject do |file|
19
- gitignore.any? do |ignore|
20
- file.start_with?(ignore) ||
21
- File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
22
- File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
23
- end
24
- end
25
- end
26
- end
27
6
 
28
7
  Gem::Specification.new do |gem|
8
+
29
9
  gem.name = "pact_broker"
30
10
  gem.version = PactBroker::VERSION
31
11
  gem.authors = ["Bethany Skurrie", "Sergei Matheson", "Warner Godfrey"]
@@ -36,7 +16,27 @@ Gem::Specification.new do |gem|
36
16
 
37
17
  gem.required_ruby_version = '>= 2.2.0'
38
18
 
39
- gem.files = gem_files
19
+ gem.files = begin
20
+ if Dir.exist?(".git")
21
+ `git ls-files`.split($/)
22
+ else
23
+ root_path = File.dirname(__FILE__)
24
+ all_files = Dir.chdir(root_path) { Dir.glob("**/{*,.*}") }
25
+ all_files.reject! { |file| [".", ".."].include?(File.basename(file)) || File.directory?(file)}
26
+ gitignore_path = File.join(root_path, ".gitignore")
27
+ gitignore = File.readlines(gitignore_path)
28
+ gitignore.map! { |line| line.chomp.strip }
29
+ gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
30
+
31
+ all_files.reject do |file|
32
+ gitignore.any? do |ignore|
33
+ file.start_with?(ignore) ||
34
+ File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
35
+ File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
36
+ end
37
+ end
38
+ end
39
+ end
40
40
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
41
41
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
42
42
  gem.require_paths = ["lib"]
@@ -64,23 +64,4 @@ Gem::Specification.new do |gem|
64
64
  gem.add_runtime_dependency 'table_print', '~> 1.5'
65
65
  gem.add_runtime_dependency 'semantic_logger', '~> 4.3'
66
66
  gem.add_runtime_dependency 'sanitize', '>= 5.2.1', '~> 5.2'
67
-
68
- gem.add_development_dependency 'pact', '~>1.14'
69
- gem.add_development_dependency 'rspec-pact-matchers', '~>0.1'
70
- gem.add_development_dependency 'bundler-audit', '~>0.4'
71
- gem.add_development_dependency 'sqlite3', '~>1.3'
72
- gem.add_development_dependency 'pry-byebug'
73
- gem.add_development_dependency 'rake', '~>12.3.3'
74
- gem.add_development_dependency 'fakefs', '~>0.4'
75
- gem.add_development_dependency 'webmock', '~>2.3'
76
- gem.add_development_dependency 'rspec', '~>3.0'
77
- gem.add_development_dependency 'rspec-its', '~>1.2'
78
- gem.add_development_dependency 'database_cleaner', '~>1.8', '>= 1.8.1'
79
- gem.add_development_dependency 'pg', '~>1.2'
80
- gem.add_development_dependency 'conventional-changelog', '~>1.3'
81
- gem.add_development_dependency 'bump', '~> 0.5'
82
- gem.add_development_dependency 'timecop', '~> 0.9'
83
- gem.add_development_dependency 'sequel-annotate', '~>1.3'
84
- gem.add_development_dependency 'faraday', '~>0.15'
85
- gem.add_development_dependency 'docker-api', '~>1.34'
86
67
  end
@@ -39,10 +39,14 @@ $(document).ready(function() {
39
39
  });
40
40
  });
41
41
 
42
+ function h(string) {
43
+ return jQuery('<div/>').text(string).html();
44
+ }
45
+
42
46
  function createDeletionConfirmationText(data) {
43
47
  return `Do you wish to delete the pact for version ${
44
- data.consumerVersionNumber
45
- } of ${data.consumerName}?`;
48
+ h(data.consumerVersionNumber)
49
+ } of ${h(data.consumerName)}?`;
46
50
  }
47
51
 
48
52
  function confirmDeleteResource(
@@ -0,0 +1,2 @@
1
+ docker exec -it pact-broker-postgres psql -U postgres -f /data/${1}
2
+
@@ -0,0 +1,11 @@
1
+ Please add code examples for consumer version selectors docs in pact.docs.io
2
+
3
+ As part of the process of making the Pact docs more user friendly, we'd like to start writing feature documentation once, and providing code examples for each of the languages, rather than everyone having to write the same docs over and over again in each language.
4
+
5
+ The documentation for the consumer version selectors can be our first opportunity to give this approach a try. I have written the behavioural docs, but we need code examples from each of the languages. Can one of the maintainers of this repository (or any other Pact user of this language!) please add (via direct edit/PR as your permissions allow) code samples for the examples found here https://docs.pact.io/pact_broker/advanced_topics/consumer_version_selectors#examples If you press the EDIT button, it will automatically fork and open a page to edit.
6
+
7
+ To add a new language, just add a comment with the name of the language (eg. <!-- Java -->) and an example surrounded by "```".
8
+
9
+ If you would like to link to these docs in your own READMEs, please use the short link `https://docs.pact.io/consumer_version_selectors` (rather than the deep link into the broker section).
10
+
11
+ Thanks all!
@@ -0,0 +1,6 @@
1
+ https://github.com/DiUS/pact-jvm/issues/1149
2
+ https://github.com/pact-foundation/pact-net/issues/251
3
+ https://github.com/pact-foundation/pact-python/issues/149
4
+ https://github.com/pact-foundation/pact-go/issues/136
5
+ https://github.com/pact-foundation/pact-js/issues/467
6
+ https://github.com/pact-foundation/pact-ruby/issues/217
@@ -0,0 +1,10 @@
1
+ #!/bin/sh
2
+
3
+ repos="pact-jvm pact-net pact-python pact-go pact-js pact"
4
+
5
+ issue_text_file=$(realpath script/dev/consumer-version-selectors-docs/issue-text.txt)
6
+
7
+ for repo in $repos; do
8
+ cd "../${repo}"
9
+ hub issue create --file "${issue_text_file}" --labels "documentation,help wanted,good first issue"
10
+ done
@@ -1,4 +1,5 @@
1
1
  UPDATE pacticipants SET name = 'pacticipant-' || id;
2
+ UPDATE versions SET number = 'version-' || id;
2
3
  UPDATE pact_versions SET content = '{}';
3
4
  UPDATE verifications SET test_results = null;
4
5
  DELETE FROM webhook_executions;
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+ set +e
3
+
4
+ git tag -d release
5
+ git push --delete origin release
6
+ git tag -a release -m "chore: releasing"
7
+ git push origin release
@@ -58,13 +58,11 @@ TestDataBuilder.new
58
58
  url: "http://localhost:9292/verification-published-webhook",
59
59
  body: webhook_body.to_json)
60
60
  .set_now(Date.today - 101)
61
- .tap{ | it |
62
- 2.times do | i |
63
- it.create_pact_with_verification("Foo", i.to_s, "Bar", i.to_s)
64
- .create_pact_with_verification("Bar", i.to_s, "Foo", i.to_s)
65
- .add_day
66
- end
67
- }.create_pact_with_hierarchy("Foo", "100", "Bar")
61
+ .create_pact_with_hierarchy("Foo/Foo", "100", "Bar/Bar")
62
+ .create_pact_with_hierarchy("Foo", "1", "Bar")
63
+ .create_pact_with_hierarchy("<script>alert('hello')</script>", "<script>alert(\"version\")</script>", "Bar/Bar")
64
+ .create_consumer_version_tag("prod")
65
+ .create_verification(provider_version: "1", tag_names: "prod")
68
66
 
69
67
 
70
68
  # .create_certificate(path: 'spec/fixtures/certificates/self-signed.badssl.com.pem')
@@ -0,0 +1,30 @@
1
+ #!/bin/sh
2
+
3
+ # Script to trigger release of gem via the pact-foundation/release-gem action
4
+ # Requires a Github API token with repo scope stored in the
5
+ # environment variable GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES
6
+
7
+ : "${GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES:?Please set environment variable GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES}"
8
+
9
+ if [ -n "$1" ]; then
10
+ increment="\"${1}\""
11
+ else
12
+ increment="null"
13
+ fi
14
+
15
+ repository_slug=$(git remote get-url origin | cut -d':' -f2 | sed 's/\.git//')
16
+
17
+ output=$(curl -v https://api.github.com/repos/${repository_slug}/dispatches \
18
+ -H 'Accept: application/vnd.github.everest-preview+json' \
19
+ -H "Authorization: Bearer $GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES" \
20
+ -d "{\"event_type\": \"release-triggered\", \"client_payload\": {\"increment\": ${increment}}}" 2>&1)
21
+
22
+ if ! echo "${output}" | grep "HTTP\/1.1 204" > /dev/null; then
23
+ echo "$output" | sed "s/${GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES}/********/g"
24
+ echo "Failed to trigger release"
25
+ exit 1
26
+ else
27
+ echo "Release workflow triggered"
28
+ fi
29
+
30
+ echo "See https://github.com/${repository_slug}/actions?query=workflow%3A%22Release+gem%22"
@@ -1,14 +1,12 @@
1
1
  require 'spec/support/test_data_builder'
2
2
 
3
3
  describe "Get versions" do
4
-
5
4
  let(:path) { "/pacticipants/Consumer/versions" }
6
5
  let(:last_response_body) { JSON.parse(subject.body, symbolize_names: true) }
7
6
 
8
- subject { get path; last_response }
7
+ subject { get(path) }
9
8
 
10
9
  context "when the pacticipant exists" do
11
-
12
10
  before do
13
11
  TestDataBuilder.new
14
12
  .create_consumer("Consumer")
@@ -23,14 +21,11 @@ describe "Get versions" do
23
21
  it "returns a list of links to the versions" do
24
22
  expect(last_response_body[:_links][:"versions"].size).to eq 2
25
23
  end
26
-
27
24
  end
28
25
 
29
26
  context "when the pacticipant does not exist" do
30
-
31
27
  it "returns a 404 response" do
32
28
  expect(subject).to be_a_404_response
33
29
  end
34
-
35
30
  end
36
31
  end
@@ -51,6 +51,10 @@ module PactBroker
51
51
  expect(subject[:_embedded][:tags].first[:name]).to eq "prod"
52
52
  end
53
53
 
54
+ it "includes the timestamps" do
55
+ expect(subject[:createdAt]).to_not be nil
56
+ end
57
+
54
58
  it "includes a list of sorted pacts" do
55
59
  expect(subject[:_links][:'pb:pact-versions']).to be_instance_of(Array)
56
60
  expect(subject[:_links][:'pb:pact-versions'].first[:href]).to include ("1.2.3")
@@ -30,7 +30,7 @@ module PactBroker
30
30
  let(:version) do
31
31
  double('version',
32
32
  pacticipant: consumer,
33
- number: "2")
33
+ number: "2/4")
34
34
  end
35
35
 
36
36
  matcher :match_route_in_api do |api|
@@ -136,7 +136,7 @@ module PactBroker
136
136
  describe "matrix_for_pacticipant_version_url" do
137
137
  subject { PactBrokerUrls.matrix_for_pacticipant_version_url(version, base_url) }
138
138
 
139
- it { is_expected.to eq "http://example.org/matrix?q[][pacticipant]=Foo%2FFoo&q[][version]=2&latestby=cvpv" }
139
+ it { is_expected.to eq "http://example.org/matrix?q[][pacticipant]=Foo%2FFoo&q[][version]=2%2F4&latestby=cvpv" }
140
140
  end
141
141
 
142
142
  describe "matrix_badge_url" do
@@ -23,22 +23,26 @@ module PactBroker
23
23
  Timecop.return
24
24
  end
25
25
 
26
- let(:consumer) { double('consumer', name: 'Consumer')}
27
- let(:provider) { double('provider', name: 'Provider')}
26
+ let(:consumer_name) { 'Consumer' }
27
+ let(:provider_name) { 'Provider' }
28
+ let(:consumer_version_number) { '1.2.3' }
29
+ let(:consumer) { double('consumer', name: consumer_name) }
30
+ let(:provider) { double('provider', name: provider_name) }
28
31
  let(:consumer_version) { double('consumer version') }
29
32
  let(:created_at) { DateTime.new(2014, 02, 27) }
30
33
  let(:json_content) { load_fixture('renderer_pact.json') }
31
34
  let(:pact) do
32
35
  double('pact',
33
36
  json_content: json_content,
34
- consumer_version_number: '1.2.3',
37
+ consumer_version_number: consumer_version_number,
35
38
  consumer: consumer,
36
39
  provider: provider,
37
- consumer_version_tag_names: ['prod', 'master'],
40
+ consumer_version_tag_names: consumer_version_tag_names,
38
41
  created_at: created_at,
39
42
  consumer_version: consumer_version
40
43
  )
41
44
  end
45
+ let(:consumer_version_tag_names) { ['prod', 'master'] }
42
46
  let(:pact_url) { '/pact/url' }
43
47
  let(:matrix_url) { '/matrix/url' }
44
48
  let(:options) do
@@ -49,7 +53,7 @@ module PactBroker
49
53
  end
50
54
  let(:logger) { double('logger').as_null_object }
51
55
 
52
- subject { HtmlPactRenderer.call pact, options }
56
+ subject { HtmlPactRenderer.call(pact, options) }
53
57
 
54
58
  describe ".call" do
55
59
  it "renders the pact as HTML" do
@@ -69,7 +73,7 @@ module PactBroker
69
73
  end
70
74
 
71
75
  it "renders the badge image" do
72
- expect(subject).to include "<img src='http://badge'/>"
76
+ expect(subject).to include "<img src=\"http://badge\"/>"
73
77
  end
74
78
 
75
79
  it "renders a text area with the badge markdown" do
@@ -81,6 +85,20 @@ module PactBroker
81
85
  expect(subject).to include matrix_url
82
86
  end
83
87
 
88
+ context "with dodgey data" do
89
+ let(:consumer_name) { '<script>alert("consumer");</script>' }
90
+ let(:provider_name) { '<script>alert("provider");</script>' }
91
+ let(:consumer_version_number) { '<script>alert("version");</script>' }
92
+ let(:consumer_version_tag_names) { ['<script>alert("tag");</script>'] }
93
+
94
+ it "does not contain the literal <script> anywhere except the badge markdown" do
95
+ expect(subject).to_not include consumer_version_number
96
+ expect(subject.scan(consumer_name).count).to eq 1
97
+ expect(subject.scan(provider_name).count).to eq 1
98
+ expect(subject).to include '[![<script>alert("consumer");</script>/<script>alert("provider");</script> Pact Status](http://badge)]'
99
+ end
100
+ end
101
+
84
102
  context "when enable_public_badge_access is false" do
85
103
  before do
86
104
  PactBroker.configuration.enable_public_badge_access = false
@@ -106,7 +106,7 @@ module PactBroker::Api
106
106
 
107
107
  it "generates the JSON response body" do
108
108
  expect(Decorators::WebhookDecorator).to receive(:new).with(saved_webhook).and_return(webhook_decorator)
109
- expect(webhook_decorator).to receive(:to_json).with(user_options: { base_url: 'http://example.org' })
109
+ expect(webhook_decorator).to receive(:to_json).with(user_options: hash_including({ base_url: 'http://example.org' }))
110
110
  subject
111
111
  end
112
112