132 lines
3.4 KiB
Go
132 lines
3.4 KiB
Go
package revert
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/cli/cli/v2/api"
|
|
"github.com/cli/cli/v2/internal/ghrepo"
|
|
"github.com/cli/cli/v2/pkg/cmd/pr/shared"
|
|
"github.com/cli/cli/v2/pkg/cmdutil"
|
|
"github.com/cli/cli/v2/pkg/iostreams"
|
|
"github.com/shurcooL/githubv4"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type RevertOptions struct {
|
|
HttpClient func() (*http.Client, error)
|
|
IO *iostreams.IOStreams
|
|
|
|
Finder shared.PRFinder
|
|
|
|
SelectorArg string
|
|
|
|
Body string
|
|
BodySet bool
|
|
Title string
|
|
IsDraft bool
|
|
}
|
|
|
|
func NewCmdRevert(f *cmdutil.Factory, runF func(*RevertOptions) error) *cobra.Command {
|
|
opts := &RevertOptions{
|
|
IO: f.IOStreams,
|
|
HttpClient: f.HttpClient,
|
|
}
|
|
|
|
var bodyFile string
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "revert {<number> | <url> | <branch>}",
|
|
Short: "Revert a pull request",
|
|
Args: cmdutil.ExactArgs(1, "cannot revert pull request: number, url, or branch required"),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
opts.Finder = shared.NewFinder(f)
|
|
|
|
if len(args) > 0 {
|
|
opts.SelectorArg = args[0]
|
|
}
|
|
|
|
bodyProvided := cmd.Flags().Changed("body")
|
|
bodyFileProvided := bodyFile != ""
|
|
|
|
if err := cmdutil.MutuallyExclusive(
|
|
"specify only one of `--body` or `--body-file`",
|
|
bodyProvided,
|
|
bodyFileProvided,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
|
|
if bodyProvided || bodyFileProvided {
|
|
opts.BodySet = true
|
|
if bodyFileProvided {
|
|
b, err := cmdutil.ReadFile(bodyFile, opts.IO.In)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
opts.Body = string(b)
|
|
}
|
|
}
|
|
|
|
if runF != nil {
|
|
return runF(opts)
|
|
}
|
|
return revertRun(opts)
|
|
},
|
|
}
|
|
|
|
cmd.Flags().BoolVarP(&opts.IsDraft, "draft", "d", false, "Mark revert pull request as a draft")
|
|
cmd.Flags().StringVarP(&opts.Title, "title", "t", "", "Title for the revert pull request")
|
|
cmd.Flags().StringVarP(&opts.Body, "body", "b", "", "Body for the revert pull request")
|
|
cmd.Flags().StringVarP(&bodyFile, "body-file", "F", "", "Read body text from `file` (use \"-\" to read from standard input)")
|
|
return cmd
|
|
}
|
|
|
|
func revertRun(opts *RevertOptions) error {
|
|
cs := opts.IO.ColorScheme()
|
|
|
|
findOptions := shared.FindOptions{
|
|
Selector: opts.SelectorArg,
|
|
Fields: []string{"id", "number", "state", "title"},
|
|
}
|
|
pr, baseRepo, err := opts.Finder.Find(findOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if pr.State != "MERGED" {
|
|
fmt.Fprintf(opts.IO.ErrOut, "%s Pull request %s#%d (%s) can't be reverted because it has not been merged\n", cs.FailureIcon(), ghrepo.FullName(baseRepo), pr.Number, pr.Title)
|
|
return cmdutil.SilentError
|
|
}
|
|
|
|
httpClient, err := opts.HttpClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
apiClient := api.NewClientFromHTTP(httpClient)
|
|
|
|
params := githubv4.RevertPullRequestInput{
|
|
PullRequestID: pr.ID,
|
|
Draft: githubv4.NewBoolean(githubv4.Boolean(opts.IsDraft)),
|
|
}
|
|
// Only set the Body field when opts.BodySet is true to avoid overriding
|
|
// GitHub's default revert body generation.
|
|
if opts.BodySet {
|
|
params.Body = githubv4.NewString(githubv4.String(opts.Body))
|
|
}
|
|
// Only set the Title field when opts.Title is not empty to avoid overriding
|
|
// GitHub's default revert title generation.
|
|
if opts.Title != "" {
|
|
params.Title = githubv4.NewString(githubv4.String(opts.Title))
|
|
}
|
|
|
|
revertPR, err := api.PullRequestRevert(apiClient, baseRepo, params)
|
|
if err != nil {
|
|
fmt.Fprintf(opts.IO.ErrOut, "%s %s\n", cs.FailureIcon(), err)
|
|
return fmt.Errorf("API call failed: %w", err)
|
|
}
|
|
|
|
if revertPR != nil {
|
|
fmt.Fprintln(opts.IO.Out, revertPR.URL)
|
|
}
|
|
return nil
|
|
}
|