diff --git a/.github/actions/pr-gate/action.yml b/.github/actions/pr-gate/action.yml index 5d4b9c183..0c55bf120 100644 --- a/.github/actions/pr-gate/action.yml +++ b/.github/actions/pr-gate/action.yml @@ -16,6 +16,9 @@ outputs: should_run: description: "true if the workflow should proceed, false otherwise" value: ${{ steps.gate.outputs.should_run }} + labels_json: + description: "JSON array of PR label names for push-triggered mirror runs, or [] otherwise" + value: ${{ steps.gate.outputs.labels_json }} runs: using: composite @@ -35,20 +38,23 @@ runs: REQUIRED_LABEL: ${{ inputs.required_label }} run: | if [ "$EVENT_NAME" != "push" ]; then + echo "labels_json=[]" >> "$GITHUB_OUTPUT" echo "should_run=true" >> "$GITHUB_OUTPUT" exit 0 fi if [ "$GET_PR_INFO_OUTCOME" != "success" ]; then + echo "labels_json=[]" >> "$GITHUB_OUTPUT" echo "should_run=false" >> "$GITHUB_OUTPUT" exit 0 fi head_sha="$(jq -r '.head.sha' <<< "$PR_INFO")" + labels_json="$(jq -c '[.labels[].name]' <<< "$PR_INFO")" if [ -z "$REQUIRED_LABEL" ]; then has_label=true else - has_label="$(jq -r --arg L "$REQUIRED_LABEL" '[.labels[].name] | index($L) != null' <<< "$PR_INFO")" + has_label="$(jq -r --arg L "$REQUIRED_LABEL" 'index($L) != null' <<< "$labels_json")" fi # Only trust copied pull-request/* pushes that still match the PR head @@ -59,4 +65,5 @@ runs: should_run=false fi + echo "labels_json=$labels_json" >> "$GITHUB_OUTPUT" echo "should_run=$should_run" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/branch-checks.yml b/.github/workflows/branch-checks.yml index 54084fddd..bb2d478fc 100644 --- a/.github/workflows/branch-checks.yml +++ b/.github/workflows/branch-checks.yml @@ -106,11 +106,14 @@ jobs: - name: Cache Rust target and registry uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2 with: - # Separate caches for clippy (check-like) vs test (full build) - # so they don't thrash each other's artifacts + # Keep branch-check caches partitioned by runner architecture; lint + # and test intentionally share the same job-local target directory. shared-key: rust-checks-${{ matrix.runner }} # Cache the sccache directory too cache-directories: .cache/sccache + # Preserve compiled artifacts from failed lint/test runs so the next + # push to the same PR branch does not start from a cold cache. + cache-on-failure: "true" - name: Format run: mise run rust:format:check diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index d6419545a..de8bd5551 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -8,6 +8,10 @@ on: permissions: {} +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: pr_metadata: name: Resolve PR metadata @@ -17,44 +21,142 @@ jobs: pull-requests: read outputs: should_run: ${{ steps.gate.outputs.should_run }} + run_core_e2e: ${{ steps.labels.outputs.run_core_e2e }} + run_gpu_e2e: ${{ steps.labels.outputs.run_gpu_e2e }} + run_any_e2e: ${{ steps.labels.outputs.run_any_e2e }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - id: gate uses: ./.github/actions/pr-gate - with: - required_label: test:e2e + - id: labels + if: steps.gate.outputs.should_run == 'true' + env: + EVENT_NAME: ${{ github.event_name }} + LABELS_JSON: ${{ steps.gate.outputs.labels_json }} + shell: bash + run: | + set -euo pipefail + if [ "$EVENT_NAME" != "push" ]; then + run_core_e2e=true + run_gpu_e2e=true + else + run_core_e2e="$(jq -r 'index("test:e2e") != null' <<< "$LABELS_JSON")" + run_gpu_e2e="$(jq -r 'index("test:e2e-gpu") != null' <<< "$LABELS_JSON")" + fi + if [ "$run_core_e2e" = "true" ] || [ "$run_gpu_e2e" = "true" ]; then + run_any_e2e=true + else + run_any_e2e=false + fi + { + echo "run_core_e2e=$run_core_e2e" + echo "run_gpu_e2e=$run_gpu_e2e" + echo "run_any_e2e=$run_any_e2e" + } >> "$GITHUB_OUTPUT" build-gateway: needs: [pr_metadata] - if: needs.pr_metadata.outputs.should_run == 'true' + if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' permissions: contents: read packages: write uses: ./.github/workflows/docker-build.yml with: component: gateway - platform: linux/arm64 - publish-manifest: false + image-tag: ${{ github.sha }} build-supervisor: needs: [pr_metadata] - if: needs.pr_metadata.outputs.should_run == 'true' + if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_any_e2e == 'true' permissions: contents: read packages: write uses: ./.github/workflows/docker-build.yml with: component: supervisor - platform: linux/arm64 - publish-manifest: false + image-tag: ${{ github.sha }} e2e: needs: [pr_metadata, build-gateway, build-supervisor] - if: needs.pr_metadata.outputs.should_run == 'true' + if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' permissions: contents: read packages: read uses: ./.github/workflows/e2e-test.yml with: - image-tag: ${{ github.sha }}-arm64 + image-tag: ${{ github.sha }} runner: linux-arm64-cpu8 + + gpu-e2e: + needs: [pr_metadata, build-supervisor] + if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_gpu_e2e == 'true' + permissions: + contents: read + packages: read + uses: ./.github/workflows/e2e-gpu-test.yaml + with: + image-tag: ${{ github.sha }} + + kubernetes-e2e: + needs: [pr_metadata, build-gateway, build-supervisor] + if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' + permissions: + contents: read + packages: read + uses: ./.github/workflows/e2e-kubernetes-test.yml + with: + image-tag: ${{ github.sha }} + + core-e2e-result: + name: Core E2E result + needs: [pr_metadata, build-gateway, build-supervisor, e2e, kubernetes-e2e] + if: always() && needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' + runs-on: ubuntu-latest + steps: + - name: Verify core E2E jobs + env: + BUILD_GATEWAY_RESULT: ${{ needs.build-gateway.result }} + BUILD_SUPERVISOR_RESULT: ${{ needs.build-supervisor.result }} + E2E_RESULT: ${{ needs.e2e.result }} + KUBERNETES_E2E_RESULT: ${{ needs.kubernetes-e2e.result }} + run: | + set -euo pipefail + failed=0 + for item in \ + "build-gateway:$BUILD_GATEWAY_RESULT" \ + "build-supervisor:$BUILD_SUPERVISOR_RESULT" \ + "e2e:$E2E_RESULT" \ + "kubernetes-e2e:$KUBERNETES_E2E_RESULT"; do + name="${item%%:*}" + result="${item#*:}" + if [ "$result" != "success" ]; then + echo "::error::$name concluded $result" + failed=1 + fi + done + exit "$failed" + + gpu-e2e-result: + name: GPU E2E result + needs: [pr_metadata, build-supervisor, gpu-e2e] + if: always() && needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_gpu_e2e == 'true' + runs-on: ubuntu-latest + steps: + - name: Verify GPU E2E jobs + env: + BUILD_SUPERVISOR_RESULT: ${{ needs.build-supervisor.result }} + GPU_E2E_RESULT: ${{ needs.gpu-e2e.result }} + run: | + set -euo pipefail + failed=0 + for item in \ + "build-supervisor:$BUILD_SUPERVISOR_RESULT" \ + "gpu-e2e:$GPU_E2E_RESULT"; do + name="${item%%:*}" + result="${item#*:}" + if [ "$result" != "success" ]; then + echo "::error::$name concluded $result" + failed=1 + fi + done + exit "$failed" diff --git a/.github/workflows/branch-kubernetes-e2e.yml b/.github/workflows/e2e-kubernetes-test.yml similarity index 59% rename from .github/workflows/branch-kubernetes-e2e.yml rename to .github/workflows/e2e-kubernetes-test.yml index dd542fa05..8ccf1ddf0 100644 --- a/.github/workflows/branch-kubernetes-e2e.yml +++ b/.github/workflows/e2e-kubernetes-test.yml @@ -1,65 +1,34 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -name: Branch Kubernetes E2E +name: Kubernetes E2E Test on: - push: - branches: - - "pull-request/[0-9]+" - workflow_dispatch: {} - -permissions: {} + workflow_call: + inputs: + image-tag: + description: "Image tag to test (typically the commit SHA)" + required: true + type: string + runner: + description: "GitHub Actions runner label" + required: false + type: string + default: "linux-amd64-cpu8" + checkout-ref: + description: "Git ref to check out for test inputs (defaults to the workflow SHA)" + required: false + type: string + default: "" + +permissions: + contents: read + packages: read jobs: - pr_metadata: - name: Resolve PR metadata - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - outputs: - should_run: ${{ steps.gate.outputs.should_run }} - steps: - - uses: actions/checkout@v6 - - - id: gate - uses: ./.github/actions/pr-gate - with: - required_label: test:e2e-kubernetes - - build-gateway: - needs: [pr_metadata] - if: needs.pr_metadata.outputs.should_run == 'true' - permissions: - contents: read - packages: write - uses: ./.github/workflows/docker-build.yml - with: - component: gateway - platform: linux/amd64 - publish-manifest: false - - build-supervisor: - needs: [pr_metadata] - if: needs.pr_metadata.outputs.should_run == 'true' - permissions: - contents: read - packages: write - uses: ./.github/workflows/docker-build.yml - with: - component: supervisor - platform: linux/amd64 - publish-manifest: false - - kubernetes-e2e: + e2e-kubernetes: name: Kubernetes E2E (Rust smoke) - needs: [pr_metadata, build-gateway, build-supervisor] - if: needs.pr_metadata.outputs.should_run == 'true' # Bare runner: running kind-in-container hits nested-Docker / kubeconfig # complications. The runner has Docker; mise installs helm, kubectl, and # the Rust toolchain. - runs-on: linux-amd64-cpu8 + runs-on: ${{ inputs.runner }} timeout-minutes: 60 permissions: contents: read @@ -68,7 +37,9 @@ jobs: MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} KIND_CLUSTER_NAME: kube-e2e-${{ github.run_id }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + ref: ${{ inputs['checkout-ref'] || github.sha }} - name: Install mise run: | @@ -100,7 +71,7 @@ jobs: # mise.toml sets KUBECONFIG="{{config_root}}/kubeconfig"; helm/kind-action # writes to ~/.kube/config. Materialize the kind context at the mise path - # so `mise run e2e:kubernetes` (and the wrapper's `kubectl --context=…`) + # so `mise run e2e:kubernetes` (and the wrapper's `kubectl --context=...`) # finds the kind cluster. - name: Export kind kubeconfig to mise path run: | @@ -112,16 +83,14 @@ jobs: run: | set -euo pipefail for component in gateway supervisor; do - src="ghcr.io/nvidia/openshell/${component}:${{ github.sha }}-amd64" - bare="ghcr.io/nvidia/openshell/${component}:${{ github.sha }}" - docker pull "$src" - docker tag "$src" "$bare" - kind load docker-image "$bare" --name "$KIND_CLUSTER_NAME" + image="ghcr.io/nvidia/openshell/${component}:${{ inputs.image-tag }}" + docker pull --platform linux/amd64 "$image" + kind load docker-image "$image" --name "$KIND_CLUSTER_NAME" done - name: Run Kubernetes E2E (Rust smoke) env: OPENSHELL_E2E_KUBE_CONTEXT: kind-${{ env.KIND_CLUSTER_NAME }} - IMAGE_TAG: ${{ github.sha }} + IMAGE_TAG: ${{ inputs.image-tag }} OPENSHELL_REGISTRY: ghcr.io/nvidia/openshell run: mise run --no-deps --skip-deps e2e:kubernetes diff --git a/.github/workflows/e2e-label-help.yml b/.github/workflows/e2e-label-help.yml index e1a268803..21f4397f7 100644 --- a/.github/workflows/e2e-label-help.yml +++ b/.github/workflows/e2e-label-help.yml @@ -1,6 +1,6 @@ name: E2E Label Help -# When a `test:e2e*` label is applied, post a PR comment +# When an E2E label is applied, post a PR comment # telling the maintainer the next manual step. We don't dispatch the workflow # ourselves: a workflow_dispatch-triggered run does not surface in the PR's # Checks tab, so we'd lose in-progress visibility. Instead we point the @@ -19,7 +19,7 @@ permissions: {} jobs: hint: name: Post next-step hint for E2E label - if: github.event.label.name == 'test:e2e' || github.event.label.name == 'test:e2e-gpu' || github.event.label.name == 'test:e2e-kubernetes' + if: github.event.label.name == 'test:e2e' || github.event.label.name == 'test:e2e-gpu' runs-on: ubuntu-latest permissions: pull-requests: write @@ -37,10 +37,17 @@ jobs: run: | set -euo pipefail + workflow_file=branch-e2e.yml + workflow_name="Branch E2E Checks" case "$LABEL_NAME" in - test:e2e) workflow_file=branch-e2e.yml; workflow_name="Branch E2E Checks" ;; - test:e2e-gpu) workflow_file=test-gpu.yml; workflow_name="GPU Test" ;; - test:e2e-kubernetes) workflow_file=branch-kubernetes-e2e.yml; workflow_name="Branch Kubernetes E2E" ;; + test:e2e) + suite_summary="the standard E2E suite" + build_summary="gateway and supervisor images" + ;; + test:e2e-gpu) + suite_summary="GPU E2E" + build_summary="supervisor image" + ;; *) echo "Unrecognized label $LABEL_NAME"; exit 1 ;; esac @@ -62,7 +69,7 @@ jobs: workflow_link="[$workflow_name](https://github.com/$GH_REPO/actions/workflows/$workflow_file)" instructions="Open $workflow_link, find the run for commit \`$short_pr\`, and click **Re-run all jobs** to execute with the label set." fi - body="Label \`$LABEL_NAME\` applied for \`$short_pr\`. $instructions The matching required CI gate status on this PR will flip green automatically once the run finishes." + body="Label \`$LABEL_NAME\` applied for \`$short_pr\`. $instructions The run will execute $suite_summary after building the required $build_summary once. The matching required CI gate status on this PR will flip green automatically once the run finishes." fi gh pr comment "$PR_NUMBER" --body "$body" diff --git a/.github/workflows/required-ci-gates.yml b/.github/workflows/required-ci-gates.yml index 6909cd5f2..ca068cf5c 100644 --- a/.github/workflows/required-ci-gates.yml +++ b/.github/workflows/required-ci-gates.yml @@ -7,8 +7,6 @@ on: workflows: - Branch Checks - Branch E2E Checks - - GPU Test - - Branch Kubernetes E2E - Helm Lint types: [completed] @@ -148,6 +146,7 @@ jobs: local workflow_file="$2" local workflow_name="$3" local required_label="${4:-}" + local required_job_name="${5:-}" local workflow_url="https://github.com/$GH_REPO/actions/workflows/$workflow_file" if [ -n "$required_label" ] && ! has_label "$required_label"; then @@ -178,6 +177,38 @@ jobs: return 0 fi + if [ -n "$required_job_name" ]; then + local jobs required_job job_status job_conclusion + jobs=$(gh api "repos/$GH_REPO/actions/runs/$run_id/jobs?per_page=100" --jq '.jobs') + required_job=$(jq -c --arg name "$required_job_name" '[.[] | select(.name == $name)] | .[0] // empty' <<< "$jobs") + + if [ -z "$required_job" ]; then + if [ "$conclusion" = "success" ]; then + post_status "$context" pending "Waiting for $required_job_name" "$run_url" + else + post_status "$context" failure "$required_job_name did not run" "$run_url" + fi + return 0 + fi + + job_status=$(jq -r '.status' <<< "$required_job") + job_conclusion=$(jq -r '.conclusion' <<< "$required_job") + + if [ "$job_status" != "completed" ]; then + post_status "$context" pending "$required_job_name is $job_status" "$run_url" + return 0 + fi + + if [ "$job_conclusion" = "success" ]; then + post_status "$context" success "$required_job_name passed" "$run_url" + elif [ "$job_conclusion" = "skipped" ] && [ "$conclusion" = "success" ]; then + post_status "$context" pending "Waiting for $required_job_name" "$run_url" + else + post_status "$context" failure "$required_job_name concluded $job_conclusion" "$run_url" + fi + return 0 + fi + if [ "$conclusion" != "success" ]; then post_status "$context" failure "$workflow_name concluded $conclusion" "$run_url" return 0 @@ -197,7 +228,6 @@ jobs: resolve_context evaluate_workflow "OpenShell / Branch Checks" "branch-checks.yml" "Branch Checks" - evaluate_workflow "OpenShell / E2E" "branch-e2e.yml" "Branch E2E Checks" "test:e2e" - evaluate_workflow "OpenShell / GPU E2E" "test-gpu.yml" "GPU Test" "test:e2e-gpu" - evaluate_workflow "OpenShell / Kubernetes E2E" "branch-kubernetes-e2e.yml" "Branch Kubernetes E2E" "test:e2e-kubernetes" + evaluate_workflow "OpenShell / E2E" "branch-e2e.yml" "Branch E2E Checks" "test:e2e" "Core E2E result" + evaluate_workflow "OpenShell / GPU E2E" "branch-e2e.yml" "Branch E2E Checks" "test:e2e-gpu" "GPU E2E result" evaluate_workflow "OpenShell / Helm Lint" "helm-lint.yml" "Helm Lint" diff --git a/.github/workflows/test-gpu.yml b/.github/workflows/test-gpu.yml deleted file mode 100644 index 4d62ccefd..000000000 --- a/.github/workflows/test-gpu.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: GPU Test - -on: - push: - branches: - - "pull-request/[0-9]+" - workflow_dispatch: {} - # Add `schedule:` here when we want nightly coverage from the same workflow. - -permissions: {} - -jobs: - pr_metadata: - name: Resolve PR metadata - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - outputs: - should_run: ${{ steps.gate.outputs.should_run }} - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - id: gate - uses: ./.github/actions/pr-gate - with: - required_label: test:e2e-gpu - - build-supervisor: - needs: [pr_metadata] - if: needs.pr_metadata.outputs.should_run == 'true' - permissions: - contents: read - packages: write - uses: ./.github/workflows/docker-build.yml - with: - component: supervisor - - e2e-gpu: - needs: [pr_metadata, build-supervisor] - if: needs.pr_metadata.outputs.should_run == 'true' - permissions: - contents: read - packages: read - uses: ./.github/workflows/e2e-gpu-test.yaml - with: - image-tag: ${{ github.sha }} diff --git a/CI.md b/CI.md index 2a00811a7..a7ca79c9d 100644 --- a/CI.md +++ b/CI.md @@ -10,11 +10,13 @@ PR CI that runs on NVIDIA self-hosted runners uses NVIDIA's copy-pr-bot. The bot `Branch Checks` run automatically after copy-pr-bot mirrors the PR. `Required CI Gates` posts PR-head statuses that verify the mirror exists, is current, and ran the expected push-based workflows. E2E suites are opt-in because they are more expensive and publish temporary images. -Three opt-in labels enable the suites: +Two opt-in labels enable the long-running E2E suites: -- `test:e2e` runs `Branch E2E Checks` (non-GPU E2E) -- `test:e2e-gpu` runs `GPU Test` -- `test:e2e-kubernetes` runs `Branch Kubernetes E2E` +- `test:e2e` runs the standard E2E suite in `Branch E2E Checks` +- `test:e2e-gpu` runs GPU E2E in `Branch E2E Checks` + +When both labels are present, `Branch E2E Checks` builds the shared gateway and supervisor images once and fans out all enabled suites in parallel. +The `OpenShell / E2E` and `OpenShell / GPU E2E` required statuses are evaluated from separate suite result jobs inside that workflow, so the expensive GPU suite stays independently gated. The GitHub ruleset should require the `OpenShell / ...` statuses published by `Required CI Gates`, not the push-triggered workflow jobs directly. @@ -66,11 +68,11 @@ Prerequisites: Flow: 1. Open the PR. copy-pr-bot mirrors it to `pull-request/` automatically. -2. The mirror push runs `Branch Checks` automatically. `Required CI Gates` keeps the PR blocked until the mirror exists, matches the PR head SHA, and the required push-based workflow succeeds. The first `Branch E2E Checks` / `GPU Test` / `Branch Kubernetes E2E` run only resolves metadata and skips expensive jobs unless the matching label is already set. -3. A maintainer applies `test:e2e`, `test:e2e-gpu`, and/or `test:e2e-kubernetes`. `E2E Label Help` posts a comment with a link to the existing gated workflow run. +2. The mirror push runs `Branch Checks` automatically. `Required CI Gates` keeps the PR blocked until the mirror exists, matches the PR head SHA, and the required push-based workflow succeeds. The first `Branch E2E Checks` run only resolves metadata and skips expensive jobs unless an E2E label is already set. +3. A maintainer applies `test:e2e` and/or `test:e2e-gpu`. `E2E Label Help` posts a comment with a link to the existing gated workflow run. 4. The maintainer opens that link and clicks **Re-run all jobs**. This time `pr_metadata` sees the label and the build/E2E jobs run. 5. When the run finishes, the matching `OpenShell / ...` gate status flips to green automatically. -6. New commits push to the mirror automatically and re-trigger `Branch Checks` plus any labeled E2E/GPU/Kubernetes workflows. +6. New commits push to the mirror automatically and re-trigger `Branch Checks` plus any labeled E2E jobs in `Branch E2E Checks`. ### Forked PR @@ -83,7 +85,7 @@ Flow: 1. Open the PR. The vouch check confirms you are vouched (otherwise the PR is auto-closed). 2. copy-pr-bot does not mirror forks automatically. A maintainer reviews the diff and comments `/ok to test ` with your latest commit SHA. -3. After `/ok to test`, copy-pr-bot mirrors to `pull-request/`. From here the flow is identical to internal PRs: `Required CI Gates` verifies the mirror and required push workflows, and maintainers apply E2E labels when the extra suites are needed. +3. After `/ok to test`, copy-pr-bot mirrors to `pull-request/`. From here the flow is identical to internal PRs: `Required CI Gates` verifies the mirror and required push workflows, and maintainers apply the E2E label when the extra suites are needed. Important: every new commit you push requires another `/ok to test ` from a maintainer before push-based CI will run on it. If a label is applied while the mirror is stale, `E2E Label Help` will post a comment explaining what's needed. @@ -106,9 +108,7 @@ The bot's full administrator documentation is internal to NVIDIA. The only comma | File | Role | |---|---| | `.github/workflows/branch-checks.yml` | Required non-E2E PR checks. Triggers on `push: pull-request/[0-9]+`. | -| `.github/workflows/branch-e2e.yml` | Non-GPU E2E. Triggers on `push: pull-request/[0-9]+`. | -| `.github/workflows/test-gpu.yml` | GPU E2E. Triggers on `push: pull-request/[0-9]+`. | -| `.github/workflows/branch-kubernetes-e2e.yml` | Kubernetes E2E. Triggers on `push: pull-request/[0-9]+`. | +| `.github/workflows/branch-e2e.yml` | Opt-in standard and GPU E2E. Triggers on `push: pull-request/[0-9]+` and runs jobs selected by `test:e2e` / `test:e2e-gpu`. | | `.github/workflows/helm-lint.yml` | Helm chart validation. Triggers on `push: pull-request/[0-9]+` and skips lint jobs unless Helm inputs changed. | | `.github/actions/pr-gate/action.yml` | Composite action that resolves PR metadata and verifies the required label is set. | | `.github/actions/pr-merge-base/action.yml` | Composite action that resolves and fetches the merge-base commit for `pull-request/` push workflows. | @@ -132,7 +132,6 @@ Require these statuses in the branch ruleset for push-based CI: - `OpenShell / Branch Checks` - `OpenShell / E2E` - `OpenShell / GPU E2E` -- `OpenShell / Kubernetes E2E` - `OpenShell / Helm Lint` Do not require the underlying push workflow jobs directly. Those jobs only appear after copy-pr-bot mirrors trusted code, so they cannot independently prove that an untrusted or stale PR head was tested. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00c1a6713..6e2dfb04d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -283,4 +283,4 @@ DCO sign-off is separate from cryptographic commit signing. CI requires signing ## CI -How PR CI runs, the `test:e2e` / `test:e2e-gpu` / `test:e2e-kubernetes` labels, copy-pr-bot, and commit-signing setup are documented in [CI.md](CI.md). +How PR CI runs, the `test:e2e` / `test:e2e-gpu` labels, copy-pr-bot, and commit-signing setup are documented in [CI.md](CI.md).