pact 1.57.0 → 1.66.1

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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +138 -0
  3. data/lib/pact/cli/run_pact_verification.rb +0 -1
  4. data/lib/pact/consumer/consumer_contract_builder.rb +1 -1
  5. data/lib/pact/hal/entity.rb +4 -0
  6. data/lib/pact/hal/http_client.rb +35 -1
  7. data/lib/pact/hash_refinements.rb +17 -0
  8. data/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb +31 -15
  9. data/lib/pact/pact_broker/pact_selection_description.rb +47 -4
  10. data/lib/pact/provider/configuration/message_provider_dsl.rb +5 -1
  11. data/lib/pact/provider/configuration/pact_verification_from_broker.rb +11 -3
  12. data/lib/pact/provider/configuration/service_provider_config.rb +4 -1
  13. data/lib/pact/provider/configuration/service_provider_dsl.rb +19 -5
  14. data/lib/pact/provider/help/console_text.rb +4 -8
  15. data/lib/pact/provider/help/prompt_text.rb +2 -4
  16. data/lib/pact/provider/matchers/messages.rb +3 -5
  17. data/lib/pact/provider/pact_spec_runner.rb +3 -0
  18. data/lib/pact/provider/pact_uri.rb +7 -3
  19. data/lib/pact/provider/print_missing_provider_states.rb +3 -5
  20. data/lib/pact/provider/request.rb +12 -5
  21. data/lib/pact/provider/rspec/formatter_rspec_2.rb +1 -3
  22. data/lib/pact/provider/rspec/formatter_rspec_3.rb +1 -3
  23. data/lib/pact/provider/rspec/pact_broker_formatter.rb +2 -2
  24. data/lib/pact/provider/rspec.rb +5 -3
  25. data/lib/pact/provider/state/provider_state.rb +5 -5
  26. data/lib/pact/provider/test_methods.rb +9 -3
  27. data/lib/pact/provider/verification_results/create.rb +7 -1
  28. data/lib/pact/provider/verification_results/publish.rb +27 -1
  29. data/lib/pact/provider/verification_results/verification_result.rb +4 -2
  30. data/lib/pact/utils/metrics.rb +100 -0
  31. data/lib/pact/version.rb +1 -1
  32. data/lib/tasks/pact.rake +2 -2
  33. data/pact.gemspec +11 -8
  34. metadata +77 -24
@@ -12,6 +12,7 @@ require 'pact/provider/rspec/pact_broker_formatter'
12
12
  require 'pact/provider/rspec/json_formatter'
13
13
  require 'pact/provider/rspec'
14
14
  require 'pact/provider/rspec/calculate_exit_code'
15
+ require 'pact/utils/metrics'
15
16
 
16
17
  module Pact
17
18
  module Provider
@@ -130,6 +131,8 @@ module Pact
130
131
  ignore_failures: options[:ignore_failures],
131
132
  request_customizer: options[:request_customizer]
132
133
  }
134
+ Pact::Utils::Metrics.report_metric("Pacts verified", "ProviderTest", "Completed")
135
+
133
136
  honour_pactfile pact_source, ordered_pact_json(pact_source.pact_json), spec_options
134
137
  end
135
138
  end
@@ -3,7 +3,7 @@ module Pact
3
3
  class PactURI
4
4
  attr_reader :uri, :options, :metadata
5
5
 
6
- def initialize (uri, options = nil, metadata = nil)
6
+ def initialize(uri, options = nil, metadata = nil)
7
7
  @uri = uri
8
8
  @options = options || {}
9
9
  @metadata = metadata || {} # make sure it's not nil if nil is passed in
@@ -30,7 +30,11 @@ module Pact
30
30
 
31
31
  def to_s
32
32
  if basic_auth? && http_or_https_uri?
33
- URI(@uri).tap { |x| x.userinfo="#{username}:*****"}.to_s
33
+ begin
34
+ URI(@uri).tap { |x| x.userinfo="#{username}:*****"}.to_s
35
+ rescue URI::InvalidComponentError
36
+ URI(@uri).tap { |x| x.userinfo="*****:*****"}.to_s
37
+ end
34
38
  elsif personal_access_token? && http_or_https_uri?
35
39
  URI(@uri).tap { |x| x.userinfo="*****"}.to_s
36
40
  else
