From eb90dcd184ad95d6aa56ccfb32620417c61f79bc Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 17:52:02 +0900 Subject: [PATCH 01/13] =?UTF-8?q?=F0=9F=94=A8=20Use=20GOBIN=20instead=20of?= =?UTF-8?q?=20$(GOPATH)/bin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index faec5af..31cbbf8 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ test: go test -v ./... GOLANGCI_LINT_VERSION=v1.61.0 -GOLANGCI_LINT = $(shell go env GOPATH)/bin/golangci-lint +GOLANGCI_LINT = $(shell go env GOBIN)/golangci-lint $(GOLANGCI_LINT): go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) From fe54c65efc76ce01289173119c8cd23be7b0f4a3 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 17:56:49 +0900 Subject: [PATCH 02/13] =?UTF-8?q?=F0=9F=A9=B9=20Explicit=20embedded=20fiel?= =?UTF-8?q?d=20name=20because=20of=20lint=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/options.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/options.go b/core/options.go index 80f7572..2a72421 100644 --- a/core/options.go +++ b/core/options.go @@ -52,16 +52,16 @@ var optionTypes = func() []*opts.Definition[Options] { ), f.Bool("", "--skip-guard", "Skip the guard check for uncommitted changes and untracked files before executing command.", - func(o *Options) bool { return o.SkipGuard }, - func(o *Options) { o.SkipGuard = true }, + func(o *Options) bool { return o.GuardOptions.SkipGuard }, + func(o *Options) { o.GuardOptions.SkipGuard = true }, ), f.Bool("", "--skip-guard-uncommitted-changes", "Skip the guard check for uncommitted changes before executing command.", - func(o *Options) bool { return o.SkipGuardUncommittedChanges }, - func(o *Options) { o.SkipGuardUncommittedChanges = true }, + func(o *Options) bool { return o.GuardOptions.SkipGuardUncommittedChanges }, + func(o *Options) { o.GuardOptions.SkipGuardUncommittedChanges = true }, ), f.Bool("", "--skip-guard-untracked-files", "Skip the guard check for untracked files before executing command.", - func(o *Options) bool { return o.SkipGuardUntrackedFiles }, - func(o *Options) { o.SkipGuardUntrackedFiles = true }, + func(o *Options) bool { return o.GuardOptions.SkipGuardUntrackedFiles }, + func(o *Options) { o.GuardOptions.SkipGuardUntrackedFiles = true }, ), f.Bool("-D", "--debug-log", "Output debug log.", From e729ecb81847d5af150730dc78ad8511b5fa9445 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:00:22 +0900 Subject: [PATCH 03/13] =?UTF-8?q?=F0=9F=94=A8=20Upgrade=20golangci-lint=20?= =?UTF-8?q?from=20v1.61.0=20to=20v2.7.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 31cbbf8..67711ff 100644 --- a/Makefile +++ b/Makefile @@ -9,10 +9,10 @@ build: test: go test -v ./... -GOLANGCI_LINT_VERSION=v1.61.0 +GOLANGCI_LINT_VERSION=v2.7.2 GOLANGCI_LINT = $(shell go env GOBIN)/golangci-lint $(GOLANGCI_LINT): - go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) + go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) .PHONY: lint lint: $(GOLANGCI_LINT) From e4dbc58952b638ec85c1c1a2de9363ab62e04d08 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:12:11 +0900 Subject: [PATCH 04/13] =?UTF-8?q?=F0=9F=94=A7=20Add=20.golanci.yaml=20to?= =?UTF-8?q?=20suppress=20lint=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .golangci.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .golangci.yaml diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..b11263b --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,14 @@ +version: "2" +linters: + # Default: standard + # default: all + + disable: + - errcheck + - staticcheck + # exclusions: + # rules: + # # Exclude some linters from running on tests files. + # - path: _test\.go + # linters: + # - errcheck From 59c96823e78e06ec3acd482ec1f21cf2a719cbad Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:18:57 +0900 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=94=A8=20Add=20TEST=5FOPTS=20into?= =?UTF-8?q?=20Makefile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 67711ff..33abc44 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,11 @@ default: build lint test build: go build -o /dev/null . +TEST_OPTS= + .PHONY: test test: - go test -v ./... + go test $(TEST_OPTS) ./... GOLANGCI_LINT_VERSION=v2.7.2 GOLANGCI_LINT = $(shell go env GOBIN)/golangci-lint From 0d5d37c01c37c45078f0542e2af6ea9dbeabf62a Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:23:44 +0900 Subject: [PATCH 06/13] =?UTF-8?q?=E2=9C=85=20Add=20test=20for=20go=20mod?= =?UTF-8?q?=20edit=20-replace=20...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/options_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/options_test.go b/core/options_test.go index d71cd0f..8ec2557 100644 --- a/core/options_test.go +++ b/core/options_test.go @@ -178,6 +178,20 @@ func TestParseOptions(t *testing.T) { []string{}, "", }, + { + map[string]string{}, + []string{"go", "mod", "edit", "-replace", "foo=bar"}, + newExpected(), + []string{"go", "mod", "edit", "-replace", "foo=bar"}, + "", + }, + { + map[string]string{}, + []string{"-C", "foo/bar", "go", "mod", "edit", "-replace", "baz/qux=../../baz/qux"}, + newExpected(directory("foo/bar")), + []string{"go", "mod", "edit", "-replace", "baz/qux=../../baz/qux"}, + "", + }, } for _, ptn := range patterns { From 6850a503890bf50303785e2ee97e7fcbf29ee2ad Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:28:46 +0900 Subject: [PATCH 07/13] =?UTF-8?q?=E2=9C=A8=20slog=20=E3=82=92=E3=82=BB?= =?UTF-8?q?=E3=83=83=E3=83=88=E3=82=A2=E3=83=83=E3=83=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/main.go b/main.go index 321778a..35fad33 100644 --- a/main.go +++ b/main.go @@ -4,8 +4,10 @@ import ( "fmt" "os" "path/filepath" + "strings" "github.com/akm/git-exec/core" + "golang.org/x/exp/slog" ) func main() { @@ -14,6 +16,20 @@ func main() { os.Exit(1) } + logLevelMap := map[string]slog.Level{ + "debug": slog.LevelDebug, + "info": slog.LevelInfo, + "warn": slog.LevelWarn, + "error": slog.LevelError, + } + + logLevel, ok := logLevelMap[strings.ToLower(os.Getenv("LOG_LEVEL"))] + if !ok { + logLevel = slog.LevelWarn + } + logHandler := slog.TextHandler(os.Stderr, &slog.HandlerOptions{Level: logLevel}) + slog.SetDefault(slog.New(logHandler)) + options, commandArgs, err := core.ParseOptions(os.Args[1:]) if err != nil { fmt.Fprintf(os.Stderr, "Failed to parse arguments: %s\n", err.Error()) From 49360b3da11ab3ce3b283e41a1f0938182f5e4f2 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:31:30 +0900 Subject: [PATCH 08/13] =?UTF-8?q?=E2=9C=A8=20Add=20debug=20logging?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- command/standard_runner.go | 4 ++++ core/run.go | 2 ++ main.go | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/command/standard_runner.go b/command/standard_runner.go index 2b4bd38..dd1eb3f 100644 --- a/command/standard_runner.go +++ b/command/standard_runner.go @@ -3,6 +3,7 @@ package command import ( "bytes" "io" + "log/slog" "os" "os/exec" ) @@ -22,6 +23,9 @@ func NewStandardRunner(debugLog bool) *StandardRunner { func (x *StandardRunner) Run(c *Command) (rerr error) { cmd := exec.Command(c.Args[0], c.Args[1:]...) cmd.Env = append(os.Environ(), c.Envs...) + + slog.Debug("Executing command", "args", cmd.Args, "envs", c.Envs) + cmd.Stdin = os.Stdin var buf bytes.Buffer diff --git a/core/run.go b/core/run.go index dad12e3..f83056d 100644 --- a/core/run.go +++ b/core/run.go @@ -10,6 +10,8 @@ import ( ) func Run(options *Options, commandArgs []string) error { + slog.Debug("Run started", "options", options, "commandArgs", commandArgs) + var guardMessage string if guardResult, err := git.Guard(&options.GuardOptions); err != nil { return err diff --git a/main.go b/main.go index 35fad33..b31e054 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,12 @@ package main import ( "fmt" + "log/slog" "os" "path/filepath" "strings" "github.com/akm/git-exec/core" - "golang.org/x/exp/slog" ) func main() { @@ -27,7 +27,7 @@ func main() { if !ok { logLevel = slog.LevelWarn } - logHandler := slog.TextHandler(os.Stderr, &slog.HandlerOptions{Level: logLevel}) + logHandler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: logLevel}) slog.SetDefault(slog.New(logHandler)) options, commandArgs, err := core.ParseOptions(os.Args[1:]) From c5b27b4927c10ef19141915f1c11e5557310e821 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:32:44 +0900 Subject: [PATCH 09/13] =?UTF-8?q?=F0=9F=8E=89=20Bump=20version=20from=200.?= =?UTF-8?q?1.3=20to=200.1.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index 3735629..2f11253 100644 --- a/version.go +++ b/version.go @@ -2,7 +2,7 @@ package main import "fmt" -const Version = "0.1.3" +const Version = "0.1.4" func showVersion() { fmt.Println(Version) From ac828492f3eb9e1056bd037d627fe04f25ad9a2e Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:40:23 +0900 Subject: [PATCH 10/13] =?UTF-8?q?=E2=9C=85=20Add=20testcase=20for=20argume?= =?UTF-8?q?nt=20including=20equal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- command/command_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/command/command_test.go b/command/command_test.go index dc1b682..76b2602 100644 --- a/command/command_test.go +++ b/command/command_test.go @@ -18,6 +18,11 @@ func TestSplitArgsToEnvsAndCommand(t *testing.T) { []string{"key1=val1", "key2=val2"}, []string{"command", "--arg1", "arg2"}, }, + { + []string{"key1=val1", "command", "--arg1", "arg2", "key2=val2"}, + []string{"key1=val1"}, + []string{"command", "--arg1", "arg2", "key2=val2"}, + }, { []string{"command", "--arg1", "arg2"}, nil, From 5c3283ff0ffcb9aba22d85a74a7205303d83a392 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:45:22 +0900 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=90=9B=20Fix=20splitArgsToEnvsAndCo?= =?UTF-8?q?mmand=20to=20handle=20argument=20including=20equal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- command/command.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/command/command.go b/command/command.go index 287d33d..08f91f9 100644 --- a/command/command.go +++ b/command/command.go @@ -19,13 +19,14 @@ func NewCommand(args []string) *Command { } func splitArgsToEnvsAndCommand(args []string) ([]string, []string) { - equalNotFound := false + notEnvFound := false var a, b []string for _, arg := range args { - if !equalNotFound && strings.Contains(arg, "=") { + if !notEnvFound && strings.Contains(arg, "=") { a = append(a, arg) } else { b = append(b, arg) + notEnvFound = true } } return a, b From 92433cd497a0638119cc8a1f42347498dd68bf46 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:50:49 +0900 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=94=A7=20Update=20go=20versions=20f?= =?UTF-8?q?or=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce0e3fd..4a67b49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: # if: "!contains(github.event.head_commit.message, '[ci skip]')" strategy: matrix: - go: ["1.21", "1.22", "1.23"] + go: ["1.23", "1.24", "1.25"] name: Test on Go ${{ matrix.go }} steps: # https://github.com/actions/checkout From 5abdb6e85fbdede98a3eb360e093f16d964e17d7 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 14 Dec 2025 18:57:30 +0900 Subject: [PATCH 13/13] =?UTF-8?q?=F0=9F=94=A8=20GOBIN=20=E3=81=8C=E7=A9=BA?= =?UTF-8?q?=E3=81=AE=E5=A0=B4=E5=90=88=E3=81=AF=20$GOPATH/bin=20=E3=82=92?= =?UTF-8?q?=E4=BD=BF=E3=81=86=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub Actions Workflow では GOBIN が空なので。 --- Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 33abc44..404e8ab 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,16 @@ TEST_OPTS= test: go test $(TEST_OPTS) ./... +GOLANG_TOOL_GOBIN=$(shell go env GOBIN) +GOLANG_TOOL_GOPATH=$(shell go env GOPATH) +ifneq ($(GOLANG_TOOL_GOBIN),) +GOLANG_TOOL_PATH_TO_BIN=$(GOLANG_TOOL_GOBIN) +else +GOLANG_TOOL_PATH_TO_BIN=$(GOLANG_TOOL_GOPATH)/bin +endif + GOLANGCI_LINT_VERSION=v2.7.2 -GOLANGCI_LINT = $(shell go env GOBIN)/golangci-lint +GOLANGCI_LINT = $(GOLANG_TOOL_PATH_TO_BIN)/golangci-lint $(GOLANGCI_LINT): go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)