gitlab_quality-test_tooling 2.6.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 279a7eab459c664263a3506753c09d78111784af48af599cab26ed8928f54e2a
4
- data.tar.gz: '06388341bfbb2c868ae25569af2597666f64cdb7e980465078a78778081ca107'
3
+ metadata.gz: bc2b98142fc0891fe937da031f64a665ef016c153263b01b7c9820b284967800
4
+ data.tar.gz: 588d0cec55fb89405d61d6e41528343929d948fe6fb03717edf2e895fe727e5c
5
5
  SHA512:
6
- metadata.gz: cd37eca775b6899df0e476d11499ee491a8ea4278d88bf8f9584feb3cb8d1245da3319aa534ed4743c06ca1bd7da7a4eefcf619aa26688eb895bf3168d58eb9d
7
- data.tar.gz: 58f7c549202b39a20d6d5b5fc117e9017a044ee2e6bff63f07b82dda9650ed819f43407f20a5363d638b986fb8860d69c2452ea68bdf7fe5b7e33e70abb281b4
6
+ metadata.gz: 2402289c4b5282ad62289b7560b0faadc8cabc675d7e0262b38e6582cee5e2e6a2711ab053dc677d2e32d917c8a29608e8b90b485d977d4fe244c6a7e4c47505
7
+ data.tar.gz: 4bebf905075eb9b8ca2fb707c004d78746d8d8e518a6e10ee7d1085a2e3450b8a33d672a9ef382103deaf996591bd1f7c6b5d86f2249276a7a576a61074acbd7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab_quality-test_tooling (2.6.0)
4
+ gitlab_quality-test_tooling (2.7.0)
5
5
  activesupport (>= 7.0, < 7.2)
6
6
  amatch (~> 0.4.1)
7
7
  fog-google (~> 1.24, >= 1.24.1)
@@ -9,10 +9,11 @@ module GitlabQuality
9
9
  RETRY_BACK_OFF_DELAY = 60
10
10
  MAX_RETRY_ATTEMPTS = 3
11
11
 
12
- def initialize(token:, project:, **_kwargs)
12
+ def initialize(token:, project:, endpoint: nil, **_kwargs)
13
13
  @token = token
14
14
  @project = project
15
15
  @retry_backoff = 0
16
+ @endpoint = endpoint
16
17
  end
17
18
 
18
19
  def handle_gitlab_client_exceptions
@@ -76,11 +77,11 @@ module GitlabQuality
76
77
 
77
78
  private
78
79
 
79
- attr_reader :project, :token
80
+ attr_reader :project, :token, :endpoint
80
81
 
81
82
  def client
82
83
  @client ||= Gitlab.client(
83
- endpoint: Runtime::Env.gitlab_api_base,
84
+ endpoint: endpoint || Runtime::Env.gitlab_api_base,
84
85
  private_token: token
85
86
  )
86
87
  end
@@ -128,6 +128,12 @@ module GitlabQuality
128
128
  end
129
129
  end
130
130
 
131
+ def find_commit(project, sha)
132
+ handle_gitlab_client_exceptions do
133
+ client.commit(project, sha)
134
+ end
135
+ end
136
+
131
137
  def find_commit_parent(project, sha)
132
138
  handle_gitlab_client_exceptions do
133
139
  # In a merged results commit, the first parent is the one from
@@ -137,6 +143,24 @@ module GitlabQuality
137
143
  end
138
144
  end
139
145
 
146
+ def find_commit_diff(project, sha)
147
+ handle_gitlab_client_exceptions do
148
+ client.commit_diff(project, sha)
149
+ end
150
+ end
151
+
152
+ def find_deployments(project, environment:, status:, order_by: 'id', sort: 'desc')
153
+ handle_gitlab_client_exceptions do
154
+ client.deployments(
155
+ project,
156
+ environment: environment,
157
+ status: status,
158
+ order_by: order_by,
159
+ sort: sort
160
+ )
161
+ end
162
+ end
163
+
140
164
  private
141
165
 
142
166
  attr_reader :token, :project
@@ -33,6 +33,21 @@ module GitlabQuality
33
33
  'gitlab-org/customers-gitlab-com' => 'gitlab-org/customers-gitlab-com'
34
34
  }.freeze
35
35
 
36
+ # The project contains record of the deployments we use to determine the commit diff
37
+ OPS_RELEASES_METADATA_PROJECT = 'gitlab-org/release/metadata'
38
+
39
+ # Naming of the environments are different between `gitlab-org/release/metadata` and `gitlab-org/quality`
40
+ # This maps the gitlab-org/quality environment names to the equivalent in `gitlab-org/release/metadata`
41
+ ENVIRONMENT_MAPPING = {
42
+ 'production' => 'gprd',
43
+ 'canary' => 'gprd-cny',
44
+ 'staging' => 'gstg',
45
+ 'staging-canary' => 'gstg-cny',
46
+ 'staging-ref' => 'gstg-ref',
47
+ 'preprod' => 'pre',
48
+ 'release' => 'release'
49
+ }.freeze
50
+
36
51
  MultipleIssuesFound = Class.new(StandardError)
