parallel_report_portal 2.0.2 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +28 -0
- data/.rspec +1 -0
- data/README.md +21 -13
- data/lib/parallel_report_portal/configuration.rb +31 -11
- data/lib/parallel_report_portal/http.rb +39 -28
- data/lib/parallel_report_portal/version.rb +1 -1
- metadata +4 -4
- data/.drone.yml +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35cc50dee2f24a1533a8ef831c0cd1977fc36c6fd9c6cdb5ccdd4a73c8022cc2
|
4
|
+
data.tar.gz: fa3c3fbe565ac7e1aa5b728a6fe73f401d84c4b327eebe83a4f1af6697d6fda0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b26b53f1e989cf4e2179e6361be41b783ca692d739aa7bdabaab50b9599c4e5378fa05b1fb9920bde748bdff56ef99a0afb4f4431b23329ac69b83db81ea057
|
7
|
+
data.tar.gz: c0cc62184f810e2bd53119e7115e29be3c014d707f8bce610c825a466d356337a0c694d4dae6e14b87f137f136136ae1056aceec0f6a7e590b35a59dedc79961
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on: [push]
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
test:
|
14
|
+
|
15
|
+
runs-on: ubuntu-latest
|
16
|
+
strategy:
|
17
|
+
matrix:
|
18
|
+
ruby-version: ['2.6', '2.7', '3.0']
|
19
|
+
|
20
|
+
steps:
|
21
|
+
- uses: actions/checkout@v2
|
22
|
+
- name: Set up Ruby
|
23
|
+
uses: ruby/setup-ruby@v1
|
24
|
+
with:
|
25
|
+
ruby-version: ${{ matrix.ruby-version }}
|
26
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
27
|
+
- name: Run tests
|
28
|
+
run: bundle exec rake
|
data/.rspec
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
This gem is a Ruby-Cucumber formatter which sends the test output to [Report Portal](https://reportportal.io).
|
4
4
|
|
5
|
-
This formatter supports plain 'ol Cucumber tests and those wrapped with [parallel_tests](https://rubygems.org/gems/parallel_tests).
|
5
|
+
This formatter supports plain 'ol Cucumber tests and those wrapped with [parallel_tests](https://rubygems.org/gems/parallel_tests).
|
6
6
|
|
7
7
|
It also supports Cucumber 3.x and 4+ (Cucumber implementations using cucumber-messages).
|
8
8
|
|
@@ -30,20 +30,30 @@ The formatter supports configuration via a config file or via environment variab
|
|
30
30
|
|
31
31
|
#### Configuration file
|
32
32
|
|
33
|
-
It will search for a file called `report_portal.yml` or `REPORT_PORTAL.YML` in `./config` and `./`. It expects this file to contain the standard Report Portal configuration options -- see the Report Portal documentation.
|
33
|
+
It will search for a file called `report_portal.yml` or `REPORT_PORTAL.YML` in `./config` and `./`. It expects this file to contain the standard Report Portal configuration options -- see the Report Portal documentation. Optionally, the config file keys may match those accepted through environment variables -- they may contain 'rp*' and 'RP*'.
|
34
|
+
|
35
|
+
#### Configurable Timeouts
|
36
|
+
|
37
|
+
When running in parallel you might encounter some connection timeouts and these have been made configurable. You can configure the Report Portal yaml file with these attributes and set your own custom timeout values.
|
38
|
+
|
39
|
+
```yaml
|
40
|
+
idle_timeout: 100
|
41
|
+
open_timeout: 60
|
42
|
+
read_timeout: 60
|
43
|
+
```
|
34
44
|
|
35
45
|
#### Environment variables
|
36
46
|
|
37
47
|
It will search for the following environment variables which may be in upper or lowercase (the official client defers to lower case, this is available here for compatibility).
|
38
48
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
49
|
+
- `RP_UUID` - the user's UUID for this Report Portal instance which must be created in advance
|
50
|
+
- `RP_ENDPOINT` - the endpoint for this Report Portal instance
|
51
|
+
- `RP_PROJECT` - the Report Portal project name which must be created in advance and this user added as a member
|
52
|
+
- `RP_LAUNCH` - the name of this 'launch'
|
53
|
+
- `RP_DEBUG` - _optional_ if set to the string value `true` it will instruct Report Portal to add the output of these tests to the debug tab
|
54
|
+
- `RP_DESCRIPTION` - _optional_ a textual description of the launch
|
55
|
+
- `RP_TAGS` - _optional_ a string of comma separated tags
|
56
|
+
- `RP_ATTRIBUTES` - _optional_ a string of comma separated attributes
|
47
57
|
|
48
58
|
### With cucumber
|
49
59
|
|
@@ -61,9 +71,7 @@ cucumber -f ParallelReportPortal::Cucumber::Formatter --out /dev/null -f progres
|
|
61
71
|
|
62
72
|
```
|
63
73
|
parallel_cucumber -- -f ParallelReportPortal::Cucumber::Formatter -- features/
|
64
|
-
|
65
|
-
|
66
|
-
|
74
|
+
```
|
67
75
|
|
68
76
|
## Development
|
69
77
|
|
@@ -22,7 +22,7 @@ module ParallelReportPortal
|
|
22
22
|
# RP_TAGS:: A set of tags to pass to Report Portal for this launch. If these are set via an environment variable, provide a comma-separated string of tags
|
23
23
|
# RP_ATTRIBUTES:: A set of attribute tags to pass to Report Portal for this launch. If these are set via an environment variable, provide a comma-separated string of attributes
|
24
24
|
class Configuration
|
25
|
-
ATTRIBUTES = [:uuid, :endpoint, :project, :launch, :debug, :description, :tags, :attributes]
|
25
|
+
ATTRIBUTES = [:uuid, :endpoint, :project, :launch, :debug, :description, :tags, :attributes, :open_timeout, :idle_timeout, :read_timeout]
|
26
26
|
|
27
27
|
# @return [String] the Report Portal user UUID
|
28
28
|
attr_accessor :uuid
|
@@ -45,10 +45,16 @@ module ParallelReportPortal
|
|
45
45
|
# @return [Array<String>] an array of attributes to attach to this launch
|
46
46
|
# (Report Portal 5)
|
47
47
|
attr_reader :attributes
|
48
|
-
|
48
|
+
# @return [Integer] the number of seconds for the open connection to timeout
|
49
|
+
attr_accessor :open_timeout
|
50
|
+
# @return [Integer] the number of seconds for the open and idle connection to timeout
|
51
|
+
attr_accessor :idle_timeout
|
52
|
+
# @return [Integer] the number of seconds for the read connection to timeout
|
53
|
+
attr_accessor :read_timeout
|
54
|
+
|
49
55
|
|
50
56
|
# Create an instance of Configuration.
|
51
|
-
#
|
57
|
+
#
|
52
58
|
# The initializer will first attempt to load a configuration files called
|
53
59
|
# +report_portal.yml+ (case insensitive) in the both the +config+ and current
|
54
60
|
# working directory (the former takes precidence). It will then apply
|
@@ -64,18 +70,18 @@ module ParallelReportPortal
|
|
64
70
|
# Sets the tags for the launch. If an array is provided, the array is used,
|
65
71
|
# if a string is provided, the string is broken into components by splitting
|
66
72
|
# on a comma.
|
67
|
-
#
|
73
|
+
#
|
68
74
|
# e.g.
|
69
75
|
# configuration.tags="one,two, three"
|
70
76
|
# #=> ["one", "two", "three"]
|
71
|
-
#
|
77
|
+
#
|
72
78
|
# param [String | Array<String>] taglist a list of tags to set
|
73
79
|
def tags=(taglist)
|
74
80
|
if taglist.is_a?(String)
|
75
81
|
@tags = taglist.split(',').map(&:strip)
|
76
82
|
elsif taglist.is_a?(Array)
|
77
83
|
@tags = taglist
|
78
|
-
else
|
84
|
+
else
|
79
85
|
@tags = []
|
80
86
|
end
|
81
87
|
tags
|
@@ -84,7 +90,7 @@ module ParallelReportPortal
|
|
84
90
|
|
85
91
|
# Enables the debug flag which is sent to Report Portal. If this flag is set
|
86
92
|
# Report Portal will include this launch in its 'debug' tab.
|
87
|
-
#
|
93
|
+
#
|
88
94
|
# param [Boolean | String] value if the value is a Boolean, it will take that value
|
89
95
|
# if it is a String, it will set values of 'true' to +true+, else all values will be false.
|
90
96
|
def debug=(value)
|
@@ -95,21 +101,27 @@ module ParallelReportPortal
|
|
95
101
|
end
|
96
102
|
end
|
97
103
|
|
104
|
+
# Simple method to obtain an attribute from this class or set default value
|
105
|
+
# param [symbol] a symbol version of the attribute
|
106
|
+
def fetch(key, default_value)
|
107
|
+
self.send(key).nil? ? default_value : self.send(key)
|
108
|
+
end
|
109
|
+
|
98
110
|
# Sets the attributes for the launch. If an array is provided, the array is used,
|
99
111
|
# if a string is provided, the string is broken into components by splitting
|
100
112
|
# on a comma.
|
101
|
-
#
|
113
|
+
#
|
102
114
|
# e.g.
|
103
115
|
# configuration.tags="one,two, three"
|
104
116
|
# #=> ["one", "two", "three"]
|
105
|
-
#
|
117
|
+
#
|
106
118
|
# param [String | Array<String>] taglist a list of tags to set
|
107
119
|
def attributes=(attrlist)
|
108
120
|
if attrlist.is_a?(String)
|
109
121
|
@attributes = attrlist.split(',').map(&:strip)
|
110
122
|
elsif attrlist.is_a?(Array)
|
111
123
|
@attributes = attrlist
|
112
|
-
else
|
124
|
+
else
|
113
125
|
@attributes = []
|
114
126
|
end
|
115
127
|
attributes
|
@@ -129,10 +141,18 @@ module ParallelReportPortal
|
|
129
141
|
.then { |fn| fn ? File.read(fn) : '' }
|
130
142
|
.then { |ys| YAML.safe_load(ys, symbolize_names: true) }
|
131
143
|
.then do |yaml|
|
144
|
+
if yaml
|
145
|
+
yaml.transform_keys! { |key| key.downcase }
|
132
146
|
ATTRIBUTES.each do |attr|
|
133
|
-
|
147
|
+
yaml_key = if yaml.has_key?("rp_#{attr}".to_sym)
|
148
|
+
"rp_#{attr}".to_sym
|
149
|
+
else
|
150
|
+
attr
|
151
|
+
end
|
152
|
+
send(:"#{attr}=", yaml[yaml_key]) if yaml.fetch(yaml_key, nil)
|
134
153
|
end
|
135
154
|
end
|
155
|
+
end
|
136
156
|
end
|
137
157
|
end
|
138
158
|
end
|
@@ -2,7 +2,7 @@ require 'logger'
|
|
2
2
|
require 'tempfile'
|
3
3
|
|
4
4
|
module ParallelReportPortal
|
5
|
-
# A collection of methods for communicating with the ReportPortal
|
5
|
+
# A collection of methods for communicating with the ReportPortal
|
6
6
|
# REST interface.
|
7
7
|
module HTTP
|
8
8
|
|
@@ -10,16 +10,16 @@ module ParallelReportPortal
|
|
10
10
|
@@logger = Logger.new(STDOUT)
|
11
11
|
@@logger.level = Logger::ERROR
|
12
12
|
|
13
|
-
# Construct the Report Portal project URL (as a string) based
|
13
|
+
# Construct the Report Portal project URL (as a string) based
|
14
14
|
# on the config settings.
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# @return [String] URL the report portal base URL
|
17
17
|
def url
|
18
18
|
"#{ParallelReportPortal.configuration.endpoint}/#{ParallelReportPortal.configuration.project}"
|
19
19
|
end
|
20
20
|
|
21
21
|
# Helper method for constructing the +Bearer+ header
|
22
|
-
#
|
22
|
+
#
|
23
23
|
# @return [String] header the bearer header value
|
24
24
|
def authorization_header
|
25
25
|
"Bearer #{ParallelReportPortal.configuration.uuid}"
|
@@ -28,7 +28,7 @@ module ParallelReportPortal
|
|
28
28
|
# Get a preconstructed Faraday HTTP connection
|
29
29
|
# which has the endpont and headers ready populated.
|
30
30
|
# This object is memoized.
|
31
|
-
#
|
31
|
+
#
|
32
32
|
# @return [Faraday::Connection] connection the HTTP connection object
|
33
33
|
def http_connection
|
34
34
|
@http_connection ||= Faraday.new(
|
@@ -39,7 +39,9 @@ module ParallelReportPortal
|
|
39
39
|
}
|
40
40
|
) do |f|
|
41
41
|
f.adapter :net_http_persistent, pool_size: 5 do |http|
|
42
|
-
http.idle_timeout = 100
|
42
|
+
http.idle_timeout = ParallelReportPortal.configuration.fetch(:idle_timeout, 100)
|
43
|
+
http.open_timeout = ParallelReportPortal.configuration.fetch(:open_timeout, 60)
|
44
|
+
http.read_timeout = ParallelReportPortal.configuration.fetch(:read_timeout, 60)
|
43
45
|
end
|
44
46
|
end
|
45
47
|
end
|
@@ -47,7 +49,7 @@ module ParallelReportPortal
|
|
47
49
|
# Get a preconstructed Faraday HTTP multipart connection
|
48
50
|
# which has the endpont and headers ready populated.
|
49
51
|
# This object is memoized.
|
50
|
-
#
|
52
|
+
#
|
51
53
|
# @return [Faraday::Connection] connection the HTTP connection object
|
52
54
|
def http_multipart_connection
|
53
55
|
@http_multipart_connection ||= Faraday.new(
|
@@ -60,7 +62,9 @@ module ParallelReportPortal
|
|
60
62
|
conn.request :url_encoded
|
61
63
|
conn.adapter :net_http_persistent, pool_size: 5 do |http|
|
62
64
|
# yields Net::HTTP::Persistent
|
63
|
-
http.idle_timeout = 100
|
65
|
+
http.idle_timeout = ParallelReportPortal.configuration.fetch(:idle_timeout, 100)
|
66
|
+
http.open_timeout = ParallelReportPortal.configuration.fetch(:open_timeout, 60)
|
67
|
+
http.read_timeout = ParallelReportPortal.configuration.fetch(:read_timeout, 60)
|
64
68
|
end
|
65
69
|
end
|
66
70
|
end
|
@@ -70,10 +74,10 @@ module ParallelReportPortal
|
|
70
74
|
def req_launch_started(time)
|
71
75
|
resp = http_connection.post('launch') do |req|
|
72
76
|
req.body = {
|
73
|
-
name: ParallelReportPortal.configuration.launch,
|
74
|
-
start_time: time,
|
75
|
-
tags: ParallelReportPortal.configuration.tags,
|
76
|
-
description: ParallelReportPortal.configuration.description,
|
77
|
+
name: ParallelReportPortal.configuration.launch,
|
78
|
+
start_time: time,
|
79
|
+
tags: ParallelReportPortal.configuration.tags,
|
80
|
+
description: ParallelReportPortal.configuration.description,
|
77
81
|
mode: (ParallelReportPortal.configuration.debug ? 'DEBUG' : 'DEFAULT' ),
|
78
82
|
attributes: ParallelReportPortal.configuration.attributes
|
79
83
|
}.to_json
|
@@ -84,7 +88,7 @@ module ParallelReportPortal
|
|
84
88
|
@@logger.error("Launch failed with response code #{resp.status} -- message #{resp.body}")
|
85
89
|
end
|
86
90
|
end
|
87
|
-
|
91
|
+
|
88
92
|
# Send a request to Report Portal to finish a launch.
|
89
93
|
# It will bubble up any Faraday connection exceptions.
|
90
94
|
def req_launch_finished(launch_id, time)
|
@@ -92,10 +96,10 @@ module ParallelReportPortal
|
|
92
96
|
req.body = { end_time: time }.to_json
|
93
97
|
end
|
94
98
|
end
|
95
|
-
|
99
|
+
|
96
100
|
# Send a request to ReportPortal to start a feature.
|
97
101
|
# It will bubble up any Faraday connection exceptions.
|
98
|
-
#
|
102
|
+
#
|
99
103
|
# @return [String] id the UUID of the feature
|
100
104
|
def req_feature_started(launch_id, parent_id, feature, time)
|
101
105
|
description = if feature.description
|
@@ -112,9 +116,9 @@ module ParallelReportPortal
|
|
112
116
|
description,
|
113
117
|
time )
|
114
118
|
end
|
115
|
-
|
119
|
+
|
116
120
|
# Sends a request to Report Portal to add an item into its hierarchy.
|
117
|
-
#
|
121
|
+
#
|
118
122
|
# @return [String] uuid the UUID of the newly created child
|
119
123
|
def req_hierarchy(launch_id, name, parent, type, tags, description, time )
|
120
124
|
resource = 'item'
|
@@ -130,23 +134,23 @@ module ParallelReportPortal
|
|
130
134
|
attributes: tags
|
131
135
|
}.to_json
|
132
136
|
end
|
133
|
-
|
137
|
+
|
134
138
|
if resp.success?
|
135
139
|
JSON.parse(resp.body)['id']
|
136
140
|
else
|
137
141
|
@@logger.warn("Starting a heirarchy failed with response code #{resp.status} -- message #{resp.body}")
|
138
142
|
end
|
139
143
|
end
|
140
|
-
|
144
|
+
|
141
145
|
# Send a request to Report Portal that a feature has completed.
|
142
146
|
def req_feature_finished(feature_id, time)
|
143
147
|
ParallelReportPortal.http_connection.put("item/#{feature_id}") do |req|
|
144
148
|
req.body = { end_time: time }.to_json
|
145
149
|
end
|
146
150
|
end
|
147
|
-
|
151
|
+
|
148
152
|
# Send a request to ReportPortal to start a test case.
|
149
|
-
#
|
153
|
+
#
|
150
154
|
# @return [String] uuid the UUID of the test case
|
151
155
|
def req_test_case_started(launch_id, feature_id, test_case, time)
|
152
156
|
resp = ParallelReportPortal.http_connection.post("item/#{feature_id}") do |req|
|
@@ -172,7 +176,7 @@ module ParallelReportPortal
|
|
172
176
|
@@logger.warn("Starting a test case failed with response code #{resp.status} -- message #{resp.body}")
|
173
177
|
end
|
174
178
|
end
|
175
|
-
|
179
|
+
|
176
180
|
# Request that the test case be finished
|
177
181
|
def req_test_case_finished(test_case_id, status, time)
|
178
182
|
resp = ParallelReportPortal.http_connection.put("item/#{test_case_id}") do |req|
|
@@ -182,8 +186,8 @@ module ParallelReportPortal
|
|
182
186
|
}.to_json
|
183
187
|
end
|
184
188
|
end
|
185
|
-
|
186
|
-
|
189
|
+
|
190
|
+
|
187
191
|
# Request that Report Portal records a log record
|
188
192
|
def req_log(test_case_id, detail, level, time)
|
189
193
|
resp = ParallelReportPortal.http_connection.post('log') do |req|
|
@@ -198,19 +202,26 @@ module ParallelReportPortal
|
|
198
202
|
|
199
203
|
|
200
204
|
# Request that Report Portal attach a file to the test case.
|
201
|
-
#
|
205
|
+
#
|
202
206
|
# @param status [String] the status level of the log, e.g. info, warn
|
203
207
|
# @param path [String] the fully qualified path of the file to attach
|
204
208
|
# @param label [String] a label to add to the attachment, defaults to the filename
|
205
209
|
# @param time [Integer] the time in milliseconds for the attachment
|
206
210
|
# @param mime_type [String] the mimetype of the attachment
|
207
|
-
def send_file(
|
211
|
+
def send_file(
|
212
|
+
status,
|
213
|
+
path,
|
214
|
+
label = nil,
|
215
|
+
time = ParallelReportPortal.clock,
|
216
|
+
mime_type = 'image/png',
|
217
|
+
scenario_id = nil
|
218
|
+
)
|
208
219
|
File.open(File.realpath(path), 'rb') do |file|
|
209
220
|
label ||= File.basename(file)
|
210
221
|
|
211
|
-
# where did @test_case_id come from? ok, I know where it came from but this
|
222
|
+
# where did @test_case_id come from? ok, I know where it came from but this
|
212
223
|
# really should be factored out of here and state handled better
|
213
|
-
json = { level: status, message: label, item_id: @test_case_id, time: time, file: { name: File.basename(file) } }
|
224
|
+
json = { level: status, message: label, item_id: scenario_id || @test_case_id, time: time, file: { name: File.basename(file) } }
|
214
225
|
|
215
226
|
json_file = Tempfile.new
|
216
227
|
json_file << [json].to_json
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallel_report_portal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nigel Brookes-Thomas
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-08-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: appraisal
|
@@ -187,7 +187,7 @@ executables: []
|
|
187
187
|
extensions: []
|
188
188
|
extra_rdoc_files: []
|
189
189
|
files:
|
190
|
-
- ".
|
190
|
+
- ".github/workflows/tests.yml"
|
191
191
|
- ".gitignore"
|
192
192
|
- ".rspec"
|
193
193
|
- Appraisals
|
@@ -234,7 +234,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
234
234
|
- !ruby/object:Gem::Version
|
235
235
|
version: '0'
|
236
236
|
requirements: []
|
237
|
-
rubygems_version: 3.
|
237
|
+
rubygems_version: 3.3.7
|
238
238
|
signing_key:
|
239
239
|
specification_version: 4
|
240
240
|
summary: Run Cucumber Tests in parallel and with Cucumber 3 and 4+
|
data/.drone.yml
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
kind: pipeline
|
2
|
-
name: default
|
3
|
-
|
4
|
-
platform:
|
5
|
-
os: linux
|
6
|
-
arch: amd64
|
7
|
-
|
8
|
-
steps:
|
9
|
-
- name: Build & Publish
|
10
|
-
pull: if-not-exists
|
11
|
-
image: 714782054810.dkr.ecr.eu-west-2.amazonaws.com/base-images/qe-ruby:2.7.0
|
12
|
-
commands:
|
13
|
-
- apk add --update git --update alpine-sdk --no-cache
|
14
|
-
- gem install bundler
|
15
|
-
- bundle
|
16
|
-
- gem install nexus
|
17
|
-
- gem build parallel_report_portal.gemspec
|
18
|
-
- gem nexus --url https://nexus.tooling.dvla.gov.uk/repository/gem-private/ parallel_report_portal*gem
|
19
|
-
when:
|
20
|
-
branch:
|
21
|
-
- master
|