hiptest-publisher 1.31.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +310 -0
  3. data/LICENSE +1 -2
  4. data/README.md +39 -22
  5. data/bin/hiptest-publisher +16 -8
  6. data/config/locales/en.yml +17 -14
  7. data/lib/config/cucumber-typescript.conf +41 -41
  8. data/lib/config/cucumber_legacy-groovy.conf +40 -0
  9. data/lib/config/cucumber_legacy-java.conf +24 -0
  10. data/lib/config/cucumber_legacy-typescript.conf +41 -0
  11. data/lib/hiptest-publisher.rb +5 -7
  12. data/lib/hiptest-publisher/client.rb +61 -10
  13. data/lib/hiptest-publisher/formatters/console_formatter.rb +41 -11
  14. data/lib/hiptest-publisher/formatters/reporter.rb +14 -0
  15. data/lib/hiptest-publisher/handlebars_helper.rb +1 -1
  16. data/lib/hiptest-publisher/options_parser.rb +46 -9
  17. data/lib/hiptest-publisher/renderer.rb +5 -1
  18. data/lib/hiptest-publisher/renderer_addons/gherkin_addon.rb +21 -0
  19. data/lib/templates/common/_gherkin_typed_pattern.hbs +1 -0
  20. data/lib/templates/cucumber/groovy/step-definitions/actionword.hbs +1 -1
  21. data/lib/templates/cucumber/groovy/step-definitions/actionwords.hbs +3 -2
  22. data/lib/templates/cucumber/groovy/step-definitions/library.hbs +3 -2
  23. data/lib/templates/cucumber/groovy/step-definitions/libraryactionword.hbs +1 -1
  24. data/lib/templates/cucumber/java/actionword.hbs +1 -1
  25. data/lib/templates/cucumber/java/actionwords.hbs +2 -2
  26. data/lib/templates/cucumber/typescript/actionword.hbs +1 -1
  27. data/lib/templates/cucumber/typescript/libraryactionword.hbs +1 -1
  28. data/lib/templates/cucumber_legacy/groovy/step-definitions/actionword.hbs +5 -0
  29. data/lib/templates/cucumber_legacy/groovy/step-definitions/actionwords.hbs +10 -0
  30. data/lib/templates/cucumber_legacy/groovy/step-definitions/library.hbs +10 -0
  31. data/lib/templates/cucumber_legacy/groovy/step-definitions/libraryactionword.hbs +5 -0
  32. data/lib/templates/cucumber_legacy/java/actionword.hbs +6 -0
  33. data/lib/templates/cucumber_legacy/java/actionwords.hbs +12 -0
  34. data/lib/templates/cucumber_legacy/typescript/actionword.hbs +5 -0
  35. data/lib/templates/cucumber_legacy/typescript/libraryactionword.hbs +5 -0
  36. data/lib/templates/gherkin/scenarios.hbs +1 -1
  37. data/lib/templates/groovy/_scenario.hbs +1 -1
  38. metadata +64 -41
@@ -16,13 +16,21 @@ require 'ruby_version'
16
16
  require 'hiptest-publisher/i18n'
17
17
  require 'hiptest-publisher/utils'
18
18
 
19
- # Ensure ruby version >= 2
20
- if RubyVersion < '2.1.0'
21
- STDERR.puts(I18n.t('ruby_version.required_version', version: '2.1.0'))
19
+ # Ensure ruby version >= 2.5
20
+ if RubyVersion < '2.5.0'
21
+ STDERR.puts(I18n.t('ruby_version.required_version', version: '2.5.0'))
22
22
  STDERR.puts(I18n.t('ruby_version.current_version', engine: RUBY_ENGINE, version: RUBY_VERSION))
23
23
  STDERR.puts(I18n.t('ruby_version.use_more_recent'))
24
24
 
25
- if RubyVersion.is? 2.0
25
+ if RubyVersion.is? 2.4
26
+ STDERR.puts(I18n.('ruby_version.support_ended', version: '2.4.0', year: '2020', month: '03', day: '31'))
27
+ elsif RubyVersion.is? 2.3
28
+ STDERR.puts(I18n.('ruby_version.support_ended', version: '2.3.0', year: '2019', month: '03', day: '31'))
29
+ elsif RubyVersion.is? 2.2
30
+ STDERR.puts(I18n.('ruby_version.support_ended', version: '2.2.0', year: '2018', month: '03', day: '31'))
31
+ elsif RubyVersion.is? 2.1
32
+ STDERR.puts(I18n.('ruby_version.support_ended', version: '2.1.0', year: '2017', month: '04', day: '01'))
33
+ elsif RubyVersion.is? 2.0
26
34
  STDERR.puts(I18n.('ruby_version.support_ended', version: '2.0.0', year: '2016', month: '02', day: '24'))
