diff --git a/.github/AGENTS.md b/.github/AGENTS.md index fc363e66f9c..352a1248250 100644 --- a/.github/AGENTS.md +++ b/.github/AGENTS.md @@ -22,5 +22,5 @@ change requires explicit security review under `MAINTAINERS.md`. - Inspect the complete workflow diff, including event triggers, permissions, conditions, interpolation, and shell behavior. - Run the local commands represented by changed workflow steps where possible. -- Run `bun run prepush` for CI, release, dependency, packaging, or cross-platform workflow changes. +- Follow the root validation policy: run the suite by default; if a full run is too costly, run at least focused regression tests and document the reason and remaining coverage. Required CI checks still apply before merge. - Do not claim the workflow itself passed until GitHub Actions reports success for the exact commit. diff --git a/.github/scripts/pr-quality-messages.test.cjs b/.github/scripts/pr-quality-messages.test.cjs index ca6e056bd61..c344ce1bc06 100644 --- a/.github/scripts/pr-quality-messages.test.cjs +++ b/.github/scripts/pr-quality-messages.test.cjs @@ -208,7 +208,7 @@ describe("buildStaleNotice", () => { // The notice must describe the exact state the reset produces: a fresh // unticked section from pr-quality.cjs. const section = buildReviewReadinessSection(); - assert.match(section, /\[ \] All CI tests are green on my local testing\./); + assert.match(section, /\[ \] Required local validation passed; commands, results, and any full-suite exception are documented\./); }); }); diff --git a/.github/scripts/pr-quality.cjs b/.github/scripts/pr-quality.cjs index 32e0500c441..4e9d8e3eccd 100644 --- a/.github/scripts/pr-quality.cjs +++ b/.github/scripts/pr-quality.cjs @@ -25,7 +25,7 @@ const REVIEW_READINESS_END = ""; * so the "ready" claim reads as the closing confirmation, not a fourth task. */ const REVIEW_READINESS_ITEMS = [ - "All CI tests are green on my local testing.", + "Required local validation passed; commands, results, and any full-suite exception are documented.", "I pushed my PR to the latest dev commit.", "I resolved all correct Codex and CodeRabbit findings.", "My PR is ready for review.", diff --git a/.github/scripts/pr-quality.test.cjs b/.github/scripts/pr-quality.test.cjs index 55c948d65af..eaeca6cd08d 100644 --- a/.github/scripts/pr-quality.test.cjs +++ b/.github/scripts/pr-quality.test.cjs @@ -409,7 +409,7 @@ describe("review readiness checklist", () => { it("treats a reworded but complete section as complete", () => { const reworded = SECTION - .replace("All CI tests are green on my local testing.", "Local suite green.") + .replace("Required local validation passed; commands, results, and any full-suite exception are documented.", "Local suite green.") .replaceAll("- [ ] ", "- [x] "); const result = extractReviewReadiness(reworded); assert.equal(result.present, true); @@ -585,7 +585,7 @@ describe("uncheckReviewReadinessBoxes", () => { "", "## Review readiness checklist", "", - "- [x] All CI tests are green on my local testing.", + "- [x] Required local validation passed; commands, results, and any full-suite exception are documented.", "- [x] I pushed my PR to the latest dev commit.", "- [x] I resolved all correct Codex and CodeRabbit findings.", "- [x] My PR is ready for review.", @@ -596,7 +596,7 @@ describe("uncheckReviewReadinessBoxes", () => { const body = uncheckReviewReadinessBoxes(checkedBody, [ REVIEW_READINESS_CLAIM_INDEX.latest_dev, ]); - assert.ok(body.includes("- [x] All CI tests are green on my local testing.")); + assert.ok(body.includes("- [x] Required local validation passed; commands, results, and any full-suite exception are documented.")); assert.ok(body.includes("- [ ] I pushed my PR to the latest dev commit.")); assert.ok(body.includes("- [x] My PR is ready for review.")); }); @@ -606,7 +606,7 @@ describe("uncheckReviewReadinessBoxes", () => { 0, REVIEW_READINESS_CLAIM_INDEX.latest_dev, ]); - assert.ok(body.includes("- [ ] All CI tests are green on my local testing.")); + assert.ok(body.includes("- [ ] Required local validation passed; commands, results, and any full-suite exception are documented.")); assert.ok(body.includes("- [ ] I pushed my PR to the latest dev commit.")); assert.ok(body.includes("- [x] I resolved all correct Codex and CodeRabbit findings.")); assert.ok(body.includes("- [x] My PR is ready for review.")); diff --git a/AGENTS.md b/AGENTS.md index 5fc447e7c3c..d57f4f7659f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -196,7 +196,7 @@ it binds you regardless of which mechanism is within reach. bun install bun run typecheck # bun x tsc --noEmit (strict) bun run test:changed # import-graph tests against the resolved `dev` merge base -bun run test # full tests/ suite (PR-ready / explicit ask only) +bun run test # full tests/ suite (default before review) bun run lint:gui # GUI eslint bun run privacy:scan # credential/privacy scan used by CI bun run structure:check # structure/ doc-map, ownership, and invariant-binding gate @@ -217,23 +217,29 @@ bun run skill:surface:check # what CI asserts also if the hand-written pages name a command the registry does not have. That second check is not hypothetical: it caught a documented `ocx request-history` that never existed. -During implementation, use the smallest focused checks that directly cover the -changed subsystem. Prefer `bun test tests//.test.ts` for a known -file, `bun test tests/` for one subsystem, or -`bun run test:changed` when the touch set is broader than one file. Do **not** -run repository-wide `bun run test` or a bare `bun test` with no file arguments -for a scoped change by default. `bun run test:changed` follows Bun's parsed module graph: it -selects test files that import changed modules, but it cannot see dependencies -expressed through subprocesses, source files read as data, or golden/derived -files. Run the relevant focused tests explicitly for those paths; if no reliable -focused set covers them, the full suite is required even for a scoped change. -That indirect-dependency case is the explicit exception to the scoped-change -default. The full suite is ~850 files, so otherwise reserve it for a failed or -ambiguous focused result, an explicit user request, or the PR-ready gate below. - -Before creating or updating a non-trivial PR as review-ready, or before -approving such a PR, run `bun run typecheck` and `bun run test`. CI runs these -on Linux, Windows, and macOS. +Run the test suite for a change; `bun run test` is the default before a +non-trivial PR is marked review-ready or approved. During implementation, use +focused files or `bun run test:changed` for faster feedback. + +If a full local run is disproportionately expensive for the task or available +resources, including contention across concurrent worktrees, run at least the +focused regression tests that exercise the changed behavior. This is a scope +exception, not permission to skip testing or ignore a failing test. Record why +the full run was impractical, the exact commands and results, and the coverage +left to CI in the PR's Verification section. Never describe an unrun suite as +passing. Run `bun run typecheck` before review readiness as well. + +`bun run test:changed` follows Bun's parsed module graph, so it cannot discover +dependencies expressed through subprocesses, source files read as data, or +golden/derived files. Run those relevant regression files explicitly. If a +focused set cannot reliably cover the change, keep the PR in draft until the +broader validation is available. + +After pushing, inspect the required CI for the current PR head. Missing, +awaiting-approval, skipped, cancelled, or older-head results are not passing +evidence. Required checks must actually complete successfully before merge. +The repository does not install an automatic pre-push validation hook; +`bun run prepush` remains available as an explicit comprehensive check. Do not rerun passing checks on unchanged code merely for additional confidence. @@ -377,8 +383,9 @@ empty, thin, or malformed descriptions; PRs whose title or description mentions `gui` must include a screenshot of the UI change in the description. Contributor PRs (authors without repository push permission) open in draft and stay there until a four-box review-readiness checklist in the description is -complete: local CI green, branch on the latest `dev` commit, all correct Codex -and CodeRabbit findings fixed, and the ready-for-review confirmation. When all +complete: required local validation passed with its scope documented, branch +on the latest `dev` commit, all correct Codex and CodeRabbit findings fixed, +and the ready-for-review confirmation. When all four boxes are ticked the gate marks the PR ready and notifies the maintainers listed in `MAINTAINERS.md` (excluding the author). Completion is bound to the exact commit the PR head pointed at: if new commits are pushed afterwards, the @@ -387,7 +394,7 @@ and asks the author to test and tick the boxes again against the latest code. Before a completion is accepted, the gate verifies the checklist claims it can check itself: the branch must be on the latest `dev` commit or at most 10 commits behind it, and Codex/CodeRabbit findings must be resolved. The -local-CI box is an author attestation only — fork contributors cannot start +local-validation box is an author attestation only — fork contributors cannot start repository CI; a maintainer has to — so the gate never disproves it; a new push still resets every box. A disproved claim unticks the matching box and keeps the PR a draft. @@ -400,7 +407,7 @@ explicitly integrate through a PR without another maintainer approval, including their own PR, under the policy in `MAINTAINERS.md`. Record the decision and exact-head CI evidence; keep outstanding maintainer objections and security review separate. The bypass is PR-only, so a direct push to `dev` remains rejected regardless of -`--no-verify`. Contributor review and `main`/`preview` rules remain unchanged. +local hook settings. Contributor review and `main`/`preview` rules remain unchanged. [`MAINTAINERS.md`](./MAINTAINERS.md) is authoritative for review and merge policy (approvals, CI requirements, security review, promotion). This file @@ -430,7 +437,8 @@ reviewers (Codex, CodeRabbit). - **Tests:** behavior changes in `src/` need a focused regression test near the existing tests for that subsystem. During implementation, run the relevant focused files and use `bun run test:changed` for import-connected coverage as - described above; the full suite is the PR-ready gate. + described above. Full-suite validation is the default before review readiness; + the documented resource exception still requires focused regression tests. - **Docs sync:** user-facing behavior changes should update `docs-site/` (and keep translated locales from contradicting the English source). - **Privacy:** `bun run privacy:scan` must stay green; never introduce logging diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ea36e08eb46..9b0ecbc6e2d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,21 +56,22 @@ A ready-for-review PR is the author's claim that the change is complete, underst stated. A closed PR can be reopened once the stated reason is resolved, or replaced with a clean one. -## Pre-push hook +## Local validation and hooks -After cloning, run once to install a local pre-push hook that runs the typecheck, -unit-test, privacy-scan, and (when `gui/` changed) GUI eslint and React Doctor -portions of the CI gate: +Run `bun run test` before review readiness. If the full local suite is too costly +for the task or available resources, run at least focused regression tests for +the changed behavior. Document the reason, commands, results, and remaining +coverage in the PR. Follow [AGENTS.md](./AGENTS.md#commands) for the complete +validation policy; required CI must pass on the current PR head before merge. +`bun run prepush` remains an optional comprehensive local check. ```sh bun run setup:hooks ``` -This installs a `pre-push` hook (into the hooks dir git reports, so worktrees and -`core.hooksPath` work) that runs `bun run prepush` — `typecheck`, -`lint:gui:if-changed`, `test`, `privacy:scan`, and `doctor:gui:if-changed` — -before every `git push`. Both `lint:gui:if-changed` and `doctor:gui:if-changed` -run their check only when the push touches `gui/`. -The same checks run on ubuntu-latest, macos-latest, and windows-latest in CI (CI -additionally builds the GUI and smoke-tests the CLI). Skip in an emergency with -`git push --no-verify`. +This installs the `post-merge` hook, which rebuilds the packaged dashboard when a +merge changes its source. It also removes the unmodified, retired repository +pre-push hook from Git's resolved hooks directory, including linked worktrees +and `core.hooksPath` setups. Custom pre-push hooks are preserved. Validation no +longer runs automatically on every push; existing contributors should rerun the +setup command once to migrate their hooks. diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 4d047649567..5c05f60ad45 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -36,7 +36,8 @@ when a maintainer steps down. mentions `gui` must include a screenshot of the UI change in the description. Contributor PRs (authors without repository push permission) open in draft and stay there until a four-box review-readiness checklist in the - description is complete: local CI green, branch on the latest `dev` commit, + description is complete: required local validation passed with its scope documented, + branch on the latest `dev` commit, all correct Codex and CodeRabbit findings fixed, and the ready-for-review confirmation. When all four boxes are ticked the gate marks the PR ready and notifies the maintainers listed in `MAINTAINERS.md` (excluding the author). @@ -47,8 +48,11 @@ when a maintainer steps down. Before a completion is accepted, the gate verifies the checklist claims it can check itself: the branch must be on the latest `dev` commit or at most 10 commits behind it, and Codex/CodeRabbit findings must be resolved. - The local-CI box is an author attestation only — fork contributors cannot - start repository CI; a maintainer has to — so the gate never disproves it; + The local-validation box follows the full-suite default and documented resource + exception in [AGENTS.md](./AGENTS.md#commands); focused regression tests remain + mandatory under that exception. It is an author attestation only — fork + contributors cannot start repository CI; a maintainer has to — so the gate + never disproves it; a new push still resets every box. A disproved claim unticks the matching box and keeps the PR a draft. Authors with repository push permission skip the ancestry heuristic only. As diff --git a/docs-site/src/content/docs/contributing.md b/docs-site/src/content/docs/contributing.md index e6f9844c1ff..947cedfb273 100644 --- a/docs-site/src/content/docs/contributing.md +++ b/docs-site/src/content/docs/contributing.md @@ -12,14 +12,17 @@ Bun runtime for users, but this checkout's scripts run through your local Bun in git clone https://github.com/lidge-jun/opencodex.git cd opencodex bun install +bun run setup:hooks # install post-merge; retire the managed pre-push hook bun run dev:proxy # proxy API in dev mode bun run dev:gui # dashboard dev server (another terminal) bun run typecheck # bun x tsc --noEmit -bun run test:changed # routine import-graph test selection -bun test tests/routing/router.test.ts # routine focused test -bun run test # complete suite (PR-ready / explicit ask) +bun run test # full suite (default) ``` +`bun run setup:hooks` installs only `post-merge` and removes an unmodified retired managed +`pre-push` hook, preserving custom hooks. A pre-push hook is no longer required. +`bun run prepush` remains an optional manual check. + `bun run dev` remains an alias for `bun run dev:proxy`. The dashboard dev server is `bun run dev:gui`; the packaged dashboard at `GET /` is produced by `bun run build:gui` (`gui/dist`). @@ -31,13 +34,21 @@ scripts so local commands match CI: ```bash bun run typecheck # strict TypeScript check bun run test:changed # import-graph tests against the resolved dev merge base -bun run test # complete tests/ suite (PR-ready / explicit ask) +bun run test # full suite (default) bun test tests/routing/router.test.ts # focused test file bun run build:gui # Vite GUI build + package preparation bun run privacy:scan # credential/privacy scan used by CI bun run prepare:package # refresh package launchers/assets ``` +Run `bun run test` by default. If a full run is disproportionately expensive for the task size, +available machine resources, or concurrent worktrees, you must at least run focused regression tests +that exercise the changed behavior, such as `bun test tests//.test.ts`. Explain the +reason for narrowing the run and report the exact commands, results, and untested scope. +`bun run test:changed` can supplement this coverage, but it cannot detect every indirect dependency. +Neither relying only on CI nor skipping local testing is a blanket exemption. Before merge, all +required CI checks must pass for the exact current PR head. + `test:changed` selects the first comparison ref that exists, in order: `upstream/dev`, `origin/dev`, then local `dev`. It reports that ref and the exact `git merge-base HEAD ` commit, then passes the merge-base SHA to Bun. @@ -54,8 +65,7 @@ and `tests/test-layout.test.ts` enforces it, so a new test goes into its domain an entry in the map (the tooling test tells you which one is missing). `tests/helpers/` holds shared fixtures and `tests/helpers/repo-root.ts` is how a test reaches repository files; `tests/e2e-style/` holds broader native-parity scenarios. Keep a focused regression near the -existing tests for the subsystem you change (`bun test tests/` runs one subsystem); run -the full suite for shared routing, adapters, config, or server behavior. +existing tests for the subsystem you change (`bun test tests/` runs one subsystem). The docs site you're reading lives in `docs-site/` (Astro + Starlight): @@ -250,6 +260,6 @@ startup path must not import the manifest catalog or activate Compatibility Lab. ## Verify before you claim done -Run the narrowest command that proves your change — `bun run typecheck` for types, a focused -`bun test tests//.test.ts` or runtime probe for behavior, then the broader gates appropriate to -the affected surface. opencodex favors small, verifiable commits over large batches. +Follow the testing policy above and run `bun run typecheck` for type changes, plus the checks +required for the affected surface. Report the commands, results, and remaining untested scope; +only claim the validation you actually completed. diff --git a/docs-site/src/content/docs/contributing/pr-quality.md b/docs-site/src/content/docs/contributing/pr-quality.md index 27bf69f5554..b0a42b19ff5 100644 --- a/docs-site/src/content/docs/contributing/pr-quality.md +++ b/docs-site/src/content/docs/contributing/pr-quality.md @@ -51,8 +51,8 @@ tells you exactly what to change: self-waive the screenshot requirement. Contributor PRs (authors without repository push permission) open in draft and stay there until a four-box review-readiness checklist in the - description is complete: local CI green, the branch on the latest `dev` - commit, all correct Codex and CodeRabbit findings fixed, and the + description is complete: required local validation passed with its scope + documented, the branch on the latest `dev` commit, all correct Codex and CodeRabbit findings fixed, and the ready-for-review confirmation. Once every box is ticked the check marks the PR ready for review and notifies the maintainers listed in `MAINTAINERS.md` (excluding the author). The gate's status and "what to do" live in a single @@ -67,8 +67,9 @@ tells you exactly what to change: can check itself: the branch must be on the latest `dev` commit or at most 10 commits behind it, and every Codex and CodeRabbit review thread authored by a review bot on the current head must be resolved (unresolved threads - from other authors do not block). The local-CI box is an author attestation - only — fork contributors cannot start repository CI; a maintainer has to — + from other authors do not block). The local-validation box follows the [test-scope policy](/contributing/#build-and-test-commands): + run the full suite by default; when it is too costly, run focused regressions + and document the exception. It is an author attestation only — fork contributors cannot start repository CI; a maintainer has to — so the gate never disproves it; a new push still resets every box. CodeRabbit findings that fall outside the diff range and are reported only in a review body on the current head add to the unresolved count while a bot review diff --git a/docs-site/src/content/docs/fr/contributing.md b/docs-site/src/content/docs/fr/contributing.md index 345d31359f2..d7a5e9296a3 100644 --- a/docs-site/src/content/docs/fr/contributing.md +++ b/docs-site/src/content/docs/fr/contributing.md @@ -12,14 +12,17 @@ runtime Bun aux utilisateurs, mais les scripts de ce dépôt utilisent votre ins git clone https://github.com/lidge-jun/opencodex.git cd opencodex bun install +bun run setup:hooks # installer post-merge et retirer l’ancien pre-push géré bun run dev:proxy # proxy API in dev mode bun run dev:gui # dashboard dev server (another terminal) bun run typecheck # bun x tsc --noEmit -bun run test:changed # routine import-graph test selection -bun test tests/routing/router.test.ts # routine focused test -bun run test # complete suite (PR-ready / explicit ask) +bun run test # suite complète (par défaut) ``` +`bun run setup:hooks` installe uniquement `post-merge` et supprime l’ancien hook `pre-push` +géré s’il n’a pas été modifié, tout en préservant les hooks personnalisés. Le hook `pre-push` +n’est plus obligatoire. `bun run prepush` reste une vérification manuelle facultative. + `bun run dev` reste un alias pour `bun run dev:proxy`. Le serveur de développement du tableau de bord est `bun run dev:gui` ; le tableau de bord packagé en `GET /` est produit par `bun run build:gui` (`gui/dist`). @@ -31,17 +34,25 @@ distincte. Utilisez les scripts enregistrés afin que les commandes locales corr ```bash bun run typecheck # strict TypeScript check bun run test:changed # import-graph tests against the resolved dev merge base -bun run test # complete tests/ suite (PR-ready / explicit ask) +bun run test # suite complète (par défaut) bun test tests/routing/router.test.ts # focused test file bun run build:gui # Vite GUI build + package preparation bun run privacy:scan # credential/privacy scan used by CI bun run prepare:package # refresh package launchers/assets ``` +Exécutez `bun run test` par défaut. Si une exécution complète est disproportionnée par rapport +à la taille de la tâche, aux ressources de la machine ou aux worktrees utilisés en parallèle, vous +devez au minimum exécuter des tests de régression ciblés qui exercent le comportement modifié, par +exemple `bun test tests//.test.ts`. Expliquez ce choix et indiquez les commandes +exactes, leurs résultats et le périmètre non testé. `bun run test:changed` peut compléter cette +couverture, mais ne détecte pas toutes les dépendances indirectes. Se reposer uniquement sur la CI +ou omettre les tests locaux ne constitue pas une exemption générale. Avant la fusion, tous les +contrôles CI obligatoires doivent réussir sur le commit exact de la tête actuelle de la PR. + Les tests Bun vivent dans des répertoires par domaine calqués sur `src/` (`tests//`), la carte étant `scripts/test-layout/layout.json`. `tests/helpers/` contient les fixtures partagées et `tests/e2e-style/` des scénarios plus larges de parité native. Placez une régression ciblée près -des tests existants du sous-système modifié. Exécutez la suite complète pour le routage partagé, les adaptateurs, -la configuration ou le comportement du serveur. +des tests existants du sous-système modifié. Le site de documentation que vous lisez se trouve dans `docs-site/` (Astro + Starlight) : @@ -224,6 +235,6 @@ la fabrique depuis `src/index.ts` lorsqu’elle appartient à l’API publique d ## Vérifiez avant de déclarer que c'est fait -Exécutez la commande la plus étroite qui prouve votre changement — `bun run typecheck` pour les types, un -`bun test tests/.test.ts` ou une sonde d'exécution pour le comportement, puis les portes plus larges appropriées à -la surface affectée. opencodex privilégie les petits commits vérifiables plutôt que les gros lots. +Suivez la politique de test ci-dessus et exécutez `bun run typecheck` pour les changements de types, +ainsi que les vérifications requises pour la zone concernée. Indiquez les commandes, les résultats +et le périmètre non testé ; ne revendiquez que les validations réellement effectuées. diff --git a/docs-site/src/content/docs/fr/contributing/pr-quality.md b/docs-site/src/content/docs/fr/contributing/pr-quality.md index 448432cbc1c..0dd1bee5b24 100644 --- a/docs-site/src/content/docs/fr/contributing/pr-quality.md +++ b/docs-site/src/content/docs/fr/contributing/pr-quality.md @@ -44,8 +44,8 @@ Trois contrôles déterministes précèdent la revue humaine. Chaque message d déclenchent plus le contrôle privilégié. Un contributeur ne peut pas lever lui-même cette exigence. Les PR de contributeurs sans droit de push sur le dépôt s’ouvrent en brouillon et le restent jusqu’à ce que - les quatre cases de préparation à la revue soient cochées dans la description : CI locale verte, branche sur - le dernier commit de `dev`, tous les constats valides de Codex et CodeRabbit corrigés, et confirmation de + les quatre cases de préparation à la revue soient cochées dans la description : validation locale requise réussie + (commandes, résultats et toute exception à la suite complète documentés), branche sur le dernier commit de `dev`, tous les constats valides de Codex et CodeRabbit corrigés, et confirmation de disponibilité pour la revue. Lorsque les quatre cases sont cochées, le contrôle marque la PR comme prête et avertit les responsables répertoriés dans `MAINTAINERS.md`, à l’exclusion de l’auteur. L’état du contrôle et les actions attendues figurent dans un unique commentaire consolidé, réécrit à chaque exécution. @@ -58,7 +58,7 @@ Trois contrôles déterministes précèdent la revue humaine. Chaque message d Avant d’accepter la liste, le contrôle vérifie les affirmations qu’il peut lui-même confirmer : la branche doit être sur le dernier commit de `dev`, ou au plus 10 commits derrière, et tous les fils de revue Codex et CodeRabbit créés par un robot sur la tête actuelle doivent être résolus. Les fils non résolus d’autres auteurs - ne bloquent pas. La case de CI locale est uniquement une attestation de l’auteur : les contributeurs depuis un + ne bloquent pas. La case de validation locale requise est uniquement une attestation de l’auteur : les contributeurs depuis un fork ne peuvent pas démarrer la CI du dépôt, seul un responsable le peut. Le contrôle ne contredit donc jamais cette case, mais tout nouveau push réinitialise toutes les cases. @@ -76,7 +76,8 @@ Trois contrôles déterministes précèdent la revue humaine. Chaque message d - **Hygiène.** Les changements de comportement exigent un test. Les nouvelles suppressions de règles de lint ou de types, les tests ciblés ou ignorés, les blocs catch vides, la modification de sorties générées et celle d’un lockfile sans son manifeste nécessitent chacun un label d’approbation explicite. Une modification limitée - à un commentaire dans un fichier source ne change pas le comportement et n’exige aucun test. + à un commentaire dans un fichier source ne change pas le comportement et n’exige aucun nouveau test + de régression. La [politique de test locale](/fr/contributing/) reste applicable. - **CI multiplateforme.** Pour les changements concernés, la suite est fragmentée sous Linux et exécutée intégralement sous macOS pour chaque pull request. La voie Windows principale ne s’exécute actuellement que diff --git a/docs-site/src/content/docs/ja/contributing.md b/docs-site/src/content/docs/ja/contributing.md index 115d182ef64..36f5a389c75 100644 --- a/docs-site/src/content/docs/ja/contributing.md +++ b/docs-site/src/content/docs/ja/contributing.md @@ -9,14 +9,17 @@ description: opencodex の開発環境、構成、規約、プロバイダーと git clone https://github.com/lidge-jun/opencodex.git cd opencodex bun install +bun run setup:hooks # post-merge の導入と旧管理対象 pre-push の削除 bun run dev:proxy # 開発モードのプロキシ API bun run dev:gui # ダッシュボード dev サーバー(別ターミナル) bun run typecheck # bun x tsc --noEmit -bun run test:changed # routine import-graph test selection -bun test tests/routing/router.test.ts # routine focused test -bun run test # complete suite (PR-ready / explicit ask) +bun run test # 全テストスイート(既定) ``` +`bun run setup:hooks` は `post-merge` だけを導入し、変更されていない旧管理対象の `pre-push` +フックを削除します。カスタムフックは保持します。`pre-push` フックは必須ではなくなりました。 +`bun run prepush` は任意の手動チェックとして引き続き利用できます。 + `bun run dev` は引き続き `bun run dev:proxy` のエイリアスとして動作します。ダッシュボード dev サーバーは `bun run dev:gui` で、`GET /` で提供するパッケージダッシュボードは `bun run build:gui` でビルドして `gui/dist` に作成します。 @@ -35,10 +38,17 @@ bun run privacy:scan # CI で使う資格情報/個人情報検査 bun run prepare:package # パッケージランチャー/asset 更新 ``` +既定では `bun run test` で全テストスイートを実行してください。作業規模、マシンのリソース、 +同時使用中のワークツリーに対して全体実行の負担が過大な場合でも、変更した動作を実際に検証する +回帰テストを最低限実行する必要があります。例は `bun test tests//.test.ts` です。 +範囲を絞った理由、正確なコマンド、結果、未テストの範囲を明記してください。 +`bun run test:changed` は補完に使えますが、すべての間接依存関係を検出するものではありません。 +CI だけに任せたり、ローカルテストを一律に省略したりする例外はありません。マージ前には、 +現在の PR ヘッドの正確なコミットですべての必須 CI チェックが成功している必要があります。 + テストは `src/` を写したドメインディレクトリ(`tests//`)に置かれた Bun テストで、対応表は `scripts/test-layout/layout.json` です。共有 fixture は `tests/helpers/`、範囲の広いネイティブ等価性シナリオは `tests/e2e-style/` にあります。変更した -サブシステムの既存テストの近くに集中した回帰テストを追加してください。共有ルーティング、アダプター、設定、サーバー -動作を触った場合は全体スイートも実行します。 +サブシステムの既存テストの近くに集中した回帰テストを追加してください。 いま読んでいるドキュメントサイトは `docs-site/` にあります(Astro + Starlight)。 @@ -170,6 +180,5 @@ manifest catalog を import したり、Compatibility Lab を有効化したり ## 完了を主張する前に検証 -変更を証明する最も狭いコマンドから実行してください。型は `bun run typecheck`、動作は集中した -`bun test tests/.test.ts` またはランタイム probe で確認した後、影響範囲に応じた広い gate を -実行します。opencodex は大きな batch より小さく検証可能な commit を好みます。 +上記のテスト方針に従い、型の変更には `bun run typecheck` を含め、影響範囲に必要な検証を +実行してください。コマンド、結果、未テストの範囲を報告し、実際に完了した検証だけを主張してください。 diff --git a/docs-site/src/content/docs/ko/contributing.md b/docs-site/src/content/docs/ko/contributing.md index f6eee2bc16a..1d297a91aa6 100644 --- a/docs-site/src/content/docs/ko/contributing.md +++ b/docs-site/src/content/docs/ko/contributing.md @@ -9,14 +9,17 @@ description: opencodex 개발 환경, 구조, 컨벤션, 프로바이더와 어 git clone https://github.com/lidge-jun/opencodex.git cd opencodex bun install +bun run setup:hooks # post-merge 설치 및 기존 관리형 pre-push 제거 bun run dev:proxy # 개발 모드 프록시 API bun run dev:gui # 대시보드 dev 서버(다른 터미널) bun run typecheck # bun x tsc --noEmit -bun run test:changed # routine import-graph test selection -bun test tests/routing/router.test.ts # routine focused test -bun run test # complete suite (PR-ready / explicit ask) +bun run test # 전체 테스트 스위트 (기본) ``` +`bun run setup:hooks`는 `post-merge`만 설치하고, 수정되지 않은 기존 관리형 `pre-push` 훅을 +제거합니다. 사용자 정의 훅은 보존합니다. `pre-push` 훅은 더 이상 필수가 아니며, +`bun run prepush`는 선택적으로 직접 실행할 수 있습니다. + `bun run dev`는 계속 `bun run dev:proxy`의 별칭으로 동작합니다. 대시보드 dev 서버는 `bun run dev:gui`이며, `GET /`에서 제공하는 패키지 대시보드는 `bun run build:gui`로 빌드해 `gui/dist`에 만듭니다. @@ -35,10 +38,17 @@ bun run privacy:scan # CI에서 쓰는 자격 증명/개인정보 bun run prepare:package # 패키지 런처/asset 갱신 ``` +기본적으로 `bun run test`로 전체 테스트 스위트를 실행하세요. 작업 규모, 머신 자원 또는 동시에 +사용 중인 워크트리 때문에 전체 실행 비용이 지나치게 크다면, 최소한 변경한 동작을 실제로 검증하는 +집중 회귀 테스트를 실행해야 합니다. 예를 들어 `bun test tests//.test.ts`를 사용할 수 +있습니다. 범위를 줄인 이유와 정확한 실행 명령, 결과, 테스트하지 않은 범위를 명시하세요. +`bun run test:changed`는 보완 수단이며 모든 간접 의존성을 찾지는 못합니다. CI에만 맡기거나 +로컬 테스트를 생략하는 일괄 면제는 없습니다. 병합 전에는 현재 PR 헤드의 정확한 커밋에서 +모든 필수 CI 검사가 통과해야 합니다. + 테스트는 `src/`를 따라 나눈 도메인 디렉터리(`tests//`)에 놓인 Bun 테스트이며, 지도는 `scripts/test-layout/layout.json`입니다. 공용 fixture는 `tests/helpers/`, 범위가 넓은 네이티브 동등성 시나리오는 `tests/e2e-style/`에 있습니다. 바꾼 -subsystem의 기존 테스트 근처에 집중된 회귀 테스트를 추가하세요. 공용 라우팅, 어댑터, 설정, 서버 -동작을 건드렸다면 전체 스위트도 실행합니다. +subsystem의 기존 테스트 근처에 집중된 회귀 테스트를 추가하세요. 지금 읽고 있는 문서 사이트는 `docs-site/`에 있습니다(Astro + Starlight). @@ -168,6 +178,5 @@ catalog를 import하거나 Compatibility Lab을 활성화해서는 안 됩니다 ## 완료를 주장하기 전에 검증하기 -변경을 증명하는 가장 좁은 명령부터 실행하세요. 타입은 `bun run typecheck`, 동작은 집중된 -`bun test tests/.test.ts` 또는 런타임 probe로 확인한 뒤 영향 범위에 맞는 넓은 gate를 -실행합니다. opencodex는 큰 batch보다 작고 검증 가능한 commit을 선호합니다. +위 테스트 정책을 따르고, 타입 변경에는 `bun run typecheck`를 포함해 영향 범위에 필요한 검사를 +실행하세요. 실행 명령, 결과, 테스트하지 않은 범위를 보고하고 실제로 완료한 검증만 주장하세요. diff --git a/docs-site/src/content/docs/ru/contributing.md b/docs-site/src/content/docs/ru/contributing.md index a1857f6821f..13ceba3cda5 100644 --- a/docs-site/src/content/docs/ru/contributing.md +++ b/docs-site/src/content/docs/ru/contributing.md @@ -9,14 +9,17 @@ description: Разработка opencodex — настройка окруже git clone https://github.com/lidge-jun/opencodex.git cd opencodex bun install +bun run setup:hooks # установить post-merge и удалить прежний управляемый pre-push bun run dev:proxy # прокси-API в режиме разработки bun run dev:gui # dev-сервер дашборда (другой терминал) bun run typecheck # bun x tsc --noEmit -bun run test:changed # routine import-graph test selection -bun test tests/routing/router.test.ts # routine focused test -bun run test # complete suite (PR-ready / explicit ask) +bun run test # полный набор тестов (по умолчанию) ``` +`bun run setup:hooks` устанавливает только `post-merge` и удаляет прежний управляемый хук +`pre-push`, если он не был изменён. Пользовательские хуки сохраняются. Хук `pre-push` больше +не обязателен; `bun run prepush` остаётся необязательной ручной проверкой. + `bun run dev` остаётся псевдонимом для `bun run dev:proxy`. Dev-сервер дашборда — `bun run dev:gui`; упакованный дашборд, доступный по `GET /`, собирается командой `bun run build:gui` (`gui/dist`). @@ -34,10 +37,18 @@ bun run privacy:scan # проверка учётных данных bun run prepare:package # обновление лаунчеров/ресурсов пакета ``` +По умолчанию запускайте `bun run test`. Если полный прогон несоразмерно затратен с учётом +размера задачи, ресурсов машины или одновременно используемых рабочих деревьев, обязательно +выполните хотя бы целевые регрессионные тесты, проверяющие изменённое поведение, например +`bun test tests//.test.ts`. Объясните причину сокращения прогона и укажите точные +команды, результаты и непроверенную область. `bun run test:changed` дополняет проверку, но не +обнаруживает все косвенные зависимости. Нельзя устанавливать общее исключение, позволяющее +полагаться только на CI или пропускать локальные тесты. Перед слиянием все обязательные проверки +CI должны успешно завершиться для точного текущего коммита HEAD pull request. + Bun-тесты лежат в доменных каталогах, повторяющих `src/` (`tests//`); карта — `scripts/test-layout/layout.json`. В `tests/helpers/` лежат общие fixtures, а в `tests/e2e-style/` — более широкие сценарии нативного паритета. Добавляйте сфокусированный -регрессионный тест рядом с существующими тестами изменяемой подсистемы; если затронуты общая -маршрутизация, адаптеры, конфигурация или поведение сервера, запускайте полный набор. +регрессионный тест рядом с существующими тестами изменяемой подсистемы. Сайт документации, который вы сейчас читаете, находится в `docs-site/` (Astro + Starlight): @@ -173,7 +184,6 @@ startup path не должны импортировать каталог ман ## Проверяйте, прежде чем объявлять работу завершённой -Запускайте самую узкую команду, которая доказывает ваше изменение: `bun run typecheck` для типов, -сфокусированный `bun test tests/.test.ts` или runtime-проверку для поведения, а затем более -широкие проверки, соответствующие затронутой области. opencodex предпочитает небольшие проверяемые -коммиты крупным пачкам изменений. +Следуйте политике тестирования выше и выполняйте `bun run typecheck` при изменении типов, +а также проверки для затронутой области. Указывайте команды, результаты и непроверенную область; +заявляйте только о реально выполненной проверке. diff --git a/docs-site/src/content/docs/tr/contributing.md b/docs-site/src/content/docs/tr/contributing.md index cd00f952625..c6ef4434036 100644 --- a/docs-site/src/content/docs/tr/contributing.md +++ b/docs-site/src/content/docs/tr/contributing.md @@ -14,14 +14,17 @@ aracının bulunması gerekir. Yayınlanan npm paketi kullanıcılar için kendi git clone https://github.com/lidge-jun/opencodex.git cd opencodex bun install +bun run setup:hooks # post-merge kur ve eski yönetilen pre-push kancasını kaldır bun run dev:proxy # geliştirme modunda proxy API bun run dev:gui # kontrol paneli geliştirme sunucusu (başka bir terminalde) bun run typecheck # bun x tsc --noEmit -bun run test:changed # routine import-graph test selection -bun test tests/routing/router.test.ts # routine focused test -bun run test # complete suite (PR-ready / explicit ask) +bun run test # tam test paketi (varsayılan) ``` +`bun run setup:hooks` yalnızca `post-merge` kancasını kurar ve değiştirilmemiş eski yönetilen +`pre-push` kancasını kaldırır; özel kancaları korur. `pre-push` kancası artık zorunlu değildir. +`bun run prepush` isteğe bağlı bir manuel denetim olarak kullanılabilir. + `bun run dev`, `bun run dev:proxy` komutunun bir takma adıdır. Kontrol paneli geliştirme sunucusu `bun run dev:gui` ile çalışır; `GET /` adresindeki paketlenmiş kontrol paneli ise `bun run build:gui` (`gui/dist`) tarafından @@ -41,12 +44,19 @@ bun run privacy:scan # CI tarafından kullanılan kimlik/gizlilik t bun run prepare:package # paket başlatıcılarını ve varlıklarını yenileme ``` +Varsayılan olarak `bun run test` çalıştırın. Tam çalıştırma görevin boyutu, makine kaynakları +veya eşzamanlı kullanılan çalışma ağaçları nedeniyle orantısız derecede maliyetliyse, en azından +değişen davranışı gerçekten sınayan odaklanmış regresyon testlerini çalıştırmanız gerekir; örneğin +`bun test tests//.test.ts`. Kapsamı daraltma nedenini, tam komutları, sonuçları ve +test edilmeyen kapsamı açıklayın. `bun run test:changed` kapsamı destekleyebilir ancak tüm dolaylı +bağımlılıkları bulamaz. Yalnızca CI sonucuna güvenmek veya yerel testleri atlamak için genel bir +muafiyet yoktur. Birleştirmeden önce tüm zorunlu CI denetimleri PR’ın mevcut başındaki tam commit +için başarılı olmalıdır. + Bun testleri `src/` yapısını yansıtan alan dizinlerinde (`tests//`) bulunur; harita `scripts/test-layout/layout.json` dosyasıdır. `tests/helpers/` paylaşılan test ortamlarını (fixtures) ve `tests/e2e-style/` daha geniş yerel parite senaryolarını içerir. Değiştirdiğiniz alt sistemin mevcut testlerinin -yakınında odaklanmış bir regresyon testi bulundurun; paylaşılan yönlendirme, -adaptörler, yapılandırma veya sunucu davranışları için test paketinin tamamını -çalıştırın. +yakınında odaklanmış bir regresyon testi bulundurun. Okumakta olduğunuz dokümantasyon sitesi `docs-site/` (Astro + Starlight) dizinindedir: @@ -263,7 +273,6 @@ fabrikayı `src/index.ts` dosyasından dışa aktarın. ## Bittiğini iddia etmeden önce doğrulayın -Değişikliğinizi kanıtlayan en dar komutu çalıştırın — tipler için `bun run -typecheck`, davranış için odaklanmış bir `bun test tests/.test.ts` veya -çalışma zamanı probu, ardından etkilenen yüzeye uygun daha geniş kapılar. -opencodex büyük partiler yerine küçük, doğrulanabilir commit'leri tercih eder. +Yukarıdaki test politikasını izleyin; tip değişiklikleri için `bun run typecheck` ve etkilenen +alanın gerektirdiği denetimleri çalıştırın. Komutları, sonuçları ve test edilmeyen kapsamı +bildirin; yalnızca gerçekten tamamlanan doğrulamaları belirtin. diff --git a/docs-site/src/content/docs/tr/contributing/pr-quality.md b/docs-site/src/content/docs/tr/contributing/pr-quality.md index 3248aa7a2a0..5067e730604 100644 --- a/docs-site/src/content/docs/tr/contributing/pr-quality.md +++ b/docs-site/src/content/docs/tr/contributing/pr-quality.md @@ -55,7 +55,8 @@ tam olarak neyi değiştirmeniz gerektiğini söyler: edemez. Katkıda bulunan PR'ları (depo yazma izni olmayan yazarlar) taslak olarak açılır ve açıklamadaki dört kutulu incelemeye hazırlık kontrol listesi tamamlanana -kadar orada kalır: yerel CI yeşil, dal en son `dev` commit'inde, tüm doğru Codex +kadar orada kalır: gerekli yerel doğrulama başarılı +(komutlar, sonuçlar ve tam test paketi istisnaları belgelenmiş), dal en son `dev` commit'inde, tüm doğru Codex ve CodeRabbit bulguları düzeltildi ve incelemeye hazır onayı. Her kutu işaretlendikten sonra kontrol, PR'ı incelemeye hazır olarak işaretler ve `MAINTAINERS.md` dosyasında listelenen bakımcıları bilgilendirir (yazar hariç). @@ -71,7 +72,7 @@ Bir tamamlama kabul edilmeden önce kapı, kontrol listesinin kendisinin kontrol edebileceği iddiaları doğrular: dal en son `dev` commit'inde veya en fazla 10 commit gerisinde olmalı ve geçerli head üzerinde bir inceleme botu tarafından yazılan her Codex ve CodeRabbit inceleme konusu çözülmelidir (diğer yazarların -çözülmemiş konuları engellemez). Yerel CI kutusu yalnızca bir yazar beyanıdır — +çözülmemiş konuları engellemez). Gerekli yerel doğrulama kutusu yalnızca bir yazar beyanıdır — fork katkıda bulunanları depo CI'ını başlatamaz; bir bakımcının başlatması gerekir — bu nedenle kapı bunu asla çürütmez; yeni bir push yine de her kutuyu sıfırlar. Fark aralığının dışına düşen ve yalnızca geçerli head üzerindeki bir @@ -93,8 +94,8 @@ PR-head kodu yürütülmez. lint veya tip bastırmaları, odaklanmış veya atlanmış testler, boş catch blokları, düzenlenen üretilmiş çıktılar ve manifestosu olmadan değiştirilen bir kilit dosyası (lockfile) açık bir onay etiketine ihtiyaç duyar. Bir kaynak - dosyadaki yalnızca yorum değişikliği bir davranış değişikliği değildir ve test - gerektirmez. + dosyadaki yalnızca yorum değişikliği bir davranış değişikliği değildir ve yeni + bir regresyon testi gerektirmez. [Yerel test politikası](/tr/contributing/) yine geçerlidir. - **Çapraz platform CI.** Test paketi her çekme isteği için Linux'ta parçalı (sharded) ve macOS'ta tam olarak çalışır. Windows, dağıtım sınırında çalışır — `main` veya `preview` dalına yükseltmede — bu nedenle yavaş veya kararsız bir diff --git a/docs-site/src/content/docs/zh-cn/contributing.md b/docs-site/src/content/docs/zh-cn/contributing.md index a25ea4fcb10..6fc0a0df66b 100644 --- a/docs-site/src/content/docs/zh-cn/contributing.md +++ b/docs-site/src/content/docs/zh-cn/contributing.md @@ -9,14 +9,16 @@ description: opencodex 的开发环境、结构、约定,以及添加 provider git clone https://github.com/lidge-jun/opencodex.git cd opencodex bun install +bun run setup:hooks # 安装 post-merge 并移除旧的托管 pre-push bun run dev:proxy # 开发模式代理 API bun run dev:gui # 仪表盘 dev 服务器(另一个终端) bun run typecheck # bun x tsc --noEmit -bun run test:changed # routine import-graph test selection -bun test tests/routing/router.test.ts # routine focused test -bun run test # complete suite (PR-ready / explicit ask) +bun run test # 完整测试套件(默认) ``` +`bun run setup:hooks` 仅安装 `post-merge`,并移除未经修改的旧版托管 `pre-push` 钩子, +保留自定义钩子。`pre-push` 钩子不再是必需项;`bun run prepush` 仍可作为可选的手动检查。 + `bun run dev` 继续作为 `bun run dev:proxy` 的别名。仪表盘 dev 服务器使用 `bun run dev:gui`; `GET /` 提供的打包仪表盘由 `bun run build:gui` 构建到 `gui/dist`。 @@ -34,9 +36,15 @@ bun run privacy:scan # CI 使用的 credential/privacy 扫描 bun run prepare:package # 刷新 package launcher/asset ``` +默认运行 `bun run test` 执行完整测试套件。如果相对于任务规模、机器资源或并行使用的工作树, +完整运行的成本过高,仍必须至少运行实际验证变更行为的针对性回归测试,例如 +`bun test tests//.test.ts`。说明缩小范围的原因,并报告准确的命令、结果和未测试范围。 +`bun run test:changed` 可以补充覆盖,但无法发现所有间接依赖。不存在仅依赖 CI 或完全跳过本地测试 +的一概豁免。合并前,所有必需的 CI 检查必须在当前 PR 头部的确切提交上通过。 + 测试是按 `src/` 划分的领域目录(`tests//`)下的 Bun test,映射表在 `scripts/test-layout/layout.json`。`tests/helpers/` 存放共享 fixture, `tests/e2e-style/` 存放范围更广的原生一致性场景。请在对应 subsystem 的现有测试附近加入聚焦的 -回归测试;若改动涉及共享 routing、adapter、config 或 server 行为,还应运行完整 suite。 +回归测试。 你正在阅读的文档站点位于 `docs-site/`(Astro + Starlight): @@ -159,6 +167,5 @@ package API,还要从 `src/index.ts` export。 ## 在声称完成前先验证 -先运行能证明改动的最小命令:类型检查用 `bun run typecheck`,行为检查用聚焦的 -`bun test tests/.test.ts` 或 runtime probe,然后再执行适合影响范围的更宽 gate。 -opencodex 倾向于小而可验证的 commit,而不是大批量改动。 +遵循上述测试政策,并针对类型变更运行 `bun run typecheck`,以及受影响范围所需的其他检查。 +报告命令、结果和未测试范围,只声明实际完成的验证。 diff --git a/docs-site/src/content/docs/zh-tw/contributing.md b/docs-site/src/content/docs/zh-tw/contributing.md index 86931c1ff6f..36c3cb55da6 100644 --- a/docs-site/src/content/docs/zh-tw/contributing.md +++ b/docs-site/src/content/docs/zh-tw/contributing.md @@ -9,14 +9,16 @@ description: opencodex 的開發環境、結構、約定,以及新增 provider git clone https://github.com/lidge-jun/opencodex.git cd opencodex bun install +bun run setup:hooks # 安裝 post-merge 並移除舊的受管理 pre-push bun run dev:proxy # 開發模式代理 API bun run dev:gui # 儀表板 dev 伺服器(另一個終端) bun run typecheck # bun x tsc --noEmit -bun run test:changed # routine import-graph test selection -bun test tests/routing/router.test.ts # routine focused test -bun run test # complete suite (PR-ready / explicit ask) +bun run test # 完整測試套件(預設) ``` +`bun run setup:hooks` 僅安裝 `post-merge`,並移除未經修改的舊版受管理 `pre-push` 掛鉤, +保留自訂掛鉤。`pre-push` 掛鉤不再是必要項目;`bun run prepush` 仍可作為選用的手動檢查。 + `bun run dev` 繼續作為 `bun run dev:proxy` 的別名。儀表板 dev 伺服器使用 `bun run dev:gui`; `GET /` 提供的打包儀表板由 `bun run build:gui` 建置到 `gui/dist`。 @@ -34,9 +36,15 @@ bun run privacy:scan # CI 使用的 credential/privacy 掃描 bun run prepare:package # 重新整理 package launcher/asset ``` +預設執行 `bun run test` 跑完整測試套件。如果相對於工作規模、機器資源或同時使用的工作樹, +完整執行的成本過高,仍必須至少執行實際驗證變更行為的針對性迴歸測試,例如 +`bun test tests//.test.ts`。說明縮小範圍的原因,並報告確切的命令、結果和未測試範圍。 +`bun run test:changed` 可以補充涵蓋範圍,但無法找出所有間接相依性。不存在僅依賴 CI 或完全略過 +本機測試的一概豁免。合併前,所有必要的 CI 檢查必須在目前 PR 頂端的確切提交上通過。 + 測試是按 `src/` 劃分的領域目錄(`tests//`)下的 Bun test,對應表在 `scripts/test-layout/layout.json`。`tests/helpers/` 存放共享 fixture, `tests/e2e-style/` 存放範圍更廣的原生一致性場景。請在對應 subsystem 的現有測試附近加入聚焦的 -迴歸測試;若改動涉及共享 routing、adapter、config 或 server 行為,還應執行完整 suite。 +迴歸測試。 你正在閱讀的文件站點位於 `docs-site/`(Astro + Starlight): @@ -189,6 +197,5 @@ package API,還要從 `src/index.ts` export。 ## 在聲稱完成前先驗證 -先執行能證明改動的最小命令:型別檢查用 `bun run typecheck`,行為檢查用聚焦的 -`bun test tests/.test.ts` 或 runtime probe,然後再執行適合影響範圍的更寬 gate。 -opencodex 傾向於小而可驗證的 commit,而不是大批次改動。 +遵循上述測試政策,並針對型別變更執行 `bun run typecheck`,以及受影響範圍所需的其他檢查。 +報告命令、結果和未測試範圍,只聲明實際完成的驗證。 diff --git a/docs-site/src/content/docs/zh-tw/contributing/pr-quality.md b/docs-site/src/content/docs/zh-tw/contributing/pr-quality.md index 00f20be8ed8..11a024c8a68 100644 --- a/docs-site/src/content/docs/zh-tw/contributing/pr-quality.md +++ b/docs-site/src/content/docs/zh-tw/contributing/pr-quality.md @@ -22,11 +22,11 @@ description: OpenCodex pull request 的審查就緒門檻、貢獻者責任、 有三個決定性的檢查會在人工作業之前執行,每個失敗訊息都會確切告訴你該改什麼: - **PR 品質(`enforce-target`)。** Pull request 必須以 `dev` 為目標,並帶有真正的描述:變更內容與原因的 **Summary**,加上 **Test plan**(或同等實質內容)。當 diff 更動 `gui/` 下的檔案,或 GitHub 對大型 diff 回傳不完整的變更檔清單時,描述必須包含 UI 變更的截圖;檢查會讓 PR 維持 draft 並留言,直到截圖出現。不完整的檔案清單會保守地視為 GUI 變更。維護者可以針對 `gui/` 變更、GUI 路徑分類誤判、或不完整檔案清單的誤判,加上 `gui-screenshot-waived` label 來豁免截圖要求;新增或移除該 label 會立即重新評估 gate。舊式維護者留言(例如「no gui changes」)在下次 PR 事件時仍會為相容性而辨識,但留言本身不再觸發這個特權 PR gate。貢獻者不能自行豁免截圖要求。 - 沒有 repository push 權限的貢獻者 PR 會以 draft 開啟,並維持 draft 直到描述中的四個格子的 review-ready 檢查清單完成:本機 CI 通過、分支位於最新 `dev` commit、所有正確的 Codex 與 CodeRabbit 發現都已修正、以及 ready-for-review 確認。當每個格子都勾選後,檢查會把 PR 標記為可審查,並通知 `MAINTAINERS.md` 中列出的維護者(不含作者)。gate 的狀態與「該做什麼」集中在單一 bot 留言中,每次執行都會重寫,所以只需看一個地方。完成綁定在 PR head 所指的確切 commit:如果之後又推出新 commit,gate 會把 PR 移回 draft、重設檢查清單與維護者通知,並要求你針對最新程式碼再次測試並勾選。重新定位到 `dev` 會自動清除錯誤分支訊息,並被 gate 記住;draft 會一直持續到檢查清單完成。 - 在接受完成之前,gate 會驗證它能自行檢查的檢查清單聲明:分支必須位於最新 `dev` commit 或落後最多 10 個 commit,而且目前 head 上所有由 review bot 撰寫的 Codex 與 CodeRabbit review thread 都必須已解決(其他作者未解決的 thread 不會阻擋)。本機 CI 的格子只是作者的 attestation——fork 貢獻者無法啟動 repository CI,必須由維護者啟動——所以 gate 永遠不會反駁它;新的 push 仍會重設每個格子。落在 diff 範圍之外、且只在目前 head 的 review body 中回報的 CodeRabbit 發現,在 bot review thread 開啟期間會計入未解決數;解決所有 bot thread 即可清除該格子。被反駁的聲明會取消勾選對應的格子,並讓 PR 維持 draft。當檢查清單完成且所有 gate 都綠燈時,gate 會加上 `review-ready` label,作為就緒時刻的可見狀態標記。 + 沒有 repository push 權限的貢獻者 PR 會以 draft 開啟,並維持 draft 直到描述中的四個格子的 review-ready 檢查清單完成:必要的本機驗證通過,並記錄命令、結果及任何完整套件例外、分支位於最新 `dev` commit、所有正確的 Codex 與 CodeRabbit 發現都已修正、以及 ready-for-review 確認。當每個格子都勾選後,檢查會把 PR 標記為可審查,並通知 `MAINTAINERS.md` 中列出的維護者(不含作者)。gate 的狀態與「該做什麼」集中在單一 bot 留言中,每次執行都會重寫,所以只需看一個地方。完成綁定在 PR head 所指的確切 commit:如果之後又推出新 commit,gate 會把 PR 移回 draft、重設檢查清單與維護者通知,並要求你針對最新程式碼再次測試並勾選。重新定位到 `dev` 會自動清除錯誤分支訊息,並被 gate 記住;draft 會一直持續到檢查清單完成。 + 在接受完成之前,gate 會驗證它能自行檢查的檢查清單聲明:分支必須位於最新 `dev` commit 或落後最多 10 個 commit,而且目前 head 上所有由 review bot 撰寫的 Codex 與 CodeRabbit review thread 都必須已解決(其他作者未解決的 thread 不會阻擋)。必要本機驗證的格子只是作者的 attestation——fork 貢獻者無法啟動 repository CI,必須由維護者啟動——所以 gate 永遠不會反駁它;新的 push 仍會重設每個格子。落在 diff 範圍之外、且只在目前 head 的 review body 中回報的 CodeRabbit 發現,在 bot review thread 開啟期間會計入未解決數;解決所有 bot thread 即可清除該格子。被反駁的聲明會取消勾選對應的格子,並讓 PR 維持 draft。當檢查清單完成且所有 gate 都綠燈時,gate 會加上 `review-ready` label,作為就緒時刻的可見狀態標記。 CodeRabbit 的狀態留言編輯不會觸發 PR gate。CodeRabbit 成功的 `CodeRabbit` commit status 會透過 `status` 事件喚醒受信任的預設分支 gate。gate 將該 status SHA 對應到確切一個目前 head 仍相符的 open PR,然後在變更檢查清單、label、留言或 draft 狀態之前,重新讀取即時的 review thread 與 review body。模糊或過時的 SHA 關聯會被忽略,且不會以 gate 的具寫入權限 token 執行任何 PR head 程式碼。 -- **Hygiene。** 行為變更需要測試;新增 lint 或 type suppression、聚焦或跳過的測試、空的 catch 區塊、編輯產生的輸出,以及未隨 manifest 一起變更的 lockfile,每項都需要明確的核准 label。僅對原始檔做留言層級的變更不算行為變更,也不需要測試。 +- **Hygiene。** 行為變更需要測試;新增 lint 或 type suppression、聚焦或跳過的測試、空的 catch 區塊、編輯產生的輸出,以及未隨 manifest 一起變更的 lockfile,每項都需要明確的核准 label。僅對原始檔做留言層級的變更不算行為變更,也不需要新增迴歸測試。[本機測試政策](/zh-tw/contributing/) 仍然適用。 - **跨平台 CI。** 每個 pull request 的測試套件在 Linux 上分片執行,並在 macOS 上完整執行。Windows 在釋出邊界執行——即提升到 `main` 或 `preview` 時——所以慢速或不穩定的 Windows runner 不能決定你的 pull request 何時變綠。 這對**每個** pull request 都執行,無論其 base 分支為何——包括 base 是另一個 open PR head 的 stacked child。由 `paths:` filter,而非 base 分支,決定 jobs 是否執行:只碰 docs 或 `devlog/` 的 PR 不會佇列任何 job。 diff --git a/scripts/AGENTS.md b/scripts/AGENTS.md index da4c2d0a16e..858db0ff14d 100644 --- a/scripts/AGENTS.md +++ b/scripts/AGENTS.md @@ -23,5 +23,5 @@ This file applies to `scripts/` and inherits the repository-wide rules in `/AGEN - Run focused tests or probes for the changed script. - Run `bun run typecheck`. - Run `bun run privacy:scan` when the script handles configuration, credentials, requests, logs, or account data. -- Run `bun run prepush` for release, packaging, dependency, or cross-platform tooling changes. +- Follow the root validation policy: run the suite by default; if a full run is too costly, run at least focused regression tests and document the reason and remaining coverage. `bun run prepush` is available as an explicit comprehensive check. - Report any platform-specific validation that was not executed. diff --git a/scripts/build-gui-if-changed.ts b/scripts/build-gui-if-changed.ts index c48badcfa75..cfa083ddaac 100644 --- a/scripts/build-gui-if-changed.ts +++ b/scripts/build-gui-if-changed.ts @@ -1,6 +1,6 @@ /** * Rebuild the packaged GUI when a merge or pull brought `gui/` changes. - * Used by the `post-merge` git hook. Skip with: git pull --no-verify + * Used by the `post-merge` git hook. * * Why this exists: `ocx` serves `gui/dist`, which is generated output and * therefore gitignored. A fast-forward advances `gui/src` but leaves `gui/dist` diff --git a/scripts/doctor-gui-if-changed.ts b/scripts/doctor-gui-if-changed.ts index b341e0eab20..dbef9c28760 100644 --- a/scripts/doctor-gui-if-changed.ts +++ b/scripts/doctor-gui-if-changed.ts @@ -1,6 +1,6 @@ /** * Run React Doctor in gui/ when this push includes gui/ changes. - * Used by `bun run prepush`. Skip with: git push --no-verify + * Used by `bun run prepush`. * * Gating by contract (doctor.config.json blocking: "warning"): findings fail * the push. An unavailable engine (offline npx fetch, missing binary) still diff --git a/scripts/lint-gui-if-changed.ts b/scripts/lint-gui-if-changed.ts index 133938a7381..fd504489ac1 100644 --- a/scripts/lint-gui-if-changed.ts +++ b/scripts/lint-gui-if-changed.ts @@ -1,8 +1,8 @@ /** * Run GUI Oxlint when this push includes gui/ changes. - * Used by `bun run prepush`. Skip with: git push --no-verify + * Used by `bun run prepush`. * - * Mirrors `scripts/doctor-gui-if-changed.ts` so the local pre-push gate and + * Mirrors `scripts/doctor-gui-if-changed.ts` so explicit local validation and * the CI `gates` job agree: GUI lint runs only when the push actually touches * `gui/`. Unlike doctor there is no engine to fetch, so lint findings always * fail the push — there is no infra-degradation path to soft-skip on. diff --git a/scripts/pre-push.sh b/scripts/pre-push.sh deleted file mode 100644 index fa04e570e0d..00000000000 --- a/scripts/pre-push.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env sh -# Pre-push hook shim. The actual command list lives in package.json ("prepush"). -# Installed by: bun run setup:hooks -set -e -exec bun run prepush diff --git a/scripts/setup-hooks.ts b/scripts/setup-hooks.ts index c632004dba9..57bc8c0262a 100644 --- a/scripts/setup-hooks.ts +++ b/scripts/setup-hooks.ts @@ -2,18 +2,16 @@ * Sets up the git hooks for local development. * Run once after cloning: bun run setup:hooks * - * - `pre-push` runs `bun run prepush` (typecheck + tests + privacy scan + GUI - * eslint and React Doctor when `gui/` changed) — the local portion of the CI - * gate. + * - Retires the unmodified repository-managed `pre-push` hook. Validation is + * run explicitly; custom hooks are preserved. * - `post-merge` runs `bun run postmerge`, which rebuilds the packaged GUI when * a merge or pull brought `gui/` changes. `gui/dist` is generated and * gitignored, so a fast-forward advances the source while the dashboard keeps * serving the previously built bundle. - * - * To skip in an emergency: git push --no-verify / git pull --no-verify */ import { execFileSync } from "node:child_process"; -import { existsSync, copyFileSync, mkdirSync, chmodSync, readFileSync, renameSync } from "node:fs"; +import { createHash } from "node:crypto"; +import { existsSync, copyFileSync, mkdirSync, chmodSync, readFileSync, renameSync, lstatSync, unlinkSync } from "node:fs"; import { join, resolve } from "node:path"; const repoRoot = resolve(import.meta.dirname, ".."); @@ -72,15 +70,25 @@ function installHook(name: string, source: string, summary: string): void { console.log(`${name} hook installed at ${dest}. ${summary}`); } -installHook( - "pre-push", - "pre-push.sh", - "Runs typecheck + tests + privacy scan (+ GUI eslint and React Doctor when gui/ changed) before every push.", -); +// Match the exact retired shim (normalizing checkout line endings), never a +// name or a partial marker: a user may have added other work to their hook. +const retiredPrePushSha256 = "2aa6b5f84ab989954d2ccc1a8680d63ad934034778e0ee99c277f8873fd40508"; +const prePushPath = join(hooksDir, "pre-push"); +const prePushStat = lstatSync(prePushPath, { throwIfNoEntry: false }); +if (prePushStat?.isFile()) { + const content = readFileSync(prePushPath, "utf8").replace(/\r\n/g, "\n"); + if (createHash("sha256").update(content).digest("hex") === retiredPrePushSha256) { + unlinkSync(prePushPath); + console.log("Removed the retired repository-managed pre-push hook."); + } else { + console.log("Preserved custom pre-push hook."); + } +} + installHook( "post-merge", "post-merge.sh", "Rebuilds the packaged GUI when a merge or pull brought gui/ changes.", ); -console.log("Skip in an emergency with: git push --no-verify / git pull --no-verify"); +console.log("Run validation explicitly before review; see AGENTS.md for test scope."); diff --git a/scripts/test-layout/layout.json b/scripts/test-layout/layout.json index 0cbb0fc7b38..ef76d6a9385 100644 --- a/scripts/test-layout/layout.json +++ b/scripts/test-layout/layout.json @@ -745,6 +745,7 @@ "digitalocean-scaleway-provider.test.ts": "providers", "docs-429-failover-claims.test.ts": "ci-workflows", "docs-bun-source-requirement.test.ts": "ci-workflows", + "setup-hooks.test.ts": "ci-workflows", "docs-provider-billing-claims.test.ts": "ci-workflows", "docs-provider-preset-counts.test.ts": "ci-workflows", "docs-readme-translation-parity.test.ts": "ci-workflows", diff --git a/structure/ops/docs-and-release.md b/structure/ops/docs-and-release.md index 1d1000b6678..ba845677609 100644 --- a/structure/ops/docs-and-release.md +++ b/structure/ops/docs-and-release.md @@ -29,6 +29,12 @@ The account reference documents the [Orca source-owned import](../codex-home.md# Its local-only command is declared in `src/cli/capabilities.ts`, and the generated skill surface lists its required source/registry paths and preview/apply flags. +Local validation follows [the contributor test policy](../../AGENTS.md#commands): run the +suite by default, with a documented resource exception requiring focused regression tests. +`scripts/setup-hooks.ts` installs the post-merge hook and retires only an exact match for +the old managed pre-push shim; custom hooks are preserved. Required current-head CI and +security review remain merge requirements. + ## Public docs The provider configuration reference and provider guide own the public Google tool-schema policy: diff --git a/tests/ci-workflows/ci-workflows.test.ts b/tests/ci-workflows/ci-workflows.test.ts index fba748aec7d..799e4a6b982 100644 --- a/tests/ci-workflows/ci-workflows.test.ts +++ b/tests/ci-workflows/ci-workflows.test.ts @@ -1668,7 +1668,7 @@ describe("GitHub Actions hardening", () => { const CHECKLIST_START = ""; const CHECKLIST_END = ""; const CHECKLIST_ITEMS = [ - "All CI tests are green on my local testing.", + "Required local validation passed; commands, results, and any full-suite exception are documented.", "I pushed my PR to the latest dev commit.", "I resolved all correct Codex and CodeRabbit findings.", "My PR is ready for review.", @@ -1794,7 +1794,7 @@ describe("GitHub Actions hardening", () => { const [injected] = callsTo(result, "pulls.update") as [{ body: string }]; expect(injected.body).toContain(CHECKLIST_START); expect(injected.body).toContain(CHECKLIST_END); - expect(injected.body).toContain("- [ ] All CI tests are green on my local testing."); + expect(injected.body).toContain("- [ ] Required local validation passed; commands, results, and any full-suite exception are documented."); expect(injected.body).toContain("- [ ] My PR is ready for review."); const [draft] = callsTo(result, "graphql") as [{ query: string }]; @@ -2002,7 +2002,7 @@ describe("GitHub Actions hardening", () => { ])); const [resetBody] = callsTo(result, "pulls.update") as [{ body: string }]; expect(resetBody.body).toContain(CHECKLIST_START); - expect(resetBody.body).toContain("- [ ] All CI tests are green on my local testing."); + expect(resetBody.body).toContain("- [ ] Required local validation passed; commands, results, and any full-suite exception are documented."); expect(resetBody.body).toContain("- [ ] My PR is ready for review."); expect(resetBody.body).not.toContain("- [x]"); @@ -2269,7 +2269,7 @@ describe("GitHub Actions hardening", () => { ])); const [bodyUpdate] = callsTo(result, "pulls.update") as [{ body: string }]; // Only the latest-dev box is unticked; local CI stays checked. - expect(bodyUpdate.body).toContain("- [x] All CI tests are green on my local testing."); + expect(bodyUpdate.body).toContain("- [x] Required local validation passed; commands, results, and any full-suite exception are documented."); expect(bodyUpdate.body).toContain("- [ ] I pushed my PR to the latest dev commit."); expect(bodyUpdate.body).toContain("- [x] My PR is ready for review."); const drafts = callsTo(result, "graphql") as [{ query: string }]; @@ -2363,7 +2363,7 @@ describe("GitHub Actions hardening", () => { ])); const [bodyUpdate] = callsTo(result, "pulls.update") as [{ body: string }]; // Only the findings box is unticked; CI and latest-dev stay checked. - expect(bodyUpdate.body).toContain("- [x] All CI tests are green on my local testing."); + expect(bodyUpdate.body).toContain("- [x] Required local validation passed; commands, results, and any full-suite exception are documented."); expect(bodyUpdate.body).toContain("- [x] I pushed my PR to the latest dev commit."); expect(bodyUpdate.body).toContain("- [ ] I resolved all correct Codex and CodeRabbit findings."); expect(bodyUpdate.body).toContain("- [x] My PR is ready for review."); @@ -5422,8 +5422,8 @@ describe("lint-gui-if-changed", () => { describe("gui exhaustive-deps suppression stays scoped and effective", () => { // `bun run doctor:gui` exited 1 on dev for one deliberate exception at - // gui/src/pages/Models.tsx, and doctor:gui runs inside `prepush`, so every - // gui-touching push needed --no-verify. Two config edits fixed it, and each has a + // gui/src/pages/Models.tsx, blocking explicit comprehensive validation. + // Two config edits fixed it, and each has a // failure mode that is silent rather than loud, which is what these assertions cover. test("the oxlint override carries its own react plugin, or it resolves to nothing", async () => { diff --git a/tests/ci-workflows/setup-hooks.test.ts b/tests/ci-workflows/setup-hooks.test.ts new file mode 100644 index 00000000000..41ac18eb479 --- /dev/null +++ b/tests/ci-workflows/setup-hooks.test.ts @@ -0,0 +1,152 @@ +import { afterEach, describe, expect, test } from "bun:test"; +import { execFileSync } from "node:child_process"; +import { copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, symlinkSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { isAbsolute, join, relative } from "node:path"; +import { repoPath } from "../helpers/repo-root"; +import { removeTreeWithRetry } from "../helpers/remove-tree"; + +// Independent fixture for the retired, formerly shipped hook, not the remover's hash. +const legacyHook = [ + "#!/usr/bin/env sh", + '# Pre-push hook shim. The actual command list lives in package.json ("prepush").', + "# Installed by: bun run setup:hooks", + "set -e", + "exec bun run prepush", + "", +].join("\n"); +const roots: string[] = []; +afterEach(() => { for (const root of roots.splice(0)) removeTreeWithRetry(root); }); + +function gitEnv(root: string): NodeJS.ProcessEnv { + // The test preload retains the real global Git config. Never let it redirect + // fixture commands or hook writes into the developer's own checkout. + const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.startsWith("GIT_"))); + return { ...env, GIT_CONFIG_NOSYSTEM: "1", GIT_CONFIG_GLOBAL: join(root, ".fixture-gitconfig") }; +} + +function git(root: string, ...args: string[]): string { + return execFileSync("git", args, { cwd: root, env: gitEnv(root), encoding: "utf8", stdio: "pipe" }).trim(); +} + +function fixture(): string { + const root = realpathSync(mkdtempSync(join(tmpdir(), "ocx-hook-setup-"))); + roots.push(root); + git(root, "init", "--quiet"); + mkdirSync(join(root, "scripts")); + for (const name of ["setup-hooks.ts", "post-merge.sh"]) { + copyFileSync(repoPath("scripts", name), join(root, "scripts", name)); + } + return root; +} + +function setup(root: string): string { + return execFileSync(process.execPath, [join(root, "scripts/setup-hooks.ts")], { + cwd: root, env: gitEnv(root), encoding: "utf8", timeout: 10_000, stdio: "pipe", + }); +} + +function hooks(root: string): string { + const path = git(root, "rev-parse", "--path-format=absolute", "--git-path", "hooks"); + // A linked worktree resolves to its parent fixture's shared hooks directory. + expect(roots.some(fixtureRoot => { + const rel = relative(fixtureRoot, path); + return rel !== ".." && !rel.startsWith("../") && !rel.startsWith("..\\") && !isAbsolute(rel); + })).toBe(true); + return path; +} + +describe("local hook setup", () => { + test("ignores inherited global hooks and Git directory overrides", () => { + const external = fixture(); + const externalHook = join(hooks(external), "pre-push"); + writeFileSync(externalHook, "user-owned hook\n"); + const globalConfig = join(external, "global-config"); + git(external, "config", "--file", globalConfig, "core.hooksPath", hooks(external)); + const savedGlobal = process.env.GIT_CONFIG_GLOBAL; + const savedDir = process.env.GIT_DIR; + try { + process.env.GIT_CONFIG_GLOBAL = globalConfig; + process.env.GIT_DIR = join(external, ".git"); + const root = fixture(); + setup(root); + expect(existsSync(join(hooks(root), "pre-push"))).toBe(false); + expect(readFileSync(externalHook, "utf8")).toBe("user-owned hook\n"); + expect(existsSync(join(hooks(external), "post-merge"))).toBe(false); + } finally { + if (savedGlobal === undefined) delete process.env.GIT_CONFIG_GLOBAL; + else process.env.GIT_CONFIG_GLOBAL = savedGlobal; + if (savedDir === undefined) delete process.env.GIT_DIR; + else process.env.GIT_DIR = savedDir; + } + }); + + test("fresh setup installs only post-merge and is idempotent", () => { + const root = fixture(); + setup(root); + const hookDir = hooks(root); + expect(existsSync(join(hookDir, "pre-push"))).toBe(false); + expect(readFileSync(join(hookDir, "post-merge"), "utf8")) + .toBe(readFileSync(repoPath("scripts/post-merge.sh"), "utf8")); + setup(root); + expect(readdirSync(hookDir).filter(name => name.startsWith("post-merge.backup-"))).toEqual([]); + }); + + for (const ending of ["\n", "\r\n"]) { + test(`retires the shipped hook with ${JSON.stringify(ending)} line endings`, () => { + const root = fixture(); + writeFileSync(join(hooks(root), "pre-push"), legacyHook.replace(/\n/g, ending)); + setup(root); + expect(existsSync(join(hooks(root), "pre-push"))).toBe(false); + expect(existsSync(join(hooks(root), "post-merge"))).toBe(true); + }); + } + + test("preserves custom hooks even when they contain the old shim", () => { + const root = fixture(); + const custom = legacyHook + "echo custom validation\n"; + writeFileSync(join(hooks(root), "pre-push"), custom); + setup(root); + expect(readFileSync(join(hooks(root), "pre-push"), "utf8")).toBe(custom); + }); + + test("uses a configured hooks directory without touching the default one", () => { + const root = fixture(); + const original = hooks(root); + writeFileSync(join(original, "pre-push"), legacyHook); + const customDir = join(root, "custom hooks"); + mkdirSync(customDir); + writeFileSync(join(customDir, "pre-push"), legacyHook); + git(root, "config", "core.hooksPath", customDir); + setup(root); + expect(existsSync(join(customDir, "pre-push"))).toBe(false); + expect(existsSync(join(customDir, "post-merge"))).toBe(true); + expect(readFileSync(join(original, "pre-push"), "utf8")).toBe(legacyHook); + }); + + test("linked worktrees migrate the Git-resolved shared hooks directory", () => { + const root = fixture(); + git(root, "add", "scripts"); + git(root, "-c", "user.name=Fixture", "-c", `user.email=${["fixture", "example.invalid"].join("@")}`, + "-c", "commit.gpgsign=false", "commit", "--quiet", "-m", "fixture"); + const linked = join(root, "linked"); + git(root, "worktree", "add", "--detach", linked); + const shared = hooks(root); + writeFileSync(join(shared, "pre-push"), legacyHook); + setup(linked); + expect(hooks(linked)).toBe(shared); + expect(existsSync(join(shared, "pre-push"))).toBe(false); + expect(existsSync(join(shared, "post-merge"))).toBe(true); + }); + + test.skipIf(process.platform === "win32")("preserves symlinked pre-push hooks", () => { + const root = fixture(); + const target = join(root, "user-hook"); + writeFileSync(target, legacyHook); + const hook = join(hooks(root), "pre-push"); + symlinkSync(target, hook); + setup(root); + expect(lstatSync(hook).isSymbolicLink()).toBe(true); + expect(readFileSync(target, "utf8")).toBe(legacyHook); + }); +}); diff --git a/tests/ci-workflows/zz-pr-coderabbit-readiness-revalidation.test.ts b/tests/ci-workflows/zz-pr-coderabbit-readiness-revalidation.test.ts index cc2e2cfb273..45ec365adcf 100644 --- a/tests/ci-workflows/zz-pr-coderabbit-readiness-revalidation.test.ts +++ b/tests/ci-workflows/zz-pr-coderabbit-readiness-revalidation.test.ts @@ -31,7 +31,7 @@ const GATE_MARKER = ""; const CHECKLIST_START = ""; const CHECKLIST_END = ""; const CHECKLIST_ITEMS = [ - "All CI tests are green on my local testing.", + "Required local validation passed; commands, results, and any full-suite exception are documented.", "I pushed my PR to the latest dev commit.", "I resolved all correct Codex and CodeRabbit findings.", "My PR is ready for review.", diff --git a/tests/fixtures/test-layout-expected.json b/tests/fixtures/test-layout-expected.json index c69955e4208..1d00123b80a 100644 --- a/tests/fixtures/test-layout-expected.json +++ b/tests/fixtures/test-layout-expected.json @@ -573,6 +573,7 @@ "digitalocean-scaleway-provider.test.ts": "providers", "docs-429-failover-claims.test.ts": "ci-workflows", "docs-bun-source-requirement.test.ts": "ci-workflows", + "setup-hooks.test.ts": "ci-workflows", "docs-provider-billing-claims.test.ts": "ci-workflows", "docs-provider-preset-counts.test.ts": "ci-workflows", "docs-readme-translation-parity.test.ts": "ci-workflows",