mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-09 17:19:02 +00:00
ci: route in-repo PRs' Linux test to self-hosted runner (#5620)
* ci: route in-repo PRs' Linux test to self-hosted runner Send the required Linux Test job to the self-hosted ECS runner for PRs whose head branch lives in this repo (which implies the author had write access), while forks and push/merge_group runs stay on GitHub-hosted runners. This lets maintainer changes skip the shared hosted Linux queue without ever running untrusted fork code on self-hosted infrastructure. The MAINTAINER_ECS_RUNNER_DISABLED repo variable forces everything back to hosted if the ECS runner is unavailable. * ci: reuse pre-installed Node on self-hosted runners, route Lint to ECS The self-hosted ECS runners cannot reliably download the Node tarball from nodejs.org through the egress proxy (actions/setup-node aborts mid-download), which failed the Test job routed there. On self-hosted runners, reuse the machine's pre-installed Node instead of re-downloading it every run; hosted runners keep using actions/setup-node. Also route the Lint job to ECS for in-repo PRs — scripts/lint.js already skips installing actionlint/shellcheck/yamllint when they are on PATH, so no lint.js change is needed. * ci: trim verbose runner-routing comments * ci: run classify_pr gate on ECS for in-repo PRs * ci: quote classify_pr/lint runs-on expressions * ci: keep Lint on hosted runners (ECS proxy truncates linter downloads) * ci: route Lint and review/triage gate jobs to self-hosted runner Lint goes back to ECS (linters are now pre-installed on the runners, so scripts/lint.js skips downloading them). The pr-review gate jobs (authorize, review-config, delay-automatic-review, ack-review-request) and the triage authorize gate also move to ECS so the ECS heavy jobs (review-pr, tmux-testing) are no longer bottlenecked by the shared hosted queue. All respect the MAINTAINER_ECS_RUNNER_DISABLED kill-switch.
This commit is contained in:
parent
8809c16b57
commit
7696d9a7d9
4 changed files with 61 additions and 14 deletions
59
.github/workflows/ci.yml
vendored
59
.github/workflows/ci.yml
vendored
|
|
@ -43,10 +43,12 @@ jobs:
|
|||
classify_pr:
|
||||
name: 'Classify PR'
|
||||
if: "${{ github.event_name == 'pull_request' }}"
|
||||
runs-on: 'ubuntu-latest'
|
||||
# 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\"]') }}"
|
||||
continue-on-error: true
|
||||
outputs:
|
||||
skip_ci: '${{ steps.release_sync.outputs.skip_ci }}'
|
||||
ubuntu_runner: '${{ steps.pick_runner.outputs.ubuntu_runner }}'
|
||||
steps:
|
||||
- name: 'Detect release version-sync PR'
|
||||
id: 'release_sync'
|
||||
|
|
@ -84,11 +86,26 @@ 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.
|
||||
- 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 }}'
|
||||
run: |-
|
||||
ubuntu_runner='["ubuntu-latest"]'
|
||||
if [[ "${ECS_DISABLED}" != "true" && "${SAME_REPO}" == "true" ]]; then
|
||||
ubuntu_runner='["self-hosted", "linux", "x64", "ecs-qwen"]'
|
||||
fi
|
||||
echo "ubuntu_runner=${ubuntu_runner}" >> "${GITHUB_OUTPUT}"
|
||||
echo "Selected Linux runner: ${ubuntu_runner}"
|
||||
|
||||
lint:
|
||||
name: 'Lint'
|
||||
needs: 'classify_pr'
|
||||
if: "${{ !cancelled() && needs.classify_pr.outputs.skip_ci != 'true' }}"
|
||||
runs-on: 'ubuntu-latest'
|
||||
runs-on: "${{ fromJSON(needs.classify_pr.outputs.ubuntu_runner || '[\"ubuntu-latest\"]') }}"
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
|
||||
|
|
@ -96,12 +113,23 @@ jobs:
|
|||
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 'Set up Node.js 22.x'
|
||||
# Self-hosted reuses the machine's Node (nodejs.org unreachable via proxy); linters are pre-installed on PATH so scripts/lint.js skips downloading them.
|
||||
- name: 'Set up Node.js 22.x (hosted)'
|
||||
if: "${{ runner.environment == 'github-hosted' }}"
|
||||
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
|
||||
with:
|
||||
node-version: '22.x'
|
||||
cache: 'npm'
|
||||
|
||||
- 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 MAINTAINER_ECS_RUNNER_DISABLED='true' to route PRs back to hosted runners."
|
||||
exit 1
|
||||
fi
|
||||
echo "Using pre-installed Node $(node -v) / npm $(npm -v)"
|
||||
|
||||
- name: 'Install dependencies and run prepare'
|
||||
run: 'npm ci'
|
||||
|
||||
|
|
@ -158,7 +186,7 @@ jobs:
|
|||
# Stay running on release-sync PRs so the required Test contexts still
|
||||
# report; the per-step skip_ci guards below make them no-op (pass) there.
|
||||
if: '${{ !cancelled() }}'
|
||||
runs-on: '${{ matrix.runner }}'
|
||||
runs-on: '${{ fromJSON(matrix.runner) }}'
|
||||
permissions:
|
||||
contents: 'read'
|
||||
checks: 'write'
|
||||
|
|
@ -168,15 +196,15 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- os: 'macos-latest'
|
||||
runner: 'macos-latest'
|
||||
runner: '["macos-latest"]'
|
||||
node-version: '22.x'
|
||||
upload-coverage: 'false'
|
||||
- os: 'ubuntu-latest'
|
||||
runner: 'ubuntu-latest'
|
||||
runner: "${{ needs.classify_pr.outputs.ubuntu_runner || '[\"ubuntu-latest\"]' }}"
|
||||
node-version: '22.x'
|
||||
upload-coverage: 'true'
|
||||
- os: 'windows-latest'
|
||||
runner: 'windows-2022'
|
||||
runner: '["windows-2022"]'
|
||||
node-version: '22.x'
|
||||
upload-coverage: 'false'
|
||||
steps:
|
||||
|
|
@ -184,8 +212,9 @@ jobs:
|
|||
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
|
||||
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
|
||||
|
||||
- name: 'Set up Node.js ${{ matrix.node-version }}'
|
||||
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
|
||||
# Self-hosted can't reach nodejs.org reliably; reuse the machine's Node.
|
||||
- name: 'Set up Node.js ${{ matrix.node-version }} (hosted)'
|
||||
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' && runner.environment == 'github-hosted' }}"
|
||||
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
|
||||
with:
|
||||
node-version: '${{ matrix.node-version }}'
|
||||
|
|
@ -193,6 +222,18 @@ jobs:
|
|||
cache-dependency-path: 'package-lock.json'
|
||||
registry-url: 'https://registry.npmjs.org/'
|
||||
|
||||
- name: 'Use pre-installed Node.js (self-hosted)'
|
||||
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' && 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 ${{ matrix.node-version }} or set the MAINTAINER_ECS_RUNNER_DISABLED repository variable to 'true' to route PRs back to hosted runners."
|
||||
exit 1
|
||||
fi
|
||||
echo "Using pre-installed Node $(node -v) / npm $(npm -v)"
|
||||
if [[ "$(node -p 'process.versions.node.split(".")[0]')" != "22" ]]; then
|
||||
echo "::warning::Expected Node 22.x but found $(node -v); tests will run against the runner's Node."
|
||||
fi
|
||||
|
||||
- name: 'Configure npm for rate limiting'
|
||||
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
|
||||
run: |-
|
||||
|
|
|
|||
8
.github/workflows/qwen-code-pr-review.yml
vendored
8
.github/workflows/qwen-code-pr-review.yml
vendored
|
|
@ -70,7 +70,7 @@ jobs:
|
|||
concurrency:
|
||||
group: 'qwen-pr-ack-${{ github.event.issue.number || github.event.pull_request.number }}'
|
||||
cancel-in-progress: false
|
||||
runs-on: 'ubuntu-latest'
|
||||
runs-on: "${{ vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true' && fromJSON('[\"self-hosted\", \"linux\", \"x64\", \"ecs-qwen\"]') || fromJSON('[\"ubuntu-latest\"]') }}"
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
pull-requests: 'write'
|
||||
|
|
@ -112,7 +112,7 @@ jobs:
|
|||
if: |-
|
||||
github.event_name == 'pull_request_target' &&
|
||||
github.event.action == 'review_requested'
|
||||
runs-on: 'ubuntu-latest'
|
||||
runs-on: "${{ vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true' && fromJSON('[\"self-hosted\", \"linux\", \"x64\", \"ecs-qwen\"]') || fromJSON('[\"ubuntu-latest\"]') }}"
|
||||
permissions: {}
|
||||
outputs:
|
||||
bot_login: '${{ steps.values.outputs.bot_login }}'
|
||||
|
|
@ -131,7 +131,7 @@ jobs:
|
|||
github.event.pull_request.state == 'open' &&
|
||||
!github.event.pull_request.draft &&
|
||||
needs.authorize.outputs.should_review == 'true'
|
||||
runs-on: 'ubuntu-latest'
|
||||
runs-on: "${{ vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true' && fromJSON('[\"self-hosted\", \"linux\", \"x64\", \"ecs-qwen\"]') || fromJSON('[\"ubuntu-latest\"]') }}"
|
||||
# Configured in repo settings with a 30-minute wait timer.
|
||||
environment:
|
||||
name: 'qwen-pr-review-delay'
|
||||
|
|
@ -183,7 +183,7 @@ jobs:
|
|||
startsWith(github.event.comment.body, '@qwen-code /review')) ||
|
||||
(github.event_name == 'pull_request_review' &&
|
||||
startsWith(github.event.review.body, '@qwen-code /review')))
|
||||
runs-on: 'ubuntu-latest'
|
||||
runs-on: "${{ vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true' && fromJSON('[\"self-hosted\", \"linux\", \"x64\", \"ecs-qwen\"]') || fromJSON('[\"ubuntu-latest\"]') }}"
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: 'read'
|
||||
|
|
|
|||
2
.github/workflows/qwen-triage.yml
vendored
2
.github/workflows/qwen-triage.yml
vendored
|
|
@ -51,7 +51,7 @@ jobs:
|
|||
startsWith(github.event.comment.body, '@qwen-code /tmux '))) ||
|
||||
(github.event_name == 'workflow_dispatch' &&
|
||||
github.event.inputs.tmux_pr != ''))
|
||||
runs-on: 'ubuntu-latest'
|
||||
runs-on: "${{ vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true' && fromJSON('[\"self-hosted\", \"linux\", \"x64\", \"ecs-qwen\"]') || fromJSON('[\"ubuntu-latest\"]') }}"
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: 'read'
|
||||
|
|
|
|||
|
|
@ -3608,7 +3608,13 @@ describe('Linux/macOS installer end-to-end', { timeout: 15000 }, () => {
|
|||
const fakeBin = path.join(tmpDir, 'bin');
|
||||
mkdirSync(fakeBin, { recursive: true });
|
||||
writeFileSync(path.join(fakeBin, 'curl'), '#!/usr/bin/env sh\nexit 22\n');
|
||||
// Shadow any system Node on PATH (e.g. /usr/bin/node on self-hosted
|
||||
// runners) with a stub that fails version detection, so the npm fallback
|
||||
// deterministically fails with "Unable to determine Node.js version"
|
||||
// regardless of whether the host has Node installed in /usr/bin.
|
||||
writeFileSync(path.join(fakeBin, 'node'), '#!/usr/bin/env sh\nexit 1\n');
|
||||
chmodSync(path.join(fakeBin, 'curl'), 0o755);
|
||||
chmodSync(path.join(fakeBin, 'node'), 0o755);
|
||||
|
||||
let failureMessage = '';
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue