hiptest-publisher 0.13.2 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/hiptest-publisher.rb +29 -17
- data/lib/hiptest-publisher/cli_options_checker.rb +1 -1
- data/lib/hiptest-publisher/client.rb +115 -0
- data/lib/hiptest-publisher/formatters/console_formatter.rb +41 -0
- data/lib/hiptest-publisher/formatters/reporter.rb +15 -0
- data/lib/hiptest-publisher/options_parser.rb +20 -1
- data/lib/hiptest-publisher/utils.rb +0 -74
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a3a011230146c49dd11289311b1adb4c1f3ec07
|
4
|
+
data.tar.gz: 5af587b772286fdd2dda10b763ba57f16064589e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3c8541ccec13d9c02f1160dbc1bfd1d5a985e0c01821dbbd0847d922356d766bd3c7dab148788b9acd4b6d2080e1e2ad2dfba4954399cc11ae221bbc3e704a7
|
7
|
+
data.tar.gz: 48da00daa178db580278ff93c4c94bcd723903b7cb8e4b19fee23685335dc26c94b22d7d2580c85ac0c788bdaae0eafa5914e4eb02e3c834671354a21ada66dd
|
data/lib/hiptest-publisher.rb
CHANGED
@@ -5,6 +5,7 @@ require 'yaml'
|
|
5
5
|
|
6
6
|
require 'hiptest-publisher/formatters/reporter'
|
7
7
|
require 'hiptest-publisher/cli_options_checker'
|
8
|
+
require 'hiptest-publisher/client'
|
8
9
|
require 'hiptest-publisher/string'
|
9
10
|
require 'hiptest-publisher/utils'
|
10
11
|
require 'hiptest-publisher/options_parser'
|
@@ -24,12 +25,12 @@ module Hiptest
|
|
24
25
|
def initialize(args, listeners: nil, exit_on_bad_arguments: true)
|
25
26
|
@reporter = Reporter.new(listeners)
|
26
27
|
@cli_options = OptionsParser.parse(args, reporter)
|
28
|
+
@client = Hiptest::Client.new(@cli_options, reporter)
|
27
29
|
# pass false to prevent hiptest-publisher from exiting, useful when used embedded
|
28
30
|
@exit_on_bad_arguments = exit_on_bad_arguments
|
29
31
|
end
|
30
32
|
|
31
33
|
def run
|
32
|
-
puts "URL: #{make_url(@cli_options)}".white if @cli_options.verbose
|
33
34
|
begin
|
34
35
|
CliOptionsChecker.new(@cli_options, reporter).check!
|
35
36
|
rescue CliOptionError => e
|
@@ -43,16 +44,12 @@ module Hiptest
|
|
43
44
|
return
|
44
45
|
end
|
45
46
|
|
46
|
-
if push?
|
47
|
+
if @cli_options.push?
|
47
48
|
post_results
|
48
49
|
return
|
49
50
|
end
|
50
51
|
|
51
|
-
|
52
|
-
xml = IO.read(@cli_options.xml_file)
|
53
|
-
else
|
54
|
-
xml = fetch_xml_file
|
55
|
-
end
|
52
|
+
xml = get_xml_file
|
56
53
|
return if xml.nil?
|
57
54
|
|
58
55
|
@project = get_project(xml)
|
@@ -70,17 +67,32 @@ module Hiptest
|
|
70
67
|
export
|
71
68
|
end
|
72
69
|
|
70
|
+
def get_xml_file
|
71
|
+
if @cli_options.xml_file
|
72
|
+
IO.read(@cli_options.xml_file)
|
73
|
+
else
|
74
|
+
fetch_xml_file
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
73
78
|
def fetch_xml_file
|
74
|
-
with_status_message "Fetching data from Hiptest" do
|
75
|
-
fetch_project_export
|
79
|
+
reporter.with_status_message "Fetching data from Hiptest" do
|
80
|
+
@client.fetch_project_export
|
81
|
+
end
|
82
|
+
rescue ClientError => err
|
83
|
+
# This should not be an error that needs reporting to an exception monitoring app
|
84
|
+
puts err.message.yellow
|
85
|
+
if @exit_on_bad_arguments == false # means we are embedded in hiptest-publisher
|
86
|
+
raise
|
76
87
|
end
|
77
88
|
rescue Exception => err
|
78
|
-
puts "
|
89
|
+
puts ("An error has occured, sorry for the inconvenience.\n" +
|
90
|
+
"Try running the command again with --verbose for detailed output").red
|
79
91
|
reporter.dump_error(err)
|
80
92
|
end
|
81
93
|
|
82
94
|
def get_project(xml)
|
83
|
-
with_status_message "Extracting data" do
|
95
|
+
reporter.with_status_message "Extracting data" do
|
84
96
|
parser = Hiptest::XMLParser.new(xml, reporter)
|
85
97
|
return parser.build_project
|
86
98
|
end
|
@@ -89,7 +101,7 @@ module Hiptest
|
|
89
101
|
end
|
90
102
|
|
91
103
|
def write_to_file(path, message)
|
92
|
-
with_status_message "#{message}: #{path}" do
|
104
|
+
reporter.with_status_message "#{message}: #{path}" do
|
93
105
|
mkdirs_for(path)
|
94
106
|
File.open(path, 'w') do |file|
|
95
107
|
file.write(yield)
|
@@ -137,7 +149,7 @@ module Hiptest
|
|
137
149
|
|
138
150
|
def show_actionwords_diff
|
139
151
|
old = nil
|
140
|
-
with_status_message "Loading previous definition" do
|
152
|
+
reporter.with_status_message "Loading previous definition" do
|
141
153
|
old = YAML.load_file("#{@cli_options.output_directory}/actionwords_signature.yaml")
|
142
154
|
end
|
143
155
|
|
@@ -239,7 +251,7 @@ module Hiptest
|
|
239
251
|
def export
|
240
252
|
return if @project.nil?
|
241
253
|
|
242
|
-
with_status_message "Analyzing data" do
|
254
|
+
reporter.with_status_message "Analyzing data" do
|
243
255
|
@language_config = LanguageConfigParser.new(@cli_options)
|
244
256
|
Hiptest::Nodes::ParentAdder.add(@project)
|
245
257
|
Hiptest::Nodes::ParameterTypeAdder.add(@project)
|
@@ -273,11 +285,11 @@ module Hiptest
|
|
273
285
|
|
274
286
|
def post_results
|
275
287
|
response = nil
|
276
|
-
with_status_message "Posting #{@cli_options.push} to #{@cli_options.site}" do
|
277
|
-
response = push_results
|
288
|
+
reporter.with_status_message "Posting #{@cli_options.push} to #{@cli_options.site}" do
|
289
|
+
response = @client.push_results
|
278
290
|
end
|
279
291
|
passed_count = JSON.parse(response.body)['test_import'].size
|
280
|
-
with_status_message "#{pluralize(passed_count, "test")} imported" do
|
292
|
+
reporter.with_status_message "#{pluralize(passed_count, "test")} imported" do
|
281
293
|
if @cli_options.verbose
|
282
294
|
JSON.parse(response.body)['test_import'].each do |imported_test|
|
283
295
|
puts " Test '#{imported_test['name']}' imported"
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
require_relative 'formatters/reporter'
|
6
|
+
|
7
|
+
module Hiptest
|
8
|
+
|
9
|
+
class ClientError < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
class Client
|
13
|
+
attr_reader :cli_options
|
14
|
+
|
15
|
+
def initialize(cli_options, reporter = nil)
|
16
|
+
@cli_options = cli_options
|
17
|
+
@reporter = reporter || NullReporter.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def url
|
21
|
+
if cli_options.push?
|
22
|
+
"#{cli_options.site}/import_test_results/#{cli_options.token}/#{cli_options.push_format}"
|
23
|
+
elsif test_run_id
|
24
|
+
"#{base_publication_path}/test_run/#{test_run_id}"
|
25
|
+
else
|
26
|
+
"#{base_publication_path}/#{cli_options.leafless_export ? 'leafless_tests' : 'project'}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def fetch_project_export
|
31
|
+
response = send_get_request(url)
|
32
|
+
response.body
|
33
|
+
end
|
34
|
+
|
35
|
+
def available_test_runs
|
36
|
+
@available_test_runs ||= begin
|
37
|
+
response = send_get_request("#{base_publication_path}/test_runs")
|
38
|
+
json_response = JSON.parse(response.body)
|
39
|
+
json_response["test_runs"]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def push_results
|
44
|
+
# Code from: https://github.com/nicksieger/multipart-post
|
45
|
+
uploaded = {}
|
46
|
+
Dir.glob(cli_options.push.gsub('\\', '/')).each_with_index do |filename, index|
|
47
|
+
uploaded["file-#{filename.normalize}"] = UploadIO.new(File.new(filename), "text", filename)
|
48
|
+
end
|
49
|
+
|
50
|
+
uri = URI.parse(url)
|
51
|
+
send_request(Net::HTTP::Post::Multipart.new(uri, uploaded))
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def test_run_id
|
57
|
+
return unless cli_options.test_run_id? || cli_options.test_run_name?
|
58
|
+
|
59
|
+
if cli_options.test_run_id?
|
60
|
+
key = "id"
|
61
|
+
searched_value = cli_options.test_run_id
|
62
|
+
elsif cli_options.test_run_name?
|
63
|
+
key = "name"
|
64
|
+
searched_value = cli_options.test_run_name
|
65
|
+
end
|
66
|
+
|
67
|
+
matching_test_run = available_test_runs.find { |test_run| test_run[key] == searched_value }
|
68
|
+
if matching_test_run.nil?
|
69
|
+
raise ClientError, no_matching_test_runs_error_message
|
70
|
+
end
|
71
|
+
matching_test_run["id"]
|
72
|
+
end
|
73
|
+
|
74
|
+
def no_matching_test_runs_error_message
|
75
|
+
if available_test_runs.empty?
|
76
|
+
"No matching test run found: this project does not have any test runs."
|
77
|
+
else
|
78
|
+
"No matching test run found. Available test runs for this project are:\n" +
|
79
|
+
columnize_test_runs(available_test_runs)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def columnize_test_runs(test_runs)
|
84
|
+
lines = []
|
85
|
+
lines << ["ID", "Name"]
|
86
|
+
lines << ["--", "----"]
|
87
|
+
lines += test_runs.map { |tr| [tr["id"].to_s, tr["name"]] }
|
88
|
+
first_column_width = lines.map { |line| line[0].length }.max
|
89
|
+
lines.map! { |line| " #{line[0].ljust(first_column_width)} #{line[1]}" }
|
90
|
+
lines.join("\n")
|
91
|
+
end
|
92
|
+
|
93
|
+
def base_publication_path
|
94
|
+
"#{cli_options.site}/publication/#{cli_options.token}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def send_get_request(url)
|
98
|
+
uri = URI.parse(url)
|
99
|
+
response = send_request(Net::HTTP::Get.new(uri))
|
100
|
+
if response.code_type == Net::HTTPNotFound
|
101
|
+
raise ClientError, "No project found with this secret token."
|
102
|
+
end
|
103
|
+
response
|
104
|
+
end
|
105
|
+
|
106
|
+
def send_request(request)
|
107
|
+
request["User-Agent"] = "Ruby/hiptest-publisher"
|
108
|
+
use_ssl = request.uri.scheme == "https"
|
109
|
+
Net::HTTP.start(request.uri.hostname, request.uri.port, use_ssl: use_ssl, :verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
|
110
|
+
@reporter.show_verbose_message("Request sent to: #{request.uri}")
|
111
|
+
http.request(request)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -5,6 +5,8 @@ class ConsoleFormatter
|
|
5
5
|
|
6
6
|
def initialize(verbose)
|
7
7
|
@verbose = verbose
|
8
|
+
@immediate_verbose = true
|
9
|
+
@verbose_messages = []
|
8
10
|
end
|
9
11
|
|
10
12
|
def dump_error(error, message = nil)
|
@@ -23,4 +25,43 @@ class ConsoleFormatter
|
|
23
25
|
puts message.yellow
|
24
26
|
options.each { |k, v| puts " - #{k}: #{v.inspect}" }
|
25
27
|
end
|
28
|
+
|
29
|
+
def show_verbose_message(message)
|
30
|
+
return unless verbose
|
31
|
+
if @immediate_verbose
|
32
|
+
STDOUT.print "#{message}\n"
|
33
|
+
else
|
34
|
+
@verbose_messages << message
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def show_status_message(message, status=nil)
|
39
|
+
status_icon = " "
|
40
|
+
output = STDOUT
|
41
|
+
|
42
|
+
if status == :success
|
43
|
+
status_icon = "v".green
|
44
|
+
elsif status == :failure
|
45
|
+
status_icon = "x".red
|
46
|
+
output = STDERR
|
47
|
+
end
|
48
|
+
if status
|
49
|
+
@immediate_verbose = true
|
50
|
+
cursor_offset = ""
|
51
|
+
else
|
52
|
+
return unless $stdout.tty?
|
53
|
+
rows, columns = IO.console.winsize
|
54
|
+
return if columns == 0
|
55
|
+
@immediate_verbose = false
|
56
|
+
vertical_offset = (4 + message.length) / columns
|
57
|
+
cursor_offset = "\r\e[#{vertical_offset + 1}A"
|
58
|
+
end
|
59
|
+
|
60
|
+
output.print "[#{status_icon}] #{message}#{cursor_offset}\n"
|
61
|
+
|
62
|
+
if @immediate_verbose && !@verbose_messages.empty?
|
63
|
+
@verbose_messages.each { |message| show_verbose_message(message) }
|
64
|
+
@verbose_messages.clear
|
65
|
+
end
|
66
|
+
end
|
26
67
|
end
|
@@ -17,6 +17,21 @@ class Reporter
|
|
17
17
|
notify(:show_options, options, message)
|
18
18
|
end
|
19
19
|
|
20
|
+
def show_verbose_message(message)
|
21
|
+
notify(:show_verbose_message, message)
|
22
|
+
end
|
23
|
+
|
24
|
+
def with_status_message(message, &blk)
|
25
|
+
notify(:show_status_message, message)
|
26
|
+
status = :success
|
27
|
+
yield
|
28
|
+
rescue
|
29
|
+
status = :failure
|
30
|
+
raise
|
31
|
+
ensure
|
32
|
+
notify(:show_status_message, message, status)
|
33
|
+
end
|
34
|
+
|
20
35
|
def notify(message, *args)
|
21
36
|
@listeners.each do |listener|
|
22
37
|
listener.send(message, *args)
|
@@ -76,6 +76,18 @@ class CliOptions < OpenStruct
|
|
76
76
|
actionwords_diff || aw_deleted || aw_created || aw_renamed || aw_signature_changed || aw_definition_changed
|
77
77
|
end
|
78
78
|
|
79
|
+
def push?
|
80
|
+
option_present?(push)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_run_id?
|
84
|
+
option_present?(test_run_id)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_run_name?
|
88
|
+
option_present?(test_run_name)
|
89
|
+
end
|
90
|
+
|
79
91
|
def language_framework
|
80
92
|
if framework.empty?
|
81
93
|
language
|
@@ -119,6 +131,12 @@ class CliOptions < OpenStruct
|
|
119
131
|
return delta
|
120
132
|
end
|
121
133
|
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def option_present?(value)
|
138
|
+
value && !value.empty?
|
139
|
+
end
|
122
140
|
end
|
123
141
|
|
124
142
|
class OptionsParser
|
@@ -150,7 +168,8 @@ class OptionsParser
|
|
150
168
|
Option.new(nil, 'filename-pattern=PATTERN', nil, String, "Filename pattern (containing %s)", :filename_pattern),
|
151
169
|
Option.new('c', 'config-file=PATH', nil, String, "Configuration file", :config),
|
152
170
|
Option.new(nil, 'overriden-templates=PATH', '', String, "Folder for overriden templates", :overriden_templates),
|
153
|
-
Option.new(nil, 'test-run-id=ID', '', String, "Export data from a test run", :test_run_id),
|
171
|
+
Option.new(nil, 'test-run-id=ID', '', String, "Export data from a test run identified by its id", :test_run_id),
|
172
|
+
Option.new(nil, 'test-run-name=NAME', '', String, "Export data from a test run identified by its name", :test_run_name),
|
154
173
|
Option.new(nil, 'only=CATEGORIES', nil, String, "Restrict export to given file categories (--only=list to list them)", :only),
|
155
174
|
Option.new('x', 'xml-file=PROJECT_XML', nil, String, "XML file to use instead of fetching it from Hiptest", :xml_file),
|
156
175
|
Option.new(nil, 'tests-only', false, nil, "(deprecated) alias for --only=tests", :tests_only),
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'colorize'
|
2
2
|
require 'io/console'
|
3
|
-
require 'open-uri'
|
4
3
|
require 'openssl'
|
5
4
|
require 'net/http/post/multipart'
|
6
5
|
require 'pathname'
|
@@ -35,79 +34,6 @@ def singularize(name)
|
|
35
34
|
name.to_s.chomp("s")
|
36
35
|
end
|
37
36
|
|
38
|
-
def make_url(options)
|
39
|
-
if push?(options)
|
40
|
-
"#{options.site}/import_test_results/#{options.token}/#{options.push_format}"
|
41
|
-
else
|
42
|
-
base_url = "#{options.site}/publication/#{options.token}"
|
43
|
-
if options.test_run_id.nil? || options.test_run_id.empty?
|
44
|
-
"#{base_url}/#{options.leafless_export ? 'leafless_tests' : 'project'}"
|
45
|
-
else
|
46
|
-
"#{base_url}/test_run/#{options.test_run_id}"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def fetch_project_export(options)
|
52
|
-
url = make_url(options)
|
53
|
-
|
54
|
-
open(url, "User-Agent" => 'Ruby/hiptest-publisher', :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE)
|
55
|
-
end
|
56
|
-
|
57
|
-
def show_status_message(message, status=nil)
|
58
|
-
status_icon = " "
|
59
|
-
output = STDOUT
|
60
|
-
|
61
|
-
if status == :success
|
62
|
-
status_icon = "v".green
|
63
|
-
elsif status == :failure
|
64
|
-
status_icon = "x".red
|
65
|
-
output = STDERR
|
66
|
-
end
|
67
|
-
if status
|
68
|
-
cursor_offset = ""
|
69
|
-
else
|
70
|
-
return unless $stdout.tty?
|
71
|
-
rows, columns = IO.console.winsize
|
72
|
-
return if columns == 0
|
73
|
-
vertical_offset = (4 + message.length) / columns
|
74
|
-
cursor_offset = "\r\e[#{vertical_offset + 1}A"
|
75
|
-
end
|
76
|
-
|
77
|
-
output.print "[#{status_icon}] #{message}#{cursor_offset}\n"
|
78
|
-
end
|
79
|
-
|
80
|
-
def with_status_message(message, &blk)
|
81
|
-
show_status_message message
|
82
|
-
status = :success
|
83
|
-
yield
|
84
|
-
rescue
|
85
|
-
status = :failure
|
86
|
-
raise
|
87
|
-
ensure
|
88
|
-
show_status_message message, status
|
89
|
-
end
|
90
|
-
|
91
|
-
def push?(options)
|
92
|
-
options.push && !options.push.empty?
|
93
|
-
end
|
94
|
-
|
95
|
-
def push_results(options)
|
96
|
-
# Code from: https://github.com/nicksieger/multipart-post
|
97
|
-
url = URI.parse(make_url(options))
|
98
|
-
use_ssl = (url.scheme == 'https')
|
99
|
-
uploaded = {}
|
100
|
-
|
101
|
-
Dir.glob(options.push.gsub('\\', '/')).each_with_index do |filename, index|
|
102
|
-
uploaded["file-#{filename.normalize}"] = UploadIO.new(File.new(filename), "text", filename)
|
103
|
-
end
|
104
|
-
|
105
|
-
req = Net::HTTP::Post::Multipart.new(url.path, uploaded)
|
106
|
-
response = Net::HTTP.start(url.host, url.port, :use_ssl => use_ssl, :verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
|
107
|
-
http.request(req)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
37
|
def clean_path(path)
|
112
38
|
Pathname.new(path).cleanpath.to_s
|
113
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hiptest-publisher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiptest R&D
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -261,6 +261,7 @@ files:
|
|
261
261
|
- lib/hiptest-publisher/actionword_indexer.rb
|
262
262
|
- lib/hiptest-publisher/call_arguments_adder.rb
|
263
263
|
- lib/hiptest-publisher/cli_options_checker.rb
|
264
|
+
- lib/hiptest-publisher/client.rb
|
264
265
|
- lib/hiptest-publisher/formatters/console_formatter.rb
|
265
266
|
- lib/hiptest-publisher/formatters/reporter.rb
|
266
267
|
- lib/hiptest-publisher/gherkin_adder.rb
|
@@ -595,7 +596,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
595
596
|
version: '0'
|
596
597
|
requirements: []
|
597
598
|
rubyforge_project:
|
598
|
-
rubygems_version: 2.4
|
599
|
+
rubygems_version: 2.6.4
|
599
600
|
signing_key:
|
600
601
|
specification_version: 4
|
601
602
|
summary: Export your tests from Hiptest into executable tests.
|