validate-registry.yml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. name: Validate Registry on PR
  2. # This workflow validates the registry.json and prompt library structure on all PRs.
  3. #
  4. # For bot-created PRs (like automated version bumps), the workflow won't trigger automatically
  5. # due to GitHub's security restrictions. In those cases, you can manually trigger this workflow:
  6. #
  7. # Option 1 - Run Validation:
  8. # 1. Go to Actions > Validate Registry on PR > Run workflow
  9. # 2. Enter the PR number (e.g., 106)
  10. # 3. Leave "skip_validation" unchecked
  11. # 4. Click "Run workflow"
  12. #
  13. # Option 2 - Admin Bypass (for trusted bot PRs):
  14. # 1. Go to Actions > Validate Registry on PR > Run workflow
  15. # 2. Enter the PR number (e.g., 106)
  16. # 3. Check "skip_validation" checkbox
  17. # 4. Click "Run workflow"
  18. # 5. The check will pass immediately without running validation
  19. on:
  20. # Use pull_request_target to allow running on bot-created PRs
  21. # This also allows the workflow to write to the PR branch
  22. pull_request_target:
  23. branches:
  24. - main
  25. - dev
  26. # Removed paths filter - this check is required by repository ruleset
  27. # so it must run on ALL PRs to prevent blocking merges
  28. workflow_dispatch:
  29. inputs:
  30. pr_number:
  31. description: 'PR number to validate (for manual runs on bot-created PRs)'
  32. required: false
  33. type: number
  34. skip_validation:
  35. description: 'Skip validation checks (maintainer override)'
  36. required: false
  37. type: boolean
  38. default: false
  39. permissions:
  40. contents: write
  41. pull-requests: write
  42. jobs:
  43. validate-and-update:
  44. runs-on: ubuntu-latest
  45. steps:
  46. - name: Admin bypass check
  47. if: github.event_name == 'workflow_dispatch' && github.event.inputs.skip_validation == 'true'
  48. run: |
  49. echo "## ✅ Validation Bypassed (Admin Override)" >> $GITHUB_STEP_SUMMARY
  50. echo "" >> $GITHUB_STEP_SUMMARY
  51. echo "Validation checks skipped by maintainer." >> $GITHUB_STEP_SUMMARY
  52. echo "PR: #${{ github.event.inputs.pr_number }}" >> $GITHUB_STEP_SUMMARY
  53. echo "" >> $GITHUB_STEP_SUMMARY
  54. echo "The workflow will complete successfully without running validation steps." >> $GITHUB_STEP_SUMMARY
  55. - name: Checkout repository (for manual runs)
  56. if: github.event_name == 'workflow_dispatch' && github.event.inputs.skip_validation != 'true'
  57. uses: actions/checkout@v4
  58. with:
  59. fetch-depth: 0
  60. token: ${{ secrets.GITHUB_TOKEN }}
  61. - name: Get PR details (for manual runs)
  62. if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_number != '' && github.event.inputs.skip_validation != 'true'
  63. id: get_pr
  64. run: |
  65. PR_DATA=$(gh pr view ${{ github.event.inputs.pr_number }} --json headRefName,headRepository,headRepositoryOwner)
  66. echo "head_ref=$(echo $PR_DATA | jq -r '.headRefName')" >> $GITHUB_OUTPUT
  67. echo "head_repo=$(echo $PR_DATA | jq -r '.headRepositoryOwner.login + "/" + .headRepository.name')" >> $GITHUB_OUTPUT
  68. env:
  69. GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  70. - name: Checkout PR branch
  71. if: github.event.inputs.skip_validation != 'true'
  72. uses: actions/checkout@v4
  73. with:
  74. # For manual runs: use PR details from get_pr step
  75. # For PR events: use event data
  76. repository: ${{ github.event_name == 'workflow_dispatch' && steps.get_pr.outputs.head_repo || github.event.pull_request.head.repo.full_name }}
  77. ref: ${{ github.event_name == 'workflow_dispatch' && steps.get_pr.outputs.head_ref || github.event.pull_request.head.ref }}
  78. fetch-depth: 0
  79. token: ${{ secrets.GITHUB_TOKEN }}
  80. - name: Detect fork PR
  81. if: github.event.inputs.skip_validation != 'true'
  82. id: fork_check
  83. run: |
  84. # For manual runs, use the fetched PR data
  85. if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
  86. HEAD_REPO="${{ steps.get_pr.outputs.head_repo }}"
  87. else
  88. HEAD_REPO="${{ github.event.pull_request.head.repo.full_name }}"
  89. fi
  90. if [ "$HEAD_REPO" != "${{ github.repository }}" ]; then
  91. echo "is_fork=true" >> $GITHUB_OUTPUT
  92. echo "🔀 Fork PR detected from: $HEAD_REPO"
  93. else
  94. echo "is_fork=false" >> $GITHUB_OUTPUT
  95. echo "📝 Internal PR detected"
  96. fi
  97. - name: Install dependencies
  98. if: github.event.inputs.skip_validation != 'true'
  99. run: |
  100. sudo apt-get update
  101. sudo apt-get install -y jq
  102. - name: Install Bun
  103. if: github.event.inputs.skip_validation != 'true'
  104. uses: oven-sh/setup-bun@v2
  105. with:
  106. bun-version: latest
  107. - name: Install dependencies
  108. if: github.event.inputs.skip_validation != 'true'
  109. run: |
  110. # Install root dependencies (glob package needed for validation script)
  111. bun install --frozen-lockfile
  112. - name: Make scripts executable
  113. if: github.event.inputs.skip_validation != 'true'
  114. run: |
  115. chmod +x scripts/registry/validate-registry.sh
  116. chmod +x scripts/registry/auto-detect-components.sh
  117. chmod +x scripts/registry/register-component.sh
  118. chmod +x scripts/prompts/validate-pr.sh
  119. - name: Auto-detect new components
  120. if: github.event.inputs.skip_validation != 'true'
  121. id: auto_detect
  122. run: |
  123. echo "## 🔍 Auto-Detection Results" >> $GITHUB_STEP_SUMMARY
  124. echo "" >> $GITHUB_STEP_SUMMARY
  125. # Run auto-detect in dry-run mode first to see what would be added
  126. if ./scripts/registry/auto-detect-components.sh --dry-run > /tmp/detect-output.txt 2>&1; then
  127. cat /tmp/detect-output.txt >> $GITHUB_STEP_SUMMARY
  128. # Check if new components were found
  129. if grep -q "Found.*new component" /tmp/detect-output.txt; then
  130. echo "new_components=true" >> $GITHUB_OUTPUT
  131. echo "" >> $GITHUB_STEP_SUMMARY
  132. echo "⚠️ New components detected - will auto-add to registry" >> $GITHUB_STEP_SUMMARY
  133. else
  134. echo "new_components=false" >> $GITHUB_OUTPUT
  135. echo "✅ No new components found" >> $GITHUB_STEP_SUMMARY
  136. fi
  137. else
  138. echo "new_components=false" >> $GITHUB_OUTPUT
  139. echo "❌ Auto-detection failed" >> $GITHUB_STEP_SUMMARY
  140. fi
  141. - name: Add new components to registry
  142. if: steps.auto_detect.outputs.new_components == 'true' && github.event.inputs.skip_validation != 'true'
  143. run: |
  144. echo "## 📝 Adding New Components" >> $GITHUB_STEP_SUMMARY
  145. echo "" >> $GITHUB_STEP_SUMMARY
  146. ./scripts/registry/auto-detect-components.sh --auto-add | tee -a $GITHUB_STEP_SUMMARY
  147. - name: Validate prompt library structure
  148. if: github.event.inputs.skip_validation != 'true'
  149. id: validate_prompts
  150. run: |
  151. echo "## 🔍 Prompt Library Validation" >> $GITHUB_STEP_SUMMARY
  152. echo "" >> $GITHUB_STEP_SUMMARY
  153. if ./scripts/prompts/validate-pr.sh > /tmp/prompt-validation.txt 2>&1; then
  154. echo "prompt_validation=passed" >> $GITHUB_OUTPUT
  155. echo "✅ Prompt library structure is valid!" >> $GITHUB_STEP_SUMMARY
  156. echo "" >> $GITHUB_STEP_SUMMARY
  157. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  158. cat /tmp/prompt-validation.txt >> $GITHUB_STEP_SUMMARY
  159. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  160. else
  161. echo "prompt_validation=failed" >> $GITHUB_OUTPUT
  162. echo "❌ Prompt library validation failed!" >> $GITHUB_STEP_SUMMARY
  163. echo "" >> $GITHUB_STEP_SUMMARY
  164. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  165. cat /tmp/prompt-validation.txt >> $GITHUB_STEP_SUMMARY
  166. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  167. echo "" >> $GITHUB_STEP_SUMMARY
  168. echo "**Architecture:**" >> $GITHUB_STEP_SUMMARY
  169. echo "- Agent files (.opencode/agent/**/*.md) = Canonical defaults" >> $GITHUB_STEP_SUMMARY
  170. echo "- Prompt variants (.opencode/prompts/<agent>/<model>.md) = Model-specific" >> $GITHUB_STEP_SUMMARY
  171. echo "- default.md files should NOT exist" >> $GITHUB_STEP_SUMMARY
  172. echo "- Agents organized in category subdirectories (core/, development/, content/, etc.)" >> $GITHUB_STEP_SUMMARY
  173. echo "" >> $GITHUB_STEP_SUMMARY
  174. echo "See [CONTRIBUTING.md](docs/contributing/CONTRIBUTING.md) for details" >> $GITHUB_STEP_SUMMARY
  175. exit 1
  176. fi
  177. - name: Validate registry
  178. if: github.event.inputs.skip_validation != 'true'
  179. id: validate
  180. run: |
  181. echo "## ✅ Registry Validation" >> $GITHUB_STEP_SUMMARY
  182. echo "" >> $GITHUB_STEP_SUMMARY
  183. # Use TypeScript validator (fast and reliable)
  184. # Run validation and capture output (show in logs AND save to file)
  185. if bun run scripts/registry/validate-registry.ts 2>&1 | tee /tmp/validation-output.txt; then
  186. echo "validation=passed" >> $GITHUB_OUTPUT
  187. echo "✅ All registry paths are valid!" >> $GITHUB_STEP_SUMMARY
  188. echo "" >> $GITHUB_STEP_SUMMARY
  189. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  190. cat /tmp/validation-output.txt >> $GITHUB_STEP_SUMMARY
  191. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  192. else
  193. echo "validation=failed" >> $GITHUB_OUTPUT
  194. echo "❌ Registry validation failed!" >> $GITHUB_STEP_SUMMARY
  195. echo "" >> $GITHUB_STEP_SUMMARY
  196. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  197. cat /tmp/validation-output.txt >> $GITHUB_STEP_SUMMARY
  198. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  199. echo "" >> $GITHUB_STEP_SUMMARY
  200. echo "**Check the logs above for detailed error output**" >> $GITHUB_STEP_SUMMARY
  201. exit 1
  202. fi
  203. - name: Commit registry updates (Internal PRs only)
  204. if: |
  205. github.event.inputs.skip_validation != 'true' &&
  206. steps.fork_check.outputs.is_fork == 'false' &&
  207. steps.auto_detect.outputs.new_components == 'true' &&
  208. steps.validate_prompts.outputs.prompt_validation == 'passed' &&
  209. steps.validate.outputs.validation == 'passed'
  210. run: |
  211. git config --local user.email "github-actions[bot]@users.noreply.github.com"
  212. git config --local user.name "github-actions[bot]"
  213. if ! git diff --quiet registry.json; then
  214. git add registry.json
  215. git commit -m "chore: auto-update registry with new components [skip ci]"
  216. # For manual runs, use the fetched branch name
  217. BRANCH_NAME="${{ github.event_name == 'workflow_dispatch' && steps.get_pr.outputs.head_ref || github.event.pull_request.head.ref }}"
  218. git push origin "$BRANCH_NAME"
  219. echo "## 🚀 Registry Updated" >> $GITHUB_STEP_SUMMARY
  220. echo "" >> $GITHUB_STEP_SUMMARY
  221. echo "Registry has been automatically updated with new components." >> $GITHUB_STEP_SUMMARY
  222. echo "Changes have been pushed to this PR branch." >> $GITHUB_STEP_SUMMARY
  223. else
  224. echo "## ℹ️ No Changes to Commit" >> $GITHUB_STEP_SUMMARY
  225. echo "" >> $GITHUB_STEP_SUMMARY
  226. echo "Registry is already up to date." >> $GITHUB_STEP_SUMMARY
  227. fi
  228. - name: Fork PR notice
  229. if: |
  230. github.event.inputs.skip_validation != 'true' &&
  231. steps.fork_check.outputs.is_fork == 'true' &&
  232. steps.auto_detect.outputs.new_components == 'true' &&
  233. steps.validate_prompts.outputs.prompt_validation == 'passed' &&
  234. steps.validate.outputs.validation == 'passed'
  235. uses: actions/github-script@v7
  236. with:
  237. script: |
  238. github.rest.issues.createComment({
  239. issue_number: context.issue.number,
  240. owner: context.repo.owner,
  241. repo: context.repo.repo,
  242. body: `## 📝 Registry Update Needed
  243. Hi @${{ github.event.pull_request.user.login }}! 👋
  244. New components were detected in your PR. Since this is a fork PR, I can't auto-commit the registry updates for security reasons.
  245. **Please run these commands locally:**
  246. \`\`\`bash
  247. ./scripts/registry/auto-detect-components.sh --auto-add
  248. git add registry.json
  249. git commit -m "chore: update registry"
  250. git push
  251. \`\`\`
  252. Once you push the updated registry, the checks will pass! ✅`
  253. });
  254. - name: Fork PR summary
  255. if: steps.fork_check.outputs.is_fork == 'true' && github.event.inputs.skip_validation != 'true'
  256. run: |
  257. echo "## 🔀 Fork PR Detected" >> $GITHUB_STEP_SUMMARY
  258. echo "" >> $GITHUB_STEP_SUMMARY
  259. echo "This is an external contribution - thank you! 🎉" >> $GITHUB_STEP_SUMMARY
  260. echo "" >> $GITHUB_STEP_SUMMARY
  261. if [ "${{ steps.auto_detect.outputs.new_components }}" == "true" ]; then
  262. echo "⚠️ **Action Required:** New components detected" >> $GITHUB_STEP_SUMMARY
  263. echo "" >> $GITHUB_STEP_SUMMARY
  264. echo "A comment has been posted with instructions to update the registry." >> $GITHUB_STEP_SUMMARY
  265. else
  266. echo "✅ No registry updates needed" >> $GITHUB_STEP_SUMMARY
  267. fi
  268. - name: Post validation summary
  269. if: always()
  270. run: |
  271. echo "" >> $GITHUB_STEP_SUMMARY
  272. echo "---" >> $GITHUB_STEP_SUMMARY
  273. echo "" >> $GITHUB_STEP_SUMMARY
  274. PROMPT_VALID="${{ steps.validate_prompts.outputs.prompt_validation }}"
  275. REGISTRY_VALID="${{ steps.validate.outputs.validation }}"
  276. if [ "$PROMPT_VALID" = "passed" ] && [ "$REGISTRY_VALID" = "passed" ]; then
  277. echo "### ✅ All Validations Passed" >> $GITHUB_STEP_SUMMARY
  278. echo "" >> $GITHUB_STEP_SUMMARY
  279. echo "- ✅ Prompt library structure is valid" >> $GITHUB_STEP_SUMMARY
  280. echo "- ✅ Registry paths are valid" >> $GITHUB_STEP_SUMMARY
  281. echo "" >> $GITHUB_STEP_SUMMARY
  282. echo "This PR is ready for review!" >> $GITHUB_STEP_SUMMARY
  283. else
  284. echo "### ❌ Validation Failed" >> $GITHUB_STEP_SUMMARY
  285. echo "" >> $GITHUB_STEP_SUMMARY
  286. if [ "$PROMPT_VALID" != "passed" ]; then
  287. echo "- ❌ Prompt library validation failed" >> $GITHUB_STEP_SUMMARY
  288. else
  289. echo "- ✅ Prompt library validation passed" >> $GITHUB_STEP_SUMMARY
  290. fi
  291. if [ "$REGISTRY_VALID" != "passed" ]; then
  292. echo "- ❌ Registry validation failed" >> $GITHUB_STEP_SUMMARY
  293. else
  294. echo "- ✅ Registry validation passed" >> $GITHUB_STEP_SUMMARY
  295. fi
  296. echo "" >> $GITHUB_STEP_SUMMARY
  297. echo "Please fix the issues above before merging." >> $GITHUB_STEP_SUMMARY
  298. fi
  299. - name: Fail if validation failed
  300. if: |
  301. (steps.validate_prompts.outputs.prompt_validation == 'failed' || steps.validate.outputs.validation == 'failed') &&
  302. github.event.inputs.skip_validation != 'true'
  303. run: |
  304. echo "❌ Validation failed - blocking PR merge"
  305. echo "Maintainer can override by running workflow manually with 'skip_validation' enabled"
  306. exit 1