gitlab-qa 4.3.3 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +434 -284
- data/.rubocop.yml +0 -3
- data/bin/merge_html_reports +86 -0
- data/bin/notify_upstream_commit +16 -8
- data/docs/run_qa_against_gdk.md +10 -8
- data/docs/what_tests_can_be_run.md +8 -0
- data/gitlab-qa.gemspec +3 -3
- data/lib/gitlab/qa.rb +6 -0
- data/lib/gitlab/qa/component/gitlab.rb +11 -0
- data/lib/gitlab/qa/component/specs.rb +11 -0
- data/lib/gitlab/qa/component/staging.rb +4 -89
- data/lib/gitlab/qa/release.rb +20 -1
- data/lib/gitlab/qa/scenario/test/instance/deployment_base.rb +0 -11
- data/lib/gitlab/qa/scenario/test/integration/geo.rb +0 -1
- data/lib/gitlab/qa/scenario/test/integration/object_storage.rb +0 -2
- data/lib/gitlab/qa/support/dev_ee_qa_image.rb +52 -0
- data/lib/gitlab/qa/support/get_request.rb +39 -0
- data/lib/gitlab/qa/support/invalid_response_error.rb +9 -0
- data/lib/gitlab/qa/version.rb +1 -1
- metadata +12 -8
data/.rubocop.yml
CHANGED
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
main_report_file = ARGV.shift
|
6
|
+
unless main_report_file
|
7
|
+
puts 'usage: merge_html_reports <main-report> <base-artifact-url> [parallel reports...]'
|
8
|
+
exit 1
|
9
|
+
end
|
10
|
+
|
11
|
+
base_artifact_url = ARGV.shift
|
12
|
+
unless base_artifact_url
|
13
|
+
puts 'usage: merge_html_reports <main-report> <base-artifact-url> [parallel reports...]'
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create the base report with empty body tag
|
18
|
+
new_report = Nokogiri::HTML.parse(File.read(ARGV[0]))
|
19
|
+
new_report.at_css('body').remove
|
20
|
+
empty_body = Nokogiri::XML::Node.new('body', new_report)
|
21
|
+
new_report.at_css('head').add_next_sibling(empty_body)
|
22
|
+
|
23
|
+
ARGV.each do |report_file|
|
24
|
+
report = Nokogiri::HTML.parse(File.read(report_file))
|
25
|
+
|
26
|
+
report.css('a').each do |link|
|
27
|
+
link_suffix = link['href'].slice(19..-1)
|
28
|
+
link['href'] = base_artifact_url + link_suffix
|
29
|
+
end
|
30
|
+
|
31
|
+
header = report.css('div #rspec-header')
|
32
|
+
tests = report.css('dt[id^="example_group_"]')
|
33
|
+
|
34
|
+
header.search("//h1/text()").first.content = "Test results for job: #{report_file.slice(/rspec-(.*)\.htm/, 1)}"
|
35
|
+
|
36
|
+
tests.each do |test|
|
37
|
+
title = test.parent
|
38
|
+
group = title.parent
|
39
|
+
script = title.css('script')
|
40
|
+
|
41
|
+
if script.inner_html.include? 'makeYellow'
|
42
|
+
test.remove_class('passed')
|
43
|
+
test.add_class('not_implemented')
|
44
|
+
|
45
|
+
group.remove_class('passed')
|
46
|
+
group.add_class('not_implemented')
|
47
|
+
header.add_class('not_implemented')
|
48
|
+
|
49
|
+
script.remove
|
50
|
+
test.next_sibling.remove
|
51
|
+
test.next_sibling.remove
|
52
|
+
|
53
|
+
elsif script.inner_html.include? 'makeRed'
|
54
|
+
test.remove_class('passed')
|
55
|
+
test.add_class('failed')
|
56
|
+
|
57
|
+
group.remove_class('passed')
|
58
|
+
group.add_class('failed')
|
59
|
+
header.add_class('failed')
|
60
|
+
|
61
|
+
script.remove
|
62
|
+
test.next_sibling.remove
|
63
|
+
test.next_sibling.remove
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
duration = report.at_css('p#duration')
|
68
|
+
totals = report.at_css('p#totals')
|
69
|
+
|
70
|
+
duration_script = report.css('div.results script')[-2]
|
71
|
+
totals_script = report.css('div.results script')[-1]
|
72
|
+
|
73
|
+
duration_text = duration_script.text.slice(49..-3)
|
74
|
+
totals_text = totals_script.text.slice(47..-3)
|
75
|
+
|
76
|
+
duration.inner_html = duration_text
|
77
|
+
totals.inner_html = totals_text
|
78
|
+
|
79
|
+
duration_script.remove
|
80
|
+
totals_script.remove
|
81
|
+
|
82
|
+
# Add the new result after the last one to keep the test order
|
83
|
+
new_report.css('body')[-1].add_next_sibling(report.at_css('body'))
|
84
|
+
end
|
85
|
+
|
86
|
+
File.write(main_report_file, new_report)
|
data/bin/notify_upstream_commit
CHANGED
@@ -10,7 +10,7 @@ Gitlab.configure do |config|
|
|
10
10
|
end
|
11
11
|
|
12
12
|
class CommitComment
|
13
|
-
def self.post!(status)
|
13
|
+
def self.post!(status, report_file_name)
|
14
14
|
unless ENV['TOP_UPSTREAM_SOURCE_SHA']
|
15
15
|
puts "The 'TOP_UPSTREAM_SOURCE_SHA' environment variable is missing, cannot post a comment on a missing upstream commit."
|
16
16
|
return
|
@@ -33,18 +33,26 @@ class CommitComment
|
|
33
33
|
"failed! :boom:"
|
34
34
|
end
|
35
35
|
|
36
|
+
# The HTML report can't be opened as a web page so we're forced to
|
37
|
+
# download it. See https://gitlab.com/gitlab-org/gitlab/issues/25192
|
36
38
|
Gitlab.create_commit_comment(
|
37
39
|
top_upstream_source_project,
|
38
40
|
top_upstream_source_sha,
|
39
|
-
|
41
|
+
<<~COMMENT
|
42
|
+
The [`gitlab-qa` downstream pipeline](#{ENV['CI_PIPELINE_URL']}) #{status_with_icon}.
|
43
|
+
|
44
|
+
You can download a report of the test results: [`#{report_file_name}`](#{ENV['CI_JOB_URL']}/artifacts/raw/#{report_file_name})
|
45
|
+
COMMENT
|
46
|
+
)
|
40
47
|
rescue Gitlab::Error::Error => error
|
41
48
|
puts "Ignoring the following error: #{error}"
|
42
49
|
end
|
43
50
|
end
|
44
51
|
|
45
|
-
status = ARGV
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
status = ARGV.shift.to_s.strip
|
53
|
+
report_file_name = ARGV.shift.to_s.strip
|
54
|
+
|
55
|
+
abort "Please provide a status!" if status == ''
|
56
|
+
abort "Please provide a file name for the report!" if report_file_name == ''
|
57
|
+
|
58
|
+
CommitComment.post!(status.to_sym, report_file_name)
|
data/docs/run_qa_against_gdk.md
CHANGED
@@ -5,16 +5,18 @@ make a few changes to your `gdk/gitlab/config/gitlab.yml` file.
|
|
5
5
|
|
6
6
|
1. Retrieve your current local IP with `ifconfig`, e.g. `192.168.0.12`.
|
7
7
|
1. Create a file named `host` in your GDK directory containing your IP. E.g.:
|
8
|
-
`echo 192.168.0.12 > host`
|
9
|
-
1. Edit `gdk/gitlab/config/gitlab.yml` and
|
10
|
-
`host: 192.168.0.12`.
|
11
|
-
|
8
|
+
`echo "192.168.0.12" > host`
|
9
|
+
1. Edit `gdk/gitlab/config/gitlab.yml` and
|
10
|
+
- replace `host: localhost` under `production:gitlab` with `host: 192.168.0.12`.
|
11
|
+
- replace `ssh_host: localhost` under `production:gitlab_shell` with
|
12
12
|
`ssh_host: 192.168.0.12`.
|
13
|
-
|
14
|
-
`
|
15
|
-
1. Edit `
|
13
|
+
- replace `host: localhost` under `production:webpack:dev_server` with
|
14
|
+
`host: 192.168.0.12`.
|
15
|
+
1. Edit `Procfile` in your GDK directory and
|
16
|
+
- enable the `sshd` service by uncommenting the relevant line
|
17
|
+
1. Edit `openssh/sshd_config` in your GDK directory and
|
16
18
|
- set `ListenAddress` to `192.168.0.12:2222`
|
17
|
-
- add `AcceptEnv GIT_PROTOCOL` to allow use of [Git protocol v2][Git protocol]
|
19
|
+
- add `AcceptEnv GIT_PROTOCOL` to allow the use of the [Git protocol v2][Git protocol]
|
18
20
|
1. Restart your GDK
|
19
21
|
1. Run the QA scenario as follows:
|
20
22
|
|
@@ -36,6 +36,14 @@ For more details on the internals, please read the
|
|
36
36
|
* `GITLAB_QA_PASSWORD_1` - password for `GITLAB_QA_USERNAME_1` available in environments where signup is disabled (e.g. staging.gitlab.com)
|
37
37
|
* `GITLAB_QA_USERNAME_2` - another username available in environments where signup is disabled
|
38
38
|
* `GITLAB_QA_PASSWORD_2` - password for `GITLAB_QA_USERNAME_2` available in environments where signup is disabled (e.g. staging.gitlab.com)
|
39
|
+
* `GITLAB_QA_USERNAME_3` - another username available in environments where signup is disabled
|
40
|
+
* `GITLAB_QA_PASSWORD_3` - password for `GITLAB_QA_USERNAME_3` available in environments where signup is disabled (e.g. staging.gitlab.com)
|
41
|
+
* `GITLAB_QA_USERNAME_4` - another username available in environments where signup is disabled
|
42
|
+
* `GITLAB_QA_PASSWORD_4` - password for `GITLAB_QA_USERNAME_4` available in environments where signup is disabled (e.g. staging.gitlab.com)
|
43
|
+
* `GITLAB_QA_USERNAME_5` - another username available in environments where signup is disabled
|
44
|
+
* `GITLAB_QA_PASSWORD_5` - password for `GITLAB_QA_USERNAME_5` available in environments where signup is disabled (e.g. staging.gitlab.com)
|
45
|
+
* `GITLAB_QA_USERNAME_6` - another username available in environments where signup is disabled
|
46
|
+
* `GITLAB_QA_PASSWORD_6` - password for `GITLAB_QA_USERNAME_6` available in environments where signup is disabled (e.g. staging.gitlab.com)
|
39
47
|
* `GITLAB_LDAP_USERNAME` - LDAP username to use when signing into GitLab
|
40
48
|
* `GITLAB_LDAP_PASSWORD` - LDAP password to use when signing into GitLab
|
41
49
|
* `GITLAB_ADMIN_USERNAME` - Admin username to use when adding a license
|
data/gitlab-qa.gemspec
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
lib = File.expand_path('
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
3
|
require 'gitlab/qa/version'
|
4
4
|
|
@@ -20,11 +20,11 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
# Some dependencies are pinned, to prevent new cops from breaking the CI pipelines
|
22
22
|
spec.add_development_dependency 'climate_control', '~> 0.2'
|
23
|
-
spec.add_development_dependency 'gitlab-styles', '2.
|
23
|
+
spec.add_development_dependency 'gitlab-styles', '2.4.0'
|
24
24
|
spec.add_development_dependency 'pry', '~> 0.11'
|
25
25
|
spec.add_development_dependency 'rake', '~> 12.2'
|
26
26
|
spec.add_development_dependency 'rspec', '~> 3.7'
|
27
|
-
spec.add_development_dependency 'rubocop', '0.
|
27
|
+
spec.add_development_dependency 'rubocop', '~> 0.54.0'
|
28
28
|
spec.add_development_dependency 'rubocop-rspec', '1.20.1'
|
29
29
|
spec.add_development_dependency 'webmock', '3.7.0'
|
30
30
|
end
|
data/lib/gitlab/qa.rb
CHANGED
@@ -64,6 +64,12 @@ module Gitlab
|
|
64
64
|
autoload :Elasticsearch, 'gitlab/qa/component/elasticsearch'
|
65
65
|
end
|
66
66
|
|
67
|
+
module Support
|
68
|
+
autoload :GetRequest, 'gitlab/qa/support/get_request'
|
69
|
+
autoload :DevEEQAImage, 'gitlab/qa/support/dev_ee_qa_image'
|
70
|
+
autoload :InvalidResponseError, 'gitlab/qa/support/invalid_response_error'
|
71
|
+
end
|
72
|
+
|
67
73
|
module Docker
|
68
74
|
autoload :Command, 'gitlab/qa/docker/command'
|
69
75
|
autoload :Engine, 'gitlab/qa/docker/engine'
|
@@ -97,6 +97,17 @@ module Gitlab
|
|
97
97
|
def start # rubocop:disable Metrics/AbcSize
|
98
98
|
ensure_configured!
|
99
99
|
|
100
|
+
if release.dev_gitlab_org?
|
101
|
+
Docker::Command.execute(
|
102
|
+
[
|
103
|
+
'login',
|
104
|
+
'--username gitlab-qa-bot',
|
105
|
+
%(--password "#{Runtime::Env.dev_access_token_variable}"),
|
106
|
+
Release::DEV_REGISTRY
|
107
|
+
]
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
100
111
|
docker.run(image, tag) do |command|
|
101
112
|
command << "-d -p #{port}"
|
102
113
|
command << "--name #{name}"
|
@@ -18,6 +18,17 @@ module Gitlab
|
|
18
18
|
def perform # rubocop:disable Metrics/AbcSize
|
19
19
|
raise ArgumentError unless [suite, release].all?
|
20
20
|
|
21
|
+
if release.dev_gitlab_org?
|
22
|
+
Docker::Command.execute(
|
23
|
+
[
|
24
|
+
'login',
|
25
|
+
'--username gitlab-qa-bot',
|
26
|
+
%(--password "#{Runtime::Env.dev_access_token_variable}"),
|
27
|
+
Release::DEV_REGISTRY
|
28
|
+
]
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
21
32
|
puts "Running test suite `#{suite}` for #{release.project_name}"
|
22
33
|
|
23
34
|
name = "#{release.project_name}-qa-#{SecureRandom.hex(4)}"
|
@@ -8,19 +8,9 @@ module Gitlab
|
|
8
8
|
class Staging
|
9
9
|
ADDRESS = 'https://staging.gitlab.com'.freeze
|
10
10
|
|
11
|
-
class InvalidResponseError < StandardError
|
12
|
-
attr_reader :response
|
13
|
-
|
14
|
-
def initialize(address, response)
|
15
|
-
@response = response
|
16
|
-
|
17
|
-
super "Invalid response received from #{address}"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
11
|
def self.release
|
22
12
|
Release.new(image)
|
23
|
-
rescue InvalidResponseError => ex
|
13
|
+
rescue Support::InvalidResponseError => ex
|
24
14
|
warn ex.message
|
25
15
|
warn "#{ex.response.code} #{ex.response.message}: #{ex.response.body}"
|
26
16
|
exit 1
|
@@ -40,7 +30,7 @@ module Gitlab
|
|
40
30
|
# - https://gitlab.com/gitlab-org/quality/staging/issues/56
|
41
31
|
# - https://gitlab.com/gitlab-org/release/framework/issues/421
|
42
32
|
# - https://gitlab.com/gitlab-org/gitlab-qa/issues/398
|
43
|
-
DevEEQAImage.new.retrieve_image_from_container_registry!(staging_revision)
|
33
|
+
Support::DevEEQAImage.new.retrieve_image_from_container_registry!(staging_revision)
|
44
34
|
else
|
45
35
|
# Auto-deploy builds have a tag formatted like 12.0.12345+5159f2949cb.59c9fa631
|
46
36
|
# but the version api returns a semver version like 12.0.1
|
@@ -84,88 +74,13 @@ module Gitlab
|
|
84
74
|
private
|
85
75
|
|
86
76
|
def api_get!
|
87
|
-
@response_body ||=
|
77
|
+
@response_body ||= # rubocop:disable Naming/MemoizedInstanceVariableName
|
88
78
|
begin
|
89
|
-
response = GetRequest.new(uri, Runtime::Env.qa_access_token).execute!
|
79
|
+
response = Support::GetRequest.new(uri, Runtime::Env.qa_access_token).execute!
|
90
80
|
JSON.parse(response.body)
|
91
81
|
end
|
92
82
|
end
|
93
83
|
end
|
94
|
-
|
95
|
-
class DevEEQAImage
|
96
|
-
attr_reader :base_url
|
97
|
-
|
98
|
-
DEV_ADDRESS = 'https://dev.gitlab.org'.freeze
|
99
|
-
GITLAB_EE_QA_REPOSITORY_ID = 55
|
100
|
-
QAImageNotFoundError = Class.new(StandardError)
|
101
|
-
|
102
|
-
def initialize
|
103
|
-
@base_url = "#{DEV_ADDRESS}/api/v4/projects/gitlab%2Fomnibus-gitlab/registry/repositories/#{GITLAB_EE_QA_REPOSITORY_ID}/tags?per_page=100"
|
104
|
-
|
105
|
-
Runtime::Env.require_qa_dev_access_token!
|
106
|
-
end
|
107
|
-
|
108
|
-
def retrieve_image_from_container_registry!(revision)
|
109
|
-
request_url = base_url
|
110
|
-
|
111
|
-
begin
|
112
|
-
response = api_get!(URI.parse(request_url))
|
113
|
-
tags = JSON.parse(response.body)
|
114
|
-
|
115
|
-
matching_qa_image_tag = find_matching_qa_image_tag(tags, revision)
|
116
|
-
return matching_qa_image_tag['location'] if matching_qa_image_tag
|
117
|
-
|
118
|
-
request_url = next_page_url_from_response(response)
|
119
|
-
end while request_url
|
120
|
-
|
121
|
-
raise QAImageNotFoundError, "No `gitlab-ee-qa` image could be found for the revision `#{revision}`."
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
|
126
|
-
def api_get!(uri)
|
127
|
-
GetRequest.new(uri, Runtime::Env.qa_dev_access_token).execute!
|
128
|
-
end
|
129
|
-
|
130
|
-
def next_page_url_from_response(response)
|
131
|
-
response['x-next-page'].to_s != '' ? "#{base_url}&page=#{response['x-next-page']}" : nil
|
132
|
-
end
|
133
|
-
|
134
|
-
def find_matching_qa_image_tag(tags, revision)
|
135
|
-
tags.find { |tag| tag['name'].end_with?(revision) }
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
class GetRequest
|
140
|
-
attr_reader :uri, :token
|
141
|
-
|
142
|
-
def initialize(uri, token)
|
143
|
-
@uri = uri
|
144
|
-
@token = token
|
145
|
-
end
|
146
|
-
|
147
|
-
def execute!
|
148
|
-
response =
|
149
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
150
|
-
http.request(build_request)
|
151
|
-
end
|
152
|
-
|
153
|
-
case response
|
154
|
-
when Net::HTTPSuccess
|
155
|
-
response
|
156
|
-
else
|
157
|
-
raise InvalidResponseError.new(uri.to_s, response)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
private
|
162
|
-
|
163
|
-
def build_request
|
164
|
-
Net::HTTP::Get.new(uri).tap do |req|
|
165
|
-
req['PRIVATE-TOKEN'] = token
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
84
|
end
|
170
85
|
end
|
171
86
|
end
|
data/lib/gitlab/qa/release.rb
CHANGED
@@ -20,6 +20,21 @@ module Gitlab
|
|
20
20
|
(:(?<tag>.+))?
|
21
21
|
\z
|
22
22
|
}xi
|
23
|
+
|
24
|
+
# Dev tag example:
|
25
|
+
# 12.1.201906121026-325a6632895.b340d0bd35d
|
26
|
+
# |----|------------|-----------|-----------|
|
27
|
+
# | | | |
|
28
|
+
# | | | omnibus-ref
|
29
|
+
# | | gitlab-ee ref
|
30
|
+
# | timestamp
|
31
|
+
# version
|
32
|
+
DEV_TAG_REGEX = /
|
33
|
+
\A
|
34
|
+
(?<version>\d+\.\d+(.\d+)?)\.(?<timestamp>\d+)\-(?<gitlab_ref>[A-Za-z0-9]+)\.(?<omnibus_ref>[A-Za-z0-9]+)
|
35
|
+
\z
|
36
|
+
/xi
|
37
|
+
|
23
38
|
DEFAULT_TAG = 'latest'.freeze
|
24
39
|
DEFAULT_CANONICAL_TAG = 'nightly'.freeze
|
25
40
|
DEV_REGISTRY = 'dev.gitlab.org:5005'.freeze
|
@@ -98,7 +113,11 @@ module Gitlab
|
|
98
113
|
|
99
114
|
# Tag scheme for gitlab-{ce,ee}-qa images is like 11.1.0-rc12-ee
|
100
115
|
def qa_tag
|
101
|
-
tag.
|
116
|
+
if dev_gitlab_org? && (match_data = tag.match(DEV_TAG_REGEX))
|
117
|
+
"#{match_data[:version]}-#{match_data[:gitlab_ref]}"
|
118
|
+
else
|
119
|
+
tag.sub(/[-\.]([ce]e)(\.(\d+))?\z/, '-\1')
|
120
|
+
end
|
102
121
|
end
|
103
122
|
|
104
123
|
def dev_gitlab_org?
|
@@ -18,17 +18,6 @@ module Gitlab
|
|
18
18
|
|
19
19
|
args.unshift(release_name) if release_name&.start_with?('--')
|
20
20
|
|
21
|
-
if release.dev_gitlab_org?
|
22
|
-
Docker::Command.execute(
|
23
|
-
[
|
24
|
-
'login',
|
25
|
-
'--username gitlab-qa-bot',
|
26
|
-
%(--password "#{Runtime::Env.dev_access_token_variable}"),
|
27
|
-
Release::DEV_REGISTRY
|
28
|
-
]
|
29
|
-
)
|
30
|
-
end
|
31
|
-
|
32
21
|
Component::Specs.perform do |specs|
|
33
22
|
specs.suite = 'Test::Instance::All'
|
34
23
|
specs.release = release
|
@@ -6,7 +6,6 @@ module Gitlab
|
|
6
6
|
module Test
|
7
7
|
module Integration
|
8
8
|
class ObjectStorage < Scenario::Template
|
9
|
-
# rubocop:disable Metrics/AbcSize
|
10
9
|
def perform(release, *rspec_args)
|
11
10
|
Component::Gitlab.perform do |gitlab|
|
12
11
|
gitlab.release = release
|
@@ -41,7 +40,6 @@ module Gitlab
|
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
44
|
-
# rubocop:enable Metrics/AbcSize
|
45
43
|
end
|
46
44
|
end
|
47
45
|
end
|