From 435ed0ec8775975b4e278dec06119a915e84c994 Mon Sep 17 00:00:00 2001 From: KeitaShimura Date: Thu, 9 Apr 2026 15:24:09 +0900 Subject: [PATCH] feat: remove --print flag and print local path by default --- cmd_get.go | 20 ++++++++++-------- cmd_get_test.go | 56 ++++++++++++++++++++++++++++++++++++++++--------- commands.go | 3 +-- getter.go | 7 ++++--- main.go | 10 ++++----- 5 files changed, 67 insertions(+), 29 deletions(-) diff --git a/cmd_get.go b/cmd_get.go index e41642a..900db3b 100644 --- a/cmd_get.go +++ b/cmd_get.go @@ -22,11 +22,10 @@ import ( func doGet(ctx context.Context, cmd *cli.Command) error { var ( - args = cmd.Args().Slice() - andLook = cmd.Bool("look") - parallel = cmd.Bool("parallel") - silent = cmd.Bool("silent") - printPath = cmd.Bool("print") + args = cmd.Args().Slice() + andLook = cmd.Bool("look") + parallel = cmd.Bool("parallel") + silent = cmd.Bool("silent") ) g := &getter{ update: cmd.Bool("update"), @@ -76,20 +75,23 @@ func doGet(ctx context.Context, cmd *cli.Command) error { sem <- struct{}{} eg.Go(func() error { defer func() { <-sem }() - info, getErr := g.get(target) + info, getErr := g.get(ctx, target) getInfo, err = info, getErr if getErr != nil { logger.Logf("error", "failed to get %q: %s", target, getErr) - } else if printPath && info.localRepository != nil { + } else if info.localRepository != nil { fmt.Println(info.localRepository.FullPath) } return nil }) } else { - if getInfo, err = g.get(target); err != nil { + if getInfo, err = g.get(ctx, target); err != nil { return fmt.Errorf("failed to get %q: %w", target, err) } - if printPath && getInfo.localRepository != nil { + if getInfo.localRepository != nil { + if !silent { + fmt.Fprintln(os.Stderr, "Got the repo to the following:") + } fmt.Println(getInfo.localRepository.FullPath) } } diff --git a/cmd_get_test.go b/cmd_get_test.go index 4fd8a8c..a64bfc7 100644 --- a/cmd_get_test.go +++ b/cmd_get_test.go @@ -245,8 +245,8 @@ func TestCommandGet(t *testing.T) { if !cloneArgs.silent { t.Errorf("cloneArgs.silent should be true") } - if out != "" { - t.Errorf("silent mode should not output any logs, but got: %s", out) + if !strings.Contains(out, localDir) { + t.Errorf("silent mode should still print local path to stdout, but got: %q", out) } }, }, { @@ -304,22 +304,22 @@ func TestCommandGet(t *testing.T) { } } -func TestCommandGet_print(t *testing.T) { +func TestCommandGet_printPath(t *testing.T) { testCases := []struct { name string args []string inputRepos []string }{{ name: "single repo", - args: []string{"", "get", "--print", "motemen/ghq-test-repo"}, + args: []string{"", "get", "motemen/ghq-test-repo"}, inputRepos: nil, }, { name: "bulk from stdin", - args: []string{"", "get", "--print"}, + args: []string{"", "get"}, inputRepos: []string{"github.com/x-motemen/ghq", "github.com/motemen/gore"}, }, { name: "bulk parallel", - args: []string{"", "get", "--print", "--parallel"}, + args: []string{"", "get", "--parallel"}, inputRepos: []string{"github.com/x-motemen/ghq", "github.com/motemen/gore"}, }} @@ -335,11 +335,11 @@ func TestCommandGet_print(t *testing.T) { var err error if len(tc.inputRepos) > 0 { out, _, err = captureWithInput(tc.inputRepos, func() { - newApp().Run(tc.args) + newApp().Run(context.Background(), tc.args) }) } else { out, _, err = capture(func() { - newApp().Run(tc.args) + newApp().Run(context.Background(), tc.args) }) } if err != nil { @@ -371,6 +371,39 @@ func TestCommandGet_print(t *testing.T) { } } +func TestCommandGet_gotMessage(t *testing.T) { + t.Run("prints 'Got the repo to the following:' to stderr", func(t *testing.T) { + withFakeGitBackend(t, func(t *testing.T, tmpRoot string, _ *_cloneArgs, _ *_updateArgs) { + _, errOut, err := capture(func() { + newApp().Run(context.Background(), []string{"", "get", "motemen/ghq-test-repo"}) + }) + if err != nil { + t.Fatalf("capture error: %s", err) + } + if !strings.Contains(errOut, "Got the repo to the following:") { + t.Errorf("expected stderr to contain 'Got the repo to the following:', got: %q", errOut) + } + }) + }) + + t.Run("suppresses message with --silent but still prints path to stdout", func(t *testing.T) { + withFakeGitBackend(t, func(t *testing.T, tmpRoot string, _ *_cloneArgs, _ *_updateArgs) { + out, errOut, err := capture(func() { + newApp().Run(context.Background(), []string{"", "get", "--silent", "motemen/ghq-test-repo"}) + }) + if err != nil { + t.Fatalf("capture error: %s", err) + } + if strings.Contains(errOut, "Got the repo to the following:") { + t.Errorf("expected stderr not to contain 'Got the repo to the following:' with --silent, got: %q", errOut) + } + if !filepath.IsAbs(strings.TrimRight(out, "\n")) { + t.Errorf("expected absolute path in stdout, got: %q", out) + } + }) + }) +} + func TestLook(t *testing.T) { withFakeGitBackend(t, func(t *testing.T, tmproot string, _ *_cloneArgs, _ *_updateArgs) { os.MkdirAll(filepath.Join(tmproot, "github.com", "motemen", "ghq", ".git"), 0755) @@ -501,8 +534,11 @@ func TestDoGet_bulk(t *testing.T) { if err != nil { t.Errorf("error should be nil, but: %s", err) } - if out != "" { - t.Errorf("out should be empty, but: %s", out) + for _, r := range in { + expectedPath := filepath.Join(tmproot, r) + if !strings.Contains(out, expectedPath) { + t.Errorf("out should contain %q, but got: %s", expectedPath, out) + } } log := filepath.ToSlash(buf.String()) for _, r := range in { diff --git a/commands.go b/commands.go index cbbbe17..5c259e1 100644 --- a/commands.go +++ b/commands.go @@ -41,7 +41,6 @@ var commandGet = &cli.Command{ Usage: "Specify `branch` name. This flag implies --single-branch on Git"}, &cli.BoolFlag{Name: "parallel", Aliases: []string{"P"}, Usage: "Import parallelly"}, &cli.BoolFlag{Name: "bare", Usage: "Do a bare clone"}, - &cli.BoolFlag{Name: "print", Usage: "Print local repository path after get"}, &cli.StringFlag{ Name: "partial", Usage: "Do a partial clone. Can specify either \"blobless\" or \"treeless\"", @@ -109,7 +108,7 @@ type commandDoc struct { } var commandDocs = map[string]commandDoc{ - "get": {"", "[-u] [-p] [--shallow] [--vcs ] [--look] [--silent] [--branch ] [--no-recursive] [--bare] [--partial blobless|treeless] [--print] ||/|//"}, + "get": {"", "[-u] [-p] [--shallow] [--vcs ] [--look] [--silent] [--branch ] [--no-recursive] [--bare] [--partial blobless|treeless] ||/|//"}, "list": {"", "[-p] [-e] []"}, "create": {"", "|/|//"}, "rm": {"", "|/|//"}, diff --git a/getter.go b/getter.go index ce7d917..18f9f65 100644 --- a/getter.go +++ b/getter.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "net/url" "os" @@ -28,7 +29,7 @@ type getter struct { vcs, branch, partial string } -func (g *getter) get(argURL string) (getInfo, error) { +func (g *getter) get(ctx context.Context, argURL string) (getInfo, error) { u, err := newURL(argURL, g.ssh, false) if err != nil { return getInfo{}, fmt.Errorf("could not parse URL %q: %w", argURL, err) @@ -42,13 +43,13 @@ func (g *getter) get(argURL string) (getInfo, error) { return getInfo{}, err } - return g.getRemoteRepository(remote, branch) + return g.getRemoteRepository(ctx, remote, branch) } // getRemoteRepository clones or updates a remote repository remote. // If doUpdate is true, updates the locally cloned repository. Otherwise does nothing. // If isShallow is true, does shallow cloning. (no effect if already cloned or the VCS is Mercurial and git-svn) -func (g *getter) getRemoteRepository(remote RemoteRepository, branch string) (getInfo, error) { +func (g *getter) getRemoteRepository(ctx context.Context, remote RemoteRepository, branch string) (getInfo, error) { remoteURL := remote.URL() local, err := LocalRepositoryFromURL(remoteURL, g.bare) if err != nil { diff --git a/main.go b/main.go index 041fa46..cfdc66f 100644 --- a/main.go +++ b/main.go @@ -26,11 +26,11 @@ func main() { func newApp() *cli.Command { return &cli.Command{ - Name: "ghq", - Usage: "Manage remote repository clones", - Version: fmt.Sprintf("%s (rev:%s)", version, revision), - Authors: []any{"motemen ", "Songmu "}, - Suggest: true, + Name: "ghq", + Usage: "Manage remote repository clones", + Version: fmt.Sprintf("%s (rev:%s)", version, revision), + Authors: []any{"motemen ", "Songmu "}, + Suggest: true, Commands: commands, } }