allure-ruby-commons 2.10.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +67 -0
- data/lib/allure-ruby-commons.rb +168 -0
- data/lib/allure_ruby_commons/allure_lifecycle.rb +257 -0
- data/lib/allure_ruby_commons/config.rb +23 -0
- data/lib/allure_ruby_commons/file_writer.rb +46 -0
- data/lib/allure_ruby_commons/model/attachment.rb +18 -0
- data/lib/allure_ruby_commons/model/content_type.rb +21 -0
- data/lib/allure_ruby_commons/model/executable_item.rb +34 -0
- data/lib/allure_ruby_commons/model/fixture_result.rb +5 -0
- data/lib/allure_ruby_commons/model/jsonable.rb +36 -0
- data/lib/allure_ruby_commons/model/label.rb +14 -0
- data/lib/allure_ruby_commons/model/link.rb +15 -0
- data/lib/allure_ruby_commons/model/parameter.rb +14 -0
- data/lib/allure_ruby_commons/model/stage.rb +10 -0
- data/lib/allure_ruby_commons/model/status.rb +10 -0
- data/lib/allure_ruby_commons/model/status_details.rb +20 -0
- data/lib/allure_ruby_commons/model/step_result.rb +5 -0
- data/lib/allure_ruby_commons/model/test_result.rb +31 -0
- data/lib/allure_ruby_commons/model/test_result_container.rb +17 -0
- data/lib/allure_ruby_commons/result_utils.rb +151 -0
- data/lib/allure_ruby_commons/util.rb +45 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c6ec9c5dd1a69617de027bd146f0deaf35ef51a1bd8861e013c41550070020b7
|
4
|
+
data.tar.gz: e049c7285aed91e6c8aceb3185ed4a11f143aaafb5b8ae20acdf996c1239f923
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1367a4de864e0c704ac5223b626a8027bdb942aaa91ceac3e25b84ec228b86e6b4f4204c3439b55f8f8a9d5860e3b044877da910aa70270a19d1ee5a4f9be5f0
|
7
|
+
data.tar.gz: 626e8aa40a5d8f7cde655ca3b6a7f1b283a5006d80676aa86001e63986f25e674220cfabaff63d8f607a6381f9221e493cbed4d88e1f4833da6e570637b343f5
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Allure Ruby Adaptor API
|
2
|
+
|
3
|
+
This is a helper library containing the basics for any ruby-based Allure adaptor.
|
4
|
+
Using it you can easily implement the adaptor for your favorite ruby testing library or
|
5
|
+
you can just create the report of any other kind using the basic Allure terms.
|
6
|
+
|
7
|
+
## Setup
|
8
|
+
|
9
|
+
Add the dependency to your Gemfile
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'allure-ruby-commons'
|
13
|
+
```
|
14
|
+
|
15
|
+
## Configuration
|
16
|
+
|
17
|
+
Following configuration options are supported:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
Allure.configure do |c|
|
21
|
+
c.results_directory = "/whatever/you/like"
|
22
|
+
c.logging_level = Logger::INFO
|
23
|
+
# these are used for creating links to bugs or test cases where {} is replaced with keys of relevant items
|
24
|
+
c.link_tms_pattern = "http://www.jira.com/browse/{}"
|
25
|
+
c.link_issue_pattern = "http://www.jira.com/browse/{}"
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
Getting the configuration object:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
Allure.configuration
|
33
|
+
```
|
34
|
+
|
35
|
+
## Allure lifecycle
|
36
|
+
|
37
|
+
Reports are built using API defined in AllureLifecycle class and using allure specific entities defined in models.
|
38
|
+
Example of building a simple test case can be seen in [integration spec](spec/integration/full_report_spec.rb).
|
39
|
+
|
40
|
+
Convenience method `Allure.lifecycle` exists for getting thread specific allure lifecycle instance.
|
41
|
+
|
42
|
+
Additional methods in [Allure](lib/allure-ruby-commons.rb) exist to add various custom attributes to test report.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
Allure.add_attachment(name: "attachment", source: "Some string", type: Allure::ContentType::TXT, test_case: false)
|
46
|
+
Allure.add_link(name: "Custom Url", url: "http://www.github.com")
|
47
|
+
```
|
48
|
+
|
49
|
+
## Testing
|
50
|
+
|
51
|
+
Install dependencies:
|
52
|
+
|
53
|
+
```bash
|
54
|
+
bundle install
|
55
|
+
```
|
56
|
+
|
57
|
+
Run tests:
|
58
|
+
|
59
|
+
```bash
|
60
|
+
bundle exec rspec
|
61
|
+
```
|
62
|
+
|
63
|
+
## Building
|
64
|
+
|
65
|
+
```bash
|
66
|
+
gem build allure-ruby-commons.gemspec
|
67
|
+
```
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# rubocop:disable Naming/FileName
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "require_all"
|
5
|
+
require "uuid"
|
6
|
+
require_rel "allure_ruby_commons/**/*rb"
|
7
|
+
|
8
|
+
# Namespace for classes that handle allure report generation and different framework adaptors
|
9
|
+
module Allure
|
10
|
+
class << self
|
11
|
+
# Get thread specific allure lifecycle object
|
12
|
+
# @return [Allure::AllureLifecycle]
|
13
|
+
def lifecycle
|
14
|
+
Thread.current[:lifecycle] ||= AllureLifecycle.new
|
15
|
+
end
|
16
|
+
|
17
|
+
# Set lifecycle object
|
18
|
+
# @param [Allure::AllureLifecycle] lifecycle
|
19
|
+
# @return [void]
|
20
|
+
def lifecycle=(lifecycle)
|
21
|
+
Thread.current[:lifecycle] = lifecycle
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get allure configuration
|
25
|
+
# @return [Allure::Config]
|
26
|
+
def configuration
|
27
|
+
Config
|
28
|
+
end
|
29
|
+
|
30
|
+
# Set allure configuration
|
31
|
+
# @yieldparam [Allure::Config]
|
32
|
+
# @yieldreturn [void]
|
33
|
+
# @return [void]
|
34
|
+
def configure
|
35
|
+
yield(Config)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add epic to current test case
|
39
|
+
# @param [String] value
|
40
|
+
# @return [void]
|
41
|
+
def epic(value)
|
42
|
+
label(ResultUtils::EPIC_LABEL_NAME, value)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Add feature to current test case
|
46
|
+
# @param [String] value
|
47
|
+
# @return [void]
|
48
|
+
def feature(value)
|
49
|
+
label(ResultUtils::FEATURE_LABEL_NAME, value)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add story to current test case
|
53
|
+
# @param [String] value
|
54
|
+
# @return [void]
|
55
|
+
def story(value)
|
56
|
+
label(ResultUtils::STORY_LABEL_NAME, value)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Add suite to current test case
|
60
|
+
# @param [String] value
|
61
|
+
# @return [void]
|
62
|
+
def suite(value)
|
63
|
+
label(ResultUtils::SUITE_LABEL_NAME, value)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Add label to current test case
|
67
|
+
# @param [String] name
|
68
|
+
# @param [String] value
|
69
|
+
# @return [void]
|
70
|
+
def label(name, value)
|
71
|
+
lifecycle.update_test_case do |test_case|
|
72
|
+
test_case.labels.push(Label.new(name, value))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Add description to current test case
|
77
|
+
# @param [String] description
|
78
|
+
# @return [void]
|
79
|
+
def description(description)
|
80
|
+
lifecycle.update_test_case do |test_case|
|
81
|
+
test_case.description = description
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Add html description to current test case
|
86
|
+
# @param [String] description_html
|
87
|
+
# @return [void]
|
88
|
+
def description_html(description_html)
|
89
|
+
lifecycle.update_test_case do |test_case|
|
90
|
+
test_case.description_html = description_html
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Add parameter to current test case
|
95
|
+
# @param [String] name
|
96
|
+
# @param [String] value
|
97
|
+
# @return [void]
|
98
|
+
def parameter(name, value)
|
99
|
+
lifecycle.update_test_case do |test_case|
|
100
|
+
test_case.parameters.push(Parameter.new(name, value))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Add tms link to current test case
|
105
|
+
# @param [String] name
|
106
|
+
# @param [String] url
|
107
|
+
# @return [void]
|
108
|
+
def tms(name, url)
|
109
|
+
add_link(name: name, url: url, type: ResultUtils::TMS_LINK_TYPE)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Add issue linkt to current test case
|
113
|
+
# @param [String] name
|
114
|
+
# @param [String] url
|
115
|
+
# @return [void]
|
116
|
+
def issue(name, url)
|
117
|
+
add_link(name: name, url: url, type: ResultUtils::ISSUE_LINK_TYPE)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Add link to current test case
|
121
|
+
# @param [String ] url
|
122
|
+
# @param [String] name
|
123
|
+
# @param [String] type type of the link used to display link icon
|
124
|
+
# @return [void]
|
125
|
+
def add_link(url:, name: nil, type: "custom")
|
126
|
+
lifecycle.update_test_case do |test_case|
|
127
|
+
test_case.links.push(Link.new(type, name || url, url))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Add attachment to current test case or step
|
132
|
+
# @param [String] name Attachment name
|
133
|
+
# @param [File, String] source File or string to save as attachment
|
134
|
+
# @param [String] type attachment type defined in {Allure::ContentType}
|
135
|
+
# @param [Boolean] test_case add attachment to current test case instead of test step
|
136
|
+
# @return [void]
|
137
|
+
def add_attachment(name:, source:, type:, test_case: false)
|
138
|
+
lifecycle.add_attachment(name: name, source: source, type: type, test_case: test_case)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Add step with provided name and optional status to current test step, fixture or test case
|
142
|
+
# @param [String] name
|
143
|
+
# @param [Symbol] status <Allure::Status>, <Allure::Status::PASSED> by default
|
144
|
+
# @return [void]
|
145
|
+
def step(name:, status: nil)
|
146
|
+
lifecycle.add_test_step(StepResult.new(name: name, status: status || Status::PASSED, stage: Stage::FINISHED))
|
147
|
+
end
|
148
|
+
|
149
|
+
# Run passed block as step with given name
|
150
|
+
# @param [String] name
|
151
|
+
# @yield [] step block
|
152
|
+
# @return [void]
|
153
|
+
def run_step(name)
|
154
|
+
lifecycle.start_test_step(StepResult.new(name: name, stage: Stage::RUNNING))
|
155
|
+
yield
|
156
|
+
lifecycle.update_test_step { |step| step.status = Status::PASSED }
|
157
|
+
rescue => e
|
158
|
+
lifecycle.update_test_step do |step|
|
159
|
+
step.status = ResultUtils.status(e)
|
160
|
+
step.status_details = ResultUtils.status_details(e)
|
161
|
+
end
|
162
|
+
raise(e)
|
163
|
+
ensure
|
164
|
+
lifecycle.stop_test_step
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
# rubocop:enable Naming/FileName
|
@@ -0,0 +1,257 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Allure
|
4
|
+
# Main class for creating and writing allure results
|
5
|
+
class AllureLifecycle
|
6
|
+
def initialize
|
7
|
+
@step_context = []
|
8
|
+
end
|
9
|
+
|
10
|
+
# Start test result container
|
11
|
+
# @param [Allure::TestResultContainer] test_result_container
|
12
|
+
# @return [Allure::TestResultContainer]
|
13
|
+
def start_test_container(test_result_container)
|
14
|
+
test_result_container.start = ResultUtils.timestamp
|
15
|
+
@current_test_result_container = test_result_container
|
16
|
+
end
|
17
|
+
|
18
|
+
# @example Update current test container
|
19
|
+
# update_test_container do |container|
|
20
|
+
# container.stage = Allure::Stage::FINISHED
|
21
|
+
# end
|
22
|
+
# @yieldparam [Allure::TestResultContainer] current test result container
|
23
|
+
# @yieldreturn [void]
|
24
|
+
# @return [void]
|
25
|
+
def update_test_container
|
26
|
+
unless @current_test_result_container
|
27
|
+
return logger.error("Could not update test container, no container is running.")
|
28
|
+
end
|
29
|
+
|
30
|
+
yield(@current_test_result_container)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Stop current test container and write result
|
34
|
+
# @return [void]
|
35
|
+
def stop_test_container
|
36
|
+
unless @current_test_result_container
|
37
|
+
return logger.error("Could not stop test container, no container is running.")
|
38
|
+
end
|
39
|
+
|
40
|
+
@current_test_result_container.stop = ResultUtils.timestamp
|
41
|
+
file_writer.write_test_result_container(@current_test_result_container)
|
42
|
+
clear_current_test_container
|
43
|
+
end
|
44
|
+
|
45
|
+
# Start test case and add to current test container
|
46
|
+
# @param [Allure::TestResult] test_result
|
47
|
+
# @return [Allure::TestResult]
|
48
|
+
def start_test_case(test_result)
|
49
|
+
clear_step_context
|
50
|
+
unless @current_test_result_container
|
51
|
+
return logger.error("Could not start test case, test container is not started")
|
52
|
+
end
|
53
|
+
|
54
|
+
test_result.start = ResultUtils.timestamp
|
55
|
+
test_result.stage = Stage::RUNNING
|
56
|
+
test_result.labels.push(ResultUtils.thread_label, ResultUtils.host_label, ResultUtils.language_label)
|
57
|
+
@current_test_result_container.children.push(test_result.uuid)
|
58
|
+
@current_test_case = test_result
|
59
|
+
end
|
60
|
+
|
61
|
+
# @example Update current test case
|
62
|
+
# update_test_container do |test_case|
|
63
|
+
# test_case.status = Allure::Status::FAILED
|
64
|
+
# end
|
65
|
+
# @yieldparam [Allure::TestResult] current test
|
66
|
+
# @yieldreturn [void]
|
67
|
+
# @return [void]
|
68
|
+
def update_test_case
|
69
|
+
return logger.error("Could not update test case, no test case running") unless @current_test_case
|
70
|
+
|
71
|
+
yield(@current_test_case)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Stop current test case and write result
|
75
|
+
# @return [void]
|
76
|
+
def stop_test_case
|
77
|
+
return logger.error("Could not stop test case, no test case is running") unless @current_test_case
|
78
|
+
|
79
|
+
@current_test_case.stop = ResultUtils.timestamp
|
80
|
+
@current_test_case.stage = Stage::FINISHED
|
81
|
+
file_writer.write_test_result(@current_test_case)
|
82
|
+
clear_current_test_case
|
83
|
+
clear_step_context
|
84
|
+
end
|
85
|
+
|
86
|
+
# Start test step and add to current test case
|
87
|
+
# @param [Allure::StepResult] step_result
|
88
|
+
# @return [Allure::StepResult]
|
89
|
+
def start_test_step(step_result)
|
90
|
+
return logger.error("Could not start test step, no test case is running") unless @current_test_case
|
91
|
+
|
92
|
+
step_result.start = ResultUtils.timestamp
|
93
|
+
step_result.stage = Stage::RUNNING
|
94
|
+
add_test_step(step_result)
|
95
|
+
step_result
|
96
|
+
end
|
97
|
+
|
98
|
+
# @example Update current test step
|
99
|
+
# update_test_container do |test_step|
|
100
|
+
# test_step.status = Allure::Status::BROKEN
|
101
|
+
# end
|
102
|
+
# @yieldparam [Allure::StepResult] current test step
|
103
|
+
# @yieldreturn [void]
|
104
|
+
# @return [void]
|
105
|
+
def update_test_step
|
106
|
+
return logger.error("Could not update test step, no step is running") unless current_test_step
|
107
|
+
|
108
|
+
yield(current_test_step)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Stop current test step
|
112
|
+
# @return [void]
|
113
|
+
def stop_test_step
|
114
|
+
return logger.error("Could not stop test step, no step is running") unless current_test_step
|
115
|
+
|
116
|
+
current_test_step.stop = ResultUtils.timestamp
|
117
|
+
current_test_step.stage = Stage::FINISHED
|
118
|
+
clear_last_test_step
|
119
|
+
end
|
120
|
+
|
121
|
+
# Start prepare fixture
|
122
|
+
# @param [Allure::FixtureResult] fixture_result
|
123
|
+
# @return [Allure::FixtureResult]
|
124
|
+
def start_prepare_fixture(fixture_result)
|
125
|
+
start_fixture(fixture_result) || return
|
126
|
+
@current_test_result_container.befores.push(fixture_result)
|
127
|
+
@current_fixture = fixture_result
|
128
|
+
end
|
129
|
+
|
130
|
+
# Start tear down fixture
|
131
|
+
# @param [Allure::FixtureResult] fixture_result
|
132
|
+
# @return [Allure::FixtureResult]
|
133
|
+
def start_tear_down_fixture(fixture_result)
|
134
|
+
start_fixture(fixture_result) || return
|
135
|
+
@current_test_result_container.afters.push(fixture_result)
|
136
|
+
@current_fixture = fixture_result
|
137
|
+
end
|
138
|
+
|
139
|
+
# Start fixture
|
140
|
+
# @param [Allure::FixtureResult] fixture_result
|
141
|
+
# @return [Allure::FixtureResult]
|
142
|
+
def start_fixture(fixture_result)
|
143
|
+
clear_step_context
|
144
|
+
unless @current_test_result_container
|
145
|
+
logger.error("Could not start fixture, test container is not started")
|
146
|
+
return false
|
147
|
+
end
|
148
|
+
|
149
|
+
fixture_result.start = ResultUtils.timestamp
|
150
|
+
fixture_result.stage = Stage::RUNNING
|
151
|
+
end
|
152
|
+
|
153
|
+
# @example Update current fixture
|
154
|
+
# update_test_container do |fixture|
|
155
|
+
# fixture.status = Allure::Status::BROKEN
|
156
|
+
# end
|
157
|
+
# @yieldparam [Allure::FixtureResult] current fixture
|
158
|
+
# @yieldreturn [void]
|
159
|
+
# @return [void]
|
160
|
+
def update_fixture
|
161
|
+
return logger.error("Could not update fixture, fixture is not started") unless @current_fixture
|
162
|
+
|
163
|
+
yield(@current_fixture)
|
164
|
+
end
|
165
|
+
|
166
|
+
def stop_fixture
|
167
|
+
return logger.error("Could not stop fixture, fixture is not started") unless @current_fixture
|
168
|
+
|
169
|
+
@current_fixture.stop = ResultUtils.timestamp
|
170
|
+
@current_fixture.stage = Stage::FINISHED
|
171
|
+
clear_current_fixture
|
172
|
+
clear_step_context
|
173
|
+
end
|
174
|
+
|
175
|
+
# Add attachment to current test or step
|
176
|
+
# @param [String] name Attachment name
|
177
|
+
# @param [File, String] source File or string to save as attachment
|
178
|
+
# @param [String] type attachment type defined in {Allure::ContentType}
|
179
|
+
# @param [Boolean] test_case add attachment to current test case
|
180
|
+
# @return [void]
|
181
|
+
def add_attachment(name:, source:, type:, test_case: false)
|
182
|
+
attachment = prepare_attachment(name, type) || begin
|
183
|
+
return logger.error("Can't add attachment, unrecognized mime type: #{type}")
|
184
|
+
end
|
185
|
+
executable_item = (test_case && @current_test_case) || current_executable
|
186
|
+
executable_item&.attachments&.push(attachment) || begin
|
187
|
+
return logger.error("Can't add attachment, no test, step or fixture is running")
|
188
|
+
end
|
189
|
+
write_attachment(source, attachment)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Create attachment object
|
193
|
+
# @param [String] name
|
194
|
+
# @param [String] type
|
195
|
+
# @return [Allure::Attachment]
|
196
|
+
def prepare_attachment(name, type)
|
197
|
+
extension = ContentType.to_extension(type) || return
|
198
|
+
file_name = "#{UUID.generate}-attachment.#{extension}"
|
199
|
+
Attachment.new(name: name, source: file_name, type: type)
|
200
|
+
end
|
201
|
+
|
202
|
+
# Write attachment file
|
203
|
+
# @param [File, String] source
|
204
|
+
# @param [Allure::Attachment] attachment
|
205
|
+
# @return [void]
|
206
|
+
def write_attachment(source, attachment)
|
207
|
+
file_writer.write_attachment(source, attachment)
|
208
|
+
end
|
209
|
+
|
210
|
+
# Add step to current fixture|step|test case
|
211
|
+
# @param [Allure::StepResult] step_result
|
212
|
+
# @return [Allure::StepResult]
|
213
|
+
def add_test_step(step_result)
|
214
|
+
current_executable.steps.push(step_result)
|
215
|
+
@step_context.push(step_result)
|
216
|
+
step_result
|
217
|
+
end
|
218
|
+
|
219
|
+
private
|
220
|
+
|
221
|
+
def logger
|
222
|
+
@logger ||= Logger.new(STDOUT, level: Config.logging_level)
|
223
|
+
end
|
224
|
+
|
225
|
+
def file_writer
|
226
|
+
@file_writer ||= FileWriter.new
|
227
|
+
end
|
228
|
+
|
229
|
+
def current_executable
|
230
|
+
current_test_step || @current_fixture || @current_test_case
|
231
|
+
end
|
232
|
+
|
233
|
+
def clear_current_test_container
|
234
|
+
@current_test_result_container = nil
|
235
|
+
end
|
236
|
+
|
237
|
+
def clear_current_test_case
|
238
|
+
@current_test_case = nil
|
239
|
+
end
|
240
|
+
|
241
|
+
def current_test_step
|
242
|
+
@step_context.last
|
243
|
+
end
|
244
|
+
|
245
|
+
def clear_last_test_step
|
246
|
+
@step_context.pop
|
247
|
+
end
|
248
|
+
|
249
|
+
def clear_step_context
|
250
|
+
@step_context.clear
|
251
|
+
end
|
252
|
+
|
253
|
+
def clear_current_fixture
|
254
|
+
@current_fixture = nil
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
module Allure
|
6
|
+
class Config
|
7
|
+
DEFAULT_RESULTS_DIRECTORY = "reports/allure-results"
|
8
|
+
DEFAULT_LOGGING_LEVEL = Logger::INFO
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :link_tms_pattern, :link_issue_pattern
|
12
|
+
attr_writer :results_directory, :logging_level
|
13
|
+
|
14
|
+
def results_directory
|
15
|
+
@results_directory || DEFAULT_RESULTS_DIRECTORY
|
16
|
+
end
|
17
|
+
|
18
|
+
def logging_level
|
19
|
+
@logging_level || DEFAULT_LOGGING_LEVEL
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Allure
|
4
|
+
class FileWriter
|
5
|
+
TEST_RESULT_SUFFIX = "-result.json"
|
6
|
+
TEST_RESULT_CONTAINER_SUFFIX = "-container.json"
|
7
|
+
ATTACHMENT_FILE_SUFFIX = "-attachment"
|
8
|
+
|
9
|
+
# Write test result
|
10
|
+
# @param [Allure::TestResult] test_result
|
11
|
+
# @return [void]
|
12
|
+
def write_test_result(test_result)
|
13
|
+
write("#{test_result.uuid}#{TEST_RESULT_SUFFIX}", test_result.to_json)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Write test result container
|
17
|
+
# @param [Allure::TestResultContainer] test_container_result
|
18
|
+
# @return [void]
|
19
|
+
def write_test_result_container(test_container_result)
|
20
|
+
write("#{test_container_result.uuid}#{TEST_RESULT_CONTAINER_SUFFIX}", test_container_result.to_json)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Write allure attachment file
|
24
|
+
# @param [File, String] source File or string of attachment to save
|
25
|
+
# @param [Allure::Attachment] attachment
|
26
|
+
# @return [void]
|
27
|
+
def write_attachment(source, attachment)
|
28
|
+
source.is_a?(File) ? copy(source.path, attachment.source) : write(attachment.source, source)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def output_dir
|
34
|
+
@output_dir ||= FileUtils.mkpath(Allure::Config.results_directory).first
|
35
|
+
end
|
36
|
+
|
37
|
+
def write(name, source)
|
38
|
+
filename = File.join(output_dir, name)
|
39
|
+
File.open(filename, "w") { |file| file.write(source) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def copy(from, to)
|
43
|
+
FileUtils.cp(from, File.join(output_dir, to))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "jsonable"
|
4
|
+
|
5
|
+
module Allure
|
6
|
+
class Attachment < JSONable
|
7
|
+
# @param [String] name attachment name
|
8
|
+
# @param [String] type attachment type, {Allure::ContentType}
|
9
|
+
# @param [String] source attachment file name
|
10
|
+
def initialize(name:, type:, source:)
|
11
|
+
@name = name
|
12
|
+
@type = type
|
13
|
+
@source = source
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :name, :type, :source
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Allure
|
4
|
+
class ContentType
|
5
|
+
TXT = "text/plain"
|
6
|
+
XML = "application/xml"
|
7
|
+
CSV = "text/csv"
|
8
|
+
TSV = "text/tab-separated-values"
|
9
|
+
CSS = "text/css"
|
10
|
+
URI = "text/uri-list"
|
11
|
+
SVG = "image/svg+xml"
|
12
|
+
PNG = "image/png"
|
13
|
+
JSON = "application/json"
|
14
|
+
WEBM = "video/webm"
|
15
|
+
JPG = "image/jpeg"
|
16
|
+
|
17
|
+
def self.to_extension(content_type)
|
18
|
+
constants.detect { |const| const_get(const) == content_type }&.to_s&.downcase
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "jsonable"
|
4
|
+
|
5
|
+
module Allure
|
6
|
+
class ExecutableItem < JSONable
|
7
|
+
# @param [Hash] options
|
8
|
+
# @option options [String] :name
|
9
|
+
# @option options [String] :description
|
10
|
+
# @option options [String] :description_html
|
11
|
+
# @option options [String] :stage ('scheduled'), {Allure::Stage}
|
12
|
+
# @option options [String] :status ('broken'), {Allure::Status}
|
13
|
+
# @option options [Allure::StatusDetails] :status_details
|
14
|
+
# @option options [Array<Allure::ExecutableItem>] :steps ([])
|
15
|
+
# @option options [Array<Allure::Attachment>] :attachments ([])
|
16
|
+
# @option options [Array<Allure::Parameter>] :parameters ([])
|
17
|
+
def initialize(**options)
|
18
|
+
@name = options[:name]
|
19
|
+
@description = options[:description]
|
20
|
+
@description_html = options[:description_html]
|
21
|
+
@status = options[:status] || Status::BROKEN
|
22
|
+
@status_details = options[:status_details] || StatusDetails.new
|
23
|
+
@stage = options[:stage] || Stage::SCHEDULED
|
24
|
+
@steps = options[:steps] || []
|
25
|
+
@attachments = options[:attachments] || []
|
26
|
+
@parameters = options[:parameters] || []
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_accessor(
|
30
|
+
:name, :status, :status_details, :stage, :description, :description_html,
|
31
|
+
:steps, :attachments, :parameters, :start, :stop
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module Allure
|
6
|
+
class JSONable
|
7
|
+
def as_json(_options = {})
|
8
|
+
instance_variables.each_with_object({}) do |var, map|
|
9
|
+
key = camelcase(var.to_s.delete_prefix("@"))
|
10
|
+
value = instance_variable_get(var)
|
11
|
+
map[key] = value unless value.nil?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_json(*options)
|
16
|
+
as_json(*options).to_json(*options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def ==(other)
|
20
|
+
self.class == other.class && state == other.state
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def state
|
26
|
+
instance_variables.map { |var| instance_variable_get(var) }
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def camelcase(str)
|
32
|
+
str = str.gsub(/(?:_+)([a-z])/) { Regexp.last_match(1).upcase }
|
33
|
+
str.gsub(/(\A|\s)([A-Z])/) { Regexp.last_match(1) + Regexp.last_match(2).downcase }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Allure
|
4
|
+
class StatusDetails < JSONable
|
5
|
+
# @param [Boolean] known
|
6
|
+
# @param [Boolean] muted
|
7
|
+
# @param [Boolean] flaky
|
8
|
+
# @param [String] message
|
9
|
+
# @param [String] trace
|
10
|
+
def initialize(known: false, muted: false, flaky: false, message: nil, trace: nil)
|
11
|
+
@known = known
|
12
|
+
@muted = muted
|
13
|
+
@flaky = flaky
|
14
|
+
@message = message
|
15
|
+
@trace = trace
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :known, :muted, :flaky, :message, :trace
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Allure
|
4
|
+
class TestResult < ExecutableItem
|
5
|
+
# @param [String] uuid
|
6
|
+
# @param [String] history_id
|
7
|
+
# @param [Hash] options
|
8
|
+
# @option options [String] :name
|
9
|
+
# @option options [String] :full_name
|
10
|
+
# @option options [String] :description
|
11
|
+
# @option options [String] :description_html
|
12
|
+
# @option options [String] :status ('broken')
|
13
|
+
# @option options [String] :stage ('scheduled')
|
14
|
+
# @option options [Allure::StatusDetails] :status_details
|
15
|
+
# @option options [Array<Allure::ExecutableItem>] :steps ([])
|
16
|
+
# @option options [Array<Allure::Label>] :labels ([])
|
17
|
+
# @option options [Array<Allure::Link>] :links ([])
|
18
|
+
# @option options [Array<Allure::Attachment>] :attachments ([])
|
19
|
+
# @option options [Array<Allure::Parameter>] :parameters ([])
|
20
|
+
def initialize(uuid: UUID.generate, history_id: UUID.generate, **options)
|
21
|
+
super
|
22
|
+
@uuid = uuid
|
23
|
+
@history_id = history_id
|
24
|
+
@full_name = options[:full_name] || "Unnamed"
|
25
|
+
@labels = options[:labels] || []
|
26
|
+
@links = options[:links] || []
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_accessor :uuid, :history_id, :full_name, :labels, :links
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "jsonable"
|
4
|
+
module Allure
|
5
|
+
class TestResultContainer < JSONable
|
6
|
+
def initialize(uuid: UUID.generate, name: "Unnamed")
|
7
|
+
@uuid = uuid
|
8
|
+
@name = name
|
9
|
+
@children = []
|
10
|
+
@befores = []
|
11
|
+
@afters = []
|
12
|
+
@links = []
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :uuid, :name, :description, :description_html, :start, :stop, :children, :befores, :afters, :links
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "socket"
|
4
|
+
|
5
|
+
module Allure
|
6
|
+
module ResultUtils
|
7
|
+
ISSUE_LINK_TYPE = "issue"
|
8
|
+
TMS_LINK_TYPE = "tms"
|
9
|
+
|
10
|
+
ALLURE_ID_LABEL_NAME = "AS_ID"
|
11
|
+
SUITE_LABEL_NAME = "suite"
|
12
|
+
PARENT_SUITE_LABEL_NAME = "parentSuite"
|
13
|
+
SUB_SUITE_LABEL_NAME = "subSuite"
|
14
|
+
EPIC_LABEL_NAME = "epic"
|
15
|
+
FEATURE_LABEL_NAME = "feature"
|
16
|
+
STORY_LABEL_NAME = "story"
|
17
|
+
SEVERITY_LABEL_NAME = "severity"
|
18
|
+
TAG_LABEL_NAME = "tag"
|
19
|
+
OWNER_LABEL_NAME = "owner"
|
20
|
+
LEAD_LABEL_NAME = "lead"
|
21
|
+
HOST_LABEL_NAME = "host"
|
22
|
+
THREAD_LABEL_NAME = "thread"
|
23
|
+
TEST_METHOD_LABEL_NAME = "testMethod"
|
24
|
+
TEST_CLASS_LABEL_NAME = "testClass"
|
25
|
+
PACKAGE_LABEL_NAME = "package"
|
26
|
+
FRAMEWORK_LABEL_NAME = "framework"
|
27
|
+
LANGUAGE_LABEL_NAME = "language"
|
28
|
+
|
29
|
+
class << self
|
30
|
+
# @param [Time] time
|
31
|
+
# @return [Number]
|
32
|
+
def timestamp(time = nil)
|
33
|
+
((time || Time.now).to_f * 1000).to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
# Current thread label
|
37
|
+
# @return [Allure::Label]
|
38
|
+
def thread_label
|
39
|
+
Label.new(THREAD_LABEL_NAME, Thread.current.object_id)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Host label
|
43
|
+
# @return [Allure::Label]
|
44
|
+
def host_label
|
45
|
+
Label.new(HOST_LABEL_NAME, Socket.gethostname)
|
46
|
+
end
|
47
|
+
|
48
|
+
def language_label
|
49
|
+
Label.new(LANGUAGE_LABEL_NAME, "ruby")
|
50
|
+
end
|
51
|
+
|
52
|
+
def framework_label(value)
|
53
|
+
Label.new(FRAMEWORK_LABEL_NAME, value)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Feature label
|
57
|
+
# @param [String] value
|
58
|
+
# @return [Allure::Label]
|
59
|
+
def feature_label(value)
|
60
|
+
Label.new(FEATURE_LABEL_NAME, value)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Package label
|
64
|
+
# @param [String] value
|
65
|
+
# @return [Allure::Label]
|
66
|
+
def package_label(value)
|
67
|
+
Label.new(PACKAGE_LABEL_NAME, value)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Suite label
|
71
|
+
# @param [String] value
|
72
|
+
# @return [Allure::Label]
|
73
|
+
def suite_label(value)
|
74
|
+
Label.new(SUITE_LABEL_NAME, value)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Story label
|
78
|
+
# @param [String] value
|
79
|
+
# @return [Allure::Label]
|
80
|
+
def story_label(value)
|
81
|
+
Label.new(STORY_LABEL_NAME, value)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Test case label
|
85
|
+
# @param [String] value
|
86
|
+
# @return [Allure::Label]
|
87
|
+
def test_class_label(value)
|
88
|
+
Label.new(TEST_CLASS_LABEL_NAME, value)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Tag label
|
92
|
+
# @param [String] value
|
93
|
+
# @return [Allure::Label]
|
94
|
+
def tag_label(value)
|
95
|
+
Label.new(TAG_LABEL_NAME, value)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Severity label
|
99
|
+
# @param [String] value
|
100
|
+
# @return [Allure::Label]
|
101
|
+
def severity_label(value)
|
102
|
+
Label.new(SEVERITY_LABEL_NAME, value)
|
103
|
+
end
|
104
|
+
|
105
|
+
# TMS link
|
106
|
+
# @param [String] value
|
107
|
+
# @return [Allure::Link]
|
108
|
+
def tms_link(value)
|
109
|
+
Link.new(TMS_LINK_TYPE, value, tms_url(value))
|
110
|
+
end
|
111
|
+
|
112
|
+
# Issue link
|
113
|
+
# @param [String] value
|
114
|
+
# @return [Allure::Link]
|
115
|
+
def issue_link(value)
|
116
|
+
Link.new(ISSUE_LINK_TYPE, value, issue_url(value))
|
117
|
+
end
|
118
|
+
|
119
|
+
# Get status based on exception type
|
120
|
+
# @param [Exception] exception
|
121
|
+
# @return [String]
|
122
|
+
def status(exception)
|
123
|
+
expectation_error?(exception) ? Status::FAILED : Status::BROKEN
|
124
|
+
end
|
125
|
+
|
126
|
+
# Get exception status detail
|
127
|
+
# @param [Exception] exception
|
128
|
+
# @return [Hash<Symbol, String>]
|
129
|
+
def status_details(exception)
|
130
|
+
StatusDetails.new(message: exception.message, trace: exception.backtrace&.join("\n"))
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def tms_url(value)
|
136
|
+
Allure.configuration.link_tms_pattern.sub("{}", value)
|
137
|
+
end
|
138
|
+
|
139
|
+
def issue_url(value)
|
140
|
+
Allure.configuration.link_issue_pattern.sub("{}", value)
|
141
|
+
end
|
142
|
+
|
143
|
+
def expectation_error?(exception)
|
144
|
+
exception.instance_of?(RSpec::Expectations::ExpectationNotMetError) ||
|
145
|
+
exception.instance_of?(RSpec::Expectations::MultipleExpectationsNotMetError)
|
146
|
+
rescue NameError
|
147
|
+
false
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "open-uri"
|
4
|
+
require "zip"
|
5
|
+
require "pathname"
|
6
|
+
|
7
|
+
module Allure
|
8
|
+
class Util
|
9
|
+
ALLURE_CLI_VERSION = "2.10.0"
|
10
|
+
ALLURE_BIN_URL = "http://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/"\
|
11
|
+
"#{ALLURE_CLI_VERSION}/allure-commandline-#{ALLURE_CLI_VERSION}.zip"
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# Download allure bin if appropriate version is not in path
|
15
|
+
# @return [String] allure executable
|
16
|
+
def allure_cli
|
17
|
+
return "allure" if ALLURE_CLI_VERSION == `allure --version`.chomp
|
18
|
+
|
19
|
+
cli_dir = File.join(".allure", "allure-#{ALLURE_CLI_VERSION}")
|
20
|
+
zip = File.join(".allure", "allure.zip")
|
21
|
+
bin = File.join(cli_dir, "bin", "allure")
|
22
|
+
|
23
|
+
FileUtils.mkpath(".allure")
|
24
|
+
download_allure(zip) unless File.exist?(zip) || File.exist?(bin)
|
25
|
+
extract_allure(zip, ".allure") unless File.exist?(bin)
|
26
|
+
|
27
|
+
bin
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def download_allure(destination)
|
33
|
+
File.open(destination, "w") { |file| file.write(open(ALLURE_BIN_URL).read) } # rubocop:disable Security/Open
|
34
|
+
end
|
35
|
+
|
36
|
+
def extract_allure(zip, destination)
|
37
|
+
Zip::File.foreach(zip) do |entry|
|
38
|
+
entry.restore_permissions = true
|
39
|
+
entry.extract(File.join(destination, entry.name))
|
40
|
+
end
|
41
|
+
FileUtils.rm(zip)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: allure-ruby-commons
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.10.0.beta2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrejs Cunskis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-06-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: uuid
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.3.9
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.3.9
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: require_all
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: json
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.8'
|
48
|
+
- - "<"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '3'
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '1.8'
|
58
|
+
- - "<"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rubyzip
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '1.2'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '1.2'
|
75
|
+
description: Utilities allowing to implement allure result generation by other test
|
76
|
+
frameworks
|
77
|
+
email: andrejs.cunskis@gmail.com
|
78
|
+
executables: []
|
79
|
+
extensions: []
|
80
|
+
extra_rdoc_files: []
|
81
|
+
files:
|
82
|
+
- README.md
|
83
|
+
- lib/allure-ruby-commons.rb
|
84
|
+
- lib/allure_ruby_commons/allure_lifecycle.rb
|
85
|
+
- lib/allure_ruby_commons/config.rb
|
86
|
+
- lib/allure_ruby_commons/file_writer.rb
|
87
|
+
- lib/allure_ruby_commons/model/attachment.rb
|
88
|
+
- lib/allure_ruby_commons/model/content_type.rb
|
89
|
+
- lib/allure_ruby_commons/model/executable_item.rb
|
90
|
+
- lib/allure_ruby_commons/model/fixture_result.rb
|
91
|
+
- lib/allure_ruby_commons/model/jsonable.rb
|
92
|
+
- lib/allure_ruby_commons/model/label.rb
|
93
|
+
- lib/allure_ruby_commons/model/link.rb
|
94
|
+
- lib/allure_ruby_commons/model/parameter.rb
|
95
|
+
- lib/allure_ruby_commons/model/stage.rb
|
96
|
+
- lib/allure_ruby_commons/model/status.rb
|
97
|
+
- lib/allure_ruby_commons/model/status_details.rb
|
98
|
+
- lib/allure_ruby_commons/model/step_result.rb
|
99
|
+
- lib/allure_ruby_commons/model/test_result.rb
|
100
|
+
- lib/allure_ruby_commons/model/test_result_container.rb
|
101
|
+
- lib/allure_ruby_commons/result_utils.rb
|
102
|
+
- lib/allure_ruby_commons/util.rb
|
103
|
+
homepage: http://allure.qatools.ru
|
104
|
+
licenses:
|
105
|
+
- Apache-2.0
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 2.5.0
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">"
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 1.3.1
|
121
|
+
requirements: []
|
122
|
+
rubygems_version: 3.0.3
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: Common library for allure results generation
|
126
|
+
test_files: []
|