diff --git a/internal/commands/repo/rm.go b/internal/commands/repo/rm.go index 8196af8..7fe558e 100644 --- a/internal/commands/repo/rm.go +++ b/internal/commands/repo/rm.go @@ -47,7 +47,7 @@ type rmOptions struct { func newRmCmd(streams command.Streams, hubClient *hub.Client, parent string) *cobra.Command { var opts rmOptions cmd := &cobra.Command{ - Use: rmName + " [OPTIONS] REPOSITORY", + Use: rmName + " [OPTIONS] NAMESPACE/REPOSITORY", Short: "Delete a repository", Args: cli.ExactArgs(1), DisableFlagsInUseLine: true, @@ -73,7 +73,11 @@ func runRm(ctx context.Context, streams command.Streams, hubClient *hub.Client, } namedRef, ok := ref.(reference.Named) if !ok { - return fmt.Errorf("invalid reference: repository not specified") + return errors.New("invalid reference: repository not specified") + } + + if !strings.Contains(repository, "/") { + return fmt.Errorf("repository name must include username or organization name, example: hub-tool repo rm username/repository") } if !opts.force { @@ -104,6 +108,9 @@ func runRm(ctx context.Context, streams command.Streams, hubClient *hub.Client, if err := hubClient.RemoveRepository(namedRef.Name()); err != nil { return err } - fmt.Fprintln(streams.Out(), "Deleted", repository) + _, err = fmt.Fprintf(streams.Out(), "Repository %q was successfully deleted\n", repository) + if err != nil { + return err + } return nil } diff --git a/pkg/hub/client.go b/pkg/hub/client.go index 0f8f098..2c5c04f 100644 --- a/pkg/hub/client.go +++ b/pkg/hub/client.go @@ -309,6 +309,11 @@ func (c *Client) doRequest(req *http.Request, reqOps ...RequestOp) ([]byte, erro defer resp.Body.Close() //nolint:errcheck } log.Tracef("HTTP response: %+v", resp) + + if resp.StatusCode == http.StatusNotFound { + return nil, ¬FoundError{} + } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { if resp.StatusCode == http.StatusForbidden { return nil, &forbiddenError{} diff --git a/pkg/hub/error.go b/pkg/hub/error.go index a989dd4..7fe17f5 100644 --- a/pkg/hub/error.go +++ b/pkg/hub/error.go @@ -56,3 +56,15 @@ func IsForbiddenError(err error) bool { _, ok := err.(*forbiddenError) return ok } + +type notFoundError struct{} + +func (n notFoundError) Error() string { + return "resource not found" +} + +// IsNotFoundError check if the error type is a not found error +func IsNotFoundError(err error) bool { + _, ok := err.(*notFoundError) + return ok +} diff --git a/pkg/hub/error_test.go b/pkg/hub/error_test.go index 42d175d..8c20e1e 100644 --- a/pkg/hub/error_test.go +++ b/pkg/hub/error_test.go @@ -37,3 +37,8 @@ func TestIsForbiddenError(t *testing.T) { assert.Assert(t, IsForbiddenError(&forbiddenError{})) assert.Assert(t, !IsForbiddenError(errors.New(""))) } + +func TestIsNotFoundError(t *testing.T) { + assert.Assert(t, IsNotFoundError(¬FoundError{})) + assert.Assert(t, !IsNotFoundError(errors.New(""))) +} diff --git a/pkg/hub/repositories.go b/pkg/hub/repositories.go index 28273db..30ff298 100644 --- a/pkg/hub/repositories.go +++ b/pkg/hub/repositories.go @@ -25,10 +25,8 @@ import ( ) const ( - // RepositoriesURL path to the Hub API listing the repositories - RepositoriesURL = "/v2/repositories/%s/" - // DeleteRepositoryURL path to the Hub API to remove a repository - DeleteRepositoryURL = "/v2/repositories/%s/" + // RepositoriesURL is the Hub API base URL + RepositoriesURL = "/v2/repositories/" ) //Repository represents a Docker Hub repository @@ -46,7 +44,8 @@ func (c *Client) GetRepositories(account string) ([]Repository, int, error) { if account == "" { account = c.account } - u, err := url.Parse(c.domain + fmt.Sprintf(RepositoriesURL, account)) + repositoriesURL := fmt.Sprintf("%s%s%s", c.domain, RepositoriesURL, account) + u, err := url.Parse(repositoriesURL) if err != nil { return nil, 0, err } @@ -77,12 +76,17 @@ func (c *Client) GetRepositories(account string) ([]Repository, int, error) { //RemoveRepository removes a repository on Hub func (c *Client) RemoveRepository(repository string) error { - req, err := http.NewRequest("DELETE", c.domain+fmt.Sprintf(DeleteRepositoryURL, repository), nil) + repositoryURL := fmt.Sprintf("%s%s%s/", c.domain, RepositoriesURL, repository) + req, err := http.NewRequest(http.MethodDelete, repositoryURL, nil) if err != nil { return err } _, err = c.doRequest(req, withHubToken(c.token)) - return err + if err != nil { + return err + } + + return nil } func (c *Client) getRepositoriesPage(url, account string) ([]Repository, int, string, error) {