pact 1.14.0 → 1.20.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1fb2ea12b63cd90b9451173dd6deb6a10146d426
4
- data.tar.gz: 2ba870980eb5403ab32c405138315b6f471b189e
3
+ metadata.gz: 4ff1d60084d4c20892a663b68af77d3c05e419a6
4
+ data.tar.gz: 78f85722706fc0c6328a16172b4e9a31adb2c4b7
5
5
  SHA512:
6
- metadata.gz: 517699fa66be479723e0f703dc00e5453482d18d5463b59176b8fd09138211c648dfa8f654223690f77c1cbe4cafad7ae98165c97b3561e69248a7bb4ad204f4
7
- data.tar.gz: 44ef94d0fa65a5ee0b003ec3e7f8c6915da6c8ecadce6c690fa9c5a50e507f313f39b802839e3671cbfb5aea54ea9c4735d86a5ee1f854f37533333d37851985
6
+ metadata.gz: 5873fe24cd3eb193068ae0a155a4ee0dfbc15ee4f2b53e4b7f1f39549b58d2a3e5563a11f7915caaa82a33562de88a35519b52223dfef6e3b103caa4c85213ea
7
+ data.tar.gz: d12f70c741c1367936ebd3a6d004b005390a2892e2171368aa0242186fd73b3fd46c515d488739e18d566c3c741f3ed561ed294c25df1db625a2c247e26edee4
data/CHANGELOG.md CHANGED
@@ -1,6 +1,73 @@
1
- Do this to generate your change history
1
+ <a name="v1.20.0"></a>
2
+ ### v1.20.0 (2017-12-10)
2
3
 
3
- git log --pretty=format:' * %h - %s (%an, %ad)'
4
+
5
+ #### Bug Fixes
6
+
7
+ * send verification publishing message to stderr when json output ([568f511](/../../commit/568f511))
8
+
9
+
10
+ <a name="v1.19.2"></a>
11
+ ### v1.19.2 (2017-11-16)
12
+
13
+
14
+ #### Features
15
+
16
+ * **publish test results**
17
+ * rename example to test in JSON ([cd2b79e](/../../commit/cd2b79e))
18
+ * remove ansi colours from error messages ([4416d04](/../../commit/4416d04))
19
+ * only publish for rspec 3 ([31192d0](/../../commit/31192d0))
20
+ * only publish verification results when all interactions have been run ([0c56752](/../../commit/0c56752))
21
+ * enable test results to be published to the pact broker in the verification results ([e0dad27](/../../commit/e0dad27))
22
+
23
+
24
+ #### Bug Fixes
25
+
26
+ * **verifications**
27
+ * tag provider version, not consumer version ([b347588](/../../commit/b347588))
28
+
29
+
30
+ <a name="v1.19.1"></a>
31
+ ### v1.19.1 (2017-10-31)
32
+
33
+
34
+ #### Bug Fixes
35
+
36
+ * **verifications**
37
+ * do not print warning about missing pb:tag-version link when there are no tags configured ([ed9468a](/../../commit/ed9468a))
38
+
39
+
40
+ <a name="v1.19.0"></a>
41
+ ### v1.19.0 (2017-10-30)
42
+
43
+
44
+ #### Features
45
+
46
+ * **verifications**
47
+ * allow provider version tags to be specified ([bff4611](/../../commit/bff4611))
48
+
49
+
50
+ <a name="v1.18.0"></a>
51
+ ## 1.18.0 (2017-10-30)
52
+ * 7cde586 - feat: correct rack-test dependency for rails 5 support (Beth Skurrie, Mon Oct 30 10:09:07 2017 +1100)
53
+
54
+ <a name="v1.17.0"></a>
55
+ ## 1.17.0 (2017-10-27)
56
+
57
+ * 4ae8417 - feat: allow json formatter to be configured for pact verify (Beth Skurrie, Fri Oct 27 16:08:41 2017 +1100)
58
+
59
+ <a name="v1.16.1"></a>
60
+ ## 1.16.1 (2017-10-18)
61
+
62
+ * 7b1747b - fix: reify terms in headers when replaying request (Beth Skurrie, Wed Oct 18 09:01:26 2017 +1100)
63
+
64
+ ## 1.16.0 (25 September 2017)
65
+ * 70e67cf - feat: improve description of rspec header matching 'it' blocks and failure text (Beth Skurrie, Mon Sep 25 08:46:06 2017 +1000)
66
+ * 85d8e09 - fix: correctly display pact term when parent key is missing (Beth Skurrie, Mon Sep 25 08:43:02 2017 +1000)
67
+
68
+ ## 1.15.0 (11 August 2017)
69
+ * a950a16 - fix: Fix module declaration (Beth Skurrie, Fri Aug 11 11:47:46 2017 +1000)
70
+ * 14cd969 - feat(output): Remove ruby specific text from pact verification output. (Beth Skurrie, Tue Aug 8 17:12:50 2017 +1000)
4
71
 
5
72
  ## 1.14.0 (19 June 2017)
6
73
  * eb44499 - Updated pact-support version (Beth Skurrie, Mon Jun 19 09:51:13 2017 +1000)
@@ -27,8 +27,9 @@ module Pact
27
27
  def initialize_rspec
28
28
  # With RSpec3, if the pact_helper loads a library that adds its own formatter before we set one,
29
29
  # we will get a ProgressFormatter too, and get little dots sprinkled throughout our output.
30
+ # Load a NilFormatter here to prevent that.
30
31
  require 'pact/rspec'
31
- ::RSpec.configuration.add_formatter Pact::RSpec.formatter_class
32
+ ::RSpec.configuration.add_formatter Pact::RSpec.formatter_class.const_get('NilFormatter')
32
33
  end
33
34
 
34
35
  def setup_load_path
@@ -69,7 +70,8 @@ module Pact
69
70
  def pact_spec_options
70
71
  {
71
72
  full_backtrace: options[:backtrace],
72
- criteria: SpecCriteria.call(options)
73
+ criteria: SpecCriteria.call(options),
74
+ format: options[:format]
73
75
  }
74
76
  end
75
77
 
