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  }