diff --git a/errors/errors.go b/errors/errors.go index ba871040..df684a47 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -17,7 +17,7 @@ const ( CodeTaskfileNotTrusted CodeTaskfileNotSecure CodeTaskfileCacheNotFound - CodeTaskfileVersionNotDefined + CodeTaskfileVersionCheckError CodeTaskfileNetworkTimeout ) diff --git a/errors/errors_taskfile.go b/errors/errors_taskfile.go index 9dc932f1..ddfb7392 100644 --- a/errors/errors_taskfile.go +++ b/errors/errors_taskfile.go @@ -4,6 +4,8 @@ import ( "fmt" "net/http" "time" + + "github.com/Masterminds/semver/v3" ) // TaskfileNotFoundError is returned when no appropriate Taskfile is found when @@ -122,21 +124,32 @@ func (err *TaskfileCacheNotFound) Code() int { return CodeTaskfileCacheNotFound } -// TaskfileVersionNotDefined is returned when the user attempts to run a -// Taskfile that does not contain a Taskfile schema version key. -type TaskfileVersionNotDefined struct { - URI string +// TaskfileVersionCheckError is returned when the user attempts to run a +// Taskfile that does not contain a Taskfile schema version key or if they try +// to use a feature that is not supported by the schema version. +type TaskfileVersionCheckError struct { + URI string + SchemaVersion *semver.Version + Message string } -func (err *TaskfileVersionNotDefined) Error() string { +func (err *TaskfileVersionCheckError) Error() string { + if err.SchemaVersion == nil { + return fmt.Sprintf( + `task: Missing schema version in Taskfile %q`, + err.URI, + ) + } return fmt.Sprintf( - `task: Taskfile %q does not contain a schema version key`, + "task: Invalid schema version in Taskfile %q:\nSchema version (%s) %s", err.URI, + err.SchemaVersion.String(), + err.Message, ) } -func (err *TaskfileVersionNotDefined) Code() int { - return CodeTaskfileVersionNotDefined +func (err *TaskfileVersionCheckError) Code() int { + return CodeTaskfileVersionCheckError } // TaskfileNetworkTimeout is returned when the user attempts to use a remote diff --git a/setup.go b/setup.go index 4bcf7339..bc8ae2d7 100644 --- a/setup.go +++ b/setup.go @@ -2,7 +2,6 @@ package task import ( "context" - "errors" "fmt" "os" "path/filepath" @@ -12,11 +11,13 @@ import ( "github.com/Masterminds/semver/v3" "github.com/sajari/fuzzy" + "github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/internal/compiler" "github.com/go-task/task/v3/internal/execext" "github.com/go-task/task/v3/internal/filepathext" "github.com/go-task/task/v3/internal/logger" "github.com/go-task/task/v3/internal/output" + "github.com/go-task/task/v3/internal/version" "github.com/go-task/task/v3/taskfile" "github.com/go-task/task/v3/taskfile/ast" ) @@ -241,35 +242,31 @@ func (e *Executor) setupConcurrencyState() { func (e *Executor) doVersionChecks() error { // Copy the version to avoid modifying the original - v := &semver.Version{} - *v = *e.Taskfile.Version + schemaVersion := &semver.Version{} + *schemaVersion = *e.Taskfile.Version - if v.LessThan(ast.V3) { - return fmt.Errorf(`task: Taskfile schemas prior to v3 are no longer supported`) - } - - // consider as equal to the greater version if round - if v.Equal(ast.V3) { - v = semver.MustParse("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`) - } - - 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`) - } - - if v.LessThan(semver.MustParse("3.7")) { - if e.Taskfile.Run != "" { - return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`) + // Error if the Taskfile uses a schema version below v3 + if schemaVersion.LessThan(ast.V3) { + return &errors.TaskfileVersionCheckError{ + URI: e.Taskfile.Location, + SchemaVersion: schemaVersion, + Message: `no longer supported. Please use v3 or above`, } + } - for _, task := range e.Taskfile.Tasks.Values() { - if task.Run != "" { - return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`) - } + // Get the current version of Task + // If we can't parse the version (e.g. when its "devel"), then ignore the current version checks + currentVersion, err := semver.NewVersion(version.GetVersion()) + if err != nil { + return nil + } + + // Error if the Taskfile uses a schema version above the current version of Task + if schemaVersion.GreaterThan(currentVersion) { + return &errors.TaskfileVersionCheckError{ + URI: e.Taskfile.Location, + SchemaVersion: schemaVersion, + Message: fmt.Sprintf(`is greater than the current version of Task (%s)`, currentVersion.String()), } } diff --git a/taskfile/ast/taskfile.go b/taskfile/ast/taskfile.go index 1e62c7ad..0ac0819a 100644 --- a/taskfile/ast/taskfile.go +++ b/taskfile/ast/taskfile.go @@ -6,8 +6,6 @@ import ( "github.com/Masterminds/semver/v3" "gopkg.in/yaml.v3" - - "github.com/go-task/task/v3/errors" ) var V3 = semver.MustParse("3") @@ -64,9 +62,6 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error { tf.Dotenv = taskfile.Dotenv tf.Run = taskfile.Run tf.Interval = taskfile.Interval - if tf.Version == nil { - return errors.New("task: 'version' is required") - } if tf.Vars == nil { tf.Vars = &Vars{} } diff --git a/taskfile/reader.go b/taskfile/reader.go index 13d83256..92784d6d 100644 --- a/taskfile/reader.go +++ b/taskfile/reader.go @@ -45,7 +45,7 @@ func Read( // Check that the Taskfile is set and has a schema version if t == nil || t.Version == nil { - return nil, &errors.TaskfileVersionNotDefined{URI: node.Location()} + return nil, &errors.TaskfileVersionCheckError{URI: node.Location()} } // Annotate any included Taskfile reference with a base directory for resolving relative paths