Repository: seachicken/gh-poi
Pull request #84 (2022-11-01 11:37:32)

Add --debug option
Logging input/output of external commands to facilitate solving execution environment-dependent problems.

Related issue #79 

codecov[bot]: # [Codecov](https://codecov.io/gh/seachicken/gh-poi/pull/84?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Seito+Tanaka) Report
> Merging [#84](https://codecov.io/gh/seachicken/gh-poi/pull/84?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Seito+Tanaka) (573a927) into [main](https://codecov.io/gh/seachicken/gh-poi/commit/78a966013391545774d35ab12dbec560a6b5710c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Seito+Tanaka) (78a9660) will **decrease** coverage by `0.22%`.
> The diff coverage is `72.72%`.

```diff
@@            Coverage Diff             @@
##             main      #84      +/-   ##
==========================================
- Coverage   87.94%   87.71%   -0.23%     
==========================================
  Files           3        3              
  Lines         622      627       +5     
==========================================
+ Hits          547      550       +3     
- Misses         56       58       +2     
  Partials       19       19              
```


| [Impacted Files](https://codecov.io/gh/seachicken/gh-poi/pull/84?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Seito+Tanaka) | Coverage Δ | |
|---|---|---|
| [main.go](https://codecov.io/gh/seachicken/gh-poi/pull/84/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Seito+Tanaka#diff-bWFpbi5nbw==) | `77.20% <72.72%> (-0.66%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Seito+Tanaka). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Seito+Tanaka)


Patch:
diff --git a/README.md b/README.md
index cef1fc5..6b4cbea 100644
--- a/README.md
+++ b/README.md
@@ -25,3 +25,4 @@ gh extension install seachicken/gh-poi
 
 - `gh poi` Delete the merged local branches
 - `gh poi --dry-run` You can check the branch to be deleted without actually deleting it
+- `gh poi --debug` Enable debug logs
diff --git a/conn/command.go b/conn/command.go
index ce419cc..bfbeaed 100644
--- a/conn/command.go
+++ b/conn/command.go
@@ -10,7 +10,18 @@ import (
 	"github.com/cli/safeexec"
 )
 
-type Connection struct{}
+type (
+	Connection struct {
+		Debug bool
+	}
+
+	DebugMask int
+)
+
+const (
+	None DebugMask = iota
+	Output
+)
 
 func (conn *Connection) CheckRepos(ctx context.Context, hostname string, repoNames []string) error {
 	for _, name := range repoNames {
@@ -20,7 +31,7 @@ func (conn *Connection) CheckRepos(ctx context.Context, hostname string, repoNam
 			"repos/" + name,
 			"--silent",
 		}
-		if _, err := run(ctx, "gh", args); err != nil {
+		if _, err := conn.run(ctx, "gh", args, None); err != nil {
 			return err
 		}
 	}
@@ -31,14 +42,14 @@ func (conn *Connection) GetRemoteNames(ctx context.Context) (string, error) {
 	args := []string{
 		"remote", "-v",
 	}
-	return run(ctx, "git", args)
+	return conn.run(ctx, "git", args, None)
 }
 
 func (conn *Connection) GetSshConfig(ctx context.Context, name string) (string, error) {
 	args := []string{
 		"-T", "-G", name,
 	}
-	return run(ctx, "ssh", args)
+	return conn.run(ctx, "ssh", args, Output)
 }
 
 func (conn *Connection) GetRepoNames(ctx context.Context, hostname string, repoName string) (string, error) {
@@ -49,7 +60,7 @@ func (conn *Connection) GetRepoNames(ctx context.Context, hostname string, repoN
 		"--json", "parent",
 		"--json", "defaultBranchRef",
 	}
-	return run(ctx, "gh", args)
+	return conn.run(ctx, "gh", args, None)
 }
 
 func (conn *Connection) GetBranchNames(ctx context.Context) (string, error) {
@@ -57,21 +68,21 @@ func (conn *Connection) GetBranchNames(ctx context.Context) (string, error) {
 		"branch", "-v", "--no-abbrev",
 		"--format=%(HEAD):%(refname:lstrip=2):%(objectname)",
 	}
-	return run(ctx, "git", args)
+	return conn.run(ctx, "git", args, None)
 }
 
 func (conn *Connection) GetMergedBranchNames(ctx context.Context, remoteName string, branchName string) (string, error) {
 	args := []string{
 		"branch", "--merged", fmt.Sprintf("%s/%s", remoteName, branchName),
 	}
-	return run(ctx, "git", args)
+	return conn.run(ctx, "git", args, None)
 }
 
 func (conn *Connection) GetLog(ctx context.Context, branchName string) (string, error) {
 	args := []string{
 		"log", "--first-parent", "--max-count=30", "--format=%H", branchName, "--",
 	}
-	return run(ctx, "git", args)
+	return conn.run(ctx, "git", args, None)
 }
 
 func (conn *Connection) GetAssociatedRefNames(ctx context.Context, oid string) (string, error) {
@@ -79,7 +90,7 @@ func (conn *Connection) GetAssociatedRefNames(ctx context.Context, oid string) (
 		"branch", "--all", "--format=%(refname)",
 		"--contains", oid,
 	}
-	return run(ctx, "git", args)
+	return conn.run(ctx, "git", args, None)
 }
 
 func (conn *Connection) GetPullRequests(
@@ -116,28 +127,28 @@ func (conn *Connection) GetPullRequests(
 			queryHashes,
 		),
 	}
-	return run(ctx, "gh", args)
+	return conn.run(ctx, "gh", args, None)
 }
 
 func (conn *Connection) GetUncommittedChanges(ctx context.Context) (string, error) {
 	args := []string{
 		"status", "--short",
 	}
-	return run(ctx, "git", args)
+	return conn.run(ctx, "git", args, None)
 }
 
 func (conn *Connection) GetConfig(ctx context.Context, key string) (string, error) {
 	args := []string{
 		"config", "--get", key,
 	}
-	return run(ctx, "git", args)
+	return conn.run(ctx, "git", args, None)
 }
 
 func (conn *Connection) CheckoutBranch(ctx context.Context, branchName string) (string, error) {
 	args := []string{
 		"checkout", "--quiet", branchName,
 	}
-	return run(ctx, "git", args)
+	return conn.run(ctx, "git", args, None)
 }
 
 func (conn *Connection) DeleteBranches(ctx context.Context, branchNames []string) (string, error) {
@@ -145,25 +156,17 @@ func (conn *Connection) DeleteBranches(ctx context.Context, branchNames []string
 		"branch", "-D"},
 		branchNames...,
 	)
-	return run(ctx, "git", args)
+	return conn.run(ctx, "git", args, None)
 }
 
 func (conn *Connection) PruneRemoteBranches(ctx context.Context, remoteName string) (string, error) {
 	args := []string{
 		"remote", "prune", remoteName,
 	}
-	return run(ctx, "git", args)
-}
-
-func getQueryRepos(repoNames []string) string {
-	var repos strings.Builder
-	for _, name := range repoNames {
-		repos.WriteString(fmt.Sprintf("repo:%s ", name))
-	}
-	return repos.String()
+	return conn.run(ctx, "git", args, None)
 }
 
-func run(ctx context.Context, name string, args []string) (string, error) {
+func (conn *Connection) run(ctx context.Context, name string, args []string, mask DebugMask) (string, error) {
 	cmdPath, err := safeexec.LookPath(name)
 	if err != nil {
 		return "", err
@@ -178,5 +181,22 @@ func run(ctx context.Context, name string, args []string) (string, error) {
 		err = fmt.Errorf("failed to run external command: %s, args: %v\n%w", name, args, err)
 	}
 
+	if conn.Debug {
+		switch mask {
+		case None:
+			fmt.Printf("run %s %v -> %s\n", name, args, stdout.String())
+		case Output:
+			fmt.Printf("run %s %v -> *****\n", name, args)
+		}
+	}
+
 	return stdout.String(), err
 }
+
+func getQueryRepos(repoNames []string) string {
+	var repos strings.Builder
+	for _, name := range repoNames {
+		repos.WriteString(fmt.Sprintf("repo:%s ", name))
+	}
+	return repos.String()
+}
diff --git a/main.go b/main.go
index e2020bd..2bee526 100644
--- a/main.go
+++ b/main.go
@@ -23,14 +23,16 @@ var (
 
 func main() {
 	var dryRun bool
+	var debug bool
 	flag.BoolVar(&dryRun, "dry-run", false, "Show branches to delete")
+	flag.BoolVar(&debug, "debug", false, "Enable debug logs")
 	flag.BoolVar(&dryRun, "check", false, "[Deprecated] Show branches to delete")
 	flag.Parse()
 
-	runMain(dryRun)
+	runMain(dryRun, debug)
 }
 
-func runMain(dryRun bool) {
+func runMain(dryRun bool, debug bool) {
 	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
 	defer stop()
 
@@ -38,13 +40,15 @@ func runMain(dryRun bool) {
 		fmt.Fprintf(color.Output, "%s\n", whiteBold("== DRY RUN =="))
 	}
 
-	connection := &conn.Connection{}
+	connection := &conn.Connection{Debug: debug}
 	sp := spinner.New(spinner.CharSets[14], 40*time.Millisecond)
 	defer sp.Stop()
 
 	fetchingMsg := " Fetching pull requests..."
 	sp.Suffix = fetchingMsg
-	sp.Start()
+	if !debug {
+		sp.Start()
+	}
 	var fetchingErr error
 
 	remote, err := GetRemote(ctx, connection)
@@ -72,7 +76,9 @@ func runMain(dryRun bool) {
 		fmt.Fprintf(color.Output, "%s%s\n", hiBlack("-"), deletingMsg)
 	} else {
 		sp.Suffix = deletingMsg
-		sp.Restart()
+		if !debug {
+			sp.Restart()
+		}
 
 		branches, deletingErr = DeleteBranches(ctx, branches, connection)
 		connection.PruneRemoteBranches(ctx, remote.Name)


Test patch:
diff --git a/main_test.go b/main_test.go
index 9acd110..1f0d14e 100644
--- a/main_test.go
+++ b/main_test.go
@@ -14,7 +14,7 @@ import (
 func Test_DeletingBranchesWhenTheDryRunOptionIsFalse(t *testing.T) {
 	onlyCI(t)
 
-	actual := captureOutput(func() { runMain(false) })
+	actual := captureOutput(func() { runMain(false, false) })
 
 	expected := fmt.Sprintf("%s %s", green("✔"), "Deleting branches...")
 	assert.Contains(t, actual, expected)
@@ -23,7 +23,7 @@ func Test_DeletingBranchesWhenTheDryRunOptionIsFalse(t *testing.T) {
 func Test_DoNotDeleteBranchesWhenTheDryRunOptionIsTrue(t *testing.T) {
 	onlyCI(t)
 
-	actual := captureOutput(func() { runMain(true) })
+	actual := captureOutput(func() { runMain(true, false) })
 
 	expected := fmt.Sprintf("%s %s", hiBlack("-"), "Deleting branches...")
 	assert.Contains(t, actual, expected)