From 54de75db82b5281499dbfc1cbeab909511dbebbf Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 18 Mar 2023 01:16:59 +0800 Subject: [PATCH] feat: add gist rename logic --- pkg/cmd/gist/rename/rename.go | 156 ++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 pkg/cmd/gist/rename/rename.go diff --git a/pkg/cmd/gist/rename/rename.go b/pkg/cmd/gist/rename/rename.go new file mode 100644 index 000000000..5ccd81e90 --- /dev/null +++ b/pkg/cmd/gist/rename/rename.go @@ -0,0 +1,156 @@ +package rename + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + + "github.com/MakeNowJust/heredoc" + "github.com/cli/cli/v2/api" + "github.com/cli/cli/v2/internal/config" + "github.com/cli/cli/v2/pkg/cmd/gist/shared" + "github.com/cli/cli/v2/pkg/cmdutil" + "github.com/cli/cli/v2/pkg/iostreams" + "github.com/spf13/cobra" +) + +type RenameOptions struct { + IO *iostreams.IOStreams + Config func() (config.Config, error) + HttpClient func() (*http.Client, error) + Prompter iprompter + DoConfirm bool + + Selector string + OldFileName string + NewFileName string +} + +type iprompter interface { + Input(string, string) (string, error) + Confirm(string, bool) (bool, error) +} + +func NewCmdRename(f *cmdutil.Factory, runf func(*RenameOptions) error) *cobra.Command { + opts := &RenameOptions{ + IO: f.IOStreams, + HttpClient: f.HttpClient, + Config: f.Config, + Prompter: f.Prompter, + } + + var confirm bool + + cmd := &cobra.Command{ + Use: "rename [ | ] ", + Short: "Rename a file in a gist", + Long: heredoc.Doc(`Rename a file in the given gist ID / URL.`), + Args: cobra.MaximumNArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 3 { + opts.Selector = args[0] + opts.OldFileName = args[1] + opts.NewFileName = args[2] + } else { + return cmdutil.FlagErrorf("not enough arguments") + } + + if runf != nil { + return runf(opts) + } + + return renameRun(opts) + }, + } + + cmd.Flags().BoolVarP(&confirm, "yes", "y", false, "Skip the confirmation prompt") + + return cmd +} + +func renameRun(opts *RenameOptions) error { + gistID := opts.Selector + + if strings.Contains(gistID, "/") { + id, err := shared.GistIDFromURL(gistID) + if err != nil { + return err + } + gistID = id + } + + client, err := opts.HttpClient() + if err != nil { + return err + } + + apiClient := api.NewClientFromHTTP(client) + + cfg, err := opts.Config() + if err != nil { + return err + } + + host, _ := cfg.Authentication().DefaultHost() + + gist, err := shared.GetGist(client, host, gistID) + if err != nil { + if errors.Is(err, shared.NotFoundErr) { + return fmt.Errorf("gist not found: %s", gistID) + } + return err + } + username, err := api.CurrentLoginName(apiClient, host) + if err != nil { + return err + } + + if username != gist.Owner.Login { + return errors.New("you do not own this gist") + } + + _, ok := gist.Files[opts.OldFileName] + if !ok { + return fmt.Errorf("File %s not found in gist", opts.OldFileName) + } + + _, ok = gist.Files[opts.NewFileName] + if ok { + return fmt.Errorf("File %s already exists in gist", opts.NewFileName) + } + + gist.Files[opts.NewFileName] = gist.Files[opts.OldFileName] + gist.Files[opts.NewFileName].Filename = opts.NewFileName + gist.Files[opts.OldFileName] = &shared.GistFile{} + + return updateGist(apiClient, host, gist) +} + +func updateGist(apiClient *api.Client, hostname string, gist *shared.Gist) error { + body := shared.Gist{ + Description: gist.Description, + Files: gist.Files, + } + + path := "gists/" + gist.ID + + requestByte, err := json.Marshal(body) + if err != nil { + return err + } + + requestBody := bytes.NewReader(requestByte) + + result := shared.Gist{} + + err = apiClient.REST(hostname, "POST", path, requestBody, &result) + + if err != nil { + return err + } + + return nil +}