@@ -45,7 +49,7 @@ module Pact
45
49
  private def http_or_https_uri?
46
50
  uri.start_with?('http://', 'https://')
47
51
  end
48
-
52
+
49
53
  end
50
54
  end
51
55
  end
@@ -1,11 +1,9 @@
1
- require 'term/ansicolor'
1
+ require 'rainbow'
2
2
 
3
3
  module Pact
4
4
  module Provider
5
5
  class PrintMissingProviderStates
6
6
 
7
- C = ::Term::ANSIColor
8
-
9
7
  # Hash of consumer names to array of names of missing provider states
10
8
  def self.call missing_provider_states, output
11
9
  if missing_provider_states.any?
@@ -15,8 +13,8 @@ module Pact
15
13
 
16
14
  def self.colorize string
17
15
  lines = string.split("\n")
18
- first_line = C.cyan(C.underline(lines[0]))
19
- other_lines = C.cyan(lines[1..-1].join("\n"))
16
+ first_line = Rainbow(lines[0]).cyan.underline
17
+ other_lines = Rainbow(lines[1..-1].join("\n")).cyan
20
18
  first_line + "\n" + other_lines
21
19
  end
22
20
 
@@ -1,6 +1,7 @@
1
1
  require 'json'
2
2
  require 'pact/reification'
3
3
  require 'pact/shared/null_expectation'
4
+ require 'pact/generators'
4
5
 
5
6
  module Pact
6
7
  module Provider
@@ -10,8 +11,9 @@ module Pact
10
11
  # See https://github.com/rack/rack/blob/e7d741c6282ca4cf4e01506f5681e6e6b14c0b32/SPEC#L87-89
11
12
  NO_HTTP_PREFIX = ["CONTENT-TYPE", "CONTENT-LENGTH"]
12
13
 
13
- def initialize expected_request
14
+ def initialize expected_request, state_params = nil
14
15
  @expected_request = expected_request
16
+ @state_params = state_params
15
17
  end
16
18
 
17
19
  def method
@@ -19,7 +21,7 @@ module Pact
19
21
  end
20
22
 
21
23
  def path
22
- expected_request.full_path
24
+ Pact::Generators.apply_generators(expected_request, "path", expected_request.full_path, @state_params)
23
25
  end
24
26
 
25
27
  def body
@@ -27,17 +29,22 @@ module Pact
27
29
  when String then expected_request.body
28
30
  when NullExpectation then ''
29
31
  else
30
- reified_body
32
+ Pact::Generators.apply_generators(expected_request, "body", reified_body, @state_params)
31
33
  end
32
34
  end
33
35
 
34
36
  def headers
35
37
  request_headers = {}
38
+ # https://github.com/pact-foundation/pact-ruby/pull/327
39
+ request_headers.merge!('HOST' => 'localhost') if defined?(Sinatra)
36
40
  return request_headers if expected_request.headers.is_a?(Pact::NullExpectation)
41
+
37
42
  expected_request.headers.each do |key, value|
38
- request_headers[rack_request_header_for(key)] = Pact::Reification.from_term(value)
43
+ request_headers[key] = Pact::Reification.from_term(value)
39
44
  end
40
- request_headers
45
+
46
+ request_headers = Pact::Generators.apply_generators(expected_request, "header", request_headers, @state_params)
47
+ request_headers.map{ |key,value| [rack_request_header_for(key), value]}.to_h
41
48
  end
42
49
 
43
50
  private
@@ -1,6 +1,6 @@
1
1
  require 'pact/provider/print_missing_provider_states'
2
2
  require 'rspec/core/formatters/documentation_formatter'
3
- require 'term/ansicolor'
3
+ require 'rainbow'
4
4
  require 'pact/provider/help/prompt_text'
5
5
 
6
6
  module Pact
@@ -13,8 +13,6 @@ module Pact
13
13
  end
14
14
  end
15
15
 
16
- C = ::Term::ANSIColor
17
-
18
16
  def dump_commands_to_rerun_failed_examples
19
17
  return if failed_examples.empty?
20
18
 
@@ -1,6 +1,6 @@
1
1
  require 'pact/provider/print_missing_provider_states'
2
2
  require 'rspec/core/formatters'
3
- require 'term/ansicolor'
3
+ require 'rainbow'
4
4
  require 'pact/provider/help/prompt_text'
