From c6d6b8fa8b2ad92319e7d6831beb5129a2e074c8 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 1 Jan 2025 12:26:25 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/qa-common/main.gitlab-ci.yml | 23 +- .gitlab/ci/qa-common/rules.gitlab-ci.yml | 5 +- .gitlab/ci/rules.gitlab-ci.yml | 8 +- .gitlab/ci/test-on-cng/main.gitlab-ci.yml | 26 +- .gitlab/ci/test-on-gdk/main.gitlab-ci.yml | 25 +- .../main.gitlab-ci.yml | 11 +- .gitlab/ci/test-on-omnibus/main.gitlab-ci.yml | 11 +- qa/knapsack/.gitignore | 1 + .../example_runtimes/master_report.json | 519 ++++++++++++++++++ qa/qa/specs/knapsack_runner.rb | 36 +- qa/qa/specs/runner.rb | 35 +- qa/qa/specs/spec_helper.rb | 4 - qa/qa/support/knapsack_report.rb | 190 ++----- qa/qa/tools/knapsack_report_updater.rb | 18 +- qa/spec/support/knapsack_report_spec.rb | 32 -- qa/spec/tools/knapsack_report_updater_spec.rb | 19 +- qa/tasks/knapsack.rake | 50 -- 17 files changed, 673 insertions(+), 340 deletions(-) create mode 100644 qa/knapsack/example_runtimes/master_report.json delete mode 100644 qa/spec/support/knapsack_report_spec.rb diff --git a/.gitlab/ci/qa-common/main.gitlab-ci.yml b/.gitlab/ci/qa-common/main.gitlab-ci.yml index e176d4495de..9bcaef0fa1b 100644 --- a/.gitlab/ci/qa-common/main.gitlab-ci.yml +++ b/.gitlab/ci/qa-common/main.gitlab-ci.yml @@ -103,28 +103,8 @@ stages: # blocking merges due to flaky tests. allow_failure: true -.download-knapsack-report: +.upload-test-runtime-data: extends: - - .gitlab-qa-image - stage: .pre - variables: - KNAPSACK_DIR: ${CI_PROJECT_DIR}/qa/knapsack - GIT_STRATEGY: none - script: - - bundle exec rake "knapsack:download[test]" - - bundle exec rake "knapsack:create_reports_for_selective" - after_script: - # when using qa-image, code runs in /home/gitlab/qa folder - - mkdir -p "$KNAPSACK_DIR" && cp /home/gitlab/qa/knapsack/*.json "${KNAPSACK_DIR}/" - allow_failure: true - artifacts: - paths: - - qa/knapsack/*.json - expire_in: 1 day - -.upload-knapsack-report: - extends: - - .generate-knapsack-report-base - .qa-install - .ruby-image stage: report @@ -132,7 +112,6 @@ stages: variables: QA_JSON_REPORT_FILE_PATTERN: $CI_PROJECT_DIR/qa/tmp/rspec-*.json script: - - !reference [.generate-knapsack-report-base, script] - bundle exec rake "knapsack:upload_example_runtimes[$QA_JSON_REPORT_FILE_PATTERN]" .export-test-metrics: diff --git a/.gitlab/ci/qa-common/rules.gitlab-ci.yml b/.gitlab/ci/qa-common/rules.gitlab-ci.yml index 7f7c9bbb677..aa73b1125f8 100644 --- a/.gitlab/ci/qa-common/rules.gitlab-ci.yml +++ b/.gitlab/ci/qa-common/rules.gitlab-ci.yml @@ -200,9 +200,8 @@ include: when: never - *process-test-results -.rules:report:upload-knapsack-report: +.rules:report:upload-test-runtime-data: rules: - <<: *not-canonical-project when: never - - if: '$KNAPSACK_GENERATE_REPORT == "true"' - when: always + - *default-branch diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 19188922abc..42d78649cfd 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -1720,7 +1720,6 @@ - <<: *if-default-branch-schedule-nightly variables: <<: *qa-e2e-test-schedule-variables - KNAPSACK_GENERATE_REPORT: "true" QA_RUN_IN_PARALLEL: "false" COVERBAND_ENABLED: "false" @@ -1728,9 +1727,7 @@ rules: - !reference [".qa:rules:e2e-schedule-nightly", rules] - <<: *if-dot-com-gitlab-org-schedule - variables: - <<: *qa-e2e-test-schedule-variables - KNAPSACK_GENERATE_REPORT: "false" + variables: *qa-e2e-test-schedule-variables .qa:rules:code-suggestions-eval-base: rules: @@ -1843,7 +1840,6 @@ - <<: *if-dot-com-gitlab-org-schedule variables: <<: *qa-e2e-test-schedule-variables - KNAPSACK_GENERATE_REPORT: "true" COVERBAND_ENABLED: "true" QA_RUN_IN_PARALLEL: "false" @@ -1864,7 +1860,6 @@ - <<: *if-dot-com-gitlab-org-schedule variables: <<: *qa-e2e-test-schedule-variables - KNAPSACK_GENERATE_REPORT: "false" QA_RUN_IN_PARALLEL: "true" .qa:rules:test-on-omnibus-nightly: @@ -1876,7 +1871,6 @@ allow_failure: true variables: <<: *qa-e2e-test-schedule-variables - KNAPSACK_GENERATE_REPORT: "true" QA_RUN_IN_PARALLEL: "false" .qa:rules:fulfillment-e2e-quarantine-report: diff --git a/.gitlab/ci/test-on-cng/main.gitlab-ci.yml b/.gitlab/ci/test-on-cng/main.gitlab-ci.yml index 01f47baaa90..fc03a12ff5e 100644 --- a/.gitlab/ci/test-on-cng/main.gitlab-ci.yml +++ b/.gitlab/ci/test-on-cng/main.gitlab-ci.yml @@ -123,16 +123,10 @@ workflow: .cng-test-parallel: extends: .cng-test - needs: - - build-cng - - download-knapsack-report parallel: 10 .cng-test-no-parallel: extends: .cng-test - needs: - - build-cng - - download-knapsack-report # ========================================== # Pre stage @@ -149,18 +143,6 @@ build-cng: # use larger runner for complex rails build jobs HIGH_CAPACITY_RUNNER_TAG: e2e -download-knapsack-report: - extends: - - .download-knapsack-report - - .ruby-image - - .qa-cache - - .rules:download-knapsack - variables: - GIT_STRATEGY: clone - before_script: - - cd qa && bundle install - after_script: [] - # ========================================== # Test stage # ========================================== @@ -247,9 +229,7 @@ notify-slack: variables: QA_RSPEC_XML_FILE_PATTERN: $CI_PROJECT_DIR/qa/tmp/rspec-*.xml -upload-knapsack-report: +upload-test-runtime-data: extends: - - .upload-knapsack-report - - .rules:report:upload-knapsack-report - variables: - QA_KNAPSACK_REPORT_FILE_PATTERN: $CI_PROJECT_DIR/qa/tmp/knapsack/*/*.json + - .upload-test-runtime-data + - .rules:report:upload-test-runtime-data diff --git a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml index 678e26e4200..a88a45e3712 100644 --- a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml +++ b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml @@ -117,23 +117,6 @@ include: variables: WITH_LOAD_BALANCER: "true" -# ========================================== -# Pre stage -# ========================================== -# override .download-knapsack-report job to not depend on qa-image build -download-knapsack-report: - extends: - - .download-knapsack-report - - .ruby-image - - .bundler-variables - - .qa-cache - - .rules:download-knapsack - variables: - GIT_STRATEGY: clone - before_script: - - cd qa && bundle install - after_script: [] - # ========================================== # Test stage # ========================================== @@ -191,10 +174,10 @@ e2e-test-report: variables: ALLURE_REPORT_RESULTS_GLOB: "qa/tmp/allure-results" -upload-knapsack-report: +upload-test-runtime-data: extends: - - .upload-knapsack-report - - .rules:report:upload-knapsack-report + - .upload-test-runtime-data + - .rules:report:upload-test-runtime-data variables: QA_KNAPSACK_REPORT_FILE_PATTERN: $CI_PROJECT_DIR/qa/tmp/knapsack/*/*.json @@ -202,8 +185,6 @@ export-test-metrics: extends: - .export-test-metrics - .rules:report:process-results - variables: - QA_METRICS_REPORT_FILE_PATTERN: $CI_PROJECT_DIR/qa/tmp/test-metrics-*.json export-code-paths-mapping: extends: diff --git a/.gitlab/ci/test-on-omnibus-nightly/main.gitlab-ci.yml b/.gitlab/ci/test-on-omnibus-nightly/main.gitlab-ci.yml index 0e6ada229f4..823dc19e998 100644 --- a/.gitlab/ci/test-on-omnibus-nightly/main.gitlab-ci.yml +++ b/.gitlab/ci/test-on-omnibus-nightly/main.gitlab-ci.yml @@ -16,11 +16,6 @@ check-release-set: - .rules:prepare - .check-release-set -download-knapsack-report: - extends: - - .download-knapsack-report - - .rules:download-knapsack - # ========================================== # Test stage # ========================================== @@ -228,10 +223,10 @@ e2e-test-report: variables: ALLURE_RESULTS_GLOB: "gitlab-qa-run-*/**/allure-results" -upload-knapsack-report: +upload-test-runtime-data: extends: - - .upload-knapsack-report - - .rules:report:upload-knapsack-report + - .upload-test-runtime-data + - .rules:report:upload-test-runtime-data variables: QA_JSON_REPORT_FILE_PATTERN: $CI_PROJECT_DIR/gitlab-qa-run-*/gitlab-*-qa-*/rspec-*.json diff --git a/.gitlab/ci/test-on-omnibus/main.gitlab-ci.yml b/.gitlab/ci/test-on-omnibus/main.gitlab-ci.yml index 993a333585b..0f959fe3406 100644 --- a/.gitlab/ci/test-on-omnibus/main.gitlab-ci.yml +++ b/.gitlab/ci/test-on-omnibus/main.gitlab-ci.yml @@ -14,11 +14,6 @@ check-release-set: - .rules:prepare - .check-release-set -download-knapsack-report: - extends: - - .download-knapsack-report - - .rules:download-knapsack - # ========================================== # Test stage # ========================================== @@ -567,10 +562,10 @@ e2e-test-report: variables: ALLURE_RESULTS_GLOB: "gitlab-qa-run-*/**/allure-results" -upload-knapsack-report: +upload-test-runtime-data: extends: - - .upload-knapsack-report - - .rules:report:upload-knapsack-report + - .upload-test-runtime-data + - .rules:report:upload-test-runtime-data variables: QA_JSON_REPORT_FILE_PATTERN: $CI_PROJECT_DIR/gitlab-qa-run-*/gitlab-*-qa-*/rspec-*.json diff --git a/qa/knapsack/.gitignore b/qa/knapsack/.gitignore index d91d3e8efdd..aed304420f0 100644 --- a/qa/knapsack/.gitignore +++ b/qa/knapsack/.gitignore @@ -1,4 +1,5 @@ ** !.gitignore +!example_runtimes/ !master_report.json diff --git a/qa/knapsack/example_runtimes/master_report.json b/qa/knapsack/example_runtimes/master_report.json new file mode 100644 index 00000000000..32d568ed828 --- /dev/null +++ b/qa/knapsack/example_runtimes/master_report.json @@ -0,0 +1,519 @@ +{ + "./qa/specs/features/api/10_govern/group_access_token_spec.rb[1:1:1]": 14.713404855, + "./qa/specs/features/api/10_govern/group_access_token_spec.rb[1:1:2]": 10.813234403, + "./qa/specs/features/api/10_govern/project_access_token_spec.rb[1:1:1:1]": 16.361371962, + "./qa/specs/features/api/10_govern/project_access_token_spec.rb[1:1:1:2]": 11.64927845, + "./qa/specs/features/api/10_govern/project_access_token_spec.rb[1:1:2:1]": 24.932715366, + "./qa/specs/features/api/10_govern/project_access_token_spec.rb[1:1:2:2]": 16.586528133, + "./qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb[1:1:1]": 65.798967915, + "./qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb[1:1:2:1]": 34.496578353, + "./qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb[1:1:1]": 106.782294984, + "./qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb[1:1:1]": 47.30113258, + "./qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb[1:1:2:1]": 59.113172759, + "./qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb[1:1:1]": 16.017957473, + "./qa/specs/features/api/1_manage/import/import_github_repo_spec.rb[1:1:1:1]": 96.359488461, + "./qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb[1:1:1]": 8.207277389, + "./qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb[1:1:2]": 15.179088176, + "./qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb[1:1:3]": 10.273955864, + "./qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb[1:1:4]": 14.349470537, + "./qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb[1:1:5]": 11.86105406, + "./qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb[1:1:2:1]": 44.614925137, + "./qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb[1:1:2:1]": 105.664791491, + "./qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb[1:1:3:1]": 101.109934339, + "./qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb[1:1:1:1]": 106.840653734, + "./qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb[1:1:4:1]": 112.901770217, + "./qa/specs/features/api/1_manage/rate_limits_spec.rb[1:1:1]": 14.780353162, + "./qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb[1:1:1]": 14.115330151, + "./qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb[1:1:1]": 12.031070879, + "./qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb[1:1:2:1]": 17.711300159, + "./qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb[1:1:1]": 25.163705863, + "./qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb[1:1:1]": 38.296261223, + "./qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb[1:1:1]": 51.502542606, + "./qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb[1:1:1]": 34.186060564, + "./qa/specs/features/api/3_create/merge_request/view_merge_requests_spec.rb[1:1:1:1]": 3.129438589, + "./qa/specs/features/api/3_create/repository/add_list_delete_branches_spec.rb[1:1:1]": 12.150535337, + "./qa/specs/features/api/3_create/repository/commit_to_templated_project_spec.rb[1:1:1]": 10.03612278, + "./qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb[1:1:1]": 5.978714415, + "./qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb[1:1:2]": 7.136598757, + "./qa/specs/features/api/3_create/repository/files_spec.rb[1:1:1]": 5.981633866, + "./qa/specs/features/api/3_create/repository/files_spec.rb[1:1:2:1]": 3.120885962, + "./qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb[1:1:1]": 11.004690829, + "./qa/specs/features/api/3_create/repository/push_postreceive_idempotent_spec.rb[1:1:1]": 19.161823748, + "./qa/specs/features/api/3_create/repository/storage_size_spec.rb[1:1:1]": 17.839682854, + "./qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb[1:1:1:1:1]": 8.339938581, + "./qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb[1:1:1]": 109.676925609, + "./qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb[1:1:1]": 15.027245687, + "./qa/specs/features/api/4_verify/file_variable_spec.rb[1:1:1]": 24.893822659, + "./qa/specs/features/api/4_verify/file_variable_spec.rb[1:1:2]": 30.377401843, + "./qa/specs/features/api/4_verify/job_downloads_artifacts_spec.rb[1:1:1]": 32.785014205, + "./qa/specs/features/api/8_monitor/metrics_spec.rb[1:1:2:1]": 1.264041772, + "./qa/specs/features/api/8_monitor/metrics_spec.rb[1:2:1:1]": 2.494687767, + "./qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb[1:1:1:1]": 23.636951626, + "./qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb[1:1:1:2]": 18.231521984, + "./qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb[1:1:1:3]": 12.7376314, + "./qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb[1:1:2:1]": 40.246186802, + "./qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb[1:1:2:2]": 14.166838985, + "./qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb[1:1:2:3]": 8.750316747, + "./qa/specs/features/api/9_data_stores/users_spec.rb[1:1:1]": 2.092173158, + "./qa/specs/features/api/9_data_stores/users_spec.rb[1:1:2]": 1.251970228, + "./qa/specs/features/api/9_data_stores/users_spec.rb[1:1:3]": 2.857577604, + "./qa/specs/features/browser_ui/10_govern/group/group_access_token_spec.rb[1:1:1]": 23.421672832, + "./qa/specs/features/browser_ui/10_govern/login/2fa_recovery_spec.rb[1:1:1]": 54.122116982, + "./qa/specs/features/browser_ui/10_govern/login/2fa_ssh_recovery_spec.rb[1:1:1]": 67.320896454, + "./qa/specs/features/browser_ui/10_govern/login/log_in_spec.rb[1:1:1]": 9.04628157, + "./qa/specs/features/browser_ui/10_govern/login/log_in_with_2fa_spec.rb[1:1:1]": 97.672799066, + "./qa/specs/features/browser_ui/10_govern/login/log_into_gitlab_via_ldap_spec.rb[1:1:1]": 4.09558917, + "./qa/specs/features/browser_ui/10_govern/login/log_into_mattermost_via_gitlab_spec.rb[1:1:1]": 29.188868053, + "./qa/specs/features/browser_ui/10_govern/login/login_via_instance_wide_saml_sso_spec.rb[1:1:1]": 15.067933546, + "./qa/specs/features/browser_ui/10_govern/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb[1:1:1:1]": 217.376118297, + "./qa/specs/features/browser_ui/10_govern/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb[1:2:1:1]": 274.23253092, + "./qa/specs/features/browser_ui/10_govern/login/oauth_login_with_github_spec.rb[1:1:1]": 40.640735123, + "./qa/specs/features/browser_ui/10_govern/login/register_spec.rb[1:1:1]": 3.193338346, + "./qa/specs/features/browser_ui/10_govern/login/register_spec.rb[1:2:1:1:1]": 33.654682073, + "./qa/specs/features/browser_ui/10_govern/login/register_spec.rb[1:2:1:2:1]": 132.040624243, + "./qa/specs/features/browser_ui/10_govern/login/register_spec.rb[1:2:2:1]": 57.503025978, + "./qa/specs/features/browser_ui/10_govern/project/project_access_token_spec.rb[1:1:1]": 19.061642652, + "./qa/specs/features/browser_ui/10_govern/user/impersonation_token_spec.rb[1:1:1]": 46.671475308, + "./qa/specs/features/browser_ui/10_govern/user/user_access_termination_spec.rb[1:1:1:1]": 18.331480826, + "./qa/specs/features/browser_ui/10_govern/user/user_access_termination_spec.rb[1:1:1:2]": 13.689933537, + "./qa/specs/features/browser_ui/10_govern/user/user_access_termination_spec.rb[1:1:1:3]": 9.550578148, + "./qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb[1:1:1:1]": 45.492231551, + "./qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb[1:1:1:1]": 12.658014304, + "./qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb[1:1:1]": 97.540627722, + "./qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb[1:1:1]": 16.378738435, + "./qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb[1:1:2]": 35.847998051, + "./qa/specs/features/browser_ui/1_manage/integrations/jira/jira_issue_import_spec.rb[1:1:1]": 33.197254798, + "./qa/specs/features/browser_ui/1_manage/integrations/pipeline_status_emails_spec.rb[1:1:1:1]": 32.708440896, + "./qa/specs/features/browser_ui/1_manage/integrations/pipeline_status_emails_spec.rb[1:1:2:1]": 25.015918078, + "./qa/specs/features/browser_ui/1_manage/migration/gitlab_migration_group_spec.rb[1:1:1]": 59.224819797, + "./qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb[1:1:1]": 25.775704513, + "./qa/specs/features/browser_ui/2_plan/design_management/archive_design_content_spec.rb[1:1:1]": 42.360591604, + "./qa/specs/features/browser_ui/2_plan/design_management/modify_design_content_spec.rb[1:1:1]": 43.180362003, + "./qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb[1:1:1]": 23.925169824, + "./qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb[1:1:1]": 27.437009764, + "./qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb[1:1:1]": 24.974694487, + "./qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb[1:1:1]": 26.352954978, + "./qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb[1:1:1]": 33.477491597, + "./qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb[1:1:2]": 41.512952184, + "./qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb[1:1:3:1]": 23.986608386, + "./qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb[1:1:1]": 33.165990536, + "./qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb[1:1:1]": 23.149692151, + "./qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb[1:1:1]": 24.916591686, + "./qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb[1:1:1]": 29.503550718, + "./qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb[1:1:1]": 29.744815155, + "./qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb[1:1:1]": 28.227754714, + "./qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb[1:1:1]": 16.741200012, + "./qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb[1:1:1:1:1]": 29.921968576, + "./qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb[1:1:1:2:1]": 52.354124671, + "./qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb[1:1:2:1:1]": 27.60775988, + "./qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb[1:1:2:2:1]": 28.296516285, + "./qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb[1:1:1]": 42.652467682, + "./qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb[1:1:1]": 34.356239911, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb[1:1:1]": 27.790738507, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb[1:1:2]": 24.696771764, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb[1:1:3]": 17.915569148, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb[1:1:4]": 20.524668258, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb[1:1:5]": 17.913761707, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_manipulation_spec.rb[1:1:1]": 19.337732858, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_manipulation_spec.rb[1:1:2]": 30.145658732, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_manipulation_spec.rb[1:1:3]": 14.46963965, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_directory_management_spec.rb[1:1:1]": 36.606963586, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_file_upload_spec.rb[1:1:1]": 41.584471828, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_list_spec.rb[1:1:1:1]": 31.362425646, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_list_spec.rb[1:1:2:1]": 44.298816688, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_page_deletion_spec.rb[1:1:1]": 17.302267872, + "./qa/specs/features/browser_ui/2_plan/project_wiki/project_based_page_deletion_spec.rb[1:1:2]": 38.589185108, + "./qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb[1:1:1]": 27.123193157, + "./qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb[1:1:1]": 69.433542409, + "./qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb[1:1:1]": 41.449943686, + "./qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb[1:1:1]": 34.588627085, + "./qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb[1:1:2]": 40.445568921, + "./qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb[1:1:1]": 37.753963871, + "./qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb[1:1:1]": 50.67135095, + "./qa/specs/features/browser_ui/3_create/merge_request/merge_request_set_to_auto_merge_spec.rb[1:1:1]": 68.398547863, + "./qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb[1:1:1]": 87.55787667, + "./qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb[1:1:1]": 35.401264196, + "./qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb[1:1:1]": 47.670894804, + "./qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb[1:1:1]": 38.618615374, + "./qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb[1:1:1]": 86.983090038, + "./qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb[1:1:1]": 68.076427905, + "./qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb[1:1:1]": 62.414924496, + "./qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb[1:1:2]": 44.726732396, + "./qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb[1:1:1]": 23.703962853, + "./qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb[1:1:2]": 30.33630376, + "./qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb[1:1:3]": 28.735242865, + "./qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb[1:1:4]": 25.500195247, + "./qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb[1:1:1]": 56.987059132, + "./qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb[1:1:1:1]": 23.008183451, + "./qa/specs/features/browser_ui/3_create/repository/clone_spec.rb[1:1:1]": 20.808135609, + "./qa/specs/features/browser_ui/3_create/repository/clone_spec.rb[1:1:2]": 19.865578139, + "./qa/specs/features/browser_ui/3_create/repository/file/create_file_via_web_spec.rb[1:1:1]": 30.362560845, + "./qa/specs/features/browser_ui/3_create/repository/file/delete_file_via_web_spec.rb[1:1:1]": 20.544643616, + "./qa/specs/features/browser_ui/3_create/repository/file/edit_file_via_web_spec.rb[1:1:1]": 26.883056585, + "./qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb[1:1:1:1]": 39.378518784, + "./qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb[1:1:1:1:1]": 9.886337607, + "./qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb[1:1:2:1:1]": 17.229689023, + "./qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb[1:1:1:1:1]": 23.186800699, + "./qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb[1:1:1:2:1]": 24.838281415, + "./qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb[1:1:2:1:1]": 48.508499557, + "./qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb[1:1:2:2:1]": 57.538374361, + "./qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb[1:1:1]": 18.462034091, + "./qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb[1:1:1]": 18.728451459, + "./qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb[1:1:1]": 18.055567469, + "./qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb[1:1:1]": 68.823799705, + "./qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb[1:1:1]": 57.526612588, + "./qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb[1:1:1]": 9.658169918, + "./qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb[1:1:2]": 40.452497268, + "./qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb[1:1:1]": 20.995187167, + "./qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb[1:1:2]": 8.770011308, + "./qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb[1:1:1]": 26.493878188, + "./qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb[1:1:2]": 12.464461322, + "./qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb[1:1:1:1]": 17.959466922, + "./qa/specs/features/browser_ui/3_create/repository/ssh_key_support_create_spec.rb[1:1:1]": 25.313018011, + "./qa/specs/features/browser_ui/3_create/repository/ssh_key_support_delete_spec.rb[1:1:1]": 19.527926848, + "./qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb[1:1:1]": 26.419766711, + "./qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb[1:1:2]": 28.455659178, + "./qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb[1:1:1:1]": 17.516981606, + "./qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb[1:1:2:1]": 23.959955351, + "./qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb[1:1:1:1]": 21.309021641, + "./qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb[1:1:2:1]": 24.943957755, + "./qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb[1:1:1]": 35.321749631, + "./qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb[1:1:2]": 52.655646063, + "./qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb[1:1:1]": 28.479452124, + "./qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb[1:1:2]": 34.059098659, + "./qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb[1:1:1:1]": 26.660832392, + "./qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb[1:1:2:1]": 22.504234843, + "./qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb[1:1:1]": 17.086094748, + "./qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb[1:1:1]": 17.306014647, + "./qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb[1:1:1]": 31.899260214, + "./qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb[1:1:1]": 41.194861958, + "./qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb[1:1:1:1]": 20.614324149, + "./qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb[1:1:2:1]": 20.747627542, + "./qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb[1:1:1:1]": 13.215484011, + "./qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb[1:1:2:1]": 12.245216697, + "./qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb[1:1:1:1]": 14.380698682, + "./qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb[1:1:2:1]": 13.947474387, + "./qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb[1:1:3:1]": 26.793534139, + "./qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb[1:1:4:1]": 16.425303478, + "./qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb[1:1:1]": 20.605555296, + "./qa/specs/features/browser_ui/3_create/web_ide/add_first_file_in_web_ide_spec.rb[1:1:1:1]": 22.278672625, + "./qa/specs/features/browser_ui/3_create/web_ide/add_first_file_in_web_ide_spec.rb[1:1:2:1]": 42.346223212, + "./qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb[1:1:1:1]": 39.884591693, + "./qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb[1:1:2:1]": 48.596460402, + "./qa/specs/features/browser_ui/3_create/web_ide/closing_web_ide_with_unsaved_changes_spec.rb[1:1:1]": 27.478323346, + "./qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb[1:1:1:1]": 29.345815022, + "./qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb[1:1:2:1:1]": 32.223756441, + "./qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb[1:1:3:1:1]": 90.225091543, + "./qa/specs/features/browser_ui/4_verify/ci_components_catalog/ci_catalog_sorting_spec.rb[1:1:1:2:1:1]": 68.135794079, + "./qa/specs/features/browser_ui/4_verify/ci_components_catalog/ci_catalog_sorting_spec.rb[1:1:1:2:2:1]": 66.903912435, + "./qa/specs/features/browser_ui/4_verify/ci_components_catalog/run_component_in_project_pipeline_spec.rb[1:1:1]": 103.308908112, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/expose_job_artifacts_in_mr_spec.rb[1:1:1:1]": 58.818003801, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/job_artifacts_access_keyword_spec.rb[1:1:1:1:1]": 38.050645062, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/job_artifacts_access_keyword_spec.rb[1:1:1:1:2]": 55.655203296, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/job_artifacts_access_keyword_spec.rb[1:1:2:1:1]": 37.003733819, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/job_artifacts_access_keyword_spec.rb[1:1:2:1:2]": 41.932304837, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/job_artifacts_access_keyword_spec.rb[1:1:3:1:1]": 37.624762312, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/job_artifacts_access_keyword_spec.rb[1:1:3:1:2]": 46.006470195, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb[1:1:1:1]": 90.623986274, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb[1:1:2:1]": 123.700945058, + "./qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb[1:1:3:1]": 121.478857466, + "./qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb[1:1:1:1]": 73.020677681, + "./qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb[1:1:1]": 46.765697734, + "./qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb[1:1:2]": 87.818013973, + "./qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb[1:1:1]": 23.843259783, + "./qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb[1:1:2]": 24.630095627, + "./qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb[1:1:1]": 64.515973779, + "./qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb[1:1:1]": 72.892487951, + "./qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb[1:1:1]": 35.998469183, + "./qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb[1:1:1]": 75.083970478, + "./qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb[1:1:1]": 74.58979811, + "./qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb[1:1:1]": 38.925082636, + "./qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb[1:1:2]": 37.517386819, + "./qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb[1:1:1]": 65.530555099, + "./qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb[1:1:1:1:1]": 67.167650613, + "./qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb[1:1:1:2:1]": 41.582991536, + "./qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb[1:1:1:3:1]": 41.727826296, + "./qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb[1:1:1:4:1]": 40.474235913, + "./qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb[1:1:1]": 67.031798694, + "./qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb[1:1:1]": 47.844069681, + "./qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb[1:1:1]": 72.620299281, + "./qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb[1:1:1]": 47.154006293, + "./qa/specs/features/browser_ui/4_verify/runner/fleet_visibility/group_runner_counts_spec.rb[1:1:1]": 15.867132199, + "./qa/specs/features/browser_ui/4_verify/runner/fleet_visibility/group_runner_status_counts_spec.rb[1:1:1]": 19.450196908, + "./qa/specs/features/browser_ui/4_verify/runner/register_group_runner_spec.rb[1:1:1]": 19.517849238, + "./qa/specs/features/browser_ui/4_verify/runner/register_project_runner_spec.rb[1:1:1]": 21.766574955, + "./qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb[1:1:1]": 68.168898462, + "./qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb[1:1:1:1:1]": 104.674381869, + "./qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb[1:1:1:2:1]": 106.205657516, + "./qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb[1:1:1:3:1]": 122.159152936, + "./qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb[1:1:1:1]": 60.294983876, + "./qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb[1:1:2:1]": 49.663351327, + "./qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb[1:1:3:1]": 52.898527795, + "./qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb[1:1:1]": 66.750124115, + "./qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb[1:1:1]": 56.01172143, + "./qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb[1:1:1]": 88.6840445, + "./qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb[1:1:1]": 66.54183963, + "./qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb[1:1:1:1]": 70.48876192, + "./qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb[1:1:2:1]": 70.838330519, + "./qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb[1:1:3:1]": 82.997239554, + "./qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb[1:1:1:1:1]": 100.049388671, + "./qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb[1:1:1:2:1]": 88.496756335, + "./qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb[1:1:1:3:1]": 102.687063774, + "./qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb[1:1:2:1:1]": 87.857193018, + "./qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb[1:1:2:2:1]": 105.216450041, + "./qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb[1:1:1:1]": 67.325168037, + "./qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb[1:1:2:1]": 66.995801425, + "./qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb[1:1:3:1]": 73.310255708, + "./qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb[1:1:1:1]": 94.580442539, + "./qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb[1:1:2:1]": 70.583133781, + "./qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb[1:1:3:1]": 66.349513987, + "./qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb[1:1:1:1]": 121.00609818, + "./qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb[1:1:2:1]": 80.91521897, + "./qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb[1:1:3:1]": 99.46816676, + "./qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb[1:1:1:1]": 92.08907372, + "./qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb[1:1:2:1]": 107.484558735, + "./qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb[1:1:3:1]": 108.950913944, + "./qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb[1:1:1:1]": 74.239436889, + "./qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb[1:1:1]": 37.360177838, + "./qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb[1:1:1]": 84.557848841, + "./qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb[1:1:2]": 48.050121062, + "./qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb[1:1:3]": 37.085549172, + "./qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb[1:1:1]": 14.855064736, + "./qa/specs/features/browser_ui/8_monitor/alert_management/alert_settings_create_new_alerts_spec.rb[1:1:1:1:1]": 21.144400109, + "./qa/specs/features/browser_ui/8_monitor/alert_management/alert_settings_create_new_alerts_spec.rb[1:1:2:1:1]": 20.640758168, + "./qa/specs/features/browser_ui/8_monitor/alert_management/automatically_creates_incident_for_alert_spec.rb[1:1:1:1:1]": 38.164911507, + "./qa/specs/features/browser_ui/8_monitor/alert_management/automatically_creates_incident_for_alert_spec.rb[1:1:2:1:1]": 31.342476548, + "./qa/specs/features/browser_ui/8_monitor/alert_management/create_alert_using_authorization_key_spec.rb[1:1:1:1:1]": 20.897215593, + "./qa/specs/features/browser_ui/8_monitor/alert_management/create_alert_using_authorization_key_spec.rb[1:1:2:1:1]": 20.399533998, + "./qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb[1:1:1:1:1:1]": 14.326192192, + "./qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb[1:1:1:2:1:1]": 15.64051355, + "./qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb[1:1:2:1:1:1]": 18.509001348, + "./qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb[1:1:2:2:1:1]": 19.815658872, + "./qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb[1:1:1:1:1]": 31.323053475, + "./qa/specs/features/browser_ui/9_data_stores/group/create_group_with_mattermost_team_spec.rb[1:1:1]": 8.374653947, + "./qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb[1:1:1]": 24.96963416, + "./qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb[1:1:2:1:1]": 31.336182763, + "./qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb[1:1:2:2:1]": 29.925609353, + "./qa/specs/features/browser_ui/9_data_stores/group/transfer_project_spec.rb[1:1:1]": 58.191406721, + "./qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb[1:1:1]": 26.762435011, + "./qa/specs/features/browser_ui/9_data_stores/project/create_project_badge_spec.rb[1:1:1]": 30.77470513, + "./qa/specs/features/browser_ui/9_data_stores/project/create_project_spec.rb[1:1:1:1:1]": 18.216962595, + "./qa/specs/features/browser_ui/9_data_stores/project/create_project_spec.rb[1:1:2:1:1]": 24.521337096, + "./qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb[1:1:1:1:1]": 7.62868923, + "./qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb[1:1:2:1:1]": 7.758908224, + "./qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb[1:1:1:1:1]": 39.180093599, + "./qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb[1:1:2:1:1]": 54.068162464, + "./qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb[1:1:1:1:1]": 21.019983545, + "./qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb[1:1:1:2:1]": 18.028456812, + "./qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb[1:1:2:1:1]": 27.798885, + "./qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb[1:1:2:2:1]": 25.642232576, + "./qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb[1:1:1:1]": 26.348265168, + "./qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb[1:1:1]": 41.948951206, + "./qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb[1:1:1:1]": 43.653508901, + "./qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb[1:1:1:1]": 22.047253101, + "./qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb[1:1:2:1]": 19.086520125, + "./qa/specs/features/ee/api/10_govern/compliance_pipeline_spec.rb[1:1:1:1]": 48.827966551, + "./qa/specs/features/ee/api/10_govern/instance_audit_event_streaming_spec.rb[1:1:1:1]": 20.806882368, + "./qa/specs/features/ee/api/10_govern/instance_audit_event_streaming_spec.rb[1:1:4:1]": 25.742396984, + "./qa/specs/features/ee/api/10_govern/user/minimal_access_user_spec.rb[1:1:1]": 43.689436743, + "./qa/specs/features/ee/api/10_govern/user/minimal_access_user_spec.rb[1:1:2]": 13.263437043, + "./qa/specs/features/ee/api/10_govern/user/minimal_access_user_spec.rb[1:1:3]": 7.739653878, + "./qa/specs/features/ee/api/1_manage/import/import_github_repo_spec.rb[1:1:1:1]": 21.236946751, + "./qa/specs/features/ee/api/1_manage/integrations/group_webhook_events_spec.rb[1:1:1]": 13.450421698, + "./qa/specs/features/ee/api/1_manage/migration/gitlab_migration_group_spec.rb[1:1:1:1]": 90.850962442, + "./qa/specs/features/ee/api/2_plan/epics_milestone_dates_spec.rb[1:1:1]": 13.460885249, + "./qa/specs/features/ee/api/2_plan/epics_milestone_dates_spec.rb[1:1:2]": 18.746768893, + "./qa/specs/features/ee/api/2_plan/epics_milestone_dates_spec.rb[1:1:3]": 14.734399026, + "./qa/specs/features/ee/api/2_plan/epics_milestone_dates_spec.rb[1:1:4]": 14.194365863, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:1:2:1:1:1:1:1]": 2.010194321, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:1:2:1:1:1:2:1:1]": 0.720048996, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:2:2:1:1:1:1:1]": 2.287621951, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:2:2:1:1:2:1:1]": 0.137797471, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:2:2:1:2:1:1]": 0.071476501, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:2:2:2:1:1]": 3.705205952, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:2:3:2:1:1:1:1:1]": 0.805047482, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:3:2:1:1:1:1:1]": 1.1682312, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:3:2:1:1:1:2:1]": 1.493816479, + "./qa/specs/features/ee/api/3_create/code_suggestions_spec.rb[1:1:3:2:1:1:1:3:1:1]": 1.975320452, + "./qa/specs/features/ee/api/9_data_stores/elasticsearch/index_tests/user_index/user_index_spec.rb[1:1:1]": 41.829291408, + "./qa/specs/features/ee/browser_ui/10_govern/change_vulnerability_status_spec.rb[1:1:1]": 34.47848225, + "./qa/specs/features/ee/browser_ui/10_govern/change_vulnerability_status_spec.rb[1:1:2]": 25.188226154, + "./qa/specs/features/ee/browser_ui/10_govern/change_vulnerability_status_spec.rb[1:1:3]": 26.507270661, + "./qa/specs/features/ee/browser_ui/10_govern/create_merge_request_with_secure_spec.rb[1:1:1]": 95.524715762, + "./qa/specs/features/ee/browser_ui/10_govern/dismissed_vulnerabilities_in_security_widget_spec.rb[1:1:1]": 124.314681467, + "./qa/specs/features/ee/browser_ui/10_govern/export_vulnerability_report_spec.rb[1:1:1]": 34.202741376, + "./qa/specs/features/ee/browser_ui/10_govern/fix_vulnerability_workflow_spec.rb[1:1:1]": 110.101399894, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_audit_event_streaming_spec.rb[1:1:1:1]": 29.085345251, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_audit_event_streaming_spec.rb[1:1:2:1:1]": 13.989479385, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_audit_event_streaming_spec.rb[1:1:2:2:1]": 18.786304581, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_audit_event_streaming_spec.rb[1:1:2:3:1]": 16.5663951, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_audit_logs_1_spec.rb[1:1:1:1:1]": 46.706704438, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_audit_logs_1_spec.rb[1:1:2:1:1]": 23.04254686, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_audit_logs_1_spec.rb[1:1:3:1:1]": 21.282050473, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_audit_logs_1_spec.rb[1:1:4:1:1]": 55.834556833, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_audit_logs_1_spec.rb[1:1:5:1:1]": 42.619538914, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_ldap_sync_spec.rb[1:1:1:1:1]": 33.67750862, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_ldap_sync_spec.rb[1:1:1:1:2]": 13.434871502, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_ldap_sync_spec.rb[1:1:1:1:3]": 21.872616819, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_ldap_sync_spec.rb[1:1:2:1:1]": 31.968525362, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_ldap_sync_spec.rb[1:1:2:1:2]": 8.898495308, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_ldap_sync_spec.rb[1:1:2:1:3]": 12.025326277, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_saml_enforced_sso_git_access_spec.rb[1:1:1]": 19.057893773, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_saml_enforced_sso_new_account_spec.rb[1:1:1:1:1]": 97.982092667, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_saml_enforced_sso_new_account_spec.rb[1:1:2:1:1]": 105.325114142, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_saml_non_enforced_sso_spec.rb[1:1:1:1]": 22.958325516, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_saml_non_enforced_sso_spec.rb[1:1:2]": 26.975854165, + "./qa/specs/features/ee/browser_ui/10_govern/group/group_saml_non_enforced_sso_spec.rb[1:1:3]": 18.571166615, + "./qa/specs/features/ee/browser_ui/10_govern/group/restrict_by_ip_address_spec.rb[1:1:1:1:1]": 21.88879038, + "./qa/specs/features/ee/browser_ui/10_govern/group/restrict_by_ip_address_spec.rb[1:1:1:2:1]": 14.023240274, + "./qa/specs/features/ee/browser_ui/10_govern/group/restrict_by_ip_address_spec.rb[1:1:1:3:1]": 47.85594747, + "./qa/specs/features/ee/browser_ui/10_govern/group/restrict_by_ip_address_spec.rb[1:1:2:1:1]": 24.194090224, + "./qa/specs/features/ee/browser_ui/10_govern/group/restrict_by_ip_address_spec.rb[1:1:2:2:1]": 13.357841085, + "./qa/specs/features/ee/browser_ui/10_govern/group/restrict_by_ip_address_spec.rb[1:1:2:3:1]": 22.050524365, + "./qa/specs/features/ee/browser_ui/10_govern/group/saml_sso_merge_request_approve_spec.rb[1:1:1]": 44.69992828, + "./qa/specs/features/ee/browser_ui/10_govern/group_pipeline_execution_policy_spec.rb[1:1:1]": 138.627503887, + "./qa/specs/features/ee/browser_ui/10_govern/group_pipeline_execution_policy_spec.rb[1:1:2]": 158.308799562, + "./qa/specs/features/ee/browser_ui/10_govern/instance/instance_audit_logs_spec.rb[1:1:1:1:1]": 19.113944899, + "./qa/specs/features/ee/browser_ui/10_govern/instance/instance_audit_logs_spec.rb[1:1:2:1:1]": 20.629124584, + "./qa/specs/features/ee/browser_ui/10_govern/instance/instance_audit_logs_spec.rb[1:1:3:1:1]": 35.645914793, + "./qa/specs/features/ee/browser_ui/10_govern/instance/instance_audit_logs_spec.rb[1:1:4:1:1]": 25.300651663, + "./qa/specs/features/ee/browser_ui/10_govern/instance/instance_audit_logs_spec.rb[1:1:5:1:1]": 25.873668446, + "./qa/specs/features/ee/browser_ui/10_govern/instance/instance_audit_logs_spec.rb[1:1:6:1:1]": 30.657595666, + "./qa/specs/features/ee/browser_ui/10_govern/project/project_audit_logs_spec.rb[1:1:1:1:1]": 36.182156287, + "./qa/specs/features/ee/browser_ui/10_govern/project/project_audit_logs_spec.rb[1:1:2:1:1]": 32.970371337, + "./qa/specs/features/ee/browser_ui/10_govern/project/project_audit_logs_spec.rb[1:1:3:1:1]": 36.072658851, + "./qa/specs/features/ee/browser_ui/10_govern/project/project_audit_logs_spec.rb[1:1:4:1:1]": 29.839557571, + "./qa/specs/features/ee/browser_ui/10_govern/project/project_audit_logs_spec.rb[1:1:5:1:1]": 57.204553687, + "./qa/specs/features/ee/browser_ui/10_govern/project/project_audit_logs_spec.rb[1:1:6:1:1]": 37.474700977, + "./qa/specs/features/ee/browser_ui/10_govern/project_security_dashboard_spec.rb[1:1:1]": 23.899263418, + "./qa/specs/features/ee/browser_ui/10_govern/project_security_dashboard_spec.rb[1:1:2]": 40.16433061, + "./qa/specs/features/ee/browser_ui/10_govern/scan_execution_policy_vulnerabilities_spec.rb[1:1:1]": 47.201465932, + "./qa/specs/features/ee/browser_ui/10_govern/scan_execution_policy_vulnerabilities_spec.rb[1:1:2]": 55.652733803, + "./qa/specs/features/ee/browser_ui/10_govern/scan_result_policy_vulnerabilities_spec.rb[1:1:1]": 86.063902587, + "./qa/specs/features/ee/browser_ui/10_govern/scan_result_policy_vulnerabilities_spec.rb[1:1:2]": 71.297732959, + "./qa/specs/features/ee/browser_ui/10_govern/security_policies_spec.rb[1:1:1]": 19.732180406, + "./qa/specs/features/ee/browser_ui/10_govern/security_policies_spec.rb[1:1:2]": 31.771598283, + "./qa/specs/features/ee/browser_ui/10_govern/security_policies_spec.rb[1:1:3]": 40.450837552, + "./qa/specs/features/ee/browser_ui/10_govern/security_reports_spec.rb[1:1:1]": 17.704807582, + "./qa/specs/features/ee/browser_ui/10_govern/security_reports_spec.rb[1:1:2]": 80.046792311, + "./qa/specs/features/ee/browser_ui/10_govern/security_reports_spec.rb[1:1:3]": 112.958934219, + "./qa/specs/features/ee/browser_ui/10_govern/security_reports_spec.rb[1:1:4]": 59.082292938, + "./qa/specs/features/ee/browser_ui/10_govern/security_reports_spec.rb[1:1:6:1]": 41.641429575, + "./qa/specs/features/ee/browser_ui/10_govern/user/minimal_access_user_spec.rb[1:1:1]": 18.850208981, + "./qa/specs/features/ee/browser_ui/10_govern/vulnerabilities_jira_integration_spec.rb[1:1:1]": 37.916871174, + "./qa/specs/features/ee/browser_ui/10_govern/vulnerability_management_spec.rb[1:1:1]": 102.285302941, + "./qa/specs/features/ee/browser_ui/10_govern/vulnerability_management_spec.rb[1:1:2]": 100.125829576, + "./qa/specs/features/ee/browser_ui/10_govern/vulnerability_management_spec.rb[1:1:3]": 103.062945042, + "./qa/specs/features/ee/browser_ui/10_govern/vulnerability_management_spec.rb[1:1:4]": 136.083906053, + "./qa/specs/features/ee/browser_ui/10_govern/vulnerability_security_training_spec.rb[1:1:1]": 72.695126592, + "./qa/specs/features/ee/browser_ui/10_govern/vulnerability_security_training_spec.rb[1:1:2]": 50.959548264, + "./qa/specs/features/ee/browser_ui/11_fulfillment/license/cloud_activation_spec.rb[1:1:1]": 48.686755024, + "./qa/specs/features/ee/browser_ui/11_fulfillment/license/cloud_activation_spec.rb[1:2:1]": 13.828334511, + "./qa/specs/features/ee/browser_ui/11_fulfillment/license/license_spec.rb[1:1:1]": 6.480427115, + "./qa/specs/features/ee/browser_ui/11_fulfillment/utilization/user_registration_billing_spec.rb[1:1:1:1:1]": 24.806789493, + "./qa/specs/features/ee/browser_ui/13_secure/cvs_dependency_scanning_spec.rb[1:1:1:1]": 57.701196734, + "./qa/specs/features/ee/browser_ui/13_secure/enable_advanced_sast_spec.rb[1:1:1]": 133.574508037, + "./qa/specs/features/ee/browser_ui/13_secure/enable_scanning_from_configuration_spec.rb[1:1:1:1]": 71.169211842, + "./qa/specs/features/ee/browser_ui/13_secure/enable_scanning_from_configuration_spec.rb[1:1:2:1]": 62.444158484, + "./qa/specs/features/ee/browser_ui/13_secure/secret_push_protection_spec.rb[1:1:1]": 45.551788342, + "./qa/specs/features/ee/browser_ui/16_ai_powered/duo_chat/duo_chat_spec.rb[1:1:1:2:1:1]": 8.925541184, + "./qa/specs/features/ee/browser_ui/1_manage/integrations/jira_issues_list_spec.rb[1:1:1]": 22.863018399, + "./qa/specs/features/ee/browser_ui/1_manage/integrations/jira_issues_list_spec.rb[1:1:2]": 15.358410078, + "./qa/specs/features/ee/browser_ui/1_manage/integrations/jira_issues_list_spec.rb[1:1:3]": 16.582402888, + "./qa/specs/features/ee/browser_ui/2_plan/analytics/contribution_analytics_spec.rb[1:1:1]": 50.722166185, + "./qa/specs/features/ee/browser_ui/2_plan/analytics/mr_analytics_spec.rb[1:1:1]": 45.111097187, + "./qa/specs/features/ee/browser_ui/2_plan/analytics/value_stream_analytics_spec.rb[1:1:1:1:1:1]": 33.076396494, + "./qa/specs/features/ee/browser_ui/2_plan/analytics/value_stream_analytics_spec.rb[1:1:1:2:1:1]": 25.673734202, + "./qa/specs/features/ee/browser_ui/2_plan/burndown_chart/burndown_chart_spec.rb[1:1:1]": 22.304099747, + "./qa/specs/features/ee/browser_ui/2_plan/custom_email/custom_email_spec.rb[1:1:1]": 14.588473201, + "./qa/specs/features/ee/browser_ui/2_plan/epic/epics_management_spec.rb[1:1:1]": 24.185034574, + "./qa/specs/features/ee/browser_ui/2_plan/epic/epics_management_spec.rb[1:1:2]": 32.76576089, + "./qa/specs/features/ee/browser_ui/2_plan/epic/epics_management_spec.rb[1:1:3:1:1]": 21.556007789, + "./qa/specs/features/ee/browser_ui/2_plan/epic/epics_management_spec.rb[1:1:3:1:2]": 16.06317314, + "./qa/specs/features/ee/browser_ui/2_plan/epic/epics_management_spec.rb[1:1:3:1:3]": 60.978649268, + "./qa/specs/features/ee/browser_ui/2_plan/epic/epics_management_spec.rb[1:1:3:2]": 31.170224843, + "./qa/specs/features/ee/browser_ui/2_plan/epic/promote_issue_to_epic_spec.rb[1:1:1]": 63.717399474, + "./qa/specs/features/ee/browser_ui/2_plan/epic/roadmap_spec.rb[1:1:1]": 17.14852358, + "./qa/specs/features/ee/browser_ui/2_plan/group_wiki/create_group_wiki_page_spec.rb[1:1:1:1]": 33.383526122, + "./qa/specs/features/ee/browser_ui/2_plan/group_wiki/create_group_wiki_page_spec.rb[1:1:2:1]": 19.692587129, + "./qa/specs/features/ee/browser_ui/2_plan/group_wiki/delete_group_wiki_page_spec.rb[1:1:1]": 15.117689405, + "./qa/specs/features/ee/browser_ui/2_plan/group_wiki/file_upload_group_wiki_page_spec.rb[1:1:1]": 46.479666714, + "./qa/specs/features/ee/browser_ui/2_plan/insights/default_insights_spec.rb[1:1:1:1]": 16.447731355, + "./qa/specs/features/ee/browser_ui/2_plan/insights/default_insights_spec.rb[1:2:1:1]": 16.380741982, + "./qa/specs/features/ee/browser_ui/2_plan/issue/default_issue_template_spec.rb[1:1:1]": 29.391700793, + "./qa/specs/features/ee/browser_ui/2_plan/issue_boards/configurable_issue_board_spec.rb[1:1:1]": 21.345064004, + "./qa/specs/features/ee/browser_ui/2_plan/issue_boards/configure_issue_board_by_label_spec.rb[1:1:1]": 22.451578122, + "./qa/specs/features/ee/browser_ui/2_plan/issue_boards/create_group_issue_board_spec.rb[1:1:1]": 24.240709516, + "./qa/specs/features/ee/browser_ui/2_plan/issue_boards/group_issue_boards_spec.rb[1:1:1]": 34.885189392, + "./qa/specs/features/ee/browser_ui/2_plan/issue_boards/project_issue_boards_spec.rb[1:1:1:1]": 25.697411573, + "./qa/specs/features/ee/browser_ui/2_plan/issue_boards/project_issue_boards_spec.rb[1:1:2:1]": 18.710533074, + "./qa/specs/features/ee/browser_ui/2_plan/issue_boards/project_issue_boards_spec.rb[1:1:3:1]": 20.280722188, + "./qa/specs/features/ee/browser_ui/2_plan/issue_boards/read_only_board_configuration_spec.rb[1:1:1]": 27.459274641, + "./qa/specs/features/ee/browser_ui/2_plan/issue_boards/sum_of_issues_weights_spec.rb[1:1:1]": 21.773349409, + "./qa/specs/features/ee/browser_ui/2_plan/issues_analytics/issues_analytics_spec.rb[1:1:1:1]": 21.993448261, + "./qa/specs/features/ee/browser_ui/2_plan/issues_analytics/issues_analytics_spec.rb[1:2:1:1]": 18.066200087, + "./qa/specs/features/ee/browser_ui/2_plan/issues_weight/issue_weight_visualization_spec.rb[1:1:1]": 32.072177078, + "./qa/specs/features/ee/browser_ui/2_plan/iterations/assign_group_iteration_spec.rb[1:1:1]": 41.416180428, + "./qa/specs/features/ee/browser_ui/2_plan/iterations/create_group_iteration_spec.rb[1:1:1:1]": 21.988262129, + "./qa/specs/features/ee/browser_ui/2_plan/iterations/create_group_iteration_spec.rb[1:1:2:1]": 22.03765391, + "./qa/specs/features/ee/browser_ui/2_plan/multiple_assignees_for_issues/four_assignees_spec.rb[1:1:1]": 24.530601356, + "./qa/specs/features/ee/browser_ui/2_plan/multiple_assignees_for_issues/more_than_four_assignees_spec.rb[1:1:1]": 26.782436737, + "./qa/specs/features/ee/browser_ui/2_plan/multiple_assignees_for_issues/more_than_four_assignees_spec.rb[1:1:2]": 30.611265913, + "./qa/specs/features/ee/browser_ui/2_plan/scoped_labels/editing_scoped_labels_spec.rb[1:1:1]": 31.1657315, + "./qa/specs/features/ee/browser_ui/3_create/merge_request/add_batch_comments_in_merge_request_spec.rb[1:1:1]": 45.161097792, + "./qa/specs/features/ee/browser_ui/3_create/merge_request/add_batch_comments_in_merge_request_spec.rb[1:1:2]": 44.195918067, + "./qa/specs/features/ee/browser_ui/3_create/merge_request/approval_rules_spec.rb[1:1:1]": 112.579942379, + "./qa/specs/features/ee/browser_ui/3_create/merge_request/default_merge_request_template_spec.rb[1:1:1]": 48.780807866, + "./qa/specs/features/ee/browser_ui/3_create/repository/assign_code_owners_spec.rb[1:1:1]": 56.327410591, + "./qa/specs/features/ee/browser_ui/3_create/repository/code_owners_spec.rb[1:1:1]": 26.89394752, + "./qa/specs/features/ee/browser_ui/3_create/repository/code_owners_with_protected_branch_and_squashed_commits_spec.rb[1:1:1]": 48.508767657, + "./qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb[1:1:1]": 51.733634393, + "./qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb[1:1:2]": 46.882782422, + "./qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb[1:1:3]": 37.416401791, + "./qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb[1:1:4]": 70.815260067, + "./qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb[1:1:5]": 46.545500694, + "./qa/specs/features/ee/browser_ui/3_create/repository/group_file_template_spec.rb[1:1:1]": 45.079318008, + "./qa/specs/features/ee/browser_ui/3_create/repository/group_file_template_spec.rb[1:1:2]": 63.931814844, + "./qa/specs/features/ee/browser_ui/3_create/repository/group_file_template_spec.rb[1:1:3]": 55.922242111, + "./qa/specs/features/ee/browser_ui/3_create/repository/group_file_template_spec.rb[1:1:4]": 44.410678454, + "./qa/specs/features/ee/browser_ui/3_create/repository/merge_with_code_owner_in_root_group_spec.rb[1:1:1:1:1:1]": 56.587284147, + "./qa/specs/features/ee/browser_ui/3_create/repository/merge_with_code_owner_in_root_group_spec.rb[1:1:1:2:1:1]": 66.250017128, + "./qa/specs/features/ee/browser_ui/3_create/repository/merge_with_code_owner_in_subgroup_spec.rb[1:1:1:1:1:1]": 59.661658029, + "./qa/specs/features/ee/browser_ui/3_create/repository/merge_with_code_owner_in_subgroup_spec.rb[1:1:1:2:1:1]": 70.112791067, + "./qa/specs/features/ee/browser_ui/3_create/repository/merge_with_code_owner_in_subgroup_spec.rb[1:1:1:3:1:1]": 76.371267231, + "./qa/specs/features/ee/browser_ui/3_create/repository/project_templates_spec.rb[1:1:1:1]": 54.077424216, + "./qa/specs/features/ee/browser_ui/3_create/repository/project_templates_spec.rb[1:1:3:1]": 63.468706289, + "./qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_http_spec.rb[1:1:1]": 61.834331757, + "./qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_ssh_with_key_spec.rb[1:1:1]": 55.590719014, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:1:1]": 25.123046212, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:1:2]": 46.567187959, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:1:3]": 61.770777728, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:1:4]": 34.062812974, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:1:5]": 50.658988036, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:1:6]": 33.604681598, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:1:7]": 39.971842711, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:1:8]": 37.921106517, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:1:9]": 41.913765651, + "./qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb[1:1:2:1]": 42.61338044, + "./qa/specs/features/ee/browser_ui/3_create/repository/restrict_push_protected_branch_spec.rb[1:1:1:1:1]": 40.896866667, + "./qa/specs/features/ee/browser_ui/3_create/repository/restrict_push_protected_branch_spec.rb[1:1:1:2:1]": 53.022816674, + "./qa/specs/features/ee/browser_ui/3_create/repository/restrict_push_protected_branch_spec.rb[1:1:2:1:1]": 48.863102004, + "./qa/specs/features/ee/browser_ui/3_create/repository/restrict_push_protected_branch_spec.rb[1:1:2:2:1]": 74.747196603, + "./qa/specs/features/ee/browser_ui/3_create/repository/restrict_push_protected_branch_spec.rb[1:1:3:1:1]": 45.194393284, + "./qa/specs/features/ee/browser_ui/3_create/web_ide/code_suggestions_in_web_ide_spec.rb[1:1:2:1:1:1:1:1]": 32.863888884, + "./qa/specs/features/ee/browser_ui/3_create/web_ide/code_suggestions_in_web_ide_spec.rb[1:1:2:1:1:2:1:1]": 29.25680473, + "./qa/specs/features/ee/browser_ui/3_create/web_ide/code_suggestions_in_web_ide_spec.rb[1:1:2:1:2:1:1]": 28.307268778, + "./qa/specs/features/ee/browser_ui/3_create/web_ide/code_suggestions_in_web_ide_spec.rb[1:1:2:2:1:1]": 30.033982648, + "./qa/specs/features/ee/browser_ui/4_verify/multi-project_pipelines_spec.rb[1:1:1]": 50.254416568, + "./qa/specs/features/ee/browser_ui/4_verify/parent_child_pipelines_dependent_relationship_spec.rb[1:1:1]": 47.736867981, + "./qa/specs/features/ee/browser_ui/4_verify/parent_child_pipelines_dependent_relationship_spec.rb[1:1:2]": 46.698199006, + "./qa/specs/features/ee/browser_ui/4_verify/pipeline_for_merged_result_spec.rb[1:1:1]": 99.409168731, + "./qa/specs/features/ee/browser_ui/4_verify/pipeline_subscription_with_group_owned_project_spec.rb[1:1:1:1]": 73.324830291, + "./qa/specs/features/ee/browser_ui/5_package/dependency_proxy_sso_spec.rb[1:1:1]": 68.979615316, + "./qa/specs/features/ee/browser_ui/8_monitor/incident_management/incident_quick_action_spec.rb[1:1:1]": 26.366336919, + "./qa/specs/features/ee/browser_ui/9_data_stores/elasticsearch/elasticsearch_reindexing_spec.rb[1:1:1]": 39.147461216, + "./qa/specs/features/ee/browser_ui/9_data_stores/elasticsearch/elasticsearch_reindexing_spec.rb[1:1:2]": 171.977816416, + "./qa/specs/features/ee/browser_ui/9_data_stores/group/prevent_forking_outside_group_spec.rb[1:1:1:1]": 34.7902967, + "./qa/specs/features/ee/browser_ui/9_data_stores/group/prevent_forking_outside_group_spec.rb[1:1:2:1]": 64.241058055, + "./qa/specs/features/ee/browser_ui/9_data_stores/group/share_group_with_group_spec.rb[1:1:1]": 59.352813395 +} diff --git a/qa/qa/specs/knapsack_runner.rb b/qa/qa/specs/knapsack_runner.rb index b8914ca3846..f865c1b69a1 100644 --- a/qa/qa/specs/knapsack_runner.rb +++ b/qa/qa/specs/knapsack_runner.rb @@ -3,26 +3,30 @@ module QA module Specs class KnapsackRunner - def self.run(args, parallel: false) - QA::Support::KnapsackReport.configure! + class << self + def run(args, example_data, parallel: false) + knapsack_reporter = Support::KnapsackReport.new + knapsack_reporter.configure! + knapsack_reporter.create_local_report!(example_data) - allocator = Knapsack::AllocatorBuilder.new(Knapsack::Adapters::RSpecAdapter).allocator + allocator = Knapsack::AllocatorBuilder.new(Knapsack::Adapters::RSpecAdapter).allocator - Knapsack.logger.info '==== Knapsack specs to execute =====' - Knapsack.logger.info 'Report specs:' - Knapsack.logger.info allocator.report_node_tests - Knapsack.logger.info 'Leftover specs:' - Knapsack.logger.info allocator.leftover_node_tests + Knapsack.logger.info '==== Knapsack specs to execute =====' + Knapsack.logger.info 'Report specs:' + Knapsack.logger.info allocator.report_node_tests + Knapsack.logger.info 'Leftover specs:' + Knapsack.logger.info allocator.leftover_node_tests - if parallel - rspec_args = args.reject { |arg| arg == "--" || arg.start_with?("qa/specs/features") } - run_args = [*rspec_args, '--', *allocator.node_tests] - return ParallelRunner.run(run_args) + if parallel + rspec_args = args.reject { |arg| arg == "--" || arg.start_with?("qa/specs/features") } + run_args = [*rspec_args, '--', *allocator.node_tests] + return ParallelRunner.run(run_args) + end + + status = RSpec::Core::Runner.run([*args, '--', *allocator.node_tests]) + yield status if block_given? + status end - - status = RSpec::Core::Runner.run([*args, '--', *allocator.node_tests]) - yield status if block_given? - status end end end diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb index 525d1150bff..b7f60e257a9 100644 --- a/qa/qa/specs/runner.rb +++ b/qa/qa/specs/runner.rb @@ -26,25 +26,29 @@ module QA end def rspec_tags + return @rspec_tags if @rspec_tags + tags_for_rspec = [] - return tags_for_rspec if Runtime::Scenario.attributes[:test_metadata_only] || Runtime::Env.rspec_retried? + if Runtime::Scenario.attributes[:test_metadata_only] || Runtime::Env.rspec_retried? + return @rspec_tags = tags_for_rspec + end if tags.any? - tags.each { |tag| tags_for_rspec.push(['--tag', tag.to_s]) } + tags.each { |tag| tags_for_rspec.push(tag.to_s) } else - tags_for_rspec.push(DEFAULT_SKIPPED_TAGS.map { |tag| %W[--tag ~#{tag}] }) unless (%w[-t --tag] & options).any? + tags_for_rspec.push(*DEFAULT_SKIPPED_TAGS.map { |tag| "~#{tag}" }) unless (%w[-t --tag] & options).any? end - tags_for_rspec.push(%w[--tag ~geo]) unless QA::Runtime::Env.geo_environment? - tags_for_rspec.push(%w[--tag ~skip_signup_disabled]) if QA::Runtime::Env.signup_disabled? - tags_for_rspec.push(%w[--tag ~skip_live_env]) if QA::Specs::Helpers::ContextSelector.dot_com? + tags_for_rspec.push("~geo") unless QA::Runtime::Env.geo_environment? + tags_for_rspec.push("~skip_signup_disabled") if QA::Runtime::Env.signup_disabled? + tags_for_rspec.push("~skip_live_env") if QA::Specs::Helpers::ContextSelector.dot_com? QA::Runtime::Env.supported_features.each_key do |key| - tags_for_rspec.push(%W[--tag ~requires_#{key}]) unless QA::Runtime::Env.can_test? key + tags_for_rspec.push("~requires_#{key}") unless QA::Runtime::Env.can_test? key end - tags_for_rspec + @rspec_tags = tags_for_rspec end def perform @@ -63,7 +67,7 @@ module QA def build_initial_args [].tap do |args| args.push('--tty') if tty - args.push(rspec_tags) + args.push(rspec_tags.flat_map { |tag| ["--tag", tag] }) args.push(options) end end @@ -74,7 +78,9 @@ module QA elsif Runtime::Scenario.attributes[:test_metadata_only] test_metadata_only(args) elsif Runtime::Env.knapsack? - KnapsackRunner.run(args.flatten, parallel: run_in_parallel?) { |status| abort if status.nonzero? } + KnapsackRunner.run(args.flatten, example_data, parallel: run_in_parallel?) do |status| + abort if status.nonzero? + end elsif run_in_parallel? ParallelRunner.run(args.flatten) elsif Runtime::Scenario.attributes[:loop] @@ -152,6 +158,15 @@ module QA def metadata_run? Runtime::Scenario.attributes[:count_examples_only] || Runtime::Scenario.attributes[:test_metadata_only] end + + # Example ids with their execution status + # + # @return [Hash] + def example_data + Support::ExampleData.fetch(rspec_tags).each_with_object({}) do |example, ids| + ids[example[:id]] = example[:status] + end + end end end end diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb index 2413901e042..bcc6b1799b1 100644 --- a/qa/qa/specs/spec_helper.rb +++ b/qa/qa/specs/spec_helper.rb @@ -99,10 +99,6 @@ RSpec.configure do |config| QA::Tools::TestResourceDataProcessor.write_to_file(suite.reporter.failed_examples.any?) end - config.append_after(:suite) do - QA::Support::KnapsackReport.move_regenerated_report if QA::Runtime::Env.knapsack? - end - config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end diff --git a/qa/qa/support/knapsack_report.rb b/qa/qa/support/knapsack_report.rb index 01642f443e1..565554024f0 100644 --- a/qa/qa/support/knapsack_report.rb +++ b/qa/qa/support/knapsack_report.rb @@ -7,23 +7,19 @@ module QA class KnapsackReport PROJECT = "gitlab-qa-resources" BUCKET = "knapsack-reports" - FALLBACK_REPORT = "knapsack/master_report.json" + BASE_PATH = "knapsack" + FALLBACK_REPORT = "#{BASE_PATH}/master_report.json".freeze PATTERN_VAR_NAME = "KNAPSACK_TEST_FILE_PATTERN" DEFAULT_TEST_PATTERN = "qa/specs/features/**/*_spec.rb" EXAMPLE_RUNTIMES_PATH = "example_runtimes" + RUNTIME_REPORT = "#{BASE_PATH}/#{EXAMPLE_RUNTIMES_PATH}/master_report.json".freeze class << self - delegate :configure!, - :move_regenerated_report, - :download_report, - :upload_report, - :upload_example_runtimes, - :merged_report, - to: :new + delegate :configure!, :upload_example_runtimes, to: :new end - def initialize(report_name = nil) - @report_name = report_name + def initialize(logger = QA::Runtime::Logger.logger) + @logger = logger end # Configure knapsack report @@ -37,82 +33,40 @@ module QA setup_logger! setup_environment! - download_report end - # Download knapsack report from gcs bucket + # Create local knapsack report based on example runtime data and configure it to be used by knapsack # + # Passing list of examples allows to craft a more precise report that will not have runtime data + # for examples that will actually be skipped due to dynamic metadata which can cause uneven test distribution + # + # @param example_data [Hash] example id list to be included in the report # @return [void] - def download_report - logger.info("Downloading latest knapsack report for '#{report_name}' to '#{report_path}'") - return logger.info("Report already exists, skipping!") if File.exist?(report_path) + def create_local_report!(example_data) + logger.info("Creating knapsack report from runtime data") + runtime_report = JSON.load_file(RUNTIME_REPORT) + report = example_data.each_with_object(Hash.new { |h, k| h[k] = 0 }) do |(id, status), report| + next report[example_file_path(id)] += runtime_report[id] || 0.01 if status == "passed" - file = client.get_object(BUCKET, report_file) - File.write(report_path, file[:body]) + # if example was not executed, add small runtime to the report + # this is needed for knapsack to not consider all specs that got skipped dynamically as leftover specs + # https://github.com/KnapsackPro/knapsack?tab=readme-ov-file#what-does-leftover-specs-mean + report[example_file_path(id)] += 0.01 + end + normalized_report = report + .transform_values { |v| v.round(3) } + .sort + .to_h + + report_path = File.join(BASE_PATH, report_name) + File.write(report_path, normalized_report.to_json) + ENV["KNAPSACK_REPORT_PATH"] = report_path rescue StandardError => e ENV["KNAPSACK_REPORT_PATH"] = FALLBACK_REPORT - logger.warn("Failed to fetch latest knapsack report: #{e}") + logger.warn("Failed to create knapsack report: #{e}") logger.warn("Falling back to '#{FALLBACK_REPORT}'") end - # Create a copy of the report that contains the selective tests and has '-selective' suffix - # - # @param [String] qa_tests - # @return [void] - def create_for_selective(qa_tests) - timed_specs = JSON.parse(File.read(report_path)) - - qa_tests_array = qa_tests.split(' ') - filtered_timed_specs = timed_specs.select { |k, _| qa_tests_array.any? { |qa_test| k.include? qa_test } } - File.write(selective_path, filtered_timed_specs.to_json) - end - - # Rename and move new regenerated report to a separate folder used to indicate report name - # - # @return [void] - def move_regenerated_report - return unless ENV["KNAPSACK_GENERATE_REPORT"] == "true" - - tmp_path = "tmp/knapsack/#{report_name}" - FileUtils.mkdir_p(tmp_path) - - # Use path from knapsack config in case of fallback to master_report.json - knapsack_report_path = Knapsack.report.report_path - logger.debug("Moving regenerated #{knapsack_report_path} to save as artifact") - FileUtils.cp(knapsack_report_path, "#{tmp_path}/#{ENV['CI_NODE_INDEX']}.json") - end - - # Merge and upload knapsack report to gcs bucket - # - # Fetches all files defined in glob and uses parent folder as report name - # - # @param [String] glob - # @return [void] - def upload_report(glob) - reports = Pathname.glob(glob).each_with_object(Hash.new { |hsh, key| hsh[key] = [] }) do |report, hash| - next unless report.extname == ".json" - - hash[report.parent.basename.to_s].push(report) - end - return logger.error("Glob '#{glob}' did not contain any valid report files!") if reports.empty? - - reports.each do |name, jsons| - file = "#{name}.json" - - report = jsons - .map { |json| JSON.parse(File.read(json)) } - .reduce({}, :merge) - .sort_by { |_k, v| v } # sort report by execution time - .to_h - next logger.warn("Knapsack generated empty report for '#{name}', skipping upload!") if report.empty? - - logger.info("Uploading latest knapsack report '#{file}'") - client.put_object(BUCKET, file, JSON.pretty_generate(report)) - rescue StandardError => e - logger.error("Failed to upload knapsack report for '#{name}'. Error: #{e}") - end - end - # Create and upload custom report based on data from JsonFormatter report files # # @param glob [String] @@ -131,16 +85,14 @@ module QA client.put_object(BUCKET, file, JSON.pretty_generate(report)) end - # Merged example runtime data from all report files + # Merged example runtime data report from all report files # # @return [Hash] - def merged_runtime_data - return @merged_runtime_data if @merged_runtime_data - + def create_merged_runtime_report logger.info("Fetching all example runtime data from GCS '#{BUCKET}' bucket") items = client.list_objects(BUCKET, prefix: EXAMPLE_RUNTIMES_PATH).items logger.info("Fetched example runtime files #{items.map(&:name)}, creating merged knapsack report") - @merged_runtime_data = client.list_objects(BUCKET, prefix: EXAMPLE_RUNTIMES_PATH).items + client.list_objects(BUCKET, prefix: EXAMPLE_RUNTIMES_PATH).items .each_with_object({}) do |report, runtimes| json = JSON.parse(client.get_object(BUCKET, report.name)[:body]) @@ -149,19 +101,20 @@ module QA end end - # Create merged knapsack report from example runtimes reports + # Create knapsack report from example runtime data # + # @param runtime_report [Hash] # @return [Hash] - def merged_report - merged_runtime_data.each_with_object(Hash.new { |hsh, key| hsh[key] = 0 }) do |(id, runtime), spec_runtimes| - file_path = id.match(/(\S+)\[\S+\]/)[1].gsub("./", "") - - spec_runtimes[file_path] += runtime + def create_knapsack_report(runtime_report = create_merged_runtime_report) + runtime_report.each_with_object(Hash.new { |hsh, key| hsh[key] = 0 }) do |(id, runtime), spec_runtimes| + spec_runtimes[example_file_path(id)] += runtime end end private + attr_reader :logger + delegate :run_type, to: QA::Runtime::Env # Setup knapsack logger @@ -175,16 +128,11 @@ module QA # # @return [void] def setup_environment! - ENV["KNAPSACK_TEST_DIR"] = "qa/specs" - ENV["KNAPSACK_REPORT_PATH"] = report_path - ENV[PATTERN_VAR_NAME] = ENV[PATTERN_VAR_NAME].presence || DEFAULT_TEST_PATTERN - end + ENV["KNAPSACK_TEST_DIR"] = "qa/specs/features" + ENV["KNAPSACK_REPORT_PATH"] = FALLBACK_REPORT + return unless ENV[PATTERN_VAR_NAME].blank? - # Logger instance - # - # @return [ActiveSupport::Logger] - def logger - QA::Runtime::Logger.logger + ENV[PATTERN_VAR_NAME] = DEFAULT_TEST_PATTERN end # GCS client @@ -201,30 +149,6 @@ module QA @report_base_path ||= "knapsack" end - # Knapsack report path - # - # @return [String] - def report_path - @report_path ||= "#{report_base_path}/#{report_file}" - end - - # Knapsack report name - # - # @return [String] - def report_file - @report_file ||= "#{report_name}.json" - end - - # Report name - # - # Infer report name from ci job name - # Remove characters incompatible with gcs bucket naming from job names like ee:instance-parallel - # - # @return [String] - def report_name - @report_name ||= ENV["QA_KNAPSACK_REPORT_NAME"] || ENV["CI_JOB_NAME"].split(" ").first.tr(":", "-") - end - # GCS credentials json # # @return [Hash] @@ -237,17 +161,6 @@ module QA { google_json_key_string: json_key } end - # Add '-selective-parallel' suffix to report name - # - # @return [String] - def selective_path - extension = File.extname(report_path) - directory = File.dirname(report_path) - file_name = File.basename(report_path, extension) - - File.join(directory, "#{file_name}-selective-parallel#{extension}") - end - # Get example runtimes from JsonFormatter report files # # @param reports [Array] @@ -264,6 +177,21 @@ module QA end end end + + # Knapsack report file name + # + # @return [String] + def report_name + "#{ENV['CI_JOB_NAME_SLUG'] || 'local'}-knapsack-report.json" + end + + # Extract file path from example id + # + # @param example_id [String] + # @return [String] + def example_file_path(example_id) + example_id.match(/(\S+)\[\S+\]/)[1].gsub("./", "") + end end end end diff --git a/qa/qa/tools/knapsack_report_updater.rb b/qa/qa/tools/knapsack_report_updater.rb index ca7742b6ffd..c38e2fc2885 100644 --- a/qa/qa/tools/knapsack_report_updater.rb +++ b/qa/qa/tools/knapsack_report_updater.rb @@ -24,6 +24,13 @@ module QA private + # Knapsack report generator + # + # @return [QA::Support::KnapsackReport] + def knapsack_reporter + @knapsack_reporter = Support::KnapsackReport.new(logger) + end + # Gitlab access token # # @return [String] @@ -69,14 +76,21 @@ module QA # @return [void] def create_commit logger.info("Creating master_report.json update commit") + runtime_report = knapsack_reporter.create_merged_runtime_report.sort.to_h + api_request(:post, "repository/commits", { branch: UPDATE_BRANCH_NAME, commit_message: "Update master_report.json for E2E tests", actions: [ { action: "update", - file_path: "qa/knapsack/master_report.json", - content: JSON.pretty_generate(Support::KnapsackReport.merged_report.sort.to_h) + file_path: File.join("qa", Support::KnapsackReport::RUNTIME_REPORT), + content: "#{JSON.pretty_generate(runtime_report)}\n" + }, + { + action: "update", + file_path: File.join("qa", Support::KnapsackReport::FALLBACK_REPORT), + content: "#{JSON.pretty_generate(knapsack_reporter.create_knapsack_report(runtime_report).sort.to_h)}\n" } ] }) diff --git a/qa/spec/support/knapsack_report_spec.rb b/qa/spec/support/knapsack_report_spec.rb deleted file mode 100644 index bbe560fad66..00000000000 --- a/qa/spec/support/knapsack_report_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe QA::Support::KnapsackReport do - subject(:knapsack_report) { described_class.new('instance') } - - describe '#create_for_selective' do - let(:qa_tests) do - <<~CMD - qa/specs/features/api/3_create - qa/specs/features/browser_ui/3_create/ - qa/specs/features/ee/api/3_create/ - qa/specs/features/ee/browser_ui/3_create/ - CMD - end - - let(:fixtures_path) { 'spec/fixtures/knapsack_report' } - let(:expected_output) { JSON.parse(File.read(File.join(fixtures_path, 'instance-selective-parallel.json'))) } - - before do - allow(File).to receive(:read).and_call_original - allow(File).to receive(:read) - .with('knapsack/instance.json') - .and_return(File.read(File.join(fixtures_path, 'instance.json'))) - end - - it 'creates a filtered file based on qa_tests' do - expect(File).to receive(:write).with('knapsack/instance-selective-parallel.json', expected_output.to_json) - - knapsack_report.create_for_selective(qa_tests) - end - end -end diff --git a/qa/spec/tools/knapsack_report_updater_spec.rb b/qa/spec/tools/knapsack_report_updater_spec.rb index b5695400084..7fa78fe22ed 100644 --- a/qa/spec/tools/knapsack_report_updater_spec.rb +++ b/qa/spec/tools/knapsack_report_updater_spec.rb @@ -5,9 +5,18 @@ RSpec.describe QA::Tools::KnapsackReportUpdater do let(:http_response) { instance_double("HTTPResponse", code: 200, body: {}.to_json) } let(:logger) { instance_double("Logger", info: nil, warn: nil) } + let(:merged_runtimes) { { "spec_file[1:1]": 0.0 } } let(:merged_report) { { spec_file: 0.0 } } let(:branch) { "qa-knapsack-master-report-update" } + let(:knapsack_reporter) do + instance_double( + QA::Support::KnapsackReport, + create_knapsack_report: merged_report, + create_merged_runtime_report: merged_runtimes + ) + end + def request_args(verb, path, payload) { method: verb, @@ -20,22 +29,28 @@ RSpec.describe QA::Tools::KnapsackReportUpdater do before do allow(RestClient::Request).to receive(:execute).and_return(http_response) - allow(QA::Support::KnapsackReport).to receive(:merged_report).and_return(merged_report) allow(Gitlab::QA::TestLogger).to receive(:logger).and_return(logger) + allow(QA::Support::KnapsackReport).to receive(:new).with(logger).and_return(knapsack_reporter) stub_env("CI_API_V4_URL", "https://gitlab.com/api/v4") stub_env("GITLAB_ACCESS_TOKEN", "token") end def expect_mr_created + expect(knapsack_reporter).to have_received(:create_knapsack_report).with(merged_runtimes) expect(RestClient::Request).to have_received(:execute).with(request_args(:post, "repository/commits", { branch: branch, commit_message: "Update master_report.json for E2E tests", actions: [ + { + action: "update", + file_path: "qa/knapsack/example_runtimes/master_report.json", + content: "#{JSON.pretty_generate(merged_runtimes)}\n" + }, { action: "update", file_path: "qa/knapsack/master_report.json", - content: JSON.pretty_generate(merged_report) + content: "#{JSON.pretty_generate(merged_report)}\n" } ] })) diff --git a/qa/tasks/knapsack.rake b/qa/tasks/knapsack.rake index 72d5e64e7b6..48e3fb4c919 100644 --- a/qa/tasks/knapsack.rake +++ b/qa/tasks/knapsack.rake @@ -15,56 +15,6 @@ namespace :knapsack do exit QA::Specs::KnapsackRunner.run(rspec_args) end - desc "Download latest knapsack reports for parallel jobs" - task :download, [:stage_name] do |_, args| - test_stage_name = args[:stage_name] - knapsack_reports = ENV["QA_KNAPSACK_REPORTS"]&.split(",") - ci_token = ENV["QA_GITLAB_CI_TOKEN"] - QA::Support::KnapsackReport.configure! - - reports = if knapsack_reports - knapsack_reports - else - unless ci_token - QA::Runtime::Logger.error("Missing QA_GITLAB_CI_TOKEN for automatically detecting parallel jobs") - next - end - - QA::Support::ParallelPipelineJobs - .fetch(stage_name: test_stage_name, access_token: ci_token) - .map { |job| job.tr(":", "-") } - end - - reports.each do |report_name| - QA::Support::KnapsackReport.new(report_name).download_report - rescue StandardError => e - QA::Runtime::Logger.error("Failed to download knapsack report '#{report_name}', error: #{e}") - end - end - - desc "Create knapsack reports from existing reports for selective jobs" - task :create_reports_for_selective do - qa_tests = ENV["QA_TESTS"] - if qa_tests.blank? - next QA::Runtime::Logger.info("QA_TESTS not set, skipping report creation for selective execution") - end - - reports = Dir.glob("knapsack/*").map { |file| file.match(%r{.*/(.*)?\.json})[1] } - reports.each do |report_name| - next unless report_name.include?('-selective-parallel') - - QA::Support::KnapsackReport.new(report_name).create_for_selective(qa_tests) - rescue StandardError => e - QA::Runtime::Logger.error("Failed to create report '#{report_name}', error: #{e}") - end - end - - desc "Merge and upload knapsack report" - task :upload, [:glob] do |_task, args| - QA::Support::KnapsackReport.configure! - QA::Support::KnapsackReport.upload_report(args[:glob]) - end - desc "Create and upload custom report for all tests in pipeline" task :upload_example_runtimes, [:glob] do |_task, args| QA::Support::KnapsackReport.upload_example_runtimes(args[:glob])