Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ env:
jobs:
classify_pr:
name: 'Classify PR'
if: "${{ github.event_name == 'pull_request' }}"
# Gate runs on ECS for in-repo PRs too, else a busy hosted pool delays it and blocks the ECS-bound jobs. The kill-switch is read here, so flipping it reverts everything to hosted.
runs-on: '${{ (vars.MAINTAINER_ECS_RUNNER_DISABLED != ''true'' && github.event.pull_request.head.repo.full_name == github.repository) && fromJSON(''["self-hosted", "linux", "x64", "ecs-qwen"]'') || fromJSON(''["ubuntu-latest"]'') }}'
if: "${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' }}"
# Gate runs on ECS for in-repo PRs and for the merge queue (which runs in the
# base-repo context), else a busy hosted pool delays it and blocks the
# ECS-bound jobs. The kill-switch is read here, so flipping it reverts
# everything to hosted.
runs-on: '${{ (vars.MAINTAINER_ECS_RUNNER_DISABLED != ''true'' && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == ''merge_group'')) && fromJSON(''["self-hosted", "linux", "x64", "ecs-qwen"]'') || fromJSON(''["ubuntu-latest"]'') }}'
continue-on-error: true
outputs:
skip_ci: '${{ steps.release_sync.outputs.skip_ci }}'
Expand Down Expand Up @@ -88,16 +91,18 @@ jobs:
echo "skip_ci=${skip_ci}" >> "${GITHUB_OUTPUT}"
echo "skip_ci=${skip_ci}"

# In-repo PR (head branch in this repo => author has write access) runs the
# Linux Test on ECS; forks stay hosted. Disable via repo var MAINTAINER_ECS_RUNNER_DISABLED=true.
# In-repo PR (head branch in this repo => author has write access) and the
# merge queue (base-repo context) run the Linux jobs on ECS; fork PRs stay
# hosted. Disable via repo var MAINTAINER_ECS_RUNNER_DISABLED=true.
- name: 'Select Linux runner'
id: 'pick_runner'
env:
SAME_REPO: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
ECS_DISABLED: '${{ vars.MAINTAINER_ECS_RUNNER_DISABLED }}'
EVENT_NAME: '${{ github.event_name }}'
run: |-
ubuntu_runner='["ubuntu-latest"]'
if [[ "${ECS_DISABLED}" != "true" && "${SAME_REPO}" == "true" ]]; then
if [[ "${ECS_DISABLED}" != "true" && ( "${SAME_REPO}" == "true" || "${EVENT_NAME}" == "merge_group" ) ]]; then
ubuntu_runner='["self-hosted", "linux", "x64", "ecs-qwen"]'
fi
echo "ubuntu_runner=${ubuntu_runner}" >> "${GITHUB_OUTPUT}"
Expand Down Expand Up @@ -463,8 +468,13 @@ jobs:
# `test:integration:cli:sandbox:none` script from `release.yml`.
integration_cli:
name: 'Integration Tests (CLI, No Sandbox)'
if: "${{ github.event_name == 'merge_group' }}"
runs-on: 'ubuntu-latest'
needs: 'classify_pr'
# Same ECS routing as the Ubuntu gate (via classify_pr): the merge queue runs
# in the base-repo context, so use the self-hosted ECS pool and keep the
# scarce hosted Linux runners free. Falls back to hosted if classify_pr is
# skipped or the ECS kill-switch is set.
if: "${{ !cancelled() && github.event_name == 'merge_group' }}"
runs-on: '${{ fromJSON(needs.classify_pr.outputs.ubuntu_runner || ''["ubuntu-latest"]'') }}'
permissions:
contents: 'read'
env:
Expand All @@ -475,13 +485,25 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2

- name: 'Setup Node.js'
# Hosted downloads Node; self-hosted ECS reuses its pre-installed Node 22
# (it can't reach nodejs.org reliably). Mirrors the Ubuntu gate.
- name: 'Setup Node.js (hosted)'
if: "${{ runner.environment == 'github-hosted' }}"
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
cache-dependency-path: 'package-lock.json'

- name: 'Use pre-installed Node.js (self-hosted)'
if: "${{ runner.environment == 'self-hosted' }}"
run: |-
if ! command -v node >/dev/null 2>&1; then
echo "::error::Node.js is not on PATH for this self-hosted runner. Provision Node 22.x or set the MAINTAINER_ECS_RUNNER_DISABLED repository variable to 'true' to route the merge queue back to hosted runners."
exit 1
fi
echo "Using pre-installed Node $(node -v) / npm $(npm -v)"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The test job's self-hosted Node step (lines 173-175) includes a major-version guard that this block omits:

if [[ "$(node -p 'process.versions.node.split(".")[0]')" != "22" ]]; then
  echo "::warning::Expected Node 22.x but found $(node -v); integration tests will run against the runner's Node."
fi

Without it, if an ECS runner is reprovisioned with a different Node major version, integration tests silently run against it. The test job would emit a warning but this job would not, making it harder to correlate version-specific integration test failures.

— qwen3.7-max via Qwen Code /review


- name: 'Install Dependencies'
env:
NPM_CONFIG_PREFER_OFFLINE: 'true'
Expand Down
Loading