github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/release/delete/delete.go (about) 1 package delete 2 3 import ( 4 "fmt" 5 "net/http" 6 7 "github.com/AlecAivazis/survey/v2" 8 "github.com/ungtb10d/cli/v2/api" 9 "github.com/ungtb10d/cli/v2/internal/ghinstance" 10 "github.com/ungtb10d/cli/v2/internal/ghrepo" 11 "github.com/ungtb10d/cli/v2/pkg/cmd/release/shared" 12 "github.com/ungtb10d/cli/v2/pkg/cmdutil" 13 "github.com/ungtb10d/cli/v2/pkg/iostreams" 14 "github.com/ungtb10d/cli/v2/pkg/prompt" 15 "github.com/spf13/cobra" 16 ) 17 18 type DeleteOptions struct { 19 HttpClient func() (*http.Client, error) 20 IO *iostreams.IOStreams 21 BaseRepo func() (ghrepo.Interface, error) 22 23 TagName string 24 SkipConfirm bool 25 CleanupTag bool 26 } 27 28 func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Command { 29 opts := &DeleteOptions{ 30 IO: f.IOStreams, 31 HttpClient: f.HttpClient, 32 } 33 34 cmd := &cobra.Command{ 35 Use: "delete <tag>", 36 Short: "Delete a release", 37 Args: cobra.ExactArgs(1), 38 RunE: func(cmd *cobra.Command, args []string) error { 39 // support `-R, --repo` override 40 opts.BaseRepo = f.BaseRepo 41 42 opts.TagName = args[0] 43 44 if runF != nil { 45 return runF(opts) 46 } 47 return deleteRun(opts) 48 }, 49 } 50 51 cmd.Flags().BoolVarP(&opts.SkipConfirm, "yes", "y", false, "Skip the confirmation prompt") 52 cmd.Flags().BoolVar(&opts.CleanupTag, "cleanup-tag", false, "Delete the specified tag in addition to its release") 53 54 return cmd 55 } 56 57 func deleteRun(opts *DeleteOptions) error { 58 httpClient, err := opts.HttpClient() 59 if err != nil { 60 return err 61 } 62 63 baseRepo, err := opts.BaseRepo() 64 if err != nil { 65 return err 66 } 67 68 release, err := shared.FetchRelease(httpClient, baseRepo, opts.TagName) 69 if err != nil { 70 return err 71 } 72 73 if !opts.SkipConfirm && opts.IO.CanPrompt() { 74 var confirmed bool 75 //nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter 76 err := prompt.SurveyAskOne(&survey.Confirm{ 77 Message: fmt.Sprintf("Delete release %s in %s?", release.TagName, ghrepo.FullName(baseRepo)), 78 Default: true, 79 }, &confirmed) 80 if err != nil { 81 return err 82 } 83 84 if !confirmed { 85 return cmdutil.CancelError 86 } 87 } 88 89 err = deleteRelease(httpClient, release.APIURL) 90 if err != nil { 91 return err 92 } 93 94 var cleanupMessage string 95 mustCleanupTag := opts.CleanupTag 96 if mustCleanupTag { 97 err = deleteTag(httpClient, baseRepo, release.TagName) 98 if err != nil { 99 return err 100 } 101 cleanupMessage = " and tag" 102 } 103 104 if !opts.IO.IsStdoutTTY() || !opts.IO.IsStderrTTY() { 105 return nil 106 } 107 108 iofmt := opts.IO.ColorScheme() 109 fmt.Fprintf(opts.IO.ErrOut, "%s Deleted release%s %s\n", iofmt.SuccessIconWithColor(iofmt.Red), cleanupMessage, release.TagName) 110 if !release.IsDraft && !mustCleanupTag { 111 fmt.Fprintf(opts.IO.ErrOut, "%s Note that the %s git tag still remains in the repository\n", iofmt.WarningIcon(), release.TagName) 112 } 113 114 return nil 115 } 116 117 func deleteRelease(httpClient *http.Client, releaseURL string) error { 118 req, err := http.NewRequest("DELETE", releaseURL, nil) 119 if err != nil { 120 return err 121 } 122 123 resp, err := httpClient.Do(req) 124 if err != nil { 125 return err 126 } 127 defer resp.Body.Close() 128 129 if resp.StatusCode > 299 { 130 return api.HandleHTTPError(resp) 131 } 132 return nil 133 } 134 135 func deleteTag(httpClient *http.Client, baseRepo ghrepo.Interface, tagName string) error { 136 path := fmt.Sprintf("repos/%s/%s/git/refs/tags/%s", baseRepo.RepoOwner(), baseRepo.RepoName(), tagName) 137 url := ghinstance.RESTPrefix(baseRepo.RepoHost()) + path 138 139 req, err := http.NewRequest("DELETE", url, nil) 140 if err != nil { 141 return err 142 } 143 144 resp, err := httpClient.Do(req) 145 if err != nil { 146 return err 147 } 148 defer resp.Body.Close() 149 150 if resp.StatusCode > 299 { 151 return api.HandleHTTPError(resp) 152 } 153 return nil 154 }