gitlab-qa 15.2.0 → 15.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 793b59a3d3817c1e3fa0794cfceaf8f80bc7a193e46e9ce3704ce8b8301e9143
4
- data.tar.gz: 299f7ce902fd8b9603cda51c2f5f018ff5c7a230b01944ca99c0eea9168ccc0a
3
+ metadata.gz: 8f1e475ea2c0271c08caf2de2d91881fb387148ee9a0686922e5c13905dfbae9
4
+ data.tar.gz: aecf00278bb4ae18d9a4b0b3e1d42d80f3a9b5482a38d755c83a2fa0fc3046ef
5
5
  SHA512:
6
- metadata.gz: 253cc2d2d41a94030bcb6c0b5a0225ff46ff9019677b8b1486104ee556fb219ecda07bbe724c51ed822699c0e2c2ccc0273795b122e810971bc956aa16af14ee
7
- data.tar.gz: eb4f3be8907209202af1aa51f9c1b8c70523645f31afdda60a294bbe7972ec769c1199fb8ca7075b46c862ad3161b1e3d5bd2369a2fe587a929bc2052f7ee208
6
+ metadata.gz: 164f25be24c4f6800d9dbb150776876a38e85c5bebcac4a72f449a0ed8e6ac2b65b89502cff82c588f101b6a9b299f3fbc2735f99d4a829990e85cdf5fc5674d
7
+ data.tar.gz: f1bbdd00cb493f5f6cb0a4f48af319503e3526515f12edceb631868194183e0910b08cedbdbf9e92f59177a7632a63b459bef681555b806eecf72bd6def571a7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-qa (15.2.0)
4
+ gitlab-qa (15.4.0)
5
5
  activesupport (>= 6.1, < 7.2)
6
6
  ffi (~> 1.17)
7
7
  gitlab (~> 4.19)
data/README.md CHANGED
@@ -90,9 +90,8 @@ of tests.
90
90
  - [Release process](docs/release_process.md)
91
91
  - [Run QA tests against your GDK setup](docs/run_qa_against_gdk.md)
92
92
  - [Trainings](docs/trainings.md)
93
- - [Waits](docs/waits.md)
94
93
  - [What tests can be run?](docs/what_tests_can_be_run.md)
95
- - [Specifics for Mac OS with M1, M2 processors & Docker Desktop](docs/specifics_for_macos_m1_m2.md)
94
+ - [Troubleshooting](docs/troubleshooting.md)
96
95
 
97
96
  ## How do we use it
98
97
 
@@ -24,5 +24,5 @@ end
24
24
  ```
25
25
 
26
26
  Mock server will be accessible from within gitlab or qa test container via `http://smocker.test` url and admin interface will be
