Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: iterators #1798

Draft
wants to merge 3 commits into
base: orderedmap
Choose a base branch
from
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 @@ -13,7 +13,7 @@ jobs:
name: Lint
strategy:
matrix:
go-version: [1.22.x, 1.23.x]
go-version: [1.23.x, 1.24.x]
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v5
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.22.x
go-version: 1.23.x

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
name: Test
strategy:
matrix:
go-version: [1.22.x, 1.23.x]
go-version: [1.23.x, 1.24.x]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{matrix.platform}}
steps:
Expand Down
6 changes: 3 additions & 3 deletions cmd/task/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ func run() error {
dir = home
}

var taskSorter sort.TaskSorter
var taskSorter sort.Sorter
switch flags.TaskSort {
case "none":
taskSorter = &sort.Noop{}
taskSorter = nil
case "alphanumeric":
taskSorter = &sort.AlphaNumeric{}
taskSorter = sort.AlphaNumeric
}

e := task.Executor{
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.22.0
go 1.23.0

require (
github.com/Ladicle/tabwriter v1.0.0
Expand Down
8 changes: 2 additions & 6 deletions help.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,18 +128,14 @@ func (e *Executor) ListTaskNames(allTasks bool) error {
w = e.Stdout
}

// Get the list of tasks and sort them
tasks := e.Taskfile.Tasks.Values()

// Sort the tasks
if e.TaskSorter == nil {
e.TaskSorter = &sort.AlphaNumericWithRootTasksFirst{}
e.TaskSorter = sort.AlphaNumericWithRootTasksFirst
}
e.TaskSorter.Sort(tasks)

// Create a list of task names
taskNames := make([]string, 0, e.Taskfile.Tasks.Len())
for _, task := range tasks {
for task := range e.Taskfile.Tasks.Values(e.TaskSorter) {
if (allTasks || task.Desc != "") && !task.Internal {
taskNames = append(taskNames, strings.TrimRight(task.Task, ":"))
for _, alias := range task.Aliases {
Expand Down
36 changes: 24 additions & 12 deletions internal/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,30 +104,42 @@ func (c *Compiler) getVariables(t *ast.Task, call *ast.Call, evaluateShVars bool
taskRangeFunc = getRangeFunc(dir)
}

if err := c.TaskfileEnv.Range(rangeFunc); err != nil {
return nil, err
for k, v := range c.TaskfileEnv.All() {
if err := rangeFunc(k, v); err != nil {
return nil, err
}
}
if err := c.TaskfileVars.Range(rangeFunc); err != nil {
return nil, err
for k, v := range c.TaskfileVars.All() {
if err := rangeFunc(k, v); err != nil {
return nil, err
}
}
if t != nil {
if err := t.IncludeVars.Range(rangeFunc); err != nil {
return nil, err
for k, v := range t.IncludeVars.All() {
if err := rangeFunc(k, v); err != nil {
return nil, err
}
}
if err := t.IncludedTaskfileVars.Range(taskRangeFunc); err != nil {
return nil, err
for k, v := range t.IncludedTaskfileVars.All() {
if err := taskRangeFunc(k, v); err != nil {
return nil, err
}
}
}

if t == nil || call == nil {
return result, nil
}

if err := call.Vars.Range(rangeFunc); err != nil {
return nil, err
for k, v := range call.Vars.All() {
if err := rangeFunc(k, v); err != nil {
return nil, err
}
}
if err := t.Vars.Range(taskRangeFunc); err != nil {
return nil, err
for k, v := range t.Vars.All() {
if err := taskRangeFunc(k, v); err != nil {
return nil, err
}
}

return result, nil
Expand Down
46 changes: 21 additions & 25 deletions internal/sort/sorter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,38 @@ package sort
import (
"sort"
"strings"

"github.com/go-task/task/v3/taskfile/ast"
)

type TaskSorter interface {
Sort([]*ast.Task)
}

type Noop struct{}
// A Sorter is any function that sorts a set of tasks.
type Sorter func(items []string, namespaces []string) []string

func (s *Noop) Sort(tasks []*ast.Task) {}

type AlphaNumeric struct{}

// Tasks that are not namespaced should be listed before tasks that are.
// We detect this by searching for a ':' in the task name.
func (s *AlphaNumeric) Sort(tasks []*ast.Task) {
sort.Slice(tasks, func(i, j int) bool {
return tasks[i].Task < tasks[j].Task
// AlphaNumeric sorts the JSON output so that tasks are in alpha numeric order
// by task name.
func AlphaNumeric(items []string, namespaces []string) []string {
sort.Slice(items, func(i, j int) bool {
return items[i] < items[j]
})
return items
}

type AlphaNumericWithRootTasksFirst struct{}

// Tasks that are not namespaced should be listed before tasks that are.
// We detect this by searching for a ':' in the task name.
func (s *AlphaNumericWithRootTasksFirst) Sort(tasks []*ast.Task) {
sort.Slice(tasks, func(i, j int) bool {
iContainsColon := strings.Contains(tasks[i].Task, ":")
jContainsColon := strings.Contains(tasks[j].Task, ":")
// AlphaNumericWithRootTasksFirst sorts the JSON output so that tasks are in
// alpha numeric order by task name. It will also ensure that tasks that are not
// namespaced will be listed before tasks that are. We detect this by searching
// for a ':' in the task name.
func AlphaNumericWithRootTasksFirst(items []string, namespaces []string) []string {
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 tasks[i].Task < tasks[j].Task
return items[i] < items[j]
}
if !iContainsColon && jContainsColon {
return true
}
return false
})
return items
}
68 changes: 32 additions & 36 deletions internal/sort/sorter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,74 +4,70 @@ import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/go-task/task/v3/taskfile/ast"
)

func TestAlphaNumericWithRootTasksFirst_Sort(t *testing.T) {
task1 := &ast.Task{Task: "task1"}
task2 := &ast.Task{Task: "task2"}
task3 := &ast.Task{Task: "ns1:task3"}
task4 := &ast.Task{Task: "ns2:task4"}
task5 := &ast.Task{Task: "task5"}
task6 := &ast.Task{Task: "ns3:task6"}
item1 := "a-item1"
item2 := "m-item2"
item3 := "ns1:item3"
item4 := "ns2:item4"
item5 := "z-item5"
item6 := "ns3:item6"

tests := []struct {
name string
tasks []*ast.Task
want []*ast.Task
items []string
want []string
}{
{
name: "no namespace tasks sorted alphabetically first",
tasks: []*ast.Task{task3, task2, task1},
want: []*ast.Task{task1, task2, task3},
name: "no namespace items sorted alphabetically first",
items: []string{item3, item2, item1},
want: []string{item1, item2, item3},
},
{
name: "namespace tasks sorted alphabetically after non-namespaced tasks",
tasks: []*ast.Task{task3, task4, task5},
want: []*ast.Task{task5, task3, task4},
name: "namespace items sorted alphabetically after non-namespaced items",
items: []string{item3, item4, item5},
want: []string{item5, item3, item4},
},
{
name: "all tasks sorted alphabetically with root tasks first",
tasks: []*ast.Task{task6, task5, task4, task3, task2, task1},
want: []*ast.Task{task1, task2, task5, task3, task4, task6},
name: "all items sorted alphabetically with root items first",
items: []string{item6, item5, item4, item3, item2, item1},
want: []string{item1, item2, item5, item3, item4, item6},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &AlphaNumericWithRootTasksFirst{}
s.Sort(tt.tasks)
assert.Equal(t, tt.want, tt.tasks)
AlphaNumericWithRootTasksFirst(tt.items, nil)
assert.Equal(t, tt.want, tt.items)
})
}
}

func TestAlphaNumeric_Sort(t *testing.T) {
task1 := &ast.Task{Task: "task1"}
task2 := &ast.Task{Task: "task2"}
task3 := &ast.Task{Task: "ns1:task3"}
task4 := &ast.Task{Task: "ns2:task4"}
task5 := &ast.Task{Task: "task5"}
task6 := &ast.Task{Task: "ns3:task6"}
item1 := "a-item1"
item2 := "m-item2"
item3 := "ns1:item3"
item4 := "ns2:item4"
item5 := "z-item5"
item6 := "ns3:item6"

tests := []struct {
name string
tasks []*ast.Task
want []*ast.Task
items []string
want []string
}{
{
name: "all tasks sorted alphabetically",
tasks: []*ast.Task{task3, task2, task5, task1, task4, task6},
want: []*ast.Task{task3, task4, task6, task1, task2, task5},
name: "all items sorted alphabetically",
items: []string{item3, item2, item5, item1, item4, item6},
want: []string{item1, item2, item3, item4, item6, item5},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &AlphaNumeric{}
s.Sort(tt.tasks)
assert.Equal(t, tt.tasks, tt.want)
AlphaNumeric(tt.items, nil)
assert.Equal(t, tt.want, tt.items)
})
}
}
5 changes: 2 additions & 3 deletions internal/templater/templater.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,9 @@ func ReplaceVarsWithExtra(vars *ast.Vars, cache *Cache, extra map[string]any) *a
}

var newVars ast.Vars
_ = vars.Range(func(k string, v ast.Var) error {
for k, v := range vars.All() {
newVars.Set(k, ReplaceVarWithExtra(v, cache, extra))
return nil
})
}

return &newVars
}
20 changes: 8 additions & 12 deletions setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,9 @@ func (e *Executor) setupFuzzyModel() {
model.SetThreshold(1) // because we want to build grammar based on every task name

var words []string
for _, taskName := range e.Taskfile.Tasks.Keys() {
words = append(words, taskName)

for _, task := range e.Taskfile.Tasks.Values() {
words = slices.Concat(words, task.Aliases)
}
for name, task := range e.Taskfile.Tasks.All(nil) {
words = append(words, name)
words = slices.Concat(words, task.Aliases)
}

model.Train(words)
Expand Down Expand Up @@ -212,12 +209,11 @@ func (e *Executor) readDotEnvFiles() error {
return err
}

err = env.Range(func(key string, value ast.Var) error {
if _, ok := e.Taskfile.Env.Get(key); !ok {
e.Taskfile.Env.Set(key, value)
for k, v := range env.All() {
if _, ok := e.Taskfile.Env.Get(k); !ok {
e.Taskfile.Env.Set(k, v)
}
return nil
})
}
return err
}

Expand All @@ -235,7 +231,7 @@ func (e *Executor) setupConcurrencyState() {

e.taskCallCount = make(map[string]*int32, e.Taskfile.Tasks.Len())
e.mkdirMutexMap = make(map[string]*sync.Mutex, e.Taskfile.Tasks.Len())
for _, k := range e.Taskfile.Tasks.Keys() {
for k := range e.Taskfile.Tasks.Keys(nil) {
e.taskCallCount[k] = new(int32)
e.mkdirMutexMap[k] = &sync.Mutex{}
}
Expand Down
17 changes: 8 additions & 9 deletions task.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ type Executor struct {
Compiler *compiler.Compiler
Output output.Output
OutputStyle ast.Output
TaskSorter sort.TaskSorter
TaskSorter sort.Sorter
UserWorkingDir string

fuzzyModel *fuzzy.Model
Expand Down Expand Up @@ -462,7 +462,7 @@ func (e *Executor) GetTask(call *ast.Call) (*ast.Task, error) {
// If didn't find one, search for a task with a matching alias
var matchingTask *ast.Task
var aliasedTasks []string
for _, task := range e.Taskfile.Tasks.Values() {
for task := range e.Taskfile.Tasks.Values(nil) {
if slices.Contains(task.Aliases, call.Task) {
aliasedTasks = append(aliasedTasks, task.Task)
matchingTask = task
Expand Down Expand Up @@ -498,8 +498,13 @@ func (e *Executor) GetTaskList(filters ...FilterFunc) ([]*ast.Task, error) {
// Create an error group to wait for each task to be compiled
var g errgroup.Group

// Sort the tasks
if e.TaskSorter == nil {
e.TaskSorter = sort.AlphaNumericWithRootTasksFirst
}

// Filter tasks based on the given filter functions
for _, task := range e.Taskfile.Tasks.Values() {
for task := range e.Taskfile.Tasks.Values(e.TaskSorter) {
var shouldFilter bool
for _, filter := range filters {
if filter(task) {
Expand Down Expand Up @@ -528,12 +533,6 @@ func (e *Executor) GetTaskList(filters ...FilterFunc) ([]*ast.Task, error) {
return nil, err
}

// Sort the tasks
if e.TaskSorter == nil {
e.TaskSorter = &sort.AlphaNumericWithRootTasksFirst{}
}
e.TaskSorter.Sort(tasks)

return tasks, nil
}

Expand Down
Loading
Loading