27
35
  elsif RubyVersion.is? '1.9.3'
28
36
  STDERR.puts(I18n.('ruby_version.support_ended', version: '1.9.3', year: '2015', month: '02', day: '23'))
@@ -32,16 +40,16 @@ if RubyVersion < '2.1.0'
32
40
  exit 1
33
41
  end
34
42
 
35
- if RubyVersion < '2.3'
43
+ if RubyVersion < '2.4' # TODO: deprecate ruby 2.5 (eol 2021-03-31)
36
44
  STDERR.puts(I18n.t('ruby_version.current_version', engine: RUBY_ENGINE, version: RUBY_VERSION))
37
- STDERR.puts(I18n.t('ruby_version.deprecation_warning', version: '2.2'))
38
- STDERR.puts(I18n.t('ruby_version.support_ended', version: '2.2', year: '2018', month: '03', day: '31'))
45
+ STDERR.puts(I18n.t('ruby_version.deprecation_warning', version: '2.3'))
46
+ STDERR.puts(I18n.t('ruby_version.support_ended', version: '2.3', year: '2019', month: '03', day: '31'))
39
47
  end
40
48
 
41
49
  require 'hiptest-publisher'
42
50
  begin
43
51
  require 'pry' # only available in development
44
- rescue LoadError
52
+ rescue StandardError, LoadError
45
53
  end
46
54
 
47
55
  Hiptest::Publisher.new(ARGV).run
@@ -66,7 +66,7 @@ en:
66
66
  up_to_date: Your current install of hiptest-publisher (%{current}) is up-to-date.
67
67
  default: default
68
68
  errors:
69
- api_error: HipTest API returned error %{code}
69
+ api_error: CucumberStudio API returned error %{code}
70
70
  cli_options:
71
71
  actionwords_signature_directory: 'Bad Action Words signature file: the file "%{path}" is a directory'
72
72
  filter_status_without_test_run: |
@@ -86,7 +86,7 @@ en:
86
86
 
87
87
  Found: %{incorrect_value}
88
88
  invalid_tag_value_list: |
89
- %{option} should be a list of comma separated tags in HipTest
89
+ %{option} should be a list of comma separated tags from CucumberStudio
90
90
 
91
91
  Found: %{incorrect_value}
92
92
  invalid_test_run_id: 'Invalid format --test-run-id="%{test_run_id}": the test run id must be numeric'
@@ -100,7 +100,7 @@ en:
100
100
  missing_token: |
101
101
  Missing argument --token: you must specify project secret token with --token=<project-token>
102
102
 
103
- The project secret token can be found on HipTest in the settings section, under
103
+ The project secret token can be found on CucumberStudio in the settings section, under
104
104
  'Test code generation'. It is a sequence of numbers uniquely identifying your
105
105
  project.
106
106
 
@@ -128,9 +128,9 @@ en:
128
128
  no_test_runs: 'No matching test run found: this project does not have any test runs.'
129
129
  project_not_found: No project found with this secret token.
130
130
  template_not_found: no template with name %{template_name} in dirs %{dirs}
131
- test_run_list_unavailable: Cannot get the list of available test runs from HipTest. Try using --test-run-id instead of --test-run-name
131
+ test_run_list_unavailable: Cannot get the list of available test runs from CucumberStudio. Try using --test-run-id instead of --test-run-name
132
132
  exporting_file: Exporting %{name}
133
- fetching_data: Fetching data from HipTest
133
+ fetching_data: Fetching data from CucumberStudio
134
134
  using_cached_data: Using cached data from previous export
135
135
  caching_data: Caching data
136
136
  using_cache: "Using cache: %{full_path}"
@@ -148,7 +148,7 @@ en:
148
148
  hiptest-publisher --language=%{language} --only=%{first},%{second}
149
149
  description: |2
150
150
 
