gitlab-qa 7.29.0 → 7.31.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: 8d4ca3feba042298fe467133b5f576653b553af61ac01a0b72a1a970917e3711
4
- data.tar.gz: 61ee29dbe4355bcbc18d8e164b97f1453c461419fcf6bd70543a659e5029d333
3
+ metadata.gz: 950731b29895b80ed3a174ade472d58c7496fc60620959224790f007a0beff79
4
+ data.tar.gz: 66d92f34024e8c9a4b679424c0f1994713ac7180eadd875f732d8c4d8f741a9b
5
5
  SHA512:
6
- metadata.gz: 5ddff780b5188c489bec89ce0b475096ac707f9e2e5138cc400efeef9fbd576b4c5bebc77f43af207109503e08e1c1efaf2813e3666bd9d88d5807f7c9691891
7
- data.tar.gz: 34b7eacbd20c81f264aaf478f35e9ed78d5c7e185b18178bd55fa1c5fc37b0053f54bd49027d994cf91d6d69120c3371fdb818727419c17ef10ea7f373a4c91d
6
+ metadata.gz: fab55c1cfbcaa92e9b24156a61d1314e28565be51c1d0e06387445554f25dd1f170f192d2784a2d1bd40d7ff28de484ceba9830bcb16dd1d792a11c2253171c8
7
+ data.tar.gz: 663d5d28fa646a0b19ac84b292b61879b8ebc238657d99928d10ffee995dfc12dd56419cfbdd5cf1b9384c665dc6e54cedde4136c2b32fd4810982821f2cd4af
data/.gitignore CHANGED
@@ -8,6 +8,9 @@
8
8
  /.idea
9
9
  .ruby-version
10
10
  .ruby-gemset
11
+ .DS_Store
12
+ .rakeTasks
13
+ .tool-versions
11
14
 
12
15
  # ignore built gems
13
16
  *.gem
@@ -70,6 +70,8 @@ workflow:
70
70
  variables:
71
71
  DOCKER_DRIVER: overlay2
72
72
  DOCKER_HOST: tcp://docker:2375
73
+ COLORIZED_LOGS: "true"
74
+ QA_DEBUG: "false"
73
75
  QA_CAN_TEST_GIT_PROTOCOL_V2: "true"
74
76
  QA_CAN_TEST_PRAEFECT: "false"
75
77
  QA_GENERATE_ALLURE_REPORT: "true"
@@ -0,0 +1,25 @@
1
+ ce:decomposition_multiple_db:
2
+ extends:
3
+ - .rules:ce-never-when-triggered-by-feature-flag-definition-change
4
+ - .rules:ce-never-when-qa-tests-specified
5
+ - .test
6
+ - .high-capacity
7
+ - .ce-variables
8
+ - .rspec-report-opts
9
+ - .combined-gitlab-qa-options-script
10
+ parallel: 5
11
+ variables:
12
+ GITLAB_QA_OPTIONS_COMBINED: "$GITLAB_QA_OPTIONS --omnibus-config decomposition_multiple_db"
13
+
14
+ ee:decomposition_multiple_db:
15
+ extends:
16
+ - .rules:ee-never-when-triggered-by-feature-flag-definition-change
17
+ - .rules:ee-never-when-qa-tests-specified
18
+ - .test
19
+ - .ee-variables
20
+ - .high-capacity
21
+ - .rspec-report-opts
22
+ - .combined-gitlab-qa-options-script
23
+ parallel: 5
24
+ variables:
25
+ GITLAB_QA_OPTIONS_COMBINED: "$GITLAB_QA_OPTIONS --omnibus-config decomposition_multiple_db"
@@ -1,4 +1,4 @@
1
- ce:ci_decomposition:
1
+ ce:decomposition_single_db:
2
2
  extends:
3
3
  - .rules:ce-never-when-triggered-by-feature-flag-definition-change
4
4
  - .rules:ce-never-when-qa-tests-specified
@@ -9,9 +9,9 @@ ce:ci_decomposition:
9
9
  - .combined-gitlab-qa-options-script
10
10
  parallel: 5
11
11
  variables:
12
- GITLAB_QA_OPTIONS_COMBINED: "$GITLAB_QA_OPTIONS --omnibus-config ci_decomposition"
12
+ GITLAB_QA_OPTIONS_COMBINED: "$GITLAB_QA_OPTIONS --omnibus-config decomposition_single_db"
13
13
 
14
- ee:ci_decomposition:
14
+ ee:decomposition_single_db:
15
15
  extends:
16
16
  - .rules:ee-never-when-triggered-by-feature-flag-definition-change
17
17
  - .rules:ee-never-when-qa-tests-specified
@@ -22,4 +22,4 @@ ee:ci_decomposition:
22
22
  - .combined-gitlab-qa-options-script
23
23
  parallel: 5
24
24
  variables:
25
- GITLAB_QA_OPTIONS_COMBINED: "$GITLAB_QA_OPTIONS --omnibus-config ci_decomposition"
25
+ GITLAB_QA_OPTIONS_COMBINED: "$GITLAB_QA_OPTIONS --omnibus-config decomposition_single_db"
data/.rubocop.yml CHANGED
@@ -36,3 +36,6 @@ Style/SignalException:
36
36
 
37
37
  Layout/SpaceBeforeFirstArg:
38
38
  Enabled: false
39
+
40
+ RSpec/MultipleMemoizedHelpers:
41
+ Enabled: false
data/.rubocop_todo.yml CHANGED
@@ -89,11 +89,6 @@ RSpec/LeakyConstantDeclaration:
89
89
  Exclude:
90
90
  - 'spec/gitlab/qa/scenario/test/instance/deployment_base_spec.rb'
