From 4c38990cea7447452c28c058068c81038482805f Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Tue, 16 Dec 2025 20:08:23 +0100 Subject: [PATCH] CI: Shared example to check CI jobs to download repo via artifacts Contributes to https://gitlab.com/gitlab-org/quality/analytics/team/-/work_items/134 --- .../pipeline_labels_spec.rb | 1 + .../shared_context_and_examples.rb | 308 ++++++++++++++++++ 2 files changed, 309 insertions(+) diff --git a/spec/dot_gitlab_ci/ci_configuration_validation/pipeline_labels_spec.rb b/spec/dot_gitlab_ci/ci_configuration_validation/pipeline_labels_spec.rb index 3a8eb73ee473ed..0e6c796ed11788 100644 --- a/spec/dot_gitlab_ci/ci_configuration_validation/pipeline_labels_spec.rb +++ b/spec/dot_gitlab_ci/ci_configuration_validation/pipeline_labels_spec.rb @@ -29,6 +29,7 @@ let(:expected_job_name) { 'rspec-all frontend_fixture 1/7' } it_behaves_like 'merge request pipeline' + it_behaves_like 'download repo from artifacts' end context 'when MR labeled with `pipeline:expedite pipeline::expedited` is changing app/models/user.rb' do diff --git a/spec/dot_gitlab_ci/ci_configuration_validation/shared_context_and_examples.rb b/spec/dot_gitlab_ci/ci_configuration_validation/shared_context_and_examples.rb index b9477e68c0d274..842b6e3ad98ecb 100644 --- a/spec/dot_gitlab_ci/ci_configuration_validation/shared_context_and_examples.rb +++ b/spec/dot_gitlab_ci/ci_configuration_validation/shared_context_and_examples.rb @@ -19,6 +19,7 @@ end let(:jobs) { pipeline.stages.flat_map { |s| s.statuses.map(&:name) } } + let(:merged_yaml) { YAML.safe_load(pipeline.config_metadata.try(:[], :merged_yaml)) } let_it_be(:group) { create(:group, path: 'gitlab-org') } let_it_be(:gitlab_org_gitlab_project) { create(:project, :empty_repo, group: group, path: 'gitlab') } @@ -137,6 +138,313 @@ end end +RSpec::Matchers.define :download_repo_from_artifacts do + match do |config| + @has_needs = (config["needs"] || []).flatten.any? do |need| + need == "clone-gitlab-repo" || (need.is_a?(Hash) && need["job"] == "clone-gitlab-repo") + end + + @has_git_strategy = config.dig("variables", "GIT_STRATEGY") == '${CI_FETCH_REPO_GIT_STRATEGY}' + + @has_needs && @has_git_strategy + end + + failure_message do |_config| + missing_parts = [] + missing_parts << "`needs: clone-gitlab-repo`" unless @has_needs + missing_parts << "`variables: GIT_STRATEGY=${CI_FETCH_REPO_GIT_STRATEGY}`" unless @has_git_strategy + + "Job is missing #{missing_parts.join(' and ')}" + end + + failure_message_when_negated do |_config| + "Job already has required configuration and should be removed from todo_list" + end +end + +RSpec.shared_examples "download repo from artifacts" do + # See https://docs.gitlab.com/ci/yaml/#global-keywords + let(:global_keywords) { %w[default include stages workflow variables] } + + # These jobs are excluded from downloading repo from artifacts + let(:legit_excludes) do + [ + "clone-gitlab-repo" # This job clones the repo and exposes it as artifact + ] + end + + # This list of jobs _should_ download repo from artifacts + # See https://gitlab.com/gitlab-org/quality/analytics/team/-/work_items/134 + let(:todo_list) do + [ + "audit-event-types-verify", + "backup gems", + "bandit-sast", + "benchmark-markdown", + "brakeman-sast", + "build-gdk-image", + "build-qa-image", + "build-qa-image as-if-foss", + "build-vite-prod", + "build-vite-prod-vue3", + "bundle-size-review", + "cache:assets-hash", + "cache:e2e-ruby-gems", + "cache:e2e-ruby-gems-e2e-runners", + "cache:fe-islands-hash", + "cache:fe-islands-node-modules", + "cache:node-modules", + "cache:node-modules-production", + "cache:orchestrator-gems", + "cache:ruby-gems", + "cache:ruby-gems-ubi", + "cache:workhorse-hash", + "check-deprecated-files", + "ci-job-token-policies-verify", + "cleanup-frontend-fixtures", + "compile-fe-islands", + "compile-production-assets", + "compile-production-assets as-if-foss", + "compile-test-assets", + "compile-test-assets vue3", + "custom-roles-verify", + "dast-variables-check-docs", + "db:backup_and_restore", + "db:backup_and_restore single-db", + "db:backup_and_restore single-db-ci-connection", + "db:backup_and_restore single-db-sec-connection", + "db:check-migrations", + "db:check-migrations-single-db", + "db:check-schema", + "db:docs-up-to-date", + "db:gitlabcom-database-testing", + "db:invalidate-old-pipeline-results", + "db:migrate:multi-version-upgrade", + "db:migrate:multi-version-upgrade-pg18", + "db:migrate-non-superuser", + "db:migrate:reset single-db", + "db:migrate:reset single-db-ci-connection", + "db:migrate:reset single-db-sec-connection", + "db:post_deployment_migrations_validator", + "db:post_deployment_migrations_validator-single-db", + "db:post_deployment_migrations_validator-single-db-ci-connection", + "db:post_deployment_migrations_validator-single-db-sec-connection", + "db:rollback", + "db:rollback geo", + "db:rollback single-db", + "db:rollback single-db-ci-connection", + "db:rollback single-db-sec-connection", + "db:setup-ee pg16", + "db:setup pg16", + "delete-as-if-foss-branch", + "delete-as-if-foss-environment", + "dependency-scanning", + "detect-previous-failed-tests", + "detect-tests", + "docs code_quality", + "docs hugo_build", + "docs-i18n-lint japanese-vale", + "docs-i18n-lint links", + "docs-i18n-lint markdown", + "docs-i18n-lint paths", + "docs-lint deprecations-and-removals", + "docs-lint links", + "docs-lint markdown", + "docs-lint mermaid", + "docs-lint redirects", + "dont-interrupt-me", + "e2e:fulfillment-quarantine-report", + "e2e:observability-backend", + "e2e:observability-backend-main-branch", + "e2e:perf-on-cng", + "e2e:test-on-cng", + "e2e:test-on-gdk", + "e2e:test-on-omnibus-ce", + "e2e:test-on-omnibus-ee", + "e2e-test-pipeline-generate", + "e2e-test-pipeline-generate as-if-foss", + "ensure-application-settings-have-definition-file", + "eslint", + "eslint-changed-files", + "eslint-docs", + "eslint-sast", + "export-predictive-test-metrics", + "fail-pipeline-early", + "feature-flags-usage", + "flawfinder-sast", + "gdk-update", + "gems activerecord-gitlab", + "gems bundler-checksum", + "gems csv_builder", + "gems devise-pbkdf2-encryptable", + "gems diff_match_patch", + "gems gitlab-active-context", + "gems gitlab-backup-cli", + "gems gitlab-database-load_balancing", + "gems gitlab-database-lock_retries", + "gems gitlab-duo-workflow-service-client", + "gems gitlab-grape-openapi", + "gems gitlab-housekeeper", + "gems gitlab-http", + "gems gitlab-rspec", + "gems gitlab-rspec_flaky", + "gems gitlab-safe_request_store", + "gems gitlab-schema-validation", + "gems gitlab-topology-service-client", + "gems gitlab-utils", + "gems ipynbdiff", + "gems mail-smtp_pool", + "gems microsoft_graph_mailer", + "gems omniauth_crowd", + "gems omniauth-gitlab", + "gems omniauth-salesforce", + "gems sidekiq", + "gems sidekiq-reliable-fetch", + "generate-apollo-graphql-schema", + "generate-frontend-fixtures-mapping", + "gitlab-advanced-sast", + "gitlab-advanced-sast-cpp", + "gitlab_git_test", + "gitlab:setup", + "gosec-sast", + "graphql-schema-dump", + "graphql-verify", + "haml-lint", + "jest", + "jest-build-cache", + "jest-build-cache-vue3-ensure-compilable-sfcs", + "jest predictive", + "jest vue3", + "jest vue3 check quarantined", + "jest vue3 check quarantined predictive", + "jest vue3 predictive", + "jest-with-fixtures vue3 check quarantined", + "jest-with-fixtures vue3 check quarantined predictive", + "kubesec-sast", + "lint-metrics-yaml", + "lint-pipeline-yaml", + "lint-yaml", + "memory-on-boot", + "mobsf-android-sast", + "mobsf-ios-sast", + "nodejs-scan-sast", + "no-ee-check", + "no-jh-check", + "notify-test-on-omnibus-failure", + "openapi-doc-check", + "package_hunter-bundler", + "package_hunter-yarn", + "pages", + "pajamas_adoption", + "permissions-verify", + "phpcs-security-audit-sast", + "ping-appsec-for-dependency-review", + "ping-appsec-for-sast-findings", + "pipeline-tier-1", + "pipeline-tier-2", + "pipeline-tier-3", + "pmd-apex-sast", + "pre-merge-checks", + "prepare-as-if-foss-branch", + "prepare-as-if-foss-env", + "qa:metadata-lint", + "qa:orchestrator-lint", + "qa:orchestrator-rspec", + "qa:rspec-internal", + "qa:selectors", + "rails-next-dependency-check", + "retag-gdk-image", + "retrieve-tests-metadata", + "review-docs-cleanup", + "review-docs-deploy", + "rspec:artifact-collector as-if-foss", + "rspec:artifact-collector ee remainder", + "rspec:artifact-collector ee remainder single-redis", + "rspec:artifact-collector ee unit", + "rspec:artifact-collector ee unit single-redis", + "rspec:artifact-collector part-a", + "rspec:artifact-collector part-b", + "rspec:artifact-collector remainder single-redis", + "rspec:artifact-collector system single-redis", + "rspec:artifact-collector unit", + "rspec:artifact-collector unit single-redis", + "rspec:coverage", + "rspec-ee:predictive:trigger", + "rspec-ee:predictive:trigger single-db", + "rspec-ee:predictive:trigger single-db-ci-connection", + "rspec:feature-flags", + "rspec:flaky-tests-report", + "rspec:merge-auto-explain-logs", + "rspec-predictive:pipeline-generate", + "rspec:predictive:trigger", + "rspec:predictive:trigger single-db", + "rspec:predictive:trigger single-db-ci-connection", + "rspec:schedule-weekly-report-failures", + "rspec:undercoverage", + "rubocop", + "rubocop-docs", + "rubocop:docs-site", + "ruby_syntax", + "run-dev-fixtures", + "run-dev-fixtures-ee", + "sast", + "secret_detection", + "security-code-scan-sast", + "semgrep-appsec-custom-rules", + "semgrep-sast", + "set-pipeline-name", + "setup-test-env", + "setup-test-env-fips", + "sobelow-sast", + "spotbugs-sast", + "start-as-if-foss", + "start-release-environments-security-pipeline", + "static-analysis", + "static-verification-with-database", + "sync-security-branch", + "sync-stable-branch", + "templates-shellcheck", + "test-coverage:export-rspec-and-e2e", + "test-coverage:export-workhorse", + "test-fe-islands", + "test-linters", + "trigger-ai-gateway-tagging", + "type-check-fe-islands", + "untamper-fe-islands-lockfile", + "untamper-my-lockfile", + "update-tests-metadata", + "upload-frontend-fixtures", + "upload-graphql-schema-dump", + "validate-fe-islands-ci", + "verify-approvals", + "verify-tests-metadata", + "verify-tests-yml", + "workhorse-coverage", + "workhorse:test fips", + "workhorse:test go", + "workhorse:test no_gitaly_transactions", + "workhorse:test race", + "workhorse:verify" + ] + end + + it "ensures jobs download repo from artifacts", :aggregate_failures do + merged_yaml.each do |job_name, config| + next if global_keywords.include?(job_name) # Skip globals + next if job_name.start_with?('.') # Skip templates + next if legit_excludes.include?(job_name) + + if todo_list.include?(job_name) + expect(config).not_to download_repo_from_artifacts, + "Job `#{job_name}` is in todo_list but already passes" + else + expect(config).to download_repo_from_artifacts, + "Job `#{job_name}` does not download repo from artifacts" + end + end + end +end + module CiConfigurationValidationHelper def sync_local_files_to_project(project, user, branch_name, files:) actions = [] -- GitLab