151
- Exports tests from HipTest for automation.
151
+ Exports tests from CucumberStudio for automation.
152
152
 
153
153
  Specific options:
154
154
  header: 'Usage: hiptest-publisher [options]'
@@ -168,6 +168,7 @@ en:
168
168
  aw_renamed: Output signatures of renamed action words
169
169
  aw_signature_changed: Output signatures of action words for which signature changed
170
170
  check_version: Check if a new release of hiptest-publisher is available
171
+ color: Force [un]use of ANSI color in text output
171
172
  config: Configuration file
172
173
  empty_folders: Export empty folders
173
174
  execution_environment: Name of the execution environment
@@ -182,9 +183,9 @@ en:
182
183
  framework: Test framework to use
183
184
  global_failure_on_missing_reports: When there is no results file to push, report a global failure
184
185
  help: Show this message
185
- http_proxy: 'Specify your http proxy to access Hiptest'
186
- keep_filenames: 'Keep the same name as in HipTest for the test files (note: may cause encoding issues)'
187
- keep_foldernames: 'Keep the same name as in HipTest for the folders (note: may cause encoding issues)'
186
+ http_proxy: 'Specify your http proxy to access CucumberStudio'
187
+ keep_filenames: 'Keep the same name as in CucumberStudio for the test files (note: may cause encoding issues)'
188
+ keep_foldernames: 'Keep the same name as in CucumberStudio for the folders (note: may cause encoding issues)'
188
189
  language: Target language
189
190
  languages_help: Show languages and framework options
190
191
  leafless_export: Use only last level action word
@@ -194,25 +195,27 @@ en:
194
195
  only: Restrict export to given file categories (--only=list to list them)
195
196
  output_directory: Output directory
196
197
  overriden_templates: Folder for overriden templates
198
+ overriden_language_configs: Folder for overriden language configs
197
199
  parameter_delimiter: Parameter delimiter (for Gherkin based export only)
198
200
  parent_folder_tags: 'Export tags from parent folders (note: if set to false, those tags are never rendered. Only available for Gherkin base exports)'
199
201
  push: Push a results file to the server
200
202
  push_format: Format of the test results (cucumber-json, junit, nunit, robot, tap)
201
203
  site: Site to fetch from
202
- sort: 'Sorting of tests in output: id will sort them by age, order will keep the same order than in hiptest (only with --with-folders option, will fallback to id otherwise), alpha will sort them by name'
204
+ sort: 'Sorting of tests in output: id will sort them by age, order will keep the same order as in CucumberStudio (only with --with-folders option, will fallback to id otherwise), alpha will sort them by name'
203
205
  split_scenarios: Export each scenario in a single file (except for Gherkin based languages)
204
206
  test_run_id: Export data from a test run identified by its id
205
207
  test_run_name: Export data from a test run identified by its name
206
208
  tests_only: "(deprecated) alias for --only=tests"
207
209
  token: Secret token (available in your project settings)
208
- uids: 'Export UIDs (note: can be disabled only for Gherkin-based exports, may cause issue when pushing results back)'
210
+ uids: 'Export UIDs for Gherkin-based exports (note: disabled by default, enabled when specifying test run, disabling it may cause issue when pushing results back into test run)'
209
211
  verbose: Run verbosely
210
212
  with_dataset_names: 'Export dataset name when creating feature files (note: available only for Gherkin-based exports)'
211
213
  with_folders: Use folders hierarchy to export files in respective directories
212
214
  without: Exclude file categories from import (--only=list to list them)
213
- xml_file: XML file to use instead of fetching it from HipTest
214
- cache_dir: "Path to the directory to store cache of Hiptest data"
215
- cache_duration: "Validity of the Hiptest data cache in seconds"
215
+ xml_file: XML file to use instead of fetching it from CucumberStudio
216
+ cache_dir: "Path to the directory to store cache of CucumberStudio data"
217
+ cache_duration: "Validity of the CucumberStudio data cache in seconds"
218
+ indentation: Customize indentation
216
219
  overwrite:
217
220
  ask_confirmation: 'File %{path} exists, do you want to overwrite it? [y/N] '
218
221
  warning_message: File %{path} already exists, skipping. Use --force to overwrite it.