91
91
 
92
- # Offense count: 221
93
- # Configuration parameters: AllowSubject.
94
- RSpec/MultipleMemoizedHelpers:
95
- Max: 22
96
-
97
92
  # Offense count: 1
98
93
  # Cop supports --auto-correct.
99
94
  Style/ExplicitBlockArgument:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-qa (7.29.0)
4
+ gitlab-qa (7.31.0)
5
5
  activesupport (~> 6.1)
6
6
  gitlab (~> 4.18.0)
7
7
  http (~> 5.0)
@@ -219,7 +219,7 @@ GEM
219
219
  concurrent-ruby (~> 1.0)
220
220
  unf (0.1.4)
221
221
  unf_ext
222
- unf_ext (0.0.8.1)
222
+ unf_ext (0.0.8.2)
223
223
  unicode-display_width (1.8.0)
224
224
  webmock (3.7.0)
225
225
  addressable (>= 2.3.6)
@@ -712,6 +712,23 @@ in the GitLab project).
712
712
  This is used to retrieve the version that staging is currently running.
713
713
  This can be found in the shared 1Password vault.
714
714
 
715
+ - `GITLAB_USERNAME`: An existing user.
716
+
717
+ - `GITLAB_PASSWORD`: The user's password.
718
+
719
+ **Required by specific tests:**
720
+
721
+ - `QA_PRAEFECT_REPOSITORY_STORAGE`: The name of a Gitaly Cluster storage.
722
+
723
+ - `GITLAB_ADMIN_USERNAME`: An existing user with administrator access. Required by tests that set feature flags or
724
+ perform other admin actions.
725
+
726
+ - `GITLAB_ADMIN_PASSWORD`: The administrator user's password.
727
+
728
+ - `GITLAB_QA_USERNAME_X`: The username of a pre-generated test user, where `X` is `1` to `6`.
729
+
730
+ - `GITLAB_QA_PASSWORD_X`: The pre-generated test user's password.
731
+
715
732
  **Optional environment variables:**
716
733
 
717
734
  - `GITLAB_QA_DEV_ACCESS_TOKEN`: A valid personal access token for the
@@ -719,17 +736,24 @@ in the GitLab project).
719
736
  This is used to pull the QA Docker image from the Omnibus GitLab `dev` Container Registry.
720
737
  If the variable isn't present, the QA image from Docker Hub will be used.
721
738
  This can be found in the shared 1Password vault.
739
+ Please note that this variable must be provided when you need to be sure the version of the
740
+ tests matches the version of GitLab on Staging. If the version from Docker Hub is used it might not include changes deployed to Staging very recently.
722
741
 
723
- Example:
742
+ An example of how to run the smoke tests:
724
743
 
725
744
  ```
726
- $ export GITLAB_QA_USER_AGENT="$GITLAB_QA_USER_AGENT"
727
- $ export GITLAB_QA_ACCESS_TOKEN=your_api_access_token
728
- $ export GITLAB_QA_DEV_ACCESS_TOKEN=your_dev_registry_access_token
745
+ $ export GITLAB_QA_USER_AGENT="<value from 1Password>"
746
+ $ export GITLAB_QA_ACCESS_TOKEN="<value from 1Password>"
747
+ $ export GITLAB_QA_DEV_ACCESS_TOKEN="<value from 1Password>"
729
748
  $ export GITLAB_USERNAME="gitlab-qa"
730
- $ export GITLAB_PASSWORD="$GITLAB_QA_PASSWORD"
749
+ $ export GITLAB_PASSWORD="<value from 1Password>"
750
+ $ export GITLAB_ADMIN_USERNAME="<value from 1Password>"
751
+ $ export GITLAB_ADMIN_PASSWORD="<value from 1Password>"
752
+ $ export GITLAB_QA_USERNAME_1="gitlab-qa-user1"
753
+ $ export GITLAB_QA_PASSWORD_1="<value from 1Password>"
754
+ $ export QA_PRAEFECT_REPOSITORY_STORAGE="nfs-file22"
731
755
 
732
- $ gitlab-qa Test::Instance::Staging
756
+ $ gitlab-qa Test::Instance::Staging -- --tag smoke
733
757
  ```
734
758
 
735
759
  ### `Test::Instance::StagingRef`
@@ -828,6 +852,52 @@ by setting `QA_COOKIES=gitlab_canary=true`. This adds a cookie
828
852
  to all web requests which will result in them being routed
829
853
  to the canary fleet.
830
854
 
