Skip to content

Commit

Permalink
Added “git:destroy” to supersede “git:reset”
Browse files Browse the repository at this point in the history
  • Loading branch information
rykov committed Nov 10, 2021
1 parent b2c5517 commit ef430cc
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 43 deletions.
12 changes: 10 additions & 2 deletions api/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,17 @@ type GitRepo struct {
Name string `json:"name"`
}

// GitReset removes a Gemfury Git repository
func (c *Client) GitReset(cc context.Context, repo string) error {
// GitDestroy either fully removes a Gemfury Git repository, or resets the repo
// by deleting content but keeping its history, configuraion, and related metadata.
func (c *Client) GitDestroy(cc context.Context, repo string, resetOnly bool) error {
path := "/git/repos/{acct}/" + url.PathEscape(repo)

// Resets Git repository content without destroying it
// Keeping ID, build history, configuration, etc
if resetOnly {
path = path + "?reset=1"
}

req := c.newRequest(cc, "DELETE", path, false)
return req.doJSON(nil)
}
Expand Down
34 changes: 25 additions & 9 deletions cli/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,59 @@ func NewCmdGitRoot() *cobra.Command {
}

gitCmd.AddCommand(NewCmdGitConfig())
gitCmd.AddCommand(NewCmdGitDestroy())
gitCmd.AddCommand(NewCmdGitRebuild())
gitCmd.AddCommand(NewCmdGitRename())
gitCmd.AddCommand(NewCmdGitReset())
gitCmd.AddCommand(NewCmdGitList())

return gitCmd
}