data/lib/pact/cli.rb CHANGED
@@ -16,6 +16,7 @@ module Pact
16
16
  default: Pact.configuration.interactions_replay_order
17
17
  method_option :description, aliases: "-d", desc: "Interaction description filter"
18
18
  method_option :provider_state, aliases: "-s", desc: "Provider state filter"
19
+ method_option :format, aliases: "-f", banner: "FORMATTER", desc: "RSpec formatter. Defaults to custom Pact formatter. [j]son may also be used."
19
20
 
20
21
  def verify
21
22
  require 'pact/cli/run_pact_verification'
@@ -5,8 +5,9 @@ module Pact
5
5
 
6
6
  attr_accessor :application_version
7
7
 
8
- def initialize application_version, publish_verification_results, &app_block
8
+ def initialize application_version, tags, publish_verification_results, &app_block
9
9
  @application_version = application_version
10
+ @tags = [*tags]
10
11
  @publish_verification_results = publish_verification_results
11
12
  @app_block = app_block
12
13
  end
@@ -18,6 +19,10 @@ module Pact
18
19
  def publish_verification_results?
19
20
  @publish_verification_results
20
21
  end
22
+
23
+ def tags
24
+ @tags
25
+ end
21
26
  end
22
27
  end
23
28
  end
@@ -13,7 +13,7 @@ module Pact
13
13
 
14
14
  extend Pact::DSL
15
15
 
16
- attr_accessor :name, :app_block, :application_version, :publish_verification_results
16
+ attr_accessor :name, :app_block, :application_version, :tags, :publish_verification_results
17
17
 
