diff --git a/task_test.go b/task_test.go index 540e7ba8de..8759bb351a 100644 --- a/task_test.go +++ b/task_test.go @@ -1323,6 +1323,56 @@ func TestIncludesRemote(t *testing.T) { } } +func TestIncludesRemoteOptionalOfflineCacheMiss(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + dir string + wantErr string + }{ + { + name: "optional include is skipped", + dir: "testdata/includes_remote_optional_offline", + }, + { + name: "non-optional include still fails", + dir: "testdata/includes_remote_nonoptional_offline", + wantErr: "was not found in the cache", + }, + { + name: "non-optional nested include still fails", + dir: "testdata/includes_remote_optional_parent_offline", + wantErr: "was not found in the cache", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var buff bytes.Buffer + e := task.NewExecutor( + task.WithDir(tt.dir), + task.WithStdout(&buff), + task.WithStderr(&buff), + task.WithOffline(true), + task.WithRemoteCacheDir(t.TempDir()), + ) + + err := e.Setup() + if tt.wantErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr) + return + } + require.NoError(t, err) + require.NoError(t, e.Run(t.Context(), &task.Call{Task: "local"})) + assert.Contains(t, buff.String(), "Hello from local") + }) + } +} + func TestIncludeCycle(t *testing.T) { t.Parallel() diff --git a/taskfile/reader.go b/taskfile/reader.go index d84abc80e1..da0148609a 100644 --- a/taskfile/reader.go +++ b/taskfile/reader.go @@ -211,6 +211,15 @@ func (r *Reader) include(ctx context.Context, node Node) error { return err } + // Checked before recursing so a nested include's cache miss isn't mistaken for this one's. + if include.Optional && r.offline { + if remote, ok := includeNode.(RemoteNode); ok { + if _, err := NewCacheNode(remote, r.tempDir).Read(); errors.Is(err, os.ErrNotExist) { + return nil + } + } + } + // Recurse into the included Taskfile if err := r.include(ctx, includeNode); err != nil { return err diff --git a/testdata/includes_remote_nonoptional_offline/Taskfile.yml b/testdata/includes_remote_nonoptional_offline/Taskfile.yml new file mode 100644 index 0000000000..ab5b0940f1 --- /dev/null +++ b/testdata/includes_remote_nonoptional_offline/Taskfile.yml @@ -0,0 +1,10 @@ +version: "3" + +includes: + remote: + taskfile: https://github.com/go-task/task.git//Taskfile.yml + +tasks: + local: + cmds: + - echo "Hello from local" diff --git a/testdata/includes_remote_optional_offline/Taskfile.yml b/testdata/includes_remote_optional_offline/Taskfile.yml new file mode 100644 index 0000000000..ce5bab9624 --- /dev/null +++ b/testdata/includes_remote_optional_offline/Taskfile.yml @@ -0,0 +1,11 @@ +version: "3" + +includes: + remote: + taskfile: https://github.com/go-task/task.git//Taskfile.yml + optional: true + +tasks: + local: + cmds: + - echo "Hello from local" diff --git a/testdata/includes_remote_optional_parent_offline/Taskfile.yml b/testdata/includes_remote_optional_parent_offline/Taskfile.yml new file mode 100644 index 0000000000..5f279751c8 --- /dev/null +++ b/testdata/includes_remote_optional_parent_offline/Taskfile.yml @@ -0,0 +1,11 @@ +version: "3" + +includes: + opt: + taskfile: ./opt.yml + optional: true + +tasks: + local: + cmds: + - echo "Hello from local" diff --git a/testdata/includes_remote_optional_parent_offline/opt.yml b/testdata/includes_remote_optional_parent_offline/opt.yml new file mode 100644 index 0000000000..9b2e6d92c1 --- /dev/null +++ b/testdata/includes_remote_optional_parent_offline/opt.yml @@ -0,0 +1,10 @@ +version: "3" + +includes: + remote: + taskfile: https://github.com/go-task/task.git//Taskfile.yml + +tasks: + nested: + cmds: + - echo "Hello from nested"