-
Notifications
You must be signed in to change notification settings - Fork 26
123 lines (112 loc) · 5.95 KB
/
Copy pathgithub-releases-sync.yml
File metadata and controls
123 lines (112 loc) · 5.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
name: github-releases-sync
# Publishes the cohort GitHub *release* feed LIVE to Supabase
# (public_releases_feed). The OS + web apps read that row anonymously, so a new
# release reaches the membrane within the hour — no PR, no merge into protected
# main, no Vercel deploy. Supabase is the sole freshness path; the committed
# apps/os/src/cohort-surface.json is only the offline / first-paint fallback and
# is intentionally NOT refreshed here.
#
# What it does:
# 1. scripts/check-github-releases.mjs queries the GitHub Releases API (via
# gh, authed with the default GITHUB_TOKEN) for every cohort repo and
# rewrites cohort-data/artifacts/github-releases/generated/*.json (in the
# runner's checkout only — nothing is committed back).
# 2. npm run build:cohort regenerates apps/os/src/cohort-surface.json in the
# runner so the publisher can read project names + the commit/ask/event
# feed items it merges with releases (again, runner-local, not committed).
# 3. scripts/publish-releases-to-supabase.mjs upserts the LIVE feed row from
# the same artifacts — carrying the FULL in-window release history (the
# committed surface caps releases per project for byte-stability).
#
# History: this workflow USED to commit the refreshed surface back to main — first
# via a direct push (rejected by branch protection, GH006), then via an
# automation-branch PR whose `gh pr create` silently fails without the repo's
# "Allow GitHub Actions to create pull requests" setting. Either way the branch
# piled up unmerged and the feed froze at v0.3.5. That whole path is gone: the
# Supabase publish needs no push, no PR, no merge, and no repo setting — it just
# upserts the row. The committed bundle drifting stale is fine; the live overlay
# always overrides it. (To re-freshen the committed bundle on demand, run
# `npm run build:cohort` in a normal PR.)
#
# Cadence:
# Hourly. Releases are low-frequency, but the upsert is idempotent (same row
# when nothing changed), so a no-op hour costs only ~1 min of runner time. Run
# at :23, off the top of the hour, where GitHub's scheduler is least congested
# (on-the-hour crons are routinely delayed or dropped under load).
on:
schedule:
- cron: "23 * * * *" # hourly at :23 UTC. GitHub may still delay under load.
workflow_dispatch: # manual run from the Actions tab
push:
branches:
- main
paths:
- "scripts/check-github-releases.mjs"
- "scripts/build-bundles.js"
- ".github/workflows/github-releases-sync.yml"
permissions:
contents: write
pull-requests: write
# Serialize against main; queue rather than cancel so we never drop a refresh.
concurrency:
group: github-releases-sync
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
cache: npm # hourly cadence → cache npm to keep each run ~1 min
- name: install deps for build:cohort
# build-bundles.js needs js-yaml (frontmatter parser); the lockfile
# pins it. --ignore-scripts skips native rebuilds we don't need.
run: npm ci --ignore-scripts
- name: refresh github-releases artifacts
# gh is preinstalled on ubuntu-latest; GH_TOKEN authenticates it.
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run audit:github-releases -- --write-artifacts
- name: rebuild apps/os/src/cohort-surface.json
run: npm run build:cohort
- name: open guarded bundle refresh PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SYNC_BRANCH: automation/github-releases-sync
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -B "$SYNC_BRANCH"
git add cohort-data/artifacts/github-releases cohort-data/artifacts/cohort-insights apps/os/src/cohort-surface.json
node scripts/check-commit-privacy-boundary.mjs --staged
npm run surface:scan
if git diff --cached --quiet; then
echo "No committed release-bundle changes."
else
git commit -m "chore(releases): sync cohort GitHub releases"
# Plain --force (not --force-with-lease): the branch is recreated
# fresh from main each run via `checkout -B` and the remote ref is
# never fetched, so --force-with-lease has no lease base and always
# rejects as "stale info". The branch is a disposable bot branch, so
# an unconditional overwrite is safe.
git push --force origin "$SYNC_BRANCH"
gh pr create --base main --head "$SYNC_BRANCH" --title "chore(releases): sync cohort GitHub releases" --body "Automated refresh of generated cohort GitHub release artifacts and offline cohort surface." || echo "Bundle refresh PR already exists or could not be created."
fi
- name: publish release feed to Supabase (live source)
# The apps read this row LIVE (public_releases_feed), so a new release
# reaches the membrane within the hour WITHOUT waiting on the offline-
# bundle PR below merging into protected main — which is exactly what
# used to freeze the feed. Carries the FULL in-window release history
# (the committed surface caps releases per project for byte-stability).
# Idempotent: upserts the same row when nothing changed. Uses the
# service-role key the calendar workflow already holds; skips cleanly if
# the secret is absent.
env:
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
run: node scripts/publish-releases-to-supabase.mjs