Skip to content

Commit

Permalink
Multi-version yank with confirmation
Browse files Browse the repository at this point in the history
  • Loading branch information
rykov committed Jul 1, 2024
1 parent c46e49f commit 54c834a
Show file tree
Hide file tree
Showing 9 changed files with 233 additions and 87 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ GIT_DESCRIBE=$$(git describe --tags --always --match "v*")
GOLDFLAGS="-X main.Version=$(GIT_DESCRIBE)"
GO_CMD?=go

bin: # creates the Fury CLI binaries for current platform
fury: # creates the Fury CLI binaries for current platform
$(GO_CMD) build -ldflags $(GOLDFLAGS) -o ./fury ./cmd/fury

bin/linux: # creates the Fury CLI binaries for Linux (AMD64)
GOOS=linux GOARCH=amd64 $(GO_CMD) build -ldflags $(GOLDFLAGS) -o ./fury ./cmd/fury

bin/windows: # create windows binaries
GOOS=windows GOARCH=amd64 $(GO_CMD) build -ldflags $(GOLDFLAGS) -o ./fury.exe ./cmd/fury

clean: # remove binary
rm -f ./fury ./fury.exe
24 changes: 23 additions & 1 deletion api/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (c *Client) Packages(cc context.Context, body *PaginationRequest) (*Package
}

