package delete import ( "errors" "fmt" "net/http" "strings" "github.com/MakeNowJust/heredoc" "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/gh" "github.com/cli/cli/v2/internal/prompter" "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 DeleteOptions struct { IO *iostreams.IOStreams Config func() (gh.Config, error) HttpClient func() (*http.Client, error) Prompter prompter.Prompter Selector string Confirmed bool } func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Command { opts := DeleteOptions{ IO: f.IOStreams, Config: f.Config, HttpClient: f.HttpClient, Prompter: f.Prompter, } cmd := &cobra.Command{ Use: "delete { | }", Short: "Delete a gist", Long: heredoc.Docf(` Delete a GitHub gist. To delete a gist interactively, use %[1]sgh gist delete%[1]s with no arguments. To delete a gist non-interactively, supply the gist id or url. `, "`"), Example: heredoc.Doc(` # Delete a gist interactively $ gh gist delete # Delete a gist non-interactively $ gh gist delete 1234 `), Args: cobra.MaximumNArgs(1), RunE: func(c *cobra.Command, args []string) error { if !opts.IO.CanPrompt() && !opts.Confirmed { return cmdutil.FlagErrorf("--yes required when not running interactively") } if !opts.IO.CanPrompt() && len(args) == 0 { return cmdutil.FlagErrorf("id or url argument required in non-interactive mode") } if len(args) == 1 { opts.Selector = args[0] } if runF != nil { return runF(&opts) } return deleteRun(&opts) }, } cmd.Flags().BoolVar(&opts.Confirmed, "yes", false, "Confirm deletion without prompting") return cmd } func deleteRun(opts *DeleteOptions) error { client, err := opts.HttpClient() if err != nil { return err } cfg, err := opts.Config() if err != nil { return err } host, _ := cfg.Authentication().DefaultHost() gistID := opts.Selector if strings.Contains(gistID, "/") { id, err := shared.GistIDFromURL(gistID) if err != nil { return err } gistID = id } cs := opts.IO.ColorScheme() var gist *shared.Gist if gistID == "" { gist, err = shared.PromptGists(opts.Prompter, client, host, cs) } else { gist, err = shared.GetGist(client, host, gistID) } if err != nil { return err } if gist.ID == "" { fmt.Fprintln(opts.IO.Out, "No gists found.") return nil } if !opts.Confirmed { confirmed, err := opts.Prompter.Confirm(fmt.Sprintf("Delete %q gist?", gist.Filename()), false) if err != nil { return err } if !confirmed { return cmdutil.CancelError } } apiClient := api.NewClientFromHTTP(client) if err := deleteGist(apiClient, host, gist.ID); err != nil { if errors.Is(err, shared.NotFoundErr) { return fmt.Errorf("unable to delete gist %q: either the gist is not found or it is not owned by you", gist.Filename()) } return err } if opts.IO.IsStdoutTTY() { cs := opts.IO.ColorScheme() fmt.Fprintf(opts.IO.Out, "%s Gist %q deleted\n", cs.SuccessIcon(), gist.Filename()) } return nil } func deleteGist(apiClient *api.Client, hostname string, gistID string) error { path := "gists/" + gistID err := apiClient.REST(hostname, "DELETE", path, nil, nil) if err != nil { var httpErr api.HTTPError if errors.As(err, &httpErr) && httpErr.StatusCode == 404 { return shared.NotFoundErr } return err } return nil }