Repository navigation
ROX-37371: Prototype CI test selection in Go #23403
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
7b6d7c7
56025a4
a44e7cb
3dee4f6
e684e8e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| name: Build CI selector | ||
| description: Build the Go CI selection prototype before gated setup steps | ||
| runs: | ||
| using: composite | ||
| steps: | ||
| - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # ratchet:actions/setup-go@v6 | ||
| with: | ||
| go-version-file: go.mod | ||
| cache: false | ||
| - name: Build CI selector | ||
| shell: bash | ||
| run: ci/select/build.sh |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| name: CI decision | ||
|
|
||
| # Prints the decision for a pull request. It does not start or stop other | ||
| # jobs. The label ci-dispatcher-enforce is read by the jobs that follow | ||
| # the decision. | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: | ||
| - opened | ||
| - reopened | ||
| - synchronize | ||
| - labeled | ||
| - unlabeled | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| decision: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 | ||
| with: | ||
| fetch-depth: 0 | ||
| ref: ${{ github.event.pull_request.head.sha }} | ||
|
|
||
| - uses: ./.github/actions/ci-select | ||
|
|
||
| - name: Print the CI decision | ||
| env: | ||
| CI_ENFORCE: ${{ contains(github.event.pull_request.labels.*.name, 'ci-dispatcher-enforce') }} | ||
| CI_REPO: ${{ github.repository }} | ||
| CI_PR: ${{ github.event.pull_request.number }} | ||
| CI_COMMIT: ${{ github.event.pull_request.head.sha }} | ||
| CI_BASE: ${{ github.event.pull_request.base.sha }} | ||
| CI_HEAD: ${{ github.event.pull_request.head.sha }} | ||
| PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }} | ||
| run: ci/select/gha-gate.sh |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| name: CI selector tests | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, reopened, synchronize, labeled, unlabeled] | ||
| push: | ||
| branches: [master, 'release-*'] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| selector-tests: | ||
| runs-on: ubuntu-24.04 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 | ||
| with: | ||
| fetch-depth: 0 | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| persist-credentials: false | ||
|
|
||
| - name: Build CI selector | ||
| continue-on-error: true | ||
| uses: ./.github/actions/ci-select | ||
|
|
||
| - name: Read the CI decision | ||
| id: ci-decision | ||
| if: github.event_name == 'pull_request' | ||
| env: | ||
| CI_ENFORCE: ${{ contains(github.event.pull_request.labels.*.name, 'ci-dispatcher-enforce') }} | ||
| CI_REPO: ${{ github.repository }} | ||
| CI_PR: ${{ github.event.pull_request.number }} | ||
| CI_COMMIT: ${{ github.event.pull_request.head.sha }} | ||
| CI_BASE: ${{ github.event.pull_request.base.sha }} | ||
| CI_HEAD: ${{ github.event.pull_request.head.sha }} | ||
| PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }} | ||
| run: ci/select/gha-gate.sh selector-tests | ||
|
|
||
| - name: Test CI selector | ||
| if: steps.ci-decision.outputs.action != 'skip' | ||
| run: go test -race ./ci/select | ||
|
|
||
| - name: Validate CI rules | ||
| if: steps.ci-decision.outputs.action != 'skip' | ||
| run: ci/select/bin/ci-select validate | ||
|
Comment on lines
+40
to
+46
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win Run the selector tests when the build step fails or the decision step is skipped. The The For Remove 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,8 @@ on: | |
| - reopened | ||
| - synchronize | ||
| - ready_for_review | ||
| - labeled | ||
| - unlabeled | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
@@ -30,108 +32,50 @@ jobs: | |
| # This allows to skip running E2E tests on draft PRs without corresponding labels or on untrusted forks. | ||
| should-dispatch: | ||
| needs: [ detect-changes ] | ||
| runs-on: ubuntu-slim | ||
| runs-on: ubuntu-24.04 | ||
| outputs: | ||
| wait-for-gha-images: ${{ steps.determine.outputs.wait-for-gha-images }} | ||
| wait-for-konflux-images: ${{ steps.determine.outputs.wait-for-konflux-images }} | ||
| jobs: ${{ steps.determine.outputs.jobs }} | ||
| steps: | ||
| - name: Determine whether should dispatch workflows | ||
| - name: Checkout | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 | ||
| with: | ||
| fetch-depth: 0 | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
# Inspect the action's build source and the workflow's token permissions.
rg -n -C 5 'go build|build.sh|ci-select|permissions:|persist-credentials:|GH_TOKEN' \
.github/actions/ci-select/action.yaml .github/workflows/e2e-dispatch.yaml ci/select/build.shRepository: stackrox/stackrox Length of output: 5891 🏁 Script executed: set -e
printf '%s\n' '--- workflow ---'
nl -ba .github/workflows/e2e-dispatch.yaml | sed -n '1,90p'
printf '%s\n' '--- local action ---'
nl -ba .github/actions/ci-select/action.yaml
printf '%s\n' '--- selector files ---'
rg -n -F --glob '!ci/select/bin/**' -e 'gha-dispatch-ci' -e 'GH_TOKEN' -e 'github' ci/select .github/actions .github/workflows/e2e-dispatch.yaml || test "$?" -eq 1
printf '%s\n' '--- relevant declarations ---'
find ci/select -maxdepth 3 -type f -not -path '*/bin/*' -printRepository: stackrox/stackrox Length of output: 22717 Do not run a PR-built selector with the dispatch token. The workflow checks out the pull request head, builds 🧰 Tools🪛 zizmor (1.30.1)[warning] 41-49: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| persist-credentials: false | ||
|
|
||
| # TODO(ROX-37371): Decide binary distribution and recovery when the selector | ||
| # cannot compile or run. A prebuilt binary removes compilation failures, | ||
| # but dispatch still needs a fallback independent of the binary. | ||
| - uses: ./.github/actions/ci-select | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift A selector build failure now blocks all e2e dispatch. The 🧰 Tools🪛 zizmor (1.30.1)[warning] 47-47: use GitHub's dedicated self-repository syntax (self-repository): use '$/...' instead of './...' (self-repository) 🤖 Prompt for AI Agents |
||
|
|
||
| - name: Print the CI decision | ||
| if: github.event_name == 'pull_request' | ||
| env: | ||
| CI_ENFORCE: ${{ contains(github.event.pull_request.labels.*.name, 'ci-dispatcher-enforce') }} | ||
| CI_REPO: ${{ github.repository }} | ||
| CI_PR: ${{ github.event.pull_request.number }} | ||
| CI_COMMIT: ${{ github.event.pull_request.head.sha }} | ||
| CI_BASE: ${{ github.event.pull_request.base.sha }} | ||
| CI_HEAD: ${{ github.event.pull_request.head.sha }} | ||
| PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }} | ||
| run: ci/select/gha-gate.sh | ||
|
|
||
| - name: Determine whether to dispatch workflows | ||
| id: determine | ||
| shell: python | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| PYTHONUNBUFFERED: "1" | ||
| input__event_name: ${{ github.event_name }} | ||
| input__is_fork: ${{ github.event.pull_request.head.repo.fork }} | ||
| input__is_draft: ${{ github.event.pull_request.draft }} | ||
| input__ui_only_change: ${{ needs.detect-changes.outputs.ui_only }} | ||
| input__repo: ${{ github.repository }} | ||
| input__pr_number: ${{ github.event.pull_request.number }} | ||
| run: | | ||
| import json | ||
| import os | ||
| import subprocess | ||
| from types import SimpleNamespace | ||
| from dataclasses import dataclass | ||
|
|
||
| @dataclass | ||
| class Job: | ||
| name: str | ||
| require_pr_label: bool = False | ||
| require_konflux_build: bool = False | ||
|
|
||
| def should_run(self, input): | ||
| if input.is_fork == 'true': | ||
| return False | ||
|
|
||
| if input.event_name != 'pull_request': | ||
| return True | ||
| elif self.name in input.pr_labels: | ||
| return True | ||
|
|
||
| # We are in a PR context, job is not explicitly listed among the PR labels. | ||
|
|
||
| # TODO(ROX-21073): re-enable Konflux for all PR branches | ||
| if self.require_konflux_build and 'konflux-build' not in input.pr_labels: | ||
| return False | ||
|
|
||
| if input.ui_only_change == 'true': | ||
| # For now, all the workflows that we dispatch should be skipped for PRs that only change UI. | ||
| # As we add more E2E test workflows, we may want to make this more flexible. | ||
| return False | ||
| if self.require_pr_label: | ||
| return False | ||
| if input.is_draft != 'true': | ||
| return True | ||
|
|
||
| return False | ||
|
|
||
|
|
||
| input = SimpleNamespace(**{ | ||
| key.removeprefix('input__'): val | ||
| for (key, val) in os.environ.items() | ||
| if key.startswith('input__')}) | ||
|
|
||
| if input.event_name != 'pull_request': | ||
| input.pr_labels = [] | ||
| else: | ||
| p = subprocess.run( | ||
| ['gh', 'pr', 'view', input.pr_number, '--repo', input.repo, '--json', 'labels', '--jq', '.labels[].name'], | ||
| check=True, encoding='utf-8', stdout=subprocess.PIPE, stdin=subprocess.DEVNULL) | ||
| input.pr_labels = p.stdout.strip().splitlines() | ||
|
|
||
| for k, v in vars(input).items(): | ||
| print(f'{k} = {v}') | ||
|
|
||
| jobs_registry = [ | ||
| Job(name='e2e-byodb-tests', require_pr_label=True), | ||
| Job(name='e2e-db-backup-restore-tests'), | ||
| Job(name='e2e-gke-upgrade-tests'), | ||
| Job(name='e2e-nongroovy-tests-gke'), | ||
| Job(name='e2e-nongroovy-tests-gke-konflux', require_konflux_build=True), | ||
| Job(name='e2e-qa-tests-gke', require_pr_label=True), | ||
| Job(name='e2e-qa-tests-gke-konflux', require_konflux_build=True), | ||
| Job(name='e2e-qa-tests-ocp-fips-konflux', require_konflux_build=True), | ||
| ] | ||
|
|
||
| with open(os.environ['GITHUB_OUTPUT'], mode='at', encoding='utf-8') as file: | ||
| def write(job, val): | ||
| line = f'{job}={val}' | ||
| print(line) | ||
| file.write(line + '\n') | ||
|
|
||
| jobs = {job.name: job.should_run(input) for job in jobs_registry} | ||
|
|
||
| write('jobs', json.dumps(jobs)) | ||
|
|
||
| # Find out when we can complete the workflow early by not even waiting for GHA-built images. | ||
| wait_for_gha_images = input.event_name != 'pull_request' or input.is_draft != 'true' or any(jobs.values()) | ||
| write('wait-for-gha-images', str(wait_for_gha_images).lower()) | ||
|
|
||
| # Waiting for konflux-built images in PR request context requires the 'konflux-build' PR label. | ||
| wait_for_konflux_images = input.event_name != 'pull_request' or ('konflux-build' in input.pr_labels and any(jobs.values())) | ||
| write('wait-for-konflux-images', str(wait_for_konflux_images).lower()) | ||
| CI_REPO: ${{ github.repository }} | ||
| CI_PR: ${{ github.event.pull_request.number }} | ||
| CI_COMMIT: ${{ github.event.pull_request.head.sha }} | ||
| CI_BASE: ${{ github.event.pull_request.base.sha }} | ||
| CI_HEAD: ${{ github.event.pull_request.head.sha }} | ||
| CI_IS_FORK: ${{ github.event.pull_request.head.repo.fork }} | ||
| CI_IS_DRAFT: ${{ github.event.pull_request.draft }} | ||
| CI_UI_ONLY: ${{ needs.detect-changes.outputs.ui_only }} | ||
| PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }} | ||
| run: ci/select/bin/ci-select gha-dispatch-ci | ||
|
|
||
| wait-for-images: | ||
| needs: [ should-dispatch ] | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.