gitlab-qa 8.4.2 → 8.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +0 -12
- data/Gemfile.lock +1 -1
- data/exe/gitlab-qa +1 -1
- data/lib/gitlab/qa/component/base.rb +2 -2
- data/lib/gitlab/qa/component/gitlab.rb +1 -1
- data/lib/gitlab/qa/component/staging.rb +17 -35
- data/lib/gitlab/qa/component/suggested_reviewer.rb +47 -0
- data/lib/gitlab/qa/docker/command.rb +3 -14
- data/lib/gitlab/qa/docker/engine.rb +1 -1
- data/lib/gitlab/qa/release.rb +6 -2
- data/lib/gitlab/qa/report/find_set_dri.rb +43 -0
- data/lib/gitlab/qa/report/gitlab_issue_client.rb +7 -0
- data/lib/gitlab/qa/report/relate_failure_issue.rb +16 -0
- data/lib/gitlab/qa/report/results_reporter_shared.rb +1 -1
- data/lib/gitlab/qa/report/test_result.rb +8 -0
- data/lib/gitlab/qa/runtime/env.rb +5 -14
- data/lib/gitlab/qa/scenario/test/integration/suggested_reviewer.rb +62 -0
- data/lib/gitlab/qa/scenario/test/omnibus/update_from_previous.rb +1 -1
- data/lib/gitlab/qa/service/cluster_provider/base.rb +33 -0
- data/lib/gitlab/qa/service/cluster_provider/k3d.rb +141 -0
- data/lib/gitlab/qa/service/kubernetes_cluster.rb +62 -0
- data/lib/gitlab/qa/support/shell_command.rb +98 -0
- data/lib/gitlab/qa/support/shellout.rb +16 -0
- data/lib/gitlab/qa/version.rb +1 -1
- data/lib/gitlab/qa.rb +0 -1
- data/support/manifests/suggested_reviewer/authenticator.yaml +41 -0
- data/support/manifests/suggested_reviewer/postgres.yaml +84 -0
- data/support/manifests/suggested_reviewer/pubsub.yaml +41 -0
- data/support/manifests/suggested_reviewer/recommender-bot.yaml +242 -0
- data/support/manifests/suggested_reviewer/recommender.yaml +52 -0
- metadata +15 -7
- data/lib/gitlab/qa/component/internet_tunnel.rb +0 -76
- data/lib/gitlab/qa/docker/shellout.rb +0 -77
- data/lib/gitlab/qa/scenario/test/integration/kubernetes.rb +0 -56
- data/lib/gitlab/qa/scenario/test/integration/ssh_tunnel.rb +0 -56
- data/lib/gitlab/qa/support/dev_ee_qa_image.rb +0 -54
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module Service
|
6
|
+
module ClusterProvider
|
7
|
+
class K3d < Base
|
8
|
+
def create_registry_mirror
|
9
|
+
return if registry_mirror_exists?('registry-gitlab')
|
10
|
+
|
11
|
+
Runtime::Env.require_qa_container_registry_access_token!
|
12
|
+
|
13
|
+
shell <<~CMD
|
14
|
+
k3d registry create registry-gitlab \
|
15
|
+
-p 5000 \
|
16
|
+
--proxy-remote-url https://#{GITLAB_REGISTRY} \
|
17
|
+
--proxy-password #{Runtime::Env.gitlab_username} \
|
18
|
+
--proxy-username #{Runtime::Env.qa_container_registry_access_token} \
|
19
|
+
-v tmp/registry-gitlab:/var/lib/registry
|
20
|
+
CMD
|
21
|
+
|
22
|
+
File.write('tmp/registry-mirror.yml', registry_mirror)
|
23
|
+
|
24
|
+
create_args << %w[--registry-use k3d-registry-gitlab:5000 --registry-config tmp/registry-mirror.yml]
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate_dependencies
|
28
|
+
find_executable('k3d') || raise("You must first install `k3d` executable to run these tests.")
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup
|
32
|
+
shell "k3d cluster create #{cluster_name} #{create_args&.join(' ')}"
|
33
|
+
|
34
|
+
install_local_storage
|
35
|
+
end
|
36
|
+
|
37
|
+
def teardown
|
38
|
+
shell "k3d cluster delete #{cluster_name}"
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def registry_mirror_exists?(name)
|
44
|
+
shell('k3d registry list').include?("k3d-#{name}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def retry_until(max_attempts: 10, wait: 1)
|
48
|
+
max_attempts.times do
|
49
|
+
result = yield
|
50
|
+
return result if result
|
51
|
+
|
52
|
+
sleep wait
|
53
|
+
end
|
54
|
+
|
55
|
+
raise "Retried #{max_attempts} times. Aborting"
|
56
|
+
end
|
57
|
+
|
58
|
+
def install_local_storage
|
59
|
+
shell('kubectl apply -f -', stdin_data: local_storage_config)
|
60
|
+
end
|
61
|
+
|
62
|
+
# See https://github.com/rancher/k3d/issues/67
|
63
|
+
def local_storage_config
|
64
|
+
<<~YAML
|
65
|
+
---
|
66
|
+
apiVersion: v1
|
67
|
+
kind: ServiceAccount
|
68
|
+
metadata:
|
69
|
+
name: storage-provisioner
|
70
|
+
namespace: kube-system
|
71
|
+
---
|
72
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
73
|
+
kind: ClusterRoleBinding
|
74
|
+
metadata:
|
75
|
+
name: storage-provisioner
|
76
|
+
roleRef:
|
77
|
+
apiGroup: rbac.authorization.k8s.io
|
78
|
+
kind: ClusterRole
|
79
|
+
name: system:persistent-volume-provisioner
|
80
|
+
subjects:
|
81
|
+
- kind: ServiceAccount
|
82
|
+
name: storage-provisioner
|
83
|
+
namespace: kube-system
|
84
|
+
---
|
85
|
+
apiVersion: v1
|
86
|
+
kind: Pod
|
87
|
+
metadata:
|
88
|
+
name: storage-provisioner
|
89
|
+
namespace: kube-system
|
90
|
+
spec:
|
91
|
+
serviceAccountName: storage-provisioner
|
92
|
+
tolerations:
|
93
|
+
- effect: NoExecute
|
94
|
+
key: node.kubernetes.io/not-ready
|
95
|
+
operator: Exists
|
96
|
+
tolerationSeconds: 300
|
97
|
+
- effect: NoExecute
|
98
|
+
key: node.kubernetes.io/unreachable
|
99
|
+
operator: Exists
|
100
|
+
tolerationSeconds: 300
|
101
|
+
hostNetwork: true
|
102
|
+
containers:
|
103
|
+
- name: storage-provisioner
|
104
|
+
image: gcr.io/k8s-minikube/storage-provisioner:v1.8.1
|
105
|
+
command: ["/storage-provisioner"]
|
106
|
+
imagePullPolicy: IfNotPresent
|
107
|
+
volumeMounts:
|
108
|
+
- mountPath: /tmp
|
109
|
+
name: tmp
|
110
|
+
volumes:
|
111
|
+
- name: tmp
|
112
|
+
hostPath:
|
113
|
+
path: /tmp
|
114
|
+
type: Directory
|
115
|
+
---
|
116
|
+
kind: StorageClass
|
117
|
+
apiVersion: storage.k8s.io/v1
|
118
|
+
metadata:
|
119
|
+
name: standard
|
120
|
+
namespace: kube-system
|
121
|
+
annotations:
|
122
|
+
storageclass.kubernetes.io/is-default-class: "true"
|
123
|
+
labels:
|
124
|
+
addonmanager.kubernetes.io/mode: EnsureExists
|
125
|
+
provisioner: k8s.io/minikube-hostpath
|
126
|
+
YAML
|
127
|
+
end
|
128
|
+
|
129
|
+
def registry_mirror
|
130
|
+
<<~YAML
|
131
|
+
mirrors:
|
132
|
+
"registry.gitlab.com":
|
133
|
+
endpoint:
|
134
|
+
- http://k3d-registry-gitlab:5000
|
135
|
+
YAML
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mkmf'
|
4
|
+
|
5
|
+
module Gitlab
|
6
|
+
module QA
|
7
|
+
module Service
|
8
|
+
class KubernetesCluster
|
9
|
+
include Support::Shellout
|
10
|
+
|
11
|
+
attr_reader :provider
|
12
|
+
|
13
|
+
def initialize(provider_class: QA::Service::ClusterProvider::K3d)
|
14
|
+
@provider = provider_class.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def create!
|
18
|
+
validate_dependencies
|
19
|
+
|
20
|
+
@provider.validate_dependencies
|
21
|
+
@provider.setup
|
22
|
+
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove!
|
27
|
+
@provider.teardown
|
28
|
+
end
|
29
|
+
|
30
|
+
def cluster_name
|
31
|
+
@provider.cluster_name
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
cluster_name
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_registry_mirror
|
39
|
+
@provider.create_registry_mirror
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_secret(secret, secret_name)
|
43
|
+
shell("kubectl create secret generic #{secret_name} --from-literal=token='#{secret}'", mask_secrets: [secret])
|
44
|
+
end
|
45
|
+
|
46
|
+
def apply_manifest(manifest)
|
47
|
+
shell('kubectl apply -f -', stdin_data: manifest)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def admin_user
|
53
|
+
@admin_user ||= "#{@provider.cluster_name}-admin"
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_dependencies
|
57
|
+
find_executable('kubectl') || raise("You must first install `kubectl` executable to run these tests.")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
require 'active_support/core_ext/string/filters'
|
5
|
+
|
6
|
+
module Gitlab
|
7
|
+
module QA
|
8
|
+
module Support
|
9
|
+
class ShellCommand
|
10
|
+
using Rainbow
|
11
|
+
|
12
|
+
StatusError = Class.new(StandardError)
|
13
|
+
|
14
|
+
# Shell command
|
15
|
+
#
|
16
|
+
# @param [<String, Array>] command
|
17
|
+
# @param [<String, Array>] mask_secrets
|
18
|
+
# @param [Boolean] stream_output stream command output to stdout directly instead of logger
|
19
|
+
def initialize(command = nil, stdin_data: nil, mask_secrets: nil, stream_output: false)
|
20
|
+
@command = command
|
21
|
+
@mask_secrets = Array(mask_secrets)
|
22
|
+
@stream_output = stream_output
|
23
|
+
@output = []
|
24
|
+
@logger = Runtime::Logger.logger
|
25
|
+
@stdin_data = stdin_data
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :command, :output, :stream_output
|
29
|
+
|
30
|
+
def execute! # rubocop:disable Metrics/AbcSize
|
31
|
+
raise StatusError, 'Command already executed' if output.any?
|
32
|
+
|
33
|
+
logger.info("Shell command: `#{mask_secrets(command).cyan}`")
|
34
|
+
|
35
|
+
Open3.popen2e(@command.to_s) do |stdin, out, wait|
|
36
|
+
if @stdin_data
|
37
|
+
stdin.puts(@stdin_data)
|
38
|
+
stdin.close
|
39
|
+
end
|
40
|
+
|
41
|
+
out.each do |line|
|
42
|
+
output.push(line)
|
43
|
+
|
44
|
+
if stream_progress
|
45
|
+
print "."
|
46
|
+
elsif stream_output
|
47
|
+
puts line
|
48
|
+
end
|
49
|
+
|
50
|
+
yield line, wait if block_given?
|
51
|
+
end
|
52
|
+
puts if stream_progress && !output.empty?
|
53
|
+
|
54
|
+
fail! if wait.value.exited? && wait.value.exitstatus.nonzero?
|
55
|
+
|
56
|
+
logger.debug("Shell command output:\n#{string_output}") unless stream_output || output.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
string_output
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
attr_reader :logger
|
65
|
+
|
66
|
+
# Raise error and print output to error log level
|
67
|
+
#
|
68
|
+
# @return [void]
|
69
|
+
def fail!
|
70
|
+
logger.error("Shell command output:\n#{string_output}") unless stream_output
|
71
|
+
raise StatusError, "Command `#{mask_secrets(command).truncate(100)}` failed! " + "✘".red
|
72
|
+
end
|
73
|
+
|
74
|
+
# Stream only command execution progress and log output when command finished
|
75
|
+
#
|
76
|
+
# @return [Boolean]
|
77
|
+
def stream_progress
|
78
|
+
!(Runtime::Env.ci || stream_output)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Stringified command output
|
82
|
+
#
|
83
|
+
# @return [String]
|
84
|
+
def string_output
|
85
|
+
mask_secrets(output.join.chomp)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns a masked string
|
89
|
+
#
|
90
|
+
# @param [String] input the string to mask
|
91
|
+
# @return [String] The masked string
|
92
|
+
def mask_secrets(input)
|
93
|
+
@mask_secrets.each_with_object(+input) { |secret, s| s.gsub!(secret, '*****') }.to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module QA
|
5
|
+
module Support
|
6
|
+
module Shellout
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def shell(command = nil, stdin_data: nil, mask_secrets: nil, stream_output: false, &block)
|
10
|
+
Support::ShellCommand.new(
|
11
|
+
command, stdin_data: stdin_data, mask_secrets: mask_secrets, stream_output: stream_output).execute!(&block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/gitlab/qa/version.rb
CHANGED
data/lib/gitlab/qa.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
---
|
2
|
+
apiVersion: apps/v1
|
3
|
+
kind: Deployment
|
4
|
+
metadata:
|
5
|
+
name: authenticator-deployment
|
6
|
+
labels:
|
7
|
+
app: authenticator
|
8
|
+
spec:
|
9
|
+
replicas: 1
|
10
|
+
selector:
|
11
|
+
matchLabels:
|
12
|
+
app: authenticator
|
13
|
+
template:
|
14
|
+
metadata:
|
15
|
+
labels:
|
16
|
+
app: authenticator
|
17
|
+
spec:
|
18
|
+
imagePullSecrets:
|
19
|
+
- name: gitlab-registry
|
20
|
+
containers:
|
21
|
+
- name: authenticator
|
22
|
+
image: registry.gitlab.com/gitlab-org/modelops/applied-ml/review-recommender/authenticator:0.1.0
|
23
|
+
imagePullPolicy: Always
|
24
|
+
ports:
|
25
|
+
- containerPort: 8080
|
26
|
+
args: []
|
27
|
+
env:
|
28
|
+
- name: AUTHENTICATOR_SERVICE_PORT
|
29
|
+
value: "8080"
|
30
|
+
---
|
31
|
+
apiVersion: v1
|
32
|
+
kind: Service
|
33
|
+
metadata:
|
34
|
+
name: authenticator-service
|
35
|
+
spec:
|
36
|
+
type: NodePort
|
37
|
+
ports:
|
38
|
+
- port: 8080
|
39
|
+
targetPort: 8080
|
40
|
+
selector:
|
41
|
+
app: authenticator
|
@@ -0,0 +1,84 @@
|
|
1
|
+
---
|
2
|
+
apiVersion: v1
|
3
|
+
kind: Secret
|
4
|
+
metadata:
|
5
|
+
name: postgres-secret
|
6
|
+
type: kubernetes.io/basic-auth
|
7
|
+
stringData:
|
8
|
+
username: reviewer-recommender
|
9
|
+
password: ml4dawin
|
10
|
+
|
11
|
+
---
|
12
|
+
apiVersion: v1
|
13
|
+
kind: PersistentVolumeClaim
|
14
|
+
metadata:
|
15
|
+
name: postgres-pvc
|
16
|
+
spec:
|
17
|
+
storageClassName: local-path
|
18
|
+
accessModes:
|
19
|
+
- ReadWriteOnce
|
20
|
+
resources:
|
21
|
+
requests:
|
22
|
+
storage: 1Gi
|
23
|
+
|
24
|
+
---
|
25
|
+
apiVersion: apps/v1
|
26
|
+
kind: Deployment
|
27
|
+
metadata:
|
28
|
+
name: postgres-deployment
|
29
|
+
spec:
|
30
|
+
replicas: 1
|
31
|
+
selector:
|
32
|
+
matchLabels:
|
33
|
+
app: postgres
|
34
|
+
template:
|
35
|
+
metadata:
|
36
|
+
labels:
|
37
|
+
app: postgres
|
38
|
+
spec:
|
39
|
+
containers:
|
40
|
+
- name: postgres
|
41
|
+
image: postgres:13-alpine
|
42
|
+
imagePullPolicy: IfNotPresent
|
43
|
+
ports:
|
44
|
+
- containerPort: 5432
|
45
|
+
volumeMounts:
|
46
|
+
- name: postgres-pv
|
47
|
+
mountPath: /var/lib/postgresql/data
|
48
|
+
subPath: postgres
|
49
|
+
resources:
|
50
|
+
limits:
|
51
|
+
memory: 256Mi
|
52
|
+
cpu: 250m
|
53
|
+
env:
|
54
|
+
- name: POSTGRES_DB
|
55
|
+
value: reviewer-recommender
|
56
|
+
- name: POSTGRES_USER
|
57
|
+
valueFrom:
|
58
|
+
secretKeyRef:
|
59
|
+
name: postgres-secret
|
60
|
+
key: username
|
61
|
+
- name: POSTGRES_PASSWORD
|
62
|
+
valueFrom:
|
63
|
+
secretKeyRef:
|
64
|
+
name: postgres-secret
|
65
|
+
key: password
|
66
|
+
volumes:
|
67
|
+
- name: postgres-pv
|
68
|
+
persistentVolumeClaim:
|
69
|
+
claimName: postgres-pvc
|
70
|
+
|
71
|
+
---
|
72
|
+
apiVersion: v1
|
73
|
+
kind: Service
|
74
|
+
metadata:
|
75
|
+
name: postgres
|
76
|
+
labels:
|
77
|
+
app: postgres
|
78
|
+
spec:
|
79
|
+
type: ClusterIP
|
80
|
+
selector:
|
81
|
+
app: postgres
|
82
|
+
ports:
|
83
|
+
- port: 5432
|
84
|
+
targetPort: 5432
|
@@ -0,0 +1,41 @@
|
|
1
|
+
---
|
2
|
+
apiVersion: apps/v1
|
3
|
+
kind: Deployment
|
4
|
+
metadata:
|
5
|
+
name: pubsub-deployment
|
6
|
+
labels:
|
7
|
+
app: pubsub
|
8
|
+
spec:
|
9
|
+
replicas: 1
|
10
|
+
selector:
|
11
|
+
matchLabels:
|
12
|
+
app: pubsub
|
13
|
+
template:
|
14
|
+
metadata:
|
15
|
+
labels:
|
16
|
+
app: pubsub
|
17
|
+
spec:
|
18
|
+
containers:
|
19
|
+
- name: pubsub
|
20
|
+
image: singularities/pubsub-emulator:latest
|
21
|
+
imagePullPolicy: IfNotPresent
|
22
|
+
env:
|
23
|
+
- name: PUBSUB_PROJECT_ID
|
24
|
+
value: project-test
|
25
|
+
- name: PUBSUB_LISTEN_ADDRESS
|
26
|
+
value: 0.0.0.0:8432
|
27
|
+
|
28
|
+
---
|
29
|
+
apiVersion: v1
|
30
|
+
kind: Service
|
31
|
+
metadata:
|
32
|
+
name: pubsub
|
33
|
+
labels:
|
34
|
+
app: pubsub
|
35
|
+
spec:
|
36
|
+
type: ClusterIP
|
37
|
+
selector:
|
38
|
+
app: pubsub
|
39
|
+
ports:
|
40
|
+
- port: 8432
|
41
|
+
targetPort: 8432
|