// NewCmdGitReset generates the Cobra command for "git:reset"
func NewCmdGitReset() *cobra.Command {
resetCmd := &cobra.Command{
Use: "reset REPO",
Short: "Remove Git repository",
// NewCmdGitDestroy generates the Cobra command for "git:destroy"
func NewCmdGitDestroy() *cobra.Command {
var resetOnly bool

destroyCmd := &cobra.Command{
Use: "destroy REPO",
Aliases: []string{"reset"},
Short: "Remove Git repository",
RunE: func(cmd *cobra.Command, args []string) error {
term := ctx.Terminal(cmd.Context())

if len(args) != 1 {
return fmt.Errorf("Please specify a repository")
}

// Reset-only when called as "git:reset"
if cmd.CalledAs() == "reset" {
resetOnly = true
}

cc := cmd.Context()
c, err := newAPIClient(cc)
if err != nil {
return err
}

err = c.GitReset(cc, args[0])
err = c.GitDestroy(cc, args[0], resetOnly)
if err != nil {
return err
}

term.Printf("Removed %s repository\n", args[0])
if resetOnly {
term.Printf("Reset %s repository\n", args[0])
} else {
term.Printf("Removed %s repository\n", args[0])
}

return nil
},
}

return resetCmd
// Flags and options
destroyCmd.Flags().BoolVar(&resetOnly, "reset-only", false, "Reset repo without destroying")

return destroyCmd
}

// NewCmdGitRename generates the Cobra command for "git:reset"
Expand Down
68 changes: 57 additions & 11 deletions cli/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"github.com/gemfury/cli/internal/ctx"
"github.com/gemfury/cli/internal/testutil"
"github.com/gemfury/cli/pkg/terminal"

"net/http"
"strings"
"testing"
)
Expand Down Expand Up @@ -95,22 +97,27 @@ func TestGitRenameCommandForbidden(t *testing.T) {
server.Close()
}

// ==== GIT RESET ====
// ==== GIT DESTROY ====

func TestGitResetCommandSuccess(t *testing.T) {
func TestGitDestroyCommandSuccess(t *testing.T) {
auth := terminal.TestAuther("user", "abc123", nil)
term := terminal.NewForTest()

// Fire up test server
// Destroy without reset
path := "/git/repos/me/repo-name"
server := testutil.APIServer(t, "DELETE", path, "{}", 200)
defer server.Close()
serverDestroy := testutil.APIServerCustom(t, "DELETE", path, func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Has("reset") {
t.Errorf("Has extraneous reset=1 URL query")
}
w.Write([]byte("{}"))
})
defer serverDestroy.Close()

cc := cli.TestContext(term, auth)
flags := ctx.GlobalFlags(cc)
flags.Endpoint = server.URL
flags.Endpoint = serverDestroy.URL

err := runCommandNoErr(cc, []string{"git", "reset", "repo-name"})
err := runCommandNoErr(cc, []string{"git", "destroy", "repo-name"})
if err != nil {
t.Fatal(err)
}
Expand All @@ -119,19 +126,58 @@ func TestGitResetCommandSuccess(t *testing.T) {
if exp := "Removed repo-name repository\n"; !strings.HasSuffix(outStr, exp) {
t.Errorf("Expected output to include %q, got %q", exp, outStr)
}

// Reset without destroying repo
serverReset := testutil.APIServerCustom(t, "DELETE", path, func(w http.ResponseWriter, r *http.Request) {
if q := r.URL.Query(); q.Get("reset") != "1" {
t.Errorf("Missing reset=1 URL query")
}
w.Write([]byte("{}"))
})
defer serverReset.Close()

// Via "--reset-only" option
cc = cli.TestContext(term, auth)
flags = ctx.GlobalFlags(cc)
flags.Endpoint = serverReset.URL

err = runCommandNoErr(cc, []string{"git", "destroy", "--reset-only", "repo-name"})
if err != nil {
t.Fatal(err)
}

outStr = string(term.OutBytes())
if exp := "Reset repo-name repository\n"; !strings.HasSuffix(outStr, exp) {
t.Errorf("Expected output to include %q, got %q", exp, outStr)
}

// Via "git:reset" command
cc = cli.TestContext(term, auth)
flags = ctx.GlobalFlags(cc)
flags.Endpoint = serverReset.URL

err = runCommandNoErr(cc, []string{"git", "reset", "repo-name"})
if err != nil {
t.Fatal(err)
}

outStr = string(term.OutBytes())
if exp := "Reset repo-name repository\n"; !strings.HasSuffix(outStr, exp) {
t.Errorf("Expected output to include %q, got %q", exp, outStr)
}
}

func TestGitResetCommandUnauthorized(t *testing.T) {
func TestGitDestroyCommandUnauthorized(t *testing.T) {
path := "/git/repos/me/repo-name"
server := testutil.APIServer(t, "DELETE", path, "{}", 200)
testCommandLoginPreCheck(t, []string{"git", "reset", "repo-name"}, server)
testCommandLoginPreCheck(t, []string{"git", "destroy", "repo-name"}, server)
server.Close()
}

func TestGitResetCommandForbidden(t *testing.T) {
func TestGitDestroyCommandForbidden(t *testing.T) {
path := "/git/repos/me/repo-name"
server := testutil.APIServer(t, "DELETE", path, "", 403)
testCommandForbiddenResponse(t, []string{"git", "reset", "repo-name"}, server)
testCommandForbiddenResponse(t, []string{"git", "destroy", "repo-name"}, server)
server.Close()
}

Expand Down
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/briandowns/spinner v1.16.0
github.com/cheggaaa/pb/v3 v3.0.8
github.com/hashicorp/go-multierror v1.1.1
github.com/manifoldco/promptui v0.8.0
github.com/manifoldco/promptui v0.9.0
github.com/spf13/cobra v1.2.1
github.com/spf13/pflag v1.0.5
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
Expand All @@ -20,8 +20,6 @@ require (
github.com/fatih/color v1.13.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc // indirect
github.com/lunixbochs/vtclean v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
Expand Down
17 changes: 2 additions & 15 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -183,33 +183,22 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc h1:ZQrgZFsLzkw7o3CoDzsfBhx0bf/1rVBXrLy8dXKRe8o=
github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc/go.mod h1:PyXUpnI3olx3bsPcHt98FGPX/KCFZ1Fi+hw1XLI6384=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo=
github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.10/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
Expand Down Expand Up @@ -603,8 +592,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Expand Down
6 changes: 3 additions & 3 deletions internal/testutil/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const loginResponse = `{
}`

func APIServer(t *testing.T, method, path, resp string, code int) *httptest.Server {
return handleAPIPath(t, method, path, func(w http.ResponseWriter, r *http.Request) {
return APIServerCustom(t, method, path, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(code)
w.Write([]byte(resp))
})
Expand All @@ -30,7 +30,7 @@ func APIServer(t *testing.T, method, path, resp string, code int) *httptest.Serv
// Allow responses to be paginated forward. Page param is just a string of "p" characters to
// simplify implementation (without parsing), and prevent parsing page number as an integer
func APIServerPaginated(t *testing.T, method, path string, resps []string, code int) *httptest.Server {
return handleAPIPath(t, method, path, func(w http.ResponseWriter, r *http.Request) {
return APIServerCustom(t, method, path, func(w http.ResponseWriter, r *http.Request) {

// Page from JSON body or query
pageReq := api.PaginationRequest{}
Expand Down Expand Up @@ -67,7 +67,7 @@ func APIServerPaginated(t *testing.T, method, path string, resps []string, code
})
}

func handleAPIPath(t *testing.T, method, path string, hf http.HandlerFunc) *httptest.Server {
func APIServerCustom(t *testing.T, method, path string, hf http.HandlerFunc) *httptest.Server {
h := http.NewServeMux()

h.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
Expand Down

0 comments on commit ef430cc

Please sign in to comment.