5
5
 
6
6
  module Pact
@@ -22,8 +22,6 @@ module Pact
22
22
  :example_passed, :example_pending, :example_failed
23
23
  end
24
24
 
25
- C = ::Term::ANSIColor
26
-
27
25
  def example_group_started(notification)
28
26
  # This is the metadata on the top level "Verifying a pact between X and Y" describe block
29
27
  if @group_level == 0
@@ -1,6 +1,6 @@
1
1
  require 'rspec/core/formatters'
2
2
  require 'pact/provider/verification_results/publish_all'
3
- require 'term/ansicolor'
3
+ require 'rainbow'
4
4
  require 'pact/matchers/extract_diff_messages'
5
5
 
6
6
  module Pact
@@ -43,7 +43,7 @@ module Pact
43
43
  if example.exception
44
44
  hash[:exception] = {
45
45
  class: example.exception.class.name,
46
- message: ::Term::ANSIColor.uncolor(example.exception.message)
46
+ message: "\e[0m#{example.exception.message}"
47
47
  }
48
48
  end
49
49
 
@@ -25,6 +25,7 @@ module Pact
25
25
  pact_uri = pact_source.uri
26
26
  Pact.configuration.output_stream.puts "INFO: Reading pact at #{pact_uri}"
27
27
  consumer_contract = Pact::ConsumerContract.from_json(pact_json)
28
+
28
29
  suffix = pact_uri.metadata[:pending] ? " [PENDING]": ""
29
30
  example_group_description = "Verifying a pact between #{consumer_contract.consumer.name} and #{consumer_contract.provider.name}#{suffix}"
30
31
  example_group_metadata = { pactfile_uri: pact_uri, pact_criteria: options[:criteria] }
@@ -77,7 +78,6 @@ module Pact
77
78
  end
78
79
 
79
80
  def describe_interaction interaction, options
80
-
81
81
  # pact_uri and pact_interaction are used by
82
82
  # Pact::Provider::RSpec::PactBrokerFormatter
83
83
 
@@ -103,8 +103,9 @@ module Pact
103
103
  before do | example |
104
104
  interaction_context.run_once :before do
105
105
  Pact.configuration.logger.info "Running example '#{Pact::RSpec.full_description(example)}'"
106
- set_up_provider_states interaction.provider_states, options[:consumer]
107
- replay_interaction interaction, options[:request_customizer]
106
+ provider_states_result = set_up_provider_states interaction.provider_states, options[:consumer]
107
+ state_params = provider_states_result[interaction.provider_state];
108
+ replay_interaction interaction, options[:request_customizer], state_params
108
109
  interaction_context.last_response = last_response
109
110
  end
110
111
  end
@@ -129,6 +130,7 @@ module Pact
129
130
  include Pact::RSpec::Matchers
130
131
  extend Pact::Matchers::Messages
131
132
 
133
+
132
134
  let(:expected_contents) { expected_response.body[:contents].as_json }
133
135
  let(:response) { interaction_context.last_response }
134
136
  let(:differ) { Pact.configuration.body_differ_for_content_type diff_content_type }
@@ -12,11 +12,11 @@ module Pact
12
12
  end
13
13
 
14
14
  def set_up &block
15
- ProviderStates.base_provider_state.register.register_set_up &block
15
+ ProviderStates.base_provider_state.register.register_set_up(&block)
16
16
  end
17
17
 
18
18
  def tear_down &block
19
- ProviderStates.base_provider_state.register_tear_down &block
19
+ ProviderStates.base_provider_state.register_tear_down(&block)
20
20
  end
21
21
 
22
22
  def provider_states_for name, &block
@@ -60,7 +60,7 @@ module Pact
60
60
  end
61
61
 
62
62
  def self.namespaced_name name, options = {}
63
- fullname = options[:for] ? "#{options[:for]}.#{name}" : name
63
+ options[:for] ? "#{options[:for]}.#{name}" : name
64
64
  end
65
65
  end
66
66
 
@@ -81,11 +81,11 @@ module Pact
81
81
 
82
82
  dsl do
83
83
  def set_up &block
84
- self.register_set_up &block
84
+ self.register_set_up(&block)
85
85
  end
86
86
 
87
87
  def tear_down &block
88
- self.register_tear_down &block
88
+ self.register_tear_down(&block)
89
89
  end
