| 725 | |
| 726 | // fallow-ignore-next-line complexity |
| 727 | function runDestroy(args: Record<string, unknown>): void { |
| 728 | const tfDir = terraformDir(); |
| 729 | const state = existsSync(statePath()) |
| 730 | ? (JSON.parse(readFileSync(statePath(), "utf8")) as Partial<StackState>) |
| 731 | : {}; |
| 732 | const project = (args.project as string | undefined) ?? state.projectId; |
| 733 | const region = (args.region as string | undefined) ?? state.region ?? "us-central1"; |
| 734 | const image = (args.image as string | undefined) ?? "unused:latest"; |
| 735 | if (!project) { |
| 736 | console.error("[cloudrun destroy] --project is required (or deploy first to cache it)."); |
| 737 | process.exit(1); |
| 738 | } |
| 739 | const vars = [ |
| 740 | "-var", |
| 741 | `project_id=${project}`, |
| 742 | "-var", |
| 743 | `region=${region}`, |
| 744 | "-var", |
| 745 | `image=${image}`, |
| 746 | "-var", |
| 747 | "bucket_force_destroy=true", |
| 748 | ]; |
| 749 | console.log("→ terraform destroy"); |
| 750 | run("terraform", ["init", "-input=false"], { cwd: tfDir }); |
| 751 | // Apply `bucket_force_destroy=true` into state FIRST. Terraform reads a |
| 752 | // bucket's force_destroy from prior state when emptying it during destroy, |
| 753 | // so passing the var only at destroy time can't flip it — a destroy of a |
| 754 | // bucket that still holds render artifacts would fail with "bucket not |
| 755 | // empty". The quick apply updates the attribute, then destroy can sweep |
| 756 | // the (scratch) bucket. Best-effort: if there's nothing to apply this |
| 757 | // no-ops. |
| 758 | try { |
| 759 | run("terraform", ["apply", "-input=false", "-auto-approve", ...vars], { cwd: tfDir }); |
| 760 | } catch { |
| 761 | // A failed pre-apply shouldn't block the destroy attempt below. |
| 762 | } |
| 763 | run("terraform", ["destroy", "-input=false", "-auto-approve", ...vars], { cwd: tfDir }); |
| 764 | console.log(`${c.accent("✓ destroyed.")}`); |
| 765 | } |
| 766 | |
| 767 | // ── config + variables helpers (shared by render + render-batch) ──────────── |
| 768 | |