packages-checks.yml 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. name: Packages Checks
  2. on:
  3. pull_request:
  4. paths:
  5. - 'packages/**'
  6. - 'package.json'
  7. - 'pnpm-lock.yaml'
  8. - 'pnpm-workspace.yaml'
  9. - '.github/workflows/packages-checks.yml'
  10. - '.github/dependabot.yml'
  11. - 'scripts/validation/detect-pr-changes.ts'
  12. - 'scripts/validation/detect-pr-changes.test.ts'
  13. # The canonical source, its committed output, and the drift gate's machinery.
  14. - 'content/**'
  15. - '.opencode/agent/**'
  16. - '.oac/**'
  17. - 'registry.json'
  18. - 'Makefile'
  19. - 'scripts/validation/check-build-drift.sh'
  20. permissions:
  21. contents: read
  22. jobs:
  23. check-changes:
  24. name: Detect Package Changes
  25. runs-on: ubuntu-latest
  26. outputs:
  27. has-packages: ${{ steps.filter.outputs.has-packages }}
  28. has-canonical: ${{ steps.filter.outputs.has-canonical }}
  29. steps:
  30. - name: Checkout code
  31. uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
  32. with:
  33. fetch-depth: 0
  34. persist-credentials: false
  35. - name: Setup Bun
  36. uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
  37. with:
  38. bun-version: 1.3.14
  39. # The detector decides which gates run, so a broken detector silently skips them —
  40. # including the drift gate. Its tests also pin the drift job's contract (that it is
  41. # blocking, gated on has-canonical, and runs the same make target contributors do).
  42. # They must execute somewhere, and nothing else in CI ran them.
  43. - name: Test change detection
  44. run: bun test scripts/validation/detect-pr-changes.test.ts
  45. - name: Check changed files
  46. id: filter
  47. run: |
  48. echo "Changed files:" >&2
  49. git diff --name-only -z "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" |
  50. tee >(while IFS= read -r -d '' path; do printf ' %q\n' "$path" >&2; done) |
  51. bun run scripts/validation/detect-pr-changes.ts
  52. cli-checks:
  53. name: CLI (build + test + typecheck)
  54. runs-on: ubuntu-latest
  55. timeout-minutes: 10
  56. needs: check-changes
  57. if: needs.check-changes.outputs.has-packages == 'true'
  58. steps:
  59. - name: Checkout code
  60. uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
  61. with:
  62. persist-credentials: false
  63. - name: Setup Bun
  64. uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
  65. with:
  66. bun-version: 1.3.14
  67. - name: Setup pnpm
  68. uses: pnpm/action-setup@b0f76dfb45f55f8421693e4803ac7bb65143bd34 # v6
  69. - name: Setup Node.js
  70. uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
  71. with:
  72. node-version: '20'
  73. cache: 'pnpm'
  74. cache-dependency-path: 'pnpm-lock.yaml'
  75. - name: Install workspace dependencies
  76. run: pnpm install --frozen-lockfile
  77. # cli tsconfig paths point at ../compatibility-layer/dist, so build it first.
  78. - name: Build compatibility-layer dependency
  79. run: pnpm --dir packages/compatibility-layer run build
  80. - name: Typecheck
  81. run: pnpm --dir packages/cli run typecheck
  82. - name: Build
  83. run: pnpm --dir packages/cli run build
  84. # packages/cli tests use Bun-only APIs (Bun.file, Bun.spawn, import.meta.dir)
  85. # until Stage 5 removes them — they must run under `bun test`, not vitest.
  86. - name: Test
  87. run: pnpm --dir packages/cli run test
  88. compatibility-layer-checks:
  89. name: Compatibility Layer (build + test + lint)
  90. runs-on: ubuntu-latest
  91. timeout-minutes: 10
  92. needs: check-changes
  93. if: needs.check-changes.outputs.has-packages == 'true'
  94. steps:
  95. - name: Checkout code
  96. uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
  97. with:
  98. persist-credentials: false
  99. - name: Setup pnpm
  100. uses: pnpm/action-setup@b0f76dfb45f55f8421693e4803ac7bb65143bd34 # v6
  101. - name: Setup Node.js
  102. uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
  103. with:
  104. node-version: '20'
  105. cache: 'pnpm'
  106. cache-dependency-path: 'pnpm-lock.yaml'
  107. - name: Install workspace dependencies
  108. run: pnpm install --frozen-lockfile
  109. # build runs tsc, which is also the typecheck for this package.
  110. - name: Build (tsc typecheck)
  111. run: pnpm --dir packages/compatibility-layer run build
  112. - name: Lint
  113. run: pnpm --dir packages/compatibility-layer run lint
  114. - name: Test (vitest)
  115. run: pnpm --dir packages/compatibility-layer test
  116. # The structural guarantee the canonical refactor rests on: the generated trees stay
  117. # COMMITTED, so drift has to be impossible rather than merely discouraged. Rebuild them from
  118. # content/agents/** and fail if the build changed anything — a hand-edit to generated output
  119. # turns this red. BLOCKING by design: no continue-on-error.
  120. canonical-drift:
  121. name: Canonical Build (no drift)
  122. runs-on: ubuntu-latest
  123. timeout-minutes: 10
  124. needs: check-changes
  125. if: needs.check-changes.outputs.has-canonical == 'true'
  126. steps:
  127. - name: Checkout code
  128. uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
  129. with:
  130. persist-credentials: false
  131. # `oac build` runs from packages/cli/dist, which is bundled `--target bun`.
  132. - name: Setup Bun
  133. uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
  134. with:
  135. bun-version: 1.3.14
  136. - name: Setup pnpm
  137. uses: pnpm/action-setup@b0f76dfb45f55f8421693e4803ac7bb65143bd34 # v6
  138. - name: Setup Node.js
  139. uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
  140. with:
  141. node-version: '20'
  142. cache: 'pnpm'
  143. cache-dependency-path: 'pnpm-lock.yaml'
  144. - name: Install workspace dependencies
  145. run: pnpm install --frozen-lockfile
  146. # The identical target contributors run locally, so a red gate here is reproducible with
  147. # one command rather than by reading this file and reassembling it by hand.
  148. - name: Build canonical trees and check for drift
  149. run: make check-canonical-drift
  150. summary:
  151. name: Packages Checks Summary
  152. runs-on: ubuntu-latest
  153. needs: [check-changes, cli-checks, compatibility-layer-checks, canonical-drift]
  154. if: always()
  155. steps:
  156. - name: Generate summary
  157. run: |
  158. echo "## 📦 Packages Checks Summary" >> $GITHUB_STEP_SUMMARY
  159. echo "" >> $GITHUB_STEP_SUMMARY
  160. report() {
  161. local label="$1" result="$2"
  162. case "$result" in
  163. success) echo "✅ **${label}:** Passed" >> $GITHUB_STEP_SUMMARY ;;
  164. skipped) echo "⏭️ **${label}:** Skipped (no relevant changes)" >> $GITHUB_STEP_SUMMARY ;;
  165. *) echo "❌ **${label}:** ${result}" >> $GITHUB_STEP_SUMMARY ;;
  166. esac
  167. }
  168. report "Change Detection" "${{ needs.check-changes.result }}"
  169. report "CLI" "${{ needs.cli-checks.result }}"
  170. report "Compatibility Layer" "${{ needs.compatibility-layer-checks.result }}"
  171. report "Canonical Build (no drift)" "${{ needs.canonical-drift.result }}"
  172. echo "" >> $GITHUB_STEP_SUMMARY
  173. if [ "${{ needs.canonical-drift.result }}" = "failure" ]; then
  174. echo "> The generated trees drift from \`content/agents/**\`." >> $GITHUB_STEP_SUMMARY
  175. echo "> Run \`make build-canonical\` and commit the result." >> $GITHUB_STEP_SUMMARY
  176. echo "" >> $GITHUB_STEP_SUMMARY
  177. fi
  178. FAILED=0
  179. [ "${{ needs.check-changes.result }}" != "success" ] && FAILED=1
  180. for result in "${{ needs.cli-checks.result }}" "${{ needs.compatibility-layer-checks.result }}" "${{ needs.canonical-drift.result }}"; do
  181. if [ "$result" != "success" ] && [ "$result" != "skipped" ]; then
  182. FAILED=1
  183. fi
  184. done
  185. if [ $FAILED -eq 0 ]; then
  186. echo "### ✅ Required Package Checks Passed" >> $GITHUB_STEP_SUMMARY
  187. else
  188. echo "### ❌ Some Package Checks Failed" >> $GITHUB_STEP_SUMMARY
  189. exit 1
  190. fi