Skip to content

Commit b08c605

Browse files
committed
feat: support cmds in status
1 parent a0acc1e commit b08c605

25 files changed

+601
-191
lines changed

executor_test.go

Lines changed: 88 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"fmt"
88
"os"
99
"path/filepath"
10+
"sort"
11+
"strings"
1012
"testing"
1113

1214
"github.com/sebdah/goldie/v2"
@@ -15,7 +17,6 @@ import (
1517

1618
"github.com/go-task/task/v3"
1719
"github.com/go-task/task/v3/internal/experiments"
18-
"github.com/go-task/task/v3/internal/filepathext"
1920
"github.com/go-task/task/v3/taskfile/ast"
2021
)
2122

@@ -417,155 +418,6 @@ func TestDeps(t *testing.T) {
417418
)
418419
}
419420

420-
// TODO: mock fs
421-
func TestStatus(t *testing.T) {
422-
t.Parallel()
423-
424-
const dir = "testdata/status"
425-
426-
files := []string{
427-
"foo.txt",
428-
"bar.txt",
429-
"baz.txt",
430-
}
431-
432-
for _, f := range files {
433-
path := filepathext.SmartJoin(dir, f)
434-
_ = os.Remove(path)
435-
if _, err := os.Stat(path); err == nil {
436-
t.Errorf("File should not exist: %v", err)
437-
}
438-
}
439-
440-
// gen-foo creates foo.txt, and will always fail it's status check.
441-
NewExecutorTest(t,
442-
WithName("run gen-foo 1 silent"),
443-
WithExecutorOptions(
444-
task.WithDir(dir),
445-
task.WithSilent(true),
446-
),
447-
WithTask("gen-foo"),
448-
)
449-
// gen-foo creates bar.txt, and will pass its status-check the 3. time it
450-
// is run. It creates bar.txt, but also lists it as its source. So, the checksum
451-
// for the file won't match before after the second run as we the file
452-
// only exists after the first run.
453-
NewExecutorTest(t,
454-
WithName("run gen-bar 1 silent"),
455-
WithExecutorOptions(
456-
task.WithDir(dir),
457-
task.WithSilent(true),
458-
),
459-
WithTask("gen-bar"),
460-
)
461-
// gen-silent-baz is marked as being silent, and should only produce output
462-
// if e.Verbose is set to true.
463-
NewExecutorTest(t,
464-
WithName("run gen-baz silent"),
465-
WithExecutorOptions(
466-
task.WithDir(dir),
467-
task.WithSilent(true),
468-
),
469-
WithTask("gen-silent-baz"),
470-
)
471-
472-
for _, f := range files {
473-
if _, err := os.Stat(filepathext.SmartJoin(dir, f)); err != nil {
474-
t.Errorf("File should exist: %v", err)
475-
}
476-
}
477-
478-
// Run gen-bar a second time to produce a checksum file that matches bar.txt
479-
NewExecutorTest(t,
480-
WithName("run gen-bar 2 silent"),
481-
WithExecutorOptions(
482-
task.WithDir(dir),
483-
task.WithSilent(true),
484-
),
485-
WithTask("gen-bar"),
486-
)
487-
// Run gen-bar a third time, to make sure we've triggered the status check.
488-
NewExecutorTest(t,
489-
WithName("run gen-bar 3 silent"),
490-
WithExecutorOptions(
491-
task.WithDir(dir),
492-
task.WithSilent(true),
493-
),
494-
WithTask("gen-bar"),
495-
)
496-
497-
// Now, let's remove source file, and run the task again to to prepare
498-
// for the next test.
499-
err := os.Remove(filepathext.SmartJoin(dir, "bar.txt"))
500-
require.NoError(t, err)
501-
NewExecutorTest(t,
502-
WithName("run gen-bar 4 silent"),
503-
WithExecutorOptions(
504-
task.WithDir(dir),
505-
task.WithSilent(true),
506-
),
507-
WithTask("gen-bar"),
508-
)
509-
// all: not up-to-date
510-
NewExecutorTest(t,
511-
WithName("run gen-foo 2"),
512-
WithExecutorOptions(
513-
task.WithDir(dir),
514-
),
515-
WithTask("gen-foo"),
516-
)
517-
// status: not up-to-date
518-
NewExecutorTest(t,
519-
WithName("run gen-foo 3"),
520-
WithExecutorOptions(
521-
task.WithDir(dir),
522-
),
523-
WithTask("gen-foo"),
524-
)
525-
// sources: not up-to-date
526-
NewExecutorTest(t,
527-
WithName("run gen-bar 5"),
528-
WithExecutorOptions(
529-
task.WithDir(dir),
530-
),
531-
WithTask("gen-bar"),
532-
)
533-
// all: up-to-date
534-
NewExecutorTest(t,
535-
WithName("run gen-bar 6"),
536-
WithExecutorOptions(
537-
task.WithDir(dir),
538-
),
539-
WithTask("gen-bar"),
540-
)
541-
// sources: not up-to-date, no output produced.
542-
NewExecutorTest(t,
543-
WithName("run gen-baz 2"),
544-
WithExecutorOptions(
545-
task.WithDir(dir),
546-
),
547-
WithTask("gen-silent-baz"),
548-
)
549-
// up-to-date, no output produced
550-
NewExecutorTest(t,
551-
WithName("run gen-baz 3"),
552-
WithExecutorOptions(
553-
task.WithDir(dir),
554-
),
555-
WithTask("gen-silent-baz"),
556-
)
557-
// up-to-date, output produced due to Verbose mode.
558-
NewExecutorTest(t,
559-
WithName("run gen-baz 4 verbose"),
560-
WithExecutorOptions(
561-
task.WithDir(dir),
562-
task.WithVerbose(true),
563-
),
564-
WithTask("gen-silent-baz"),
565-
WithPostProcessFn(PPRemoveAbsolutePaths),
566-
)
567-
}
568-
569421
func TestPrecondition(t *testing.T) {
570422
t.Parallel()
571423
const dir = "testdata/precondition"
@@ -948,3 +800,89 @@ func TestVarInheritance(t *testing.T) {
948800
)
949801
}
950802
}
803+
804+
func TestStatusFor(t *testing.T) {
805+
t.Parallel()
806+
807+
statusDir := "testdata/status"
808+
809+
// Setup test files
810+
if err := os.MkdirAll(statusDir, 0755); err != nil {
811+
t.Fatalf("Failed to create test directory: %v", err)
812+
}
813+
814+
// Create test files
815+
fooPath := filepath.Join(statusDir, "foo.txt")
816+
barPath := filepath.Join(statusDir, "bar.txt")
817+
statusPath := filepath.Join(statusDir, "status.txt")
818+
819+
// Clean up before test
820+
os.Remove(fooPath)
821+
os.Remove(barPath)
822+
os.Remove(statusPath)
823+
824+
// Create test files
825+
if err := os.WriteFile(fooPath, []byte("foo content"), 0644); err != nil {
826+
t.Fatalf("Failed to create foo.txt: %v", err)
827+
}
828+
if err := os.WriteFile(barPath, []byte("bar content"), 0644); err != nil {
829+
t.Fatalf("Failed to create bar.txt: %v", err)
830+
}
831+
832+
// Defer cleanup
833+
defer func() {
834+
os.Remove(fooPath)
835+
os.Remove(barPath)
836+
os.Remove(statusPath)
837+
}()
838+
839+
tests := []struct {
840+
name string
841+
wantErr bool
842+
checkFunc func(t *testing.T)
843+
}{
844+
{
845+
name: "status-generates",
846+
checkFunc: func(t *testing.T) {
847+
// After running status-generates, check that status.txt contains both foo.txt and bar.txt
848+
content, err := os.ReadFile(statusPath)
849+
require.NoError(t, err)
850+
lines := strings.Split(strings.TrimSpace(string(content)), "\n")
851+
sort.Strings(lines)
852+
assert.Equal(t, []string{"bar.txt", "foo.txt"}, lines)
853+
},
854+
},
855+
}
856+
857+
for _, test := range tests {
858+
test := test // Capture range variable
859+
t.Run(test.name, func(t *testing.T) {
860+
// Remove status.txt before each test
861+
os.Remove(statusPath)
862+
863+
// Create executor options
864+
testOpts := []ExecutorTestOption{
865+
WithName(test.name),
866+
WithExecutorOptions(
867+
task.WithDir(statusDir),
868+
task.WithSilent(false), // Set to false to see command output
869+
task.WithVerbose(true),
870+
task.WithForce(true),
871+
),
872+
WithTask(test.name),
873+
WithStatusError(), // Run Status() to execute status commands
874+
}
875+
if test.wantErr {
876+
testOpts = append(testOpts, WithRunError())
877+
}
878+
879+
// Run the test
880+
NewExecutorTest(t, testOpts...)
881+
882+
// Check results
883+
if test.checkFunc != nil {
884+
test.checkFunc(t)
885+
}
886+
})
887+
}
888+
}

