Skip to content

Commit 6ffa8a8

Browse files
committed
Support a remote
1 parent 4bef3c1 commit 6ffa8a8

File tree

2 files changed

+63
-39
lines changed

2 files changed

+63
-39
lines changed

cmd/tag-release-tui/README.md

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,39 @@
22

33
A terminal user interface (TUI) for creating GitHub releases using Charmbracelet's Bubbletea library.
44

5+
## Building
6+
7+
```bash
8+
# Build the application into bin/ directory (ignored by git)
9+
go build -o bin/tag-release-tui ./cmd/tag-release-tui
10+
```
11+
512
## Usage
613

714
```bash
8-
# Build the application
9-
go build -o tag-release-tui ./cmd/tag-release-tui
15+
# Basic usage with default remote (origin)
16+
./bin/tag-release-tui v1.2.3
1017

11-
# Run with a version tag
12-
./tag-release-tui v1.2.3
18+
# Specify a different remote (e.g., your fork)
19+
./bin/tag-release-tui v1.2.3 --remote omgitsads
1320

1421
# Run in test mode (validation only, no actual changes)
15-
./tag-release-tui v1.2.3 --test
22+
./bin/tag-release-tui v1.2.3 --test
1623

17-
# Or use the convenience script
18-
./run-tag-release-tui.sh v1.2.3 --test
24+
# Test with a specific remote
25+
./bin/tag-release-tui v1.2.3 --remote omgitsads --test
1926
```
2027

2128
## Features
2229

2330
- **Interactive Validation**: Shows real-time validation of release requirements
2431
- **Test Mode**: Run with `--test` flag to validate without making any actual changes
32+
- **Remote Selection**: Specify git remote with `--remote` flag (default: origin)
2533
- **Flexible Branch Support**: Can be configured to work with any branch (currently set to `tag-release-charmbracelet`)
2634
- **Confirmation Screen**: Displays a summary and asks for confirmation before proceeding
2735
- **Live Execution**: Shows progress as the release is being created
2836
- **Post-Release Instructions**: Provides next steps after successful release creation
37+
- **Safe Testing**: Perfect for testing against your fork without affecting upstream
2938

3039
## Flow
3140

