Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ These are the same durable learnings the root [`AGENTS.md`](../AGENTS.md) record

- The required `benchmark` context must always exist, even when benchmark work is skipped. In `ci.yml`, use the PR base-to-head three-dot range so base-only package changes do not run benchmarks, the push before-to-after two-dot range with the all-zero initial-base fallback, and fail closed on an unexpected event or unavailable range; condition only dependency installation, baselines, benchmarking, the push-only summary, and PR artifact on that output.

- The weekly npm downloads workflow reuses `automation/weekly-npm-downloads`; merge `origin/main` into that branch before committing a new snapshot so an open automation PR does not drift behind `main`.
- The weekly npm downloads workflow reuses `automation/weekly-npm-downloads`, but rebuilds it from `origin/main` plus one snapshot commit on every run and force-pushes with a lease, so an open automation PR never drifts behind `main`. Never merge `main` into it or check it out: the merge commit would carry `main`'s workflow-file changes, which the token's missing Workflows permission rejects, and checking out the unprotected branch would run whatever a collaborator pushed there (hooks included) while the token is exposed. Keep `core.hooksPath` unset in that step for the same reason.

- The weekly npm downloads workflow pushes and opens its PR with the `WEEKLY_AUTOMATION_TOKEN` fine-grained personal access token (Contents and Pull requests read/write on this repository only), never `GITHUB_TOKEN`: a push or PR made with `GITHUB_TOKEN` leaves that PR's `pull_request` workflows at `action_required`, so every required check waits for a maintainer to approve the runs. Keep the workflow's own `GITHUB_TOKEN` read-only. The token is an owner credential, and the owner bypasses the default-branch ruleset, so keep it an environment secret of `weekly-automation` (deployment branches: `main` only), never a repository secret: any branch can dispatch the workflow or add a new one, and the dispatched branch supplies the workflow definition, so a guard inside the workflow does not protect a repository secret.

- Cloudflare Workers Builds watch paths are represented by [`.github/cloudflare/docs-watch-paths.json`](../.github/cloudflare/docs-watch-paths.json). Keep the desired list a superset of every docs-build input, including both packages, `.node-version`, `.nvmrc`, and the existing docs/build inputs. Include the gate and configuration policy paths so a policy change forces a real Cloudflare build; the gate uses the union of the immutable merge-base and head policies so a PR cannot hide changes by narrowing its own list. Cloudflare `*` spans `/`, and the owner must sync and verify both live triggers through the documented MCP checklist or dashboard.

Expand Down
54 changes: 35 additions & 19 deletions .github/workflows/weekly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ on:
schedule:
- cron: "17 3 * * 1"

# Pushes and pull requests made with `GITHUB_TOKEN` leave the pull request's
# `pull_request` workflows waiting for maintainer approval, so the required
# checks never report on their own. A fine-grained personal access token
# (`WEEKLY_AUTOMATION_TOKEN`) pushes and opens the pull request instead, and
# `GITHUB_TOKEN` stays read-only. The token lives in the `weekly-automation`
# environment, which only `main` may deploy to, so a run dispatched from
# another branch cannot read it.
permissions:
contents: write
pull-requests: write
contents: read

concurrency:
group: update-weekly-npm-downloads
Expand All @@ -17,6 +23,7 @@ jobs:
npm-downloads:
name: npm-downloads
if: github.repository == 'joe-bell/cva'
environment: weekly-automation
runs-on: ubuntu-latest
timeout-minutes: 10
env:
Expand Down Expand Up @@ -50,41 +57,50 @@ jobs:
- name: Commit and push snapshot
if: steps.snapshot.outputs.changed == 'true'
env:
GH_TOKEN: ${{ github.token }}
GH_TOKEN: ${{ secrets.WEEKLY_AUTOMATION_TOKEN }}
Comment thread
joe-bell marked this conversation as resolved.
Resolved
Comment thread
joe-bell marked this conversation as resolved.
Resolved
shell: bash
run: |
snapshot="$RUNNER_TEMP/npm-weekly-downloads.json"
cp "$SNAPSHOT_PATH" "$snapshot"
git restore -- "$SNAPSHOT_PATH"
# `pnpm install` above points `core.hooksPath` at `.github/hooks`.
# Drop it so no repository hook runs while the token is exposed.
git config --unset-all core.hooksPath || true
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
gh auth setup-git
if [[ "$(git rev-parse --is-shallow-repository)" == true ]]; then
git fetch --unshallow --no-tags origin
fi
git fetch --no-tags origin main:refs/remotes/origin/main

