cucumber 4.1.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1f051aade812ee4bb28ab3670734b189ade8bc0cd0150a686e21874594ae62f
4
- data.tar.gz: 80c272791953dc442492c0571acffc628cb7b1f37a28a00adeef413bc7f76e1b
3
+ metadata.gz: 61cd1181584bcc92134ced753b975cfd74a8501c00bdce0c75695145cf4ceaef
4
+ data.tar.gz: 57f3dec452665986e5f4916ad78f453e833a9fc94ba2f45124a5643f87b77d0f
5
5
  SHA512:
6
- metadata.gz: 5026e105060af702f3b0adf50f3925ce04fdee7de79c2482093831cab838e2a605d69c056733d7820b6592c7229ee93e1ce64b80ae373ac7acd29f11d113d3a8
7
- data.tar.gz: c66fe1effa60270eb430bc2c381252e5c3da5dec524e49c58a7e508febaeb0b1398791f75eba5542395672b2431dafcfb820da2870410a52474ebc157bfbe333
6
+ metadata.gz: f5f971b543114f4baab695a987ed131fe39931a7b644871ce036862a310b9bf17f52f9d4fe80069072864a295d9c31e3254be5f363e87a946ff80733bf33ecb7
7
+ data.tar.gz: 1c3bb21ce293544c88161cd40460be9e4b12c0dcc3221e50e976a8cc6d5666a982ebde2f5a7bb33d3de65d1423f80d14eaab1b6570a6c03434b568c6cde6e09d
data/CHANGELOG.md CHANGED
@@ -10,6 +10,110 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo
10
10
 
11
11
  ----
12
12
 
