validate-registry.yml 15 KB

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