90
90
 
91
91
  def no_op
@@ -14,8 +14,8 @@ module Pact
14
14
  include Pact::Logging
15
15
  include Rack::Test::Methods
16
16
 
17
- def replay_interaction interaction, request_customizer = nil
18
- request = Request::Replayable.new(interaction.request)
17
+ def replay_interaction interaction, request_customizer = nil, state_params = nil
18
+ request = Request::Replayable.new(interaction.request, state_params)
19
19
  request = request_customizer.call(request, interaction) if request_customizer
20
20
  args = [request.path, request.body, request.headers]
21
21
 
@@ -42,11 +42,17 @@ module Pact
42
42
  end
43
43
 
44
44
  def set_up_provider_states provider_states, consumer, options = {}
45
+ provider_states_result = {};
45
46
  # If there are no provider state, execute with an nil state to ensure global and base states are executed
46
47
  Pact.configuration.provider_state_set_up.call(nil, consumer, options) if provider_states.nil? || provider_states.empty?
47
48
  provider_states.each do | provider_state |
48
- Pact.configuration.provider_state_set_up.call(provider_state.name, consumer, options.merge(params: provider_state.params))
49
+ result = Pact.configuration.provider_state_set_up.call(provider_state.name, consumer, options.merge(params: provider_state.params))
50
+ if result.is_a?(Hash)
51
+ provider_states_result[provider_state.name] = result
52
+ end
49
53
  end
54
+
55
+ provider_states_result
50
56
  end
51
57
 
52
58
  def tear_down_provider_states provider_states, consumer, options = {}
@@ -14,7 +14,13 @@ module Pact
14
14
  end
15
15
 
16
16
  def call
17
- VerificationResult.new(publishable?, !any_failures?, Pact.configuration.provider.application_version, test_results_hash_for_pact_uri)
17
+ VerificationResult.new(
18
+ publishable?,
19
+ !any_failures?,
20
+ Pact.configuration.provider.application_version,
21
+ test_results_hash_for_pact_uri,
22
+ Pact.configuration.provider.build_url
23
+ )
18
24
  end
19
25
 
20
26
  private
@@ -16,6 +16,7 @@ module Pact
16
16
  PUBLISH_RELATION = 'pb:publish-verification-results'.freeze
17
17
  PROVIDER_RELATION = 'pb:provider'.freeze
18
18
  VERSION_TAG_RELATION = 'pb:version-tag'.freeze
19
+ BRANCH_VERSION_RELATION = 'pb:branch-version'.freeze
19
20
 
20
21
  def self.call pact_source, verification_result, options = {}
21
22
  new(pact_source, verification_result, options).call
@@ -31,6 +32,7 @@ module Pact
31
32
 
32
33
  def call
33
34
  if can_publish_verification_results?
35
+ create_branch_version_if_configured
34
36
  tag_versions_if_configured
35
37
  publish_verification_results
36
38
  true
@@ -72,8 +74,28 @@ module Pact
72
74
  end
73
75
  end
74
76
 
77
+ def create_branch_version_if_configured
78
+ if Pact.configuration.provider.branch
79
+ branch_version_link = provider_entity._link(BRANCH_VERSION_RELATION)
80
+ if branch_version_link
81
+ version_number = Pact.configuration.provider.application_version
82
+ branch = Pact.configuration.provider.branch
83
+
84
+ Pact.configuration.output_stream.puts "INFO: Creating #{provider_name} version #{version_number} with branch \"#{branch}\""
85
+ branch_entity = branch_version_link.expand(
86
+ version: version_number,
87
+ branch: branch
88
+ ).put
89
+ unless branch_entity.success?
90
+ raise PublicationError.new("Error returned from tagging request: status=#{branch_entity.response.code} body=#{branch_entity.response.body}")
91
+ end
92
+ else
93
+ raise PublicationError.new("This version of the Pact Broker does not support version branches. Please update to version 2.58.0 or later.")
94
+ end
95
+ end
96
+ end
97
+
75
98
  def tag_versions
76
- provider_entity = pact_entity.get(PROVIDER_RELATION)
77
99
  tag_link = provider_entity._link(VERSION_TAG_RELATION) || hacky_tag_url(provider_entity)
78
100
  provider_application_version = Pact.configuration.provider.application_version