@@ -1,41 +1,41 @@
1
- [_common]
2
- indentation = ' '
3
- fallback_template = 'empty'
4
-
5
- [features]
6
- node_name = folders
7
- template_dirs = gherkin/inlined_uids, gherkin, common
8
- named_filename = '%s.feature'
9
- indentation = ' '
10
- renderer_addons = 'GherkinAddon'
11
-
12
- [step_definitions]
13
- node_name = actionwords
14
- template_dirs = cucumber/typescript, javascript, common
15
- filename = 'step_definitions.ts'
16
- naming_convention = 'camelize_lower'
17
- call_prefix = 'actionwords'
18
- renderer_addons = 'GherkinAddon'
19
-
20
- [step_definitions_library]
21
- node_name = libraries
22
- template_dirs = cucumber/typescript, javascript, common
23
- named_filename = 'steps_%s.ts'
24
- naming_convention = 'camelize_lower'
25
- call_prefix = 'actionwords'
26
- renderer_addons = 'GherkinAddon'
27
-
28
- [actionwords]
29
- template_dirs = typescript, javascript, common
30
- filename = 'actionwords.ts'
31
- naming_convention = 'camelize_lower'
32
-
33
-
34
- [library]
35
- template_dirs = typescript, javascript, common
36
- filename = 'actionword_library.ts'
37
-
38
- [libraries]
39
- template_dirs = typescript, javascript, common
40
- named_filename = '%s_library.ts'
41
- filename_convention = 'underscore'
1
+ [_common]
2
+ indentation = ' '
3
+ fallback_template = 'empty'
4
+
5
+ [features]
6
+ node_name = folders
7
+ template_dirs = gherkin/inlined_uids, gherkin, common
8
+ named_filename = '%s.feature'
9
+ indentation = ' '
10
+ renderer_addons = 'GherkinAddon'
11
+
12
+ [step_definitions]
13
+ node_name = actionwords
14
+ template_dirs = cucumber/typescript, javascript, common
15
+ filename = 'step_definitions.ts'
16
+ naming_convention = 'camelize_lower'
17
+ call_prefix = 'actionwords'
18
+ renderer_addons = 'GherkinAddon'
19
+
20
+ [step_definitions_library]
21
+ node_name = libraries
22
+ template_dirs = cucumber/typescript, javascript, common
23
+ named_filename = 'steps_%s.ts'
24
+ naming_convention = 'camelize_lower'
25
+ call_prefix = 'actionwords'
26
+ renderer_addons = 'GherkinAddon'
27
+
28
+ [actionwords]
29
+ template_dirs = typescript, javascript, common
30
+ filename = 'actionwords.ts'
31
+ naming_convention = 'camelize_lower'
32
+
33
+
34
+ [library]
35
+ template_dirs = typescript, javascript, common
36
+ filename = 'actionword_library.ts'
37
+
38
+ [libraries]
39
+ template_dirs = typescript, javascript, common
40
+ named_filename = '%s_library.ts'
41
+ filename_convention = 'underscore'
@@ -0,0 +1,40 @@
1
+ [_common]
2
+ package = 'com.example'
3
+ fallback_template = 'empty'
4
+ indentation = ' '
5
+ dirname_convention = 'underscore'
6
+ filename_convention = 'camelize'
7
+ naming_convention = 'camelize_lower'
8
+
9
+ [features]
10
+ node_name = folders
11
+ template_dirs = gherkin/inlined_uids, gherkin/java, gherkin, common
12
+ named_filename = '%s.feature'
13
+ indentation = ' '
14
+ renderer_addons = 'GherkinAddon'
15
+
16
+ [step_definitions]
17
+ node_name = actionwords
18
+ template_dirs = cucumber_legacy/groovy/step-definitions, cucumber/groovy/step-definitions, groovy, java, common
19
+ filename = 'StepDefinitions.groovy'
20
+ call_prefix = 'actionwords'
21
+ renderer_addons = 'GherkinAddon'
22
+
23
+ [step_definitions_library]
24
+ node_name = libraries
25
+ call_prefix = 'actionwords'
26
+ template_dirs = cucumber_legacy/groovy/step-definitions, cucumber/groovy/step-definitions, groovy, java, common
27
+ named_filename = 'StepDefinitions%s.groovy'
28
+ renderer_addons = 'GherkinAddon'
29
+
30
+ [actionwords]
31
+ template_dirs = groovy, java, common
32
+ filename = 'Actionwords.groovy'
33
+
34
+ [library]
35
+ template_dirs = groovy, java, common
36
+ filename = 'ActionwordLibrary.groovy'
37
+
38
+ [libraries]
39
+ template_dirs = groovy, java, common
40
+ named_filename = '%sLibrary.groovy'
@@ -0,0 +1,24 @@
1
+ [_common]
2
+ package = 'com.example'
3
+ indentation = ' '
4
+ fallback_template = 'empty'
5
+
6
+ [features]
7
+ node_name = folders
8
+ template_dirs = gherkin/inlined_uids, gherkin/java, gherkin, common
9
+ named_filename = '%s.feature'
10
+ indentation = ' '
11
+ renderer_addons = 'GherkinAddon'
12
+
13
+ [step_definitions]
14
+ node_name = actionwords
15
+ template_dirs = cucumber_legacy/java, cucumber/java, java, common
16
+ filename = 'StepDefinitions.java'
17
+ naming_convention = 'camelize_lower'
18
+ call_prefix = 'actionwords'
19
+ renderer_addons = 'GherkinAddon'
20
+
21
+ [actionwords]
22
+ template_dirs = cucumber_legacy/java/actionwords, cucumber/java/actionwords, java, common
23
+ filename = 'Actionwords.java'
24
+ naming_convention = 'camelize_lower'
@@ -0,0 +1,41 @@
1
+ [_common]
2
+ indentation = ' '
3
+ fallback_template = 'empty'
4
+
5
+ [features]
6
+ node_name = folders
7
+ template_dirs = gherkin/inlined_uids, gherkin, common
8
+ named_filename = '%s.feature'
9
+ indentation = ' '
10
+ renderer_addons = 'GherkinAddon'
11
+
12
+ [step_definitions]
13
+ node_name = actionwords
14
+ template_dirs = cucumber_legacy/typescript, cucumber/typescript, javascript, common
15
+ filename = 'step_definitions.ts'
16
+ naming_convention = 'camelize_lower'
17
+ call_prefix = 'actionwords'
18
+ renderer_addons = 'GherkinAddon'
19
+
20
+ [step_definitions_library]
21
+ node_name = libraries
22
+ template_dirs = cucumber_legacy/typescript, cucumber/typescript, javascript, common
23
+ named_filename = 'steps_%s.ts'
24
+ naming_convention = 'camelize_lower'
25
+ call_prefix = 'actionwords'
26
+ renderer_addons = 'GherkinAddon'
27
+
28
+ [actionwords]
29
+ template_dirs = typescript, javascript, common
30
+ filename = 'actionwords.ts'
31
+ naming_convention = 'camelize_lower'
32
+
33
+
34
+ [library]
35
+ template_dirs = typescript, javascript, common
36
+ filename = 'actionword_library.ts'
37
+
38
+ [libraries]
39
+ template_dirs = typescript, javascript, common
40
+ named_filename = '%s_library.ts'
41
+ filename_convention = 'underscore'
@@ -83,15 +83,15 @@ module Hiptest
83
83
  end