855
+ **Required environment variables:**
856
+
857
+ - `GITLAB_QA_USER_AGENT`: The browser user-agent to use instead of the default Chrome user-agent.
858
+ This is needed for the automated tests to bypass the WAF
859
+
860
+ - `GITLAB_QA_ACCESS_TOKEN`: A valid personal access token with the `api` scope.
861
+ This is used to retrieve the version that staging is currently running.
862
+ This can be found in the shared 1Password vault.
863
+
864
+ - `GITLAB_USERNAME`: An existing user.
865
+
866
+ - `GITLAB_PASSWORD`: The user's password.
867
+
868
+ **Required by specific tests:**
869
+
870
+ - `GITLAB_QA_USERNAME_X`: The username of a pre-generated test user, where `X` is `1` to `6`.
871
+
872
+ - `GITLAB_QA_PASSWORD_X`: The pre-generated test user's password.
873
+
874
+ **Optional environment variables:**
875
+
876
+ - `GITLAB_QA_DEV_ACCESS_TOKEN`: A valid personal access token for the
877
+ `gitlab-qa-bot` on `dev.gitlab.org` with the `registry` scope.
878
+ This is used to pull the QA Docker image from the Omnibus GitLab `dev` Container Registry.
879
+ If the variable isn't present, the QA image from Docker Hub will be used.
880
+ This can be found in the shared 1Password vault.
881
+ Please note that this variable should be provided when you need to be sure the version of the
882
+ tests matches the version of GitLab on Staging. If the version from Docker Hub is used it might not include changes deployed to Staging very recently.
883
+
884
+ An example of how to run the smoke tests:
885
+
886
+ ```
887
+ $ export GITLAB_QA_USER_AGENT="<value from 1Password>"
888
+ $ export GITLAB_QA_ACCESS_TOKEN="<value from 1Password>"
889
+ $ export GITLAB_QA_DEV_ACCESS_TOKEN="<value from 1Password>"
890
+ $ export GITLAB_USERNAME="gitlab-qa"
891
+ $ export GITLAB_PASSWORD="<value from 1Password>"
892
+ $ export GITLAB_QA_USERNAME_1="gitlab-qa-user1"
893
+ $ export GITLAB_QA_PASSWORD_1="<value from 1Password>"
894
+ $ export QA_CAN_TEST_GIT_PROTOCOL_V2="false"
895
+ $ export QA_CAN_TEST_ADMIN_FEATURES="false"
896
+ $ export QA_CAN_TEST_PRAEFECT="false"
897
+
898
+ $ gitlab-qa Test::Instance::Production -- --tag smoke
899
+ ```
900
+
831
901
  ### `Test::Instance::Preprod`
832
902
 
833
903
  This scenario functions the same as `Test::Instance::Staging`
@@ -927,12 +997,20 @@ This scenario is a composition of two orchestrated scenarios. It tests the conta
927
997
  GITLAB_TLS_CERTIFICATE=$(cat /path/to/certificate.crt) gitlab-qa Test::Integration::RegistryTLS EE --omnibus-config object_storage_aws
928
998
  ```
929
999
 
930
- ### Test::Instance::Image EE --omnibus-config ci_decomposition
1000
+ ### Test::Instance::Image EE --omnibus-config decomposition_single_db
1001
+
1002
+ This scenario is to run tests against a GitLab instance with a [decomposed database](https://gitlab.com/groups/gitlab-org/-/epics/6160) using a single database:
1003
+
1004
+ ```ruby
1005
+ gitlab-qa Test::Instance::Image EE --omnibus-config decomposition_single_db
1006
+ ```
1007
+
1008
+ ### Test::Instance::Image EE --omnibus-config decomposition_multiple_db
931
1009
 
932
- This scenario is to run tests against GitLab instance with [decomposed database](https://gitlab.com/groups/gitlab-org/-/epics/6160) on a single Postgres:
1010
+ This scenario is to run tests against a GitLab instance with a [decomposed database](https://gitlab.com/groups/gitlab-org/-/epics/6160) using multiple databases:
933
1011
 
934
1012
  ```ruby
935
- gitlab-qa Test::Instance::Image EE --omnibus-config ci_decomposition
1013
+ gitlab-qa Test::Instance::Image EE --omnibus-config decomposition_multiple_db
936
1014
  ```
937
1015
 
938
1016
  ### `Test::Instance::Geo EE|<full image address>:nightly|latest|any_tag http://geo-primary.gitlab http://geo-secondary.gitlab`
@@ -176,6 +176,7 @@ module Gitlab
176
176
  exec_commands << seed_admin_token_command if seed_admin_token
177
177
  exec_commands << seed_test_data_command if seed_db
178
178
  exec_commands << Runtime::Scenario.omnibus_exec_commands
179
+ exec_commands << add_git_server_hooks unless Runtime::Scenario.skip_server_hooks
179
180
 
180
181
  commands = exec_commands.flatten.uniq
181
182
  return if commands.empty?
@@ -184,14 +185,17 @@ module Gitlab
184
185
  commands.each { |command| @docker.exec(name, command) }
185
186
  end
186
187
 
187
- def sha_version
188
+ def rails_version
188
189
  json = @docker.read_file(
189
190
  @release.image, @release.tag,
190
191
  '/opt/gitlab/version-manifest.json'
191
192
  )
192
193
 
193
194
  manifest = JSON.parse(json)
194
- manifest['software']['gitlab-rails']['locked_version']
195
+ {
196
+ sha: manifest['software']['gitlab-rails']['locked_version'],
197
+ source: manifest['software']['gitlab-rails']['locked_source']['git']
198
+ }
195
199
  end
196
200
 
197
201
  def copy_key_file(env_key)
@@ -243,6 +247,25 @@ module Gitlab
243
247
  ["gitlab-rails runner #{DATA_PATH}/admin_access_token_seed.rb"]
244
248
  end
245
249
 
250
+ def add_git_server_hooks
251
+ global_server_prereceive_hook = <<~SCRIPT
252
+ #!/usr/bin/env bash
253
+
254
+ if [[ \\\$GL_PROJECT_PATH =~ 'reject-prereceive' ]]; then
255
+ echo 'GL-HOOK-ERR: Custom error message rejecting prereceive hook for projects with GL_PROJECT_PATH matching pattern reject-prereceive'
256
+ exit 1
257
+ fi
258
+ SCRIPT
259
+
260
+ [
261
+ @docker.exec(name, 'mkdir -p /opt/gitlab/embedded/service/gitlab-shell/hooks/pre-receive.d'),
262
+ @docker.write_files(name) do |f|
263
+ f.write('/opt/gitlab/embedded/service/gitlab-shell/hooks/pre-receive.d/pre-receive.d', global_server_prereceive_hook, false)
264
+ end,
265
+ @docker.exec(name, 'chmod +x /opt/gitlab/embedded/service/gitlab-shell/hooks/pre-receive.d/*')
266
+ ]
267
+ end
268
+
246
269
  class Availability
