{"id":601,"date":"2026-03-21T22:52:56","date_gmt":"2026-03-21T14:52:56","guid":{"rendered":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/ci\/"},"modified":"2026-03-21T23:08:57","modified_gmt":"2026-03-21T15:08:57","slug":"ci","status":"publish","type":"post","link":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/ci\/","title":{"rendered":"CI Pipeline"},"content":{"rendered":"<h1>CI Pipeline<\/h1>\n<p>The CI runs on every push to <code>main<\/code> and every pull request. It uses smart scoping to skip expensive jobs when only unrelated areas changed.<\/p>\n<h2>Job Overview<\/h2>\n<table>\n<thead>\n<tr>\n<th>Job<\/th>\n<th>Purpose<\/th>\n<th>When it runs<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>docs-scope<\/code><\/td>\n<td>Detect docs-only changes<\/td>\n<td>Always<\/td>\n<\/tr>\n<tr>\n<td><code>changed-scope<\/code><\/td>\n<td>Detect which areas changed (node\/macos\/android\/windows)<\/td>\n<td>Non-doc changes<\/td>\n<\/tr>\n<tr>\n<td><code>check<\/code><\/td>\n<td>TypeScript types, lint, format<\/td>\n<td>Non-docs, node changes<\/td>\n<\/tr>\n<tr>\n<td><code>check-docs<\/code><\/td>\n<td>Markdown lint + broken link check<\/td>\n<td>Docs changed<\/td>\n<\/tr>\n<tr>\n<td><code>secrets<\/code><\/td>\n<td>Detect leaked secrets<\/td>\n<td>Always<\/td>\n<\/tr>\n<tr>\n<td><code>build-artifacts<\/code><\/td>\n<td>Build dist once, share with <code>release-check<\/code><\/td>\n<td>Pushes to <code>main<\/code>, node changes<\/td>\n<\/tr>\n<tr>\n<td><code>release-check<\/code><\/td>\n<td>Validate npm pack contents<\/td>\n<td>Pushes to <code>main<\/code> after build<\/td>\n<\/tr>\n<tr>\n<td><code>checks<\/code><\/td>\n<td>Node tests + protocol check on PRs; Bun compat on push<\/td>\n<td>Non-docs, node changes<\/td>\n<\/tr>\n<tr>\n<td><code>compat-node22<\/code><\/td>\n<td>Minimum supported Node runtime compatibility<\/td>\n<td>Pushes to <code>main<\/code>, node changes<\/td>\n<\/tr>\n<tr>\n<td><code>checks-windows<\/code><\/td>\n<td>Windows-specific tests<\/td>\n<td>Non-docs, windows-relevant changes<\/td>\n<\/tr>\n<tr>\n<td><code>macos<\/code><\/td>\n<td>Swift lint\/build\/test + TS tests<\/td>\n<td>PRs with macos changes<\/td>\n<\/tr>\n<tr>\n<td><code>android<\/code><\/td>\n<td>Gradle build + tests<\/td>\n<td>Non-docs, android changes<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Fail-Fast Order<\/h2>\n<p>Jobs are ordered so cheap checks fail before expensive ones run:<\/p>\n<ol>\n<li><code>docs-scope<\/code> + <code>changed-scope<\/code> + <code>check<\/code> + <code>secrets<\/code> (parallel, cheap gates first)<\/li>\n<li>PRs: <code>checks<\/code> (Linux Node test split into 2 shards), <code>checks-windows<\/code>, <code>macos<\/code>, <code>android<\/code><\/li>\n<li>Pushes to <code>main<\/code>: <code>build-artifacts<\/code> + <code>release-check<\/code> + Bun compat + <code>compat-node22<\/code><\/li>\n<\/ol>\n<p>Scope logic lives in <code>scripts\/ci-changed-scope.mjs<\/code> and is covered by unit tests in <code>src\/scripts\/ci-changed-scope.test.ts<\/code>.<\/p>\n<h2>Runners<\/h2>\n<table>\n<thead>\n<tr>\n<th>Runner<\/th>\n<th>Jobs<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>blacksmith-16vcpu-ubuntu-2404<\/code><\/td>\n<td>Most Linux jobs, including scope detection<\/td>\n<\/tr>\n<tr>\n<td><code>blacksmith-32vcpu-windows-2025<\/code><\/td>\n<td><code>checks-windows<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>macos-latest<\/code><\/td>\n<td><code>macos<\/code>, <code>ios<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Local Equivalents<\/h2>\n<p><code>bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}<br \/>\npnpm check          # types + lint + format<br \/>\npnpm test           # vitest tests<br \/>\npnpm check:docs     # docs format + lint + broken links<br \/>\npnpm release:check  # validate npm pack<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>CI Pipeline The CI runs on every push to main and every [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-601","post","type-post","status-publish","format-standard","hentry","category-docs"],"_links":{"self":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/601","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/comments?post=601"}],"version-history":[{"count":2,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/601\/revisions"}],"predecessor-version":[{"id":739,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/601\/revisions\/739"}],"wp:attachment":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/media?parent=601"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/categories?post=601"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/tags?post=601"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}