feat(pulls): add --confirm flag for non-interactive safety

Add --confirm/-y flag to tea pulls merge and close commands to skip
interactive confirmation prompts. This enables safe use in CI/CD
pipelines and scripts where interactive prompts would hang.

When --confirm is not set, the user is prompted with a y/N confirmation
before the operation proceeds. With --confirm, the operation executes
immediately without prompting.
This commit is contained in:
Ross Golder 2026-07-30 08:59:30 +07:00
parent d50c9f75dc
commit 913c22263a
No known key found for this signature in database
GPG key ID: 253A7E508D2D59CD
4 changed files with 145 additions and 1 deletions

View file

@ -5,10 +5,13 @@ package pulls
import (
"context"
"fmt"
"gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
teacontext "gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3"
)
@ -19,8 +22,31 @@ var CmdPullsClose = cli.Command{
Description: `Change state of one or more pull requests to 'closed'`,
ArgsUsage: "<pull index> [<pull index>...]",
Action: func(ctx context.Context, cmd *cli.Command) error {
if !cmd.Bool("confirm") {
teaCtx, err := teacontext.InitCommand(cmd)
if err != nil {
return err
}
indices, err := utils.ArgsToIndices(teaCtx.Args().Slice())
if err != nil {
return err
}
fmt.Printf("Are you sure you want to close PR(s) %v? [y/N] ", indices)
var response string
fmt.Scanln(&response)
if response != "y" && response != "Y" && response != "yes" {
fmt.Println("Close canceled.")
return nil
}
}
s := gitea.StateClosed
return editPullState(ctx, cmd, gitea.EditPullRequestOption{State: &s})
},
Flags: flags.AllDefaultFlags,
Flags: append([]cli.Flag{
&cli.BoolFlag{
Name: "confirm",
Aliases: []string{"y"},
Usage: "confirm close without prompting",
},
}, flags.AllDefaultFlags...),
}

49
cmd/pulls/close_test.go Normal file
View file

@ -0,0 +1,49 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package pulls
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3"
)
func TestCloseCommandMetadata(t *testing.T) {
cmd := &CmdPullsClose
assert.Equal(t, "close", cmd.Name)
assert.Equal(t, "Change state of one or more pull requests to 'closed'", cmd.Usage)
assert.Equal(t, `Change state of one or more pull requests to 'closed'`, cmd.Description)
assert.Equal(t, "<pull index> [<pull index>...]", cmd.ArgsUsage)
assert.NotNil(t, cmd.Action)
}
func TestCloseCommandFlags(t *testing.T) {
cmd := &CmdPullsClose
expectedFlags := []string{
"confirm",
}
for _, flagName := range expectedFlags {
found := false
for _, flag := range cmd.Flags {
if flag.Names()[0] == flagName {
found = true
break
}
}
assert.True(t, found, "Expected flag %s not found", flagName)
}
for _, flag := range cmd.Flags {
if flag.Names()[0] == "confirm" {
if boolFlag, ok := flag.(*cli.BoolFlag); ok {
assert.Contains(t, boolFlag.Aliases, "y")
assert.Equal(t, "confirm close without prompting", boolFlag.Usage)
}
}
}
}

View file

@ -5,6 +5,7 @@ package pulls
import (
stdctx "context"
"fmt"
gitea "gitea.dev/sdk"
"github.com/urfave/cli/v3"
@ -24,6 +25,11 @@ var CmdPullsMerge = cli.Command{
Description: "Merge a pull request",
ArgsUsage: "<pull index>",
Flags: append([]cli.Flag{
&cli.BoolFlag{
Name: "confirm",
Aliases: []string{"y"},
Usage: "confirm merge without prompting",
},
&cli.StringFlag{
Name: "style",
Aliases: []string{"s"},
@ -63,6 +69,16 @@ var CmdPullsMerge = cli.Command{
return err
}
if !ctx.Bool("confirm") {
fmt.Printf("Are you sure you want to merge PR #%d? [y/N] ", idx)
var response string
fmt.Scanln(&response)
if response != "y" && response != "Y" && response != "yes" {
fmt.Println("Merge canceled.")
return nil
}
}
return task.PullMerge(requestCtx, ctx.Login, ctx.Owner, ctx.Repo, idx, gitea.MergePullRequestOption{
Style: gitea.MergeStyle(ctx.String("style")),
Title: ctx.String("title"),

53
cmd/pulls/merge_test.go Normal file
View file

@ -0,0 +1,53 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package pulls
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3"
)
func TestMergeCommandMetadata(t *testing.T) {
cmd := &CmdPullsMerge
assert.Equal(t, "merge", cmd.Name)
assert.Contains(t, cmd.Aliases, "m")
assert.Equal(t, "Merge a pull request", cmd.Usage)
assert.Equal(t, "Merge a pull request", cmd.Description)
assert.Equal(t, "<pull index>", cmd.ArgsUsage)
assert.NotNil(t, cmd.Action)
}
func TestMergeCommandFlags(t *testing.T) {
cmd := &CmdPullsMerge
expectedFlags := []string{
"confirm",
"style",
"title",
"message",
}
for _, flagName := range expectedFlags {
found := false
for _, flag := range cmd.Flags {
if flag.Names()[0] == flagName {
found = true
break
}
}
assert.True(t, found, "Expected flag %s not found", flagName)
}
for _, flag := range cmd.Flags {
if flag.Names()[0] == "confirm" {
if boolFlag, ok := flag.(*cli.BoolFlag); ok {
assert.Contains(t, boolFlag.Aliases, "y")
assert.Equal(t, "confirm merge without prompting", boolFlag.Usage)
}
}
}
}