13
+ ## [In GIT](https://github.com/cucumber/cucumber-ruby/compare/v5.3.0...master)
14
+
15
+ ### Added
16
+
17
+ ### Fixed
18
+
19
+ ### Changed
20
+
21
+ ### Removed
22
+
23
+ ### Security fixes
24
+
25
+ ## [5.3.0](https://github.com/cucumber/cucumber-ruby/compare/v5.2.0...v5.3.0)
26
+
27
+ ### Added
28
+
29
+ * `fileattribute` cli argument available to attach `file` to junit formatter
30
+
31
+ ### Fixed
32
+
33
+ * Circle-CI windows build now silently installs MSYS2 using Chocolatey before
34
+ setting-up the ruby devkit with ridk
35
+ ([#1503](https://github.com/cucumber/cucumber-ruby/pull/1503)
36
+ [aurelien-reeves](https://github.com/aurelien-reeves))
37
+
38
+ * `--publish` and no formatter now uses the pretty formatter per default
39
+ ([#1468](https://github.com/cucumber/cucumber-ruby/issues/1468)
40
+ [#1500](https://github.com/cucumber/cucumber-ruby/pull/1500)
41
+ [aurelien-reeves](https://github.com/aurelien-reeves))
42
+
43
+ ## [5.2.0](https://github.com/cucumber/cucumber-ruby/compare/v5.1.3...v5.2.0)
44
+
45
+ ### Changed
46
+
47
+ * `--publish` uses the response provided by the server as the banner [#1472](https://github.com/cucumber/cucumber-ruby/issues/1472)
48
+
49
+ ## [5.1.3](https://github.com/cucumber/cucumber-ruby/compare/v5.1.2...v5.1.3)
50
+
51
+ ### Fixed
52
+
53
+ * The `CUCUMBER_PUBLISH_TOKEN` now sets the correct HTTP header, following a fix in the curl option parser.
54
+
55
+ ## [5.1.2](https://github.com/cucumber/cucumber-ruby/compare/v5.1.1...v5.1.2)
56
+
57
+ ### Fixed
58
+
59
+ * Do not send headers after following redirection [#1475](https://github.com/cucumber/cucumber-ruby/pull/1475)
60
+
61
+ ## [5.1.1](https://github.com/cucumber/cucumber-ruby/compare/v5.1.0...v5.1.1)
62
+
63
+ ### Security fixes
64
+
65
+ * Update `cucumber-create-meta` to 2.0.2
66
+
67
+ ## [5.1.0](https://github.com/cucumber/cucumber-ruby/compare/v5.0.0...5.1.0)
68
+
69
+ ### Added
70
+
71
+ * `-X GET` in an `--out` URL will now issue a `GET` request *without* a body. If the response is `202 Accepted` *and*
72
+ the `Location` header is present, a new `PUT` request will be sent *with* the body.
73
+
74
+ The main reason for this added behaviour is to allow request bodies larger than 6Mb to be sent while using `--publish`.
75
+ This also improves performance since the request body is only sent once (previously it would be sent twice).
76
+
77
+ ### Changed
78
+
79
+ * Set banner border color to green when publishing reports
80
+ * Postpone removal of `--format=json`, `embed` and `puts` to version 6.0.0 in deprecation messages
81
+
82
+ ### Fixed
83
+
84
+ * Display banner on stderr when publishing reports [#1462](https://github.com/cucumber/cucumber-ruby/issues/1462)
85
+
86
+ ## [5.0.0](https://github.com/cucumber/cucumber-ruby/compare/v4.1.0...5.0.0)
87
+
88
+ ### Added
89
+
90
+ * `--publish` automatically publishes reports to [reports.cucumber.io](https://reports.cucumber.io)
91
+ * `--publish-quiet` does not print information banner about [reports.cucumber.io](https://reports.cucumber.io)
92
+
93
+ ### Changed
94
+
95
+ * `-q, --quiet` will also imply `--publish-quiet` in addition to `--no-snippets --no-source --no-duration`
96
+
97
+ ### Removed
98
+
99
+ * Dropped support for Ruby [2.3](https://www.ruby-lang.org/en/news/2019/03/31/support-of-ruby-2-3-has-ended/)
100
+ and [2.4](https://www.ruby-lang.org/en/news/2020/04/05/support-of-ruby-2-4-has-ended/)
101
+
102
+ ### Fixed
103
+
104
+ * Update code to be compatible with `diff-lcs` versions 1.3 and 1.4
105
+ * Defer registration of `at_exit` hook that flushes and closes formatter streams
106
+ ([#1458](https://github.com/cucumber/cucumber-ruby/pull/1458))
107
+ * Updated gems (see git diff for details)
108
+ * `cucumber-expressions`
109
+ * `cucumber-gherkin`
110
+ * `cucumber-create-meta`
111
+ * `cucumber-messages`
112
+ * Fix issue with timestamp nanos [#1438](https://github.com/cucumber/cucumber-ruby/issues/1438)
113
+ * `cucumber-html-formatter`
114
+ * Add filtering capabilities [#1444](https://github.com/cucumber/cucumber-ruby/issues/1444)
115
+ * Fix Interceptor that was raising exception when calling `puts` on the wrapped stream ([#1445](https://github.com/cucumber/cucumber-ruby/issues/1445))
116
+
13
117
  ## [4.1.0](https://github.com/cucumber/cucumber-ruby/compare/v4.0.1...v4.1.0)
14
118
 
15
119
  ### Changed
data/CONTRIBUTING.md CHANGED
@@ -59,13 +59,15 @@ help us to correct style violations reported here:
59
59
 
60
60
  ## Release Process
61
61
 
62
- * Bump the version number in `lib/cucumber/version`.
63
- * Make sure `CHANGELOG.md` is updated with the upcoming version number, and has entries for all fixes.
64
-
65
- Now release it
66
-
67
- bundle update
68
- bundle exec rake
69
- git commit -m "Release X.Y.Z"
70
- # Make sure you run gem signin as the cukebot@cucumber.io user before running the following step. Credentials can be found in 1Password
71
- rake release
62
+ * Upgrade gems with `scripts/update-gemspec`
63
+ * Bump the version number in `lib/cucumber/version`
64
+ * Update `CHANGELOG.md` with the upcoming version number and create a new `In Git` section
65
+ * Remove empty sections from `CHANGELOG.md`
66
+ * Now release it:
67
+
68
+ ```
69
+ git commit -am "Release X.Y.Z"
70
+ make release
71
+ ```
72
+
73
+ * Finally, update the cucumber-ruby version in the [documentation project](https://cucumber.io/docs/installation/) in [versions.yaml](https://github.com/cucumber/docs.cucumber.io/blob/master/data/versions.yaml) file.
@@ -24,23 +24,21 @@ module Autotest::CucumberMixin
24
24
  add_sigint_handler
25
25
 
26
26
  loop do # ^c handler
27
- begin
28
- get_to_green
29
- if tainted
30
- rerun_all_tests
31
- rerun_all_features if all_good
32
- else
33
- hook :all_good
34
- end
35
- wait_for_changes
36
- # Once tests and features are green, reset features every
37
- # time a file is changed to see if anything breaks.
38
- reset_features
39
- rescue Interrupt
40
- break if wants_to_quit
41
- reset
42
- reset_features
27
+ get_to_green
28
+ if tainted
29
+ rerun_all_tests
30
+ rerun_all_features if all_good
31
+ else
32
+ hook :all_good
43
33
  end
34
+ wait_for_changes
35
+ # Once tests and features are green, reset features every
36
+ # time a file is changed to see if anything breaks.
37
+ reset_features
38
+ rescue Interrupt
39
+ break if wants_to_quit
40
+ reset
41
+ reset_features
44
42
  end
45
43
  hook :quit
46
44
  end
@@ -126,13 +126,35 @@ module Cucumber
126
126
  end
127
127
 
128
128
  def arrange_formats
129
- @options[:formats] << ['pretty', {}, @out_stream] if @options[:formats].empty?
129
+ add_default_formatter if needs_default_formatter?
130
+
130
131
  @options[:formats] = @options[:formats].sort_by do |f|
131
132
  f[2] == @out_stream ? -1 : 1
132
133
  end
133
134
  @options[:formats].uniq!
134
135
  @options.check_formatter_stream_conflicts
135
136
  end
137
+
138
+ def add_default_formatter
139
+ @options[:formats] << ['pretty', {}, @out_stream]
140
+ end
141
+
142
+ def needs_default_formatter?
143
+ formatter_missing? || publish_only?
144
+ end
145
+
146
+ def formatter_missing?
147
+ @options[:formats].empty?
148
+ end
149
+
150
+ def publish_only?
151
+ @options[:formats]
152
+ .uniq
153
+ .map { |formatter, _, stream| [formatter, stream] }
154
+ .uniq
155
+ .reject { |formatter, stream| formatter == 'message' && stream != @out_stream }
156
+ .empty?
157
+ end
136
158
  end
137
159
  end
138
160
  end
@@ -9,6 +9,7 @@ require 'cucumber/core/test/result'
9
9
  module Cucumber
10
10
  module Cli
11
11
  class Options
12
+ CUCUMBER_PUBLISH_URL = ENV['CUCUMBER_PUBLISH_URL'] || 'https://messages.cucumber.io/api/reports -X GET'
12
13
  INDENT = ' ' * 53
13
14
  BUILTIN_FORMATS = {
14
15
  'pretty' => ['Cucumber::Formatter::Pretty', 'Prints the feature as is - in colours.'],
@@ -21,7 +22,8 @@ module Cucumber
21
22
  "#{INDENT}filename instead."],
22
23
  'stepdefs' => ['Cucumber::Formatter::Stepdefs', "Prints All step definitions with their locations. Same as\n" \
23
24
  "#{INDENT}the usage formatter, except that steps are not printed."],
24
- 'junit' => ['Cucumber::Formatter::Junit', 'Generates a report similar to Ant+JUnit.'],
25
+ 'junit' => ['Cucumber::Formatter::Junit', "Generates a report similar to Ant+JUnit. Use\n" \
26
+ "#{INDENT}junit,fileattribute=true to include a file attribute."],
25
27
  'json' => ['Cucumber::Formatter::Json', '[DEPRECATED] Prints the feature as JSON'],
26
28
  'message' => ['Cucumber::Formatter::Message', 'Outputs protobuf messages'],
27
29
  'html' => ['Cucumber::Formatter::HTML', 'Outputs HTML report'],
@@ -93,6 +95,10 @@ module Cucumber
93
95
 
94
96
  @args.options do |opts| # rubocop:disable Metrics/BlockLength
95
97
  opts.banner = banner
98
+ opts.on('--publish', 'Publish a report to https://reports.cucumber.io') do
99
+ set_option :publish_enabled, true
100
+ end
101
+ opts.on('--publish-quiet', 'Don\'t print information banner about publishing reports') { set_option :publish_quiet }
96
102
  opts.on('-r LIBRARY|DIR', '--require LIBRARY|DIR', *require_files_msg) { |lib| require_files(lib) }
97
103
 
98
104
  opts.on('-j DIR', '--jars DIR', 'Load all the jars under DIR') { |jars| load_jars(jars) } if Cucumber::JRUBY
@@ -117,7 +123,7 @@ module Cucumber
117
123
  opts.on('-s', '--no-source', "Don't print the file and line of the step definition with the steps.") { set_option :source, false }
118
124
  opts.on('-i', '--no-snippets', "Don't print snippets for pending steps.") { set_option :snippets, false }
119
125
  opts.on('-I', '--snippet-type TYPE', *snippet_type_msg) { |v| set_option :snippet_type, v.to_sym }
120
- opts.on('-q', '--quiet', 'Alias for --no-snippets --no-source.') { shut_up }
126
+ opts.on('-q', '--quiet', 'Alias for --no-snippets --no-source --no-duration --publish-quiet.') { shut_up }
121
127
  opts.on('--no-duration', "Don't print the duration at the end of the summary") { set_option :duration, false }
122
128
  opts.on('-b', '--backtrace', 'Show full backtrace for all errors.') { Cucumber.use_full_backtrace = true }
123
129
  opts.on('-S', '--[no-]strict', *strict_msg) { |setting| set_strict(setting) }
@@ -145,6 +151,8 @@ Specify SEED to reproduce the shuffling from a previous run.
145
151
  opts.on_tail('-h', '--help', "You're looking at it.") { exit_ok(opts.help) }
146
152
  end.parse!
147
153
 
154
+ process_publish_options
155
+
148
156
  @args.map! { |a| "#{a}:#{@options[:lines]}" } if @options[:lines]
149
157
 
150
158
  extract_environment_variables
@@ -182,6 +190,18 @@ Specify SEED to reproduce the shuffling from a previous run.
182
190
 
183
191
  private
184
192
 
193
+ def process_publish_options
194
+ @options[:publish_enabled] = true if truthy_string?(ENV['CUCUMBER_PUBLISH_ENABLED']) || ENV['CUCUMBER_PUBLISH_TOKEN']
195
+ @options[:formats] << publisher if @options[:publish_enabled]
196
+
197
+ @options[:publish_quiet] = true if truthy_string?(ENV['CUCUMBER_PUBLISH_QUIET'])
198
+ end
199
+
200
+ def truthy_string?(str)
201
+ return false if str.nil?
202
+ str !~ /^(false|no|0)$/i
203
+ end
204
+
185
205
  def color_msg
186
206
  [
187
207
  'Whether or not to use ANSI color in the output. Cucumber decides',
@@ -316,7 +336,7 @@ Specify SEED to reproduce the shuffling from a previous run.
316
336
  'option is specified; all loading becomes explicit.',
317
337
  'Files in directories named "support" are still always',
318
338
  'loaded first when their parent directories are',
319
- 'required or if the "support" directoires themselves are',
339
+ 'required or if the "support" directories themselves are',
320
340
  'explicitly required.',
321
341
  'This option can be specified multiple times.'
322
342
  ]
@@ -348,7 +368,13 @@ Specify SEED to reproduce the shuffling from a previous run.
348
368
  end
349
369
 
350
370
  def require_jars(jars)
351
- Dir["#{jars}/**/*.jar"].each { |jar| require jar }
371
+ Dir["#{jars}/**/*.jar"].sort.each { |jar| require jar }
372
+ end
373
+
374
+ def publisher
375
+ url = CUCUMBER_PUBLISH_URL
376
+ url += %( -H "Authorization: Bearer #{ENV['CUCUMBER_PUBLISH_TOKEN']}") if ENV['CUCUMBER_PUBLISH_TOKEN']
377
+ ['message', {}, url]
352
378
  end
353
379
 
354
380
  def language(lang)
@@ -415,6 +441,7 @@ Specify SEED to reproduce the shuffling from a previous run.
415
441
  end
416
442
 
417
443
  def shut_up
444
+ @options[:publish_quiet] = true
418
445
  @options[:snippets] = false
419
446
  @options[:source] = false
420
447
  @options[:duration] = false
@@ -62,6 +62,14 @@ module Cucumber
62
62
  @options[:dry_run]
63
63
  end
64
64
 
65
+ def publish_enabled?
66
+ @options[:publish_enabled]
67
+ end
68
+
69
+ def publish_quiet?
70
+ @options[:publish_quiet]
71
+ end
72
+
65
73
  def fail_fast?
66
74
  @options[:fail_fast]
67
75
  end
@@ -197,14 +205,12 @@ module Cucumber
197
205
 
198
206
  def formatter_factories
199
207
  formats.map do |format, formatter_options, path_or_io|
200
- begin
201
- factory = formatter_class(format)
202
- yield factory,
203
- formatter_options,
204
- path_or_io
205
- rescue Exception => e # rubocop:disable Lint/RescueException
206
- raise e, "#{e.message}\nError creating formatter: #{format}", e.backtrace
207
- end
208
+ factory = formatter_class(format)
209
+ yield factory,
210
+ formatter_options,
211
+ path_or_io
212
+ rescue Exception => e # rubocop:disable Lint/RescueException
213
+ raise e, "#{e.message}\nError creating formatter: #{format}", e.backtrace
208
214
  end
209
215
  end
210
216
 
@@ -256,6 +262,7 @@ module Cucumber
256
262
  strict: Cucumber::Core::Test::Result::StrictConfiguration.new,
257
263
  require: [],
258
264
  dry_run: false,
265
+ publish_quiet: false,
259
266
  fail_fast: false,
260
267
  formats: [],
261
268
  excludes: [],
@@ -41,7 +41,7 @@ module Cucumber
41
41
 
42
42
  module ForDevelopers
43
43
  def self.call(_message, _method, remove_after_version)
44
- raise "This method is due for removal after version #{remove_after_version}" if Cucumber::VERSION > remove_after_version
44
+ raise "This method is due for removal after version #{remove_after_version}" if Cucumber::VERSION >= remove_after_version
45
45
  end
46
46
  end
47
47
 
@@ -11,7 +11,7 @@ module Cucumber
11
11
  begin
12
12
  raise new(with_prefix(step_name)) # rubocop:disable Style/RaiseArgs
13
13
  rescue StandardError => e
14
- return e
14
+ e
15
15
  end
16
16
  end
17
17
 
@@ -136,7 +136,6 @@ module Cucumber
136
136
 
137
137
  private
138
138
 
139
- # rubocop:disable Metrics/PerceivedComplexity
140
139
  def process_scenario_container(container, original_previous_node)
141
140
  container.children.each do |child|
142
141
  previous_node = original_previous_node
@@ -158,7 +157,6 @@ module Cucumber
158
157
  end
159
158
  end
160
159
  end
161
- # rubocop:enable Metrics/PerceivedComplexity
162
160
  end
163
161
  end
164
162
  end
@@ -8,7 +8,7 @@ module Cucumber
8
8
  include Io
9
9
 
10
10
  def initialize(config)
11
- @io = ensure_io(config.out_stream)
11
+ @io = ensure_io(config.out_stream, config.error_stream)
12
12
  @html_formatter = Cucumber::HTMLFormatter::Formatter.new(@io)
13
13
  @html_formatter.write_pre_message
14
14
 
@@ -1,80 +1,82 @@
1
1
  require 'net/http'
2
2
  require 'tempfile'
3
+ require 'shellwords'
3
4
 
4
5
  module Cucumber
5
6
  module Formatter
6
7
  class HTTPIO
7
8
  class << self
8
9
  # Returns an IO that will write to a HTTP request's body
9
- def open(url, https_verify_mode = nil)
10
+ # https_verify_mode can be set to OpenSSL::SSL::VERIFY_NONE
11
+ # to ignore unsigned certificate - setting to nil will verify the certificate
12
+ def open(url, https_verify_mode = nil, reporter = nil)
10
13
  @https_verify_mode = https_verify_mode
11
14
  uri, method, headers = CurlOptionParser.parse(url)
12
- IOHTTPBuffer.new(uri, method, headers, https_verify_mode)
15
+ IOHTTPBuffer.new(uri, method, headers, https_verify_mode, reporter)
13
16
  end
14
17
  end
15
18
  end
16
19
 
17
20
  class CurlOptionParser
18
21
  def self.parse(options)
19
- chunks = options.split(/\s/).compact
20
- http_method = 'PUT'
21
- url = chunks[0]
22
- headers = ''
23
-
24
- last_flag = nil
25
- chunks.each do |chunk|
26
- if ['-X', '--request'].include?(chunk)
27
- last_flag = '-X'
28
- next
29
- end
22
+ args = Shellwords.split(options)
30
23
 
31
- if chunk == '-H'
32
- last_flag = '-H'
33
- next
34
- end
35
-
36
- if last_flag == '-X'
37
- http_method = chunk
38
- last_flag = nil
24
+ url = nil
25
+ http_method = 'PUT'
26
+ headers = {}
27
+
28
+ until args.empty?
29
+ arg = args.shift
30
+ case arg
31
+ when '-X', '--request'
32
+ http_method = remove_arg_for(args, arg)
33
+ when '-H'
34
+ header_arg = remove_arg_for(args, arg)
35
+ headers = headers.merge(parse_header(header_arg))
36
+ else
37
+ raise StandardError, "#{options} was not a valid curl command. Can't set url to #{arg} it is already set to #{url}" if url
38
+ url = arg
39
39
  end
40
-
41
- headers += chunk if last_flag == '-H'
42
40
  end
41
+ raise StandardError, "#{options} was not a valid curl command" unless url
43
42
 
44
43
  [
45
44
  url,
46
45
  http_method,
47
- make_headers(headers)
46
+ headers
48
47
  ]
49
48
  end
50
49
 
51
- def self.make_headers(headers)
52
- hash_headers = {}
53
- str_scanner = /("(?<key>[^":]+)\s*:\s*(?<value>[^":]+)")|('(?<key1>[^':]+)\s*:\s*(?<value1>[^':]+)')/
54
-
55
- headers.scan(str_scanner) do |header|
56
- header = header.compact!
57
- hash_headers[header[0]] = header[1]&.strip
58
- end
50
+ def self.remove_arg_for(args, arg)
51
+ return args.shift unless args.empty?
52
+ raise StandardError, "Missing argument for #{arg}"
53
+ end
59
54
 
60
- hash_headers
55
+ def self.parse_header(header_arg)
56
+ parts = header_arg.split(':', 2)
57
+ raise StandardError, "#{header_arg} was not a valid header" unless parts.length == 2
58
+ { parts[0].strip => parts[1].strip }
61
59
  end
62
60
  end
63
61
 
64
62
  class IOHTTPBuffer
65
63
  attr_reader :uri, :method, :headers
66
64
 
67
- def initialize(uri, method, headers = {}, https_verify_mode = nil)
65
+ def initialize(uri, method, headers = {}, https_verify_mode = nil, reporter = nil)
68
66
  @uri = URI(uri)
69
67
  @method = method
70
68
  @headers = headers
71
69
  @write_io = Tempfile.new('cucumber', encoding: 'UTF-8')
72
70
  @https_verify_mode = https_verify_mode
71
+ @reporter = reporter || NoReporter.new
73
72
  end
74
73
 
75
74
  def close
76
- post_content(@uri, @method, @headers)
75
+ response = send_content(@uri, @method, @headers)
76
+ @reporter.report(response.body)
77
77
  @write_io.close
78
+ return if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPRedirection)
79
+ raise StandardError, "request to #{uri} failed with status #{response.code}"
78
80
  end
79
81
 
80
82
  def write(data)
@@ -91,8 +93,8 @@ module Cucumber
91
93
 
92
94
  private
93
95
 
94
- def post_content(uri, method, headers, attempt = 10)
95
- content = @write_io
96
+ def send_content(uri, method, headers, attempt = 10)
97
+ content = (method == 'GET' ? StringIO.new : @write_io)
96
98
  http = build_client(uri, @https_verify_mode)
97
99
 
98
100
  raise StandardError, "request to #{uri} failed (too many redirections)" if attempt <= 0
@@ -115,13 +117,12 @@ module Cucumber
115
117
  end
116
118
 
117
119
  case response
118
- when Net::HTTPSuccess
119
- response
120
+ when Net::HTTPAccepted
121
+ send_content(URI(response['Location']), 'PUT', {}, attempt - 1) if response['Location']
120
122
  when Net::HTTPRedirection
121
- post_content(URI(response['Location']), method, headers, attempt - 1)
122
- else
123
- raise StandardError, "request to #{uri} failed with status #{response.code}"
123
+ send_content(URI(response['Location']), method, headers, attempt - 1)
124
124
  end
125
+ response
125
126
  end
126
127
 
127
128
  def build_request(uri, method, headers)
@@ -5,6 +5,7 @@ module Cucumber
5
5
  module Interceptor
6
6
  class Pipe
7
7
  attr_reader :pipe
8
+
8
9
  def initialize(pipe)
9
10
  @pipe = pipe
10
11
  @buffer = StringIO.new
@@ -31,7 +32,7 @@ module Cucumber
31
32
  end
32
33
 
33
34
  def method_missing(method, *args, &blk)
34
- @pipe.send(method, *args, &blk) || super
35
+ @pipe.respond_to?(method) ? @pipe.send(method, *args, &blk) : super
35
36
  end
36
37
 
37
38
  def respond_to_missing?(method, include_private = false)
@@ -62,10 +63,10 @@ module Cucumber
62
63
  case pipe
63
64
  when :stderr
64
65
  $stderr = new($stderr)
65
- return $stderr
66
+ $stderr
66
67
  when :stdout
67
68
  $stdout = new($stdout)
68
- return $stdout
69
+ $stdout
69
70
  end
70
71
  end
71
72
  end
@@ -1,34 +1,70 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cucumber/formatter/http_io'
4
+ require 'cucumber/formatter/url_reporter'
5
+ require 'cucumber/cli/options'
4
6
 
5
7
  module Cucumber
6
8
  module Formatter
7
9
  module Io
8
10
  module_function
9
11
 
10
- def ensure_io(path_or_url_or_io)
12
+ def ensure_io(path_or_url_or_io, error_stream)
11
13
  return nil if path_or_url_or_io.nil?
12
- return path_or_url_or_io if path_or_url_or_io.respond_to?(:write)
13
- io = if path_or_url_or_io.match(%r{^https?://})
14
- HTTPIO.open(path_or_url_or_io)
14
+ return path_or_url_or_io if io?(path_or_url_or_io)
15
+
16
+ io = if url?(path_or_url_or_io)
17
+ url = path_or_url_or_io
18
+ reporter = url.start_with?(Cucumber::Cli::Options::CUCUMBER_PUBLISH_URL) ? URLReporter.new(error_stream) : NoReporter.new
19
+ HTTPIO.open(url, nil, reporter)
15
20
  else
16
21
  File.open(path_or_url_or_io, Cucumber.file_mode('w'))
17
22
  end
18
- at_exit do
19
- unless io.closed?
20
- io.flush
21
- io.close
23
+ @io_objects_to_close ||= []
24
+ @io_objects_to_close.push(io)
25
+ io
26
+ end
27
+
28
+ module ClassMethods
29
+ def new(*args, &block)
30
+ instance = super
31
+
32
+ config = args[0]
33
+ if config.respond_to? :on_event
34
+ config.on_event :test_run_finished do
35
+ ios = instance.instance_variable_get(:@io_objects_to_close) || []
36
+ ios.each do |io|
37
+ at_exit do
38
+ unless io.closed?
39
+ io.flush
40
+ io.close
41
+ end
42
+ end
43
+ end
44
+ end
22
45
  end
46
+
47
+ instance
23
48
  end
24
- io
49
+ end
50
+
51
+ def self.included(formatter_class)
52
+ formatter_class.extend(ClassMethods)
53
+ end
54
+
55
+ def io?(path_or_url_or_io)
56
+ path_or_url_or_io.respond_to?(:write)
57
+ end
58
+
59
+ def url?(path_or_url_or_io)
60
+ path_or_url_or_io.match(%r{^https?://})
25
61
  end
26
62
 
27
63
  def ensure_file(path, name)
28
64
  raise "You *must* specify --out FILE for the #{name} formatter" unless String == path.class
29
65
  raise "I can't write #{name} to a directory - it has to be a file" if File.directory?(path)
30
66
  raise "I can't write #{name} to a file in the non-existing directory #{File.dirname(path)}" unless File.directory?(File.dirname(path))
31
- ensure_io(path)
67
+ ensure_io(path, nil)
32
68
  end
33
69
 
34
70
  def ensure_dir(path, name)