79
101
 
@@ -111,6 +133,10 @@ module Pact
111
133
  def provider_name
112
134
  pact_source.pact_hash['provider']['name']
113
135
  end
136
+
137
+ def provider_entity
138
+ @provider_entity ||= pact_entity.get!(PROVIDER_RELATION)
139
+ end
114
140
  end
115
141
  end
116
142
  end
@@ -6,11 +6,12 @@ module Pact
6
6
  class VerificationResult
7
7
  attr_reader :success, :provider_application_version, :test_results_hash
8
8
 
9
- def initialize publishable, success, provider_application_version, test_results_hash
9
+ def initialize publishable, success, provider_application_version, test_results_hash, build_url
10
10
  @publishable = publishable
11
11
  @success = success
12
12
  @provider_application_version = provider_application_version
13
13
  @test_results_hash = test_results_hash
14
+ @build_url = build_url
14
15
  end
15
16
 
16
17
  def publishable?
@@ -25,7 +26,8 @@ module Pact
25
26
  {
26
27
  success: success,
27
28
  providerApplicationVersion: provider_application_version,
28
- testResults: test_results_hash
29
+ testResults: test_results_hash,
30
+ buildUrl: @build_url
29
31
  }.to_json(options)
30
32
  end
31
33
 
@@ -0,0 +1,100 @@
1
+ require 'securerandom'
2
+ require 'digest'
3
+ require 'socket'
4
+ require 'pact/version'
5
+ require 'net/http'
6
+
7
+ module Pact
8
+ module Utils
9
+ class Metrics
10
+
11
+ def self.report_metric(event, category, action, value = 1)
12
+ do_once_per_thread(:pact_metrics_message_shown) do
13
+ if track_events?
14
+ Pact.configuration.output_stream.puts "pact WARN: Please note: we are tracking events anonymously to gather important usage statistics like Pact-Ruby version
15
+ and operating system. To disable tracking, set the 'PACT_DO_NOT_TRACK' environment
16
+ variable to 'true'."
17
+ end
18
+ end
19
+
20
+ in_thread do
21
+ begin
22
+ if track_events?
23
+ uri = URI('https://www.google-analytics.com/collect')
24
+ req = Net::HTTP::Post.new(uri)
25
+ req.set_form_data(create_tracking_event(event, category, action, value))
26
+
27
+ Net::HTTP.start(uri.hostname, uri.port, read_timeout:2, open_timeout:2, :use_ssl => true ) do |http|
28
+ http.request(req)
29
+ end
30
+ end
31
+ rescue StandardError => e
32
+ handle_error(e)
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def self.handle_error e
40
+ if ENV['PACT_METRICS_DEBUG'] == 'true'
41
+ Pact.configuration.output_stream.puts("DEBUG: #{e.inspect}\n" + e.backtrace.join("\n"))
42
+ end
43
+ end
44
+
45
+ def self.in_thread
46
+ Thread.new do
47
+ yield
48
+ end
49
+ end
50
+
51
+ # not super safe to use the thread, but it's good enough for this usecase
52
+ def self.do_once_per_thread(key)
53
+ result = nil
54
+ if !Thread.current[key]
55
+ result = yield
56
+ end
57
+ Thread.current[key] = true
58
+ result
59
+ end
60
+
61
+ def self.create_tracking_event(event, category, action, value)
62
+ {
63
+ "v" => 1,
64
+ "t" => "event",
65
+ "tid" => "UA-117778936-1",
66
+ "cid" => calculate_cid,
67
+ "an" => "Pact Ruby",
68
+ "av" => Pact::VERSION,
69
+ "aid" => "pact-ruby",
70
+ "aip" => 1,
71
+ "ds" => ENV['PACT_EXECUTING_LANGUAGE'] ? "client" : "cli",
72
+ "cd2" => ENV['CI'] == "true" ? "CI" : "unknown",
73
+ "cd3" => RUBY_PLATFORM,
74
+ "cd6" => ENV['PACT_EXECUTING_LANGUAGE'] || "unknown",
75
+ "cd7" => ENV['PACT_EXECUTING_LANGUAGE_VERSION'],
76
+ "el" => event,
77
+ "ec" => category,
78
+ "ea" => action,
79
+ "ev" => value
80
+ }
81
+ end
82
+
83
+ def self.track_events?
84
+ ENV['PACT_DO_NOT_TRACK'] != 'true'
85
+ end
86
+
87
+ def self.calculate_cid
88
+ if RUBY_PLATFORM.include? "windows"
89
+ hostname = ENV['COMPUTERNAME']
90
+ else
91
+ hostname = ENV['HOSTNAME']
92
+ end
93
+ if !hostname
94
+ hostname = Socket.gethostname
95
+ end
96
+ Digest::MD5.hexdigest hostname || SecureRandom.urlsafe_base64(5)
97
+ end
98
+ end
99
+ end
100
+ end
data/lib/pact/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # Remember to bump pact-provider-proxy when this changes major version
2
2
  module Pact