18
18
  CONFIG_RU_APP = lambda {
19
19
  unless File.exist? Pact.configuration.config_ru_path
@@ -25,6 +25,7 @@ module Pact
25
25
  def initialize name
26
26
  @name = name
27
27
  @publish_verification_results = false
28
+ @tags = []
28
29
  @app_block = CONFIG_RU_APP
29
30
  end
30
31
 
@@ -37,10 +38,14 @@ module Pact
37
38
  self.application_version = application_version
38
39
  end
39
40
 
41
+ def app_version_tags tags
42
+ self.tags = tags
43
+ end
44
+
40
45
  def publish_verification_results publish_verification_results
41
46
  self.publish_verification_results = publish_verification_results
42
47
  Pact::RSpec.with_rspec_2 do
43
- puts "WARNING: Publishing of verification results is currently not supported with rspec 2. If you would like this functionality, please feel free to submit a PR!"
48
+ Pact.configuration.error_stream.puts "WARN: Publishing of verification results is currently not supported with rspec 2. If you would like this functionality, please feel free to submit a PR!"
44
49
  end
45
50
  end
46
51
 
@@ -70,7 +75,7 @@ module Pact
70
75
  end
71
76
 
72
77
  def create_service_provider
73
- Pact.configuration.provider = ServiceProviderConfig.new(application_version, publish_verification_results, &@app_block)
78
+ Pact.configuration.provider = ServiceProviderConfig.new(application_version, tags, publish_verification_results, &@app_block)
74
79
  end
75
80
  end
76
81
  end
@@ -19,6 +19,20 @@ module Pact
19
19
  "Expected header \"#{header_name}\" to #{expected_desc(expected)}, but was #{actual_desc(actual)}"
20
20
  end
21
21
 
22
+ def expected_desc_for_it expected
23
+ case expected
24
+ when NilClass then "is nil"
25
+ when Regexp
26
+ "matches #{expected.inspect}"
27
+ when Pact::Term
28
+ "matches #{expected.matcher.inspect}"
29
+ when Pact::SomethingLike
30
+ "is an instance of #{Pact::Reification.from_term(expected).class}"
31
+ else
32
+ "equals #{expected.inspect}"
33
+ end
34
+ end
35
+
22
36
  private
23
37
 
24
38
  def colorize_if_enabled formatted_diff, color_enabled
@@ -35,15 +49,20 @@ module Pact
35
49
  def expected_desc expected
36
50
  case expected
37
51
  when NilClass then "be nil"
38
- else
52
+ when Regexp
39
53
  "match #{expected.inspect}"
54
+ when Pact::Term
55
+ "match #{expected.matcher.inspect}"
56
+ when Pact::SomethingLike
57
+ "be an instance of #{Pact::Reification.from_term(expected).class}"
58
+ else
59
+ "equal #{expected.inspect}"
40
60
  end
41
61
  end
42
62
 
43
63
  def actual_desc actual
44
64
  actual.nil? ? 'nil' : '"' + actual + '"'
45
65
  end
46
-
47
66
  end
48
67
  end
49
68
  end
@@ -8,6 +8,7 @@ require 'pact/rspec'
8
8
  require 'pact/provider/pact_source'
9
9
  require 'pact/provider/help/write'
10
10
  require 'pact/provider/verification_results/publish_all'
11
+ require 'pact/provider/rspec/pact_broker_formatter'
11
12
 
12
13
  require_relative 'rspec'
13
14
 
@@ -20,7 +21,6 @@ module Pact
20
21
 
21
22
  attr_reader :pact_urls
22
23
  attr_reader :options
23
- attr_reader :output
24
24
 
25
25
  def initialize pact_urls, options = {}
26
26
  @pact_urls = pact_urls
@@ -62,10 +62,20 @@ module Pact
62
62
  config.output_stream = Pact.configuration.output_stream
63
63
  end
64
64
 
65
- # Sometimes the formatter set in the cli.rb get set with an output of StringIO.. don't know why
66
- formatter_class = Pact::RSpec.formatter_class
67
- pact_formatter = ::RSpec.configuration.formatters.find {|f| f.class == formatter_class && f.output == ::RSpec.configuration.output_stream}
68
- ::RSpec.configuration.add_formatter formatter_class unless pact_formatter
65
+ Pact::RSpec.with_rspec_3 do
66
+ ::RSpec.configuration.add_formatter Pact::Provider::RSpec::PactBrokerFormatter, StringIO.new
67
+ end
68
+
69
+ if options[:format]
70
+ ::RSpec.configuration.add_formatter options[:format]
71
+ # Don't want to mess up the JSON parsing with messages to stdout, so send it to stderr
72
+ Pact.configuration.output_stream = Pact.configuration.error_stream
73
+ else
74
+ # Sometimes the formatter set in the cli.rb get set with an output of StringIO.. don't know why
75
+ formatter_class = Pact::RSpec.formatter_class
76
+ pact_formatter = ::RSpec.configuration.formatters.find {|f| f.class == formatter_class && f.output == ::RSpec.configuration.output_stream}
77
+ ::RSpec.configuration.add_formatter formatter_class unless pact_formatter
78
+ end
69
79
  ::RSpec.configuration.full_backtrace = @options[:full_backtrace]
70
80
 
71
81
  config.before(:suite) do
@@ -77,14 +87,12 @@ module Pact
77
87
  Pact.configuration.provider.app
78
88
  end
79
89
 
90
+ # For the Pact::Provider::RSpec::PactBrokerFormatter
91
+ Pact.provider_world.pact_sources = pact_sources
80
92
  jsons = pact_jsons
81
- sources = pact_sources
82
93
 
83
94
  config.after(:suite) do | suite |
84
95
  Pact::Provider::Help::Write.call(jsons)
85
- Pact::RSpec.with_rspec_3 do
86
- Pact::Provider::VerificationResults::PublishAll.call(sources, ::RSpec.configuration.reporter.failed_examples)
87
- end
88
96
  end
89
97
 
90
98
  end
@@ -35,12 +35,13 @@ module Pact
35
35
  request_headers = {}
36
36
  return request_headers if expected_request.headers.is_a?(Pact::NullExpectation)
37
37
  expected_request.headers.each do |key, value|
38
- request_headers[rack_request_header_for(key)] = value
38
+ request_headers[rack_request_header_for(key)] = Pact::Reification.from_term(value)
39
39
  end
40
40
  request_headers
41
41
  end
42
42
 
43
43
  private
44
+
44
45
  attr_reader :expected_request
45
46
 
46
47
  def reified_body
@@ -63,8 +64,7 @@ module Pact
63
64
  def with_http_prefix header
64
65
  NO_HTTP_PREFIX.include?(header) ? header : "HTTP_#{header}"
65
66
  end
66
-
67
67
  end
68
68
  end
69
69
  end
70
- end
70
+ end
@@ -8,6 +8,11 @@ module Pact
8
8
  module RSpec
9
9
  class Formatter2 < ::RSpec::Core::Formatters::DocumentationFormatter
10
10
 
11
+ class NilFormatter < ::RSpec::Core::Formatters::DocumentationFormatter
12
+ def dump_commands_to_rerun_failed_examples
13
+ end
14
+ end
15
+
11
16
  C = ::Term::ANSIColor
12
17
 
13
18
  def dump_commands_to_rerun_failed_examples
@@ -29,7 +34,9 @@ module Pact
29
34
  end
30
35
 
31
36
  def print_missing_provider_states
32
- PrintMissingProviderStates.call Pact.provider_world.provider_states.missing_provider_states, output
37
+ if executing_with_ruby?
38
+ PrintMissingProviderStates.call Pact.provider_world.provider_states.missing_provider_states, output
39
+ end
33
40
  end
34
41
 
35
42
  def interaction_rerun_commands
@@ -39,26 +46,33 @@ module Pact
39
46
  end
40
47
 
41
48
  def interaction_rerun_command_for example
42
- provider_state = example.metadata[:pact_interaction].provider_state
43
- description = example.metadata[:pact_interaction].description
44
- pactfile_uri = example.metadata[:pactfile_uri]
45
49
  example_description = example.metadata[:pact_interaction_example_description]
46
- failure_color("bundle exec rake pact:verify:at[#{pactfile_uri}] PACT_DESCRIPTION=\"#{description}\" PACT_PROVIDER_STATE=\"#{provider_state}\"") + " " + detail_color("# #{example_description}")
50
+ if ENV['PACT_INTERACTION_RERUN_COMMAND']
51
+ cmd = String.new(ENV['PACT_INTERACTION_RERUN_COMMAND'])
52
+ provider_state = example.metadata[:pact_interaction].provider_state
53
+ description = example.metadata[:pact_interaction].description
54
+ pactfile_uri = example.metadata[:pactfile_uri]
55
+ cmd.gsub!("<PACT_URI>", pactfile_uri.to_s)
56
+ cmd.gsub!("<PACT_DESCRIPTION>", description)
57
+ cmd.gsub!("<PACT_PROVIDER_STATE>", "#{provider_state}")
58
+ failure_color(cmd) + " " + detail_color("# #{example_description}")
59
+ else
60
+ failure_color("* #{example_description}")
61
+ end
47
62
  end
48
63
 
49
64
  def print_failure_message
50
- output.puts failure_message
65
+ output.puts(failure_message) if executing_with_ruby?
51
66
  end
52
67
 
53
68
  def failure_message
54
69
  "\n" + Pact::Provider::Help::PromptText.() + "\n"
55
70
  end
56
71
 
72
+ def executing_with_ruby?
73
+ ENV['PACT_EXECUTING_LANGUAGE'] == 'ruby'
74
+ end
57
75
  end
58
-
59
76
  end
60
-
61
77
  end
62
78
  end
63
-
64
-
@@ -6,8 +6,17 @@ require 'pact/provider/help/prompt_text'
6
6
  module Pact
7
7
  module Provider
8
8
  module RSpec
9
+
9
10
  class Formatter < ::RSpec::Core::Formatters::DocumentationFormatter
10
11
 
12
+ class NilFormatter < ::RSpec::Core::Formatters::BaseFormatter
13
+ Pact::RSpec.with_rspec_3 do
14
+ ::RSpec::Core::Formatters.register self, :start, :example_group_started, :close
15
+ end
16
+ def dump_summary(summary)
17
+ end
18
+ end
19
+
11
20
  Pact::RSpec.with_rspec_3 do
12
21
  ::RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished,
13
22
  :example_passed, :example_pending, :example_failed
@@ -55,26 +64,35 @@ module Pact
55
64
  end
56
65
 
57
66
  def print_missing_provider_states
58
- PrintMissingProviderStates.call Pact.provider_world.provider_states.missing_provider_states, output
67
+ if executing_with_ruby?
68
+ PrintMissingProviderStates.call Pact.provider_world.provider_states.missing_provider_states, output
69
+ end
59
70
  end
60
71
 
61
72
  def interaction_rerun_commands summary
62
73
  summary.failed_examples.collect do |example|
63
74
  interaction_rerun_command_for example
64
- end.uniq
75
+ end.uniq.compact
65
76
  end
66
77
 
67
78
  def interaction_rerun_command_for example
68
- provider_state = example.metadata[:pact_interaction].provider_state
69
- description = example.metadata[:pact_interaction].description
70
- pactfile_uri = example.metadata[:pactfile_uri]
71
79
  example_description = example.metadata[:pact_interaction_example_description]
72
- colorizer.wrap("bundle exec rake pact:verify:at[#{pactfile_uri}] PACT_DESCRIPTION=\"#{description}\" PACT_PROVIDER_STATE=\"#{provider_state}\" ", ::RSpec.configuration.failure_color) +
73
- colorizer.wrap("# #{example_description}", ::RSpec.configuration.detail_color)
80
+ if ENV['PACT_INTERACTION_RERUN_COMMAND']
81
+ cmd = String.new(ENV['PACT_INTERACTION_RERUN_COMMAND'])
82
+ provider_state = example.metadata[:pact_interaction].provider_state
83
+ description = example.metadata[:pact_interaction].description
84
+ pactfile_uri = example.metadata[:pactfile_uri]
85
+ cmd.gsub!("<PACT_URI>", pactfile_uri.to_s)
86
+ cmd.gsub!("<PACT_DESCRIPTION>", description)
87
+ cmd.gsub!("<PACT_PROVIDER_STATE>", "#{provider_state}")
88
+ colorizer.wrap("#{cmd} ", ::RSpec.configuration.failure_color) + colorizer.wrap("# #{example_description}", ::RSpec.configuration.detail_color)
89
+ else
90
+ colorizer.wrap("* #{example_description}", ::RSpec.configuration.failure_color)
91
+ end
74
92
  end
75
93
 
76
94
  def print_failure_message
77
- output.puts failure_message
95
+ output.puts(failure_message) if executing_with_ruby?
78
96
  end
79
97
 
80
98
  def failure_message
@@ -85,11 +103,11 @@ module Pact
85
103
  @colorizer ||= ::RSpec::Core::Formatters::ConsoleCodes
86
104
  end
87
105
 
106
+ def executing_with_ruby?
107
+ ENV['PACT_EXECUTING_LANGUAGE'] == 'ruby'
108
+ end
88
109
  end
89
-
90
110
  end
91
-
92
111
  end
93
112
  end
94
113
 
95
-
@@ -0,0 +1,67 @@
1
+ require 'rspec/core/formatters'
2
+ require 'pact/provider/verification_results/publish_all'
3
+ require 'term/ansicolor'
4
+
5
+ module Pact
6
+ module Provider
7
+ module RSpec
8
+ class PactBrokerFormatter < ::RSpec::Core::Formatters::BaseFormatter
9
+ Pact::RSpec.with_rspec_3 do
10
+ ::RSpec::Core::Formatters.register self, :message, :dump_summary, :stop, :seed, :close
11
+ end
12
+
13
+ attr_reader :output_hash
14
+
15
+ def initialize(output)
16
+ super
17
+ @output_hash = {
18
+ :version => ::RSpec::Core::Version::STRING
19
+ }
20
+ end
21
+
22
+ def message(notification)
23
+ (@output_hash[:messages] ||= []) << notification.message
24
+ end
25
+
26
+ def dump_summary(summary)
27
+ end
28
+
29
+ def stop(notification)
30
+ @output_hash[:tests] = notification
31
+ .examples
32
+ .map { |example| format_example(example) }
33
+ end
34
+
35
+ def seed(notification)
36
+ return unless notification.seed_used?
37
+ @output_hash[:seed] = notification.seed
38
+ end
39
+
40
+ def close(_notification)
41
+ Pact::Provider::VerificationResults::PublishAll.call(Pact.provider_world.pact_sources, output_hash)
42
+ end
43
+
44
+ private
45
+
46
+ def format_example(example)
47
+ {
48
+ testDescription: example.description,
49
+ testFullDescription: example.full_description,
50
+ status: example.execution_result.status.to_s,
51
+ interactionProviderState: example.metadata[:pact_interaction].provider_state,
52
+ interactionDescription: example.metadata[:pact_interaction].description,
53
+ pact_uri: example.metadata[:pact_uri],
54
+ pact_interaction: example.metadata[:pact_interaction]
55
+ }.tap do |hash|
56
+ if example.exception
57
+ hash[:exception] = {
58
+ class: example.exception.class.name,
59
+ message: ::Term::ANSIColor.uncolor(example.exception.message)
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -3,6 +3,8 @@ require 'pact/consumer_contract'
3
3
  require 'pact/provider/rspec/matchers'
4
4
  require 'pact/provider/test_methods'
5
5
  require 'pact/provider/configuration'
6
+ require 'pact/provider/matchers/messages'
7
+
6
8
 
7
9
  module Pact
8
10
  module Provider
@@ -19,12 +21,11 @@ module Pact
19
21
  include ::RSpec::Core::DSL
20
22
 
21
23
  def honour_pactfile pact_uri, pact_json, options
22
- #TODO change puts to use output stream
23
- puts "Reading pact at #{pact_uri}"
24
- puts "Filtering interactions by: #{options[:criteria]}" if options[:criteria] && options[:criteria].any?
24
+ Pact.configuration.output_stream.puts "INFO: Reading pact at #{pact_uri}"
25
+ Pact.configuration.output_stream.puts "INFO: Filtering interactions by: #{options[:criteria]}" if options[:criteria] && options[:criteria].any?
25
26
  consumer_contract = Pact::ConsumerContract.from_json(pact_json)
26
27
  ::RSpec.describe "Verifying a pact between #{consumer_contract.consumer.name} and #{consumer_contract.provider.name}", pactfile_uri: pact_uri do
27
- honour_consumer_contract consumer_contract, options.merge(pact_json: pact_json)
28
+ honour_consumer_contract consumer_contract, options.merge(pact_json: pact_json, pact_uri: pact_uri)
28
29
  end
29
30
  end
30
31
 
@@ -60,19 +61,24 @@ module Pact
60
61
 
61
62
  def describe_interaction interaction, options
62
63
 
64
+ # pact_uri and pact_interaction are used by
65
+ # Pact::Provider::RSpec::PactBrokerFormatter
66
+
67
+ # pact_interaction_example_description is used by
68
+ # Pact::Provider::RSpec::Formatter and Pact::Provider::RSpec::Formatter2
69
+
70
+ # pact: verify is used to allow RSpec before and after hooks.
63
71
  metadata = {
64
72
  pact: :verify,
65
73
  pact_interaction: interaction,
66
74
  pact_interaction_example_description: interaction_description_for_rerun_command(interaction),
67
- pact_json: options[:pact_json]
75
+ pact_uri: options[:pact_uri]
68
76
  }
69
77
 
70
78
  describe description_for(interaction), metadata do
71
79
 
72
-
73
80
  describe "with #{interaction.request.method_and_path}" do
74
81
 
75
-
76
82
  interaction_context = InteractionContext.new
77
83
 
78
84
  before do | example |
@@ -90,7 +96,7 @@ module Pact
90
96
  end
91
97
  end
92
98
 
93
- describe_response Pact::Response.new(Pact::Term.unpack_regexps(interaction.response)), interaction_context
99
+ describe_response Pact::Response.new(interaction.response), interaction_context
94
100
 
95
101
  end
96
102
 
@@ -103,6 +109,7 @@ module Pact
103
109
  describe "returns a response which" do
104
110
 
105
111
  include Pact::RSpec::Matchers
112
+ extend Pact::Matchers::Messages
106
113
 
107
114
  let(:expected_response_status) { expected_response.status }
108
115
  let(:expected_response_body) { expected_response.body }
@@ -125,7 +132,7 @@ module Pact
125
132
  if expected_response.headers
126
133
  describe "includes headers" do
127
134
  expected_response.headers.each do |name, expected_header_value|
128
- it "\"#{name}\" with value #{expected_header_value.inspect}" do
135
+ it "\"#{name}\" which #{expected_desc_for_it(expected_header_value)}" do
129
136
  header_value = response.headers[name]
130
137
  expect(header_value).to match_header(name, expected_header_value)
131
138
  end
@@ -1,13 +1,15 @@
1
1
  require 'rspec/mocks'
2
2
 
3
3
  module Pact
4
- module Provider::State
5
- module ProviderStateConfiguredModules
4
+ module Provider
5
+ module State
6
+ module ProviderStateConfiguredModules
6
7
 
7
- include ::RSpec::Mocks::ExampleMethods
8
+ include ::RSpec::Mocks::ExampleMethods
8
9
 
9
- # Placeholder for modules configured using config.include
10
+ # Placeholder for modules configured using config.include
10
11
 
12
+ end
11
13
  end
12
14
  end
13
15
  end
@@ -4,38 +4,67 @@ module Pact
4
4
  module VerificationResults
5
5
  class Create
6
6
 
7
- def self.call pact_json, failed_examples
8
- new(pact_json, failed_examples).call
7
+ def self.call pact_source, test_results_hash
8
+ new(pact_source, test_results_hash).call
9
9
  end
10
10
 
11
- def initialize pact_json, failed_examples
12
- @pact_json = pact_json
13
- @failed_examples = failed_examples
11
+ def initialize pact_source, test_results_hash
12
+ @pact_source = pact_source
13
+ @test_results_hash = test_results_hash
14
14
  end
15
15
 
16
16
  def call
17
- VerificationResult.new(!any_failures?, Pact.configuration.provider.application_version)
17
+ VerificationResult.new(publishable?, !any_failures?, Pact.configuration.provider.application_version, test_results_hash_for_pact_uri)
18
18
  end
19
19
 
20
20
  private
21
21
 
22
- def pact_hash
23
- @pact_hash ||= json_load(pact_json)
22
+ def pact_uri
23
+ @pact_uri ||= pact_source.uri
24
24
  end
25
25
 
26
- def json_load json
27
- JSON.load(json, nil, { max_nesting: 50 })
26
+ def any_failures?
27
+ count_failures_for_pact_uri > 0
28
28
  end
29
29
 
30
- def count_failures_for_pact_json
31
- failed_examples.collect{ |e| e.metadata[:pact_json] == pact_json }.uniq.size
30
+ def publishable?
31
+ executed_interactions_count == all_interactions_count && all_interactions_count > 0
32
32
  end
33
33
 
34
- def any_failures?
35
- count_failures_for_pact_json > 0
34
+ def examples_for_pact_uri
35
+ @examples_for_pact_uri ||= test_results_hash[:tests].select{ |e| e[:pact_uri] == pact_uri }
36
+ end
37
+
38
+ def count_failures_for_pact_uri
39
+ examples_for_pact_uri.count{ |e| e[:status] != 'passed' }
40
+ end
41
+
42
+ def executed_interactions_count
43
+ examples_for_pact_uri
44
+ .collect { |e| e[:pact_interaction].object_id }
45
+ .uniq
46
+ .count
47
+ end
48
+
49
+ def all_interactions_count
50
+ pact_source.pact_hash['interactions'].count
51
+ end
52
+
53
+ def test_results_hash_for_pact_uri
54
+ {
55
+ tests: examples_for_pact_uri.collect{ |e| clean_example(e) },
56
+ summary: {
57
+ testCount: examples_for_pact_uri.size,
58
+ failureCount: count_failures_for_pact_uri
59
+ }
60
+ }
61
+ end
62
+
63
+ def clean_example(example)
64
+ example.reject{ |k, v| k == :pact_uri || k == :pact_interaction }
36
65
  end
37
66
 
38
- attr_reader :pact_json, :failed_examples
67
+ attr_reader :pact_source, :test_results_hash
39
68
  end
40
69
  end
41
70
  end
@@ -1,6 +1,9 @@
1
1
  require 'json'
2
2
  require 'pact/errors'
3
3
 
4
+ # TODO move this to the pact broker client
5
+ # TODO retries
6
+
4
7
  module Pact
5
8
  module Provider
6
9
  module VerificationResults
@@ -19,26 +22,76 @@ module Pact
19
22
  end
20
23
 
21
24
  def call
22
- if Pact.configuration.provider.publish_verification_results?
23
- if publication_url
24
- publish
25
- else
26
- puts "WARNING: Cannot publish verification for #{consumer_name} as there is no link named pb:publish-verification-results in the pact JSON. If you are using a pact broker, please upgrade to version 2.0.0 or later."
27
- end
25
+ if can_publish_verification_results?
26
+ tag_versions_if_configured
27
+ publish_verification_results
28
28
  end
29
29
  end
30
30
 
31
31
  private
32
32
 
33
+ def can_publish_verification_results?
34
+ return false unless Pact.configuration.provider.publish_verification_results?
35
+
36
+ if publication_url.nil?
37
+ Pact.configuration.error_stream.puts "WARN: Cannot publish verification for #{consumer_name} as there is no link named pb:publish-verification-results in the pact JSON. If you are using a pact broker, please upgrade to version 2.0.0 or later."
38
+ return false
39
+ end
40
+
41
+ if !verification_result.publishable?
42
+ Pact.configuration.error_stream.puts "WARN: Cannot publish verification for #{consumer_name} as not all interactions have been verified. Re-run the verification without the filter parameters or environment variables to publish the verification."
43
+ return false
44
+ end
45
+ true
46
+ end
47
+
33
48
  def publication_url
34
49
  @publication_url ||= pact_source.pact_hash.fetch('_links', {}).fetch('pb:publish-verification-results', {})['href']
35
50
  end
36
51
 
37
- def publish
38
- #TODO https
39
- #TODO username/password
52
+ def tag_url tag
53
+ # This is so dodgey, need to use proper HAL
54
+ if publication_url
55
+ u = URI(publication_url)
56
+ if match = publication_url.match(%r{/provider/([^/]+)})
57
+ provider_name = match[1]
58
+ base_url = "#{u.scheme}://#{u.host}:#{u.host == u.default_port ? '' : u.port}"
59
+ provider_application_version = Pact.configuration.provider.application_version
60
+ "#{base_url}/pacticipants/#{provider_name}/versions/#{provider_application_version}/tags/#{tag}"
61
+ end
62
+ end
63
+ end
64
+
65
+ def tag_versions_if_configured
66
+ if Pact.configuration.provider.tags.any?
67
+ tag_versions if tag_url('')
68
+ end
69
+ end
70
+
71
+ def tag_versions
72
+ Pact.configuration.provider.tags.each do | tag |
73
+ uri = URI(tag_url(tag))
74
+ request = build_request('Put', uri, nil, "Tagging provider version at")
75
+ response = nil
76
+ begin
77
+ options = {:use_ssl => uri.scheme == 'https'}
78
+ response = Net::HTTP.start(uri.host, uri.port, options) do |http|
79
+ http.request request
80
+ end
81
+ rescue StandardError => e
82
+ error_message = "Failed to tag provider version due to: #{e.class} #{e.message}"
83
+ raise PublicationError.new(error_message)
84
+ end
85
+
86
+ unless response.code.start_with?("2")
87
+ raise PublicationError.new("Error returned from tagging request #{response.code} #{response.body}")
88
+ end
89
+ end
90
+ end
91
+
92
+ def publish_verification_results
40
93
  uri = URI(publication_url)
41
- request = build_request(uri)
94
+ request = build_request('Post', uri, verification_result.to_json, "Publishing verification result #{verification_result} to")
42
95
  response = nil
43
96
  begin
44
97
  options = {:use_ssl => uri.scheme == 'https'}
@@ -46,25 +99,30 @@ module Pact
46
99
  http.request request
47
100
  end
48
101
  rescue StandardError => e
49
- error_message = "Failed to publish verification result due to: #{e.class} #{e.message}"
102
+ error_message = "Failed to publish verification results due to: #{e.class} #{e.message}"
50
103
  raise PublicationError.new(error_message)
51
104
  end
52
105
 
53
- unless response.code.start_with?("2")
54
- raise PublicationError.new("Error returned from verification result publication #{response.code} #{response.body}")
106
+
107
+
108
+ if response.code.start_with?("2")
109
+ new_resource_url = JSON.parse(response.body)['_links']['self']['href']
110
+ Pact.configuration.output_stream.puts "INFO: Verification results published to #{new_resource_url}"
111
+ else
112
+ raise PublicationError.new("Error returned from verification results publication #{response.code} #{response.body}")
55
113
  end
56
114
  end
57
115
 
58
- def build_request uri
59
- request = Net::HTTP::Post.new(uri.path)
116
+ def build_request meth, uri, body, action
117
+ request = Net::HTTP.const_get(meth).new(uri.path)
60
118
  request['Content-Type'] = "application/json"
61
- request.body = verification_result.to_json
119
+ request.body = body if body
62
120
  debug_uri = uri
63
121
  if pact_source.uri.basic_auth?
64
122
  request.basic_auth pact_source.uri.username, pact_source.uri.password
65
123
  debug_uri = URI(uri.to_s).tap { |x| x.userinfo="#{pact_source.uri.username}:*****"}
66
124
  end
67
- puts "Publishing verification result #{verification_result.to_json} to #{debug_uri}"
125
+ Pact.configuration.output_stream.puts "INFO: #{action} #{debug_uri}"
68
126
  request
69
127
  end
70
128
 
@@ -6,18 +6,18 @@ module Pact
6
6
  module VerificationResults
7
7
  class PublishAll
8
8
 
9
- def self.call pact_sources, rspec_summary
10
- new(pact_sources, rspec_summary).call
9
+ def self.call pact_sources, test_results_hash
10
+ new(pact_sources, test_results_hash).call
11
11
  end
12
12
 
13
- def initialize pact_sources, rspec_summary
13
+ def initialize pact_sources, test_results_hash
14
14
  @pact_sources = pact_sources
15
- @rspec_summary = rspec_summary
15
+ @test_results_hash = test_results_hash
16
16
  end
17
17
 
18
18
  def call
19
- verification_results.collect do | pair |
20
- Publish.call(pair.first, pair.last)
19
+ verification_results.collect do | (pact_source, verification_result) |
20
+ Publish.call(pact_source, verification_result)
21
21
  end
22
22
  end
23
23
 
@@ -25,11 +25,11 @@ module Pact
25
25
 
26
26
  def verification_results
27
27
  pact_sources.collect do | pact_source |
28
- [pact_source, Create.call(pact_source.pact_json, rspec_summary)]
28
+ [pact_source, Create.call(pact_source, test_results_hash)]
29
29
  end
30
30
  end
31
31
 
32
- attr_reader :pact_sources, :rspec_summary
32
+ attr_reader :pact_sources, :test_results_hash
33
33
  end
34
34
  end
35
35
  end
@@ -1,11 +1,19 @@
1
+ require 'json'
2
+
1
3
  module Pact
2
4
  module Provider
3
5
  module VerificationResults
4
6
  class VerificationResult
5
7
 
6
- def initialize success, provider_application_version
8
+ def initialize publishable, success, provider_application_version, test_results_hash
9
+ @publishable = publishable
7
10
  @success = success
8
11
  @provider_application_version = provider_application_version
12
+ @test_results_hash = test_results_hash
13
+ end
14
+
15
+ def publishable?
16
+ @publishable
9
17
  end
10
18
 
11
19
  def provider_application_version_set?
@@ -15,13 +23,18 @@ module Pact
15
23
  def to_json
16
24
  {
17
25
  success: success,
18
- providerApplicationVersion: provider_application_version
26
+ providerApplicationVersion: provider_application_version,
27
+ #testResults: test_results_hash # not yet
19
28
  }.to_json
20
29
  end
21
30
 
31
+ def to_s
32
+ "[success: #{success}, providerApplicationVersion: #{provider_application_version}]"
33
+ end
34
+
22
35
  private
23
36
 
24
- attr_reader :success, :provider_application_version
37
+ attr_reader :success, :provider_application_version, :test_results_hash
25
38
  end
26
39
  end
27
40
  end
@@ -14,6 +14,8 @@ module Pact
14
14
  module Provider
15
15
  class World
16
16
 
17
+ attr_accessor :pact_sources
18
+
17
19
  def provider_states
18
20
  @provider_states_proxy ||= Pact::Provider::State::ProviderStateProxy.new
19
21
  end
@@ -29,7 +31,6 @@ module Pact
29
31
  def pact_urls
30
32
  pact_verifications.collect(&:uri)
31
33
  end
32
-
33
34
  end
34
35
  end
35
36
  end
@@ -1,3 +1,4 @@
1
+ require 'pact/configuration'
1
2
  require 'pact/provider/pact_helper_locator'
2
3
  require 'rake/file_utils'
3
4
  require 'shellwords'
@@ -5,6 +6,8 @@ require 'shellwords'
5
6
  module Pact
6
7
  module TaskHelper
7
8
 
9
+ PACT_INTERACTION_RERUN_COMMAND = "bundle exec rake pact:verify:at[<PACT_URI>] PACT_DESCRIPTION=\"<PACT_DESCRIPTION>\" PACT_PROVIDER_STATE=\"<PACT_PROVIDER_STATE>\""
10
+
8
11
  extend self
9
12
 
10
13
  def execute_pact_verify pact_uri = nil, pact_helper = nil, rspec_opts = nil
@@ -34,9 +37,20 @@ module Pact
34
37
  end
35
38
 
36
39
  def execute_cmd command
37
- $stdout.puts command
38
- system(command) ? 0 : 1
40
+ Pact.configuration.output_stream.puts command
41
+ temporarily_set_env_var 'PACT_EXECUTING_LANGUAGE', 'ruby' do
42
+ temporarily_set_env_var 'PACT_INTERACTION_RERUN_COMMAND', PACT_INTERACTION_RERUN_COMMAND do
43
+ exit_status = system(command) ? 0 : 1
44
+ end
45
+ end
39
46
  end
40
47
 
48
+ def temporarily_set_env_var name, value
49
+ original_value = ENV[name]
50
+ ENV[name] ||= value
51
+ yield
52
+ ensure
53
+ ENV[name] = original_value
54
+ end
41
55
  end
42
56
  end
@@ -19,4 +19,4 @@
19
19
 
20
20
  * Check out https://github.com/realestate-com-au/pact/wiki/Troubleshooting
21
21
 
22
- * Ask a question in the google users' group https://groups.google.com/forum/#!forum/pact-support
22
+ * Ask a question on stackoverflow and tag it `pact-ruby`
data/lib/pact/version.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # Remember to bump pact-provider-proxy when this changes major version
1
2
  module Pact
2
- VERSION = "1.14.0"
3
+ VERSION = "1.20.0"
3
4
  end
data/lib/tasks/pact.rake CHANGED
@@ -31,5 +31,4 @@ namespace :pact do
31
31
  require 'pact/provider/help/console_text'
32
32
  puts Pact::Provider::Help::ConsoleText.(args[:reports_dir])
33
33
  end
34
-
35
34
  end
data/pact.gemspec CHANGED
@@ -22,13 +22,13 @@ Gem::Specification.new do |gem|
22
22
 
23
23
  gem.add_runtime_dependency 'randexp', '~> 0.1.7'
24
24
  gem.add_runtime_dependency 'rspec', '>=2.14'
25
- gem.add_runtime_dependency 'rack-test', '~> 0.6.2'
25
+ gem.add_runtime_dependency 'rack-test', '~> 0.6', '>= 0.6.3'
26
26
  gem.add_runtime_dependency 'thor'
27
27
  gem.add_runtime_dependency 'json','> 1.8.5'
28
28
  gem.add_runtime_dependency 'webrick'
29
29
  gem.add_runtime_dependency 'term-ansicolor', '~> 1.0'
30
30
 
31
- gem.add_runtime_dependency 'pact-support', '~> 1.1'
31
+ gem.add_runtime_dependency 'pact-support', '~> 1.2', '>= 1.2.4'
32
32
  gem.add_runtime_dependency 'pact-mock_service', '~> 2.0'
33
33
 
34
34
  gem.add_development_dependency 'rake', '~> 10.0.3'
@@ -37,6 +37,8 @@ Gem::Specification.new do |gem|
37
37
  gem.add_development_dependency 'fakefs', '0.5' # 0.6.0 blows up
38
38
  gem.add_development_dependency 'hashie', '~> 2.0'
39
39
  gem.add_development_dependency 'activesupport'
40
- gem.add_development_dependency 'faraday'
41
- gem.add_development_dependency 'appraisal'
40
+ gem.add_development_dependency 'faraday', '~> 0.13'
41
+ gem.add_development_dependency 'appraisal', '~> 2.2'
42
+ gem.add_development_dependency 'conventional-changelog', '~> 1.3'
43
+ gem.add_development_dependency 'bump', '~> 0.5'
42
44
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.14.0
4
+ version: 1.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Fraser
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2017-06-18 00:00:00.000000000 Z
15
+ date: 2017-12-09 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: randexp
@@ -48,14 +48,20 @@ dependencies:
48
48
  requirements:
49
49
  - - "~>"
50
50
  - !ruby/object:Gem::Version
51
- version: 0.6.2
51
+ version: '0.6'
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.3
52
55
  type: :runtime
53
56
  prerelease: false
54
57
  version_requirements: !ruby/object:Gem::Requirement
55
58
  requirements:
56
59
  - - "~>"
57
60
  - !ruby/object:Gem::Version
58
- version: 0.6.2
61
+ version: '0.6'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 0.6.3
59
65
  - !ruby/object:Gem::Dependency
60
66
  name: thor
61
67
  requirement: !ruby/object:Gem::Requirement
@@ -118,14 +124,20 @@ dependencies:
118
124
  requirements:
119
125
  - - "~>"
120
126
  - !ruby/object:Gem::Version
121
- version: '1.1'
127
+ version: '1.2'
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: 1.2.4
122
131
  type: :runtime
123
132
  prerelease: false
124
133
  version_requirements: !ruby/object:Gem::Requirement
125
134
  requirements:
126
135
  - - "~>"
127
136
  - !ruby/object:Gem::Version
128
- version: '1.1'
137
+ version: '1.2'
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: 1.2.4
129
141
  - !ruby/object:Gem::Dependency
130
142
  name: pact-mock_service
131
143
  requirement: !ruby/object:Gem::Requirement
@@ -228,30 +240,58 @@ dependencies:
228
240
  name: faraday
229
241
  requirement: !ruby/object:Gem::Requirement
230
242
  requirements:
231
- - - ">="
243
+ - - "~>"
232
244
  - !ruby/object:Gem::Version
233
- version: '0'
245
+ version: '0.13'
234
246
  type: :development
235
247
  prerelease: false
236
248
  version_requirements: !ruby/object:Gem::Requirement
237
249
  requirements:
238
- - - ">="
250
+ - - "~>"
239
251
  - !ruby/object:Gem::Version
240
- version: '0'
252
+ version: '0.13'
241
253
  - !ruby/object:Gem::Dependency
242
254
  name: appraisal
243
255
  requirement: !ruby/object:Gem::Requirement
244
256
  requirements:
245
- - - ">="
257
+ - - "~>"
246
258
  - !ruby/object:Gem::Version
247
- version: '0'
259
+ version: '2.2'
248
260
  type: :development
249
261
  prerelease: false
250
262
  version_requirements: !ruby/object:Gem::Requirement
251
263
  requirements:
252
- - - ">="
264
+ - - "~>"
253
265
  - !ruby/object:Gem::Version
254
- version: '0'
266
+ version: '2.2'
267
+ - !ruby/object:Gem::Dependency
268
+ name: conventional-changelog
269
+ requirement: !ruby/object:Gem::Requirement
270
+ requirements:
271
+ - - "~>"
272
+ - !ruby/object:Gem::Version
273
+ version: '1.3'
274
+ type: :development
275
+ prerelease: false
276
+ version_requirements: !ruby/object:Gem::Requirement
277
+ requirements:
278
+ - - "~>"
279
+ - !ruby/object:Gem::Version
280
+ version: '1.3'
281
+ - !ruby/object:Gem::Dependency
282
+ name: bump
283
+ requirement: !ruby/object:Gem::Requirement
284
+ requirements:
285
+ - - "~>"
286
+ - !ruby/object:Gem::Version
287
+ version: '0.5'
288
+ type: :development
289
+ prerelease: false
290
+ version_requirements: !ruby/object:Gem::Requirement
291
+ requirements:
292
+ - - "~>"
293
+ - !ruby/object:Gem::Version
294
+ version: '0.5'
255
295
  description: Enables consumer driven contract testing, providing a mock service and
256
296
  DSL for the consumer project, and interaction playback and verification for the
257
297
  service provider project.
@@ -326,6 +366,7 @@ files:
326
366
  - lib/pact/provider/rspec/formatter_rspec_2.rb
327
367
  - lib/pact/provider/rspec/formatter_rspec_3.rb
328
368
  - lib/pact/provider/rspec/matchers.rb
369
+ - lib/pact/provider/rspec/pact_broker_formatter.rb
329
370
  - lib/pact/provider/state/provider_state.rb
330
371
  - lib/pact/provider/state/provider_state_configured_modules.rb
331
372
  - lib/pact/provider/state/provider_state_manager.rb
@@ -367,7 +408,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
367
408
  version: '0'
368
409
  requirements: []
369
410
  rubyforge_project:
370
- rubygems_version: 2.4.5
411
+ rubygems_version: 2.6.11
371
412
  signing_key:
372
413
  specification_version: 4
373
414
  summary: Enables consumer driven contract testing, providing a mock service and DSL