()
| 19 | ) |
| 20 | |
| 21 | func main() { |
| 22 | var dryRun bool |
| 23 | cmd := &serpent.Command{ |
| 24 | Use: "releaser", |
| 25 | Short: "Interactive release tagging for coder/coder.", |
| 26 | Long: "Tag RCs from main, releases/patches from release/X.Y. The tool detects the branch, infers the next version, and walks you through tagging, pushing, and triggering the release workflow.", |
| 27 | Options: serpent.OptionSet{ |
| 28 | { |
| 29 | Name: "dry-run", |
| 30 | Flag: "dry-run", |
| 31 | Description: "Print write commands instead of executing them.", |
| 32 | Value: serpent.BoolOf(&dryRun), |
| 33 | }, |
| 34 | }, |
| 35 | Handler: func(inv *serpent.Invocation) error { |
| 36 | ctx := inv.Context() |
| 37 | w := inv.Stderr |
| 38 | |
| 39 | // --- Check dependencies --- |
| 40 | if _, err := exec.LookPath("git"); err != nil { |
| 41 | return xerrors.New("git is required but not found in PATH") |
| 42 | } |
| 43 | |
| 44 | // --- Check GPG signing --- |
| 45 | signingKey, _ := gitOutput("config", "--get", "user.signingkey") |
| 46 | gpgFormat, _ := gitOutput("config", "--get", "gpg.format") |
| 47 | gpgConfigured := signingKey != "" || gpgFormat != "" |
| 48 | if !gpgConfigured { |
| 49 | warnf(w, "GPG signing is not configured. Tags will be unsigned — there will be no way to verify who pushed the tag.") |
| 50 | _, _ = fmt.Fprintf(w, " To fix: set git config user.signingkey or gpg.format\n") |
| 51 | if err := confirmWithDefault(inv, "Continue without signing?", cliui.ConfirmNo); err != nil { |
| 52 | return err |
| 53 | } |
| 54 | _, _ = fmt.Fprintln(w) |
| 55 | } |
| 56 | |
| 57 | // --- Check gh CLI auth --- |
| 58 | ghAvailable := checkGHAuth() |
| 59 | if !ghAvailable { |
| 60 | warnf(w, "gh CLI is not available or not authenticated.") |
| 61 | infof(w, "Continuing without GitHub features (PR checks, label lookups, workflow trigger).") |
| 62 | _, _ = fmt.Fprintln(w) |
| 63 | } |
| 64 | |
| 65 | // --- Wire up executor --- |
| 66 | var executor ReleaseExecutor |
| 67 | if dryRun { |
| 68 | outputPrefix = "[DRYRUN] " |
| 69 | executor = &dryRunExecutor{w: w} |
| 70 | } else { |
| 71 | executor = &liveExecutor{} |
| 72 | } |
| 73 | |
| 74 | return runRelease(ctx, inv, executor, ghAvailable, gpgConfigured, dryRun) |
| 75 | }, |
| 76 | } |
| 77 | |
| 78 | err := cmd.Invoke().WithOS().Run() |
nothing calls this directly
no test coverage detected