if git ls-remote --exit-code --heads origin "$UPDATE_BRANCH" >/dev/null; then
git fetch --no-tags origin "$UPDATE_BRANCH:refs/remotes/origin/$UPDATE_BRANCH"
git switch --create "$UPDATE_BRANCH" --track "origin/$UPDATE_BRANCH"
git merge --no-commit --no-ff origin/main
else
git switch --create "$UPDATE_BRANCH" origin/main
fi

# Rebuild the update branch from `main` on every run instead of
# merging `main` into it: the branch is never checked out, so its
# contents never run here, and the only new commit is the snapshot,
# so the push never carries workflow-file changes that the token
# has no permission to write.
git fetch --no-tags --depth=1 origin main:refs/remotes/origin/main
git switch --create "$UPDATE_BRANCH" origin/main
cp "$snapshot" "$SNAPSHOT_PATH"
git add "$SNAPSHOT_PATH"
if git diff --cached --quiet && ! git rev-parse --quiet --verify MERGE_HEAD >/dev/null; then
if git diff --cached --quiet; then
exit 0
fi

git commit -m "chore: update weekly npm downloads"
git push --set-upstream origin "$UPDATE_BRANCH"

remote_sha=""
if git ls-remote --exit-code --heads origin "$UPDATE_BRANCH" >/dev/null; then
git fetch --no-tags --depth=1 origin \
"refs/heads/$UPDATE_BRANCH:refs/remotes/origin/$UPDATE_BRANCH"
remote_sha="$(git rev-parse "origin/$UPDATE_BRANCH")"
if git diff --quiet "origin/$UPDATE_BRANCH" HEAD; then
exit 0
fi
fi
git push \
--force-with-lease="refs/heads/$UPDATE_BRANCH:$remote_sha" \
origin "HEAD:refs/heads/$UPDATE_BRANCH"

- name: Open or update pull request
if: steps.snapshot.outputs.changed == 'true'
env:
GH_TOKEN: ${{ github.token }}
GH_TOKEN: ${{ secrets.WEEKLY_AUTOMATION_TOKEN }}
shell: bash
run: |
pr_url="$(gh pr list --head "$UPDATE_BRANCH" --base main --state open --json url --jq '.[0].url')"
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The generator removes stale `docs/.generated/bundle-sizes.json`. It runs each pa

The generator does not compile packages. Root install/prepare provides `dist`. After editing package source, run `pnpm build` or `pnpm --filter <package> build` before direct docs measurement.

The homepage reads weekly npm totals from [`src/content/npm-weekly-downloads.json`](./src/content/npm-weekly-downloads.json). The `weekly / npm-downloads` workflow fetches and validates npm's latest seven-day totals each Monday, then opens or updates a pull request containing the snapshot. Documentation builds read only the checked-in file and never depend on npm's API.
The homepage reads weekly npm totals from [`src/content/npm-weekly-downloads.json`](./src/content/npm-weekly-downloads.json). The `weekly / npm-downloads` workflow fetches and validates npm's latest seven-day totals each Monday, then opens or updates a pull request containing the snapshot. It pushes and opens that pull request with `WEEKLY_AUTOMATION_TOKEN`, a fine-grained personal access token limited to this repository with Contents and Pull requests read/write, so the pull request's required checks run without a maintainer approving them. The token is a secret of the `weekly-automation` environment, which only `main` may deploy to, so workflows on other branches cannot read it. Renew the token before it expires, or the weekly run fails. Documentation builds read only the checked-in file and never depend on npm's API.
Comment thread
joe-bell marked this conversation as resolved.
Resolved

## Markdown mirrors

Expand Down
Loading