mirror of
https://github.com/go-task/task.git
synced 2025-06-15 00:15:10 +02:00
fix: inconsistent current directory resolution depending on include order (#1757)
This commit is contained in:
committed by
GitHub
parent
c5eea294aa
commit
a72e70b026
102
task_test.go
102
task_test.go
@ -5,6 +5,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -12,6 +15,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
"github.com/Masterminds/semver/v3"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -21,6 +25,7 @@ import (
|
|||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
"github.com/go-task/task/v3/internal/experiments"
|
"github.com/go-task/task/v3/internal/experiments"
|
||||||
"github.com/go-task/task/v3/internal/filepathext"
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
|
"github.com/go-task/task/v3/internal/logger"
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1086,6 +1091,88 @@ func TestIncludesEmptyMain(t *testing.T) {
|
|||||||
tt.Run(t)
|
tt.Run(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIncludesHttp(t *testing.T) {
|
||||||
|
enableExperimentForTest(t, &experiments.RemoteTaskfiles, "1")
|
||||||
|
|
||||||
|
dir, err := filepath.Abs("testdata/includes_http")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
srv := httptest.NewServer(http.FileServer(http.Dir(dir)))
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
// This test fills the .task/remote directory with cache entries because the include URL
|
||||||
|
// is different on every test due to the dynamic nature of the TCP port in srv.URL
|
||||||
|
if err := os.RemoveAll(filepath.Join(dir, ".task")); err != nil {
|
||||||
|
t.Logf("error cleaning up: %s", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
taskfiles, err := fs.Glob(os.DirFS(dir), "root-taskfile-*.yml")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
remotes := []struct {
|
||||||
|
name string
|
||||||
|
root string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "local",
|
||||||
|
root: ".",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "http-remote",
|
||||||
|
root: srv.URL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, taskfile := range taskfiles {
|
||||||
|
t.Run(taskfile, func(t *testing.T) {
|
||||||
|
for _, remote := range remotes {
|
||||||
|
t.Run(remote.name, func(t *testing.T) {
|
||||||
|
t.Setenv("INCLUDE_ROOT", remote.root)
|
||||||
|
entrypoint := filepath.Join(dir, taskfile)
|
||||||
|
|
||||||
|
var buff SyncBuffer
|
||||||
|
e := task.Executor{
|
||||||
|
Entrypoint: entrypoint,
|
||||||
|
Dir: dir,
|
||||||
|
Stdout: &buff,
|
||||||
|
Stderr: &buff,
|
||||||
|
Insecure: true,
|
||||||
|
Download: true,
|
||||||
|
AssumeYes: true,
|
||||||
|
Logger: &logger.Logger{Stdout: &buff, Stderr: &buff, Verbose: true},
|
||||||
|
Timeout: time.Minute,
|
||||||
|
}
|
||||||
|
require.NoError(t, e.Setup())
|
||||||
|
defer func() { t.Log("output:", buff.buf.String()) }()
|
||||||
|
|
||||||
|
tcs := []struct {
|
||||||
|
name, dir string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "second-with-dir-1:third-with-dir-1:default",
|
||||||
|
dir: filepath.Join(dir, "dir-1"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "second-with-dir-1:third-with-dir-2:default",
|
||||||
|
dir: filepath.Join(dir, "dir-2"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tcs {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
task, err := e.CompiledTask(&ast.Call{Task: tc.name})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tc.dir, task.Dir)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIncludesDependencies(t *testing.T) {
|
func TestIncludesDependencies(t *testing.T) {
|
||||||
tt := fileContentTest{
|
tt := fileContentTest{
|
||||||
Dir: "testdata/includes_deps",
|
Dir: "testdata/includes_deps",
|
||||||
@ -2616,3 +2703,18 @@ func TestReference(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enableExperimentForTest enables the experiment behind pointer e for the duration of test t and sub-tests,
|
||||||
|
// with the experiment being restored to its previous state when tests complete.
|
||||||
|
//
|
||||||
|
// Typically experiments are controlled via TASK_X_ env vars, but we cannot use those in tests
|
||||||
|
// because the experiment settings are parsed during experiments.init(), before any tests run.
|
||||||
|
func enableExperimentForTest(t *testing.T, e *experiments.Experiment, val string) {
|
||||||
|
prev := *e
|
||||||
|
*e = experiments.Experiment{
|
||||||
|
Name: prev.Name,
|
||||||
|
Enabled: true,
|
||||||
|
Value: val,
|
||||||
|
}
|
||||||
|
t.Cleanup(func() { *e = prev })
|
||||||
|
}
|
||||||
|
@ -110,8 +110,12 @@ func (node *HTTPNode) ResolveDir(dir string) (string, error) {
|
|||||||
|
|
||||||
// NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
|
// NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
|
||||||
// This means that files are included relative to one another
|
// This means that files are included relative to one another
|
||||||
entrypointDir := filepath.Dir(node.Dir())
|
parent := node.Dir()
|
||||||
return filepathext.SmartJoin(entrypointDir, path), nil
|
if node.Parent() != nil {
|
||||||
|
parent = node.Parent().Dir()
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepathext.SmartJoin(parent, path), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *HTTPNode) FilenameAndLastDir() (string, string) {
|
func (node *HTTPNode) FilenameAndLastDir() (string, string) {
|
||||||
|
9
testdata/includes_http/child-taskfile2.yml
vendored
Normal file
9
testdata/includes_http/child-taskfile2.yml
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
third-with-dir-1:
|
||||||
|
taskfile: "{{.INCLUDE_ROOT}}/child-taskfile3.yml"
|
||||||
|
dir: ./dir-1
|
||||||
|
third-with-dir-2:
|
||||||
|
taskfile: "{{.INCLUDE_ROOT}}/child-taskfile3.yml"
|
||||||
|
dir: ./dir-2
|
4
testdata/includes_http/child-taskfile3.yml
vendored
Normal file
4
testdata/includes_http/child-taskfile3.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default: "true"
|
8
testdata/includes_http/root-taskfile-remotefile-empty-dir-1st.yml
vendored
Normal file
8
testdata/includes_http/root-taskfile-remotefile-empty-dir-1st.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
second-no-dir:
|
||||||
|
taskfile: "{{.INCLUDE_ROOT}}/child-taskfile2.yml"
|
||||||
|
second-with-dir-1:
|
||||||
|
taskfile: "{{.INCLUDE_ROOT}}/child-taskfile2.yml"
|
||||||
|
dir: ./dir-1
|
8
testdata/includes_http/root-taskfile-remotefile-empty-dir-2nd.yml
vendored
Normal file
8
testdata/includes_http/root-taskfile-remotefile-empty-dir-2nd.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
second-with-dir-1:
|
||||||
|
taskfile: "{{.INCLUDE_ROOT}}/child-taskfile2.yml"
|
||||||
|
dir: ./dir-1
|
||||||
|
second-no-dir:
|
||||||
|
taskfile: "{{.INCLUDE_ROOT}}/child-taskfile2.yml"
|
Reference in New Issue
Block a user