84
84
 
85
85
  def fetch_xml_file
86
- @client.fetch_project_export
86
+ @client.fetch_project
87
87
  rescue ClientError => err
88
88
  # This should not be an error that needs reporting to an exception monitoring app
89
- puts err.message.yellow
89
+ reporter.show_error(err.message)
90
90
  if @exit_on_bad_arguments == false # means we are embedded in hiptest-publisher
91
91
  raise
92
92
  end
93
93
  rescue => err
94
- puts I18n.t("errors.default").red
94
+ reporter.show_failure(I18n.t("errors.default"))
95
95
  reporter.dump_error(err)
96
96
  end
97
97
 
@@ -113,10 +113,8 @@ module Hiptest
113
113
  return true unless File.file?(path)
114
114
  return true if @cli_options.force_overwrite
115
115
 
116
- if $stdout.isatty
117
- STDOUT.print "\n"
118
- STDOUT.print "[#{"?".yellow}] #{I18n.t('overwrite.ask_confirmation', path: path)}"
119
- answer = $stdin.gets.chomp.downcase.strip
116
+ if $stdout.tty?
117
+ answer = reporter.ask(I18n.t('overwrite.ask_confirmation', path: path))
120
118
  return ['y', 'yes'].include?(answer)
121
119
  else
122
120
  reporter.warning_message(I18n.t('overwrite.warning_message', path: path))
