mirror of
https://github.com/go-task/task.git
synced 2025-03-17 21:08:01 +02:00
Expose timestamp and checksum to status
This commit is contained in:
parent
613dfe06d3
commit
1ee684b7c0
@ -340,6 +340,16 @@ tasks:
|
||||
- test -f directory/file2.txt
|
||||
```
|
||||
|
||||
Normally, you would use either `status` or `sources` in combination with
|
||||
`generates` - but for tasks that generate remote artifacts (docker images,
|
||||
deploys, CD releases) the checksum source and timestamps require either
|
||||
access to the artifact or for an out-of-band refresh of the `.checksum`
|
||||
fingerprint file.
|
||||
|
||||
Two special variables `{{.CHECKSUM}}` and `{{.TIMESTAMP}}` are available
|
||||
for interpolation within `status` commands, depending on the method assigned
|
||||
to fingerprint the sources. Only `source` globs are fingerprinted.
|
||||
|
||||
You can use `--force` or `-f` if you want to force a task to run even when
|
||||
up-to-date.
|
||||
|
||||
|
@ -46,6 +46,10 @@ func (c *Checksum) IsUpToDate() (bool, error) {
|
||||
return oldMd5 == newMd5, nil
|
||||
}
|
||||
|
||||
func (t *Checksum) Kind() string {
|
||||
return "checksum"
|
||||
}
|
||||
|
||||
func (c *Checksum) checksum(files ...string) (string, error) {
|
||||
h := md5.New()
|
||||
|
||||
@ -73,6 +77,11 @@ func (c *Checksum) checksum(files ...string) (string, error) {
|
||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// Value implements the Chcker Interface
|
||||
func (c *Checksum) Value() (string, error) {
|
||||
return c.checksum()
|
||||
}
|
||||
|
||||
// OnError implements the Checker interface
|
||||
func (c *Checksum) OnError() error {
|
||||
return os.Remove(c.checksumFilePath())
|
||||
|
@ -8,6 +8,15 @@ func (None) IsUpToDate() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Value implements the Checker interface
|
||||
func (None) Value() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (None) Kind() string {
|
||||
return "none"
|
||||
}
|
||||
|
||||
// OnError implements the Checker interface
|
||||
func (None) OnError() error {
|
||||
return nil
|
||||
|
@ -9,5 +9,7 @@ var (
|
||||
// Checker is an interface that checks if the status is up-to-date
|
||||
type Checker interface {
|
||||
IsUpToDate() (bool, error)
|
||||
Value() (string, error)
|
||||
OnError() error
|
||||
Kind() string
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
@ -41,6 +42,29 @@ func (t *Timestamp) IsUpToDate() (bool, error) {
|
||||
return !generatesMinTime.Before(sourcesMaxTime), nil
|
||||
}
|
||||
|
||||
func (t *Timestamp) Kind() string {
|
||||
return "timestamp"
|
||||
}
|
||||
|
||||
// Value implements the Checker Interface
|
||||
func (t *Timestamp) Value() (string, error) {
|
||||
sources, err := glob(t.Dir, t.Sources)
|
||||
if err != nil {
|
||||
return "<no value>", err
|
||||
}
|
||||
|
||||
sourcesMaxTime, err := getMaxTime(sources...)
|
||||
if err != nil {
|
||||
return "<no value>", err
|
||||
}
|
||||
|
||||
if sourcesMaxTime.IsZero() {
|
||||
return "0", nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%d", sourcesMaxTime.Unix()), nil
|
||||
}
|
||||
|
||||
func getMinTime(files ...string) (time.Time, error) {
|
||||
var t time.Time
|
||||
for _, f := range files {
|
||||
|
@ -32,7 +32,7 @@ func (e *Executor) isTaskUpToDate(ctx context.Context, t *taskfile.Task) (bool,
|
||||
return e.isTaskUpToDateStatus(ctx, t)
|
||||
}
|
||||
|
||||
checker, err := e.getStatusChecker(t)
|
||||
checker, err := e.GetStatusChecker(t)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -41,14 +41,14 @@ func (e *Executor) isTaskUpToDate(ctx context.Context, t *taskfile.Task) (bool,
|
||||
}
|
||||
|
||||
func (e *Executor) statusOnError(t *taskfile.Task) error {
|
||||
checker, err := e.getStatusChecker(t)
|
||||
checker, err := e.GetStatusChecker(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return checker.OnError()
|
||||
}
|
||||
|
||||
func (e *Executor) getStatusChecker(t *taskfile.Task) (status.Checker, error) {
|
||||
func (e *Executor) GetStatusChecker(t *taskfile.Task) (status.Checker, error) {
|
||||
switch t.Method {
|
||||
case "", "timestamp":
|
||||
return &status.Timestamp{
|
||||
|
21
task_test.go
21
task_test.go
@ -11,6 +11,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task/v2"
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
@ -388,12 +389,20 @@ func TestStatusChecksum(t *testing.T) {
|
||||
}
|
||||
|
||||
var buff bytes.Buffer
|
||||
|
||||
logCapturer := logger.Logger{
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Verbose: true,
|
||||
}
|
||||
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
e.Logger = &logCapturer
|
||||
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build"}))
|
||||
for _, f := range files {
|
||||
@ -404,6 +413,18 @@ func TestStatusChecksum(t *testing.T) {
|
||||
buff.Reset()
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build"}))
|
||||
assert.Equal(t, `task: Task "build" is up to date`+"\n", buff.String())
|
||||
|
||||
buff.Reset()
|
||||
e.Silent = false
|
||||
e.Verbose = true
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build-with-checksum"}))
|
||||
assert.Contains(t, buff.String(), "d41d8cd98f00b204e9800998ecf8427e")
|
||||
|
||||
buff.Reset()
|
||||
inf, _ := os.Stat(filepath.Join(dir, "source.txt"))
|
||||
ts := fmt.Sprintf("%d", inf.ModTime().Unix())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build-with-timestamp"}))
|
||||
assert.Contains(t, buff.String(), ts)
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
|
13
testdata/checksum/Taskfile.yml
vendored
13
testdata/checksum/Taskfile.yml
vendored
@ -7,3 +7,16 @@ build:
|
||||
generates:
|
||||
- ./generated.txt
|
||||
method: checksum
|
||||
|
||||
build-with-checksum:
|
||||
sources:
|
||||
- ./source.txt
|
||||
method: checksum
|
||||
status:
|
||||
- echo "{{.CHECKSUM}}"
|
||||
|
||||
build-with-timestamp:
|
||||
sources:
|
||||
- ./source.txt
|
||||
status:
|
||||
- echo "{{.TIMESTAMP}}"
|
||||
|
29
variables.go
29
variables.go
@ -1,7 +1,9 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v2/internal/execext"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
@ -20,6 +22,7 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := templater.Templater{Vars: vars}
|
||||
|
||||
new := taskfile.Task{
|
||||
@ -27,7 +30,6 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
|
||||
Desc: r.Replace(origTask.Desc),
|
||||
Sources: r.ReplaceSlice(origTask.Sources),
|
||||
Generates: r.ReplaceSlice(origTask.Generates),
|
||||
Status: r.ReplaceSlice(origTask.Status),
|
||||
Dir: r.Replace(origTask.Dir),
|
||||
Vars: nil,
|
||||
Env: nil,
|
||||
@ -62,6 +64,31 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
|
||||
new.Env[k] = taskfile.Var{Static: static}
|
||||
}
|
||||
|
||||
if len(origTask.Status) > 0 {
|
||||
|
||||
e := &Executor{
|
||||
Dir: new.Dir,
|
||||
Stdout: ioutil.Discard,
|
||||
Stderr: ioutil.Discard,
|
||||
Dry: true,
|
||||
}
|
||||
|
||||
checker, err := e.GetStatusChecker(&new)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := checker.Value()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vars[strings.ToUpper(checker.Kind())] = taskfile.Var{Static: value}
|
||||
|
||||
statusTemplater := templater.Templater{Vars: vars}
|
||||
new.Status = statusTemplater.ReplaceSlice(origTask.Status)
|
||||
}
|
||||
|
||||
if len(origTask.Cmds) > 0 {
|
||||
new.Cmds = make([]*taskfile.Cmd, len(origTask.Cmds))
|
||||
for i, cmd := range origTask.Cmds {
|
||||
|
Loading…
x
Reference in New Issue
Block a user