name: CI
on:
push:
branches: [master, main]
pull_request:
branches: [master, main]
schedule:
- cron: '31 6 * * 1'
workflow_dispatch:
inputs:
expected_sha:
description: Exact 40-character commit selected by --ref (manual runs always force full CI)
required: true
type: string
permissions:
contents: read
concurrency:
group: ${{ github.event_name == 'pull_request' && format('ci-pr-{0}', github.event.pull_request.number) || format('ci-{0}-{1}', github.workflow, github.sha) }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
RUSTFLAGS: -Dwarnings
RUST_MIN_STACK: 8388608
jobs:
changes:
name: Change detection
timeout-minutes: 10
runs-on: ubuntu-latest
outputs:
heavy: ${{ steps.detect.outputs.heavy }}
workflow: ${{ steps.detect.outputs.workflow }}
mobile: ${{ steps.detect.outputs.mobile }}
actions: ${{ steps.detect.outputs.actions }}
trusted: ${{ steps.trust.outputs.trusted }}
steps:
- name: Classify event trust
id: trust
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
THIS_REPO: ${{ github.repository }}
run: |
set -euo pipefail
# "trusted" means the code came from this repository, not a fork.
# Only trusted events may run on the self-hosted macOS runner: this
# repo is public with thousands of forks, and a fork PR on a
# self-hosted runner is arbitrary code execution on that machine.
if [ "${EVENT_NAME}" != "pull_request" ] || [ "${HEAD_REPO}" = "${THIS_REPO}" ]; then
echo "trusted=true" >> "$GITHUB_OUTPUT"
else
echo "trusted=false" >> "$GITHUB_OUTPUT"
fi
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Detect executable changes
id: detect
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
BASE_REF: ${{ github.base_ref }}
BEFORE_SHA: ${{ github.event.before }}
EXPECTED_SHA: ${{ inputs.expected_sha }}
run: |
set -euo pipefail
if [[ "${EVENT_NAME}" == "workflow_dispatch" ]]; then
if [[ "${#EXPECTED_SHA}" -ne 40 || "${EXPECTED_SHA}" =~ [^0-9a-fA-F] ]]; then
echo "::error::expected_sha must be a full 40-character commit SHA." >&2
exit 1
fi
actual="$(git rev-parse HEAD)"
expected_normalized="$(printf '%s' "${EXPECTED_SHA}" | tr '[:upper:]' '[:lower:]')"
if [[ "${actual}" != "${expected_normalized}" ]]; then
echo "::error::Dispatch resolved to ${actual}, not requested ${EXPECTED_SHA}." >&2
exit 1
fi
echo "Manual exact-head dispatch: forcing heavy, workflow, mobile, and action gates."
echo "heavy=true" >> "${GITHUB_OUTPUT}"
echo "workflow=true" >> "${GITHUB_OUTPUT}"
echo "mobile=true" >> "${GITHUB_OUTPUT}"
echo "actions=true" >> "${GITHUB_OUTPUT}"
exit 0
fi
if [[ "${EVENT_NAME}" == "schedule" ]]; then
echo "heavy=true" >> "${GITHUB_OUTPUT}"
echo "workflow=true" >> "${GITHUB_OUTPUT}"
echo "mobile=true" >> "${GITHUB_OUTPUT}"
echo "actions=true" >> "${GITHUB_OUTPUT}"
exit 0
fi
base=""
if [[ "${EVENT_NAME}" == "pull_request" && -n "${BASE_REF}" ]]; then
git fetch --no-tags origin "${BASE_REF}:refs/remotes/origin/${BASE_REF}" --depth=1
base="origin/${BASE_REF}"
elif [[ -n "${BEFORE_SHA}" && "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" ]]; then
base="${BEFORE_SHA}"
fi
if [[ -z "${base}" ]]; then
echo "heavy=true" >> "${GITHUB_OUTPUT}"
echo "workflow=true" >> "${GITHUB_OUTPUT}"
echo "mobile=true" >> "${GITHUB_OUTPUT}"
echo "actions=true" >> "${GITHUB_OUTPUT}"
exit 0
fi
mapfile -t changed < <(git diff --name-only "${base}" "${GITHUB_SHA}" | sort)
heavy=false
workflow=false
mobile=false
actions=false
for path in "${changed[@]}"; do
case "${path}" in
scripts/release/npm-wrapper-smoke.js|scripts/mobile-smoke.sh|scripts/check-provider-registry.py)
heavy=true
;;
docs/*|*.md|packaging/aur/*|.github/PULL_REQUEST_TEMPLATE.md|.github/ISSUE_TEMPLATE/*|.github/scripts/agent-task-metadata.test.sh|.github/workflows/agent-task-labels.yml|.github/workflows/auto-tag.yml|.github/workflows/stale.yml|.github/workflows/triage.yml|scripts/release/check-versions.sh|scripts/release/check-ohos-deps.sh|scripts/release/install-dogfood.sh|scripts/release/install-dogfood.test.sh|scripts/release/prepare-release.sh|scripts/release/prepare-release.test.sh|scripts/dev-cache.sh|scripts/dev-cache.test.sh|scripts/dev-cargo.sh|scripts/dev-test.sh)
;;
*)
heavy=true
;;
esac
case "${path}" in
crates/workflow/*|.github/workflows/ci.yml)
workflow=true
;;
esac
case "${path}" in
crates/app-server/*|crates/tui/src/runtime_api*|crates/tui/src/runtime_mobile.html|crates/tui/src/runtime_threads*|crates/tui/src/main.rs|scripts/mobile-smoke.sh|.github/workflows/ci.yml|Cargo.lock|Cargo.toml)
mobile=true
;;
esac
case "${path}" in
.github/workflows/*|.github/actionlint.yml)
actions=true
;;
esac
done
echo "heavy=${heavy}" >> "${GITHUB_OUTPUT}"
echo "workflow=${workflow}" >> "${GITHUB_OUTPUT}"
echo "mobile=${mobile}" >> "${GITHUB_OUTPUT}"
echo "actions=${actions}" >> "${GITHUB_OUTPUT}"
echo "Heavy Rust CI required: ${heavy}"
echo "Workflow RLM cache CI required: ${workflow}"
echo "Mobile runtime smoke required (PRs): ${mobile}"
echo "Workflow lint required: ${actions}"
printf 'Changed files:\n'
printf ' %s\n' "${changed[@]}"
versions:
name: Version drift
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- uses: actions/setup-node@v7
with:
node-version: 20
- name: Check version drift
run: ./scripts/release/check-versions.sh --range-audit-advisory
- name: Check OHOS dependency graph
run: ./scripts/release/check-ohos-deps.sh
- name: Check release helper contracts
run: |
bash .github/scripts/agent-task-metadata.test.sh
bash scripts/release/check-feature-release-notes.test.sh
bash scripts/release/generate-release-body.test.sh
bash scripts/release/install-dogfood.test.sh
bash scripts/release/prepare-release.test.sh
bash scripts/release/require-release-tag-checkout.test.sh
bash scripts/release/validate-crate-publish-order.test.sh
python3 scripts/release/publish-crates.test.py
bash scripts/release/verify-remote-tag.test.sh
bash packaging/aur/render.test.sh
sh scripts/dev-cache.test.sh
bash .github/scripts/update-homebrew-tap.test.sh
node .github/scripts/release-workflows.test.js
node --test scripts/release/assemble-release-assets.test.js
node --test scripts/release/ensure-release-assets-absent.test.js
- name: Run runtime web client tests
run: node --test crates/tui/tests/runtime_web_client.test.mjs
integrations:
name: Integrations
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
- name: Run chat-bridge suites
run: |
set -euo pipefail
for bridge in bridge-core feishu-bridge telegram-bridge wecom-bridge weixin-bridge; do
echo "== ${bridge}"
(cd "integrations/${bridge}" && npm test)
done
- name: Run computer-use plugin suites
run: (cd crates/tui/plugins/computer-use && npm test)
vscode-extension:
name: VS Code extension
timeout-minutes: 15
runs-on: ubuntu-latest
defaults:
run:
working-directory: extensions/vscode
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 20
- name: Install extension dependencies
run: npm ci
- name: Run VS Code extension suites
run: npm test
safety-gate:
name: Safety gate
needs: changes
if: needs.changes.outputs.heavy == 'true'
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: mozilla-actions/sccache-action@v0.0.11
id: sccache
continue-on-error: true
- name: Enable sccache
if: steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
run: |
for i in 1 2 3 4 5; do
sudo apt-get update && break
echo "apt-get update failed (attempt $i); retrying in 15s"
sleep 15
done
sudo apt-get install -y libdbus-1-dev pkg-config
- uses: Swatinem/rust-cache@v2
with:
cache-bin: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Hermetic safety and authorization tests
env:
HOME: ${{ runner.temp }}/cw-hermetic-home
USERPROFILE: ${{ runner.temp }}/cw-hermetic-home
CODEWHALE_HOME: ${{ runner.temp }}/cw-hermetic-home/.codewhale
RUST_MIN_STACK: "8388608"
run: |
mkdir -p "${HOME}" "${CODEWHALE_HOME}"
unset CODEWHALE_CONFIG_PATH DEEPSEEK_CONFIG_PATH DEEPSEEK_HOME || true
cargo test -p codewhale-tui --lib --locked -- command_safety auto_review authority sandbox
cargo test -p codewhale-execpolicy --locked
lint:
name: Lint
needs: changes
timeout-minutes: 45
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@master
if: needs.changes.outputs.heavy == 'true'
with:
toolchain: stable
components: rustfmt, clippy
- uses: mozilla-actions/sccache-action@v0.0.11
id: sccache
continue-on-error: true
if: needs.changes.outputs.heavy == 'true'
- name: Enable sccache
if: needs.changes.outputs.heavy == 'true' && steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
if: needs.changes.outputs.heavy == 'true'
run: |
for i in 1 2 3 4 5; do
sudo apt-get update && break
echo "apt-get update failed (attempt $i); retrying in 15s"
sleep 15
done
sudo apt-get install -y libdbus-1-dev pkg-config
- uses: Swatinem/rust-cache@v2
if: needs.changes.outputs.heavy == 'true'
with:
cache-bin: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check formatting
if: needs.changes.outputs.heavy == 'true'
run: cargo fmt --all -- --check
- name: Run clippy
if: needs.changes.outputs.heavy == 'true'
run: |
cargo clippy --workspace --all-targets --all-features --locked -- \
-D warnings \
-A clippy::uninlined_format_args \
-A clippy::too_many_arguments \
-A clippy::unnecessary_map_or
- name: sccache stats
if: needs.changes.outputs.heavy == 'true' && steps.sccache.outcome == 'success'
continue-on-error: true
shell: bash
run: sccache --show-stats
- name: Check provider registry drift
if: needs.changes.outputs.heavy == 'true'
run: python3 scripts/check-provider-registry.py
- name: Check command-contract prototype boundary
if: needs.changes.outputs.heavy == 'true'
run: |
python3 scripts/test_check_command_crate_boundaries.py
python3 scripts/check-command-crate-boundaries.py
- name: Check command migration manifest
if: needs.changes.outputs.heavy == 'true'
env:
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PUSH_BEFORE_SHA: ${{ github.event.before }}
run: |
python3 scripts/test_check_command_migration_manifest.py
baseline="${PR_BASE_SHA:-${PUSH_BEFORE_SHA:-}}"
if [[ -n "${baseline}" && ! "${baseline}" =~ ^0+$ ]]; then
git fetch --no-tags origin "${baseline}"
python3 scripts/check-command-migration-manifest.py --baseline-ref "${baseline}"
else
python3 scripts/check-command-migration-manifest.py
fi
- name: Check dead-code budget
if: needs.changes.outputs.heavy == 'true'
continue-on-error: ${{ github.event_name == 'pull_request' }}
run: python3 scripts/check-dead-code-budget.py
- name: Test runtime-contract measurement harness
if: needs.changes.outputs.heavy == 'true'
run: |
python3 scripts/test_measure_runtime_contract.py
python3 scripts/test_check_runtime_contract_budget.py
- name: Fetch locked dependency graph for offline measurement
if: needs.changes.outputs.heavy == 'true'
run: cargo fetch --locked
- name: Check runtime-contract budget
if: needs.changes.outputs.heavy == 'true'
continue-on-error: ${{ github.event_name == 'pull_request' }}
run: python3 scripts/check-runtime-contract-budget.py
- name: Test persistence-backlog measurement and checker harnesses
if: needs.changes.outputs.heavy == 'true'
run: |
python3 scripts/test_measure_persistence_backlog.py
python3 scripts/test_check_persistence_backlog_budget.py
- name: Check persistence-backlog budget
if: needs.changes.outputs.heavy == 'true'
continue-on-error: ${{ github.event_name == 'pull_request' }}
run: python3 scripts/check-persistence-backlog-budget.py
- name: Check README translations stay in sync
if: github.event_name != 'schedule'
run: python3 scripts/check-readme-translations.py
- name: Check README locale link symmetry
if: github.event_name != 'schedule'
run: bash scripts/check-readme-locales.sh
- name: Check TUI locale pack parity
if: github.event_name != 'schedule'
run: python3 scripts/check-tui-locale-parity.py
- name: Check TUI product vocabulary
if: github.event_name != 'schedule'
run: sh scripts/check-tui-product-vocabulary.sh
- name: Check website locale dictionary parity
if: github.event_name != 'schedule'
run: node web/scripts/check-locales.mjs
- name: Skip Rust lint for light change
if: needs.changes.outputs.heavy != 'true'
run: echo "No executable Rust changes detected; preserving required Lint context."
- name: Linux clippy location
if: needs.changes.outputs.heavy == 'true'
run: echo "Linux clippy/test gates run on CNB for mirrored fix/*, rebrand/*, work/v*, and main branches."
workflow-rlm-cache:
name: Workflow RLM cache
needs: changes
if: needs.changes.outputs.workflow == 'true'
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: mozilla-actions/sccache-action@v0.0.11
id: sccache
continue-on-error: true
- name: Enable sccache
if: steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- uses: Swatinem/rust-cache@v2
with:
cache-bin: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Run workflow crate tests
run: cargo test -p codewhale-workflow --locked
test:
name: Test
needs: changes
timeout-minutes: 90
runs-on: ${{ needs.changes.outputs.heavy != 'true' && 'ubuntu-latest' || (matrix.os == 'macos-latest' && needs.changes.outputs.trusted == 'true' && vars.CW_SELF_HOSTED_MAC == 'true' && fromJSON('["self-hosted","macOS","ARM64","codewhale-mac"]')) || matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- name: Skip tests for light change
if: needs.changes.outputs.heavy != 'true'
run: echo "No executable Rust changes detected; preserving required Test context."
- uses: actions/checkout@v7
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- name: Test Windows installer PATH helper
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'windows-latest'
shell: pwsh
run: ./scripts/installer/update-user-path.tests.ps1
- name: Install NSIS for Windows installer regression
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'windows-latest'
shell: pwsh
run: |
$ErrorActionPreference = 'Continue'
$delays = @(0, 20, 45)
for ($attempt = 0; $attempt -lt $delays.Count; $attempt++) {
if ($delays[$attempt] -gt 0) {
Write-Host "NSIS install attempt $($attempt + 1) after $($delays[$attempt])s backoff"
Start-Sleep -Seconds $delays[$attempt]
}
choco install nsis -y --no-progress
if ($LASTEXITCODE -eq 0) {
Write-Host "NSIS installed on attempt $($attempt + 1)"
exit 0
}
Write-Host "::warning::choco install nsis failed (exit $LASTEXITCODE)"
}
Write-Host "::error::NSIS could not be provisioned from Chocolatey after $($delays.Count) attempts"
exit 1
- name: Test Windows installer PATH regression
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'windows-latest'
shell: pwsh
run: ./scripts/installer/installer-path-regression.tests.ps1 -AllowUserPathMutation
- uses: dtolnay/rust-toolchain@stable
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- uses: mozilla-actions/sccache-action@v0.0.11
id: sccache
continue-on-error: true
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- name: Enable sccache
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'ubuntu-latest' && (github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
run: |
for i in 1 2 3 4 5; do
sudo apt-get update && break
echo "apt-get update failed (attempt $i); retrying in 15s"
sleep 15
done
sudo apt-get install -y libdbus-1-dev pkg-config
- uses: Swatinem/rust-cache@v2
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
with:
cache-bin: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- uses: taiki-e/install-action@nextest
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- name: Run tests
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
run: cargo nextest run --workspace --all-features --locked --profile ci
env:
RUST_MIN_STACK: '16777216'
- name: Run doctests
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
run: cargo test --workspace --all-features --locked --doc
env:
RUST_MIN_STACK: '16777216'
- name: Check persistence-backlog RSS budget
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'macos-latest'
run: python3 scripts/check-persistence-backlog-budget.py
- name: Lockfile drift guard
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
run: git diff --exit-code -- Cargo.lock
- name: Run Offline Eval Harness
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'macos-latest'
run: cargo run -p codewhale-tui --all-features -- eval
- name: sccache stats
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && steps.sccache.outcome == 'success'
continue-on-error: true
shell: bash
run: sccache --show-stats
- name: Linux test location (CNB)
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'ubuntu-latest' && github.event_name != 'workflow_dispatch' && github.event_name != 'pull_request'
run: echo "Linux workspace tests run on CNB for non-PR release/main pushes; pull requests run directly on Ubuntu."
npm-wrapper-smoke:
name: npm wrapper smoke
needs: changes
if: github.event_name != 'schedule'
timeout-minutes: 30
runs-on: ${{ needs.changes.outputs.heavy == 'true' && matrix.os || 'ubuntu-latest' }}
strategy:
matrix:
os: ${{ fromJSON(github.event_name == 'pull_request' && '["ubuntu-latest"]' || '["ubuntu-latest","macos-latest","windows-latest"]') }}
steps:
- name: Skip npm wrapper smoke for light change
if: needs.changes.outputs.heavy != 'true'
run: echo "No executable Rust changes detected; preserving required npm wrapper smoke context."
- uses: actions/checkout@v7
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- uses: dtolnay/rust-toolchain@stable
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- uses: mozilla-actions/sccache-action@v0.0.11
id: sccache
continue-on-error: true
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- name: Enable sccache
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- uses: actions/setup-node@v7
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
with:
node-version: 20
- name: Install Linux system dependencies
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'ubuntu-latest' && (github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
run: |
for i in 1 2 3 4 5; do
sudo apt-get update && break
echo "apt-get update failed (attempt $i); retrying in 15s"
sleep 15
done
sudo apt-get install -y libdbus-1-dev pkg-config
- uses: Swatinem/rust-cache@v2
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
with:
cache-bin: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Build wrapper binaries
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
env:
CARGO_PROFILE_RELEASE_LTO: 'off'
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16'
run: cargo build --release --locked -p codewhale-cli -p codewhale-tui
- name: Smoke wrapper install and delegated entrypoints
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
run: node scripts/release/npm-wrapper-smoke.js
- name: sccache stats
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && steps.sccache.outcome == 'success'
continue-on-error: true
shell: bash
run: sccache --show-stats
- name: Linux smoke location
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'ubuntu-latest' && github.event_name != 'workflow_dispatch' && github.event_name != 'pull_request'
run: echo "Linux npm wrapper smoke runs on CNB for non-PR release/main pushes; pull requests run directly on Ubuntu."
mobile-smoke:
name: Mobile runtime smoke
needs: changes
if: >-
github.event_name != 'schedule' &&
needs.changes.outputs.heavy == 'true' &&
(github.event_name != 'pull_request' || needs.changes.outputs.mobile == 'true')
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: mozilla-actions/sccache-action@v0.0.11
id: sccache
continue-on-error: true
- name: Enable sccache
if: steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
run: |
for i in 1 2 3 4 5; do
sudo apt-get update && break
echo "apt-get update failed (attempt $i); retrying in 15s"
sleep 15
done
sudo apt-get install -y libdbus-1-dev pkg-config
- uses: Swatinem/rust-cache@v2
with:
cache-bin: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Run mobile smoke tests
env:
CARGO_PROFILE_RELEASE_LTO: 'off'
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16'
run: ./scripts/mobile-smoke.sh
- name: sccache stats
if: steps.sccache.outcome == 'success'
continue-on-error: true
shell: bash
run: sccache --show-stats
actionlint:
name: Workflow lint
needs: changes
if: needs.changes.outputs.actions == 'true'
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Run actionlint
uses: docker://rhysd/actionlint:1.7.12
with:
args: -color -ignore SC2129 -ignore SC2221 -ignore SC2222
docs:
name: Documentation
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- name: Install Linux system dependencies
if: runner.os == 'Linux'
run: |
for i in 1 2 3 4 5; do
sudo apt-get update && break
echo "apt-get update failed (attempt $i); retrying in 15s"
sleep 15
done
sudo apt-get install -y libdbus-1-dev pkg-config
- uses: Swatinem/rust-cache@v2
with:
cache-bin: false
- name: Build docs
run: cargo doc --workspace --no-deps
env:
RUSTDOCFLAGS: -Dwarnings