37
52
 
38
53
  def initialize(
@@ -54,7 +69,7 @@ module GitlabQuality
54
69
 
55
70
  private
56
71
 
57
- attr_reader :max_diff_ratio, :system_logs, :base_issue_labels, :exclude_labels_for_search, :metrics_files
72
+ attr_reader :max_diff_ratio, :system_logs, :base_issue_labels, :exclude_labels_for_search, :metrics_files, :ops_gitlab_client
58
73
 
59
74
  def run!
60
75
  puts "Reporting test failures in `#{files.join(',')}` as issues in project `#{project}` via the API at `#{Runtime::Env.gitlab_api_base}`."
@@ -278,7 +293,7 @@ module GitlabQuality
278
293
 
279
294
  def new_issue_description(test)
280
295
  super + [
281
- "\n#{compare_against_previous_commit}",
296
+ "\n#{commit_diff_section}",
282
297
  "### Stack trace",
283
298
  "```\n#{test.full_stacktrace}\n```",
284
299
  screenshot_section(test),
@@ -287,8 +302,123 @@ module GitlabQuality
287
302
  ].compact.join("\n\n")
288
303
  end
289
304
 
290
- def compare_against_previous_commit
291
- pipeline_sha = gitlab.find_pipeline(project, Runtime::Env.ci_pipeline_id.to_i).sha
305
+ def commit_diff_section
306
+ "### Commit diff\n#{generate_diff_link}"
307
+ end
308
+
309
+ def generate_diff_link
310
+ initialize_gitlab_ops_client
311
+
312
+ if Runtime::Env.ci_pipeline_url.include?('ops.gitlab.net')
313
+ pipeline = ops_gitlab_client.find_pipeline(project, Runtime::Env.ci_pipeline_id.to_i)
314
+ generate_ops_gitlab_diff(pipeline)
315
+ else
316
+ pipeline = gitlab.find_pipeline(project, Runtime::Env.ci_pipeline_id.to_i)
317
+ generate_gitlab_diff(pipeline)
318
+ end
319
+ end
320
+
321
+ def generate_ops_gitlab_diff(pipeline)
322
+ deployment_info = fetch_deployment_info(pipeline)
323
+
324
+ return deployment_info if deployment_info.is_a?(String)
325
+
326
+ source_gitlab_ee_sha = fetch_deployment_gitlab_ee_sha(ops_gitlab_client, deployment_info[:source].sha)
327
+ target_gitlab_ee_sha = fetch_deployment_gitlab_ee_sha(ops_gitlab_client, deployment_info[:target].sha)
328
+
329
+ if source_gitlab_ee_sha == target_gitlab_ee_sha
330
+ "No diff"
331
+ else
332
+ "https://gitlab.com/gitlab-org/security/gitlab/-/compare/#{target_gitlab_ee_sha}...#{source_gitlab_ee_sha}"
333
+ end
334
+ end
335
+
336
+ def fetch_deployment_info(pipeline)
337
+ pipeline_deploy_version = Runtime::Env.ci_pipeline_name.match(/(\d+\.\d+\.\d+)(?:-|$)/)&.captures&.first
338
+ deployments = fetch_deployments(ops_gitlab_client, pipeline)
339
+ found_deployment = find_matching_deployment(pipeline_deploy_version, deployments)
340
+
341
+ return 'No matching deployment found to generate a diff link.' unless found_deployment
342
+
343
+ {
344
+ source: found_deployment[:deployment],
345
+ target: deployments[found_deployment[:index] + 1]
346
+ }
347
+ end
348
+
349
+ def fetch_deployments(client, pipeline)
350
+ ops_environment = pipeline.web_url.match(%r{gitlab-org/quality/([^/-]+(?:-[^/-]+)*?)(?:/-)?/pipelines})[1]
351
+
352
+ raise "Environment '#{ops_environment}' is not supported" unless ENVIRONMENT_MAPPING.key?(ops_environment)
353
+
354
+ environment = ENVIRONMENT_MAPPING[ops_environment]
355
+
356
+ client.find_deployments(
357
+ OPS_RELEASES_METADATA_PROJECT,
358
+ environment: environment,
359
+ status: 'success'
360
+ )
361
+ end
362
+
363
+ def initialize_gitlab_ops_client
364
+ @ops_gitlab_client = GitlabClient::IssuesClient.new(
365
+ endpoint: Runtime::Env.ci_api_v4_url,
366
+ token: Runtime::Env.gitlab_ci_token,
367
+ project: OPS_RELEASES_METADATA_PROJECT
368
+ )
369
+ end
370
+
371
+ def find_matching_deployment(pipeline_deploy_version, deployments)
372
+ return nil unless pipeline_deploy_version
373
+ return nil unless deployments
374
+
375
+ target_timestamp = extract_timestamp(pipeline_deploy_version)
376
+ return nil unless target_timestamp
377
+
378
+ matching_deployment = nil
379
+
380
+ deployments.each_with_index do |deployment, index|
381
+ deployment_version = extract_deployment_version(ops_gitlab_client, deployment)
382
+ next unless deployment_version
383
+
384
+ deployment_timestamp = extract_timestamp(deployment_version)
385
+ next unless deployment_timestamp
386
+
387
+ # Stop searching if the deployment timestamp is older than the target timestamp
388
+ break if deployment_timestamp && deployment_timestamp < target_timestamp
389
+
390
+ if deployment_version == pipeline_deploy_version
391
+ matching_deployment = { deployment: deployment, index: index }
392
+ break
393
+ end
394
+ end
395
+
396
+ matching_deployment
397
+ end
398
+
399
+ def extract_timestamp(version)
400
+ version.match(/\d{12}$/)&.to_s
401
+ end
402
+
403
+ def extract_deployment_version(client, deployment)
404
+ commit = client.find_commit(OPS_RELEASES_METADATA_PROJECT, deployment.sha)
405
+ version_match = commit.message&.match(/Product-Version: ([\d.]+)/)
406
+ version_match&.[](1)
407
+ end
408
+
409
+ def fetch_deployment_gitlab_ee_sha(client, deployment_sha)
410
+ commit_diff = client.find_commit_diff(OPS_RELEASES_METADATA_PROJECT, deployment_sha).first
411
+ diffs_content = commit_diff.diff.lines.select { |line| line.start_with?('+') }.map { |line| line[1..] }.join
412
+
413
+ begin
414
+ JSON.parse(diffs_content).dig('releases', 'gitlab-ee', 'sha')
415
+ rescue JSON::ParserError
416
+ raise "Failed to parse the diffs content"
417
+ end
418
+ end
419
+
420
+ def generate_gitlab_diff(pipeline)
421
+ pipeline_sha = pipeline.sha
292
422
  parent_sha = gitlab.find_commit_parent(project, pipeline_sha)
293
423
  diff_project = if DIFF_PROJECT_MAPPINGS.key?(project)
294
424
  DIFF_PROJECT_MAPPINGS[project]
@@ -296,7 +426,7 @@ module GitlabQuality
296
426
  raise "Project #{project} is not supported for commit diff links"
297
427
  end
298
428
 
299
- "### Commit diff\nhttps://gitlab.com/#{diff_project}/-/compare/#{parent_sha}...#{pipeline_sha}"
429
+ "https://gitlab.com/#{diff_project}/-/compare/#{parent_sha}...#{pipeline_sha}"
300
430
  end
301
431
 
302
432
  def system_log_errors_section(test)
@@ -19,9 +19,11 @@ module GitlabQuality
19
19
  'CI_PROJECT_NAME' => :ci_project_name,
20
20
  'CI_PROJECT_PATH' => :ci_project_path,
21
21
  'CI_PIPELINE_ID' => :ci_pipeline_id,
22
+ 'CI_PIPELINE_NAME' => :ci_pipeline_name,
22
23
  'CI_PIPELINE_URL' => :ci_pipeline_url,
23
24
  'SLACK_QA_CHANNEL' => :slack_qa_channel,
24
- 'DEPLOY_VERSION' => :deploy_version
25
+ 'DEPLOY_VERSION' => :deploy_version,
26
+ 'QA_GITLAB_CI_TOKEN' => :gitlab_ci_token
25
27
  }.freeze
26
28
 
27
29
  ENV_VARIABLES.each do |env_name, method_name|
@@ -11,7 +11,9 @@ module GitlabQuality
11
11
  "unexpected token at 'GitLab is not responding'",
12
12
  "GitLab: Internal API error (502).",
13
13
  "could not be found (502)",
14
- "Error reference number: 502"
14
+ "Error reference number: 502",
15
+ "(502): `GitLab is not responding`",
16
+ "<head><title>502 Bad Gateway</title></head>"
15
17
  ].freeze
16
18
 
17
19
  SHARED_EXAMPLES_CALLERS = %w[include_examples it_behaves_like].freeze
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "2.6.0"
5
+ VERSION = "2.7.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab_quality-test_tooling
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.0
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab Quality
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-01-24 00:00:00.000000000 Z
11
+ date: 2025-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control