mirror of
https://github.com/go-task/task.git
synced 2026-05-18 05:05:20 +02:00
fix: Windows CI test failures and path normalization (#2670)
This commit is contained in:
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1,2 +1,5 @@
|
|||||||
* text=auto
|
* text=auto
|
||||||
*.mdx -linguist-detectable
|
*.mdx -linguist-detectable
|
||||||
|
|
||||||
|
# Keep LF line endings in testdata for consistent checksums across platforms
|
||||||
|
testdata/** text eol=lf
|
||||||
|
|||||||
18
.github/workflows/test.yml
vendored
18
.github/workflows/test.yml
vendored
@@ -12,27 +12,19 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
name: Test
|
name: Test
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.25.x, 1.26.x]
|
go-version: [1.25.x, 1.26.x]
|
||||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
runs-on: ${{matrix.platform}}
|
runs-on: ${{matrix.platform}}
|
||||||
steps:
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Set up Go ${{matrix.go-version}}
|
- name: Set up Go ${{matrix.go-version}}
|
||||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{matrix.go-version}}
|
go-version: ${{matrix.go-version}}
|
||||||
id: go
|
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
|
|
||||||
- name: Download Go modules
|
|
||||||
run: go mod download
|
|
||||||
env:
|
|
||||||
GOPROXY: https://proxy.golang.org
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: go build -o ./bin/task -v ./cmd/task
|
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: ./bin/task test --output=group --output-group-begin='::group::{{.TASK}}' --output-group-end='::endgroup::'
|
run: go run ./cmd/task test
|
||||||
|
|||||||
15
compiler.go
15
compiler.go
@@ -198,18 +198,21 @@ func (c *Compiler) ResetCache() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) getSpecialVars(t *ast.Task, call *Call) (map[string]string, error) {
|
func (c *Compiler) getSpecialVars(t *ast.Task, call *Call) (map[string]string, error) {
|
||||||
|
// Use filepath.ToSlash for all paths to ensure consistent forward slashes
|
||||||
|
// across platforms. This prevents issues with backslashes being interpreted
|
||||||
|
// as escape sequences when paths are used in shell commands on Windows.
|
||||||
allVars := map[string]string{
|
allVars := map[string]string{
|
||||||
"TASK_EXE": filepath.ToSlash(os.Args[0]),
|
"TASK_EXE": filepath.ToSlash(os.Args[0]),
|
||||||
"ROOT_TASKFILE": filepathext.SmartJoin(c.Dir, c.Entrypoint),
|
"ROOT_TASKFILE": filepath.ToSlash(filepathext.SmartJoin(c.Dir, c.Entrypoint)),
|
||||||
"ROOT_DIR": c.Dir,
|
"ROOT_DIR": filepath.ToSlash(c.Dir),
|
||||||
"USER_WORKING_DIR": c.UserWorkingDir,
|
"USER_WORKING_DIR": filepath.ToSlash(c.UserWorkingDir),
|
||||||
"TASK_VERSION": version.GetVersion(),
|
"TASK_VERSION": version.GetVersion(),
|
||||||
}
|
}
|
||||||
if t != nil {
|
if t != nil {
|
||||||
allVars["TASK"] = t.Task
|
allVars["TASK"] = t.Task
|
||||||
allVars["TASK_DIR"] = filepathext.SmartJoin(c.Dir, t.Dir)
|
allVars["TASK_DIR"] = filepath.ToSlash(filepathext.SmartJoin(c.Dir, t.Dir))
|
||||||
allVars["TASKFILE"] = t.Location.Taskfile
|
allVars["TASKFILE"] = filepath.ToSlash(t.Location.Taskfile)
|
||||||
allVars["TASKFILE_DIR"] = filepath.Dir(t.Location.Taskfile)
|
allVars["TASKFILE_DIR"] = filepath.ToSlash(filepath.Dir(t.Location.Taskfile))
|
||||||
} else {
|
} else {
|
||||||
allVars["TASK"] = ""
|
allVars["TASK"] = ""
|
||||||
allVars["TASK_DIR"] = ""
|
allVars["TASK_DIR"] = ""
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package errors
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
"github.com/Masterminds/semver/v3"
|
||||||
@@ -27,7 +28,7 @@ func (err TaskfileNotFoundError) Error() string {
|
|||||||
if err.AskInit {
|
if err.AskInit {
|
||||||
walkText += " Run `task --init` to create a new Taskfile."
|
walkText += " Run `task --init` to create a new Taskfile."
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(`task: No Taskfile found at %q%s`, err.URI, walkText)
|
return fmt.Sprintf(`task: No Taskfile found at %q%s`, filepath.ToSlash(err.URI), walkText)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err TaskfileNotFoundError) Code() int {
|
func (err TaskfileNotFoundError) Code() int {
|
||||||
@@ -54,7 +55,7 @@ type TaskfileInvalidError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (err TaskfileInvalidError) Error() string {
|
func (err TaskfileInvalidError) Error() string {
|
||||||
return fmt.Sprintf("task: Failed to parse %s:\n%v", err.URI, err.Err)
|
return fmt.Sprintf("task: Failed to parse %s:\n%v", filepath.ToSlash(err.URI), err.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err TaskfileInvalidError) Code() int {
|
func (err TaskfileInvalidError) Code() int {
|
||||||
@@ -73,7 +74,7 @@ func (err TaskfileFetchFailedError) Error() string {
|
|||||||
if err.HTTPStatusCode != 0 {
|
if err.HTTPStatusCode != 0 {
|
||||||
statusText = fmt.Sprintf(" with status code %d (%s)", err.HTTPStatusCode, http.StatusText(err.HTTPStatusCode))
|
statusText = fmt.Sprintf(" with status code %d (%s)", err.HTTPStatusCode, http.StatusText(err.HTTPStatusCode))
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(`task: Download of %q failed%s`, err.URI, statusText)
|
return fmt.Sprintf(`task: Download of %q failed%s`, filepath.ToSlash(err.URI), statusText)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err TaskfileFetchFailedError) Code() int {
|
func (err TaskfileFetchFailedError) Code() int {
|
||||||
@@ -89,7 +90,7 @@ type TaskfileNotTrustedError struct {
|
|||||||
func (err *TaskfileNotTrustedError) Error() string {
|
func (err *TaskfileNotTrustedError) Error() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`task: Taskfile %q not trusted by user`,
|
`task: Taskfile %q not trusted by user`,
|
||||||
err.URI,
|
filepath.ToSlash(err.URI),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +107,7 @@ type TaskfileNotSecureError struct {
|
|||||||
func (err *TaskfileNotSecureError) Error() string {
|
func (err *TaskfileNotSecureError) Error() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`task: Taskfile %q cannot be downloaded over an insecure connection. You can override this by using the --insecure flag`,
|
`task: Taskfile %q cannot be downloaded over an insecure connection. You can override this by using the --insecure flag`,
|
||||||
err.URI,
|
filepath.ToSlash(err.URI),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +124,7 @@ type TaskfileCacheNotFoundError struct {
|
|||||||
func (err *TaskfileCacheNotFoundError) Error() string {
|
func (err *TaskfileCacheNotFoundError) Error() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`task: Taskfile %q was not found in the cache. Remove the --offline flag to use a remote copy or download it using the --download flag`,
|
`task: Taskfile %q was not found in the cache. Remove the --offline flag to use a remote copy or download it using the --download flag`,
|
||||||
err.URI,
|
filepath.ToSlash(err.URI),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,12 +145,12 @@ func (err *TaskfileVersionCheckError) Error() string {
|
|||||||
if err.SchemaVersion == nil {
|
if err.SchemaVersion == nil {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`task: Missing schema version in Taskfile %q`,
|
`task: Missing schema version in Taskfile %q`,
|
||||||
err.URI,
|
filepath.ToSlash(err.URI),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"task: Invalid schema version in Taskfile %q:\nSchema version (%s) %s",
|
"task: Invalid schema version in Taskfile %q:\nSchema version (%s) %s",
|
||||||
err.URI,
|
filepath.ToSlash(err.URI),
|
||||||
err.SchemaVersion.String(),
|
err.SchemaVersion.String(),
|
||||||
err.Message,
|
err.Message,
|
||||||
)
|
)
|
||||||
@@ -169,7 +170,7 @@ type TaskfileNetworkTimeoutError struct {
|
|||||||
func (err *TaskfileNetworkTimeoutError) Error() string {
|
func (err *TaskfileNetworkTimeoutError) Error() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`task: Network connection timed out after %s while attempting to download Taskfile %q`,
|
`task: Network connection timed out after %s while attempting to download Taskfile %q`,
|
||||||
err.Timeout, err.URI,
|
err.Timeout, filepath.ToSlash(err.URI),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,8 +187,8 @@ type TaskfileCycleError struct {
|
|||||||
|
|
||||||
func (err TaskfileCycleError) Error() string {
|
func (err TaskfileCycleError) Error() string {
|
||||||
return fmt.Sprintf("task: include cycle detected between %s <--> %s",
|
return fmt.Sprintf("task: include cycle detected between %s <--> %s",
|
||||||
err.Source,
|
filepath.ToSlash(err.Source),
|
||||||
err.Destination,
|
filepath.ToSlash(err.Destination),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +207,7 @@ type TaskfileDoesNotMatchChecksum struct {
|
|||||||
func (err *TaskfileDoesNotMatchChecksum) Error() string {
|
func (err *TaskfileDoesNotMatchChecksum) Error() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"task: The checksum of the Taskfile at %q does not match!\ngot: %q\nwant: %q",
|
"task: The checksum of the Taskfile at %q does not match!\ngot: %q\nwant: %q",
|
||||||
err.URI,
|
filepath.ToSlash(err.URI),
|
||||||
err.ActualChecksum,
|
err.ActualChecksum,
|
||||||
err.ExpectedChecksum,
|
err.ExpectedChecksum,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ func (tt *ExecutorTest) run(t *testing.T) {
|
|||||||
// Create a golden fixture file for the output
|
// Create a golden fixture file for the output
|
||||||
g := goldie.New(t,
|
g := goldie.New(t,
|
||||||
goldie.WithFixtureDir(filepath.Join(e.Dir, "testdata")),
|
goldie.WithFixtureDir(filepath.Join(e.Dir, "testdata")),
|
||||||
|
goldie.WithEqualFn(NormalizedEqual),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Call setup and check for errors
|
// Call setup and check for errors
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ func (tt *FormatterTest) run(t *testing.T) {
|
|||||||
// Create a golden fixture file for the output
|
// Create a golden fixture file for the output
|
||||||
g := goldie.New(t,
|
g := goldie.New(t,
|
||||||
goldie.WithFixtureDir(filepath.Join(e.Dir, "testdata")),
|
goldie.WithFixtureDir(filepath.Join(e.Dir, "testdata")),
|
||||||
|
goldie.WithEqualFn(NormalizedEqual),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Call setup and check for errors
|
// Call setup and check for errors
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package fingerprint
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
@@ -50,7 +51,8 @@ func collectKeys(m map[string]bool) []string {
|
|||||||
keys := make([]string, 0, len(m))
|
keys := make([]string, 0, len(m))
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
if v {
|
if v {
|
||||||
keys = append(keys, k)
|
// Normalize path separators for consistent sorting across platforms
|
||||||
|
keys = append(keys, filepath.ToSlash(k))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|||||||
108
task_test.go
108
task_test.go
@@ -88,13 +88,14 @@ func (tt *TaskTest) writeFixture(
|
|||||||
if tt.fixtureTemplatingEnabled {
|
if tt.fixtureTemplatingEnabled {
|
||||||
fixtureTemplateData := map[string]any{
|
fixtureTemplateData := map[string]any{
|
||||||
"TEST_NAME": t.Name(),
|
"TEST_NAME": t.Name(),
|
||||||
"TEST_DIR": wd,
|
"TEST_DIR": filepath.ToSlash(wd),
|
||||||
}
|
}
|
||||||
// If the test has additional template data, copy it into the map
|
// If the test has additional template data, copy it into the map
|
||||||
if tt.fixtureTemplateData != nil {
|
if tt.fixtureTemplateData != nil {
|
||||||
maps.Copy(fixtureTemplateData, tt.fixtureTemplateData)
|
maps.Copy(fixtureTemplateData, tt.fixtureTemplateData)
|
||||||
}
|
}
|
||||||
g.AssertWithTemplate(t, goldenFileName, fixtureTemplateData, b)
|
// Normalize output before comparison (CRLF→LF, backslash→forward slash)
|
||||||
|
g.AssertWithTemplate(t, goldenFileName, fixtureTemplateData, normalizeOutput(b))
|
||||||
} else {
|
} else {
|
||||||
g.Assert(t, goldenFileName, b)
|
g.Assert(t, goldenFileName, b)
|
||||||
}
|
}
|
||||||
@@ -308,6 +309,73 @@ func PPSortedLines(t *testing.T, b []byte) []byte {
|
|||||||
return []byte(strings.Join(lines, "\n") + "\n")
|
return []byte(strings.Join(lines, "\n") + "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// normalizeOutput normalizes cross-platform differences for byte slice comparison:
|
||||||
|
// - Converts CRLF and CR to LF (line endings)
|
||||||
|
// - Converts backslashes to forward slashes (Windows paths)
|
||||||
|
// - Handles escaped backslashes in JSON (\\) by converting to single forward slash
|
||||||
|
func normalizeOutput(b []byte) []byte {
|
||||||
|
b = bytes.ReplaceAll(b, []byte("\r\n"), []byte("\n"))
|
||||||
|
b = bytes.ReplaceAll(b, []byte("\r"), []byte("\n"))
|
||||||
|
// First replace escaped backslashes (common in JSON), then single backslashes
|
||||||
|
b = bytes.ReplaceAll(b, []byte("\\\\"), []byte("/"))
|
||||||
|
b = bytes.ReplaceAll(b, []byte("\\"), []byte("/"))
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizePathSeparators converts backslashes to forward slashes for cross-platform path comparison.
|
||||||
|
func normalizePathSeparators(s string) string {
|
||||||
|
return strings.ReplaceAll(s, "\\", "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NormalizedEqual compares two byte slices after normalizing output.
|
||||||
|
// This is used as a custom goldie.EqualFn for cross-platform golden file tests.
|
||||||
|
func NormalizedEqual(actual, expected []byte) bool {
|
||||||
|
return bytes.Equal(normalizeOutput(actual), normalizeOutput(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNormalizeOutput(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input []byte
|
||||||
|
expected []byte
|
||||||
|
}{
|
||||||
|
{"CRLF to LF", []byte("line1\r\nline2\r\n"), []byte("line1\nline2\n")},
|
||||||
|
{"CR to LF", []byte("line1\rline2\r"), []byte("line1\nline2\n")},
|
||||||
|
{"Windows path", []byte(`D:\a\task\task`), []byte(`D:/a/task/task`)},
|
||||||
|
{"JSON escaped backslash", []byte(`{"path":"D:\\a\\task"}`), []byte(`{"path":"D:/a/task"}`)},
|
||||||
|
{"Mixed", []byte("D:\\a\\task\r\n"), []byte("D:/a/task\n")},
|
||||||
|
{"Unix path unchanged", []byte("/home/user/task\n"), []byte("/home/user/task\n")},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
got := normalizeOutput(tt.input)
|
||||||
|
assert.Equal(t, tt.expected, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNormalizePathSeparators(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"Windows path", `D:\a\task\task`, `D:/a/task/task`},
|
||||||
|
{"Unix path unchanged", `/home/user/task`, `/home/user/task`},
|
||||||
|
{"Mixed separators", `C:\Users/name\file`, `C:/Users/name/file`},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
got := normalizePathSeparators(tt.input)
|
||||||
|
assert.Equal(t, tt.expected, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SyncBuffer is a threadsafe buffer for testing.
|
// SyncBuffer is a threadsafe buffer for testing.
|
||||||
// Some times replace stdout/stderr with a buffer to capture output.
|
// Some times replace stdout/stderr with a buffer to capture output.
|
||||||
// stdout and stderr are threadsafe, but a regular bytes.Buffer is not.
|
// stdout and stderr are threadsafe, but a regular bytes.Buffer is not.
|
||||||
@@ -1078,7 +1146,7 @@ func TestIncludesOptionalImplicitFalse(t *testing.T) {
|
|||||||
wd, _ := os.Getwd()
|
wd, _ := os.Getwd()
|
||||||
|
|
||||||
message := "task: No Taskfile found at \"%s/%s/TaskfileOptional.yml\""
|
message := "task: No Taskfile found at \"%s/%s/TaskfileOptional.yml\""
|
||||||
expected := fmt.Sprintf(message, wd, dir)
|
expected := fmt.Sprintf(message, filepath.ToSlash(wd), dir)
|
||||||
|
|
||||||
e := task.NewExecutor(
|
e := task.NewExecutor(
|
||||||
task.WithDir(dir),
|
task.WithDir(dir),
|
||||||
@@ -1098,7 +1166,7 @@ func TestIncludesOptionalExplicitFalse(t *testing.T) {
|
|||||||
wd, _ := os.Getwd()
|
wd, _ := os.Getwd()
|
||||||
|
|
||||||
message := "task: No Taskfile found at \"%s/%s/TaskfileOptional.yml\""
|
message := "task: No Taskfile found at \"%s/%s/TaskfileOptional.yml\""
|
||||||
expected := fmt.Sprintf(message, wd, dir)
|
expected := fmt.Sprintf(message, filepath.ToSlash(wd), dir)
|
||||||
|
|
||||||
e := task.NewExecutor(
|
e := task.NewExecutor(
|
||||||
task.WithDir(dir),
|
task.WithDir(dir),
|
||||||
@@ -1146,11 +1214,11 @@ func TestIncludesRelativePath(t *testing.T) {
|
|||||||
require.NoError(t, e.Setup())
|
require.NoError(t, e.Setup())
|
||||||
|
|
||||||
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "common:pwd"}))
|
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "common:pwd"}))
|
||||||
assert.Contains(t, buff.String(), "testdata/includes_rel_path/common")
|
assert.Contains(t, filepath.ToSlash(buff.String()), "testdata/includes_rel_path/common")
|
||||||
|
|
||||||
buff.Reset()
|
buff.Reset()
|
||||||
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "included:common:pwd"}))
|
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "included:common:pwd"}))
|
||||||
assert.Contains(t, buff.String(), "testdata/includes_rel_path/common")
|
assert.Contains(t, filepath.ToSlash(buff.String()), "testdata/includes_rel_path/common")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIncludesInternal(t *testing.T) {
|
func TestIncludesInternal(t *testing.T) {
|
||||||
@@ -1328,7 +1396,7 @@ func TestIncludedTaskfileVarMerging(t *testing.T) {
|
|||||||
|
|
||||||
err := e.Run(t.Context(), &task.Call{Task: test.task})
|
err := e.Run(t.Context(), &task.Call{Task: test.task})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Contains(t, buff.String(), test.expectedOutput)
|
assert.Contains(t, filepath.ToSlash(buff.String()), test.expectedOutput)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1475,7 +1543,9 @@ func TestWhenNoDirAttributeItRunsInSameDirAsTaskfile(t *testing.T) {
|
|||||||
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "whereami"}))
|
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "whereami"}))
|
||||||
|
|
||||||
// got should be the "dir" part of "testdata/dir"
|
// got should be the "dir" part of "testdata/dir"
|
||||||
got := strings.TrimSuffix(filepath.Base(out.String()), "\n")
|
// Normalize path separators for cross-platform compatibility (Windows uses backslashes)
|
||||||
|
normalized := normalizePathSeparators(out.String())
|
||||||
|
got := strings.TrimSuffix(filepath.Base(normalized), "\n")
|
||||||
assert.Equal(t, expected, got, "Mismatch in the working directory")
|
assert.Equal(t, expected, got, "Mismatch in the working directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1494,7 +1564,9 @@ func TestWhenDirAttributeAndDirExistsItRunsInThatDir(t *testing.T) {
|
|||||||
require.NoError(t, e.Setup())
|
require.NoError(t, e.Setup())
|
||||||
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "whereami"}))
|
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "whereami"}))
|
||||||
|
|
||||||
got := strings.TrimSuffix(filepath.Base(out.String()), "\n")
|
// Normalize path separators for cross-platform compatibility (Windows uses backslashes)
|
||||||
|
normalized := normalizePathSeparators(out.String())
|
||||||
|
got := strings.TrimSuffix(filepath.Base(normalized), "\n")
|
||||||
assert.Equal(t, expected, got, "Mismatch in the working directory")
|
assert.Equal(t, expected, got, "Mismatch in the working directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1520,7 +1592,9 @@ func TestWhenDirAttributeItCreatesMissingAndRunsInThatDir(t *testing.T) {
|
|||||||
require.NoError(t, e.Setup())
|
require.NoError(t, e.Setup())
|
||||||
require.NoError(t, e.Run(t.Context(), &task.Call{Task: target}))
|
require.NoError(t, e.Run(t.Context(), &task.Call{Task: target}))
|
||||||
|
|
||||||
got := strings.TrimSuffix(filepath.Base(out.String()), "\n")
|
// Normalize path separators for cross-platform compatibility (Windows uses backslashes)
|
||||||
|
normalized := normalizePathSeparators(out.String())
|
||||||
|
got := strings.TrimSuffix(filepath.Base(normalized), "\n")
|
||||||
assert.Equal(t, expected, got, "Mismatch in the working directory")
|
assert.Equal(t, expected, got, "Mismatch in the working directory")
|
||||||
|
|
||||||
// Clean-up after ourselves only if no error.
|
// Clean-up after ourselves only if no error.
|
||||||
@@ -1549,7 +1623,11 @@ func TestDynamicVariablesRunOnTheNewCreatedDir(t *testing.T) {
|
|||||||
require.NoError(t, e.Setup())
|
require.NoError(t, e.Setup())
|
||||||
require.NoError(t, e.Run(t.Context(), &task.Call{Task: target}))
|
require.NoError(t, e.Run(t.Context(), &task.Call{Task: target}))
|
||||||
|
|
||||||
got := strings.TrimSuffix(filepath.Base(out.String()), "\n")
|
// Normalize path separators for cross-platform compatibility (Windows uses backslashes)
|
||||||
|
// Take only the first line as Windows may output additional debug info
|
||||||
|
normalized := normalizePathSeparators(out.String())
|
||||||
|
firstLine := strings.Split(normalized, "\n")[0]
|
||||||
|
got := filepath.Base(firstLine)
|
||||||
assert.Equal(t, expected, got, "Mismatch in the working directory")
|
assert.Equal(t, expected, got, "Mismatch in the working directory")
|
||||||
|
|
||||||
// Clean-up after ourselves only if no error.
|
// Clean-up after ourselves only if no error.
|
||||||
@@ -2268,7 +2346,8 @@ func TestUserWorkingDirectory(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, e.Setup())
|
require.NoError(t, e.Setup())
|
||||||
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "default"}))
|
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "default"}))
|
||||||
assert.Equal(t, fmt.Sprintf("%s\n", wd), buff.String())
|
// Use filepath.ToSlash because USER_WORKING_DIR uses forward slashes on all platforms
|
||||||
|
assert.Equal(t, fmt.Sprintf("%s\n", filepath.ToSlash(wd)), buff.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserWorkingDirectoryWithIncluded(t *testing.T) {
|
func TestUserWorkingDirectoryWithIncluded(t *testing.T) {
|
||||||
@@ -2277,7 +2356,7 @@ func TestUserWorkingDirectoryWithIncluded(t *testing.T) {
|
|||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
wd = filepathext.SmartJoin(wd, "testdata/user_working_dir_with_includes/somedir")
|
wd = filepath.ToSlash(filepathext.SmartJoin(wd, "testdata/user_working_dir_with_includes/somedir"))
|
||||||
|
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
e := task.NewExecutor(
|
e := task.NewExecutor(
|
||||||
@@ -2290,7 +2369,8 @@ func TestUserWorkingDirectoryWithIncluded(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, e.Setup())
|
require.NoError(t, e.Setup())
|
||||||
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "included:echo"}))
|
require.NoError(t, e.Run(t.Context(), &task.Call{Task: "included:echo"}))
|
||||||
assert.Equal(t, fmt.Sprintf("%s\n", wd), buff.String())
|
// Normalize path separators for cross-platform compatibility (Windows uses backslashes)
|
||||||
|
assert.Equal(t, fmt.Sprintf("%s\n", wd), normalizePathSeparators(buff.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlatforms(t *testing.T) {
|
func TestPlatforms(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user