27
- accessible via `http://smocker.test:8081`. Refer to [Getting Started](https://smocker.dev/guide/getting-started.html) guide on
27
+ accessible via `http://smocker.test:8081`. Refer to [Getting Started](https://smocker.dev/docs/guide/getting-started) guide on
28
28
  how to use the server and define mocked requests and responses.
@@ -299,11 +299,11 @@ $ gitlab-qa Test::Omnibus::Upgrade CE
299
299
  $ gitlab-qa Test::Omnibus::Upgrade gitlab/gitlab-ce:my-custom-tag
300
300
  ```
301
301
 
302
- ### `Test::Omnibus::UpdateFromPrevious <full image address> <current_version> <major|minor> <from_edition>`
302
+ ### `Test::Omnibus::UpdateFromPrevious <full image address> <current_version> <major|minor|patch> <from_edition>`
303
303
 
304
- Scenario verifies upgrade from previous (major|minor) version to current release.
304
+ Scenario verifies upgrade from previous (major|minor|patch) version to current release.
305
305
 
306
- - Deploys previous (major|minor) version and runs Smoke test suite
306
+ - Deploys previous (major|minor|patch) version and runs Health Check test suite (Smoke test suite if below 17.1.0)
307
307
  to populate data in database before upgrade
308
308
  - Generates upgrade path following current GitLab recommendations
309
309
  from ['gitlab.com/gitlab-org/gitlab'](https://gitlab.com/gitlab-org/gitlab/-/raw/master/config/upgrade_path.yml) project
@@ -318,6 +318,30 @@ $ gitlab-qa Test::Omnibus::UpdateFromPrevious gitlab-ee:dev-tag 15.6.0-pre minor
318
318
 
319
319
  # Major upgrade - will perform upgrades 14.10.x -> 15.0.x -> 15.4.x -> gitlab-ee:dev-tag (15.6.0-pre)
320
320
  $ gitlab-qa Test::Omnibus::UpdateFromPrevious gitlab-ee:dev-tag 15.6.0-pre major
321
+
322
+ # Patch upgrade - will perform upgrade from 17.8.1 -> gitlab-ee:dev-tag (17.8.2-pre)
323
+ $ gitlab-qa Test::Omnibus::UpdateFromPrevious gitlab-ee:dev-tag 17.8.2-pre patch
324
+
325
+ # Internal patch upgrade - will perform upgrade from dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ee:17.8.1-internal0-0 -> gitlab-ee:dev-tag (17.8.2-pre)
326
+ $ gitlab-qa Test::Omnibus::UpdateFromPrevious gitlab-ee:dev-tag 17.8.2-pre internal_patch
327
+ ```
328
+
329
+ ### `Test::Omnibus::UpdateToNext <full image address> <current_version> <from_edition>`
330
+
331
+ Scenario verifies upgrade from current development version to next available stable release.
332
+
333
+ - Deploys development version and runs Health Check test suite to populate data in database (Smoke test suite if below 17.1.0)
334
+ - Finds next available stable version
335
+ - Upgrades GitLab instance from development version to next stable and runs tests against it
336
+ - Skips if either current version or next version is not yet released
337
+
338
+ Note: `from_edition` setting is optional, can be set to `ee` or `ce`.
339
+
340
+ Example:
341
+
342
+ ```shell
343
+ # Will perform upgrade from gitlab-ee:dev-tag (17.8.2-pre) -> 17.9.2
344
+ $ gitlab-qa Test::Omnibus::UpdateToNext gitlab-ee:dev-tag 17.8.2-pre
321
345
  ```
322
346
 
323
347
  ### `Test::Integration::Geo EE|<full image address>`
@@ -1049,6 +1073,29 @@ This orchestrated scenario runs tests from the test suite against a GitLab insta
1049
1073
 
1050
1074
  These variables are available at 1Password QA Vault.
1051
1075
 
1076
+ ----
1077
+
1078
+ #### `Test::Instance::SecureVersion EE|<full image address>`
1079
+
1080
+ Used for testing that a project with Secure scanner functionality functions correctly against the specified version.
1081
+ As this is Secure functionality, an EE license is required.
1082
+ Can be used for running older instances of GitLab, this skips the Security version modal on login.
1083
+
1084
+ The script applies the license, imports the project, kicks off a pipeline, and checks that the pipeline was successful.
1085
+
1086
+ **Required environment variables:**
1087
+
1088
+ - `EE_LICENSE`: A valid EE license for testing.
1089
+ - `PROJECT_URL`: The URL of the project to test.
1090
+ - `PROJECT_NAME`: The name of the project to test, when imported to the instance.
1091
+
1092
+ Example:
1093
+
1094
+ ```shell
1095
+ $ export EE_LICENSE=$(cat /path/to/gitlab_license)
1096
+ $ PROJECT_URL='https://gitlab.com/gitlab-org/quality/ci/secure-testing/secure-matrix-test.git' PROJECT_NAME='secure-matrix-test' gitlab-qa Test::Instance::SecureVersion gitlab/gitlab-ee:16.5.0-ee.0
1097
+ ```
1098
+
1052
1099
  ### `Test::Integration::RegistryTLS EE`
1053
1100
 
1054
1101
  It uses GitLab's TLS certificate found in the [`tls_certificates`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/tls_certificates/gitlab/gitlab.test.crt) folder.
@@ -1236,4 +1283,16 @@ $ gitlab-qa Test::Integration::AiGatewayNoLicense EE
1236
1283
 
1237
1284
  ----
1238
1285
 
1286
+ #### Troubleshooting `AiGateway` Tests
1287
+
1288
+ The following logs are available for troubleshooting `AiGateway` tests in the `e2e-test-on-omnibus` pipelines.
1289
+
1290
+ | Component | Log Location | Additional Info |
1291
+ |----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
1292
+ | CustomersDot Staging | [Kibana](https://nonprod-log.gitlab.net/) (`pubsub-rails-inf-stgsub*`), [Sentry](https://new-sentry.gitlab.net/organizations/gitlab/issues/?environment=stg&project=8) | See [CustomersDot Logging](https://gitlab.com/gitlab-org/customers-gitlab-com/blob/main/doc/architecture/logging.md#customersdot-logging) for details |
1293
+ | GitLab Omnibus | Job artifacts: `gitlab/logs` | See the GitLab [Log system](https://docs.gitlab.com/ee/administration/logs/) docs for more details |
1294
+ | AI Gateway | Job artifacts: `ai-gateway/logs/modelgateway_debug.log` | See the AI Gateway's [README](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist#gitlab-ai-gateway) for more details |
1295
+
1296
+ ----
1297
+
1239
1298
  [Back to README.md](../README.md)
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Component
6
+ class LicenseOps < Base
7
+ LicenseError = Class.new(StandardError)
8
+ require 'shellwords'
9
+
10
+ def add_license(gitlab)
11
+ license_key = fetch_license_key
12
+ command = build_license_command(license_key)
13
+ apply_license(gitlab, command, license_key)
14
+ end
15
+
16
+ private
17
+
18
+ def fetch_license_key
19
+ license_key = ENV.fetch('EE_LICENSE', '')
20
+ raise LicenseError, "EE_LICENSE environment variable is not set or is empty" if license_key.empty?
21
+
22
+ Shellwords.shellwords(license_key).join
23
+ end
24
+
25
+ def build_license_command(license_key)
26
+ script = <<~RUBY
27
+ key = ENV['EE_LICENSE']
28
+ license = License.new(data: key)
29
+ if license.save
30
+ puts "License applied successfully"
31
+ else
32
+ STDERR.puts "Failed to apply license"
33
+ end
34
+ RUBY
35
+ "EE_LICENSE='#{license_key}' gitlab-rails runner $'#{script.gsub("'", "\\\\'").gsub("\n", '\\n')}'"
36
+ end
37
+
38
+ def apply_license(gitlab, command, license_key)
39
+ result = gitlab.docker.exec(gitlab.name, command, mask_secrets: license_key)
40
+ verify_license_application(result)
41
+ end
42
+
43
+ def verify_license_application(result)
44
+ return if result.include?("License applied successfully")
45
+
46
+ raise LicenseError, "Failed to apply license."
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Component
6
+ class PipelineOps < Base
7
+ def start(gitlab, project_name)
8
+ create_and_execute_pipeline_script(gitlab, project_name)
9
+ end
10
+
11
+ def check_status(gitlab)
12
+ pipeline_status = gitlab.docker.exec(
13
+ gitlab.name, wait_for_pipeline)
14
+
15
+ case pipeline_status
16
+ when 'success'
17
+ puts "Pipeline succeeded!"
18
+ nil
19
+ when 'failed'
20
+ raise StandardError, "Pipeline failed."
21
+ else
22
+ puts "Pipeline is currently #{pipeline_status}"
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def create_and_execute_pipeline_script(gitlab, project_name)
29
+ setup_src_path = File.expand_path('../../../../support/pipeline', __dir__)
30
+ setup_dest_path = '/tmp/setup-scripts'
31
+
32
+ gitlab.docker.copy(gitlab.name, setup_src_path, setup_dest_path)
33
+
34
+ gitlab.docker.exec(
35
+ gitlab.name,
36
+ "PROJECT_NAME='#{project_name}' gitlab-rails runner #{setup_dest_path}/create_for_projectname.rb"
37
+ )
38
+ end
39
+
40
+ def wait_for_pipeline
41
+ <<~SHELL
42
+ gitlab-rails runner "
43
+ latest_pipeline = Ci::Pipeline.last
44
+ # wait for the pipeline to complete
45
+ loop do
46
+ latest_pipeline.reload
47
+ break if latest_pipeline.complete?
48
+ sleep 1
49
+ end
50
+ puts latest_pipeline.status
51
+ "
52
+ SHELL
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Component
6
+ class ProjectImporter < Base
7
+ IMPORT_TIMEOUT = 300 # 5 minutes
8
+
9
+ def initialize(project_url, project_name, project_path: project_name)
10
+ @project_name = project_name
11
+ @project_url = project_url
12
+ @project_path = project_path
13
+ end
14
+
15
+ def import_project(gitlab)
16
+ import_command = build_import_command(create_import_script, @project_url, @project_name, @project_path)
17
+ puts gitlab.docker.exec(gitlab.name, import_command)
18
+ end
19
+
20
+ private
21
+
22
+ def create_import_script
23
+ <<~'RUBY'
24
+ require 'timeout'
25
+
26
+ project_url = ENV.fetch('PROJECT_URL')
27
+ project_name = ENV.fetch('PROJECT_NAME')
28
+ project_path = ENV.fetch('PROJECT_PATH')
29
+
30
+ root_user = User.find_by_username('root')
31
+
32
+ project = Projects::CreateService.new(root_user,
33
+ { name: project_name, path: project_path, import_url: project_url }).execute
34
+
35
+ if project.persisted?
36
+ # Wait for import to complete
37
+ begin
38
+ Timeout.timeout(300) do # 5 minutes timeout
39
+ until ['finished', 'failed'].include?(project.import_status)
40
+ sleep 5
41
+ project.reload
42
+ end
43
+ end
44
+ rescue Timeout::Error
45
+ puts "Import process timed out after 5 minutes"
46
+ end
47
+ else
48
+ puts "Failed to create project: #{project.errors.full_messages.join(', ')}"
49
+ end
50
+
51
+ # Always print import state for debugging
52
+ puts "Import state: #{project.import_state.attributes}" if project.respond_to?(:import_state)
53
+ RUBY
54
+ end
55
+
56
+ def build_import_command(script, project_url, project_name, project_path)
57
+ escaped_script = script.gsub("'", "\\\\'").gsub("\n", "\\n")
58
+ "PROJECT_URL='#{project_url}' PROJECT_NAME='#{project_name}' PROJECT_PATH='#{project_path}' gitlab-rails runner $'#{escaped_script}'"
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Component
6
+ class RunnerOps < Base
7
+ include Support::Shellout
8
+
9
+ RUNNER_DESCRIPTION = "QA Runner"
10
+ DOCKER_IMAGE = "registry.gitlab.com/gitlab-org/gitlab-runner:alpine"
11
+ BUILD_IMAGE = "registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7"
12
+
13
+ def setup_runner(gitlab)
14
+ token = SecureRandom.hex(15)
15
+ add_runner_to_gitlab(gitlab, token)
16
+ register_docker_runner(gitlab, token)
17
+ end
18
+
19
+ private
20
+
21
+ def add_runner_to_gitlab(gitlab, token)
22
+ gitlab.docker.exec(
23
+ gitlab.name,
24
+ create_runner_command(token),
25
+ mask_secrets: token
26
+ )
27
+ end
28
+
29
+ def create_runner_command(token)
30
+ <<~RUBY.strip.gsub(/\s+/, ' ')
31
+ gitlab-rails runner '
32
+ Ci::Runner.create!(
33
+ description: "#{RUNNER_DESCRIPTION}",
34
+ run_untagged: true,
35
+ active: true,
36
+ token: "#{token}",
37
+ runner_type: :instance_type
38
+ );
39
+ puts "Runner created"
40
+ '
41
+ RUBY
42
+ end
43
+
44
+ def register_docker_runner(gitlab, token)
45
+ runner_name = generate_runner_name
46
+ docker_command = build_docker_command(
47
+ runner_name: runner_name,
48
+ network: gitlab.network,
49
+ address: gitlab.address,
50
+ token: token
51
+ )
52
+
53
+ shell(docker_command, mask_secrets: [token])
54
+ end
55
+
56
+ def generate_runner_name
57
+ "test-runner-#{SecureRandom.hex(4)}"
58
+ end
59
+
60
+ def build_docker_command(runner_name:, network:, address:, token:)
61
+ <<~CMD.tr("\n", ' ')
62
+ docker run -d --rm --network #{network} --name #{runner_name}
63
+ -v /var/run/docker.sock:/var/run/docker.sock
64
+ --privileged
65
+ #{DOCKER_IMAGE}
66
+ && docker exec --detach #{runner_name} sh -c "#{register_command(runner_name, address, token, network)}"
67
+ CMD
68
+ end
69
+
70
+ def runner_config
71
+ <<~CONFIG
72
+ concurrent = 1
73
+ check_interval = 0
74
+
75
+ [session_server]
76
+ session_timeout = 1800
77
+ CONFIG
78
+ end
79
+
80
+ def register_command(name, address, token, network)
81
+ registration_args = build_registration_args(
82
+ name: name,
83
+ address: address,
84
+ token: token,
85
+ network: network
86
+ )
87
+
88
+ <<~CMD.strip
89
+ printf '#{runner_config.chomp.gsub(/\n/, '\\n').gsub('"', '\"')}' > /etc/gitlab-runner/config.toml &&
90
+ gitlab-runner register #{registration_args} &&
91
+ gitlab-runner run
92
+ CMD
93
+ end
94
+
95
+ def build_registration_args(name:, address:, token:, network:)
96
+ [
97
+ '--non-interactive',
98
+ "--name #{name}",
99
+ "--url #{address}",
100
+ "--token #{token}",
101
+ '--run-untagged=true',
102
+ '--executor docker',
103
+ "--docker-image #{BUILD_IMAGE}",
104
+ '--docker-tlsverify=false',
105
+ '--docker-privileged=true',
106
+ "--docker-network-mode=#{network}",
107
+ '--docker-volumes=/certs/client'
108
+ ].join(' ')
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -81,6 +81,18 @@ module Gitlab
81
81
  ), mask_secrets: mask_secrets)
82
82
  end
83
83
 
84
+ # Executes a command inside a running Docker container.
85
+ #
86
+ # @param name [String] The name or ID of the container to execute the command in.
87
+ # @param command [String] The command to be executed inside the container.
88
+ # @param mask_secrets [Boolean, nil] Whether to mask sensitive information in logs. Defaults to nil.
89
+ # @param shell [String] The shell to use for executing the command. Defaults to "bash".
90
+ #
91
+ # @return [String] The output of the executed command.
92
+ #
93
+ # @example
94
+ # exec("my-container", "echo 'hello world'")
95
+ # # => "hello world\n"
84
96
  def exec(name, command, mask_secrets: nil, shell: "bash")
85
97
  cmd = ['exec']
86
98
  cmd << '--privileged' if privileged_command?(command)
@@ -37,7 +37,7 @@ module Gitlab
37
37
  # version
38
38
  DEV_OFFICIAL_TAG_REGEX = /
39
39
  \A
40
- (?<version>\d+\.\d+.\d+(?:-rc\d+)?)-(?<edition>ce|ee|jh)
40
+ (?<version>\d+\.\d+.\d+(?:-rc\d+)?)-(?<edition>ce|ee|jh)(?:\.(?<build>\d+))?
41
41
  \z
42
42
  /xi
43
43
 
@@ -115,6 +115,11 @@ module Gitlab
115
115
  omnibus_project = image.match(CUSTOM_GITLAB_IMAGE_REGEX)[:project]
116
116
  gitlab_project = ci_project_path ? "/#{ci_project_path}/" : "/gitlab-org/gitlab/"
117
117
 
118
+ "#{image.gsub(omnibus_project, gitlab_project)}-qa"
119
+ elsif dev_gitlab_org?
120
+ omnibus_project = image.match(CUSTOM_GITLAB_IMAGE_REGEX)[:project]
121
+ gitlab_project = "/gitlab/gitlab-ee/"
122
+
118
123
  "#{image.gsub(omnibus_project, gitlab_project)}-qa"
119
124
  else
120
125
  "#{image}-qa"
@@ -140,9 +145,14 @@ module Gitlab
140
145
  end
141
146
  end
142
147
 
143
- # Tag scheme for gitlab-{ce,ee}-qa images is like 11.1.0-rc12-ee
144
148
  def qa_tag
145
- if dev_gitlab_org? && (match_data = tag.match(DEV_TAG_REGEX))
149
+ # Case 1: Official packages (e.g., 11.1.0-rc12.ee.0 or 12.5.4-ce.1)
150
+ if match_data = tag.match(DEV_OFFICIAL_TAG_REGEX)
151
+ version = match_data[:version]
152
+ edition = match_data[:edition]
153
+ "#{version}-#{edition}"
154
+ # Case 2: Auto-deploy packages from dev.gitlab.org (e.g., 12.1.201906121026-325a6632895.b340d0bd35d)
155
+ elsif match_data = tag.match(DEV_TAG_REGEX)
146
156
  match_data[:gitlab_ref]
147
157
  else
148
158
  tag.sub(/[-.]([ce]e)(\.(\d+))?\z/, '-\1')
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Scenario
6
+ module Test
7
+ module Instance
8
+ class SecureVersion < Scenario::Template
9
+ include Support::Shellout
10
+
11
+ attr_writer :volumes, :seed_admin_token
12
+
13
+ def initialize
14
+ @volumes = {}
15
+ @seed_admin_token = true
16
+ @pipeline_ops = Component::PipelineOps.new
17
+ @runner_ops = Component::RunnerOps.new
18
+ @importer = Component::ProjectImporter.new(
19
+ ENV.fetch('PROJECT_URL', nil),
20
+ ENV.fetch('PROJECT_NAME', nil))
21
+ @license_ops = Component::LicenseOps.new
22
+ end
23
+
24
+ def perform(release, *_rspec_args)
25
+ Component::Gitlab.perform do |gitlab|
26
+ setup_gitlab(gitlab, release)
27
+ execute_gitlab_operations(gitlab)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def setup_gitlab(gitlab, release)
34
+ gitlab.release = release
35
+ gitlab.volumes = @volumes
36
+ gitlab.network = Runtime::Env.docker_network
37
+ gitlab.name = Runtime::Env.qa_gitlab_hostname
38
+ gitlab.seed_admin_token = @seed_admin_token
39
+ gitlab.tls = Runtime::Env.qa_gitlab_use_tls?
40
+ # gitlab.exec_commands = foo
41
+ end
42
+
43
+ def execute_gitlab_operations(gitlab)
44
+ gitlab.instance do
45
+ @license_ops.add_license(gitlab)
46
+ @runner_ops.setup_runner(gitlab)
47
+ @importer.import_project(gitlab)
48
+ @pipeline_ops.start(gitlab, 'secure-matrix-test')
49
+ @pipeline_ops.check_status(gitlab)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Scenario
6
+ module Test
7
+ module Omnibus
8
+ class UpdateToNext < UpdateFromPrevious
9
+ using Rainbow
10
+ # Test upgrade from development version to next stable release
11
+ #
12
+ # @example
13
+ # perform(gitlab-ee:dev-tag, 17.8.2-pre)
14
+ # => will perform upgrade gitlab-ee:dev-tag -> 17.9.2
15
+ #
16
+ # @param [String] release current release docker image with development changes
17
+ # @param [String] current_version current gitlab version associated with docker image
18
+ # @param [String] from_edition gitlab edition to update from
19
+ # @param [Array] *rspec_args rspec arguments
20
+ # @return [void]
21
+ def perform(release, current_version, from_edition = nil, *rspec_args)
22
+ # When from_edition isn't actually passed but RSpec args arg passed with `-- rspec_args...`,
23
+ # from_edition is wrongly set to `--`, so we fix that here.
24
+ if from_edition == "--"
25
+ rspec_args.prepend('--')
26
+ from_edition = nil
27
+ end
28
+
29
+ @current_release = QA::Release.new(release)
30
+ @upgrade_path = Support::GitlabUpgradePath.new(
31
+ current_version,
32
+ 'from_patch',
33
+ from_edition || @current_release.edition
34
+ ).fetch
35
+ @rspec_args = rspec_args
36
+
37
+ # Key difference to UpdateFromPrevious: current_release comes first in the upgrade path
38
+ upgrade_info = "(#{current_version}) #{[current_release, *upgrade_path].join(' => ')}".bright
39
+ Runtime::Logger.info("Performing gitlab update: #{upgrade_info}")
40
+
41
+ update(rspec_args)
42
+ end
43
+
44
+ private
45
+
46
+ # Override to run specs in reverse order - first on development version, then on target version
47
+ #
48
+ # @param [Array] rspec_args
49
+ # @return [void]
50
+ def update(rspec_args)
51
+ Docker::Volumes.new.with_temporary_volumes do |volumes|
52
+ # deploy development release and run specs to populate db
53
+ Runtime::Logger.info("Running the development release: #{current_release}")
54
+ run_gitlab(current_release, volumes, seeding_suite_args, seeding_run: true)
55
+
56
+ # deploy target release and run tests
57
+ upgrade_path.each do |release|
58
+ Runtime::Logger.info("Upgrading GitLab to target release: #{release}")
59
+ run_gitlab(release, volumes, rspec_args, skip_setup: true)
60
+ end
61
+ end
62
+ end
63
+
64
+ # Override to run specs on development release and final target
65
+ #
66
+ # @param [Gitlab::QA::Release] release
67
+ # @return [Boolean]
68
+ def run_specs?(release)
69
+ [current_release, upgrade_path.last].any?(release)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -13,11 +13,17 @@ module Gitlab
13
13
  # @param [String] semver_component version number component for previous version detection - major|minor|patch
14
14
  # @param [String] edition GitLab edition - ee or ce
15
15
  def initialize(current_version, semver_component, edition)
16
+ @logger = Runtime::Logger.logger
17
+
18
+ unless current_version.match?(GitlabVersionInfo::VERSION_PATTERN)
19
+ logger.error("Invalid 'current_version' format: #{current_version}. Expected format: MAJOR.MINOR.PATCH (e.g., 17.8.2)")
20
+ exit 1
21
+ end
22
+
16
23
  @version_info = GitlabVersionInfo.new(current_version, edition)
17
- @current_version = Gem::Version.new(current_version)
24
+ @current_version = Gem::Version.new(current_version.match(GitlabVersionInfo::VERSION_PATTERN)[:version]) # Extract version without postfixes like pre or ee
18
25
  @semver_component = semver_component
19
26
  @edition = edition
20
- @logger = Runtime::Logger.logger
21
27
  end
22
28
 
23
29
  # Get upgrade path between releases
@@ -26,9 +32,20 @@ module Gitlab
26
32
  #
27
33
  # @return [Array<QA::Release>]
28
34
  def fetch
29
- return minor_upgrade_path unless major_upgrade?
30
-
31
- major_upgrade_path
35
+ case semver_component
36
+ when "patch"
37
+ patch_upgrade_path
38
+ when "minor"
39
+ minor_upgrade_path
40
+ when "major"
41
+ major_upgrade_path
42
+ when "from_patch"
43
+ from_patch_upgrade_path
44
+ when "internal_patch"
45
+ internal_patch_upgrade_path
46
+ else
47
+ raise ArgumentError, "Unknown semver component: #{semver_component}"
48
+ end
32
49
  rescue GitlabVersionInfo::VersionNotFoundError
33
50
  logger.error("Failed to construct gitlab upgrade path")
34
51
  raise
@@ -40,6 +57,17 @@ module Gitlab
40
57
 
41
58
  attr_reader :version_info, :current_version, :semver_component, :edition, :logger
42
59
 
60
+ # Upgrade path for patch version update
61
+ # Returns array with current version as we're testing upgrade from
62
+ # latest stable patch to development version
63
+ #
64
+ # @return [Array]
65
+ def patch_upgrade_path
66
+ verify_current_version_exists
67
+
68
+ [release(latest_patch(current_version))]
69
+ end
70
+
43
71
  # Upgrade path from previous minor version
44
72
  #
45
73
  # @return [Array]
@@ -63,11 +91,84 @@ module Gitlab
63
91
  end
64
92
  end
65
93
 
66
- # Upgrade from previous major
94
+ # Upgrade path from current version to next stable version
95
+ # Checks if current version exists in releases
96
+ # Gets next available major.minor version and its latest patch
67
97
  #
68
- # @return [Boolean]
69
- def major_upgrade?
70
- semver_component == "major"
98
+ # @return [Array] Array with next version's latest patch release or exits with message
99
+ def from_patch_upgrade_path
100
+ verify_current_version_exists
101
+ next_version = version_info.next_version(current_version.to_s)
102
+
103
+ unless next_version
104
+ logger.info("Skipping upgrade test as next version after #{current_version} is not yet available")
105
+ exit 0
106
+ end
107
+
108
+ [release(latest_patch(next_version))]
109
+ end
110
+
111
+ # Upgrade path for internal patch version
112
+ # Sets up authentication for internal registry
113
+ # Finds the latest internal build for the current version
114
+ #
115
+ # @return [Array<QA::Release>] Array with the latest internal build for current version or exits with message
116
+ def internal_patch_upgrade_path
117
+ unless Runtime::Env.dev_access_token_variable
118
+ logger.error("Skipping upgrade test as internal patch upgrades are not supported without dev access token")
119
+ exit 0
120
+ end
121
+
122
+ verify_current_version_exists
123
+ gitlab_int_reg_repo = "dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ee"
124
+
125
+ # Internal releases are stored in private repo and
126
+ # not available for search with API
127
+ release = QA::Release.new("#{gitlab_int_reg_repo}:latest")
128
+ docker = Docker::Engine.new
129
+ docker.login(**release.login_params) if release.login_params
130
+ latest_internal_tag = find_latest_internal_tag(gitlab_int_reg_repo, docker)
131
+
132
+ if latest_internal_tag
133
+ [QA::Release.new("#{gitlab_int_reg_repo}:#{latest_internal_tag}")]
134
+ else
135
+ logger.warn("No internal image found for GitLab version #{current_version}")
136
+ exit 0
137
+ end
138
+ end
139
+
140
+ # Find the latest internal tag for the current version
141
+ # Searches for tags in descending order, from 10 down to 0
142
+ # Returns the first available tag or nil if none found
143
+ #
144
+ # @param [String] gitlab_int_reg_repo Registry repository path
145
+ # @param [Docker::Engine] docker_engine Docker engine instance
146
+ # @return [String, nil] Tag name if found, nil otherwise
147
+ def find_latest_internal_tag(gitlab_int_reg_repo, docker)
148
+ # Try to find the highest internal release tag, starting from 10
149
+ latest_internal_tag = nil
150
+ logger.info("Start searching for the latest released internal image for gitlab version: #{current_version}...")
151
+
152
+ # Release team note: no more than 10 internal releases expected for version
153
+ 10.downto(0) do |internal_num|
154
+ tag = "#{current_version}-internal#{internal_num}-0"
155
+ image_uri = "#{gitlab_int_reg_repo}:#{tag}"
156
+
157
+ logger.info("Checking for image: #{image_uri}")
158
+
159
+ begin
160
+ # Try to pull the image (this will fail if image doesn't exist)
161
+ docker.pull(image: gitlab_int_reg_repo, tag: tag)
162
+
163
+ latest_internal_tag = tag
164
+ logger.info("Found image: #{image_uri}")
165
+ break
166
+ rescue Support::ShellCommand::StatusError => e
167
+ logger.info("x - Image not found: #{image_uri}, \n #{e}")
168
+ end
169
+ end
170
+
171
+ latest_internal_tag
71
172
  end
72
173
 
73
174
  # Docker release image
@@ -85,6 +186,17 @@ module Gitlab
85
186
  @previous_version ||= version_info.previous_version(semver_component)
86
187
  end
87
188
 
189
+ # Verify if current version exists in GitLab releases
190
+ # Exit with message if version is not yet released
191
+ #
192
+ # @return [void]
193
+ def verify_current_version_exists
194
+ return if version_info.version_exists?(current_version.to_s)
195
+
196
+ logger.info("Skipping upgrade test as version #{current_version} is not yet released")
197
+ exit 0
198
+ end
199
+
88
200
  # Gitlab upgrade path
89
201
  #
90
202
  # @return [Array<Gem::Version>]
@@ -36,6 +36,18 @@ module Gitlab
36
36
  end
37
37
  end
38
38
 
39
+ # Check if specific version exists in GitLab releases
40
+ #
41
+ # @example
42
+ # version_exists?("17.10.5") => true
43
+ # version_exists?("17.10.28") => false
44
+ #
45
+ # @param [String] version Version to check
46
+ # @return [Boolean] true if version exists in GitLab releases, false otherwise
47
+ def version_exists?(version)
48
+ !!versions.find { |ver| ver.to_s == version }
49
+ end
50
+
39
51
  # Get latest patch for specific version number
40
52
  #
41
53
  # @example
@@ -53,6 +65,27 @@ module Gitlab
53
65
  end
54
66
  end
55
67
 
68
+ # Get next version major.minor from available releases
69
+ #
70
+ # @example
71
+ # next_version("17.7.4") => "17.8"
72
+ # next_version("17.12.5") => "18.0"
73
+ # next_version("18.0.3") => nil # when no next version exists
74
+ #
75
+ # @param [String] version Current version
76
+ # @return [String, nil] Next version in major.minor format or nil if no next version exists
77
+ def next_version(version)
78
+ current_ver = Gem::Version.new(version)
79
+
80
+ # Since versions are already sorted in descending order (newest first),
81
+ # we need to reverse them to find the next version after current
82
+ next_ver = versions.reverse.find { |ver| ver > current_ver }
83
+
84
+ return nil unless next_ver
85
+
86
+ [next_ver.segments[0], next_ver.segments[1]].join('.') # major.minor
87
+ end
88
+
56
89
  private
57
90
 
58
91
  MAX_TAGS_HTTP_REQUESTS = 50
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  module QA
5
- VERSION = '15.2.0'
5
+ VERSION = '15.4.0'
6
6
  end
7
7
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateForProjectname
4
+ class << self
5
+ def create_pipeline
6
+ project_name = ENV.fetch('PROJECT_NAME', nil)
7
+ root_user = User.find_by_username('root')
8
+ project = Project.find_by_path(project_name)
9
+
10
+ if project
11
+ pipeline_service = Ci::CreatePipelineService.new(project, root_user, ref: project.default_branch_or_main)
12
+ pipeline = pipeline_service.execute(:api)
13
+
14
+ if pipeline
15
+ puts "Pipeline created successfully. Pipeline ID: \#{pipeline.payload.id}"
16
+ else
17
+ puts "Failed to create pipeline"
18
+ exit 1
19
+ end
20
+ else
21
+ puts "Project not found: \#{project_name}"
22
+ exit 1
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ CreateForProjectname.create_pipeline
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-qa
3
3
  version: !ruby/object:Gem::Version
4
- version: 15.2.0
4
+ version: 15.4.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-26 00:00:00.000000000 Z
11
+ date: 2025-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control
@@ -407,15 +407,19 @@ files:
407
407
  - lib/gitlab/qa/component/gitlab.rb
408
408
  - lib/gitlab/qa/component/jira.rb
409
409
  - lib/gitlab/qa/component/ldap.rb
410
+ - lib/gitlab/qa/component/license_ops.rb
410
411
  - lib/gitlab/qa/component/mail_hog.rb
411
412
  - lib/gitlab/qa/component/minio.rb
412
413
  - lib/gitlab/qa/component/mock_server.rb
413
414
  - lib/gitlab/qa/component/opensearch.rb
415
+ - lib/gitlab/qa/component/pipeline_ops.rb
414
416
  - lib/gitlab/qa/component/postgresql.rb
415
417
  - lib/gitlab/qa/component/praefect.rb
416
418
  - lib/gitlab/qa/component/preprod.rb
417
419
  - lib/gitlab/qa/component/production.rb
420
+ - lib/gitlab/qa/component/project_importer.rb
418
421
  - lib/gitlab/qa/component/release.rb
422
+ - lib/gitlab/qa/component/runner_ops.rb
419
423
  - lib/gitlab/qa/component/saml.rb
420
424
  - lib/gitlab/qa/component/selenoid.rb
421
425
  - lib/gitlab/qa/component/specs.rb
@@ -452,6 +456,7 @@ files:
452
456
  - lib/gitlab/qa/scenario/test/instance/relative_url.rb
453
457
  - lib/gitlab/qa/scenario/test/instance/release.rb
454
458
  - lib/gitlab/qa/scenario/test/instance/repository_storage.rb
459
+ - lib/gitlab/qa/scenario/test/instance/secure_version.rb
455
460
  - lib/gitlab/qa/scenario/test/instance/smoke.rb
456
461
  - lib/gitlab/qa/scenario/test/instance/staging.rb
457
462
  - lib/gitlab/qa/scenario/test/instance/staging_ref.rb
@@ -493,6 +498,7 @@ files:
493
498
  - lib/gitlab/qa/scenario/test/omnibus/image.rb
494
499
  - lib/gitlab/qa/scenario/test/omnibus/update_from_previous.rb
495
500
  - lib/gitlab/qa/scenario/test/omnibus/update_from_previous_ai.rb
501
+ - lib/gitlab/qa/scenario/test/omnibus/update_to_next.rb
496
502
  - lib/gitlab/qa/scenario/test/omnibus/upgrade.rb
497
503
  - lib/gitlab/qa/service/cluster_provider/base.rb
498
504
  - lib/gitlab/qa/service/cluster_provider/k3d.rb
@@ -516,6 +522,7 @@ files:
516
522
  - support/manifests/suggested_reviewer/pubsub.yaml
517
523
  - support/manifests/suggested_reviewer/recommender-bot.yaml
518
524
  - support/manifests/suggested_reviewer/recommender.yaml
525
+ - support/pipeline/create_for_projectname.rb
519
526
  - support/setup/gitlab_duo_setup.rb
520
527
  - tls_certificates/authority/ca.crt
521
528
  - tls_certificates/authority/ca.key
@@ -549,7 +556,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
549
556
  - !ruby/object:Gem::Version
550
557
  version: '0'
551
558
  requirements: []
552
- rubygems_version: 3.3.27
559
+ rubygems_version: 3.5.22
553
560
  signing_key:
554
561
  specification_version: 4
555
562
  summary: Integration tests for GitLab