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
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ Rules carried from the #1828 ruling:
what makes rollback a first-class operation instead of a redeploy:
`deploy.mjs --deploy-version <id>` creates a deployment at any
retained version, forward or back.
- **Bootstrap exception.** `cf workers versions create` cannot create
a brand-new Worker (found by the pilot's first deploy run; recorded
on #1829). A Worker's first-ever deploy therefore goes through
`cf deploy` with the same tag/message, which creates version 1 and
its deployment together; the versions flow governs everything
after.
- **State handling is deferrable.** No terraform/terranix in the pilot;
the Worker's own config (`cloudflare.config.ts`, mirrored by
`wrangler.jsonc` for dev/tests) is the resource declaration.
Expand Down
7 changes: 7 additions & 0 deletions pkgs/pkarr-worker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ The deploy itself uses the **cf versions flow**:
`?deployable=true` set.
3. `cf workers deployments create` puts that version at 100%.

First deploy only: `cf workers versions create` cannot create a
brand-new Worker (it refuses and points at the deploy command), so
when the Worker does not exist yet the script bootstraps with
`cf deploy` — same tag and message — which creates the first version
and its deployment together. Every later deploy uses the versions
flow above.

### Rollback

Versions and deployments are separate objects; rollback is a new
Expand Down
69 changes: 55 additions & 14 deletions pkgs/pkarr-worker/deploy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
// machinery run at an older version id: --deploy-version <id> creates a
// deployment at an existing version without uploading anything.
//
// One cf gap: versions create cannot create a brand-new Worker, so the
// first-ever deploy bootstraps through `cf deploy` (same tag/message);
// see the bootstrap note at the deploy step below.
//
// Usage:
// deploy.mjs [--dry-run] upload + deploy HEAD
// deploy.mjs --deploy-version <id> deploy (or roll back to) an
Expand Down Expand Up @@ -70,19 +74,38 @@ if (deployVersion !== null) {

const sha = execFileSync("git", ["rev-parse", "HEAD"], { encoding: "utf8" }).trim();
const tag = `git-${sha.slice(0, 12)}`;

const createArgs = [
"workers", "versions", "create",
"--worker", WORKER,
"--tag", tag,
"--message", `deploy ${sha} via nix run .#pkarr-deploy`,
];
if (dryRun) createArgs.push("--dry-run");
console.log(`uploading version (tag ${tag})`);
runCf(createArgs, { stdio: "inherit" });
if (dryRun) {
console.log("dry run: config builds, nothing uploaded");
process.exit(0);
const message = `deploy ${sha} via nix run .#pkarr-deploy`;

// cf gap (recorded on #1829): `cf workers versions create` cannot
// create a brand-new Worker — it refuses and tells you to run the
// deploy command first. So the very first deploy bootstraps with
// `cf deploy`, which creates the Worker's first version (with the
// same tag/message) and its first deployment in one step. Every
// later deploy uses the versions flow below.
const bootstrapping = !workerExists();
if (bootstrapping) {
const deployArgs = ["deploy", "--worker", WORKER, "--tag", tag, "--message", message];
if (dryRun) deployArgs.push("--dry-run");
console.log(`worker ${WORKER} does not exist yet; bootstrapping with cf deploy (tag ${tag})`);
runCf(deployArgs, { stdio: "inherit" });
if (dryRun) {
console.log("dry run: config builds, nothing uploaded");
process.exit(0);
}
} else {
const createArgs = [
"workers", "versions", "create",
"--worker", WORKER,
"--tag", tag,
"--message", message,
];
if (dryRun) createArgs.push("--dry-run");
console.log(`uploading version (tag ${tag})`);
runCf(createArgs, { stdio: "inherit" });
if (dryRun) {
console.log("dry run: config builds, nothing uploaded");
process.exit(0);
}
}

// Re-deploying an unchanged tree uploads a second version under the
Expand All @@ -96,10 +119,28 @@ if (!version) {
console.log(`uploaded version ${version.id}`);

await assertDeployable(version.id);
createDeployment(version.id);
if (bootstrapping) {
console.log(`bootstrap deployment already live at version ${version.id}`);
} else {
createDeployment(version.id);
}
reportLive();
console.log(`live: ${WORKER_URL} at version ${version.id} (${tag})`);

function workerExists() {
try {
execFileSync("cf", ["-q", "workers", "get", WORKER], {
cwd: here,
env,
encoding: "utf8",
stdio: ["inherit", "pipe", "pipe"],
});
return true;
} catch {
return false;
}
}

function createDeployment(versionId) {
const versions = JSON.stringify([{ version_id: versionId, percentage: 100 }]);
console.log(`creating deployment at version ${versionId} (100%)`);
Expand Down