Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Validate GitHub Actions workflows
uses: docker://rhysd/actionlint:1.7.11
with:
args: .github/workflows/ci.yml .github/workflows/release.yml
args: .github/workflows/ci.yml .github/workflows/release.yml .github/workflows/turbo.yml
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v4
with:
Expand Down
94 changes: 94 additions & 0 deletions .github/workflows/turbo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: Turbo

# Additive Turborepo lane. The required gates stay in ci.yml; this workflow
# proves the turbo.json task graph end to end on every change:
# - pull requests run the AFFECTED graph only (merge-base diff)
# - pushes to main run the FULL graph
# Remote caching activates as soon as the two secrets below exist; without
# them turbo falls back to the local cache and every step still works.

on:
push:
branches: [main]
pull_request:

concurrency:
group: turbo-${{ github.ref }}
cancel-in-progress: true

env:
# Vercel Remote Cache. Absent secrets degrade to local-only caching.
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
# Artifact signature verification (remoteCache.signature in turbo.json).
TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}

jobs:
graph:
name: turbo ${{ github.event_name == 'pull_request' && '--affected' || '(full)' }}
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
# --affected diffs against the merge base; depth 1 hides it.
fetch-depth: 0
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v4
with:
node-version: 22.19.0
cache: pnpm
- run: pnpm install --frozen-lockfile --ignore-scripts
# Same jj setup as ci.yml: the jj and host-contract suites exercise a
# real jj binary and refuse to skip silently.
- name: Install jj
uses: taiki-e/install-action@v2
with:
tool: jj-cli@0.39.0
- name: Initialize colocated jj repository
run: jj git init --colocate
# --affected diffs against TURBO_SCM_BASE when set. On pull requests, pin
# it to the base SHA so the affected graph is exactly this PR's changes
# no matter what the checkout's merge history looks like. Pushes to main
# run the full graph, so no base is needed there.
- name: Pin the affected base to the PR base
if: github.event_name == 'pull_request'
run: echo "TURBO_SCM_BASE=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_ENV"
# The graph itself is a deliverable: what turbo THINKS must run for this
# diff, as JSON, before anything executes.
- name: Record the affected graph
if: github.event_name == 'pull_request'
run: pnpm exec turbo run build check lint circular test --affected --dry=json > affected-graph.json
- name: Build
run: pnpm exec turbo run build ${{ github.event_name == 'pull_request' && '--affected' || '' }} --summarize
- name: Check + lint + circular
run: pnpm exec turbo run check lint circular ${{ github.event_name == 'pull_request' && '--affected' || '' }} --summarize
# The heavy vitest suites carry finite 30s per-test budgets that host
# parallelism starves (see the smthrs-shadow job in ci.yml), so the test
# fan-out stays at concurrency 2. --continue runs every affected suite
# even when a sibling fails, so one red package never hides another.
- name: Test
run: pnpm exec turbo run test ${{ github.event_name == 'pull_request' && '--affected' || '' }} --concurrency=2 --continue --summarize
# Boundaries is experimental and currently reports 210 pre-existing
# findings on this repository (config-file imports that leave the
# package, undeclared test dependencies, one circular package pair).
# Advisory until those are triaged; the engine-tier rule it encodes is
# enforced below by the query-based assertion, which is green.
- name: Boundaries (advisory)
continue-on-error: true
run: pnpm exec turbo boundaries
- name: Engine boundary assertion (turbo query)
run: node scripts/turbo-engine-boundary.mjs
# Root gates are not affected-filterable (//# tasks read the whole
# workspace), so they always run.
- name: Root gates
run: pnpm exec turbo run '//#browser' '//#test:scripts' '//#docs' --summarize
- name: Upload run summaries
if: always()
uses: actions/upload-artifact@v4
with:
name: turbo-run-summaries
path: |
.turbo/runs/
affected-graph.json
if-no-files-found: ignore
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
node_modules/
dist/
.turbo/
/out/
/flows
.smithers/
.artifacts/
Expand Down
47 changes: 47 additions & 0 deletions apps/server/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"$schema": "https://turborepo.dev/schema.json",
"extends": ["//"],
"tasks": {
"deploy": {
"dependsOn": ["smithers-ui#build"],
"inputs": ["src/**", "scripts/**", "wrangler.jsonc", "tsconfig.json", "package.json"],
"outputs": ["deploy-receipts/**"],
"cache": false,
"interactive": true,
"passThroughEnv": ["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID"]
},
"deploy:dry": {
"dependsOn": ["smithers-ui#build"],
"inputs": ["src/**", "scripts/**", "wrangler.jsonc", "tsconfig.json", "package.json"],
"outputs": ["deploy-receipts/**"],
"cache": false
},
"deploy:dry-run": {
"dependsOn": ["smithers-ui#build"],
"inputs": ["src/**", "scripts/**", "wrangler.jsonc", "tsconfig.json", "package.json"],
"outputs": [],
"cache": false
},
"test": {
"inputs": ["src/**", "scripts/**", "tsconfig.json", "package.json"],
"outputs": []
},
"dev": {
"dependsOn": ["smithers-ui#build"],
"cache": false,
"persistent": true,
"interactive": true
},
"serve:local": {
"dependsOn": ["smithers-ui#build"],
"cache": false,
"persistent": true,
"interactive": true
},
"seed:allowlist": {
"cache": false,
"outputs": [],
"passThroughEnv": ["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID"]
}
}
}
10 changes: 10 additions & 0 deletions apps/shared/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "https://turborepo.dev/schema.json",
"extends": ["//"],
"tasks": {
"test": {
"inputs": ["src/**", "tsconfig.json", "package.json"],
"outputs": []
}
}
}
15 changes: 15 additions & 0 deletions apps/tui/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://turborepo.dev/schema.json",
"extends": ["//"],
"tasks": {
"test": {
"inputs": ["src/**", "scripts/**", "tsconfig.json", "package.json"],
"outputs": []
},
"smoke": {
"cache": false,
"interactive": true,
"outputs": []
}
}
}
90 changes: 90 additions & 0 deletions apps/ui/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"$schema": "https://turborepo.dev/schema.json",
"extends": ["//"],
"tasks": {
"build": {
"inputs": [
"src/**",
"vite.config.ts",
"postcss.config.js",
"tailwind.config.js",
"electrobun.config.ts",
"tsconfig.json",
"package.json"
],
"outputs": ["dist/**"],
"env": ["SMITHERS_CHAT_URL", "SMITHERS_CHAT_ORIGIN"]
},
"test": {
"inputs": ["src/**", "scripts/**", "tsconfig.json", "package.json"],
"outputs": []
},
"dev": {
"cache": false,
"persistent": true,
"interactive": true,
"passThroughEnv": ["SMITHERS_DEV_UPSTREAM", "SMITHERS_CHAT_URL", "SMITHERS_CHAT_ORIGIN", "SMITHERS_APP_URL"]
},
"dev:hmr": {
"cache": false,
"persistent": true,
"interactive": true,
"passThroughEnv": ["SMITHERS_DEV_UPSTREAM", "SMITHERS_CHAT_URL", "SMITHERS_CHAT_ORIGIN"]
},
"hmr": {
"cache": false,
"persistent": true,
"interactive": true,
"passThroughEnv": ["SMITHERS_DEV_UPSTREAM", "SMITHERS_CHAT_URL", "SMITHERS_CHAT_ORIGIN"]
},
"web": {
"cache": false,
"persistent": true,
"interactive": true,
"passThroughEnv": ["SMITHERS_DEV_UPSTREAM", "SMITHERS_CHAT_URL", "SMITHERS_CHAT_ORIGIN"]
},
"start": {
"dependsOn": ["build"],
"cache": false,
"persistent": true,
"interactive": true
},
"start:canary": {
"cache": false,
"persistent": true,
"interactive": true,
"passThroughEnv": ["SMITHERS_APP_URL"]
},
"build:canary": {
"dependsOn": ["build"],
"outputs": [],
"cache": false,
"passThroughEnv": ["SMITHERS_APP_URL"]
},
"serve:local": {
"cache": false,
"persistent": true,
"interactive": true
},
"test:e2e:web": {
"cache": false,
"outputs": []
},
"test:e2e:web:context": {
"cache": false,
"outputs": []
},
"test:e2e:web:shell": {
"cache": false,
"outputs": []
},
"test:e2e:worker": {
"cache": false,
"outputs": []
},
"checklist": {
"cache": false,
"outputs": []
}
}
}
Loading
Loading