// Versions returns the details of the versions listing for a package
func (c *Client) Versions(cc context.Context, pkg string, body *PaginationRequest) (*VersionsResponse, error) {
func (c *Client) PackageVersions(cc context.Context, pkg string, body *PaginationRequest) (*VersionsResponse, error) {
req := c.newRequest(cc, "GET", "/packages/"+url.PathEscape(pkg)+"/versions?expand=package", true)

if body != nil {
Expand All @@ -36,6 +36,21 @@ func (c *Client) Versions(cc context.Context, pkg string, body *PaginationReques
return &resp, err
}

// Versions returns the details of the versions listing for specified filters
func (c *Client) Versions(cc context.Context, filter url.Values, body *PaginationRequest) (*VersionsResponse, error) {
req := c.newRequest(cc, "GET", "/versions?expand=package&"+filter.Encode(), true)

if body != nil {
c.prepareJSONBody(req, body)
}

resp := VersionsResponse{}
pagination, err := req.doPaginatedJSON(&resp.Versions)
resp.Pagination = pagination

return &resp, err
}

// Version returns the details of a specific version of a package
func (c *Client) Version(cc context.Context, pkg, ver string) (*Version, error) {
path := "/packages/" + url.PathEscape(pkg) + "/versions/" + url.PathEscape(ver)
Expand Down Expand Up @@ -108,3 +123,10 @@ func (v Version) DisplayCreatedBy() string {
}
return "N/A"
}

func (v Version) Kind() string {
if p := v.Package; p != nil && p.Kind != "" {
return p.Kind
}
return "N/A"
}
13 changes: 9 additions & 4 deletions cli/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/briandowns/spinner"
"github.com/gemfury/cli/api"
"github.com/gemfury/cli/internal/ctx"
"github.com/gemfury/cli/pkg/terminal"
"github.com/spf13/cobra"

"context"
Expand Down Expand Up @@ -89,7 +90,7 @@ func listVersions(cmd *cobra.Command, args []string) error {

// Paginate over package listings until no more pages
err = iterateAllPages(cc, func(pageReq *api.PaginationRequest) (*api.PaginationResponse, error) {
resp, err := c.Versions(cc, args[0], pageReq)
resp, err := c.PackageVersions(cc, args[0], pageReq)
if err != nil {
return nil, err
}
Expand All @@ -100,16 +101,20 @@ func listVersions(cmd *cobra.Command, args []string) error {

// Print results
term.Printf("\n*** %s versions ***\n\n", args[0])
termPrintVersions(term, versions)
return err
}

func termPrintVersions(term terminal.Terminal, versions []*api.Version) {
w := tabwriter.NewWriter(term.IOOut(), 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "version\tuploaded_by\tuploaded_at\tfilename\n")
fmt.Fprintf(w, "version\tuploaded_by\tuploaded_at\tkind\tfilename\n")

for _, v := range versions {
uploadedAt := timeStringWithAgo(v.CreatedAt)
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", v.Version, v.DisplayCreatedBy(), uploadedAt, v.Filename)
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", v.Version, v.DisplayCreatedBy(), uploadedAt, v.Kind(), v.Filename)
}

w.Flush()
return err
}

func iterateAllPages(cc context.Context, fn func(req *api.PaginationRequest) (*api.PaginationResponse, error)) error {
Expand Down
14 changes: 12 additions & 2 deletions cli/packages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,23 @@ var versionsResponses = []string{`[{
"id": "ver_a1b2c3",
"version": "1.2.3",
"created_at": "2011-05-27T00:39:07+00:00",
"filename": "foo-1.2.3.tgz",
"created_by": {
"name": "user1"
},
"package": {
"id": "pkg_x9y8z7",
"kind": "js"
}
}]`, `[{
"id": "ver_z1y2x3",
"version": "3.2.1",
"created_at": "2011-01-27T00:44:00+00:00"
"created_at": "2011-01-27T00:44:00+00:00",
"filename": "foo-3.2.1.tgz",
"package": {
"id": "pkg_x9y8z7",
"kind": "js"
}
}]`}

func TestVersionsCommandSuccess(t *testing.T) {
Expand All @@ -95,7 +105,7 @@ func TestVersionsCommandSuccess(t *testing.T) {
t.Fatal(err)
}

exp := "1.2.3 user1 2011-05-26 17:39 3.2.1 N/A 2011-01-26 16:44"
exp := "1.2.3 user1 2011-05-26 17:39 js foo-1.2.3.tgz 3.2.1 N/A 2011-01-26 16:44 js foo-3.2.1.tgz"
if outStr := compactString(term.OutBytes()); !strings.HasSuffix(outStr, exp) {
t.Errorf("Expected output to include %q, got %q", exp, outStr)
}
Expand Down
65 changes: 62 additions & 3 deletions cli/yank.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package cli

import (
"github.com/gemfury/cli/api"
"github.com/gemfury/cli/internal/ctx"
"github.com/hashicorp/go-multierror"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"

"context"
"errors"
"fmt"
"net/url"
"strings"
)

// NewCmdYank generates the Cobra command for "yank"
func NewCmdYank() *cobra.Command {
var versionFlag string
var forceFlag bool

yankCmd := &cobra.Command{
Use: "yank PACKAGE@VERSION",
Expand All @@ -32,6 +38,7 @@ func NewCmdYank() *cobra.Command {
return err
}

versions := make([]*api.Version, 0, len(args))
var multiErr *multierror.Error
for _, pkg := range args {
var ver string = ""
Expand All @@ -48,21 +55,73 @@ func NewCmdYank() *cobra.Command {
continue
}

err = c.Yank(cc, pkg, ver)
pkgVersions, err := filterVersions(cc, c, pkg, ver)
versions = append(versions, pkgVersions...)
multiErr = multierror.Append(multiErr, err)
}

if err := multiErr.Unwrap(); err != nil {
return err
} else if len(versions) == 0 {
term.Printf("No matching versions found\n")
return nil
}

if !forceFlag {
termPrintVersions(term, versions)
prompt := promptui.Prompt{
Label: "Are you sure you want to delete these files? [y/N]",
IsConfirm: true,
}
_, err := term.RunPrompt(&prompt)
if errors.Is(err, promptui.ErrAbort) {
return nil
} else if err != nil {
return err
}
}

for _, v := range versions {
err = c.Yank(cc, v.Package.ID, v.ID)
if err != nil {
multiErr = multierror.Append(multiErr, err)
continue
}

term.Printf("Removed package %q version %q\n", pkg, ver)
term.Printf("Removed %q\n", v.Filename)
}

return multiErr.Unwrap()
},
}

// Flags and options
yankCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Skip confirmation")
yankCmd.Flags().StringVarP(&versionFlag, "version", "v", "", "Version")

return yankCmd
}

func filterVersions(cc context.Context, c *api.Client, pkg, ver string) ([]*api.Version, error) {
versions := []*api.Version{}

// Default search filters for listed versions
filter := url.Values(map[string][]string{"name": {pkg}, "version": {ver}})

// Extract "kind:" from package name, if present
if at := strings.Index(pkg, ":"); at > 0 {
filter["name"] = []string{pkg[at+1:]}
filter["kind"] = []string{pkg[0:at]}
}

// Paginate over package listings until no more pages
err := iterateAllPages(cc, func(pageReq *api.PaginationRequest) (*api.PaginationResponse, error) {
resp, err := c.Versions(cc, filter, pageReq)
if err != nil {
return nil, err
}
versions = append(versions, resp.Versions...)
return resp.Pagination, nil
})

return versions, err
}
Loading

0 comments on commit 54c834a

Please sign in to comment.