mirror of
https://github.com/Heretek-AI/awesome-opencode.git
synced 2026-11-07 02:35:58 -10:00
ci: publish the README through the required validate check
Deploy keys are disabled for this org and GitHub Actions cannot be a ruleset bypass actor, so main is protected by requiring a passing validate check on every commit. The README workflow stages its regenerated commit on bot/readme-<sha>, dispatches validate there (allowed to touch generated files only for that bot branch), waits for success and fast-forwards main. Adds a catalog policy link to the README header and documents the branch protection. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
6279aab5e1
commit
dcbe583a4b
5 files changed
+54
-11
No files matched your search
@@ -10,8 +10,12 @@ on:
|
||||
- 'scripts/**'
|
||||
workflow_dispatch:
|
||||
|
||||
# main requires a passing "validate" check on every commit, so the regenerated README is first pushed
|
||||
# to a bot/readme-* branch, validated there, and then fast-forwarded onto main.
|
||||
permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
checks: read
|
||||
|
||||
concurrency:
|
||||
group: auto-generate-readme-main
|
||||
@@ -39,7 +43,9 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci --ignore-scripts
|
||||
|
||||
- name: Generate and push README/registry
|
||||
- name: Generate, validate and publish README/registry
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -62,14 +68,34 @@ jobs:
|
||||
|
||||
git add README.md dist/registry.json
|
||||
git commit -m "docs: auto-regenerate README and registry data"
|
||||
sha="$(git rev-parse HEAD)"
|
||||
branch="bot/readme-${sha:0:12}"
|
||||
|
||||
if git push origin HEAD:main; then
|
||||
# Stage the commit and run the required "validate" check on it
|
||||
git push --force origin "HEAD:refs/heads/${branch}"
|
||||
gh workflow run validate-pr.yml --ref "${branch}"
|
||||
conclusion=""
|
||||
for i in $(seq 1 60); do
|
||||
sleep 10
|
||||
conclusion="$(gh api "repos/${GITHUB_REPOSITORY}/commits/${sha}/check-runs?check_name=validate" \
|
||||
--jq '[.check_runs[] | select(.status == "completed") | .conclusion][0] // ""')"
|
||||
[ -n "${conclusion}" ] && break
|
||||
done
|
||||
|
||||
if [ "${conclusion}" != "success" ]; then
|
||||
git push origin --delete "${branch}" || true
|
||||
echo "validate on ${sha} finished with '${conclusion:-timeout}'; not publishing" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if git push origin "${sha}:refs/heads/main"; then
|
||||
git push origin --delete "${branch}" || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Push raced with another main update; retrying..."
|
||||
sleep 2
|
||||
git push origin --delete "${branch}" || true
|
||||
echo "main moved while validating; retrying..."
|
||||
done
|
||||
|
||||
echo "Failed to push regenerated README/registry after retries" >&2
|
||||
echo "Failed to publish regenerated README/registry after retries" >&2
|
||||
exit 1
|
||||
@@ -41,7 +41,14 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
BASE_REF: ${{ github.event.pull_request.base.sha || 'origin/main' }}
|
||||
run: node scripts/check-pr.js --base "$BASE_REF"
|
||||
# The README bot stages its regenerated README on bot/readme-* and dispatches this check
|
||||
ALLOW_GENERATED: ${{ github.event_name == 'workflow_dispatch' && github.actor == 'github-actions[bot]' && startsWith(github.ref_name, 'bot/readme-') }}
|
||||
run: |
|
||||
if [ "$ALLOW_GENERATED" = "true" ]; then
|
||||
node scripts/check-pr.js --base "$BASE_REF" --allow-generated
|
||||
else
|
||||
node scripts/check-pr.js --base "$BASE_REF"
|
||||
fi
|
||||
|
||||
- name: README and registry still generate
|
||||
run: |
|
||||
|
||||
+5
-1
@@ -49,13 +49,17 @@ Removal PRs are reviewed like any other PR; closing one keeps the entries until
|
||||
|
||||
A weekly scout searches npm for packages published since V2 shipped that depend on `@opencode/*`, keeps public, licensed, non-archived, non-fork repositories that are not already listed or in an open PR, and ranks them by weekly downloads, then stars. It posts a **Scout** issue; a maintainer ticking a candidate's box makes the bot open a PR for it. Add a package or repo to [`discovery/declined.txt`](../discovery/declined.txt) to stop suggesting it.
|
||||
|
||||
## Branch protection
|
||||
|
||||
`main` has a ruleset: every commit that lands on it must have a passing `validate` check, and force-pushes and deletion are blocked. Contributors and maintainers get the check through pull requests; bots get it by dispatching `validate` on their branch. Repository admins can merge a PR whose check is failing or pending (for a broken CI), but cannot push unvalidated commits directly.
|
||||
|
||||
## Automation map
|
||||
|
||||
| Workflow | When | What |
|
||||
| :--- | :--- | :--- |
|
||||
| `validate-pr.yml` | every PR | Required `validate` check |
|
||||
| `triage.yml` | PR opened/updated | Labels and a results comment (base-branch code only) |
|
||||
| `generate-readme.yml` | push to main | README.md and dist/registry.json; fails without writing on any invalid entry |
|
||||
| `generate-readme.yml` | push to main | README.md and dist/registry.json; fails without writing on any invalid entry. The regenerated commit is staged on `bot/readme-*`, validated, then fast-forwarded onto main |
|
||||
| `site.yml` | push to main, daily | Search site on GitHub Pages |
|
||||
| `health.yml` | daily | Health report issue, rename and removal PRs |
|
||||
| `reprobe.yml` | daily | Re-checks `needs-v2` PRs |
|
||||
|
||||
+8
-4
@@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* The required "validate" check for pull requests.
|
||||
* Usage: node scripts/check-pr.js --base <git-ref> [--no-probe]
|
||||
* Usage: node scripts/check-pr.js --base <git-ref> [--no-probe] [--allow-generated]
|
||||
*
|
||||
* --allow-generated is passed only for the README bot's own staged commits (see generate-readme.yml).
|
||||
*
|
||||
* Compares HEAD against the merge base with <git-ref>, analyzes the changed files, writes a report to
|
||||
* $GITHUB_STEP_SUMMARY (when set) and exits 1 on any blocking problem.
|
||||
@@ -11,7 +13,7 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execFileSync } = require('child_process');
|
||||
const { loadCatalog } = require('./utils/catalog');
|
||||
const { DATA_FILE_RE, analyzePullRequest, formatReport } = require('./utils/pr-checks');
|
||||
const { DATA_FILE_RE, GENERATED_FILES, analyzePullRequest, formatReport } = require('./utils/pr-checks');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const git = (...args) => execFileSync('git', args, { cwd: ROOT, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
||||
@@ -20,7 +22,8 @@ function parseArgs(argv) {
|
||||
const baseIndex = argv.indexOf('--base');
|
||||
return {
|
||||
base: baseIndex !== -1 ? argv[baseIndex + 1] : 'origin/main',
|
||||
probe: !argv.includes('--no-probe')
|
||||
probe: !argv.includes('--no-probe'),
|
||||
allowGenerated: argv.includes('--allow-generated')
|
||||
};
|
||||
}
|
||||
|
||||
@@ -42,7 +45,7 @@ function changedFiles(mergeBase) {
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { base, probe } = parseArgs(process.argv.slice(2));
|
||||
const { base, probe, allowGenerated } = parseArgs(process.argv.slice(2));
|
||||
const mergeBase = git('merge-base', base, 'HEAD').trim();
|
||||
const changes = changedFiles(mergeBase);
|
||||
|
||||
@@ -61,6 +64,7 @@ async function main() {
|
||||
const baseEntries = entries.filter(e => !changedPaths.has(e.file));
|
||||
|
||||
const result = await analyzePullRequest({ changes, baseEntries, probe });
|
||||
if (allowGenerated) result.errors = result.errors.filter(e => !GENERATED_FILES.includes(e.file));
|
||||
// Unparseable files anywhere in the catalog break README generation, so they always block
|
||||
for (const err of loadErrors) {
|
||||
if (!result.errors.some(e => e.file === err.file)) result.errors.push({ ...err, kind: 'metadata' });
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
<a href="https://heretek-ai.github.io/awesome-opencode/"><b>🔎 Search & filter the catalog</b></a>
|
||||
•
|
||||
<a href="https://github.com/Heretek-AI/awesome-opencode/issues/new?template=add-entry.yml"><b>➕ Submit an entry</b></a>
|
||||
•
|
||||
<a href="https://github.com/Heretek-AI/awesome-opencode/blob/main/docs/policy.md"><b>📋 Catalog policy</b></a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
Reference in new issue
Block a user