From 942106811e237d546992f63f3293a9e959671f95 Mon Sep 17 00:00:00 2001 From: tkrop Date: Fri, 8 Dec 2023 12:34:54 +0100 Subject: [PATCH] feat: refactore and improve code (#0) Signed-off-by: tkrop --- VERSION | 2 +- main.go | 328 +++++++++++------- main_test.go | 934 ++++++++++++++++++++++++++++++--------------------- 3 files changed, 753 insertions(+), 511 deletions(-) diff --git a/VERSION b/VERSION index bcab45a..81340c7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.3 +0.0.4 diff --git a/main.go b/main.go index 3ec653e..d16c85a 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,8 @@ package main //revive:disable:max-public-structs // keep it simple import ( - _ "embed" "encoding/json" + "errors" "fmt" "io" "os" @@ -11,11 +11,8 @@ import ( "regexp" "runtime" "runtime/debug" - "strconv" "strings" "time" - - "golang.org/x/exp/slices" ) var ( @@ -97,13 +94,13 @@ type Info struct { // NewDefaultInfo returns the build information of a command or module with // default values. func NewDefaultInfo() *Info { - return NewInfo(Path, Version, Revision, Build, Commit, Dirty) + return NewInfo(Path, Version, Revision, Build, Commit, true) } // NewInfo returns the build information of a command or module using given // custom version and custom build time using RFC3339 format. The provided // version must follow semantic versioning as supported by go. -func NewInfo(path, version, revision, build, commit, dirty string) *Info { +func NewInfo(path, version, revision, build, commit string, dirty bool) *Info { info := &Info{ Go: runtime.Version()[2:], Compiler: runtime.Compiler, @@ -114,7 +111,7 @@ func NewInfo(path, version, revision, build, commit, dirty string) *Info { info.Revision = revision info.Build, _ = time.Parse(time.RFC3339, build) info.Commit, _ = time.Parse(time.RFC3339, commit) - info.Dirty, _ = strconv.ParseBool(dirty) + info.Dirty = dirty if buildinfo, ok := debug.ReadBuildInfo(); ok { if path != "" { info.Path = path @@ -182,6 +179,17 @@ func NewMakeFilter(writer io.Writer) *MakeFilter { } } +// Printer provides a common interface for printing. +type Printer interface { + Fprintf(io.Writer, string, ...any) +} + +type DefaultPrinter struct{} + +func (*DefaultPrinter) Fprintf(writer io.Writer, format string, args ...any) { + fmt.Fprintf(writer, format, args...) +} + // Write writes the given data to the underlying writer. func (f *MakeFilter) Write(data []byte) (int, error) { return f.writer.Write(f.filter.ReplaceAll(data, []byte{})) //nolint:wrapcheck // not used @@ -191,34 +199,25 @@ func (f *MakeFilter) Write(data []byte) (int, error) { type CmdExecutor interface { // Exec executes the command with given name and arguments in given // directory redirecting stdout and stderr to given writers. - Exec(stdout, stderr io.Writer, dir, name string, args ...string) error - // Trace returns flags whether the command executor traces the command - // execution. - Trace() bool + Exec(stdout, stderr io.Writer, dir string, args ...string) error } // DefaultCmdExecutor provides a default command executor using `os/exec` // supporting optional tracing. -type DefaultCmdExecutor struct { - trace bool -} +type DefaultCmdExecutor struct{} -// NewCmdExecutor creates a new default command executor with given trace flag. -func NewCmdExecutor(trace bool) CmdExecutor { - return &DefaultCmdExecutor{trace: trace} +// NewCmdExecutor creates a new default command executor. +func NewCmdExecutor() CmdExecutor { + return &DefaultCmdExecutor{} } // Exec executes the command with given name and arguments in given directory // redirecting stdout and stderr to given writers. -func (e *DefaultCmdExecutor) Exec( - stdout, stderr io.Writer, dir, name string, args ...string, +func (*DefaultCmdExecutor) Exec( + stdout, stderr io.Writer, dir string, args ...string, ) error { - if e.trace { - fmt.Fprintf(stdout, "%s %s [%s]\n", - name, strings.Join(args, " "), dir) - } - - cmd := exec.Command(name, args...) + //#nosec G204 -- caller ensures safe commands + cmd := exec.Command(args[0], args[1:]...) cmd.Dir, cmd.Env = dir, os.Environ() cmd.Env = append(cmd.Env, "MAKE=go-make") cmd.Stdout, cmd.Stderr = stdout, stderr @@ -226,27 +225,12 @@ func (e *DefaultCmdExecutor) Exec( return cmd.Run() //nolint:wrapcheck // checked on next layer } -// Trace returns flags whether the command executor traces the command -// execution. -func (e *DefaultCmdExecutor) Trace() bool { - return e.trace -} - -// Printer provides a common interface for printing. -type Printer interface { - Fprintf(io.Writer, string, ...any) -} - -type DefaultPrinter struct{} - -func (*DefaultPrinter) Fprintf(writer io.Writer, format string, args ...any) { - fmt.Fprintf(writer, format, args...) -} - // Logger provides a common interface for logging. type Logger interface { // Logs the build information of the command or module to the given writer. Info(writer io.Writer, info *Info, raw bool) + // Exec logs the internal command execution for debugging to the given writer. + Exec(writer io.Writer, dir string, args ...string) // Logs the call of the command to the given writer. Call(writer io.Writer, args ...string) // Logs the given error message and error to the given writer. @@ -257,7 +241,7 @@ type Logger interface { // DefaultLogger provides a default logger using `fmt` and `json` package. type DefaultLogger struct { - // fmt provides the print formater. + // fmt provides the print formatter. fmt Printer } @@ -278,6 +262,11 @@ func (log *DefaultLogger) Info(writer io.Writer, info *Info, raw bool) { } } +// Exec logs the internal command execution for debugging to the given writer. +func (log *DefaultLogger) Exec(writer io.Writer, dir string, args ...string) { + log.fmt.Fprintf(writer, "exec: %s [%s]\n", strings.Join(args, " "), dir) +} + // Call logs the call of the command to the given writer. func (log *DefaultLogger) Call(writer io.Writer, args ...string) { log.fmt.Fprintf(writer, "call: %s\n", strings.Join(args, " ")) @@ -297,6 +286,59 @@ func (*DefaultLogger) Message(writer io.Writer, message string) { fmt.Fprintf(writer, "%s\n", message) } +var ( + // Base command array for `git clone` arguments. + cmdGitClone = []string{"git", "clone", "--depth=1"} + // Base command array for `git fetch` arguments. + cmdGitFetch = []string{"git", "fetch"} + // Base command array for `git reset --hard` arguments. + cmdGitHashReset = []string{"git", "reset", "--hard"} + // Base command array for `git rev-list --max-count=1` arguments. + cmdGitHashTag = []string{"git", "rev-list", "--max-count=1"} + // Base command array for `git rev-parse HEAD` arguments. + cmdGitHashHead = []string{"git", "rev-parse", "HEAD"} + // Base command array for `git log --max-count=1 --format="%H"` arguments. + cmdGitHashNow = []string{"git", "log", "--max-count=1", "--format=\"%H\""} +) + +// CmdGitClone creates the argument array of a `git clone` command of the given +// repository into the target directory. +func CmdGitClone(repo, dir string) []string { + return append(cmdGitClone, repo, dir) +} + +// CmdGitFetch creates the argument array of a `git fetch` command using the +// given source repository. +func CmdGitFetch(repo string) []string { + return append(cmdGitFetch, repo) +} + +// CmdGitHashReset creates the argument array of a `git reset --hard` command +// using the given revision hash. +func CmdGitHashReset(hash string) []string { + return append(cmdGitHashReset, hash) +} + +// CmdGitHashTag creates the argument array of a `git rev-list --max-count=1` +// command using the given target tag. +func CmdGitHashTag(tag string) []string { + return append(cmdGitHashTag, "tags/"+tag) +} + +func CmdGitHashHead() []string { + return cmdGitHashHead +} + +func CmdGitHashNow() []string { + return cmdGitHashNow +} + +// CmdMakeTargets creates the argument array of a `make --file +// ` command using the given makefile name amd argument list. +func CmdMakeTargets(file string, args ...string) []string { + return append([]string{"make", "--file", file}, args...) +} + // GoMake provides the default `go-make` application context. type GoMake struct { // Info provides the build information of go-make. @@ -315,12 +357,16 @@ type GoMake struct { Stdout io.Writer // Stderr provides the standard error writer. Stderr io.Writer + // Trace provides the flags to trace commands. + Trace bool + // Debug provides the flags to debug commands + Debug bool } // NewGoMake returns a new default `go-make` application context with given // standard output writer, standard error writer, and trace flag. func NewGoMake( - stdout, stderr io.Writer, info *Info, trace bool, + stdout, stderr io.Writer, info *Info, ) *GoMake { cmd, _ := os.Executable() cmdDir := cmd + ".config" @@ -332,130 +378,165 @@ func NewGoMake( CmdDir: cmdDir, WorkDir: workdir, Makefile: makefile, - Executor: NewCmdExecutor(trace), + Executor: NewCmdExecutor(), Logger: NewLogger(), Stdout: stdout, Stderr: stderr, } } -// Updates the go-make command. -func (gm *GoMake) updateGoMake() error { +// Updates the go-make command repository. +func (gm *GoMake) updateGoMakeRepo() error { + // Update by cloning the current revision. if _, err := os.Stat(gm.CmdDir); os.IsNotExist(err) { - if err := gm.cloneRepo(); err != nil { - return err - } else if err := gm.setRevision(); err != nil { - return err - } - return nil + return gm.cloneGoMakeRepo() } else if err != nil { - return ErrConfigFailure(gm.CmdDir, err) + return NewErrNotFound(gm.CmdDir, gm.Info.Revision, err) + } + + // Do never update on dirty revisions. + if gm.Info.Dirty { + return nil } - if gm.Info.Revision != "" { - if revision, err := gm.getRevision(); err != nil { + // Update revision checking for new commits. + if err := gm.updateRevision(); errors.Is(err, ErrNotFound) { + // Update revision again after fetching latest commits. + if err := gm.exec(gm.Stderr, gm.Stderr, gm.CmdDir, + CmdGitFetch(gm.Info.Repo)...); err != nil { return err - } else if strings.HasPrefix(revision, gm.Info.Revision) { - return nil } + return gm.updateRevision() + } else if err != nil { + return err } - return gm.updateRevision() + return nil } -// Clones the go-make command repository. -func (gm *GoMake) cloneRepo() error { - if err := gm.exec(gm.Stderr, gm.Stderr, gm.WorkDir, - "git", "clone", "--depth=1", gm.Info.Repo, gm.CmdDir); err != nil { +// cloneGoMakeRepo clones the go-make command repository. +func (gm *GoMake) cloneGoMakeRepo() error { + if err := gm.cloneGoMakeExec(gm.Info.Repo); err != nil { repo := "https://" + gm.Info.Path + ".git" - return gm.exec(gm.Stderr, gm.Stderr, gm.WorkDir, - "git", "clone", "--depth=1", repo, gm.CmdDir) + if err := gm.cloneGoMakeExec(repo); err != nil { + return err + } } - return nil + return gm.updateRevision() } -// Updates the go-make command repository. -func (gm *GoMake) updateRepo() error { - return gm.exec(gm.Stderr, gm.Stderr, gm.CmdDir, - "git", "fetch", gm.Info.Repo) +// cloneGoMakeExec executes the cloning of the go-make command repository. +func (gm *GoMake) cloneGoMakeExec(repo string) error { + return gm.exec(gm.Stderr, gm.Stderr, gm.WorkDir, + CmdGitClone(repo, gm.CmdDir)...) } -// Updates the go-make command repository revision. +// updateRevision updates the current revision of the go-make command +// repository as required by the go-make command. If the update fails the +// an error is returned. func (gm *GoMake) updateRevision() error { - if gm.Info.Dirty { - return nil - } else if err := gm.updateRepo(); err != nil { + if revision, err := gm.findRevision(); err != nil { return err + } else if ok, err := gm.isOnRevision(revision); err != nil { + return err + } else if !ok { + if err := gm.exec(gm.Stderr, gm.Stderr, gm.CmdDir, + CmdGitHashReset(revision)...); err != nil { + return NewErrNotFound(gm.CmdDir, revision, err) + } } - return gm.setRevision() + + return nil } -// Returns the current revision of the go-make command repository. -func (gm *GoMake) getRevision() (string, error) { - builder := strings.Builder{} - if err := gm.exec(&builder, gm.Stderr, gm.CmdDir, - "git", "rev-parse", "HEAD"); err != nil { - return "", err +// findRevision returns the current revision required by the go-make command +// as git commit hash. If the revision is a git tag, it is resolved to the +// respective git commit hash of the tag. If the resolution of the git hash +// fails the error is returned. +func (gm *GoMake) findRevision() (string, error) { + if gm.Info.Revision == "" { + builder := strings.Builder{} + if err := gm.exec(&builder, gm.Stderr, gm.CmdDir, + CmdGitHashHead()...); err != nil { + return "", err + } + return builder.String(), nil + } else if gm.Info.Version == gm.Info.Revision { + builder := strings.Builder{} + if err := gm.exec(&builder, gm.Stderr, gm.CmdDir, + CmdGitHashTag(gm.Info.Revision)...); err != nil { + return "", err + } + return builder.String(), nil } - return builder.String()[0:GitFullHashLen], nil + return gm.Info.Revision, nil } -// Sets the current revision of the go-make command repository. -func (gm *GoMake) setRevision() error { - revision := gm.Info.Revision - if revision == "" { - revision = "HEAD" +// isOnRevision returns whether the go-make config repository head commit hash +// is matching the revision required by the go-make command. If the resolution +// of the current hash fails the error is returned. +func (gm *GoMake) isOnRevision(hash string) (bool, error) { + builder := strings.Builder{} + err := gm.exec(&builder, gm.Stderr, gm.CmdDir, CmdGitHashNow()...) + if err != nil { + return false, err } - - return gm.exec(gm.Stderr, gm.Stderr, gm.CmdDir, - "git", "reset", "--hard", revision) + return strings.HasPrefix(builder.String(), hash), nil } -// Executes the provided make targets. -func (gm *GoMake) makeTarget(args ...string) error { - args = append([]string{"--file", gm.Makefile}, args...) - return gm.exec(gm.Stdout, gm.Stderr, gm.WorkDir, "make", args...) +// makeTargets executes the provided make targets. +func (gm *GoMake) makeTargets(args ...string) error { + return gm.exec(gm.Stdout, gm.Stderr, gm.WorkDir, + CmdMakeTargets(gm.Makefile, args...)...) } // Executes the command with given name and arguments in given directory // calling the command executor taking care to wrap the resulting error. func (gm *GoMake) exec( - stdout, stderr io.Writer, dir, name string, args ...string, + stdout, stderr io.Writer, dir string, args ...string, ) error { - err := gm.Executor.Exec(stdout, stderr, dir, name, args...) - if err != nil { - return ErrCallFailed(name, args, err) + if gm.Debug { + gm.Logger.Exec(stdout, dir, args...) + } + + if err := gm.Executor.Exec(stdout, stderr, dir, args...); err != nil { + return NewErrCallFailed(args, err) } return nil } // RunCmd runs the go-make command with given arguments. func (gm *GoMake) RunCmd(args ...string) error { - if gm.Executor.Trace() { - gm.Logger.Call(gm.Stderr, args...) - gm.Logger.Info(gm.Stderr, gm.Info, false) - } + for _, arg := range args { + switch arg { + case "--debug": + gm.Debug = true - switch { - case slices.Contains(args, "--version"): - gm.Logger.Info(gm.Stdout, gm.Info, false) - return nil + case "--trace": + gm.Logger.Call(gm.Stderr, args...) + gm.Logger.Info(gm.Stderr, gm.Info, false) + gm.Trace = true - case slices.Contains(args, "--completion=bash"): - gm.Logger.Message(gm.Stdout, BashCompletion) - return nil + case "--version": + gm.Logger.Info(gm.Stdout, gm.Info, false) + return nil + + case "--completion=bash": + gm.Logger.Message(gm.Stdout, BashCompletion) + return nil + } } - if err := gm.updateGoMake(); err != nil { - if !gm.Executor.Trace() { + if err := gm.updateGoMakeRepo(); err != nil { + if !gm.Trace { gm.Logger.Call(gm.Stderr, args...) gm.Logger.Info(gm.Stderr, gm.Info, false) } gm.Logger.Error(gm.Stderr, "update config", err) return err } - if err := gm.makeTarget(args...); err != nil { - if !gm.Executor.Trace() { + if err := gm.makeTargets(args...); err != nil { + if !gm.Trace { gm.Logger.Call(gm.Stderr, args...) gm.Logger.Info(gm.Stderr, gm.Info, false) } @@ -465,15 +546,19 @@ func (gm *GoMake) RunCmd(args ...string) error { return nil } -// ErrCallFailed wraps the error of a failed command call. -func ErrCallFailed(name string, args []string, err error) error { - return fmt.Errorf("call failed [name=%s, args=%v]: %w", - name, args, err) +// ErrNotFound represent a revision not found error. +var ErrNotFound = errors.New("revision not found") + +// NewErrNotFound wraps the error of failed command unable to find a revision. +func NewErrNotFound(dir, revision string, err error) error { + return fmt.Errorf("%w [dir=%s, revision=%s]: %w", + ErrNotFound, dir, revision, err) } -// ErrConfigFailure wraps the error of a failed config update. -func ErrConfigFailure(dir string, err error) error { - return fmt.Errorf("config failure [dir=%s]: %w", dir, err) +// NewErrCallFailed wraps the error of a failed command call. +func NewErrCallFailed(args []string, err error) error { + return fmt.Errorf("call failed [name=%s, args=%v]: %w", + args[0], args[1:], err) } // Run runs the go-make command with given build information, standard output @@ -483,8 +568,7 @@ func Run(info *Info, stdout, stderr io.Writer, args ...string) error { // TODO we would like to filter some make file startup specific // output that creates hard to validate output. // NewMakeFilter(stdout), NewMakeFilter(stderr), - stdout, stderr, - info, slices.Contains(args, "--trace"), + stdout, stderr, info, ).RunCmd(args[1:]...) } diff --git a/main_test.go b/main_test.go index 5749730..33794a0 100644 --- a/main_test.go +++ b/main_test.go @@ -23,6 +23,8 @@ import ( //revive:enable:line-length-limit const ( + // DirExist contains an arbitrary execution directory (use '.'). + DirExec = "." // GoMakeDirNew contains an arbitrary non-existing directory. GoMakeDirNew = "new-dir" // GoMakeDirExist contains an arbitrary existing directory (use build). @@ -31,38 +33,59 @@ const ( GoMakeGit = "git@github.com:tkrop/go-make" // GoMakeHTTP contains an arbitrary source repository for go-make. GoMakeHTTP = "https://github.com/tkrop/go-make.git" - // OtherRevision contains an arbitrary revision different from default. - OtherRevision = "x1b66f320c950b25fa63b81fd4e660c5d1f9d758" + // RevisionHead contains an arbitrary head revision. + RevisionHead = "1b66f320c950b25fa63b81fd4e660c5d1f9d758e" + // HeadRevision contains an arbitrary default revision. + RevisionDefault = "c0a7f81b82937ffe379ac39ece2925fa4d19fd40" + // RevisionOther contains an arbitrary different revision. + RevisionOther = "fbb61d4981d22b94412b906ea4d7ae3302d860d0" ) var ( - // DefaultInfo captured from once existing state. - DefaultInfo = main.NewInfo("github.com/tkrop/go-make", + // InfoDirty without version and revision hash. + InfoDirty = main.NewDefaultInfo() + + // InfoTag with version and revision hash from git. + InfoTag = main.NewInfo("github.com/tkrop/go-make", + "v1.1.1", + "v1.1.1", + "2023-11-14T13:02:46+01:00", + "2023-11-10T16:22:54+01:00", + false) + + // InfoHash with revision hash from git. + InfoHash = main.NewInfo("github.com/tkrop/go-make", "v0.0.0-20231110152254-1b66f320c950", - "1b66f320c950b25fa63b81fd4e660c5d1f9d758e", + RevisionDefault, "2023-11-14T13:02:46+01:00", "2023-11-10T16:22:54+01:00", - "false") + false) - // ShortInfo with hash to short captured from once existing state. - ShortInfo = main.NewInfo("github.com/tkrop/go-make", + // InfoShort with revision hash from git to short. + InfoShort = main.NewInfo("github.com/tkrop/go-make", "v0.0.0-20231110152254-1b66f320c950", - "1b66f320c950b25fa63b81fd4e660c5d1f9d758", + RevisionDefault[:20], "2023-11-14T13:02:46+01:00", "2023-11-10T16:22:54+01:00", - "false") + false) - // HeadInfo without hash captured from once existing state. - HeadInfo = main.NewInfo("github.com/tkrop/go-make", + // InfoHead without revision hash from git. + InfoHead = main.NewInfo("github.com/tkrop/go-make", "v0.0.0-20231110152254-1b66f320c950", "", "2023-11-14T13:02:46+01:00", "2023-11-10T16:22:54+01:00", - "false") + false) - // NewInfo captured created after installing. - NewInfo = main.NewDefaultInfo() + ArgsVersion = []string{"--version"} + ArgsBash = []string{"--completion=bash"} + ArgsTarget = []string{"target"} + ArgsDebugTarget = []string{"--debug", "target"} + ArgsTraceVersion = []string{"--trace", "--version"} + ArgsTraceBash = []string{"--trace", "--completion=bash"} + ArgsTraceTarget = []string{"--trace", "target"} + // Any error that can happen. errAny = errors.New("any error") ) @@ -76,14 +99,10 @@ func GoMakeSetup( SetArg("builder", &strings.Builder{}). Expect(param.mockSetup) - if param.info == nil { - param.info = DefaultInfo - } - gm := main.NewGoMake( mocks.GetArg("stdout").(io.Writer), mocks.GetArg("stderr").(io.Writer), - param.info, false, + param.info, ) if param.goMakeDir == "" { @@ -94,7 +113,7 @@ func GoMakeSetup( gm.Logger = mock.Get(mocks, NewMockLogger) gm.Makefile = main.Makefile gm.CmdDir = param.goMakeDir - gm.WorkDir = "." + gm.WorkDir = DirExec return gm, mocks } @@ -103,20 +122,13 @@ func ToAny(args ...any) []any { return args } -func Trace(trace bool) mock.SetupFunc { - return func(mocks *mock.Mocks) any { - return mock.Get(mocks, NewMockCmdExecutor).EXPECT(). - Trace().DoAndReturn(mocks.Do(main.CmdExecutor.Trace, trace)) - } -} - func Exec( //revive:disable:argument-limit - stdout, stderr string, dir, name string, + stdout, stderr string, dir string, args []string, err error, sout, serr string, ) mock.SetupFunc { return func(mocks *mock.Mocks) any { return mock.Get(mocks, NewMockCmdExecutor).EXPECT(). - Exec(mocks.GetArg(stdout), mocks.GetArg(stderr), dir, name, ToAny(args)...). + Exec(mocks.GetArg(stdout), mocks.GetArg(stderr), dir, ToAny(args)...). DoAndReturn(mocks.Call(main.CmdExecutor.Exec, func(args ...any) []any { if _, err := args[0].(io.Writer).Write([]byte(sout)); err != nil { @@ -138,6 +150,14 @@ func LogCall(writer string, args []string) mock.SetupFunc { } } +func LogExec(writer string, dir string, args []string) mock.SetupFunc { + return func(mocks *mock.Mocks) any { + return mock.Get(mocks, NewMockLogger).EXPECT(). + Exec(mocks.GetArg(writer), dir, ToAny(args)...). + DoAndReturn(mocks.Do(main.Logger.Exec)) + } +} + func LogInfo(writer string, info *main.Info, raw bool) mock.SetupFunc { return func(mocks *mock.Mocks) any { return mock.Get(mocks, NewMockLogger).EXPECT(). @@ -171,408 +191,546 @@ type MainParams struct { } var testMainParams = map[string]MainParams{ - // successful options without trace. + // dirty option targets without trace. + "check go-make completion bash": { + mockSetup: mock.Chain( + LogMessage("stdout", main.BashCompletion), + ), + args: ArgsBash, + }, "check go-make version": { - mockSetup: mock.Chain(Trace(false), - LogInfo("stdout", DefaultInfo, false), + mockSetup: mock.Chain( + LogInfo("stdout", InfoDirty, false), ), - args: []string{"--version"}, + info: InfoDirty, + args: ArgsVersion, }, - "check new go-make version": { - mockSetup: mock.Chain(Trace(false), - LogInfo("stdout", NewInfo, false), + "dirty go-make to run target": { + mockSetup: mock.Chain( + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), nil, "", ""), ), - info: NewInfo, - args: []string{"--version"}, + info: InfoDirty, + args: ArgsTarget, }, - "check go-make completion bash": { - mockSetup: mock.Chain(Trace(false), - LogMessage("stdout", main.BashCompletion), + "dirty go-make failed": { + mockSetup: mock.Chain( + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), errAny, "", ""), + LogCall("stderr", ArgsTarget), + LogInfo("stderr", InfoDirty, false), + LogError("stderr", "execute make", main.NewErrCallFailed( + main.CmdMakeTargets(main.Makefile, ArgsTarget...), errAny)), ), - args: []string{"--completion=bash"}, + info: InfoDirty, + args: ArgsTarget, + expectError: main.NewErrCallFailed( + main.CmdMakeTargets(main.Makefile, ArgsTarget...), errAny), }, - // successful options without trace. - "check go-make version with trace": { - mockSetup: mock.Chain(Trace(true), - LogCall("stderr", []string{"--trace", "--version"}), - LogInfo("stderr", DefaultInfo, false), - LogInfo("stdout", DefaultInfo, false), + "clone go-make clone failed": { + mockSetup: mock.Chain( + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), errAny, "", ""), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), errAny, "", ""), + LogCall("stderr", ArgsTarget), + LogInfo("stderr", InfoDirty, false), + LogError("stderr", "update config", main.NewErrCallFailed( + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), errAny)), ), - args: []string{"--trace", "--version"}, + info: InfoDirty, + args: ArgsTarget, + goMakeDir: GoMakeDirNew, + expectError: main.NewErrCallFailed( + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), errAny), }, - "check go-make completion bash with trace": { - mockSetup: mock.Chain(Trace(true), - LogCall("stderr", []string{"--trace", "--completion=bash"}), - LogInfo("stderr", DefaultInfo, false), + // dirty option targets with trace. + "check go-make completion bash traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceBash), + LogInfo("stderr", InfoDirty, false), LogMessage("stderr", main.BashCompletion), ), - args: []string{"--trace", "--completion=bash"}, + info: InfoDirty, + args: ArgsTraceBash, + }, + "check go-make version traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceVersion), + LogInfo("stderr", InfoDirty, false), + LogInfo("stderr", InfoDirty, false), + ), + info: InfoDirty, + args: ArgsTraceVersion, + }, + "dirty go-make to run target traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoDirty, false), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), nil, "", ""), + ), + info: InfoDirty, + args: ArgsTraceTarget, + }, + "dirty go-make failed traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoDirty, false), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), errAny, "", ""), + LogError("stderr", "execute make", main.NewErrCallFailed( + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), errAny)), + ), + info: InfoDirty, + args: ArgsTraceTarget, + expectError: main.NewErrCallFailed( + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), errAny), + }, + "clone go-make failed traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoDirty, false), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), errAny, "", ""), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), errAny, "", ""), + LogError("stderr", "update config", main.NewErrCallFailed( + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), errAny)), + ), + info: InfoDirty, + args: ArgsTraceTarget, + goMakeDir: GoMakeDirNew, + expectError: main.NewErrCallFailed( + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), errAny), }, - // successful targets without trace. - "check go-make to run target": { - mockSetup: mock.Chain(Trace(false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, DefaultInfo.Revision, ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "target"}, nil, "", ""), + // dirty option targets with debug. + "dirty go-make to run target debugged": { + mockSetup: mock.Chain( + LogExec("stdout", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsDebugTarget...)), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsDebugTarget...), nil, "", ""), ), - args: []string{"target"}, + info: InfoDirty, + args: ArgsDebugTarget, }, - "fetch and reset go-make to run target": { - mockSetup: mock.Chain(Trace(false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, OtherRevision, ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"fetch", GoMakeGit}, nil, "", ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "target"}, nil, "", ""), + "dirty go-make failed debugged": { + mockSetup: mock.Chain( + LogExec("stdout", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsDebugTarget...)), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsDebugTarget...), errAny, "", ""), + LogCall("stderr", ArgsDebugTarget), + LogInfo("stderr", InfoDirty, false), + LogError("stderr", "execute make", main.NewErrCallFailed( + main.CmdMakeTargets(main.Makefile, ArgsDebugTarget...), errAny)), ), - args: []string{"target"}, + info: InfoDirty, + args: ArgsDebugTarget, + expectError: main.NewErrCallFailed( + main.CmdMakeTargets(main.Makefile, ArgsDebugTarget...), errAny), }, - "fetch and reset head go-make to run target": { - mockSetup: mock.Chain(Trace(false), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"fetch", GoMakeGit}, nil, "", ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"reset", "--hard", "HEAD"}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "target"}, nil, "", ""), + "clone go-make clone failed debugged": { + mockSetup: mock.Chain( + LogExec("stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew)), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), errAny, "", ""), + LogExec("stderr", DirExec, + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew)), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), errAny, "", ""), + LogCall("stderr", ArgsDebugTarget), + LogInfo("stderr", InfoDirty, false), + LogError("stderr", "update config", main.NewErrCallFailed( + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), errAny)), ), - info: HeadInfo, - args: []string{"target"}, + info: InfoDirty, + args: ArgsDebugTarget, + goMakeDir: GoMakeDirNew, + expectError: main.NewErrCallFailed( + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), errAny), }, - "clone and reset go-make to run target": { - mockSetup: mock.Chain(Trace(false), - Exec("stderr", "stderr", ".", "git", - []string{"clone", "--depth=1", GoMakeGit, GoMakeDirNew}, - nil, "", ""), - Exec("stderr", "stderr", GoMakeDirNew, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "target"}, nil, "", ""), + // clone targets without trace. + "clone go-make reset failed": { + mockSetup: mock.Chain( + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), nil, "", ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashNow(), nil, RevisionOther, ""), + Exec("stderr", "stderr", GoMakeDirNew, + main.CmdGitHashReset(InfoHash.Revision), errAny, "", ""), + LogCall("stderr", ArgsTarget), + LogInfo("stderr", InfoHash, false), + LogError("stderr", "update config", + main.NewErrNotFound(GoMakeDirNew, InfoHash.Revision, + main.NewErrCallFailed(main.CmdGitHashReset(InfoHash.Revision), + errAny))), ), + info: InfoHash, + args: ArgsTarget, goMakeDir: GoMakeDirNew, - args: []string{"target"}, - }, - - "clone fallback and reset go-make to run target": { - mockSetup: mock.Chain(Trace(false), - Exec("stderr", "stderr", ".", "git", []string{ - "clone", "--depth=1", - GoMakeGit, GoMakeDirNew, - }, errAny, "", ""), - Exec("stderr", "stderr", ".", "git", []string{ - "clone", "--depth=1", - GoMakeHTTP, GoMakeDirNew, - }, nil, "", ""), - Exec("stderr", "stderr", GoMakeDirNew, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "target"}, nil, "", ""), + expectError: main.NewErrNotFound(GoMakeDirNew, InfoHash.Revision, + main.NewErrCallFailed(main.CmdGitHashReset(InfoHash.Revision), errAny)), + }, + + "clone go-make head to run target": { + mockSetup: mock.Chain( + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), nil, "", ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashHead(), nil, RevisionHead, ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), + nil, "", ""), ), + info: InfoHead, + args: ArgsTarget, goMakeDir: GoMakeDirNew, - args: []string{"target"}, - }, - - // successful targets with trace. - "check go-make to run target with trace": { - mockSetup: mock.Chain(Trace(true), - LogCall("stderr", []string{"--trace", "target"}), - LogInfo("stderr", DefaultInfo, false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, DefaultInfo.Revision, ""), - Exec("stdout", "stderr", ".", "make", []string{ - "--file", main.Makefile, "--trace", "target", - }, nil, "", ""), - ), - args: []string{"--trace", "target"}, - }, - - "fetch and reset go-make to run target with trace": { - mockSetup: mock.Chain(Trace(true), - LogCall("stderr", []string{"--trace", "target"}), - LogInfo("stderr", DefaultInfo, false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, OtherRevision, ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"fetch", GoMakeGit}, nil, "", ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "--trace", "target"}, nil, "", ""), - ), - args: []string{"--trace", "target"}, - }, - - "clone and reset go-make to run target with trace": { - mockSetup: mock.Chain(Trace(true), - LogCall("stderr", []string{"--trace", "target"}), - LogInfo("stderr", DefaultInfo, false), - Exec("stderr", "stderr", ".", "git", - []string{"clone", "--depth=1", GoMakeGit, GoMakeDirNew}, + }, + + "clone go-make hash to run target": { + mockSetup: mock.Chain( + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), nil, "", ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashNow(), nil, RevisionOther, ""), + Exec("stderr", "stderr", GoMakeDirNew, + main.CmdGitHashReset(InfoHash.Revision), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), nil, "", ""), - Exec("stderr", "stderr", GoMakeDirNew, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "--trace", "target"}, nil, "", ""), ), + info: InfoHash, + args: ArgsTarget, goMakeDir: GoMakeDirNew, - args: []string{"--trace", "target"}, - }, - - "clone fallback and reset go-make to run target with trace": { - mockSetup: mock.Chain(Trace(true), - LogCall("stderr", []string{"--trace", "target"}), - LogInfo("stderr", DefaultInfo, false), - Exec("stderr", "stderr", ".", "git", []string{ - "clone", "--depth=1", - GoMakeGit, GoMakeDirNew, - }, errAny, "", ""), - Exec("stderr", "stderr", ".", "git", []string{ - "clone", "--depth=1", - GoMakeHTTP, GoMakeDirNew, - }, nil, "", ""), - Exec("stderr", "stderr", GoMakeDirNew, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "--trace", "target"}, nil, "", ""), + }, + + "clone go-make tag to run target": { + mockSetup: mock.Chain( + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), nil, "", ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashTag(InfoTag.Revision), nil, RevisionOther, ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stderr", "stderr", GoMakeDirNew, + main.CmdGitHashReset(RevisionOther), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), + nil, "", ""), ), + info: InfoTag, + args: ArgsTarget, goMakeDir: GoMakeDirNew, - args: []string{"--trace", "target"}, - }, - - // failed targets without trace. - "check go-make to run target failed": { - mockSetup: mock.Chain(Trace(false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, DefaultInfo.Revision, ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "target"}, errAny, "", ""), - Trace(false), - LogCall("stderr", []string{"target"}), - LogInfo("stderr", DefaultInfo, false), - LogError("stderr", "execute make", main.ErrCallFailed("make", - []string{"--file", main.Makefile, "target"}, errAny)), - ), - args: []string{"target"}, - expectError: main.ErrCallFailed("make", []string{ - "--file", main.Makefile, "target", - }, errAny), - }, - - "fetch and reset go-make to run target failed": { - mockSetup: mock.Chain(Trace(false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, OtherRevision, ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"fetch", GoMakeGit}, nil, "", ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "target"}, errAny, "", ""), - Trace(false), - LogCall("stderr", []string{"target"}), - LogInfo("stderr", DefaultInfo, false), - LogError("stderr", "execute make", main.ErrCallFailed("make", - []string{"--file", main.Makefile, "target"}, errAny)), - ), - args: []string{"target"}, - expectError: main.ErrCallFailed("make", []string{ - "--file", main.Makefile, "target", - }, errAny), - }, - - "clone and reset go-make to run target failed": { - mockSetup: mock.Chain(Trace(false), - Exec("stderr", "stderr", ".", "git", - []string{"clone", "--depth=1", GoMakeGit, GoMakeDirNew}, + }, + + "clone go-make fallback to run target": { + mockSetup: mock.Chain( + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), errAny, "", ""), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), nil, "", ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashNow(), nil, RevisionOther, ""), + Exec("stderr", "stderr", GoMakeDirNew, + main.CmdGitHashReset(InfoHash.Revision), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), nil, "", ""), - Exec("stderr", "stderr", GoMakeDirNew, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "target"}, errAny, "", ""), - Trace(false), - LogCall("stderr", []string{"target"}), - LogInfo("stderr", DefaultInfo, false), - LogError("stderr", "execute make", main.ErrCallFailed("make", - []string{"--file", main.Makefile, "target"}, errAny)), ), + info: InfoHash, + args: ArgsTarget, goMakeDir: GoMakeDirNew, - args: []string{"target"}, - expectError: main.ErrCallFailed("make", []string{ - "--file", main.Makefile, "target", - }, errAny), - }, - - // failed targets with trace. - "check go-make to run target with trace failed": { - mockSetup: mock.Chain(Trace(true), - LogCall("stderr", []string{"--trace", "target"}), - LogInfo("stderr", DefaultInfo, false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, DefaultInfo.Revision, ""), - Exec("stdout", "stderr", ".", "make", []string{ - "--file", main.Makefile, "--trace", "target", - }, errAny, "", ""), - Trace(true), - LogError("stderr", "execute make", main.ErrCallFailed("make", - []string{"--file", main.Makefile, "--trace", "target"}, errAny)), - ), - args: []string{"--trace", "target"}, - expectError: main.ErrCallFailed("make", []string{ - "--file", main.Makefile, "--trace", "target", - }, errAny), - }, - - "fetch and reset go-make to run target with trace failed": { - mockSetup: mock.Chain(Trace(true), - LogCall("stderr", []string{"--trace", "target"}), - LogInfo("stderr", DefaultInfo, false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, OtherRevision, ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"fetch", GoMakeGit}, nil, "", ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "--trace", "target"}, errAny, "", ""), - Trace(true), - LogError("stderr", "execute make", main.ErrCallFailed("make", - []string{"--file", main.Makefile, "--trace", "target"}, errAny)), - ), - args: []string{"--trace", "target"}, - expectError: main.ErrCallFailed("make", []string{ - "--file", main.Makefile, "--trace", "target", - }, errAny), - }, - - "clone and reset go-make to run target with trace failed": { - mockSetup: mock.Chain(Trace(true), - LogCall("stderr", []string{"--trace", "target"}), - LogInfo("stderr", DefaultInfo, false), - Exec("stderr", "stderr", ".", "git", - []string{"clone", "--depth=1", GoMakeGit, GoMakeDirNew}, + }, + + // clone targets with trace. + "clone go-make head to run target traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoHead, false), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), nil, "", ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashHead(), nil, RevisionHead, ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), nil, "", ""), - Exec("stderr", "stderr", GoMakeDirNew, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, nil, "", ""), - Exec("stdout", "stderr", ".", "make", - []string{"--file", main.Makefile, "--trace", "target"}, errAny, "", ""), - Trace(true), - LogError("stderr", "execute make", main.ErrCallFailed("make", - []string{"--file", main.Makefile, "--trace", "target"}, errAny)), ), + info: InfoHead, + args: ArgsTraceTarget, goMakeDir: GoMakeDirNew, - args: []string{"--trace", "target"}, - expectError: main.ErrCallFailed("make", []string{ - "--file", main.Makefile, "--trace", "target", - }, errAny), - }, - - // failed setup without trace. - "check go-make failed": { - mockSetup: mock.Chain(Trace(false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, errAny, "", ""), - Trace(false), - LogCall("stderr", []string{"target"}), - LogInfo("stderr", DefaultInfo, false), - LogError("stderr", "update config", main.ErrCallFailed("git", - []string{"rev-parse", "HEAD"}, errAny)), - ), - args: []string{"target"}, - expectError: main.ErrCallFailed("git", - []string{"rev-parse", "HEAD"}, errAny), - }, - - "fetch go-make failed": { - mockSetup: mock.Chain(Trace(false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, OtherRevision, ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"fetch", GoMakeGit}, errAny, "", ""), - Trace(false), - LogCall("stderr", []string{"target"}), - LogInfo("stderr", DefaultInfo, false), - LogError("stderr", "update config", main.ErrCallFailed("git", - []string{"fetch", GoMakeGit}, errAny)), - ), - args: []string{"target"}, - expectError: main.ErrCallFailed("git", []string{"fetch", GoMakeGit}, errAny), - }, - - "fetch and reset go-make failed": { - mockSetup: mock.Chain(Trace(false), - Exec("builder", "stderr", GoMakeDirExist, "git", - []string{"rev-parse", "HEAD"}, nil, OtherRevision, ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"fetch", GoMakeGit}, nil, "", ""), - Exec("stderr", "stderr", GoMakeDirExist, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, errAny, "", ""), - Trace(false), - LogCall("stderr", []string{"target"}), - LogInfo("stderr", DefaultInfo, false), - LogError("stderr", "update config", main.ErrCallFailed("git", - []string{"reset", "--hard", DefaultInfo.Revision}, errAny)), + }, + + "clone go-make hash to run target traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoHash, false), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), nil, "", ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashNow(), nil, RevisionOther, ""), + Exec("stderr", "stderr", GoMakeDirNew, + main.CmdGitHashReset(InfoHash.Revision), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), + nil, "", ""), ), - goMakeDir: GoMakeDirExist, - args: []string{"target"}, - expectError: main.ErrCallFailed("git", - []string{"reset", "--hard", DefaultInfo.Revision}, errAny), - }, - - "clone fallback go-make failed": { - mockSetup: mock.Chain(Trace(false), - Exec("stderr", "stderr", ".", "git", []string{ - "clone", "--depth=1", - GoMakeGit, GoMakeDirNew, - }, errAny, "", ""), - Exec("stderr", "stderr", ".", "git", []string{ - "clone", "--depth=1", - GoMakeHTTP, GoMakeDirNew, - }, errAny, "", ""), - Trace(false), - LogCall("stderr", []string{"target"}), - LogInfo("stderr", DefaultInfo, false), - LogError("stderr", "update config", main.ErrCallFailed("git", - []string{"clone", "--depth=1", GoMakeHTTP, GoMakeDirNew}, errAny)), + info: InfoHash, + args: ArgsTraceTarget, + goMakeDir: GoMakeDirNew, + }, + + "clone go-make tag to run target traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoTag, false), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), nil, "", ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashTag(InfoTag.Revision), nil, RevisionOther, ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stderr", "stderr", GoMakeDirNew, + main.CmdGitHashReset(RevisionOther), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), + nil, "", ""), ), + info: InfoTag, + args: ArgsTraceTarget, goMakeDir: GoMakeDirNew, - args: []string{"target"}, - expectError: main.ErrCallFailed("git", - []string{"clone", "--depth=1", GoMakeHTTP, GoMakeDirNew}, errAny), - }, - - "clone fallback and reset go-make failed": { - mockSetup: mock.Chain(Trace(false), - Exec("stderr", "stderr", ".", "git", []string{ - "clone", "--depth=1", - GoMakeGit, GoMakeDirNew, - }, errAny, "", ""), - Exec("stderr", "stderr", ".", "git", []string{ - "clone", "--depth=1", - GoMakeHTTP, GoMakeDirNew, - }, nil, "", ""), - Exec("stderr", "stderr", GoMakeDirNew, "git", - []string{"reset", "--hard", DefaultInfo.Revision}, errAny, "", ""), - Trace(false), - LogCall("stderr", []string{"target"}), - LogInfo("stderr", DefaultInfo, false), - LogError("stderr", "update config", main.ErrCallFailed("git", - []string{"reset", "--hard", DefaultInfo.Revision}, errAny)), + }, + + "clone go-make fallback to run target traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoHash, false), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeGit, GoMakeDirNew), errAny, "", ""), + Exec("stderr", "stderr", DirExec, + main.CmdGitClone(GoMakeHTTP, GoMakeDirNew), nil, "", ""), + Exec("builder", "stderr", GoMakeDirNew, + main.CmdGitHashNow(), nil, RevisionOther, ""), + Exec("stderr", "stderr", GoMakeDirNew, + main.CmdGitHashReset(InfoHash.Revision), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), + nil, "", ""), ), + info: InfoHash, + args: ArgsTraceTarget, goMakeDir: GoMakeDirNew, - args: []string{"target"}, - expectError: main.ErrCallFailed("git", - []string{"reset", "--hard", DefaultInfo.Revision}, errAny), + }, + + // check targets without trace. + "check go-make head hash failed": { + mockSetup: mock.Chain( + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashHead(), errAny, "", ""), + LogCall("stderr", ArgsTarget), + LogInfo("stderr", InfoHead, false), + LogError("stderr", "update config", main.NewErrCallFailed( + main.CmdGitHashHead(), errAny)), + ), + info: InfoHead, + args: ArgsTarget, + goMakeDir: GoMakeDirExist, + expectError: main.NewErrCallFailed(main.CmdGitHashHead(), errAny), + }, + + "check go-make head now failed": { + mockSetup: mock.Chain( + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashHead(), nil, RevisionHead, ""), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), errAny, "", ""), + LogCall("stderr", ArgsTarget), + LogInfo("stderr", InfoHead, false), + LogError("stderr", "update config", main.NewErrCallFailed( + main.CmdGitHashNow(), errAny)), + ), + info: InfoHead, + args: ArgsTarget, + goMakeDir: GoMakeDirExist, + expectError: main.NewErrCallFailed(main.CmdGitHashNow(), errAny), + }, + + "check go-make tag log failed": { + mockSetup: mock.Chain( + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashTag(InfoTag.Revision), errAny, RevisionDefault, ""), + LogCall("stderr", ArgsTarget), + LogInfo("stderr", InfoTag, false), + LogError("stderr", "update config", main.NewErrCallFailed( + main.CmdGitHashTag(InfoTag.Revision), errAny)), + ), + info: InfoTag, + args: ArgsTarget, + goMakeDir: GoMakeDirExist, + expectError: main.NewErrCallFailed( + main.CmdGitHashTag(InfoTag.Revision), errAny), + }, + + "check go-make tag fetch failed": { + mockSetup: mock.Chain( + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashTag(InfoTag.Revision), nil, RevisionDefault, ""), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stderr", "stderr", GoMakeDirExist, + main.CmdGitHashReset(RevisionDefault), + main.NewErrNotFound(GoMakeDirExist, RevisionDefault, errAny), "", ""), + Exec("stderr", "stderr", GoMakeDirExist, + main.CmdGitFetch(InfoTag.Repo), errAny, "", ""), + LogCall("stderr", ArgsTarget), + LogInfo("stderr", InfoTag, false), + LogError("stderr", "update config", main.NewErrCallFailed( + main.CmdGitFetch(InfoTag.Repo), errAny)), + ), + info: InfoTag, + args: ArgsTarget, + goMakeDir: GoMakeDirExist, + expectError: main.NewErrCallFailed(main.CmdGitFetch(InfoTag.Repo), errAny), + }, + + "check go-make head to run target": { + mockSetup: mock.Chain( + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashHead(), nil, RevisionHead, ""), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), + nil, "", ""), + ), + info: InfoHead, + args: ArgsTarget, + goMakeDir: GoMakeDirExist, + }, + + "check go-make hash to run target": { + mockSetup: mock.Chain( + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stderr", "stderr", GoMakeDirExist, + main.CmdGitHashReset(InfoHash.Revision), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), + nil, "", ""), + ), + info: InfoHash, + args: ArgsTarget, + goMakeDir: GoMakeDirExist, + }, + + "check go-make tag to run target": { + mockSetup: mock.Chain( + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashTag(InfoTag.Revision), nil, RevisionDefault, ""), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stderr", "stderr", GoMakeDirExist, + main.CmdGitHashReset(RevisionDefault), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), + nil, "", ""), + ), + info: InfoTag, + args: ArgsTarget, + goMakeDir: GoMakeDirExist, + }, + + "check go-make tag fetch to run target": { + mockSetup: mock.Chain( + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashTag(InfoTag.Revision), nil, RevisionDefault, ""), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stderr", "stderr", GoMakeDirExist, + main.CmdGitHashReset(RevisionDefault), + main.NewErrNotFound(GoMakeDirExist, RevisionDefault, errAny), "", ""), + Exec("stderr", "stderr", GoMakeDirExist, + main.CmdGitFetch(InfoTag.Repo), nil, "", ""), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashTag(InfoTag.Revision), nil, RevisionDefault, ""), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stderr", "stderr", GoMakeDirExist, + main.CmdGitHashReset(RevisionDefault), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTarget...), + nil, "", ""), + ), + info: InfoTag, + args: ArgsTarget, + goMakeDir: GoMakeDirExist, + }, + + // check targets with trace. + "check go-make head to run target traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoHead, false), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashHead(), nil, RevisionHead, ""), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), + nil, "", ""), + ), + info: InfoHead, + args: ArgsTraceTarget, + goMakeDir: GoMakeDirExist, + }, + + "check go-make hash to run target traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoHash, false), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stderr", "stderr", GoMakeDirExist, + main.CmdGitHashReset(InfoHash.Revision), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), + nil, "", ""), + ), + info: InfoHash, + args: ArgsTraceTarget, + goMakeDir: GoMakeDirExist, + }, + + "check go-make tag to run target traced": { + mockSetup: mock.Chain( + LogCall("stderr", ArgsTraceTarget), + LogInfo("stderr", InfoTag, false), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashTag(InfoTag.Revision), nil, RevisionDefault, ""), + Exec("builder", "stderr", GoMakeDirExist, + main.CmdGitHashNow(), nil, RevisionHead, ""), + Exec("stderr", "stderr", GoMakeDirExist, + main.CmdGitHashReset(RevisionDefault), nil, "", ""), + Exec("stdout", "stderr", DirExec, + main.CmdMakeTargets(main.Makefile, ArgsTraceTarget...), + nil, "", ""), + ), + info: InfoTag, + args: ArgsTraceTarget, + goMakeDir: GoMakeDirExist, }, } @@ -630,7 +788,7 @@ func TestMainTargets(t *testing.T) { t.Cleanup(func() { os.RemoveAll(cmdDir) }) - err = exec.Command("cp", "--recursive", ".", cmdDir).Run() + err = exec.Command("cp", "--recursive", DirExec, cmdDir).Run() assert.NoError(t, err) test.Map(t, testMainTargetParams).