247
270
  def initialize(name, relative_path: '', scheme: 'http', protocol_port: 80)
248
271
  @docker = Docker::Engine.new
@@ -11,7 +11,7 @@ module Gitlab
11
11
  attr_accessor :suite, :release, :network, :args, :volumes, :env, :runner_network, :hostname
12
12
 
13
13
  def initialize
14
- @docker = Docker::Engine.new
14
+ @docker = Docker::Engine.new(stream_output: true) # stream test output directly instead of through logger
15
15
  @volumes = {}
16
16
  @env = {}
17
17
  end
@@ -2,11 +2,17 @@ module Gitlab
2
2
  module QA
3
3
  module Docker
4
4
  class Command
5
- attr_reader :args
5
+ attr_reader :args, :stream_output
6
6
 
7
- def initialize(cmd = nil, mask_secrets: nil)
7
+ # Shell command
8
+ #
9
+ # @param [<String, Array>] cmd
10
+ # @param [<String, Array>] mask_secrets
11
+ # @param [Boolean] stream_output stream command output to stdout directly instead of logger
12
+ def initialize(cmd = nil, mask_secrets: nil, stream_output: false)
8
13
  @args = Array(cmd)
9
14
  @mask_secrets = Array(mask_secrets)
15
+ @stream_output = stream_output
10
16
  end
11
17
 
12
18
  def <<(*args)
@@ -7,6 +7,12 @@ module Gitlab
7
7
  DOCKER_HOST = ENV['DOCKER_HOST'] || 'http://localhost'
8
8
  PRIVILEGED_COMMANDS = [/^iptables.*/].freeze
9
9
 
10
+ attr_reader :stream_output
11
+
12
+ def initialize(stream_output: false)
13
+ @stream_output = stream_output
14
+ end
15
+
10
16
  def hostname
11
17
  URI(DOCKER_HOST).host
12
18
  end
@@ -25,7 +31,7 @@ module Gitlab
25
31
  end
26
32
 
27
33
  def run(image:, tag: nil, args: [])
28
- Docker::Command.new('run').tap do |command|
34
+ Docker::Command.new('run', stream_output: stream_output).tap do |command|
29
35
  yield command if block_given?
30
36
 
31
37
  command << full_image_name(image, tag)
@@ -55,8 +61,15 @@ module Gitlab
55
61
  def write_files(name)