@@ -21,6 +21,9 @@ module Hiptest
21
21
  end
22
22
  end
23
23
 
24
+ class AsyncExportUnavailable < StandardError
25
+ end
26
+
24
27
  class MaximumRedirectionReachedError < StandardError
25
28
  end
26
29
 
@@ -28,10 +31,12 @@ module Hiptest
28
31
 
29
32
  class Client
30
33
  attr_reader :cli_options
34
+ attr_writer :async_options
31
35
 
32
36
  def initialize(cli_options, reporter = nil)
33
37
  @cli_options = cli_options
34
38
  @reporter = reporter || NullReporter.new
39
+ @async_options = { max_attempts: 200, sleep_time_between_attemps: 5 }
35
40
  end
36
41
 
37
42
  def url
@@ -86,7 +91,7 @@ module Hiptest
86
91
  return "?filter_status=#{value}"
87
92
  end
88
93
 
89
- def fetch_project_export
94
+ def fetch_project
90
95
  cached = export_cache.cache_for(url)
91
96
 
92
97
  unless cached.nil?
@@ -95,17 +100,18 @@ module Hiptest
95
100
  end
96
101
  end
97
102
 
98
- @reporter.with_status_message I18n.t(:fetching_data) do
99
- response = send_get_request(url)
100
- if response.code_type == Net::HTTPNotFound
101
- raise ClientError, I18n.t('errors.project_not_found')
102
- end
103
-
104
- content = response.body
105
- export_cache.cache(url, content)
103
+ content = @reporter.with_status_message I18n.t(:fetching_data) do
104
+ break fetch_project_export if use_synchronous_fetch?
106
105
 
107
- return content
106
+ begin
107
+ fetch_project_export_asynchronously
108
+ rescue AsyncExportUnavailable
109
+ fetch_project_export
110
+ end
108
111
  end
112
+
113
+ export_cache.cache(url, content)
114
+ content
109
115
  end
110
116
 
111
117
  def available_test_runs
@@ -136,6 +142,50 @@ module Hiptest
136
142
 
137
143
  private
138
144
 
145
+ def use_synchronous_fetch?
146
+ cli_options.push? || cli_options.leafless_export || test_run_id
147
+ end
148
+
149
+ def fetch_project_export
150
+ response = send_get_request(url)
151
+ if response.code_type == Net::HTTPNotFound
152
+ raise ClientError, I18n.t('errors.project_not_found')
153
+ end
154
+
155
+ response.body
156
+ end
157
+
158
+ def fetch_project_export_asynchronously
159
+ publication_export_id = fetch_asynchronous_publication_export_id
160
+ url = "#{base_publication_path}/async_project/#{publication_export_id}"
161
+ response = nil
162
+
163
+ # the server should respond with a timeout after 15 minutes
164
+ # it is about 180 attempts with a sleep time of 5 seconds between each requests
165
+ sleep_time_between_attemps = @async_options[:sleep_time_between_attemps]
166
+ max_attempts = @async_options[:max_attempts]
167
+
168
+ loop do
169
+ response = send_get_request(url)
170
+
171
+ break unless response.code_type == Net::HTTPAccepted
172
+ break if 0 >= (max_attempts -= 1)
173
+
174
+ sleep(sleep_time_between_attemps)
175
+ end
176
+
177
+ response.body
178
+ end
179
+
180
+ def fetch_asynchronous_publication_export_id
181
+ url = "#{base_publication_path}/async_project#{project_export_filters}"
182
+ response = send_post_request(url)
183
+
184
+ raise AsyncExportUnavailable if response.code_type == Net::HTTPNotFound
185
+
186
+ JSON.parse(response.body)['publication_export_id']
187
+ end
188
+
139
189
  def export_cache
140
190
  @export_cache ||= ExportCache.new(
141
191
  @cli_options.cache_dir,
@@ -243,6 +293,7 @@ module Hiptest
243
293
  response = http.request(request)
244
294
 
245
295
  raise RedirectionError.new("Got redirected", response['location']) if response.is_a?(Net::HTTPRedirection)
296
+
246
297
  response
247
298
  end
248
299
  end