| 34 | /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/; |
| 35 | |
| 36 | const parseArgs = (argv: ReadonlyArray<string>): ReleaseCliOptions => { |
| 37 | let mode: ReleaseMode = "full"; |
| 38 | let skipBuild = false; |
| 39 | |
| 40 | for (const arg of argv) { |
| 41 | if (arg === "--skip-build") { |
| 42 | skipBuild = true; |
| 43 | continue; |
| 44 | } |
| 45 | |
| 46 | const next: ReleaseMode | null = |
| 47 | arg === "--dry-run" |
| 48 | ? "dry-run" |
| 49 | : arg === "--stage-only" |
| 50 | ? "stage-only" |
| 51 | : arg === "--publish-only" |
| 52 | ? "publish-only" |
| 53 | : null; |
| 54 | if (next === null) { |
| 55 | throw new Error(`Unknown argument: ${arg}`); |
| 56 | } |
| 57 | if (mode !== "full") { |
| 58 | throw new Error(`--${next} conflicts with --${mode}; pass at most one mode flag`); |
| 59 | } |
| 60 | mode = next; |
| 61 | } |
| 62 | |
| 63 | if (mode === "publish-only" && skipBuild) { |
| 64 | throw new Error("--skip-build is implied by --publish-only; drop it"); |
| 65 | } |
| 66 | if (mode === "dry-run" && skipBuild) { |
| 67 | throw new Error("--skip-build with --dry-run would validate artifacts and do nothing else"); |
| 68 | } |
| 69 | |
| 70 | return { mode, skipBuild }; |
| 71 | }; |
| 72 | |
| 73 | const runCommand = async (input: CommandInput): Promise<CommandOutput> => { |
| 74 | const proc = Bun.spawn([input.command, ...input.args], { |