Skip to content

Commit 4f0ed87

Browse files
committed
improve cli args
1 parent b1317ab commit 4f0ed87

File tree

1 file changed

+97
-23
lines changed

1 file changed

+97
-23
lines changed

internal/cmd/root.go

Lines changed: 97 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,18 @@ var (
2020
branchPrefix string
2121
branchSuffix string
2222
branchRegex string
23-
labels []string
23+
selectLabel string
24+
selectLabels []string
25+
addLabels []string
2426
assignees []string
25-
mustBeGreen bool
27+
requireCI bool
2628
mustBeApproved bool
2729
autoclose bool
2830
updateBranch bool
2931
ignoreLabel string
30-
selectLabel string
32+
ignoreLabels []string
3133
reposFile string
32-
minCombine int
34+
minimum int
3335
)
3436

3537
// NewRootCmd creates the root command for the gh-combine CLI
@@ -38,31 +40,74 @@ func NewRootCmd() *cobra.Command {
3840
Use: "combine [repo1,repo2,...]",
3941
Short: "Combine multiple pull requests into a single PR",
4042
Long: `Combine multiple pull requests that match specific criteria into a single PR.
41-
Examples:
42-
gh combine octocat/hello-world
43-
gh combine octocat/repo1,octocat/repo2
44-
gh combine --file repos.txt
45-
gh combine octocat/hello-world --branch-prefix dependabot-
46-
gh combine octocat/hello-world --branch-regex "dependabot/.*"
47-
gh combine octocat/hello-world --labels security,dependencies
48-
gh combine octocat/hello-world --select-label dependencies`,
43+
Examples:
44+
# Basic usage with a single repository
45+
gh combine octocat/hello-world
46+
47+
# Multiple repositories (comma-separated)
48+
gh combine octocat/repo1,octocat/repo2
49+
50+
# Using a file with repository names (one per line)
51+
gh combine --file repos.txt
52+
53+
# Filter PRs by branch name
54+
gh combine octocat/hello-world --branch-prefix dependabot-
55+
gh combine octocat/hello-world --branch-suffix -update
56+
gh combine octocat/hello-world --branch-regex "dependabot/.*"
57+
58+
# Filter PRs by labels
59+
gh combine octocat/hello-world --label dependencies # PRs must have this single label
60+
gh combine octocat/hello-world --labels security,dependencies # PRs must have ALL these labels
61+
62+
# Exclude PRs by labels
63+
gh combine octocat/hello-world --ignore-label wip # Ignore PRs with this label
64+
gh combine octocat/hello-world --ignore-labels wip,draft # Ignore PRs with ANY of these labels
65+
66+
# Set requirements for PRs to be combined
67+
gh combine octocat/hello-world --require-ci # Only include PRs with passing CI
68+
gh combine octocat/hello-world --require-approved # Only include approved PRs
69+
gh combine octocat/hello-world --minimum 3 # Need at least 3 matching PRs
70+
71+
# Add metadata to combined PR
72+
gh combine octocat/hello-world --add-labels security,dependencies # Add these labels to the new PR
73+
gh combine octocat/hello-world --assignees octocat,hubot # Assign users to the new PR
74+
75+
# Additional options
76+
gh combine octocat/hello-world --autoclose # Close source PRs when combined PR is merged
77+
gh combine octocat/hello-world --update-branch # Update the branch of the combined PR`,
4978
RunE: runCombine,
5079
}
5180

