Spaces:
Runtime error
A newer version of the Gradio SDK is available: 6.14.0
T-008: GitHub Actions CI β Windows Runner, Check/Lint/Test, Python Enforcement
Type: Task
Phase: 0 β Foundation
Autonomy: agent:review-required β CI config has security implications (permissions, secrets scope). Human reviews before merge.
Stack: stack:infra
Version: v0.1
Iteration: iter-1
Effort: S (half-day)
β οΈ Agent Scope: Replace the T-001 CI stub at
.github/workflows/ci.ymlwith a full workflow. Add missingpackage.jsonscripts if absent. Do not add a fullcargo tauri buildstep β that is T-015's scope. This workflow is check/lint/test only: fast feedback on every PR.
Context
Every PR to main must be gated by: compile check, clippy lint, unit tests, TypeScript typecheck, format check, and the Python-in-src enforcement rule. Without CI these checks are optional and will be skipped. With CI they are required status checks β the PR cannot merge if any fails.
Why Windows runner: The project is Windows-first. WASAPI, DirectML, and the VST3/CLAP bundler all have Windows-specific behaviour. Running CI on ubuntu-latest would miss platform-specific compile errors that only appear with the MSVC toolchain.
Scope boundary: This workflow runs checks only. The full cargo tauri build (which requires WebView2 and takes ~10 minutes) is gated behind T-015 which adds a separate build job. Keeping check/lint/test fast means PR feedback in under 5 minutes.
Prerequisites
- T-001 merged β
.github/workflows/ci.ymlstub exists,package.jsonexists - T-007 merged β
Taskfile.ymlwithtask ci:python-checkexists
Acceptance Criteria
Workflow
- Workflow triggers on push to
mainand on all pull requests targetingmain - All steps run on
windows-latest - Rust nightly toolchain is installed with
clippyandrustfmtcomponents - Rust build cache (
~/.cargo/registry,~/.cargo/git,target/) is cached keyed onCargo.lock - Node.js 20 LTS and pnpm 9 are installed and frontend deps cached
-
go-taskis installed sotask ci:python-checkcan run
Jobs β check (fast feedback, ~3β5 min)
-
cargo check --workspacepasses -
cargo clippy --workspace -- -D warningspasses -
cargo fmt --all --checkpasses (fails if unformatted Rust code is committed) -
pnpm typecheckpasses -
pnpm format:checkpasses -
task ci:python-checkpasses (zero Python subprocess calls insrc/orkansas/)
Jobs β test (depends on check)
-
cargo test --workspacepasses -
pnpm testpasses (or skips gracefully if no test suite exists yet)
package.json scripts
-
typecheckscript exists:tsc --noEmit -
format:checkscript exists:prettier --check "src/**/*.{ts,css,html}" -
formatscript exists:prettier --write "src/**/*.{ts,css,html}" -
lintscript exists:eslint src/ --ext .ts -
testscript exists:vitest run(orecho 'No tests yet' && exit 0stub if vitest not configured)
Security
- Workflow has
permissions: read-allat the top level (deny-by-default principle) - No
GITHUB_TOKENused beyond the default checkout scope - No secrets accessed in this workflow (secrets are for Day 10 release workflow)
package.json Scripts to Add
If these are missing from the package.json created by T-001, add them:
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit",
"lint": "eslint src/ --ext .ts --max-warnings 0",
"format": "prettier --write \"src/**/*.{ts,css,html}\"",
"format:check": "prettier --check \"src/**/*.{ts,css,html}\"",
"test": "echo '[test] No frontend tests yet β see T-130' && exit 0"
}
}
Add prettier and eslint as dev deps if not already present:
pnpm add -D prettier eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
Add .prettierrc at repo root:
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 100,
"tabWidth": 2
}
Add .eslintrc.json at repo root:
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": "error"
},
"ignorePatterns": ["dist/", "node_modules/"]
}
.github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
# Deny all permissions by default; grant only what each job needs
permissions: read-all
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Job 1: Check, lint, typecheck, format, Python enforcement
# Target time: < 5 minutes
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
check:
name: Check & Lint
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# ββ Rust ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- name: Install Rust nightly
uses: dtolnay/rust-toolchain@nightly
with:
components: clippy, rustfmt
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
# Key on Cargo.lock so wildcard deps get fresh cache on cargo update
key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }}
cache-on-failure: true
# ββ Node / pnpm βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
run_install: false
- name: Get pnpm store path
id: pnpm-cache
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-pnpm-
- name: Install frontend dependencies
run: pnpm install --frozen-lockfile
# ββ go-task βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- name: Install go-task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
# ββ Rust checks βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- name: cargo check
run: cargo check --workspace
- name: cargo clippy
run: cargo clippy --workspace -- -D warnings
- name: cargo fmt check
run: cargo fmt --all --check
# ββ TypeScript checks βββββββββββββββββββββββββββββββββββββββββββββββββββ
- name: TypeScript typecheck
run: pnpm typecheck
- name: Prettier format check
run: pnpm format:check
- name: ESLint
run: pnpm lint
# ββ Policy enforcement ββββββββββββββββββββββββββββββββββββββββββββββββββ
- name: Python-in-src check
run: task ci:python-check
shell: bash
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Job 2: Unit tests (runs after check passes)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
test:
name: Test
runs-on: windows-latest
needs: check
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust nightly
uses: dtolnay/rust-toolchain@nightly
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }}
cache-on-failure: true
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
run_install: false
- name: Install frontend dependencies
run: pnpm install --frozen-lockfile
- name: cargo test
run: cargo test --workspace
- name: Frontend test
run: pnpm test
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Job 3: Plugin validation stub (T-143 wires in pluginval)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
pluginval:
name: Plugin Validation (stub)
runs-on: windows-latest
needs: check
# T-143 replaces this stub with real pluginval execution
# and removes the `if: false` guard
if: false
steps:
- name: pluginval stub
run: echo "pluginval CI β see T-143"
Implementation Notes
Why dtolnay/rust-toolchain@nightly not actions-rs/toolchain
actions-rs/toolchain is unmaintained. dtolnay/rust-toolchain is the community-maintained replacement β it handles nightly, components, and targets correctly on all platforms.
Why Swatinem/rust-cache@v2
It caches ~/.cargo/registry, ~/.cargo/git, and target/ in a single step. On Windows runners the target/ directory can be 2β4 GB β without caching the Rust build step takes 8β12 minutes on every run. With a warm cache it drops to 1β3 minutes.
pnpm install --frozen-lockfile
This fails the CI job if pnpm-lock.yaml is out of sync with package.json. It prevents "works on my machine" dependency drift. Developers must commit an updated lockfile when adding deps.
Python check via task ci:python-check
Calls the Taskfile target defined in T-007. The target uses grep -rn and exits non-zero if any match is found. The shell: bash directive is required on Windows runners to use bash syntax in the grep command.
The pluginval job with if: false
This is a placeholder job that never runs (if: false prevents execution). T-143 replaces it with real pluginval steps and removes the guard. Having it here means:
- T-143 agents have a named job to fill in β no new job creation needed
- The job name appears in the GitHub Actions UI under "skipped" β visible reminder
Branch protection (manual step β not in YAML)
After merging T-008, go to GitHub β Settings β Branches β Add rule for main:
- β Require status checks to pass before merging
- Required checks:
Check & Lint,Test - β Require branches to be up to date before merging
This is a repo settings action, not something the agent can do via YAML.
Testing
Local simulation
# These are the same commands the CI runs β all should pass locally first
cargo check --workspace
cargo clippy --workspace -- -D warnings
cargo fmt --all --check
pnpm typecheck
pnpm format:check
pnpm lint
task ci:python-check
cargo test --workspace
pnpm test
After pushing
- Open a draft PR against
main - Verify both
Check & LintandTestjobs appear and pass - Introduce a deliberate clippy warning (e.g. unused variable) β verify CI fails on that job
- Revert the deliberate warning β verify CI passes again
GitHub CLI
gh issue create \
--title "T-008: GitHub Actions CI β Windows runner, check/lint/test, Python enforcement" \
--label "type:task,stack:infra,agent:review-required,priority:critical,status:ready,day:1" \
--body-file T-008.md
Parent: GENESIS
Blocks: T-015 (adds build job to this workflow), T-074 (adds timing test step), T-136 (expands Python check to cover more patterns), T-143 (fills in pluginval job), T-147 (adds perf regression job)
Blocked By: T-001, T-007
Version: v0.1 Β· Iteration: iter-1 Β· Effort: S (half-day)