feat: implement task sorting with --sort flag (#1105)

* refactor: move deepcopy into its own package

* feat: add generic orderedmap implementation

* refactor: implement tasks with orderedmap

* feat: implement sort flag for all task outputs

* refactor: implement vars with orderedmap

* chore: docs

* fix: linting issues

* fix: non deterministic behavior in tests
This commit is contained in:
Pete Davison
2023-04-06 12:07:57 +01:00
committed by GitHub
parent 719f30219b
commit f22389a824
25 changed files with 678 additions and 242 deletions

44
internal/sort/sorter.go Normal file
View File

@@ -0,0 +1,44 @@
package sort
import (
"sort"
"strings"
"github.com/go-task/task/v3/taskfile"
)
type TaskSorter interface {
Sort([]*taskfile.Task)
}
type Noop struct{}
func (s *Noop) Sort(tasks []*taskfile.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 []*taskfile.Task) {
sort.Slice(tasks, func(i, j int) bool {
return tasks[i].Task < tasks[j].Task
})
}
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 []*taskfile.Task) {
sort.Slice(tasks, func(i, j int) bool {
iContainsColon := strings.Contains(tasks[i].Task, ":")
jContainsColon := strings.Contains(tasks[j].Task, ":")
if iContainsColon == jContainsColon {
return tasks[i].Task < tasks[j].Task
}
if !iContainsColon && jContainsColon {
return true
}
return false
})
}

View File

@@ -0,0 +1,77 @@
package sort
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/go-task/task/v3/taskfile"
)
func TestAlphaNumericWithRootTasksFirst_Sort(t *testing.T) {
task1 := &taskfile.Task{Task: "task1"}
task2 := &taskfile.Task{Task: "task2"}
task3 := &taskfile.Task{Task: "ns1:task3"}
task4 := &taskfile.Task{Task: "ns2:task4"}
task5 := &taskfile.Task{Task: "task5"}
task6 := &taskfile.Task{Task: "ns3:task6"}
tests := []struct {
name string
tasks []*taskfile.Task
want []*taskfile.Task
}{
{
name: "no namespace tasks sorted alphabetically first",
tasks: []*taskfile.Task{task3, task2, task1},
want: []*taskfile.Task{task1, task2, task3},
},
{
name: "namespace tasks sorted alphabetically after non-namespaced tasks",
tasks: []*taskfile.Task{task3, task4, task5},
want: []*taskfile.Task{task5, task3, task4},
},
{
name: "all tasks sorted alphabetically with root tasks first",
tasks: []*taskfile.Task{task6, task5, task4, task3, task2, task1},
want: []*taskfile.Task{task1, task2, task5, task3, task4, task6},
},
}
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)
})
}
}
func TestAlphaNumeric_Sort(t *testing.T) {
task1 := &taskfile.Task{Task: "task1"}
task2 := &taskfile.Task{Task: "task2"}
task3 := &taskfile.Task{Task: "ns1:task3"}
task4 := &taskfile.Task{Task: "ns2:task4"}
task5 := &taskfile.Task{Task: "task5"}
task6 := &taskfile.Task{Task: "ns3:task6"}
tests := []struct {
name string
tasks []*taskfile.Task
want []*taskfile.Task
}{
{
name: "all tasks sorted alphabetically",
tasks: []*taskfile.Task{task3, task2, task5, task1, task4, task6},
want: []*taskfile.Task{task3, task4, task6, task1, task2, task5},
},
}
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)
})
}
}