5281
// Add flags
5382
rootCmd.Flags().StringVar(&branchPrefix, "branch-prefix", "", "Branch prefix to filter PRs")
5483
rootCmd.Flags().StringVar(&branchSuffix, "branch-suffix", "", "Branch suffix to filter PRs")
5584
rootCmd.Flags().StringVar(&branchRegex, "branch-regex", "", "Regex pattern to filter PRs by branch name")
56-
rootCmd.Flags().StringSliceVar(&labels, "labels", nil, "Comma-separated list of labels to add to the combined PR")
85+
86+
// Label selection flags - singular and plural forms
87+
rootCmd.Flags().StringVar(&selectLabel, "label", "", "Only include PRs with this specific label")
88+
rootCmd.Flags().StringSliceVar(&selectLabels, "labels", nil, "Only include PRs with ALL these labels (comma-separated)")
89+
90+
// Label ignoring flags - singular and plural forms
91+
rootCmd.Flags().StringVar(&ignoreLabel, "ignore-label", "", "Ignore PRs with this specific label")
92+
rootCmd.Flags().StringSliceVar(&ignoreLabels, "ignore-labels", nil, "Ignore PRs with ANY of these labels (comma-separated)")
93+
94+
// Labels to add to the combined PR
95+
rootCmd.Flags().StringSliceVar(&addLabels, "add-labels", nil, "Comma-separated list of labels to add to the combined PR")
96+
97+
// Other flags
5798
rootCmd.Flags().StringSliceVar(&assignees, "assignees", nil, "Comma-separated list of users to assign to the combined PR")
58-
rootCmd.Flags().BoolVar(&mustBeGreen, "require-green", false, "Only include PRs with passing CI checks")
99+
rootCmd.Flags().BoolVar(&requireCI, "require-ci", false, "Only include PRs with passing CI checks")
59100
rootCmd.Flags().BoolVar(&mustBeApproved, "require-approved", false, "Only include PRs that have been approved")
60101
rootCmd.Flags().BoolVar(&autoclose, "autoclose", false, "Close source PRs when combined PR is merged")
61102
rootCmd.Flags().BoolVar(&updateBranch, "update-branch", false, "Update the branch of the combined PR if possible")
62-
rootCmd.Flags().StringVar(&ignoreLabel, "ignore-label", "", "Ignore PRs with this label")
63-
rootCmd.Flags().StringVar(&selectLabel, "select-label", "", "Only include PRs with this label")
64103
rootCmd.Flags().StringVar(&reposFile, "file", "", "File containing repository names, one per line")
65-
rootCmd.Flags().IntVar(&minCombine, "min-combine", 2, "Minimum number of PRs to combine")
104+
rootCmd.Flags().IntVar(&minimum, "minimum", 2, "Minimum number of PRs to combine")
105+
106+
// Add deprecated flags for backward compatibility
107+
// rootCmd.Flags().IntVar(&minimum, "min-combine", 2, "Minimum number of PRs to combine (deprecated, use --minimum)")
108+
109+
// Mark deprecated flags
110+
// rootCmd.Flags().MarkDeprecated("min-combine", "use --minimum instead")
66111

67112
return rootCmd
68113
}
@@ -139,7 +184,8 @@ func validateInputs(args []string) error {
139184

140185
// Warn if no filtering options are provided at all
141186
if branchPrefix == "" && branchSuffix == "" && branchRegex == "" &&
142-
ignoreLabel == "" && selectLabel == "" && !mustBeGreen && !mustBeApproved {
187+
ignoreLabel == "" && selectLabel == "" && len(selectLabels) == 0 &&
188+
!requireCI && !mustBeApproved {
143189
Logger.Warn("No filtering options specified. This will attempt to combine ALL open pull requests.")
144190
}
145191

@@ -264,8 +310,8 @@ func executeCombineCommand(ctx context.Context, spinner *Spinner, repos []string
264310
}
265311

266312
// Check if we have enough PRs to combine
267-
if len(matchedPRs) < minCombine {
268-
Logger.Debug("Not enough PRs match criteria", "repo", repo, "matched", len(matchedPRs), "required", minCombine)
313+
if len(matchedPRs) < minimum {
314+
Logger.Debug("Not enough PRs match criteria", "repo", repo, "matched", len(matchedPRs), "required", minimum)
269315
continue
270316
}
271317

@@ -332,11 +378,12 @@ func branchMatchesCriteria(branch string) bool {
332378
// labelsMatchCriteria checks if PR labels match the label filtering criteria
333379
func labelsMatchCriteria(prLabels []struct{ Name string }) bool {
334380
// If no label filters are specified, all PRs pass this check
335-
if ignoreLabel == "" && selectLabel == "" {
381+
if ignoreLabel == "" && len(ignoreLabels) == 0 &&
382+
selectLabel == "" && len(selectLabels) == 0 {
336383
return true
337384
}
338385

339-
// Check for ignore label
386+
// Check for ignore label (singular)
340387
if ignoreLabel != "" {
341388
for _, label := range prLabels {
342389
if label.Name == ignoreLabel {
@@ -345,7 +392,18 @@ func labelsMatchCriteria(prLabels []struct{ Name string }) bool {
345392
}
346393
}
347394

348-
// Check for select label
395+
// Check for ignore labels (plural)
396+
if len(ignoreLabels) > 0 {
397+
for _, ignoreL := range ignoreLabels {
398+
for _, prLabel := range prLabels {
399+
if prLabel.Name == ignoreL {
400+
return false
401+
}
402+
}
403+
}
404+
}
405+
406+
// Check for select label (singular)
349407
if selectLabel != "" {
350408
found := false
351409
for _, label := range prLabels {
@@ -359,5 +417,21 @@ func labelsMatchCriteria(prLabels []struct{ Name string }) bool {
359417
}
360418
}
361419

420+
// Check for select labels (plural)
421+
if len(selectLabels) > 0 {
422+
for _, requiredLabel := range selectLabels {
423+
found := false
424+
for _, prLabel := range prLabels {
425+
if prLabel.Name == requiredLabel {
426+
found = true
427+
break
428+
}
429+
}
430+
if !found {
431+
return false
432+
}
433+
}
434+
}
435+
362436
return true
363437
}

0 commit comments

Comments
 (0)