56
62
  exec(name, yield(
57
63
  Class.new do
58
- def self.write(file, contents)
59
- %(echo "#{contents}" > #{file};)
64
+ # @param file The name of the file
65
+ # @param contents The content of the file to write
66
+ # @param expand_vars Set false if you need to write an environment variable '$' to a file. The variable should be escaped \\\$
67
+ def self.write(file, contents, expand_vars = true)
68
+ if expand_vars
69
+ %(echo "#{contents}" > #{file};)
70
+ else
71
+ %(echo '#{contents}' > #{file};)
72
+ end
60
73
  end
61
74
 
62
75
  def self.append(file, contents)
@@ -17,25 +17,33 @@ module Gitlab
17
17
  @logger = Runtime::Logger.logger
18
18
  end
19
19
 
20
+ attr_reader :command, :logger
21
+
20
22
  def execute! # rubocop:disable Metrics/AbcSize
21
23
  raise StatusError, 'Command already executed' if @output.any?
22
24
 
23
- @logger.info("Docker shell command: `#{@command.mask_secrets}`".cyan)
25
+ logger.info("Docker shell command: `#{@command.mask_secrets.cyan}`")
24
26
 
25
27
  Open3.popen2e(@command.to_s) do |_in, out, wait|
26
28
  out.each do |line|
27
29
  @output.push(line)
28
- print "." unless Runtime::Env.ci # indicate progress for local run
30
+
31
+ if stream_progress
32
+ print "."
33
+ elsif command.stream_output
34
+ puts line
35
+ end
36
+
29
37
  yield line, wait if block_given?
30
38
  end
31
- puts unless Runtime::Env.ci # add newline after progress dots
39
+ puts if stream_progress
32
40
 
33
41
  if wait.value.exited? && wait.value.exitstatus.nonzero?
34
- @logger.error("Docker shell command output:\n#{output}")
35
- raise StatusError, "Docker command `#{@command.mask_secrets}` failed! ✘"
42
+ logger.error("Docker shell command output:\n#{output}") unless command.stream_output
43
+ raise StatusError, "Docker command `#{@command.mask_secrets[0..100]}` failed! ✘"
36
44
  end
37
45
 
38
- @logger.debug("Docker shell command output:\n#{output}") unless output.empty?
46
+ logger.debug("Docker shell command output:\n#{output}") unless command.stream_output || output.empty?
39
47
  end
40
48
 
41
49
  output
@@ -43,6 +51,13 @@ module Gitlab
43
51
 
44
52
  private
45
53
 
54
+ # Stream only command execution progress and log output when command finished
55
+ #
56
+ # @return [Boolean]
57
+ def stream_progress
58
+ !(Runtime::Env.ci || command.stream_output)
59
+ end
60
+
46
61
  def output
47
62
  @output.join.chomp
48
63
  end
@@ -210,10 +210,10 @@ module Gitlab
210
210
 
211
211
  failure = full_stacktrace(test)
212
212
 
213
- if test.screenshot? && !failure.include?('500 Internal Server Error') && !failure.include?('fabricate_via_api!')
213
+ if test.screenshot? && !['500 Internal Server Error', 'fabricate_via_api!', 'Error Code 500'].any? { |e| failure.include?(e) }
214
214
  relative_url = gitlab.upload_file(file_fullpath: test.failure_screenshot)
215
215
 
216
- section = "### Screenshot: #{relative_url.markdown}"
216
+ section = "### Screenshot: #{relative_url.markdown}" if relative_url
217
217
  end
218
218
 
219
219
  section
@@ -7,7 +7,9 @@ module Gitlab
7
7
  class ReportResults < ReportAsIssue
8
8
  attr_accessor :testcase_project_reporter, :results_issue_project_reporter, :files, :test_case_project, :results_issue_project, :gitlab
9
9
 
10
- def initialize(token:, input_files:, test_case_project:, results_issue_project:, dry_run: false, **kwargs)
10
+ IGNORE_EXCEPTIONS = ['Net::ReadTimeout'].freeze
11
+
12
+ def initialize(token:, input_files:, test_case_project: nil, results_issue_project: nil, dry_run: false, **kwargs)
11
13
  @testcase_project_reporter = Gitlab::QA::Report::ResultsInTestCases.new(token: token, input_files: input_files, project: test_case_project, dry_run: dry_run, **kwargs)
12
14
  @results_issue_project_reporter = Gitlab::QA::Report::ResultsInIssues.new(token: token, input_files: input_files, project: results_issue_project, dry_run: dry_run, **kwargs)
13
15
  @test_case_project = test_case_project
@@ -32,7 +34,7 @@ module Gitlab
32
34
  test_results.each do |test|
33
35
  puts "Reporting test: #{test.file} | #{test.name}\n"
34
36
 
35
- report_test(test) unless test.skipped
37
+ report_test(test) if should_report?(test)
36
38
  end
37
39
 
38
40
  test_results.write
@@ -54,6 +56,40 @@ module Gitlab
54
56
  testcase_project_reporter.update_testcase(testcase, test)
55
57
  results_issue_project_reporter.update_issue(issue, test)
56
58
  end
59
+
60
+ # Checks if a test result should be reported.
61
+ #
62
+ # @return [Boolean] false if the test was skipped or failed because of a transient error that can be ignored.
63
+ # Otherwise returns true.
64
+ def should_report?(test)
65
+ return false if test.skipped
66
+
67
+ if test.report.key?('exceptions')
68
+ reason = ignore_failure_reason(test.report['exceptions'])
69
+
70
+ if reason
71
+ puts "Issue update skipped because #{reason}"
72
+
73
+ return false
74
+ end
75
+ end
76
+
77
+ true
78
+ end
79
+
80
+ # Determine any reason to ignore a failure.
81
+ #
82
+ # @param [Array<Hash>] exceptions the exceptions associated with the failure.
83
+ # @return [String] the reason to ignore the exceptions, or `nil` if any exceptions should not be ignored.
84
+ def ignore_failure_reason(exceptions)
85
+ exception_classes = exceptions
86
+ .filter_map { |exception| exception['class'] if IGNORE_EXCEPTIONS.include?(exception['class']) }
87
+ .compact
88
+ return if exception_classes.empty? || exception_classes.size < exceptions.size
89
+
90
+ msg = exception_classes.many? ? 'the errors were' : 'the error was'
91
+ "#{msg} #{exception_classes.join(', ')}"
92
+ end
57
93
  end
58
94
  end
59
95
  end
@@ -35,7 +35,7 @@ module Gitlab
35
35
  note_posted = note_status(issue, test)
36
36
 
37
37
  if labels_updated || note_posted
38
- puts "Issue updated."
38
+ puts "Issue updated: #{issue.web_url}"
39
39
  else
40
40
  puts "Test passed, no results issue update needed."
41
41
  end
@@ -15,6 +15,7 @@ module Gitlab
15
15
  Runtime::Scenario.define(:seed_db, false)
16
16
  Runtime::Scenario.define(:seed_admin_token, true) # Create an admin access token for root user by default
17
17
  Runtime::Scenario.define(:omnibus_exec_commands, [])
18
+ Runtime::Scenario.define(:skip_server_hooks, false)
18
19
 
19
20
  # Omnibus Configurators specified by flags
20
21
  @active_configurators = []
@@ -37,6 +38,10 @@ module Gitlab
37
38
  Runtime::Scenario.define(:seed_admin_token, false)
38
39
  end
39
40
 
41
+ opts.on('--skip-server-hooks', 'Skip adding global git server hooks') do
42
+ Runtime::Scenario.define(:skip_server_hooks, true)
43
+ end
44
+
40
45
  opts.on('--qa-image QA_IMAGE', String, 'Specifies a QA image to be used instead of inferring it from the GitLab image. See Gitlab::QA::Release#qa_image') do |value|
41
46
  Runtime::Scenario.define(:qa_image, value)
42
47
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
+ require 'fileutils'
4
5
 
5
6
  module Gitlab
6
7
  module QA
@@ -12,13 +13,10 @@ module Gitlab
12
13
 
13
14
  def self.logger
14
15
  @logger ||= begin
15
- log_path = Runtime::Env.log_path
16
- FileUtils.mkdir_p(log_path) unless File.exist?(log_path)
16
+ log_path = Env.log_path
17
+ ::FileUtils.mkdir_p(log_path) unless File.exist?(log_path)
17
18
 
18
- QA::TestLogger.logger(
19
- level: Runtime::Env.debug? ? "DEBUG" : Runtime::Env.log_level,
20
- path: log_path
21
- )
19
+ TestLogger.logger(level: Env.debug? ? "DEBUG" : Env.log_level, path: log_path)
22
20
  end
23
21
  end
24
22
  end
@@ -4,7 +4,7 @@ module Gitlab
4
4
  module QA
5
5
  module Runtime
6
6
  module OmnibusConfigurations
7
- class CiDecomposition < Default
7
+ class DecompositionMultipleDb < Default
8
8
  def configuration
9
9
  # HACK: commenting commands out as these commands should be run *after* the first
10
10
  # reconfiguration (see first command in #exec_commands)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Runtime
6
+ module OmnibusConfigurations
7
+ class DecompositionSingleDb < Default
8
+ def configuration
9
+ <<~OMNIBUS
10
+ gitlab_rails['databases']['main']['enable'] = true
11
+ gitlab_rails['databases']['ci']['enable'] = true
12
+ gitlab_rails['databases']['ci']['db_database'] = 'gitlabhq_production'
13
+ OMNIBUS
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -12,22 +12,43 @@ module Gitlab
12
12
  # the window defined by the `weekday_hours` method.
13
13
  # We perform a single API call to get the commit
14
14
  class Version < Scenario::Template
15
+ SOURCE_MAP = {
16
+ 'git@dev.gitlab.org:gitlab/gitlab-ee.git' => {
17
+ host: 'dev.gitlab.org',
18
+ project: 'gitlab/gitlab-ee'
19
+ },
20
+ 'git@dev.gitlab.org:gitlab/gitlabhq.git' => {
21
+ host: 'dev.gitlab.org',
22
+ project: 'gitlab/gitlabhq'
23
+ },
24
+ 'git@gitlab.com:gitlab-org/gitlab.git' => {
25
+ host: 'gitlab.com',
26
+ project: 'gitlab-org/gitlab'
27
+ },
28
+ 'git@gitlab.com:gitlab-org/gitlab-foss.git' => {
29
+ host: 'gitlab.com',
30
+ project: 'gitlab-org/gitlab-foss'
31
+ }
32
+ }.freeze
33
+
15
34
  def perform(release = 'ce')
16
35
  version = Component::Gitlab.perform do |gitlab|
17
36
  gitlab.release = release
18
37
  gitlab.act do
19
38
  pull
20
- sha_version
39
+ rails_version
21
40
  end
22
41
  end
23
42
 
24
- project = "gitlab-org/#{QA::Release.new(release).api_project_name}"
25
- commit = api_commit_detail(project, version)
43
+ project = SOURCE_MAP[version[:source]][:project]
44
+ host = SOURCE_MAP[version[:source]][:host]
45
+ sha = version[:sha]
46
+ commit = api_commit_detail(host, project, sha)
26
47
 
27
48
  if commit_within_hours?(commit['created_at'], weekday_hours(commit['created_at']))
28
- puts "Found commit #{version} in recent history of #{project}"
49
+ puts "Found commit #{sha} in recent history of #{project} on #{host}"
29
50
  else
30
- puts "Did not find #{version} in recent history of #{project}"
51
+ puts "Did not find #{sha} in recent history of #{project} on #{host}"
31
52
  exit 1
32
53
  end
33
54
  end
@@ -51,9 +72,14 @@ module Gitlab
51
72
  Time.at(Time.parse(commit_time_string).utc).to_datetime > Time.at((Time.now - hours * 60 * 60).utc).to_datetime
52
73
  end
53
74
 
54
- def api_commit_detail(project, commit_id)
55
- api = 'https://gitlab.com/api/v4'
56
- url = "#{api}/projects/#{CGI.escape(project)}/repository/commits/#{commit_id}"
75
+ def api_commit_detail(host, project, sha)
76
+ url = "https://#{host}/api/v4/projects/#{CGI.escape(project)}/repository/commits/#{sha}"
77
+
78
+ if host == 'dev.gitlab.org'
79
+ Runtime::Env.require_qa_dev_access_token!
80
+
81
+ url = "#{url}?private_token=#{Runtime::Env.qa_dev_access_token}"
82
+ end
57
83
 
58
84
  JSON.parse(Net::HTTP.get(URI(url)))
59
85
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  module QA
5
- VERSION = '7.29.0'
5
+ VERSION = '7.31.0'
6
6
  end
7
7
  end
data/lib/gitlab/qa.rb CHANGED
@@ -20,7 +20,8 @@ module Gitlab
20
20
  autoload :ObjectStorageGcs, 'gitlab/qa/runtime/omnibus_configurations/object_storage_gcs'
21
21
  autoload :LicenseMode, 'gitlab/qa/runtime/omnibus_configurations/license_mode'
22
22
  autoload :RegistryObjectStorage, 'gitlab/qa/runtime/omnibus_configurations/registry_object_storage'
23
- autoload :CiDecomposition, 'gitlab/qa/runtime/omnibus_configurations/ci_decomposition'
23
+ autoload :DecompositionSingleDb, 'gitlab/qa/runtime/omnibus_configurations/decomposition_single_db'
24
+ autoload :DecompositionMultipleDb, 'gitlab/qa/runtime/omnibus_configurations/decomposition_multiple_db'
24
25
  end
25
26
  end
26
27
 
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'yaml'
4
+
3
5
  class GenerateQAJobs
4
6
  def initialize(no_of_example_files)
5
7
  @no_of_example_files = no_of_example_files
@@ -7,63 +9,82 @@ class GenerateQAJobs
7
9
  end
8
10
 
9
11
  # rubocop:disable Metrics/AbcSize
10
- # rubocop:disable Metrics/PerceivedComplexity
11
- # rubocop:disable Metrics/CyclomaticComplexity
12
12
  def execute
13
13
  jobs = load_yml_contents('base')
14
- jobs.concat(load_yml_contents('sanity_framework'))
15
- jobs.concat(load_yml_contents('custom_parallel'))
16
- jobs.concat(load_yml_contents('instance')) if should_run?('test_instance_all')
17
- jobs.concat(load_yml_contents('relative_url')) if should_run?('test_instance_all')
18
- jobs.concat(load_yml_contents('ci_decomposition')) if should_run?('test_instance_all')
19
- jobs.concat(load_yml_contents('repository_storage')) if should_run?('test_instance_all_repository_storage')
20
- jobs.concat(load_yml_contents('omnibus_image'))
21
- jobs.concat(load_yml_contents('update')) if should_run?('test_instance_all')
22
- jobs.concat(load_yml_contents('omnibus_upgrade'))
23
- jobs.concat(load_yml_contents('ee_previous_to_ce_update'))
24
- jobs.concat(load_yml_contents('mattermost')) if should_run?('test_integration_mattermost')
25
- jobs.concat(load_yml_contents('service_ping_disabled')) if should_run?('test_integration_servicepingdisabled')
26
- jobs.concat(load_yml_contents('ldap_no_tls')) if should_run?('test_integration_ldapnotls')
27
- jobs.concat(load_yml_contents('ldap_tls')) if should_run?('test_integration_ldaptls')
28
- jobs.concat(load_yml_contents('ldap_no_server')) if should_run?('test_integration_ldapnoserver')
29
- jobs.concat(load_yml_contents('instance_saml')) if should_run?('test_integration_instancesaml')
30
- jobs.concat(load_yml_contents('group_saml')) if should_run?('test_integration_groupsaml')
31
- jobs.concat(load_yml_contents('object_storage')) if should_run?('test_instance_all_object_storage')
32
- jobs.concat(load_yml_contents('object_storage_aws')) if should_run?('test_instance_all_object_storage')
33
- jobs.concat(load_yml_contents('object_storage_gcs')) if should_run?('test_instance_all_object_storage')
34
- jobs.concat(load_yml_contents('object_storage_registry_tls')) if should_run?('test_integration_registrytls')
35
- jobs.concat(load_yml_contents('registry')) if should_run?('test_integration_registry')
36
- jobs.concat(load_yml_contents('packages')) if should_run?('test_instance_all_packages')
37
- jobs.concat(load_yml_contents('elasticsearch')) if should_run?('test_integration_elasticsearch')
38
- jobs.concat(load_yml_contents('praefect')) if should_run?('test_instance_all')
39
- jobs.concat(load_yml_contents('gitaly_cluster')) if should_run?('test_instance_all')
40
- jobs.concat(load_yml_contents('mtls')) if should_run?('test_instance_all_mtls')
41
- jobs.concat(load_yml_contents('smtp')) if should_run?('test_integration_smtp')
42
- jobs.concat(load_yml_contents('jira')) if should_run?('test_instance_all_jira')
43
- jobs.concat(load_yml_contents('integrations')) if should_run?('test_instance_all_integrations')
44
- jobs.concat(load_yml_contents('large_setup')) if should_run?('test_instance_all_can_use_large_setup')
45
- jobs.concat(load_yml_contents('cloud_activation')) if should_run?('test_instance_all_cloud_activation')
46
- jobs.concat(load_yml_contents('registry_with_cdn')) if should_run?('test_integration_registrywithcdn')
47
- jobs.concat(load_yml_contents('staging'))
14
+ jobs.merge!(load_yml_contents('sanity_framework'))
15
+ jobs.merge!(load_yml_contents('custom_parallel'))
16
+ jobs.merge!(load_yml_contents('instance', should_automatically_run?('test_instance_all')))
17
+ jobs.merge!(load_yml_contents('relative_url', should_automatically_run?('test_instance_all')))
18
+ jobs.merge!(load_yml_contents('decomposition_single_db', should_automatically_run?('test_instance_all')))
19
+ jobs.merge!(load_yml_contents('decomposition_multiple_db', should_automatically_run?('test_instance_all')))
20
+ jobs.merge!(load_yml_contents('repository_storage', should_automatically_run?('test_instance_all_repository_storage')))
21
+ jobs.merge!(load_yml_contents('omnibus_image'))
22
+ jobs.merge!(load_yml_contents('update', should_automatically_run?('test_instance_all')))
23
+ jobs.merge!(load_yml_contents('omnibus_upgrade'))
24
+ jobs.merge!(load_yml_contents('ee_previous_to_ce_update'))
25
+ jobs.merge!(load_yml_contents('mattermost', should_automatically_run?('test_integration_mattermost')))
26
+ jobs.merge!(load_yml_contents('service_ping_disabled', should_automatically_run?('test_integration_servicepingdisabled')))
27
+ jobs.merge!(load_yml_contents('ldap_no_tls', should_automatically_run?('test_integration_ldapnotls')))
28
+ jobs.merge!(load_yml_contents('ldap_tls', should_automatically_run?('test_integration_ldaptls')))
29
+ jobs.merge!(load_yml_contents('ldap_no_server', should_automatically_run?('test_integration_ldapnoserver')))
30
+ jobs.merge!(load_yml_contents('instance_saml', should_automatically_run?('test_integration_instancesaml')))
31
+ jobs.merge!(load_yml_contents('group_saml', should_automatically_run?('test_integration_groupsaml')))
32
+ jobs.merge!(load_yml_contents('object_storage', should_automatically_run?('test_instance_all_object_storage')))
33
+ jobs.merge!(load_yml_contents('object_storage_aws', should_automatically_run?('test_instance_all_object_storage')))
34
+ jobs.merge!(load_yml_contents('object_storage_gcs', should_automatically_run?('test_instance_all_object_storage')))
35
+ jobs.merge!(load_yml_contents('object_storage_registry_tls', should_automatically_run?('test_integration_registrytls')))
36
+ jobs.merge!(load_yml_contents('registry', should_automatically_run?('test_integration_registry')))
37
+ jobs.merge!(load_yml_contents('packages', should_automatically_run?('test_instance_all_packages')))
38
+ jobs.merge!(load_yml_contents('elasticsearch', should_automatically_run?('test_integration_elasticsearch')))
39
+ jobs.merge!(load_yml_contents('praefect', should_automatically_run?('test_instance_all')))
40
+ jobs.merge!(load_yml_contents('gitaly_cluster', should_automatically_run?('test_instance_all')))
41
+ jobs.merge!(load_yml_contents('mtls', should_automatically_run?('test_instance_all_mtls')))
42
+ jobs.merge!(load_yml_contents('smtp', should_automatically_run?('test_integration_smtp')))
43
+ jobs.merge!(load_yml_contents('jira', should_automatically_run?('test_instance_all_jira')))
44
+ jobs.merge!(load_yml_contents('integrations', should_automatically_run?('test_instance_all_integrations')))
45
+ jobs.merge!(load_yml_contents('large_setup', should_automatically_run?('test_instance_all_can_use_large_setup')))
46
+ jobs.merge!(load_yml_contents('cloud_activation', should_automatically_run?('test_instance_all_cloud_activation')))
47
+ jobs.merge!(load_yml_contents('registry_with_cdn', should_automatically_run?('test_integration_registrywithcdn')))
48
+ jobs.merge!(load_yml_contents('staging'))
48
49
 
49
50
  # Disabling geo jobs temporarily due to https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/774
50
- # base.concat(load_yml_contents('geo')) if should_run?('scenario_test_geo')
51
+ # jobs.merge!(load_yml_contents('geo', should_automatically_run?('scenario_test_geo')))
52
+
53
+ yaml_string = jobs.to_yaml
54
+ de_stringify_reference(yaml_string)
51
55
 
52
- jobs
56
+ yaml_string
53
57
  end
58
+
54
59
  # rubocop:enable Metrics/AbcSize
55
- # rubocop:enable Metrics/PerceivedComplexity
56
- # rubocop:enable Metrics/CyclomaticComplexity
57
60
 
58
61
  private
59
62
 
60
- def should_run?(example_file_name)
63
+ def should_automatically_run?(example_file_name)
61
64
  @no_of_example_files.include?(example_file_name)
62
65
  end
63
66
 
64
- def load_yml_contents(file_prefix)
67
+ def load_yml_contents(file_prefix, automatic = true)
65
68
  jobs_dir_path = File.expand_path('../.gitlab/ci/jobs', __dir__)
66
- File.read(File.join(jobs_dir_path, "#{file_prefix}.gitlab-ci.yml"))
69
+ file_contents = File.read(File.join(jobs_dir_path, "#{file_prefix}.gitlab-ci.yml"))
70
+
71
+ # Enclose !reference in double quotes at it is not supported with YAML.load
72
+ stringify_reference(file_contents)
73
+ yaml_hash = YAML.safe_load(file_contents)
74
+
75
+ yaml_hash.each { |key, value| value.merge!("when" => "manual") } unless automatic
76
+
77
+ yaml_hash
78
+ end
79
+
80
+ def stringify_reference(str)
81
+ match_data = str.match(/!reference \[[a-zA-Z_, ]*\]/)
82
+ str.gsub!(match_data[0], "\"#{match_data[0]}\"") if match_data
83
+ end
84
+
85
+ def de_stringify_reference(str)
86
+ match_data = str.match(/"(!reference \[[a-zA-Z_, ]*\])"/)
87
+ str.gsub!(match_data[0], match_data[1]) if match_data
67
88
  end
68
89
  end
69
90
 
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: 7.29.0
4
+ version: 7.31.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: 2022-05-25 00:00:00.000000000 Z
11
+ date: 2022-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control
@@ -219,9 +219,10 @@ files:
219
219
  - ".gitignore"
220
220
  - ".gitlab-ci.yml"
221
221
  - ".gitlab/ci/jobs/base.gitlab-ci.yml"
222
- - ".gitlab/ci/jobs/ci_decomposition.gitlab-ci.yml"
223
222
  - ".gitlab/ci/jobs/cloud_activation.gitlab-ci.yml"
224
223
  - ".gitlab/ci/jobs/custom_parallel.gitlab-ci.yml"
224
+ - ".gitlab/ci/jobs/decomposition_multiple_db.gitlab-ci.yml"
225
+ - ".gitlab/ci/jobs/decomposition_single_db.gitlab-ci.yml"
225
226
  - ".gitlab/ci/jobs/ee_previous_to_ce_update.gitlab-ci.yml"
226
227
  - ".gitlab/ci/jobs/elasticsearch.gitlab-ci.yml"
227
228
  - ".gitlab/ci/jobs/geo.gitlab-ci.yml"
@@ -336,7 +337,8 @@ files:
336
337
  - lib/gitlab/qa/runtime/env.rb
337
338
  - lib/gitlab/qa/runtime/logger.rb
338
339
  - lib/gitlab/qa/runtime/omnibus_configuration.rb
339
- - lib/gitlab/qa/runtime/omnibus_configurations/ci_decomposition.rb
340
+ - lib/gitlab/qa/runtime/omnibus_configurations/decomposition_multiple_db.rb
341
+ - lib/gitlab/qa/runtime/omnibus_configurations/decomposition_single_db.rb
340
342
  - lib/gitlab/qa/runtime/omnibus_configurations/default.rb
341
343
  - lib/gitlab/qa/runtime/omnibus_configurations/license_mode.rb
342
344
  - lib/gitlab/qa/runtime/omnibus_configurations/object_storage.rb