cmd/tag-release-tui/main.go

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const (
2727
type model struct {
2828
state state
2929
tag string
30+
remote string
3031
currentBranch string
3132
latestTag string
3233
errors []string
@@ -101,18 +102,19 @@ var (
101102
Padding(0, 2)
102103
)
103104

104-
func initialModel(tag string, testMode bool) model {
105+
func initialModel(tag, remote string, testMode bool) model {
105106
return model{
106107
state: stateValidating,
107108
tag: tag,
109+
remote: remote,
108110
testMode: testMode,
109111
}
110112
}
111113

112114
func (m model) Init() tea.Cmd {
113115
return tea.Batch(
114116
tea.EnterAltScreen,
115-
performValidation(m.tag, "tag-release-charmbracelet", m.testMode),
117+
performValidation(m.tag, "tag-release-charmbracelet", m.remote, m.testMode),
116118
)
117119
}
118120

@@ -131,7 +133,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
131133
if m.state == stateConfirming {
132134
m.confirmed = true
133135
m.state = stateExecuting
134-
return m, performExecution(m.tag, m.testMode)
136+
return m, performExecution(m.tag, m.remote, m.testMode)
135137
}
136138
case "n", "N":
137139
if m.state == stateConfirming {
@@ -238,6 +240,7 @@ func (m model) renderConfirming() string {
238240

239241
// Summary box
240242
summaryContent := fmt.Sprintf("Repository: %s\n", highlightStyle.Render(m.repoSlug))
243+
summaryContent += fmt.Sprintf("Remote: %s\n", highlightStyle.Render(m.remote))
241244
summaryContent += fmt.Sprintf("Current branch: %s\n", highlightStyle.Render(m.currentBranch))
242245
if m.latestTag != "" {
243246
summaryContent += fmt.Sprintf("Latest release: %s\n", highlightStyle.Render(m.latestTag))
@@ -255,9 +258,9 @@ func (m model) renderConfirming() string {
255258

256259
steps := []string{
257260
fmt.Sprintf("Create release tag: %s", m.tag),
258-
fmt.Sprintf("Push tag %s to origin", m.tag),
261+
fmt.Sprintf("Push tag %s to %s", m.tag, m.remote),
259262
"Update 'latest-release' tag",
260-
"Push 'latest-release' tag to origin",
263+
fmt.Sprintf("Push 'latest-release' tag to %s", m.remote),
261264
}
262265

263266
for _, step := range steps {
@@ -291,9 +294,9 @@ func (m model) renderExecuting() string {
291294

292295
steps := []string{
293296
fmt.Sprintf("Creating tag %s", m.tag),
294-
fmt.Sprintf("Pushing tag %s to origin", m.tag),
297+
fmt.Sprintf("Pushing tag %s to %s", m.tag, m.remote),
295298
"Updating 'latest-release' tag",
296-
"Pushing 'latest-release' tag to origin",
299+
fmt.Sprintf("Pushing 'latest-release' tag to %s", m.remote),
297300
}
298301

299302
for i, step := range steps {
@@ -364,7 +367,7 @@ func (m model) renderError() string {
364367
}
365368

366369
// Command functions
367-
func performValidation(tag, allowedBranch string, testMode bool) tea.Cmd {
370+
func performValidation(tag, allowedBranch, remote string, testMode bool) tea.Cmd {
368371
return tea.Cmd(func() tea.Msg {
369372
errors := []string{}
370373
data := make(map[string]string)
@@ -393,13 +396,13 @@ func performValidation(tag, allowedBranch string, testMode bool) tea.Cmd {
393396
}
394397
}
395398

396-
// 3. Fetch latest from origin
397-
cmd = exec.Command("git", "fetch", "origin", allowedBranch)
399+
// 3. Fetch latest from remote
400+
cmd = exec.Command("git", "fetch", remote, allowedBranch)
398401
if err := cmd.Run(); err != nil {
399402
if testMode {
400-
errors = append(errors, fmt.Sprintf("WARNING: Failed to fetch latest changes from origin/%s, but continuing in test mode", allowedBranch))
403+
errors = append(errors, fmt.Sprintf("WARNING: Failed to fetch latest changes from %s/%s, but continuing in test mode", remote, allowedBranch))
401404
} else {
402-
errors = append(errors, fmt.Sprintf("Failed to fetch latest changes from origin/%s", allowedBranch))
405+
errors = append(errors, fmt.Sprintf("Failed to fetch latest changes from %s/%s", remote, allowedBranch))
403406
}
404407
}
405408

@@ -424,9 +427,9 @@ func performValidation(tag, allowedBranch string, testMode bool) tea.Cmd {
424427

425428
if string(localSha) != string(remoteSha) {
426429
if testMode {
427-
errors = append(errors, fmt.Sprintf("WARNING: Local '%s' branch is not up-to-date with 'origin/%s', but continuing in test mode", allowedBranch, allowedBranch))
430+
errors = append(errors, fmt.Sprintf("WARNING: Local '%s' branch is not up-to-date with '%s/%s', but continuing in test mode", allowedBranch, remote, allowedBranch))
428431
} else {
429-
errors = append(errors, fmt.Sprintf("Your local '%s' branch is not up-to-date with 'origin/%s'. Please pull the latest changes", allowedBranch, allowedBranch))
432+
errors = append(errors, fmt.Sprintf("Your local '%s' branch is not up-to-date with '%s/%s'. Please pull the latest changes", allowedBranch, remote, allowedBranch))
430433
}
431434
}
432435

@@ -445,13 +448,13 @@ func performValidation(tag, allowedBranch string, testMode bool) tea.Cmd {
445448
}
446449
}
447450

448-
cmd = exec.Command("git", "ls-remote", "--tags", "origin")
451+
cmd = exec.Command("git", "ls-remote", "--tags", remote)
449452
output, err = cmd.Output()
450453
if err != nil {
451-
errors = append(errors, "Failed to check remote tags")
454+
errors = append(errors, fmt.Sprintf("Failed to check remote tags on %s", remote))
452455
} else {
453456
if strings.Contains(string(output), "refs/tags/"+tag) {
454-
errors = append(errors, fmt.Sprintf("Tag %s already exists on remote 'origin'", tag))
457+
errors = append(errors, fmt.Sprintf("Tag %s already exists on remote '%s'", tag, remote))
455458
}
456459
}
457460

@@ -466,7 +469,7 @@ func performValidation(tag, allowedBranch string, testMode bool) tea.Cmd {
466469
}
467470

468471
// Get repository slug
469-
cmd = exec.Command("git", "remote", "get-url", "origin")
472+
cmd = exec.Command("git", "remote", "get-url", remote)
470473
output, err = cmd.Output()
471474
if err == nil {
472475
repoUrl := strings.TrimSpace(string(output))
@@ -491,7 +494,7 @@ func performValidation(tag, allowedBranch string, testMode bool) tea.Cmd {
491494
})
492495
}
493496

494-
func performExecution(tag string, testMode bool) tea.Cmd {
497+
func performExecution(tag, remote string, testMode bool) tea.Cmd {
495498
return tea.Cmd(func() tea.Msg {
496499
errors := []string{}
497500

@@ -508,9 +511,9 @@ func performExecution(tag string, testMode bool) tea.Cmd {
508511
}
509512

510513
// Step 1: Push the tag
511-
cmd = exec.Command("git", "push", "origin", tag)
514+
cmd = exec.Command("git", "push", remote, tag)
512515
if err := cmd.Run(); err != nil {
513-
errors = append(errors, fmt.Sprintf("Failed to push tag %s: %v", tag, err))
516+
errors = append(errors, fmt.Sprintf("Failed to push tag %s to %s: %v", tag, remote, err))
514517
return executionCompleteMsg{success: false, errors: errors}
515518
}
516519

@@ -522,9 +525,9 @@ func performExecution(tag string, testMode bool) tea.Cmd {
522525
}
523526

524527
// Step 3: Push latest-release tag
525-
cmd = exec.Command("git", "push", "origin", "latest-release", "--force")
528+
cmd = exec.Command("git", "push", remote, "latest-release", "--force")
526529
if err := cmd.Run(); err != nil {
527-
errors = append(errors, fmt.Sprintf("Failed to push latest-release tag: %v", err))
530+
errors = append(errors, fmt.Sprintf("Failed to push latest-release tag to %s: %v", remote, err))
528531
return executionCompleteMsg{success: false, errors: errors}
529532
}
530533

@@ -535,28 +538,40 @@ func performExecution(tag string, testMode bool) tea.Cmd {
535538
func main() {
536539
if len(os.Args) < 2 {
537540
fmt.Println("Error: No tag specified.")
538-
fmt.Println("Usage: tag-release-tui vX.Y.Z [--test]")
541+
fmt.Println("Usage: tag-release-tui vX.Y.Z [--remote <remote-name>] [--test]")
542+
fmt.Println(" --remote: Specify git remote name (default: origin)")
539543
fmt.Println(" --test: Run in test mode (validation only, no actual changes)")
540544
os.Exit(1)
541545
}
542546

543547
tag := os.Args[1]
544548
testMode := false
545-
546-
// Check for test flag
549+
remote := "origin" // default remote
550+
551+
// Parse flags
547552
for i := 2; i < len(os.Args); i++ {
548-
if os.Args[i] == "--test" || os.Args[i] == "-t" {
553+
switch os.Args[i] {
554+
case "--test", "-t":
549555
testMode = true
550-
break
556+
case "--remote", "-r":
557+
if i+1 < len(os.Args) {
558+
remote = os.Args[i+1]
559+
i++ // skip next arg
560+
} else {
561+
fmt.Println("Error: --remote flag requires a value")
562+
os.Exit(1)
563+
}
551564
}
552565
}
553-
566+
554567
if testMode {
555-
fmt.Println("🧪 Running in TEST MODE - no actual changes will be made")
568+
fmt.Printf("🧪 Running in TEST MODE - no actual changes will be made (remote: %s)\n", remote)
569+
} else {
570+
fmt.Printf("🚀 Running release process (remote: %s)\n", remote)
556571
}
557-
572+
558573
p := tea.NewProgram(
559-
initialModel(tag, testMode),
574+
initialModel(tag, remote, testMode),
560575
tea.WithAltScreen(),
561576
tea.WithMouseCellMotion(),
562577
)

0 commit comments

Comments
 (0)