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 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 diff --git a/Makefile b/Makefile index faec5af..404e8ab 100644 --- a/Makefile +++ b/Makefile @@ -5,14 +5,24 @@ default: build lint test build: go build -o /dev/null . +TEST_OPTS= + .PHONY: test test: - go test -v ./... - -GOLANGCI_LINT_VERSION=v1.61.0 -GOLANGCI_LINT = $(shell go env GOPATH)/bin/golangci-lint + 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 = $(GOLANG_TOOL_PATH_TO_BIN)/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) 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 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, 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/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.", 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 { 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 321778a..b31e054 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,10 @@ package main import ( "fmt" + "log/slog" "os" "path/filepath" + "strings" "github.com/akm/git-exec/core" ) @@ -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.NewTextHandler(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()) 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)