CI và gác trước khi merge
Hai repo (16.10.2026)
Từ 16.10.2026 job www đã gỡ khỏi ci-checks.yml (www sang repo conan-web); bộ chọn job còn các job dưới đây trừ www. Xem Hai repo.
ci-checks.yml chạy trên mọi pull request vào main: không deploy, không cần secret. Trang này mô tả nó sau Đợt 0 / PR-A của kế hoạch tách repo (14.10.2026). Quy tắc deploy ở Quy tắc triển khai; các gác viết thế nào ở Guardrails và skill ci-guards.
Hình dạng một lượt chạy
changes (luôn chạy, cả cây, cả lịch sử)
1. scripts/ci/select-jobs.mjs --github-output chọn job theo file đổi của PR
2. scripts/run-guards.mjs --self-test
3. scripts/run-guards.mjs mọi gác ở gốc repo, chạy hết rồi mới báo
|
| output chọn job (vẫn tới nơi khi bước 3 đỏ)
v
api, tool-plane, play, admin-router, admin, com, www, mam, video, sites[...]
if: !cancelled() && output == 'true' chạy cả khi gác đỏ
sparse checkout chỉ phần cây job đó đọc
npm ci (không rơi về npm install)Năm điều đổi ở PR-A, và vì sao
| Đổi | Trước | Vì sao |
|---|---|---|
Gác ở một danh sách, scripts/run-guards.mjs | 19 step trong yml, check:guards có 16, qc-scan đọc lại bằng regex | Ba danh sách lệch nhau; 16/42 lượt sửa ci-checks.yml chỉ để thêm gác, mỗi lượt từng chạy lại mọi job build |
| Chạy hết rồi mới báo | Step đỏ đầu tiên dừng job | Ba nhánh phải push thêm 4 lần chỉ để thấy lỗi kế tiếp |
Job build !cancelled() | Gác đỏ thì skip mọi build | 16/25 lượt đỏ: một lỗi gạch dài che luôn lỗi tsc |
| Bộ chọn job bằng Node, so với điểm rẽ nhánh | Bash, diff hai chấm, so lượt push | Hỏng ba lần im lặng: SIGPIPE (PR #332), job thừa ở 5/32 run, commit merge main chạy TẤT CẢ |
| Sparse checkout cho job build | Checkout cả repo ~600 MB | Checkout chiếm 42% thời gian job; một nửa repo là migration |
Chỉ npm ci + gác lockfiles | npm ci || npm install, kể cả lúc deploy | Lockfile lệch không làm đỏ gì; 1.649 run chưa cần đường rơi lần nào |
Gác workspace-deps | Không có | 3/7 lỗi mã thật là import gói không khai hoặc gói dùng chung không được cài |
Thêm một gác
Thêm một dòng vào GUARDS của scripts/run-guards.mjs:
{ id: 'ten-gac', run: [NODE, 'scripts/check-ten-gac.mjs'], fast: true,
why: 'Sự cố thật đã sinh ra gác này, ngày, PR.' },Không sửa ci-checks.yml, không sửa check:guards. Script scripts/check-*.mjs không đăng ký thì runner đỏ. Gác dưới ~2 giây thì đánh fast: hook trước git push chạy nhóm đó.
node scripts/run-guards.mjs --list # danh sách
node scripts/run-guards.mjs # chạy đủ (~11 giây ấm, 4 luồng)
node scripts/run-guards.mjs --only seo,jtbd # vài gác
node scripts/run-guards.mjs --fast # nhóm nhanh, như hook trước pushThêm một job hay một site
- Thêm job vào
ci-checks.yml, thêm dòng<khoá>: ${{ steps.f.outputs.<khoá> }}vàooutputs:của jobchangesvà khoá vào vòng dự phòng ở stepf, vớiif: ${{ !cancelled() && needs.changes.outputs.<khoá> == 'true' }}và sparse checkout (cone, chỉ ghi THƯ MỤC). - Thêm luật vào
rules()củascripts/ci/select-jobs.mjs: mọi đường dẫn job đó ĐỌC (thư mục app, gói dùng chung nó import,deploy-<app>.yml). Site không có job riêng thì thêm vào mảngSITES. node scripts/ci/select-jobs.mjs --self-test: mẫu 15 đỏ nếu thiếu bất kỳ chỗ nào trong bốn chỗ (luật, outputs,if:, vòng dự phòng). Thiếu dòng outputs thì job bị skip ở mọi PR mà run vẫn xanh.
.nvmrc (bản Node của mọi job và mọi deploy) đổi thì bộ chọn bật tất cả, và mọi workflow deploy chạy lại.
Thử bộ chọn bằng tay:
node scripts/ci/select-jobs.mjs --files packages/design-system/theme.css,api.conan.school/migrations/x.sqlNhững gì job api đọc ngoài thư mục của nó
Không chép tay: select-jobs.mjs QUÉT từ mã. Thư mục content/ mà src import (hiện chỉ content/bmc), file migration mà tests đọc (dựng bảng SQLite trong bộ nhớ), và file ngoài api mà test đọc (router của tokyo và www, danh mục bất biến D1 ở scripts/lib/). Những thứ đó bật job api; mọi migration khác và nguồn nội dung thì không.
Job api lấy cây sparse NỀN (bỏ migrations/, content/ trừ bmc, assets/), rồi bước select-jobs.mjs --print-api-reads | xargs git sparse-checkout add lấy thêm đúng những file kể trên, rồi --assert-api-sparse kiểm lại. Ngày 14.10.2026 danh sách chép tay đã phải sửa ba lần vì ba PR thêm test đọc file mới; giờ test mới đọc file nào thì tự được lấy theo.
Bẫy đã gặp khi dựng
Phần lớn bẫy dưới đây do một vòng rà soát đối kháng tìm ra trước khi push (17 phát hiện, mỗi cái được một agent khác tái hiện): rà soát kiểu đó rẻ hơn nhiều so với một lượt CI đỏ trên main.
npm run -slàm gác lockfiles xanh giả: npm con nhận loglevel silent, thoát 1 mà không in gì.Build trước khi cài gói dùng chung ở job admin và com: deploy chỉ cài thư mục app.
Hết giờ phải giết cả nhóm tiến trình: python của check-whats-new giữ ống stdio, runner chờ nó (trước 17.10.2026 là check-jtbd, nay ở repo conan-content).
Job
coursepack(CoursePack + PlaybookPack--check) đã gỡ ngày 17.10.2026: nguồn nội dung và bộ biên dịch sang repoconan-content, CI bên đó chạy phép kiểm này (repo-slim).Gác của phiên khác tự kiểm "đã được nối" bằng cách đọc yml: check-sentry (luật m) và check-email-docs đòi một step
run: node scripts/...trong ci-checks.yml và mộtnpm run check:xtrongcheck:guards. Sau khi gác chuyển vào runner, cả hai đỏ dù gác vẫn chạy. Gác mới hãy hỏiGUARDScủa run-guards (hoặc gọiselectJobs), đừng đọc chữ yml.Hai phiên cùng ngày dựng hai gác lockfile trùng tên (PR #431 và PR-A, 14.10.2026). Khi gộp, giữ bản đã lên main (kiểm NGHIÊM ở mọi thư mục, ngoại lệ phải khai
ALLOW_LEGACY_PEERSkèm lý do). Gác mới của #431 (sentry, hooks, smoke-production, d1-invariants) chuyển từ step yml vàoGUARDS; luật "gác đã được nối" của check-sentry giờ hỏiGUARDSvà gọi thẳngselectJobs, không đọc chữ yml.Danh sách sparse viết tay lệch mã: #431 cho tool-plane import
packages/observability, sparse của job chỉ cóconan-tool-plane, lượt CI đầu sau khi gộp đỏ TS2307. Gácsparsegiờ so tập file mỗi job build (từanalyzecủa check-workspace-deps) với mẫu sparse của job.Ghim
pathstrong tsconfig của app ("zod": ["./node_modules/zod"]) cho gói dùng chungimport typegói đó mà không cần cài gói dùng chung; gác workspace-deps tha đúng trường hợp đó (import giá trị vẫn đỏ, vì Vite không đọcpaths).Cây sparse làm gác xanh giả.
git ls-filesvẫn liệt kê file không có trên đĩa, còn check-no-emdash và qc-scan bỏ qua file vắng. Vì vậy jobchangesluôn lấy cả cây, và run-guards từ chối chạy khicore.sparseCheckoutbật.Cone mode với đường dẫn FILE lấy cả thư mục chứa nó, không báo gì: ghi
api.conan.school/migrations/a.sqlở cone là kéo về 318 MB. File lẻ chỉ ghi ở non-cone.always()thay vì!cancelled()sẽ build tiếp ở lượt đã bịcancel-in-progresshuỷ.Glob khớp 0 file:
node --test "tests/*.test.ts"in# tests 0và thoát 0. Job tool-plane có bước đếm file test; CoursePack/PlaybookPack 0 pack là::error::.cwd của gác: check-no-emdash, check-analytics, check-worker-observability tính từ cwd; chạy từ một thư mục con thì chúng thoát 0 mà chỉ soi thư mục con. run-guards luôn chạy ở gốc repo.
Số liệu nền (07.09 tới 13.10.2026)
ci-checks p50 1,52 phút, p90 1,90; xếp hàng 3 giây. 25/351 lượt đỏ, 0 chập chờn, 18 do gác chính sách. Khoảng 2.200 phút tính tiền mỗi 30 ngày trên hạn mức 2.000 của gói Free, 15 startup_failure. Đo lại 14 ngày sau khi merge PR-A, so với bảng "Chỉ số thành công" của kế hoạch.