diff --git a/.github/workflows/template-sync.yml b/.github/workflows/template-sync.yml index 23328884..33d431cb 100644 --- a/.github/workflows/template-sync.yml +++ b/.github/workflows/template-sync.yml @@ -3,7 +3,7 @@ name: Template sync # Keeps cloudhal-dev/cloudhal-template, the repository the Deploy to Cloudflare button copies # (docs/guides/deploy-button.md), on the latest release (issue #111). release.yml calls this after # a successful npm publish; to re-sync by hand, run Actions › Template sync › Run workflow with a -# version npm has. +# version npm has, or scripts/template-sync.ts from a checkout (CONTRIBUTING.md, Releasing). # scripts/template-sync.ts copies src/, public/, astro.config.mjs and tsconfig.json from the blog # starter `@cloudhal/cli@` ships and moves @cloudhal/* to ^; the lockfile is # refreshed with every @cloudhal/* at exactly , without running package code; then one PR diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cb9b2f44..1bf74ce2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ All publishable packages (`@cloudhal/*` and `create-cloudhal`) share one version 3. **Approval.** The merge starts the `publish` job, which waits for the `npm-publish` environment's approval (the maintainer, with 2FA). Approve it in the run's page on GitHub. 4. **Publish.** `scripts/publish-ci.ts` checks the build, packs every package and installs the tarballs from scratch with npm (`scripts/smoke-pack.ts`), publishes exactly those tarballs with npm trusted publishing (OIDC, with provenance), waits until npm serves all of them, then creates the `vX.Y.Z` tag and the GitHub Release from the changelogs. 5. **After the release.** Bring the rest along: - - **cloudhal-template** (the Deploy to Cloudflare button): the workflow's `template` job (`.github/workflows/template-sync.yml`) opens `chore: Cloudhal X.Y.Z and the X.Y.Z starter theme` from `cloudhal/vX.Y.Z`, with `src/`, `public/`, `astro.config.mjs` and `tsconfig.json` from the published starter, `@cloudhal/*` at `^X.Y.Z` and a lockfile that installs exactly `X.Y.Z`. Merge it once its `cloudhal/template-check` status is green: the same run installs a copy of the synced template with `npm ci` and runs `cloudhal deploy --dry-run` with `WORKERS_CI=1`. To sync again, run Actions › Template sync › Run workflow. Without the `TEMPLATE_SYNC_APP_CLIENT_ID` variable and the `TEMPLATE_SYNC_APP_PRIVATE_KEY` secret (a GitHub App installed on cloudhal-template only, with Contents, Pull requests and Commit statuses write) the job only logs a notice; Dependabot's `@cloudhal/*` PR on the template is the fallback, and it brings dependencies only, no theme. + - **cloudhal-template** (the Deploy to Cloudflare button): the workflow's `template` job (`.github/workflows/template-sync.yml`) opens `chore: Cloudhal X.Y.Z and the X.Y.Z starter theme` from `cloudhal/vX.Y.Z`, with `src/`, `public/`, `astro.config.mjs` and `tsconfig.json` from the published starter, `@cloudhal/*` at `^X.Y.Z` and a lockfile that installs exactly `X.Y.Z`. Merge it once its `cloudhal/template-check` status is green: the same run installs a copy of the synced template with `npm ci` and runs `cloudhal deploy --dry-run` with `WORKERS_CI=1`. To sync again, run Actions › Template sync › Run workflow. Without the `TEMPLATE_SYNC_APP_CLIENT_ID` variable and the `TEMPLATE_SYNC_APP_PRIVATE_KEY` secret (a GitHub App installed on cloudhal-template only, with Contents, Pull requests and Commit statuses write) the job only logs a notice. Then sync by hand from a checkout: clone cloudhal-template next to this repository, run `node scripts/template-sync.ts --template ../cloudhal-template --version X.Y.Z --summary pr-body.md` and then the same command with `--lock` in place of `--summary` (Node 24, no `pnpm install` needed), check a copy of the template (`npm ci`, then `WORKERS_CI=1 npx cloudhal deploy --dry-run`), commit on `cloudhal/vX.Y.Z`, push, open the PR with the title above and `pr-body.md` as its body, and post the `cloudhal/template-check` status on its head commit (`gh api -X POST repos/cloudhal-dev/cloudhal-template/statuses/ -f state=success -f context=cloudhal/template-check -f description='npm ci and cloudhal deploy --dry-run (WORKERS_CI=1) passed, run by hand'`). Dependabot's `@cloudhal/*` PR on the template is no substitute: it moves dependencies only, no theme, and it fails to install whenever the starter's own pins moved with the release (0.6.3 moved astro to 7.4.7 for the `^7.4.0` peer range, so Dependabot's `^0.6.1` PR hit ERESOLVE); close it as superseded by the sync PR. - **cloudhal.com**: Dependabot opens the `@cloudhal/*` PR the next morning (06:00 Europe/Istanbul). A patch release merges itself after its check; a minor bump waits for a person. - **try.cloudhal.com** (`cloudhal-dev/try`): by hand. Bump its exact `@cloudhal/*` pins, then `pnpm install` and `pnpm run deploy`. - **The Docker image** (`ghcr.io/cloudhal-dev/cloudhal`, [self-host guide](docs/guides/self-host.md)): the workflow's `docker` job (`.github/workflows/docker.yml`) builds it from the npm release and pushes `X.Y.Z`, `X.Y` and `latest` for linux/amd64 and linux/arm64, with an SBOM, provenance and a smoke test. The image never carries a version of its own: one release, one version everywhere. To rebuild a version (a base-image fix) run Actions › Docker image › Run workflow with it; that re-tags `X.Y.Z` and `X.Y` and leaves `latest` alone. `edge` is built nightly from `main`. diff --git a/packages/cli/test/template-sync.test.ts b/packages/cli/test/template-sync.test.ts index dc98bd5c..d5c97b70 100644 --- a/packages/cli/test/template-sync.test.ts +++ b/packages/cli/test/template-sync.test.ts @@ -526,6 +526,14 @@ describe("PR body", () => { expect(body).toContain("Do not push to this branch"); }); + it("says who opened it: the workflow run, or a hand run of the script", () => { + const byHand = prBody({ ops: [], from: "0.6.0", to: "0.6.3" }); + expect(byHand).toContain("Opened by hand with `scripts/template-sync.ts`"); + expect(byHand).toContain("whoever synced by hand installed a copy of this branch"); + expect(byHand).not.toContain("release workflow"); + expect(byHand).toContain("None: dependencies and the lockfile only."); + }); + it("caps each path list at 50", () => { const ops = Array.from({ length: 60 }, (_, i) => write(`src/f${String(i).padStart(2, "0")}.css`), diff --git a/scripts/template-pr.ts b/scripts/template-pr.ts index 20388d58..d2f543c6 100644 --- a/scripts/template-pr.ts +++ b/scripts/template-pr.ts @@ -1,6 +1,7 @@ /** * The text of the cloudhal-template PR that scripts/template-sync.ts writes for - * .github/workflows/template-sync.yml (issue #111): what moved, what to read, what must pass. + * .github/workflows/template-sync.yml, or for a hand run of the script (issue #111): what moved, + * what to read, what must pass, and who opened it. * A pure function over scripts/template-plan.ts's operations; Node built-ins only. */ import type { DepChange, SyncOp } from "./template-plan.ts"; @@ -11,7 +12,7 @@ export interface PrBodyOptions { readonly from: string | undefined; readonly to: string; readonly deps?: readonly DepChange[] | undefined; - /** The workflow run that opened the PR. */ + /** The workflow run that opened the PR; undefined when the script ran by hand. */ readonly runUrl?: string | undefined; } @@ -69,9 +70,11 @@ export function prBody(o: PrBodyOptions): string { "", "### Before merging", "", - "The `cloudhal/template-check` status must be green: the Template sync run installed a copy of this branch with `npm ci` and ran `cloudhal deploy --dry-run` with `WORKERS_CI=1`. Merging changes what the Deploy to Cloudflare button deploys from now on; sites created earlier keep their theme.", + `The \`cloudhal/template-check\` status must be green: ${o.runUrl ? "the Template sync run" : "whoever synced by hand"} installed a copy of this branch with \`npm ci\` and ran \`cloudhal deploy --dry-run\` with \`WORKERS_CI=1\`. Merging changes what the Deploy to Cloudflare button deploys from now on; sites created earlier keep their theme.`, "", - `Opened by the Cloudhal release workflow${o.runUrl ? ` ([run](${o.runUrl}))` : ""}. Do not push to this branch: a re-run of Template sync rebuilds it from \`main\` and replaces it.`, + o.runUrl + ? `Opened by the Cloudhal release workflow ([run](${o.runUrl})). Do not push to this branch: a re-run of Template sync rebuilds it from \`main\` and replaces it.` + : "Opened by hand with `scripts/template-sync.ts` (CONTRIBUTING.md, Releasing), not by the Template sync workflow. Do not push to this branch: a run of Template sync rebuilds it from `main` and replaces it.", "", ].join("\n"); } diff --git a/scripts/template-sync.ts b/scripts/template-sync.ts index 317eed52..bd406425 100644 --- a/scripts/template-sync.ts +++ b/scripts/template-sync.ts @@ -1,7 +1,8 @@ /** * Moves cloudhal-template (the Deploy to Cloudflare button) to a Cloudhal release, issue #111. * .github/workflows/template-sync.yml runs it after each npm publish, then refreshes the - * lockfile and opens the PR; scripts/template-plan.ts has the rules. + * lockfile and opens the PR; scripts/template-plan.ts has the rules. Without the workflow's + * GitHub App it runs by hand from a checkout, the same two commands (CONTRIBUTING.md, Releasing). * * node scripts/template-sync.ts --template --version * [--starter ] [--wait ] [--summary ] [--check] [--allow-downgrade]