internal/fingerprint/status.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ func NewStatusChecker(logger *logger.Logger) StatusCheckable {
2222
func (checker *StatusChecker) IsUpToDate(ctx context.Context, t *ast.Task) (bool, error) {
2323
for _, s := range t.Status {
2424
err := execext.RunCommand(ctx, &execext.RunCommandOptions{
25-
Command: s,
25+
Command: s.Cmd,
2626
Dir: t.Dir,
2727
Env: env.Get(t),
2828
})
2929
if err != nil {
30-
checker.logger.VerboseOutf(logger.Yellow, "task: status command %s exited non-zero: %s\n", s, err)
30+
checker.logger.VerboseOutf(logger.Yellow, "task: status command %s exited non-zero: %s\n", s.Cmd, err)
3131
return false, nil
3232
}
33-
checker.logger.VerboseOutf(logger.Yellow, "task: status command %s exited zero\n", s)
33+
checker.logger.VerboseOutf(logger.Yellow, "task: status command %s exited zero\n", s.Cmd)
3434
}
3535
return true, nil
3636
}

internal/fingerprint/task_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func TestIsTaskUpToDate(t *testing.T) {
7272
{
7373
name: "expect TRUE when status is up-to-date and sources are not defined",
7474
task: &ast.Task{
75-
Status: []string{"status"},
75+
Status: []*ast.StatusCmd{{Cmd: "status"}},
7676
Sources: nil,
7777
},
7878
setupMockStatusChecker: func(m *mocks.StatusCheckable) {
@@ -84,7 +84,7 @@ func TestIsTaskUpToDate(t *testing.T) {
8484
{
8585
name: "expect TRUE when status and sources are up-to-date",
8686
task: &ast.Task{
87-
Status: []string{"status"},
87+
Status: []*ast.StatusCmd{{Cmd: "status"}},
8888
Sources: []*ast.Glob{{Glob: "sources"}},
8989
},
9090
setupMockStatusChecker: func(m *mocks.StatusCheckable) {
@@ -98,7 +98,7 @@ func TestIsTaskUpToDate(t *testing.T) {
9898
{
9999
name: "expect FALSE when status is up-to-date, but sources are NOT up-to-date",
100100
task: &ast.Task{
101-
Status: []string{"status"},
101+
Status: []*ast.StatusCmd{{Cmd: "status"}},
102102
Sources: []*ast.Glob{{Glob: "sources"}},
103103
},
104104
setupMockStatusChecker: func(m *mocks.StatusCheckable) {
@@ -112,7 +112,7 @@ func TestIsTaskUpToDate(t *testing.T) {
112112
{
113113
name: "expect FALSE when status is NOT up-to-date and sources are not defined",
114114
task: &ast.Task{
115-
Status: []string{"status"},
115+
Status: []*ast.StatusCmd{{Cmd: "status"}},
116116
Sources: nil,
117117
},
118118
setupMockStatusChecker: func(m *mocks.StatusCheckable) {
@@ -124,7 +124,7 @@ func TestIsTaskUpToDate(t *testing.T) {
124124
{
125125
name: "expect FALSE when status is NOT up-to-date, but sources are up-to-date",
126126
task: &ast.Task{
127-
Status: []string{"status"},
127+
Status: []*ast.StatusCmd{{Cmd: "status"}},
128128
Sources: []*ast.Glob{{Glob: "sources"}},
129129
},
130130
setupMockStatusChecker: func(m *mocks.StatusCheckable) {
@@ -138,7 +138,7 @@ func TestIsTaskUpToDate(t *testing.T) {
138138
{
139139
name: "expect FALSE when status and sources are NOT up-to-date",
140140
task: &ast.Task{
141-
Status: []string{"status"},
141+
Status: []*ast.StatusCmd{{Cmd: "status"}},
142142
Sources: []*ast.Glob{{Glob: "sources"}},
143143
},
144144
setupMockStatusChecker: func(m *mocks.StatusCheckable) {

0 commit comments

Comments
 (0)