reduce CI token costs: 1x/day schedule, Haiku for sub-agents, no retries #91
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| jobs: | |
| verify: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| version: "latest" | |
| - name: Detect and verify project | |
| run: | | |
| chmod +x scripts/detect_stack.sh | |
| STACK_JSON=$(bash scripts/detect_stack.sh src/ 2>/dev/null || echo '{"stack":"unknown"}') | |
| STACK=$(echo "$STACK_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin)['stack'])") | |
| echo "Detected stack: $STACK" | |
| if [ "$STACK" = "unknown" ]; then | |
| echo "No project stack detected yet — skipping build verification." | |
| exit 0 | |
| fi | |
| if [ "$STACK" = "monorepo" ]; then | |
| echo "Monorepo detected — verifying each substack..." | |
| echo "$STACK_JSON" | python3 -c " | |
| import json, subprocess, sys, os | |
| data = json.load(sys.stdin) | |
| substacks = data.get('substacks', []) | |
| failed = False | |
| for s in substacks: | |
| subdir = os.path.join('src', s['dir']) | |
| print(f\"\n=== {s['name']} ({s['stack']}) ===\") | |
| # Install dependencies | |
| if s['stack'] in ('typescript', 'javascript', 'nextjs'): | |
| subprocess.run('npm ci || npm install', shell=True, cwd=subdir) | |
| elif s['stack'] == 'python': | |
| if os.path.exists(os.path.join(subdir, 'uv.lock')): | |
| subprocess.run('uv sync', shell=True, cwd=subdir) | |
| else: | |
| subprocess.run('pip install -e . 2>/dev/null || pip install -r requirements.txt 2>/dev/null || true', shell=True, cwd=subdir) | |
| for cmd_name in ('build', 'test', 'lint'): | |
| cmd = s.get(cmd_name, '') | |
| if cmd: | |
| print(f'Running {cmd_name}: {cmd}') | |
| result = subprocess.run(cmd, shell=True, cwd=subdir) | |
| if result.returncode != 0 and cmd_name != 'lint': | |
| failed = True | |
| sys.exit(1 if failed else 0) | |
| " | |
| else | |
| # Single-stack path | |
| BUILD_CMD=$(echo "$STACK_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin)['build'])") | |
| TEST_CMD=$(echo "$STACK_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin)['test'])") | |
| LINT_CMD=$(echo "$STACK_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin)['lint'])") | |
| cd src/ | |
| case "$STACK" in | |
| typescript|javascript|nextjs) npm ci || npm install ;; | |
| python) pip install -e . 2>/dev/null || pip install -r requirements.txt 2>/dev/null || true ;; | |
| rust) ;; | |
| esac | |
| [ -n "$BUILD_CMD" ] && echo "Running build: $BUILD_CMD" && eval "$BUILD_CMD" | |
| [ -n "$TEST_CMD" ] && echo "Running tests: $TEST_CMD" && eval "$TEST_CMD" | |
| [ -n "$LINT_CMD" ] && echo "Running lint: $LINT_CMD" && eval "$LINT_CMD" || true | |
| fi |