Skip to content

Commit

Permalink
feat: make checking for definitions configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya committed Feb 7, 2024
1 parent 8ae936e commit eeaeffd
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 90 deletions.
5 changes: 5 additions & 0 deletions help.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,13 @@ func (e *Executor) ToEditorOutput(tasks []*ast.Task, noStatus bool) (*editors.Ta
if task.Method != "" {
method = task.Method
}
definitionCheck := e.Taskfile.DefinitionCheck
if task.DefinitionCheck != "" {
definitionCheck = task.DefinitionCheck
}
upToDate, err := fingerprint.IsTaskUpToDate(context.Background(), task,
fingerprint.WithMethod(method),
fingerprint.WithDefinitionCheck(definitionCheck),
fingerprint.WithTempDir(e.TempDir),
fingerprint.WithDry(e.Dry),
fingerprint.WithLogger(e.Logger),
Expand Down
14 changes: 11 additions & 3 deletions internal/fingerprint/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type (
CheckerOption func(*CheckerConfig)
CheckerConfig struct {
method string
definitionCheck string
dry bool
tempDir string
logger *logger.Logger
Expand All @@ -26,6 +27,12 @@ func WithMethod(method string) CheckerOption {
}
}

func WithDefinitionCheck(definitionCheck string) CheckerOption {
return func(config *CheckerConfig) {
config.definitionCheck = definitionCheck
}
}

func WithDry(dry bool) CheckerOption {
return func(config *CheckerConfig) {
config.dry = dry
Expand Down Expand Up @@ -68,6 +75,7 @@ func IsTaskUpToDate(
// Default config
config := &CheckerConfig{
method: "none",
definitionCheck: "auto",
tempDir: "",
dry: false,
logger: nil,
Expand Down Expand Up @@ -147,9 +155,9 @@ func IsTaskUpToDate(
}
}

// if the status or sources are set, check if the definition is up-to-date
// TODO: allow caching based on the task definition even if status or sources are not set
if sourcesIsSet || statusIsSet {
// check if the definition is up-to-date when it is requested. By default (auto), it is only checked when sources are set but not the status
shouldCheckDefinition := config.definitionCheck == "always" || (config.definitionCheck == "auto" && (sourcesIsSet && !statusIsSet))
if shouldCheckDefinition {
// check if the definition is up-to-date
isDefinitionUpToDate, err := config.definitionChecker.IsUpToDate(maybeDefinitionPath)
if err != nil {
Expand Down
32 changes: 3 additions & 29 deletions internal/fingerprint/task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func TestIsTaskUpToDate(t *testing.T) {
expected: false,
},
{
name: "expect False when no status is defined and sources are up-to-date for the second time",
name: "expect True when no status is defined and sources are up-to-date for the second time",
task: &ast.Task{
Status: nil,
Sources: []*ast.Glob{{Glob: "sources"}},
Expand All @@ -85,19 +85,7 @@ func TestIsTaskUpToDate(t *testing.T) {
expected: false,
},
{
name: "expect False when status is up-to-date and sources are not defined for the first time",
task: &ast.Task{
Status: []string{"status"},
Sources: nil,
},
setupMockStatusChecker: func(m *mocks.StatusCheckable) {
m.EXPECT().IsUpToDate(mock.Anything, mock.Anything).Return(true, nil)
},
setupMockSourcesChecker: nil,
expected: false,
},
{
name: "expect TRUE when status is up-to-date and sources are not defined for the second time",
name: "expect TRUE when status is up-to-date and sources are not defined",
task: &ast.Task{
Status: []string{"status"},
Sources: nil,
Expand All @@ -109,21 +97,7 @@ func TestIsTaskUpToDate(t *testing.T) {
expected: true,
},
{
name: "expect False when status and sources are up-to-date for the first time",
task: &ast.Task{
Status: []string{"status"},
Sources: []*ast.Glob{{Glob: "sources"}},
},
setupMockStatusChecker: func(m *mocks.StatusCheckable) {
m.EXPECT().IsUpToDate(mock.Anything, mock.Anything).Return(true, nil)
},
setupMockSourcesChecker: func(m *mocks.SourcesCheckable) {
m.EXPECT().IsUpToDate(mock.Anything).Return(true, nil)
},
expected: false,
},
{
name: "expect True when status and sources are up-to-date for the second time",
name: "expect True when status and sources are up-to-date",
task: &ast.Task{
Status: []string{"status"},
Sources: []*ast.Glob{{Glob: "sources"}},
Expand Down
3 changes: 3 additions & 0 deletions setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ func (e *Executor) setupDefaults() {
if e.Taskfile.Method == "" {
e.Taskfile.Method = "checksum"
}
if e.Taskfile.DefinitionCheck == "" {
e.Taskfile.DefinitionCheck = "auto"
}
if e.Taskfile.Run == "" {
e.Taskfile.Run = "always"
}
Expand Down
6 changes: 6 additions & 0 deletions status.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ func (e *Executor) Status(ctx context.Context, calls ...ast.Call) error {
method = t.Method
}

definitionCheck := e.Taskfile.DefinitionCheck
if t.DefinitionCheck != "" {
definitionCheck = t.DefinitionCheck
}

// Check if the task is up-to-date
isUpToDate, err := fingerprint.IsTaskUpToDate(ctx, t,
fingerprint.WithMethod(method),
fingerprint.WithDefinitionCheck(definitionCheck),
fingerprint.WithTempDir(e.TempDir),
fingerprint.WithDry(e.Dry),
fingerprint.WithLogger(e.Logger),
Expand Down
6 changes: 6 additions & 0 deletions task.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,14 @@ func (e *Executor) RunTask(ctx context.Context, call ast.Call) error {
method = t.Method
}

definitionCheck := e.Taskfile.DefinitionCheck
if t.DefinitionCheck != "" {
definitionCheck = t.DefinitionCheck
}

upToDate, err := fingerprint.IsTaskUpToDate(ctx, t,
fingerprint.WithMethod(method),
fingerprint.WithDefinitionCheck(definitionCheck),
fingerprint.WithTempDir(e.TempDir),
fingerprint.WithDry(e.Dry),
fingerprint.WithLogger(e.Logger),
Expand Down
6 changes: 3 additions & 3 deletions task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ func TestLabelUpToDate(t *testing.T) {
}
require.NoError(t, e.Setup())
require.NoError(t, e.Run(context.Background(), ast.Call{Task: "foo"}))
assert.NotContains(t, buff.String(), "foobar") // first run
assert.Contains(t, buff.String(), "foobar")

require.NoError(t, e.Run(context.Background(), ast.Call{Task: "foo"}))
assert.Contains(t, buff.String(), "foobar")
Expand Down Expand Up @@ -575,7 +575,7 @@ func TestLabelWithVariableExpansion(t *testing.T) {
}
require.NoError(t, e.Setup())
require.NoError(t, e.Run(context.Background(), ast.Call{Task: "foo"}))
assert.NotContains(t, buff.String(), "foobaz") // first run
assert.Contains(t, buff.String(), "foobaz") // first run

require.NoError(t, e.Run(context.Background(), ast.Call{Task: "foo"}))
assert.Contains(t, buff.String(), "foobaz")
Expand All @@ -593,7 +593,7 @@ func TestLabelInSummary(t *testing.T) {
}
require.NoError(t, e.Setup())
require.NoError(t, e.Run(context.Background(), ast.Call{Task: "foo"}))
assert.NotContains(t, buff.String(), "foobar") // first run
assert.Contains(t, buff.String(), "foobar") // first run

require.NoError(t, e.Run(context.Background(), ast.Call{Task: "foo"}))
assert.Contains(t, buff.String(), "foobar")
Expand Down
60 changes: 32 additions & 28 deletions taskfile/ast/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Task struct {
Interactive bool
Internal bool
Method string
DefinitionCheck string
Prefix string
IgnoreError bool
Run string
Expand Down Expand Up @@ -75,34 +76,35 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error {
// Full task object
case yaml.MappingNode:
var task struct {
Cmds []*Cmd
Cmd *Cmd
Deps []*Dep
Label string
Desc string
Prompt string
Summary string
Aliases []string
Sources []*Glob
Generates []*Glob
Status []string
Preconditions []*Precondition
Dir string
Set []string
Shopt []string
Vars *Vars
Env *Vars
Dotenv []string
Silent bool
Interactive bool
Internal bool
Method string
Prefix string
IgnoreError bool `yaml:"ignore_error"`
Run string
Platforms []*Platform
Requires *Requires
Watch bool
Cmds []*Cmd
Cmd *Cmd
Deps []*Dep
Label string
Desc string
Prompt string
Summary string
Aliases []string
Sources []*Glob
Generates []*Glob
Status []string
Preconditions []*Precondition
Dir string
Set []string
Shopt []string
Vars *Vars
Env *Vars
Dotenv []string
Silent bool
Interactive bool
Internal bool
Method string
DefinitionCheck string `yaml:"definition_check"`
Prefix string
IgnoreError bool `yaml:"ignore_error"`
Run string
Platforms []*Platform
Requires *Requires
Watch bool
}
if err := node.Decode(&task); err != nil {
return err
Expand Down Expand Up @@ -135,6 +137,7 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error {
t.Interactive = task.Interactive
t.Internal = task.Internal
t.Method = task.Method
t.DefinitionCheck = task.DefinitionCheck
t.Prefix = task.Prefix
t.IgnoreError = task.IgnoreError
t.Run = task.Run
Expand Down Expand Up @@ -176,6 +179,7 @@ func (t *Task) DeepCopy() *Task {
Interactive: t.Interactive,
Internal: t.Internal,
Method: t.Method,
DefinitionCheck: t.DefinitionCheck,
Prefix: t.Prefix,
IgnoreError: t.IgnoreError,
Run: t.Run,
Expand Down
57 changes: 30 additions & 27 deletions taskfile/ast/taskfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@ var V3 = semver.MustParse("3")

// Taskfile is the abstract syntax tree for a Taskfile
type Taskfile struct {
Location string
Version *semver.Version
Output Output
Method string
Includes *Includes
Set []string
Shopt []string
Vars *Vars
Env *Vars
Tasks Tasks
Silent bool
Dotenv []string
Run string
Interval time.Duration
Location string
Version *semver.Version
Output Output
Method string
DefinitionCheck string
Includes *Includes
Set []string
Shopt []string
Vars *Vars
Env *Vars
Tasks Tasks
Silent bool
Dotenv []string
Run string
Interval time.Duration
}

// Merge merges the second Taskfile into the first
Expand All @@ -55,26 +56,28 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error {
switch node.Kind {
case yaml.MappingNode:
var taskfile struct {
Version *semver.Version
Output Output
Method string
Includes *Includes
Set []string
Shopt []string
Vars *Vars
Env *Vars
Tasks Tasks
Silent bool
Dotenv []string
Run string
Interval time.Duration
Version *semver.Version
Output Output
Method string
DefinitionCheck string `yaml:"definition_check"`
Includes *Includes
Set []string
Shopt []string
Vars *Vars
Env *Vars
Tasks Tasks
Silent bool
Dotenv []string
Run string
Interval time.Duration
}
if err := node.Decode(&taskfile); err != nil {
return err
}
tf.Version = taskfile.Version
tf.Output = taskfile.Output
tf.Method = taskfile.Method
tf.DefinitionCheck = taskfile.DefinitionCheck
tf.Includes = taskfile.Includes
tf.Set = taskfile.Set
tf.Shopt = taskfile.Shopt
Expand Down
1 change: 1 addition & 0 deletions variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func (e *Executor) compiledTask(call ast.Call, evaluateShVars bool) (*ast.Task,
Interactive: origTask.Interactive,
Internal: origTask.Internal,
Method: r.Replace(origTask.Method),
DefinitionCheck: r.Replace(origTask.DefinitionCheck),
Prefix: r.Replace(origTask.Prefix),
IgnoreError: origTask.IgnoreError,
Run: r.Replace(origTask.Run),
Expand Down

0 comments on commit eeaeffd

Please sign in to comment.