commit cf20cd088e4c7bd62d98be311f96e2609857ec1d
parent 67ace2d330967dd2ec7b6ec34df37ee3a39db1a4
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Fri, 25 Sep 2026 16:20:01 -0400
publish: deploy homepage [--preview <branch>] — deployHomepage takes previewBranch the way deployHub does
previewBranchProblem refuses main/production and bad names before the build
check; a preview deploys to its own branch with no --branch main and prints
the previewAliasUrl line. homepageDeployArgs is the pure argv, pinned in
build.test.ts (+2).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
3 files changed, 67 insertions(+), 8 deletions(-)
diff --git a/common/bin/archilyzer.ts b/common/bin/archilyzer.ts
@@ -158,10 +158,17 @@ export const COMMANDS: Command[] = [
},
{
path: ["deploy", "homepage"],
- usage: "ship homepage/out to the Pages project archilyzer (production branch main)",
- run: async () => {
+ usage:
+ "[--preview <branch>] ship homepage/out to the Pages project archilyzer (production branch main)",
+ flags: { preview: "string" },
+ run: async ({ flags }) => {
const { deployHomepage } = await import("../publish/build");
- return refusalsExit(() => deployHomepage({ signal: interrupted() }));
+ return refusalsExit(() =>
+ deployHomepage({
+ signal: interrupted(),
+ previewBranch: typeof flags.preview === "string" ? flags.preview : undefined,
+ }),
+ );
},
},
{
diff --git a/common/publish/build.test.ts b/common/publish/build.test.ts
@@ -6,6 +6,8 @@ import {
buildHubSteps,
buildSiteSteps,
hubProjectProblem,
+ homepageDeployArgs,
+ deployHomepage,
dockerSiteOutDir,
dockerSiteStagingDir,
resolveOutDir,
@@ -126,3 +128,26 @@ test("hubProjectProblem refuses a missing project and the homepage's", () => {
assert.match(hubProjectProblem("archilyzer")!, /homepage's — set the hub's own project/);
assert.equal(hubProjectProblem("archilyzer-hub"), null);
});
+
+test("homepageDeployArgs: production is branch main; a preview is its own branch and never main", () => {
+ const base = ["wrangler", "pages", "deploy", "/repo/homepage/out", "--project-name", "archilyzer"];
+ assert.deepEqual(homepageDeployArgs("/repo/homepage/out"), [...base, "--branch", "main"]);
+ assert.deepEqual(homepageDeployArgs("/repo/homepage/out", " "), [...base, "--branch", "main"]);
+ assert.deepEqual(homepageDeployArgs("/repo/homepage/out", " r8-home "), [...base, "--branch", "r8-home"]);
+});
+
+test("deployHomepage refuses a bad preview branch before it looks for a build", async () => {
+ const noBuild = { monorepoRoot: "/nonexistent-repo" } as Paths;
+ await assert.rejects(
+ deployHomepage({ paths: noBuild, previewBranch: "main" }),
+ /"main" is the production branch/,
+ );
+ await assert.rejects(
+ deployHomepage({ paths: noBuild, previewBranch: "Not_Valid" }),
+ /not a valid preview branch name/,
+ );
+ await assert.rejects(
+ deployHomepage({ paths: noBuild, previewBranch: "r8-home" }),
+ /homepage\/out holds no build/,
+ );
+});
diff --git a/common/publish/build.ts b/common/publish/build.ts
@@ -974,21 +974,48 @@ export async function buildHomepage(opts: PublishOpts = {}): Promise<number> {
}
/**
- * Deploy homepage/out to the homepage's constant project, to its production
- * branch `main` — exactly what homepage/package.json's hardcoded `deploy` line
- * ran. THROWS on failure or when there is no build.
+ * The wrangler argv (after `pnpm dlx`) for a homepage deploy of `outDir`: the
+ * production branch `main` — what homepage/package.json's hardcoded `deploy`
+ * line ran — or, with `previewBranch`, that preview branch and no `main`.
+ * Pure, so the test pins exactly what deployHomepage runs.
*/
-export async function deployHomepage(opts: PublishOpts = {}): Promise<void> {
+export function homepageDeployArgs(outDir: string, previewBranch?: string): string[] {
+ const branch = previewBranch?.trim() || undefined;
+ return [
+ ...pagesDeployArgs({ outDir, project: HOMEPAGE_PAGES_PROJECT, previewBranch: branch }),
+ ...homepageProductionArgs(branch),
+ ];
+}
+
+function homepageProductionArgs(previewBranch: string | undefined): string[] {
+ return previewBranch ? [] : ["--branch", "main"];
+}
+
+/**
+ * Deploy homepage/out to the homepage's constant project: production (branch
+ * `main`), or a PREVIEW with `previewBranch` — the same refusals and alias line
+ * as deployHub. THROWS on failure or when there is no build.
+ */
+export async function deployHomepage(
+ opts: PublishOpts & { previewBranch?: string } = {},
+): Promise<void> {
const { paths, onLog, signal } = resolved(opts);
+ if (opts.previewBranch !== undefined) {
+ const problem = previewBranchProblem(opts.previewBranch);
+ if (problem) throw new Error(problem);
+ }
+ const branch = opts.previewBranch?.trim() || undefined;
const outDir = path.join(homepageDir(paths), "out");
if (!existsSync(path.join(outDir, "index.html"))) {
throw new Error("homepage/out holds no build — run archilyzer build homepage first");
}
+ if (branch) onLog(`=== Deploy homepage (preview "${branch}") ===\n`);
const code = await runPagesDeployIntoLog(onLog, signal, {
outDir,
project: HOMEPAGE_PAGES_PROJECT,
cwd: homepageDir(paths),
- extraArgs: ["--branch", "main"],
+ previewBranch: branch,
+ extraArgs: homepageProductionArgs(branch),
});
if (signal.aborted) return;
if (code !== 0) throw new Error(`Homepage deploy failed (exit ${code}).`);