1
0
mirror of https://github.com/go-task/task.git synced 2025-08-10 22:42:19 +02:00

Merge pull request #1004 from go-task/semver

feat: use semver package for taskfile schema version
This commit is contained in:
Pete Davison
2023-03-02 19:07:52 +00:00
committed by GitHub
9 changed files with 53 additions and 68 deletions

View File

@@ -174,11 +174,6 @@ func main() {
if err := e.Setup(); err != nil { if err := e.Setup(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
v, err := e.Taskfile.ParsedVersion()
if err != nil {
log.Fatal(err)
return
}
if listOptions.ShouldListTasks() { if listOptions.ShouldListTasks() {
if foundTasks, err := e.ListTasks(listOptions); !foundTasks || err != nil { if foundTasks, err := e.ListTasks(listOptions); !foundTasks || err != nil {
@@ -197,7 +192,7 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
if v >= 3.0 { if e.Taskfile.Version.Compare(taskfile.V3) >= 0 {
calls, globals = args.ParseV3(tasksAndVars...) calls, globals = args.ParseV3(tasksAndVars...)
} else { } else {
calls, globals = args.ParseV2(tasksAndVars...) calls, globals = args.ParseV2(tasksAndVars...)

1
go.mod
View File

@@ -1,6 +1,7 @@
module github.com/go-task/task/v3 module github.com/go-task/task/v3
require ( require (
github.com/Masterminds/semver/v3 v3.2.0
github.com/fatih/color v1.14.1 github.com/fatih/color v1.14.1
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1

2
go.sum
View File

@@ -1,3 +1,5 @@
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=

View File

@@ -9,6 +9,9 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/Masterminds/semver/v3"
"github.com/sajari/fuzzy"
compilerv2 "github.com/go-task/task/v3/internal/compiler/v2" compilerv2 "github.com/go-task/task/v3/internal/compiler/v2"
compilerv3 "github.com/go-task/task/v3/internal/compiler/v3" compilerv3 "github.com/go-task/task/v3/internal/compiler/v3"
"github.com/go-task/task/v3/internal/execext" "github.com/go-task/task/v3/internal/execext"
@@ -17,8 +20,6 @@ import (
"github.com/go-task/task/v3/internal/output" "github.com/go-task/task/v3/internal/output"
"github.com/go-task/task/v3/taskfile" "github.com/go-task/task/v3/taskfile"
"github.com/go-task/task/v3/taskfile/read" "github.com/go-task/task/v3/taskfile/read"
"github.com/sajari/fuzzy"
) )
func (e *Executor) Setup() error { func (e *Executor) Setup() error {
@@ -32,11 +33,6 @@ func (e *Executor) Setup() error {
e.setupFuzzyModel() e.setupFuzzyModel()
v, err := e.Taskfile.ParsedVersion()
if err != nil {
return err
}
if err := e.setupTempDir(); err != nil { if err := e.setupTempDir(); err != nil {
return err return err
} }
@@ -45,17 +41,17 @@ func (e *Executor) Setup() error {
if err := e.setupOutput(); err != nil { if err := e.setupOutput(); err != nil {
return err return err
} }
if err := e.setupCompiler(v); err != nil { if err := e.setupCompiler(); err != nil {
return err return err
} }
if err := e.readDotEnvFiles(v); err != nil { if err := e.readDotEnvFiles(); err != nil {
return err return err
} }
if err := e.doVersionChecks(v); err != nil { if err := e.doVersionChecks(); err != nil {
return err return err
} }
e.setupDefaults(v) e.setupDefaults()
e.setupConcurrencyState() e.setupConcurrencyState()
return nil return nil
@@ -163,8 +159,8 @@ func (e *Executor) setupOutput() error {
return err return err
} }
func (e *Executor) setupCompiler(v float64) error { func (e *Executor) setupCompiler() error {
if v < 3 { if e.Taskfile.Version.LessThan(taskfile.V3) {
var err error var err error
e.taskvars, err = read.Taskvars(e.Dir) e.taskvars, err = read.Taskvars(e.Dir)
if err != nil { if err != nil {
@@ -195,8 +191,8 @@ func (e *Executor) setupCompiler(v float64) error {
return nil return nil
} }
func (e *Executor) readDotEnvFiles(v float64) error { func (e *Executor) readDotEnvFiles() error {
if v < 3.0 { if e.Taskfile.Version.LessThan(taskfile.V3) {
return nil return nil
} }
@@ -214,14 +210,14 @@ func (e *Executor) readDotEnvFiles(v float64) error {
return err return err
} }
func (e *Executor) setupDefaults(v float64) { func (e *Executor) setupDefaults() {
// Color available only on v3 // Color available only on v3
if v < 3 { if e.Taskfile.Version.LessThan(taskfile.V3) {
e.Logger.Color = false e.Logger.Color = false
} }
if e.Taskfile.Method == "" { if e.Taskfile.Method == "" {
if v >= 3 { if e.Taskfile.Version.Compare(taskfile.V3) >= 0 {
e.Taskfile.Method = "checksum" e.Taskfile.Method = "checksum"
} else { } else {
e.Taskfile.Method = "timestamp" e.Taskfile.Method = "timestamp"
@@ -248,37 +244,41 @@ func (e *Executor) setupConcurrencyState() {
} }
} }
func (e *Executor) doVersionChecks(v float64) error { func (e *Executor) doVersionChecks() error {
if v < 2 { // Copy the version to avoid modifying the original
v := &semver.Version{}
*v = *e.Taskfile.Version
if v.LessThan(taskfile.V2) {
return fmt.Errorf(`task: Taskfile versions prior to v2 are not supported anymore`) return fmt.Errorf(`task: Taskfile versions prior to v2 are not supported anymore`)
} }
// consider as equal to the greater version if round // consider as equal to the greater version if round
if v == 2.0 { if v.Equal(taskfile.V2) {
v = 2.6 v = semver.MustParse("2.6")
} }
if v == 3.0 { if v.Equal(taskfile.V3) {
v = 3.8 v = semver.MustParse("3.8")
} }
if v > 3.8 { if v.GreaterThan(semver.MustParse("3.8")) {
return fmt.Errorf(`task: Taskfile versions greater than v3.8 not implemented in the version of Task`) return fmt.Errorf(`task: Taskfile versions greater than v3.8 not implemented in the version of Task`)
} }
if v < 2.1 && !e.Taskfile.Output.IsSet() { if v.LessThan(semver.MustParse("2.1")) && !e.Taskfile.Output.IsSet() {
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`) return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
} }
if v < 2.2 && e.Taskfile.Includes.Len() > 0 { if v.LessThan(semver.MustParse("2.2")) && e.Taskfile.Includes.Len() > 0 {
return fmt.Errorf(`task: Including Taskfiles is only available starting on Taskfile version v2.2`) return fmt.Errorf(`task: Including Taskfiles is only available starting on Taskfile version v2.2`)
} }
if v >= 3.0 && e.Taskfile.Expansions > 2 { if v.Compare(taskfile.V3) >= 0 && e.Taskfile.Expansions > 2 {
return fmt.Errorf(`task: The "expansions" setting is not available anymore on v3.0`) return fmt.Errorf(`task: The "expansions" setting is not available anymore on v3.0`)
} }
if v < 3.8 && e.Taskfile.Output.Group.IsSet() { if v.LessThan(semver.MustParse("3.8")) && e.Taskfile.Output.Group.IsSet() {
return fmt.Errorf(`task: Taskfile option "output.group" is only available starting on Taskfile version v3.8`) return fmt.Errorf(`task: Taskfile option "output.group" is only available starting on Taskfile version v3.8`)
} }
if v <= 2.1 { if v.Compare(semver.MustParse("2.1")) <= 0 {
err := errors.New(`task: Taskfile option "ignore_error" is only available starting on Taskfile version v2.1`) err := errors.New(`task: Taskfile option "ignore_error" is only available starting on Taskfile version v2.1`)
for _, task := range e.Taskfile.Tasks { for _, task := range e.Taskfile.Tasks {
@@ -293,7 +293,7 @@ func (e *Executor) doVersionChecks(v float64) error {
} }
} }
if v < 2.6 { if v.LessThan(semver.MustParse("2.6")) {
for _, task := range e.Taskfile.Tasks { for _, task := range e.Taskfile.Tasks {
if len(task.Preconditions) > 0 { if len(task.Preconditions) > 0 {
return errors.New(`task: Task option "preconditions" is only available starting on Taskfile version v2.6`) return errors.New(`task: Task option "preconditions" is only available starting on Taskfile version v2.6`)
@@ -301,7 +301,7 @@ func (e *Executor) doVersionChecks(v float64) error {
} }
} }
if v < 3 { if v.LessThan(taskfile.V3) {
err := e.Taskfile.Includes.Range(func(_ string, taskfile taskfile.IncludedTaskfile) error { err := e.Taskfile.Includes.Range(func(_ string, taskfile taskfile.IncludedTaskfile) error {
if taskfile.AdvancedImport { if taskfile.AdvancedImport {
return errors.New(`task: Import with additional parameters is only available starting on Taskfile version v3`) return errors.New(`task: Import with additional parameters is only available starting on Taskfile version v3`)
@@ -313,7 +313,7 @@ func (e *Executor) doVersionChecks(v float64) error {
} }
} }
if v < 3.7 { if v.LessThan(semver.MustParse("3.7")) {
if e.Taskfile.Run != "" { if e.Taskfile.Run != "" {
return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`) return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`)
} }

View File

@@ -11,6 +11,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/Masterminds/semver/v3"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/go-task/task/v3" "github.com/go-task/task/v3"
@@ -728,9 +729,9 @@ func TestCyclicDep(t *testing.T) {
func TestTaskVersion(t *testing.T) { func TestTaskVersion(t *testing.T) {
tests := []struct { tests := []struct {
Dir string Dir string
Version string Version *semver.Version
}{ }{
{"testdata/version/v2", "2"}, {"testdata/version/v2", semver.MustParse("2")},
} }
for _, test := range tests { for _, test := range tests {

View File

@@ -10,7 +10,7 @@ const NamespaceSeparator = ":"
// Merge merges the second Taskfile into the first // Merge merges the second Taskfile into the first
func Merge(t1, t2 *Taskfile, includedTaskfile *IncludedTaskfile, namespaces ...string) error { func Merge(t1, t2 *Taskfile, includedTaskfile *IncludedTaskfile, namespaces ...string) error {
if t1.Version != t2.Version { if !t1.Version.Equal(t2.Version) {
return fmt.Errorf(`task: Taskfiles versions should match. First is "%s" but second is "%s"`, t1.Version, t2.Version) return fmt.Errorf(`task: Taskfiles versions should match. First is "%s" but second is "%s"`, t1.Version, t2.Version)
} }

View File

@@ -58,11 +58,6 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, string, error) {
return nil, "", err return nil, "", err
} }
v, err := t.ParsedVersion()
if err != nil {
return nil, "", err
}
// Annotate any included Taskfile reference with a base directory for resolving relative paths // Annotate any included Taskfile reference with a base directory for resolving relative paths
_ = t.Includes.Range(func(key string, includedFile taskfile.IncludedTaskfile) error { _ = t.Includes.Range(func(key string, includedFile taskfile.IncludedTaskfile) error {
// Set the base directory for resolving relative paths, but only if not already set // Set the base directory for resolving relative paths, but only if not already set
@@ -74,7 +69,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, string, error) {
}) })
err = t.Includes.Range(func(namespace string, includedTask taskfile.IncludedTaskfile) error { err = t.Includes.Range(func(namespace string, includedTask taskfile.IncludedTaskfile) error {
if v >= 3.0 { if t.Version.Compare(taskfile.V3) >= 0 {
tr := templater.Templater{Vars: t.Vars, RemoveNoValue: true} tr := templater.Templater{Vars: t.Vars, RemoveNoValue: true}
includedTask = taskfile.IncludedTaskfile{ includedTask = taskfile.IncludedTaskfile{
Taskfile: tr.Replace(includedTask.Taskfile), Taskfile: tr.Replace(includedTask.Taskfile),
@@ -123,7 +118,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, string, error) {
return err return err
} }
if v >= 3.0 && len(includedTaskfile.Dotenv) > 0 { if t.Version.Compare(taskfile.V3) >= 0 && len(includedTaskfile.Dotenv) > 0 {
return ErrIncludedTaskfilesCantHaveDotenvs return ErrIncludedTaskfilesCantHaveDotenvs
} }
@@ -168,7 +163,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, string, error) {
return nil, "", err return nil, "", err
} }
if v < 3.0 { if t.Version.Compare(taskfile.V3) < 0 {
path = filepathext.SmartJoin(readerNode.Dir, fmt.Sprintf("Taskfile_%s.yml", runtime.GOOS)) path = filepathext.SmartJoin(readerNode.Dir, fmt.Sprintf("Taskfile_%s.yml", runtime.GOOS))
if _, err = os.Stat(path); err == nil { if _, err = os.Stat(path); err == nil {
osTaskfile, err := readTaskfile(path) osTaskfile, err := readTaskfile(path)

View File

@@ -2,15 +2,20 @@ package taskfile
import ( import (
"fmt" "fmt"
"strconv"
"time" "time"
"github.com/Masterminds/semver/v3"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
var (
V3 = semver.MustParse("3")
V2 = semver.MustParse("2")
)
// Taskfile represents a Taskfile.yml // Taskfile represents a Taskfile.yml
type Taskfile struct { type Taskfile struct {
Version string Version *semver.Version
Expansions int Expansions int
Output Output Output Output
Method string Method string
@@ -31,7 +36,7 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error {
case yaml.MappingNode: case yaml.MappingNode:
var taskfile struct { var taskfile struct {
Version string Version *semver.Version
Expansions int Expansions int
Output Output Output Output
Method string Method string
@@ -77,12 +82,3 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error {
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into taskfile", node.Line, node.ShortTag()) return fmt.Errorf("yaml: line %d: cannot unmarshal %s into taskfile", node.Line, node.ShortTag())
} }
// ParsedVersion returns the version as a float64
func (tf *Taskfile) ParsedVersion() (float64, error) {
v, err := strconv.ParseFloat(tf.Version, 64)
if err != nil {
return 0, fmt.Errorf(`task: Could not parse taskfile version "%s": %v`, tf.Version, err)
}
return v, nil
}

View File

@@ -40,12 +40,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
return nil, err return nil, err
} }
v, err := e.Taskfile.ParsedVersion() r := templater.Templater{Vars: vars, RemoveNoValue: e.Taskfile.Version.Compare(taskfile.V3) >= 0}
if err != nil {
return nil, err
}
r := templater.Templater{Vars: vars, RemoveNoValue: v >= 3.0}
new := taskfile.Task{ new := taskfile.Task{
Task: origTask.Task, Task: origTask.Task,