3
- VERSION = "1.57.0"
3
+ VERSION = "1.66.1"
4
4
  end
data/lib/tasks/pact.rake CHANGED
@@ -15,12 +15,12 @@ namespace :pact do
15
15
 
16
16
  desc "Verifies the pact at the given URI against this service provider."
17
17
  task 'verify:at', :pact_uri do | t, args |
18
- require 'term/ansicolor'
18
+ require 'rainbow'
19
19
  require 'pact/tasks/task_helper'
20
20
 
21
21
  include Pact::TaskHelper
22
22
 
23
- abort(::Term::ANSIColor.red("Please provide a pact URI. eg. rake pact:verify:at[../my-consumer/spec/pacts/my_consumer-my_provider.json]")) unless args[:pact_uri]
23
+ abort(Rainbow("Please provide a pact URI. eg. rake pact:verify:at[../my-consumer/spec/pacts/my_consumer-my_provider.json]").red) unless args[:pact_uri]
24
24
  handle_verification_failure do
25
25
  execute_pact_verify args[:pact_uri]
26
26
  end
data/pact.gemspec CHANGED
@@ -27,22 +27,25 @@ Gem::Specification.new do |gem|
27
27
  }
28
28
 
29
29
  gem.add_runtime_dependency 'rspec', '~> 3.0'
30
- gem.add_runtime_dependency 'rack-test', '>= 0.6.3', '< 2.0.0'
30
+ gem.add_runtime_dependency 'rack-test', '>= 0.6.3', '< 3.0.0'
31
31
  gem.add_runtime_dependency 'thor', '>= 0.20', '< 2.0'
32
- gem.add_runtime_dependency 'webrick', '~> 1.3'
33
- gem.add_runtime_dependency 'term-ansicolor', '~> 1.0'
32
+ gem.add_runtime_dependency "rainbow", '~> 3.1'
33
+ gem.add_runtime_dependency 'string_pattern', '~> 2.0'
34
+ gem.add_runtime_dependency 'jsonpath', '~> 1.0'
34
35
 
35
- gem.add_runtime_dependency 'pact-support', '~> 1.15'
36
+ gem.add_runtime_dependency 'pact-support', '~> 1.21', '>= 1.21.0'
36
37
  gem.add_runtime_dependency 'pact-mock_service', '~> 3.0', '>= 3.3.1'
37
38
 
38
39
  gem.add_development_dependency 'rake', '~> 13.0'
39
40
  gem.add_development_dependency 'webmock', '~> 3.0'
40
- gem.add_development_dependency 'fakefs', '0.5' # 0.6.0 blows up
41
- gem.add_development_dependency 'hashie', '~> 2.0'
42
- gem.add_development_dependency 'activesupport', '~> 5.2'
43
- gem.add_development_dependency 'faraday', '~> 0.13'
41
+ gem.add_development_dependency 'fakefs', '2.4'
42
+ gem.add_development_dependency 'hashie', '~> 5.0'
43
+ gem.add_development_dependency 'faraday', '~>2.0', '<3.0'
44
+ gem.add_development_dependency 'faraday-multipart', '~> 1.0'
44
45
  gem.add_development_dependency 'conventional-changelog', '~> 1.3'
45
46
  gem.add_development_dependency 'bump', '~> 0.5'
46
47
  gem.add_development_dependency 'pact-message', '~> 0.8'
47
48
  gem.add_development_dependency 'rspec-its', '~> 1.3'
49
+ gem.add_development_dependency 'webrick', '~> 1.8'
50
+ gem.add_development_dependency 'ostruct'
48
51
  end