Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
name: Lint
strategy:
matrix:
go-version: [1.25.10, 1.26.x]
go-version: [1.26.x]
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
go-version: [1.25.10, 1.26.x]
go-version: [1.26.x]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{matrix.platform}}
steps:
Expand Down
1 change: 0 additions & 1 deletion checksum_benchmark_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//go:build fsbench
// +build fsbench

package task_test

Expand Down
6 changes: 2 additions & 4 deletions errors/error_taskfile_decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ type (

func NewTaskfileDecodeError(err error, node *yaml.Node) *TaskfileDecodeError {
// If the error is already a DecodeError, return it
taskfileInvalidErr := &TaskfileDecodeError{}
if errors.As(err, &taskfileInvalidErr) {
if taskfileInvalidErr, ok := errors.AsType[*TaskfileDecodeError](err); ok {
return taskfileInvalidErr
}
return &TaskfileDecodeError{
Expand All @@ -45,8 +44,7 @@ func (err *TaskfileDecodeError) Error() string {
fmt.Fprintln(buf, color.RedString("err: %s", err.Message))
} else {
// Extract the errors from the TypeError
te := &yaml.TypeError{}
if errors.As(err.Err, &te) {
if te, ok := errors.AsType[*yaml.TypeError](err.Err); ok {
if len(te.Errors) > 1 {
fmt.Fprintln(buf, color.RedString("errs:"))
for _, message := range te.Errors {
Expand Down
7 changes: 7 additions & 0 deletions errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ func As(err error, target any) bool {
return errors.As(err, target)
}

// AsType wraps the standard errors.AsType function so that we don't need to alias
// that package. It returns the first error in err's tree that matches type T, and
// whether such an error was found.
func AsType[T error](err error) (T, bool) {
return errors.AsType[T](err)
}

// Unwrap wraps the standard errors.Unwrap function so that we don't need to alias that package.
func Unwrap(err error) error {
return errors.Unwrap(err)
Expand Down
3 changes: 1 addition & 2 deletions errors/errors_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ func (err *TaskRunError) Code() int {
}

func (err *TaskRunError) TaskExitCode() int {
var exit interp.ExitStatus
if errors.As(err.Err, &exit) {
if exit, ok := errors.AsType[interp.ExitStatus](err.Err); ok {
return int(exit)
}
return err.Code()
Expand Down
2 changes: 1 addition & 1 deletion experiments/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type InvalidValueError struct {

func (err InvalidValueError) Error() string {
return fmt.Sprintf(
"task: Experiment %q has an invalid value %q (allowed values: %s)",
"task: Experiment %q has an invalid value %d (allowed values: %s)",
err.Name,
err.Value,
strings.Join(slicesext.Convert(err.AllowedValues, strconv.Itoa), ", "),
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/go-task/task/v3

go 1.25.10
go 1.26.4

require (
charm.land/bubbles/v2 v2.1.0
Expand Down
23 changes: 11 additions & 12 deletions internal/fingerprint/gitignore.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package fingerprint

import (
"bufio"
"cmp"
"maps"
"os"
"path/filepath"
"sort"
"slices"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -95,17 +97,14 @@ func filterGitignored(files map[string]bool, dir string) map[string]bool {

// Shallow dirs first (lower priority): the matcher scans patterns last to
// first, so deeper rules win and can negate shallower ones.
dirs := make([]string, 0, len(dirSet))
for d := range dirSet {
dirs = append(dirs, d)
}
sort.Slice(dirs, func(i, j int) bool {
di := strings.Count(dirs[i], string(filepath.Separator))
dj := strings.Count(dirs[j], string(filepath.Separator))
if di != dj {
return di < dj
}
return dirs[i] < dirs[j]
dirs := slices.Collect(maps.Keys(dirSet))
slices.SortFunc(dirs, func(a, b string) int {
da := strings.Count(a, string(filepath.Separator))
db := strings.Count(b, string(filepath.Separator))
if da != db {
return cmp.Compare(da, db)
}
return cmp.Compare(a, b)
})

var patterns []gitignore.Pattern
Expand Down
4 changes: 2 additions & 2 deletions internal/fingerprint/glob.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package fingerprint
import (
"os"
"path/filepath"
"sort"
"slices"

"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/filepathext"
Expand Down Expand Up @@ -65,6 +65,6 @@ func collectKeys(m map[string]bool) []string {
keys = append(keys, filepath.ToSlash(k))
}
}
sort.Strings(keys)
slices.Sort(keys)
return keys
}
4 changes: 2 additions & 2 deletions internal/fsext/glob.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"io/fs"
"os"
"path/filepath"
"sort"
"slices"
"strings"

"github.com/go-task/task/v3/errors"
Expand Down Expand Up @@ -74,6 +74,6 @@ func FastRecursiveGlob(pattern string) ([]string, bool, error) {
if err != nil {
return nil, true, err
}
sort.Strings(results)
slices.Sort(results)
return results, true, nil
}
18 changes: 9 additions & 9 deletions internal/sort/sorter.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package sort

import (
"cmp"
"slices"
"sort"
"strings"
)

Expand All @@ -29,16 +29,16 @@ func AlphaNumericWithRootTasksFirst(items []string, namespaces []string) []strin
if len(namespaces) > 0 {
return AlphaNumeric(items, namespaces)
}
sort.Slice(items, func(i, j int) bool {
iContainsColon := strings.Contains(items[i], ":")
jContainsColon := strings.Contains(items[j], ":")
if iContainsColon == jContainsColon {
return items[i] < items[j]
slices.SortFunc(items, func(a, b string) int {
aContainsColon := strings.Contains(a, ":")
bContainsColon := strings.Contains(b, ":")
if aContainsColon == bContainsColon {
return cmp.Compare(a, b)
}
if !iContainsColon && jContainsColon {
return true
if !aContainsColon && bContainsColon {
return -1
}
return false
return 1
})
return items
}
3 changes: 1 addition & 2 deletions setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ func (e *Executor) getRootNode() (taskfile.Node, error) {
taskfile.WithCert(e.Cert),
taskfile.WithCertKey(e.CertKey),
)
var taskNotFoundError errors.TaskfileNotFoundError
if errors.As(err, &taskNotFoundError) {
if taskNotFoundError, ok := errors.AsType[errors.TaskfileNotFoundError](err); ok {
taskNotFoundError.AskInit = true
return nil, taskNotFoundError
}
Expand Down
6 changes: 2 additions & 4 deletions signals_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//go:build signals
// +build signals

// This file contains tests for signal handling on Unix.
// Based on code from https://github.com/marco-m/timeit
Expand Down Expand Up @@ -154,9 +153,8 @@ func TestSignalSentToProcessGroup(t *testing.T) {

err := sut.Wait()

var wantErr *exec.ExitError
const wantExitStatus = 201
if errors.As(err, &wantErr) {
if wantErr, ok := errors.AsType[*exec.ExitError](err); ok {
if wantErr.ExitCode() != wantExitStatus {
t.Errorf(
"waiting for child process: got exit status %v; want %d\n"+
Expand All @@ -166,7 +164,7 @@ func TestSignalSentToProcessGroup(t *testing.T) {
}
} else {
t.Errorf("waiting for child process: got unexpected error type %v (%T); want (%T)",
err, err, wantErr)
err, err, (*exec.ExitError)(nil))
}

gotLines := strings.SplitAfter(out.String(), "\n")
Expand Down
9 changes: 3 additions & 6 deletions task.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,7 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error {
e.Logger.VerboseErrf(logger.Yellow, "task: error cleaning status on error: %v\n", err2)
}

var exitCode interp.ExitStatus
if errors.As(err, &exitCode) {
if exitCode, ok := errors.AsType[interp.ExitStatus](err); ok {
if t.IgnoreError {
e.Logger.VerboseErrf(logger.Yellow, "task: task error ignored: %v\n", err)
continue
Expand Down Expand Up @@ -382,8 +381,7 @@ func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *Call, i in
defer reacquire()

err := e.RunTask(ctx, &Call{Task: cmd.Task, Vars: cmd.Vars, Silent: cmd.Silent, Indirect: true})
var exitCode interp.ExitStatus
if errors.As(err, &exitCode) && cmd.IgnoreError {
if _, ok := errors.AsType[interp.ExitStatus](err); ok && cmd.IgnoreError {
e.Logger.VerboseErrf(logger.Yellow, "task: [%s] task error ignored: %v\n", t.Name(), err)
return nil
}
Expand Down Expand Up @@ -426,8 +424,7 @@ func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *Call, i in
if closeErr := closer(err); closeErr != nil {
e.Logger.Errf(logger.Red, "task: unable to close writer: %v\n", closeErr)
}
var exitCode interp.ExitStatus
if errors.As(err, &exitCode) && cmd.IgnoreError {
if _, ok := errors.AsType[interp.ExitStatus](err); ok && cmd.IgnoreError {
e.Logger.VerboseErrf(logger.Yellow, "task: [%s] command error ignored: %v\n", t.Name(), err)
return nil
}
Expand Down
3 changes: 1 addition & 2 deletions taskfile/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,7 @@ func (r *Reader) readNode(ctx context.Context, node Node) (*ast.Taskfile, error)
var tf ast.Taskfile
if err := yaml.Unmarshal(b, &tf); err != nil {
// Decode the taskfile and add the file info the any errors
taskfileDecodeErr := &errors.TaskfileDecodeError{}
if errors.As(err, &taskfileDecodeErr) {
if taskfileDecodeErr, ok := errors.AsType[*errors.TaskfileDecodeError](err); ok {
snippet := NewSnippet(b,
WithLine(taskfileDecodeErr.Line),
WithColumn(taskfileDecodeErr.Column),
Expand Down
1 change: 0 additions & 1 deletion watch_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//go:build watch
// +build watch

package task_test

Expand Down
Loading