mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-23 10:55:31 -06:00
fix: keep CI running during Blacksmith outages (#123263)
* ci: add runner-backend circuit breaker with GitHub-hosted fallback * fix(ci): extend hosted timeouts to circuit-breaker runs
This commit is contained in:
committed by
GitHub
parent
9550d6f962
commit
fb82d87cad
@@ -175,12 +175,42 @@ These are intentionally guarded by `test/scripts/ci-workflow-guards.test.ts`:
|
||||
- lower-weight Node/check shards on `blacksmith-4vcpu-ubuntu-2404`.
|
||||
- heavy retained Linux/Android shards on `blacksmith-8vcpu-ubuntu-2404`.
|
||||
- CodeQL Critical Quality on `ubuntu-24.04` with no `blacksmith-` labels.
|
||||
- `OPENCLAW_CI_RUNNER_BACKEND=github` routes every configurable `ci.yml` job
|
||||
to its existing GitHub-hosted fallback label. Unset or `blacksmith` preserves
|
||||
the normal Blacksmith-first route.
|
||||
- Vitest/test compile caches are restore-only in CI and use immutable Actions
|
||||
caches; the daily/dispatch warmer is their sole writer. Build compile cache
|
||||
writes rotate at most once per UTC day. PRs create no runtime-cache archives.
|
||||
|
||||
When changing one knob, update `docs/ci.md` and the guard test in the same PR.
|
||||
|
||||
## Blacksmith Outage Circuit Breaker
|
||||
|
||||
Use the repository variable only after confirming a Blacksmith outage or
|
||||
unavailable runner capacity. Do not set it merely for a failing test that has
|
||||
already started.
|
||||
|
||||
```bash
|
||||
gh variable set OPENCLAW_CI_RUNNER_BACKEND --repo openclaw/openclaw --body github
|
||||
```
|
||||
|
||||
In degraded mode, `ci.yml` uses the same hosted labels and non-Blacksmith paths
|
||||
as manual dispatches and fork pull requests. Blacksmith-only Docker and sticky
|
||||
steps stay off, dependency setup uses the ordinary Actions pnpm-store cache,
|
||||
and Android's large build uses separate low-memory Gradle processes. Standard
|
||||
4-core hosted runners make builds and test lanes slower. Blacksmith runner
|
||||
registration is no longer part of the budget, while GitHub-hosted concurrency
|
||||
limits apply.
|
||||
|
||||
Flip back after the outage by deleting the variable:
|
||||
|
||||
```bash
|
||||
gh variable delete OPENCLAW_CI_RUNNER_BACKEND --repo openclaw/openclaw
|
||||
```
|
||||
|
||||
Scheduled health detection and automatic flipping are a follow-up, not part of
|
||||
the current circuit breaker.
|
||||
|
||||
## Validation
|
||||
|
||||
For workflow-only or docs/skill-only changes in a Codex worktree:
|
||||
|
||||
+78
-76
@@ -73,7 +73,7 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
outputs:
|
||||
checkout_revision: ${{ steps.checkout_ref.outputs.sha }}
|
||||
@@ -871,10 +871,11 @@ jobs:
|
||||
run: node scripts/check-protocol-event-coverage.mjs
|
||||
|
||||
# Publish one immutable semantic dependency archive before same-repo
|
||||
# Blacksmith jobs fan out. Pull-request archives remain merge-ref scoped;
|
||||
# Blacksmith jobs fan out. The GitHub backend uses the pnpm-store cache.
|
||||
# Pull-request archives remain merge-ref scoped;
|
||||
# main archives seed later pull requests through the default-branch scope.
|
||||
- name: Publish exact dependency cache
|
||||
if: github.repository == 'openclaw/openclaw' && steps.manifest.outputs.run_node == 'true' && ((github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository))
|
||||
if: vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.repository == 'openclaw/openclaw' && steps.manifest.outputs.run_node == 'true' && ((github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository))
|
||||
uses: ./.github/actions/setup-node-env
|
||||
with:
|
||||
dependency-cache: "true"
|
||||
@@ -1088,14 +1089,14 @@ jobs:
|
||||
run: node scripts/pre-commit/pnpm-audit-prod.mjs --audit-level=high
|
||||
|
||||
# Warm the lockfile- and pnpm-pinned Actions cache for fork PRs, manual runs,
|
||||
# and docs-only same-repo PRs. Node-relevant canonical main and same-repo PRs
|
||||
# already publish it through the exact dependency-cache writer in preflight.
|
||||
# the GitHub backend, and docs-only same-repo PRs. Node-relevant Blacksmith
|
||||
# runs already publish it through the exact dependency-cache writer in preflight.
|
||||
pnpm-store-warmup:
|
||||
permissions:
|
||||
contents: read
|
||||
needs: [preflight]
|
||||
if: ${{ (needs.preflight.outputs.run_node == 'true' || needs.preflight.outputs.run_check_docs == 'true') && !(github.repository == 'openclaw/openclaw' && github.event_name == 'push' && github.ref == 'refs/heads/main') && !(github.repository == 'openclaw/openclaw' && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && needs.preflight.outputs.run_node == 'true') }}
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
if: ${{ (needs.preflight.outputs.run_node == 'true' || needs.preflight.outputs.run_check_docs == 'true') && (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || (!(github.repository == 'openclaw/openclaw' && github.event_name == 'push' && github.ref == 'refs/heads/main') && !(github.repository == 'openclaw/openclaw' && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && needs.preflight.outputs.run_node == 'true'))) }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- &linux_node_checkout_step
|
||||
@@ -1165,8 +1166,8 @@ jobs:
|
||||
# 32 vCPU: the dist build sits on the light-run critical path alongside
|
||||
# check-lint/check-dependencies; tsdown parallelizes across the extra
|
||||
# cores for roughly the same billed core-minutes.
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-32vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && 35 || 20 }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-32vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: ${{ (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository)) && 35 || 20 }}
|
||||
outputs:
|
||||
channels-result: ${{ steps.built_artifact_checks.outputs['channels-result'] }}
|
||||
core-support-boundary-result: ${{ steps.built_artifact_checks.outputs['core-support-boundary-result'] }}
|
||||
@@ -1189,8 +1190,8 @@ jobs:
|
||||
node-compile-cache-scope: "build"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
save-node-compile-cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'true' || 'false' }}
|
||||
|
||||
- name: Restore build-all step cache
|
||||
@@ -1448,7 +1449,7 @@ jobs:
|
||||
name: check-sqlite-session-lifecycle
|
||||
needs: [preflight, build-artifacts]
|
||||
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_sqlite_session_lifecycle == 'true' && needs.build-artifacts.result == 'success' }}
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- *linux_node_checkout_step
|
||||
@@ -1456,8 +1457,8 @@ jobs:
|
||||
uses: ./.github/actions/setup-node-env
|
||||
with:
|
||||
install-bun: "false"
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- name: Download exact-run built runtime
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
@@ -1479,7 +1480,7 @@ jobs:
|
||||
contents: read
|
||||
needs: [preflight]
|
||||
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_native_i18n == 'true' }}
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -1494,8 +1495,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- name: Verify native app i18n source
|
||||
run: |
|
||||
@@ -1523,7 +1524,7 @@ jobs:
|
||||
name: checks-ui
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_ui_tests == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
COMPATIBILITY_TARGET: ${{ needs.preflight.outputs.compatibility_target }}
|
||||
@@ -1536,8 +1537,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- &install_playwright_chromium
|
||||
name: Install Playwright Chromium
|
||||
@@ -1582,9 +1583,9 @@ jobs:
|
||||
# Compatibility targets pin a frozen Control UI whose e2e expectations track
|
||||
# that release, not current main.
|
||||
if: needs.preflight.outputs.run_ui_tests == 'true' && needs.preflight.outputs.compatibility_target != 'true'
|
||||
# First-attempt same-repo runs use Blacksmith; manual dispatches, forks, and
|
||||
# same-repo PR retries use GitHub-hosted capacity as an independent fallback.
|
||||
runs-on: ${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
# First-attempt same-repo runs use Blacksmith unless the backend breaker is
|
||||
# set; manual dispatches, forks, and same-repo PR retries also use GitHub-hosted capacity.
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
# Keep Chromium ownership serial within each independently required shard.
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
@@ -1603,8 +1604,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Hosted paths use the pnpm store cache; first-attempt same-repo
|
||||
# Blacksmith runs restore the preflight-published dependency tree.
|
||||
dependency-cache: ${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'false' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false') }}
|
||||
use-actions-cache: ${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'true' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true') }}
|
||||
dependency-cache: ${{ (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'false' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false') }}
|
||||
use-actions-cache: ${{ (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'true' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true') }}
|
||||
|
||||
- *install_playwright_chromium
|
||||
|
||||
@@ -1628,9 +1629,9 @@ jobs:
|
||||
# Compatibility targets pin a frozen Control UI whose e2e expectations track
|
||||
# that release, not current main.
|
||||
if: needs.preflight.outputs.run_ui_tests == 'true' && needs.preflight.outputs.compatibility_target != 'true'
|
||||
# First-attempt same-repo runs use Blacksmith; manual dispatches, forks, and
|
||||
# same-repo PR retries use GitHub-hosted capacity as an independent fallback.
|
||||
runs-on: ${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
# First-attempt same-repo runs use Blacksmith unless the backend breaker is
|
||||
# set; manual dispatches, forks, and same-repo PR retries also use GitHub-hosted capacity.
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- *linux_node_checkout_step
|
||||
@@ -1641,8 +1642,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Hosted paths use the pnpm store cache; first-attempt same-repo
|
||||
# Blacksmith runs restore the preflight-published dependency tree.
|
||||
dependency-cache: ${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'false' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false') }}
|
||||
use-actions-cache: ${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'true' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true') }}
|
||||
dependency-cache: ${{ (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'false' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false') }}
|
||||
use-actions-cache: ${{ (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'true' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true') }}
|
||||
|
||||
- *install_playwright_chromium
|
||||
|
||||
@@ -1666,7 +1667,7 @@ jobs:
|
||||
name: control-ui-i18n
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_control_ui_i18n == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
COMPATIBILITY_TARGET: ${{ needs.preflight.outputs.compatibility_target }}
|
||||
@@ -1679,8 +1680,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- name: Verify Control UI i18n source
|
||||
run: |
|
||||
@@ -1706,7 +1707,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_checks_fast_core == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -1767,8 +1768,8 @@ jobs:
|
||||
install-bun: ${{ matrix.task == 'bun-launcher' && 'true' || 'false' }}
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- name: Run ${{ matrix.task }} (${{ matrix.runtime }})
|
||||
env:
|
||||
@@ -1844,7 +1845,7 @@ jobs:
|
||||
name: QA Smoke CI (${{ matrix.name }})
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_qa_smoke_ci == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -1872,11 +1873,11 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- name: Set up Blacksmith Docker layer cache
|
||||
if: ${{ matrix.docker_cache == true && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') }}
|
||||
if: ${{ matrix.docker_cache == true && vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') }}
|
||||
uses: useblacksmith/setup-docker-builder@6ff44f8e5255f9d8aa31ef22f7e57a2d926b7da0 # v1
|
||||
with:
|
||||
max-cache-size-mb: 800000
|
||||
@@ -1908,7 +1909,7 @@ jobs:
|
||||
env:
|
||||
PROFILE_PART: ${{ matrix.lane }}
|
||||
PROFILE_PART_SLUG: ${{ matrix.slug }}
|
||||
OPENCLAW_QA_SUITE_WORKER_START_STAGGER_MS: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && '0' || '1500' }}
|
||||
OPENCLAW_QA_SUITE_WORKER_START_STAGGER_MS: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && '0' || '1500' }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -2038,7 +2039,7 @@ jobs:
|
||||
name: ${{ matrix.checkName }}
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_plugin_contracts_shards == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -2052,8 +2053,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- name: Run plugin contract shard
|
||||
env:
|
||||
@@ -2080,7 +2081,7 @@ jobs:
|
||||
name: ${{ matrix.checkName }}
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_channel_contracts_shards == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -2094,8 +2095,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- name: Run channel contract shard
|
||||
env:
|
||||
@@ -2123,7 +2124,7 @@ jobs:
|
||||
name: checks-node-compat-node22
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_build_artifacts == 'true' && github.event_name == 'workflow_dispatch'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- *linux_node_checkout_step
|
||||
@@ -2153,7 +2154,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_checks_node_core_nondist == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
|
||||
timeout-minutes: ${{ matrix.timeout_minutes || 60 }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -2170,8 +2171,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Only the preflight writer saves an archive. Same-repo Blacksmith
|
||||
# shards restore it; hosted and non-Node-24 paths use the pnpm store.
|
||||
dependency-cache: ${{ (matrix.node_version == null || matrix.node_version == '24.x') && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ (matrix.node_version == null || matrix.node_version == '24.x') && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ (matrix.node_version == null || matrix.node_version == '24.x') && vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ (matrix.node_version == null || matrix.node_version == '24.x') && vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
vitest-fs-cache: "true"
|
||||
node-compile-cache: "true"
|
||||
node-compile-cache-scope: "test"
|
||||
@@ -2264,7 +2265,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check == 'true' }}
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -2306,15 +2307,15 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
# check-lint's shard runner rebuilds the same plugin-sdk boundary
|
||||
# artifacts the boundary lane snapshots (~72s cold); restore them from
|
||||
# the shared sticky. Strictly read-only (commit: false): only the
|
||||
# protected boundary lane may publish this repository-global snapshot.
|
||||
- name: Mount extension boundary sticky disk
|
||||
if: matrix.task == 'lint' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
if: matrix.task == 'lint' && vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
uses: useblacksmith/stickydisk@6d373c96a74cbde0c99fedc5ea5d3a7ba66ba494 # main (post-v1.4.0 hot-attach fix)
|
||||
with:
|
||||
# One stable disk for the whole repository. The v1 per-PR/per-config
|
||||
@@ -2327,7 +2328,7 @@ jobs:
|
||||
commit: "false"
|
||||
|
||||
- name: Restore extension boundary artifacts from sticky disk
|
||||
if: matrix.task == 'lint' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
if: matrix.task == 'lint' && vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
shell: bash
|
||||
env:
|
||||
# Config/toolchain inputs the tree-OID gate below cannot see; must
|
||||
@@ -2544,7 +2545,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check_additional == 'true' }}
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -2610,8 +2611,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
# Same-repo runs carry boundary artifacts on a Blacksmith sticky disk:
|
||||
# the GitHub cache below is evicted so quickly under the repo quota that
|
||||
@@ -2619,7 +2620,7 @@ jobs:
|
||||
# plugin-sdk declarations. Fork PRs must never produce writable
|
||||
# repository-global snapshots, so they keep the GitHub cache path.
|
||||
- name: Mount extension boundary sticky disk
|
||||
if: matrix.group == 'extension-package-boundary' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
if: matrix.group == 'extension-package-boundary' && vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
uses: useblacksmith/stickydisk@6d373c96a74cbde0c99fedc5ea5d3a7ba66ba494 # main (post-v1.4.0 hot-attach fix)
|
||||
with:
|
||||
# One stable disk for the whole repository. The v1 per-PR/per-config
|
||||
@@ -2640,7 +2641,7 @@ jobs:
|
||||
|
||||
- name: Restore extension boundary artifacts from sticky disk
|
||||
id: boundary-sticky-restore
|
||||
if: matrix.group == 'extension-package-boundary' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
if: matrix.group == 'extension-package-boundary' && vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
shell: bash
|
||||
env:
|
||||
# Config/toolchain inputs the tree-OID gate below cannot see; must
|
||||
@@ -2861,7 +2862,7 @@ jobs:
|
||||
# clone). Seed the payload before the sticky post-action flushes.
|
||||
# rsync -aR mirrors the repo-relative layout the restore step replays.
|
||||
- name: Seed extension boundary sticky disk
|
||||
if: success() && steps.boundary-sticky-restore.outputs.restored == 'false' && matrix.group == 'extension-package-boundary' && github.event_name != 'workflow_dispatch' && github.event_name != 'pull_request' && github.repository == 'openclaw/openclaw'
|
||||
if: success() && steps.boundary-sticky-restore.outputs.restored == 'false' && matrix.group == 'extension-package-boundary' && vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.event_name != 'pull_request' && github.repository == 'openclaw/openclaw'
|
||||
shell: bash
|
||||
env:
|
||||
# Must stay identical to the restore gates above.
|
||||
@@ -2889,7 +2890,7 @@ jobs:
|
||||
contents: read
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_check_docs == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- *linux_node_checkout_step
|
||||
@@ -2899,8 +2900,8 @@ jobs:
|
||||
install-bun: "false"
|
||||
# Same-repo Blacksmith runs restore the dependency cache published by
|
||||
# preflight; hosted paths use the pnpm store cache instead.
|
||||
dependency-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
dependency-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- name: Check formatting
|
||||
if: needs.preflight.outputs.run_format_check == 'true'
|
||||
@@ -2958,7 +2959,7 @@ jobs:
|
||||
contents: read
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_skills_python_job == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -3013,7 +3014,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_checks_windows == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'windows-2025' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-8vcpu-windows-2025') || 'windows-2025') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'windows-2025' || github.event_name == 'workflow_dispatch' && 'windows-2025' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && (matrix.runner || 'blacksmith-8vcpu-windows-2025') || 'windows-2025') }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
@@ -3159,7 +3160,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_macos_node == 'true' }}
|
||||
runs-on: ${{ (github.event_name == 'workflow_dispatch' || github.run_attempt > 1) && 'macos-15' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-6vcpu-macos-15' || 'macos-15') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'macos-15' || (github.event_name == 'workflow_dispatch' || github.run_attempt > 1) && 'macos-15' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-6vcpu-macos-15' || 'macos-15') }}
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -3198,10 +3199,10 @@ jobs:
|
||||
name: "macos-swift"
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_macos_swift == 'true'
|
||||
runs-on: ${{ (github.event_name == 'workflow_dispatch' || github.run_attempt > 1) && 'macos-26' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-12vcpu-macos-26' || 'macos-26') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'macos-26' || (github.event_name == 'workflow_dispatch' || github.run_attempt > 1) && 'macos-26' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-12vcpu-macos-26' || 'macos-26') }}
|
||||
# Hosted runs may still be finalizing large Swift caches after every test
|
||||
# passes; keep that post-job work non-blocking.
|
||||
timeout-minutes: ${{ (github.event_name == 'workflow_dispatch' || github.run_attempt > 1) && 30 || 20 }}
|
||||
timeout-minutes: ${{ (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || github.event_name == 'workflow_dispatch' || github.run_attempt > 1) && 30 || 20 }}
|
||||
env:
|
||||
HISTORICAL_TARGET: ${{ needs.preflight.outputs.compatibility_target }}
|
||||
SWIFT_TEST_EXECUTION: ${{ (github.event_name == 'workflow_dispatch' || github.run_attempt > 1) && 'serial' || 'parallel' }}
|
||||
@@ -3417,7 +3418,7 @@ jobs:
|
||||
name: "ios-build"
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_ios_build == 'true'
|
||||
runs-on: ${{ (github.event_name == 'workflow_dispatch' || github.run_attempt > 1) && 'macos-26' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-12vcpu-macos-26' || 'macos-26') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'macos-26' || (github.event_name == 'workflow_dispatch' || github.run_attempt > 1) && 'macos-26' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-12vcpu-macos-26' || 'macos-26') }}
|
||||
timeout-minutes: 150
|
||||
env:
|
||||
HISTORICAL_TARGET: ${{ needs.preflight.outputs.compatibility_target }}
|
||||
@@ -3598,7 +3599,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_android_job == 'true'
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
runs-on: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -3672,11 +3673,11 @@ jobs:
|
||||
# build caches) on a Blacksmith sticky disk: the setup-java gradle cache
|
||||
# above is evicted so quickly under the repo quota that it rarely
|
||||
# restores, leaving every run to re-resolve the full dependency graph.
|
||||
# Fork PRs and manual dispatches must never produce writable
|
||||
# Fork PRs, manual dispatches, and the GitHub backend must never produce writable
|
||||
# repository-global snapshots, so they keep the GitHub cache path (their
|
||||
# runs-on already selects non-Blacksmith ubuntu-24.04 runners).
|
||||
- name: Mount Gradle sticky disk
|
||||
if: github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
if: vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
uses: useblacksmith/stickydisk@6d373c96a74cbde0c99fedc5ea5d3a7ba66ba494 # main (post-v1.4.0 hot-attach fix)
|
||||
with:
|
||||
# One stable disk per matrix task. The v1 per-PR/per-dependency-hash
|
||||
@@ -3698,7 +3699,7 @@ jobs:
|
||||
commit: ${{ github.event_name != 'pull_request' && 'true' || 'false' }}
|
||||
|
||||
- name: Point Gradle at the sticky disk
|
||||
if: github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
if: vars.OPENCLAW_CI_RUNNER_BACKEND != 'github' && github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw')
|
||||
shell: bash
|
||||
env:
|
||||
# Gradle caches are content-addressed, so a stale snapshot is safe
|
||||
@@ -3731,6 +3732,7 @@ jobs:
|
||||
- name: Run Android ${{ matrix.task }}
|
||||
working-directory: apps/android
|
||||
env:
|
||||
CI_RUNNER_BACKEND: ${{ vars.OPENCLAW_CI_RUNNER_BACKEND }}
|
||||
TASK: ${{ matrix.task }}
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -3753,7 +3755,7 @@ jobs:
|
||||
./gradlew --no-daemon --build-cache :wear:testDebugUnitTest
|
||||
;;
|
||||
build-play)
|
||||
if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then
|
||||
if [ "$CI_RUNNER_BACKEND" = "github" ] || [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then
|
||||
# GitHub-hosted runners have less memory headroom. Separate Gradle
|
||||
# processes release each variant's build state before the next starts.
|
||||
./gradlew --no-daemon --build-cache \
|
||||
|
||||
+19
-1
@@ -202,6 +202,24 @@ for commands and recovery.
|
||||
| `blacksmith-6vcpu-macos-15` | `macos-node` on `openclaw/openclaw`; forks fall back to `macos-15` |
|
||||
| `blacksmith-12vcpu-macos-26` | `macos-swift` and `ios-build` on `openclaw/openclaw`; forks fall back to `macos-26` |
|
||||
|
||||
### Blacksmith outage circuit breaker
|
||||
|
||||
The repository variable `OPENCLAW_CI_RUNNER_BACKEND` controls the runner backend for `ci.yml`. Leave it unset or set it to `blacksmith` for the normal Blacksmith-first routing. During a Blacksmith outage, set it to `github` to send every configurable CI job to that job's existing GitHub-hosted fallback label:
|
||||
|
||||
```bash
|
||||
gh variable set OPENCLAW_CI_RUNNER_BACKEND --repo openclaw/openclaw --body github
|
||||
```
|
||||
|
||||
Degraded mode uses the same hosted paths exercised by manual dispatches and fork pull requests. Blacksmith-only Docker and sticky-disk steps are skipped, dependency setup uses the ordinary Actions pnpm-store cache, and low-memory Android builds use separate Gradle processes. Expect slower builds and test lanes on standard 4-core hosted runners. Blacksmith's runner-registration budget is irrelevant while the breaker is active, but GitHub-hosted concurrency limits apply.
|
||||
|
||||
Flip back after the outage by deleting the variable, which restores the default behavior:
|
||||
|
||||
```bash
|
||||
gh variable delete OPENCLAW_CI_RUNNER_BACKEND --repo openclaw/openclaw
|
||||
```
|
||||
|
||||
Scheduled health detection and automatic flipping are an explicit follow-up; `ci.yml` does not probe Blacksmith or mutate this variable.
|
||||
|
||||
## Runner registration budget
|
||||
|
||||
OpenClaw's current GitHub runner-registration bucket reports 10,000 self-hosted
|
||||
@@ -222,7 +240,7 @@ concurrent repositories, retries, and burst overlap.
|
||||
|
||||
The changed-target PR plan reduces the common Node test burst from 14 Blacksmith registrations to one. Broad-risk PRs keep the 14-registration compact fallback, so the worst case does not increase.
|
||||
|
||||
Canonical-repo CI keeps Blacksmith as the default runner path for pushes and first-attempt same-repo pull-request runs. Pull-request retries of both UI E2E jobs use GitHub-hosted Ubuntu; push retries stay on Blacksmith. All `workflow_dispatch` runs, including `release_gate`, and non-canonical repository runs use GitHub-hosted runners. Normal canonical runs do not currently probe Blacksmith queue health or automatically fall back to GitHub-hosted labels when Blacksmith is unavailable.
|
||||
Canonical-repo CI keeps Blacksmith as the default runner path for pushes and first-attempt same-repo pull-request runs. Pull-request retries of both UI E2E jobs use GitHub-hosted Ubuntu; push retries stay on Blacksmith. All `workflow_dispatch` runs, including `release_gate`, and non-canonical repository runs use GitHub-hosted runners. The [Blacksmith outage circuit breaker](#blacksmith-outage-circuit-breaker) provides a manual repository-wide fallback; canonical runs do not probe Blacksmith queue health or flip it automatically.
|
||||
|
||||
## Surface ratchets
|
||||
|
||||
|
||||
@@ -80,7 +80,9 @@ function evaluateWorkflowExpression(
|
||||
context: {
|
||||
eventName: "pull_request" | "push" | "workflow_dispatch";
|
||||
headRepository?: string;
|
||||
matrix?: Record<string, unknown>;
|
||||
repository: string;
|
||||
runnerBackend?: "" | "blacksmith" | "github";
|
||||
runAttempt: number;
|
||||
},
|
||||
) {
|
||||
@@ -108,6 +110,10 @@ function evaluateWorkflowExpression(
|
||||
}
|
||||
: {},
|
||||
},
|
||||
matrix: context.matrix ?? {},
|
||||
vars: {
|
||||
OPENCLAW_CI_RUNNER_BACKEND: context.runnerBackend ?? "",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2753,9 +2759,9 @@ NODE
|
||||
);
|
||||
const buildPlayBranches = expectDefined(
|
||||
buildPlayCase.match(
|
||||
/if \[ "\$GITHUB_EVENT_NAME" = "workflow_dispatch" \]; then\n([\s\S]*?)\n\s*else\n([\s\S]*?)\n\s*fi/u,
|
||||
/if \[ "\$CI_RUNNER_BACKEND" = "github" \] \|\| \[ "\$GITHUB_EVENT_NAME" = "workflow_dispatch" \]; then\n([\s\S]*?)\n\s*else\n([\s\S]*?)\n\s*fi/u,
|
||||
),
|
||||
"Android build-play event branches",
|
||||
"Android build-play runner branches",
|
||||
);
|
||||
const dispatchBuild = expectDefined(buildPlayBranches[1], "hosted dispatch build branch");
|
||||
const blacksmithBuild = expectDefined(buildPlayBranches[2], "Blacksmith build branch");
|
||||
@@ -2772,8 +2778,9 @@ NODE
|
||||
expect(source).toContain('task: useCompatibleAndroidCi ? "build-play-compat" : "build-play"');
|
||||
expect(androidJob.name).toBe("${{ matrix.check_name }}");
|
||||
expect(androidJob["runs-on"]).toBe(
|
||||
"${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}",
|
||||
"${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}",
|
||||
);
|
||||
expect(runStep.env.CI_RUNNER_BACKEND).toBe("${{ vars.OPENCLAW_CI_RUNNER_BACKEND }}");
|
||||
expect(runStep.run).toContain(":app:testPlayDebugUnitTest");
|
||||
expect(runStep.run).toContain(":app:testThirdPartyDebugUnitTest");
|
||||
expect(dispatchBuild.match(/^\s*\.\/gradlew\b/gmu)).toHaveLength(3);
|
||||
@@ -2843,6 +2850,110 @@ NODE
|
||||
expect(workflow.jobs["pnpm-store-warmup"]["runs-on"]).toContain("blacksmith-4vcpu-ubuntu-2404");
|
||||
});
|
||||
|
||||
it("routes every configurable CI job to GitHub-hosted runners when the backend breaker is set", () => {
|
||||
const workflow = readCiWorkflow();
|
||||
const jobs = workflow.jobs as Record<string, { "runs-on": unknown }>;
|
||||
const expectedHostedRunners = {
|
||||
android: "ubuntu-24.04",
|
||||
"build-artifacts": "ubuntu-24.04",
|
||||
"check-additional-shard": "ubuntu-24.04",
|
||||
"check-docs": "ubuntu-24.04",
|
||||
"check-shard": "ubuntu-24.04",
|
||||
"checks-fast-channel-contracts-shard": "ubuntu-24.04",
|
||||
"checks-fast-core": "ubuntu-24.04",
|
||||
"checks-fast-plugin-contracts-shard": "ubuntu-24.04",
|
||||
"checks-node-compat": "ubuntu-24.04",
|
||||
"checks-node-core-test-nondist-shard": "ubuntu-24.04",
|
||||
"checks-ui": "ubuntu-24.04",
|
||||
"checks-ui-e2e": "ubuntu-24.04",
|
||||
"checks-ui-e2e-real-gateway": "ubuntu-24.04",
|
||||
"control-ui-i18n": "ubuntu-24.04",
|
||||
"ios-build": "macos-26",
|
||||
"macos-node": "macos-15",
|
||||
"macos-swift": "macos-26",
|
||||
"native-i18n": "ubuntu-24.04",
|
||||
"pnpm-store-warmup": "ubuntu-24.04",
|
||||
preflight: "ubuntu-24.04",
|
||||
"qa-smoke-ci-profile": "ubuntu-24.04",
|
||||
"skills-python": "ubuntu-24.04",
|
||||
"sqlite-session-lifecycle": "ubuntu-24.04",
|
||||
"checks-windows": "windows-2025",
|
||||
} as const;
|
||||
const configurableJobs = Object.entries(jobs)
|
||||
.filter(([, job]) => String(job["runs-on"]).startsWith("${{"))
|
||||
.map(([jobName]) => jobName)
|
||||
.toSorted();
|
||||
const canonicalPullRequest = {
|
||||
eventName: "pull_request",
|
||||
headRepository: "openclaw/openclaw",
|
||||
matrix: { runner: "blacksmith-32vcpu-ubuntu-2404" },
|
||||
repository: "openclaw/openclaw",
|
||||
runAttempt: 1,
|
||||
} as const;
|
||||
|
||||
expect(configurableJobs).toEqual(Object.keys(expectedHostedRunners).toSorted());
|
||||
for (const [jobName, hostedRunner] of Object.entries(expectedHostedRunners)) {
|
||||
const expression = jobs[jobName]?.["runs-on"];
|
||||
expect(expression, jobName).toContain("vars.OPENCLAW_CI_RUNNER_BACKEND == 'github'");
|
||||
expect(
|
||||
evaluateWorkflowExpression(expression, {
|
||||
...canonicalPullRequest,
|
||||
runnerBackend: "github",
|
||||
}),
|
||||
jobName,
|
||||
).toBe(hostedRunner);
|
||||
expect(
|
||||
evaluateWorkflowExpression(expression, {
|
||||
...canonicalPullRequest,
|
||||
runnerBackend: "blacksmith",
|
||||
}),
|
||||
jobName,
|
||||
).toBe(evaluateWorkflowExpression(expression, canonicalPullRequest));
|
||||
}
|
||||
});
|
||||
|
||||
it("gives breaker-routed hosted jobs their hosted timeout budgets", () => {
|
||||
const workflow = readCiWorkflow();
|
||||
const jobs = workflow.jobs as Record<string, { "timeout-minutes": unknown }>;
|
||||
const expectedHostedTimeouts = {
|
||||
"build-artifacts": 35,
|
||||
"macos-swift": 30,
|
||||
} as const;
|
||||
const routeDependentTimeoutJobs = Object.entries(jobs)
|
||||
.filter(([, job]) => {
|
||||
const timeout = job["timeout-minutes"];
|
||||
return typeof timeout === "string" && timeout.includes("github.");
|
||||
})
|
||||
.map(([jobName]) => jobName)
|
||||
.toSorted();
|
||||
const canonicalPullRequest = {
|
||||
eventName: "pull_request",
|
||||
headRepository: "openclaw/openclaw",
|
||||
repository: "openclaw/openclaw",
|
||||
runAttempt: 1,
|
||||
} as const;
|
||||
|
||||
expect(routeDependentTimeoutJobs).toEqual(Object.keys(expectedHostedTimeouts).toSorted());
|
||||
for (const [jobName, hostedTimeout] of Object.entries(expectedHostedTimeouts)) {
|
||||
const expression = jobs[jobName]?.["timeout-minutes"];
|
||||
expect(expression, jobName).toContain("vars.OPENCLAW_CI_RUNNER_BACKEND == 'github'");
|
||||
expect(
|
||||
evaluateWorkflowExpression(expression, {
|
||||
...canonicalPullRequest,
|
||||
runnerBackend: "github",
|
||||
}),
|
||||
jobName,
|
||||
).toBe(hostedTimeout);
|
||||
expect(
|
||||
evaluateWorkflowExpression(expression, {
|
||||
...canonicalPullRequest,
|
||||
runnerBackend: "blacksmith",
|
||||
}),
|
||||
jobName,
|
||||
).toBe(20);
|
||||
}
|
||||
});
|
||||
|
||||
it("scans only the pull request commit range for leaked credentials", () => {
|
||||
const securitySteps = readCiWorkflow().jobs["security-fast"].steps as WorkflowStep[];
|
||||
const fetchScanHistoryIndex = securitySteps.findIndex(
|
||||
@@ -2995,6 +3106,10 @@ NODE
|
||||
});
|
||||
expect(writers[0]?.step.if).toContain("github.ref == 'refs/heads/main'");
|
||||
expect(writers[0]?.step.if).toContain("github.event_name == 'pull_request'");
|
||||
expect(writers[0]?.step.if).toContain("vars.OPENCLAW_CI_RUNNER_BACKEND != 'github'");
|
||||
expect(workflow.jobs["pnpm-store-warmup"].if).toContain(
|
||||
"vars.OPENCLAW_CI_RUNNER_BACKEND == 'github'",
|
||||
);
|
||||
const consumers = dependencySetups.filter(({ jobName }) => jobName !== "preflight");
|
||||
expect(consumers.map(({ jobName }) => jobName).toSorted()).toEqual([
|
||||
"build-artifacts",
|
||||
@@ -3019,6 +3134,29 @@ NODE
|
||||
expect(consumer.with, jobName).not.toHaveProperty("save-dependency-cache");
|
||||
expect(consumer.with?.["dependency-cache"], jobName).toContain("'true' || 'false'");
|
||||
expect(consumer.with?.["use-actions-cache"], jobName).toContain("'false' || 'true'");
|
||||
expect(consumer.with?.["dependency-cache"], jobName).toContain(
|
||||
"vars.OPENCLAW_CI_RUNNER_BACKEND",
|
||||
);
|
||||
expect(
|
||||
evaluateWorkflowExpression(consumer.with?.["dependency-cache"], {
|
||||
eventName: "push",
|
||||
matrix: { node_version: "24.x" },
|
||||
repository: "openclaw/openclaw",
|
||||
runnerBackend: "github",
|
||||
runAttempt: 1,
|
||||
}),
|
||||
jobName,
|
||||
).toBe("false");
|
||||
expect(
|
||||
evaluateWorkflowExpression(consumer.with?.["use-actions-cache"], {
|
||||
eventName: "push",
|
||||
matrix: { node_version: "24.x" },
|
||||
repository: "openclaw/openclaw",
|
||||
runnerBackend: "github",
|
||||
runAttempt: 1,
|
||||
}),
|
||||
jobName,
|
||||
).toBe("true");
|
||||
}
|
||||
for (const { jobName, step: setup } of Object.entries(workflow.jobs).flatMap(([jobName, job]) =>
|
||||
((job as { steps?: WorkflowStep[] }).steps ?? [])
|
||||
@@ -3638,7 +3776,7 @@ server.listen(0, "127.0.0.1", () => writeFileSync(readyPath, String(server.addre
|
||||
expect(source).toContain("createNodeTestShardBundles");
|
||||
expect(workflow.jobs["build-artifacts"]["runs-on"]).toContain("blacksmith-32vcpu-ubuntu-2404");
|
||||
expect(workflow.jobs["build-artifacts"]["timeout-minutes"]).toBe(
|
||||
"${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && 35 || 20 }}",
|
||||
"${{ (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository)) && 35 || 20 }}",
|
||||
);
|
||||
expect(buildArtifactsTestbox.jobs["build-artifacts"]["runs-on"]).toBe(
|
||||
"blacksmith-16vcpu-ubuntu-2404",
|
||||
@@ -3705,6 +3843,9 @@ server.listen(0, "127.0.0.1", () => writeFileSync(readyPath, String(server.addre
|
||||
);
|
||||
expect(boundaryMount.with.key).toBe("${{ github.repository }}-ext-boundary-v2");
|
||||
expect(lintMount.with.key).toBe(boundaryMount.with.key);
|
||||
for (const gate of [boundaryMount, lintMount]) {
|
||||
expect(gate.if).toContain("vars.OPENCLAW_CI_RUNNER_BACKEND != 'github'");
|
||||
}
|
||||
// Single semantic writer: protected pushes commit explicitly (not
|
||||
// on-change/if-missing, whose allocated-byte heuristic can strand a stale
|
||||
// marker); PR clones and the lint consumer stay read-only.
|
||||
@@ -3731,6 +3872,7 @@ server.listen(0, "127.0.0.1", () => writeFileSync(readyPath, String(server.addre
|
||||
expect(lintRestoreStep.env.BOUNDARY_CONFIG_HASH).toBe(configHash);
|
||||
for (const gate of [restoreStep, lintRestoreStep, seedStep]) {
|
||||
expect(gate.run).toContain('echo "$BOUNDARY_CONFIG_HASH"');
|
||||
expect(gate.if).toContain("vars.OPENCLAW_CI_RUNNER_BACKEND != 'github'");
|
||||
}
|
||||
// Seeding is writer-only work: PR mounts never commit, so seeding there
|
||||
// would burn wall clock on a discarded clone.
|
||||
@@ -3756,6 +3898,10 @@ server.listen(0, "127.0.0.1", () => writeFileSync(readyPath, String(server.addre
|
||||
// minted a backing disk per PR/bump until Blacksmith's installation-wide
|
||||
// budget 429-failed every mount fleet-wide.
|
||||
expect(mountWith.key).toBe("${{ github.repository }}-gradle-v2-${{ matrix.task }}");
|
||||
expect(androidSteps.find((step) => step.name === "Mount Gradle sticky disk")?.if).toContain(
|
||||
"vars.OPENCLAW_CI_RUNNER_BACKEND != 'github'",
|
||||
);
|
||||
expect(pointStep.if).toContain("vars.OPENCLAW_CI_RUNNER_BACKEND != 'github'");
|
||||
// Single semantic writer: protected pushes commit explicitly (on-change's
|
||||
// allocated-byte heuristic can miss a same-size refresh and strand the
|
||||
// fingerprint marker); PR clones stay read-only.
|
||||
@@ -5579,9 +5725,9 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
||||
"node-version": "24.x",
|
||||
"install-bun": "false",
|
||||
"dependency-cache":
|
||||
"${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'false' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false') }}",
|
||||
"${{ (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'false' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false') }}",
|
||||
"use-actions-cache":
|
||||
"${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'true' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true') }}",
|
||||
"${{ (vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'true' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true') }}",
|
||||
} as const;
|
||||
expect(uiE2eSetup.with).toEqual(expectedUiE2eSetup);
|
||||
const realGatewaySetup = expectDefined(
|
||||
@@ -5615,6 +5761,17 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
||||
},
|
||||
expected: { blacksmith: true, dependencyCache: "true", useActionsCache: "false" },
|
||||
},
|
||||
{
|
||||
name: "same-repo pull request with GitHub backend",
|
||||
context: {
|
||||
eventName: "pull_request",
|
||||
headRepository: "openclaw/openclaw",
|
||||
repository: "openclaw/openclaw",
|
||||
runnerBackend: "github",
|
||||
runAttempt: 1,
|
||||
},
|
||||
expected: { blacksmith: false, dependencyCache: "false", useActionsCache: "true" },
|
||||
},
|
||||
{
|
||||
name: "same-repo pull request retry",
|
||||
context: {
|
||||
@@ -5656,7 +5813,7 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
||||
] as const;
|
||||
for (const { blacksmithRunner, job, name: jobName, setup } of routedUiE2eJobs) {
|
||||
expect(job["runs-on"]).toBe(
|
||||
"${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && '" +
|
||||
"${{ vars.OPENCLAW_CI_RUNNER_BACKEND == 'github' && 'ubuntu-24.04' || (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.run_attempt > 1)) && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && '" +
|
||||
blacksmithRunner +
|
||||
"' || 'ubuntu-24.04') }}",
|
||||
);
|
||||
@@ -7413,6 +7570,7 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
||||
"useblacksmith/setup-docker-builder@6ff44f8e5255f9d8aa31ef22f7e57a2d926b7da0",
|
||||
);
|
||||
expect(smokeDockerCacheStep.if).toContain("matrix.docker_cache == true");
|
||||
expect(smokeDockerCacheStep.if).toContain("vars.OPENCLAW_CI_RUNNER_BACKEND != 'github'");
|
||||
expect(smokeDockerCacheStep.if).toContain("github.event_name != 'workflow_dispatch'");
|
||||
expect(smokeDockerCacheStep.if).toContain("github.repository == 'openclaw/openclaw'");
|
||||
expect(smokeDockerCacheStep.if).toContain(
|
||||
@@ -7450,6 +7608,9 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
||||
expect(smokeRunStep.env.OPENCLAW_QA_SUITE_WORKER_START_STAGGER_MS).toContain(
|
||||
"github.event_name != 'workflow_dispatch'",
|
||||
);
|
||||
expect(smokeRunStep.env.OPENCLAW_QA_SUITE_WORKER_START_STAGGER_MS).toContain(
|
||||
"vars.OPENCLAW_CI_RUNNER_BACKEND != 'github'",
|
||||
);
|
||||
expect(smokeRunStep.env.OPENCLAW_QA_SUITE_WORKER_START_STAGGER_MS).toContain(
|
||||
"github.repository == 'openclaw/openclaw'",
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user