mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-03 00:17:47 +00:00
Merge pull request #1044 from kaitranntt/kai/chore/ci-speed-and-ai-doc-gate
chore(ci): parallelize CI matrix + cache, tighten AI-facing quality gate
This commit is contained in:
+32
-12
@@ -4,35 +4,55 @@ on:
|
||||
pull_request:
|
||||
branches: [main, dev]
|
||||
|
||||
# Design notes:
|
||||
# - Matrix parallelism cuts wall time from ~3-4min to ~60-90s (cache warm).
|
||||
# - Each matrix leg restores the same cache; `Ensure deps` fills gaps on cache miss.
|
||||
# - fail-fast: false so every failure is visible in one run (no re-pushing to see the next failure).
|
||||
# - Test leg runs build:all inline because it needs dist/ artifacts; still parallel with other legs.
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: [self-hosted, linux, x64]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
check:
|
||||
- { name: typecheck, cmd: 'bun run typecheck' }
|
||||
- { name: lint, cmd: 'bun run lint' }
|
||||
- { name: format, cmd: 'bun run format:check' }
|
||||
- { name: build, cmd: 'bun run build:all' }
|
||||
- { name: test, cmd: 'bun run build:all && bun run test:all' }
|
||||
name: ${{ matrix.check.name }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Clean stale artifacts
|
||||
run: rm -rf node_modules ui/node_modules dist
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: '1.3.9'
|
||||
no-cache: true
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Install dependencies
|
||||
- name: Restore bun + node_modules cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.bun/install/cache
|
||||
node_modules
|
||||
ui/node_modules
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock', 'ui/bun.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- name: Ensure dependencies
|
||||
run: |
|
||||
bun install --frozen-lockfile
|
||||
cd ui && bun install --frozen-lockfile
|
||||
[ -d node_modules ] || bun install --frozen-lockfile
|
||||
[ -d ui/node_modules ] || (cd ui && bun install --frozen-lockfile)
|
||||
|
||||
- name: Build package
|
||||
run: bun run build:all
|
||||
|
||||
- name: Validate (typecheck + lint + format + tests)
|
||||
run: bun run validate
|
||||
- name: Run ${{ matrix.check.name }}
|
||||
run: ${{ matrix.check.cmd }}
|
||||
|
||||
@@ -29,6 +29,7 @@ echo " base: $BASE_BRANCH"
|
||||
bun run typecheck
|
||||
bun run lint:fix
|
||||
bun run format:check
|
||||
bun run build:all
|
||||
|
||||
git fetch origin "$BASE_BRANCH" --quiet || true
|
||||
DIFF_RANGE="HEAD"
|
||||
|
||||
@@ -15,6 +15,32 @@ AI-facing guidance for agent tooling when working with this repository.
|
||||
|
||||
Tests set `process.env.CCS_HOME` to a temp directory. Code using `os.homedir()` directly will modify the user's real files.
|
||||
|
||||
## CI-First Protocol (MANDATORY)
|
||||
|
||||
**A task is NOT complete until CI is green. After every `git push`, the AI agent MUST block on CI until it passes.**
|
||||
|
||||
### Required Sequence
|
||||
1. `git push`
|
||||
2. **Immediately** run `gh pr checks --watch` (or `gh run watch`) and block until all checks complete.
|
||||
3. If **green** → task may proceed to next step / be declared done.
|
||||
4. If **red**:
|
||||
- Pull failing logs: `gh run view --log-failed` (or `gh pr checks <n>` to identify the failing job, then `gh run view <run-id> --log-failed`).
|
||||
- Fix the root cause locally. Do NOT retry blindly.
|
||||
- Commit and push again. Re-watch CI.
|
||||
5. Applies to initial `gh pr create` AND every subsequent push on an open PR.
|
||||
|
||||
### Fallback (when `--watch` is unavailable or flaky)
|
||||
Poll with short sleep until no check is `pending` / `in_progress`:
|
||||
```bash
|
||||
until [ "$(gh pr checks <n> --json state -q '[.[] | select(.state == "IN_PROGRESS" or .state == "PENDING" or .state == "QUEUED")] | length')" = "0" ]; do
|
||||
sleep 10
|
||||
done
|
||||
gh pr checks <n>
|
||||
```
|
||||
|
||||
### Absolute rule
|
||||
AI MUST NOT declare a task done, close a session, or move to the next task while CI is red or still running. Leaving a PR red and moving on is the primary failure mode this protocol prevents.
|
||||
|
||||
## Core Function
|
||||
|
||||
Multi-provider profile and runtime manager for Claude Code, Factory Droid,
|
||||
@@ -201,9 +227,11 @@ bun run validate # Step 3: Final check (must pass)
|
||||
|
||||
| Project | Command | Runs |
|
||||
|---------|---------|------|
|
||||
| Main | `bun run validate` | typecheck + lint:fix + format:check + maintainability:check + test:all |
|
||||
| Main | `bun run validate` | typecheck + lint:fix + format:check + test:all |
|
||||
| UI | `bun run validate` | typecheck + lint:fix + format:check |
|
||||
|
||||
**Note:** `maintainability:check` is a SEPARATE gate — not part of `validate`. Run it explicitly via `bun run maintainability:check[:strict|:warn]` when touching debt-sensitive code or before merging to protected branches.
|
||||
|
||||
### ESLint Rules (ALL errors)
|
||||
|
||||
| Rule | Level | Notes |
|
||||
@@ -238,7 +266,7 @@ bun run validate # Step 3: Final check (must pass)
|
||||
- Baseline file: `docs/metrics/maintainability-baseline.json`
|
||||
- Metric collector/check script: `scripts/maintainability-baseline.js`
|
||||
- Branch-aware gate wrapper: `scripts/maintainability-check.js`
|
||||
- Enforcement path: `bun run maintainability:check` (included in `bun run validate`)
|
||||
- Enforcement path: `bun run maintainability:check` (run separately — NOT part of `bun run validate`; invoked by `validate:ci-parity` on protected branches)
|
||||
- Gate modes:
|
||||
- `strict`: protected branches (`main`, `dev`, `hotfix/*`, `kai/hotfix-*`) and equivalent CI refs
|
||||
- `warn`: pull request CI and non-protected local branches (non-blocking for parallel PR workflow)
|
||||
@@ -499,27 +527,30 @@ rm -rf ~/.ccs # Clean environment
|
||||
|
||||
**IMPORTANT:** Use `bun run dev` at CCS root for always up-to-date code. Do NOT use `ccs config` during development as it uses the globally installed version.
|
||||
|
||||
## Pre-Commit Checklist
|
||||
## Two-Tier Pre-Push Checklist
|
||||
|
||||
**Quality (BLOCKERS):**
|
||||
- [ ] `bun run format` — formatting fixed
|
||||
- [ ] `bun run validate` — all checks pass
|
||||
- [ ] `bun run validate:ci-parity` — CI parity passed (required before protected-branch pushes; recommended before PRs)
|
||||
- [ ] `cd ui && bun run format && bun run validate` — if UI changed
|
||||
- [ ] If touching debt-sensitive code, run `bun run maintainability:check:strict` before opening/merging PR
|
||||
Optimized for iterative push-then-review workflow. Do NOT run the full gate on every push — CI is the safety net. Run the full gate once before asking for review / merge.
|
||||
|
||||
### Tier 1 — Iterative push (feature branch)
|
||||
Husky `pre-push` auto-runs: `typecheck + lint:fix + format:check + build:all` plus targeted tests based on changed files. AI does **nothing extra** at push time.
|
||||
|
||||
**After push (MANDATORY):** follow the [CI-First Protocol](#ci-first-protocol-mandatory) — watch CI until green. Do not move on while CI is red.
|
||||
|
||||
### Tier 2 — Before requesting review / merge
|
||||
Run ONCE, not per push:
|
||||
- [ ] `bun run validate:ci-parity` — full build + validate matches CI
|
||||
- [ ] `gh pr checks <n>` — all checks green
|
||||
- [ ] If touching debt-sensitive code: `bun run maintainability:check:strict`
|
||||
- [ ] If strict mode fails and increase is intentional: `bun run maintainability:baseline` and commit `docs/metrics/maintainability-baseline.json`
|
||||
- [ ] If UI changed: `cd ui && bun run format && bun run validate`
|
||||
|
||||
**Code:**
|
||||
### Code / Docs / Standards (verify before merge)
|
||||
- [ ] Conventional commit format (`feat:`, `fix:`, etc.)
|
||||
- [ ] Respective `--help` updated (see Help Location Reference) — if CLI changed
|
||||
- [ ] Tests added/updated — if behavior changed
|
||||
- [ ] README.md updated — if user-facing
|
||||
|
||||
**Documentation:**
|
||||
- [ ] CCS docs updated (owner: `~/CloudPersonal/ccs/docs/`) — if CLI/config changed
|
||||
- [ ] Local `docs/` updated — if architecture changed
|
||||
|
||||
**Standards:**
|
||||
- [ ] CLI output ASCII only (NO emojis in terminal output), NO_COLOR respected
|
||||
- [ ] YAGNI/KISS/DRY alignment verified
|
||||
- [ ] No manual version bump or tags
|
||||
|
||||
@@ -116,11 +116,9 @@ describe('cliproxy routing strategy service', () => {
|
||||
expect(result.applied).toBe('config-only');
|
||||
expect(result.strategy).toBe('fill-first');
|
||||
|
||||
const { getConfigPathForPort } = await import('../../../src/cliproxy/config/path-resolver');
|
||||
const configPath = getConfigPathForPort(routingTarget.port);
|
||||
const configContent = fs.readFileSync(configPath, 'utf8');
|
||||
expect(configContent).toContain('routing:');
|
||||
expect(configContent).toContain('strategy: fill-first');
|
||||
const { loadUnifiedConfig } = await import('../../../src/config/unified-config-loader');
|
||||
const persisted = loadUnifiedConfig();
|
||||
expect(persisted?.cliproxy?.routing?.strategy).toBe('fill-first');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -465,6 +465,7 @@ global.fetch = async (url) => {
|
||||
}),
|
||||
env: {
|
||||
...process.env,
|
||||
CCS_PROFILE_TYPE: NEUTRAL_PROFILE_TYPE,
|
||||
CCS_WEBSEARCH_ENABLED: '1',
|
||||
CCS_WEBSEARCH_SKIP: '0',
|
||||
CCS_WEBSEARCH_BRAVE: '0',
|
||||
|
||||
Reference in New Issue
Block a user