mirror of
https://github.com/hanzoai/pack.git
synced 2026-11-02 13:32:48 +00:00
RailpackBuilderImage and RailpackRuntimeImage named
ghcr.io/railwayapp/railpack-{builder,runtime}, so every `pack build`
pulled the upstream vendor's images instead of our own. Point them at
ghcr.io/hanzoai/pack-{builder,runtime}, published by the release
pipeline as of the prior commit.
Also updates the local-dev mirrors of the same reference: the
mise-builder-shell task, the run-with-frontend script, the mise clean
task's image cleanup list, and a stale comment in buildkit/frontend.go.
Snapshots refreshed with the project's own task
(UPDATE_SNAPS=true go test -short ./...) and inspected line by line:
every changed line is exactly the builder/runtime image string, nothing
else. The pre-existing, unrelated php-vanilla frankenphp version drift
that the same refresh also touches was left untouched here.
Do not merge until a release tag has gone through the pipeline from the
prior commit and ghcr.io/hanzoai/pack-builder and pack-runtime actually
exist -- until then this is a correct diff sitting ahead of its own
prerequisite, not something to land on main.
Co-authored-by: Hanzo Dev <[email protected]>
139 lines
3.8 KiB
TypeScript
Executable File
139 lines
3.8 KiB
TypeScript
Executable File
#!/usr/bin/env bun
|
|
|
|
/**
|
|
* Development script to test building with the Railpack BuildKit frontend.
|
|
*
|
|
* This script validates the production BuildKit frontend flow by:
|
|
* 1. Generating a build plan using `railpack plan`
|
|
* 2. Invoking BuildKit with the frontend container image (ghcr.io/hanzoai/pack-frontend:latest)
|
|
* 3. Loading the resulting image into Docker
|
|
*
|
|
* This is useful for testing the frontend integration locally before publishing,
|
|
* as the frontend path is what production platforms use. The `railpack build` command
|
|
* uses a different approach (direct BuildKit client) for simplicity.
|
|
*
|
|
* Example:
|
|
* bun scripts/run-with-frontend.ts examples/node-vite-react
|
|
* bun scripts/run-with-frontend.ts examples/node-vite-react --env NODE_ENV=production
|
|
*/
|
|
|
|
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
import crypto from "node:crypto";
|
|
|
|
const PLAN_FILE = "railpack-plan.json";
|
|
const PRODUCTION_FRONTEND_IMAGE_NAME = "ghcr.io/hanzoai/pack-frontend:latest";
|
|
|
|
// Parse command line arguments
|
|
const args = process.argv.slice(2);
|
|
if (args.length === 0) {
|
|
console.error("Please provide a directory path");
|
|
process.exit(1);
|
|
}
|
|
|
|
const dir = args[0];
|
|
const envArgs = args.slice(1).filter((arg) => arg.startsWith("--env"));
|
|
|
|
// Create temp directory to save the build plan to
|
|
const randId = Math.random().toString(36).slice(2);
|
|
const tmpDir = join("/tmp", "railpack-" + randId);
|
|
const planDir = join(tmpDir, "plan");
|
|
mkdirSync(planDir, { recursive: true });
|
|
|
|
const cleanup = () => {
|
|
if (existsSync(tmpDir)) {
|
|
rmSync(tmpDir, { recursive: true, force: true });
|
|
}
|
|
};
|
|
|
|
process.on("exit", cleanup);
|
|
process.on("SIGINT", () => {
|
|
cleanup();
|
|
process.exit();
|
|
});
|
|
|
|
// Generate build plan
|
|
console.log(`Generating build plan for ${dir}`);
|
|
const planResult = spawnSync(
|
|
"go",
|
|
["run", "cmd/cli/main.go", "plan", dir, ...envArgs],
|
|
{
|
|
stdio: ["inherit", "pipe", "inherit"],
|
|
}
|
|
);
|
|
|
|
if (planResult.status !== 0) {
|
|
console.error("Failed to generate build plan");
|
|
process.exit(1);
|
|
}
|
|
|
|
const planPath = join(planDir, PLAN_FILE);
|
|
writeFileSync(planPath, planResult.stdout);
|
|
|
|
// Parse all env vars so that we can use them as secrets
|
|
const envVars: Record<string, string> = {};
|
|
const secretArgs: string[] = [];
|
|
|
|
// Find all env args and their values
|
|
for (let i = 0; i < args.length; i++) {
|
|
if (args[i] === "--env" && i + 1 < args.length) {
|
|
const nameValue = args[i + 1];
|
|
const [name, value] = nameValue.split("=");
|
|
if (name && value) {
|
|
envVars[name] = value;
|
|
secretArgs.push(`--secret=id=${name},env=${name}`);
|
|
}
|
|
i++; // Skip the next argument since we've processed it
|
|
}
|
|
}
|
|
|
|
// Pipe buildctl and docker load together
|
|
const buildctlArgs = [
|
|
"build",
|
|
`--local`,
|
|
`context=${dir}`,
|
|
`--local`,
|
|
`dockerfile=${planDir}`,
|
|
"--frontend=gateway.v0",
|
|
"--opt",
|
|
`source=${PRODUCTION_FRONTEND_IMAGE_NAME}`,
|
|
"--output",
|
|
"type=docker,name=test",
|
|
...secretArgs,
|
|
];
|
|
|
|
// Options that are passed to our custom frontend
|
|
const cacheKey = dir;
|
|
buildctlArgs.push("--opt", `cache-key=${cacheKey}`);
|
|
|
|
if (Object.keys(envVars).length > 0) {
|
|
const secretsHash = crypto
|
|
.createHash("sha256")
|
|
.update(Object.values(envVars).sort().join(""))
|
|
.digest("hex");
|
|
buildctlArgs.push("--opt", `secrets-hash=${secretsHash}`);
|
|
}
|
|
|
|
console.log(`Executing buildctl\n ${buildctlArgs.join(" ")}`);
|
|
|
|
const buildctl = spawnSync("buildctl", buildctlArgs, {
|
|
stdio: ["inherit", "pipe", "inherit"],
|
|
env: { ...process.env, ...envVars },
|
|
});
|
|
|
|
if (buildctl.status !== 0) {
|
|
console.error("buildctl command failed");
|
|
process.exit(1);
|
|
}
|
|
|
|
const dockerLoad = spawnSync("docker", ["load"], {
|
|
input: buildctl.stdout,
|
|
stdio: ["pipe", "inherit", "inherit"],
|
|
});
|
|
|
|
if (dockerLoad.status !== 0) {
|
|
console.error("docker load failed");
|
|
process.exit(1);
|
|
}
|