1
0
mirror of https://github.com/go-task/task.git synced 2025-02-03 13:22:11 +02:00

feat: add task location data to json output (#1056)

* feat: add task location data to json output

* feat: add root taskfile location to --json output
This commit is contained in:
Pete Davison 2023-03-17 12:34:06 +00:00 committed by GitHub
parent 15ef1fa1c2
commit e40d2eec9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 169 additions and 44 deletions

View File

@ -2,6 +2,10 @@
## Unreleased
- Added task location data to the `--json` flag output ([#1056](https://github.com/go-task/task/pull/1056) by @pd93)
## Unreleased
- Change the name of the file generated by `task --init` from `Taskfile.yaml`
to `Taskfile.yml`
([#1062](https://github.com/go-task/task/pull/1062) by @misitebao).
@ -9,6 +13,7 @@
(`{{splitArgs "foo bar 'foo bar baz'"}}`) to ensure string is splitted as
arguments not whitespaces
([#1040](https://github.com/go-task/task/issues/1040), [#1059](https://github.com/go-task/task/pull/1059) by @dhanusaputra).
- Added task location data to the `--json` flag output ([#1056](https://github.com/go-task/task/pull/1056) by @pd93)
## v3.22.0 - 2023-03-10

View File

@ -34,6 +34,7 @@ variable
| `-I` | `--interval` | `string` | `5s` | Sets a different watch interval when using `--watch`, the default being 5 seconds. This string should be a valid [Go Duration](https://pkg.go.dev/time#ParseDuration). |
| `-l` | `--list` | `bool` | `false` | Lists tasks with description of current Taskfile. |
| `-a` | `--list-all` | `bool` | `false` | Lists tasks with or without a description. |
| | `--json` | `bool` | `false` | See [JSON Output](#json-output) |
| `-o` | `--output` | `string` | Default set in the Taskfile or `intervealed` | Sets output style: [`interleaved`/`group`/`prefixed`]. |
| | `--output-group-begin` | `string` | | Message template to print before a task's grouped output. |
| | `--output-group-end` | `string` | | Message template to print after a task's grouped output. |
@ -47,6 +48,30 @@ variable
| | `--version` | `bool` | `false` | Show Task version. |
| `-w` | `--watch` | `bool` | `false` | Enables watch of the given task. |
## JSON Output
When using the `--json` flag in combination with either the `--list` or `--list-all` flags, the output will be a JSON object with the following structure:
```jsonc
{
"tasks": [
{
"name": "",
"desc": "",
"summary": "",
"up_to_date": false,
"location": {
"line": 54,
"column": 3,
"taskfile": "/path/to/Taskfile.yml"
}
},
// ...
],
"location": "/path/to/Taskfile.yml"
}
```
## Special Variables
There are some special variables that is available on the templating system:

64
help.go
View File

@ -11,6 +11,8 @@ import (
"strings"
"text/tabwriter"
"golang.org/x/sync/errgroup"
"github.com/go-task/task/v3/internal/editors"
"github.com/go-task/task/v3/internal/fingerprint"
"github.com/go-task/task/v3/internal/logger"
@ -144,31 +146,43 @@ func (e *Executor) ListTaskNames(allTasks bool) {
}
}
func (e *Executor) ToEditorOutput(tasks []*taskfile.Task) (*editors.Output, error) {
o := &editors.Output{
Tasks: make([]editors.Task, len(tasks)),
func (e *Executor) ToEditorOutput(tasks []*taskfile.Task) (*editors.Taskfile, error) {
o := &editors.Taskfile{
Tasks: make([]editors.Task, len(tasks)),
Location: e.Taskfile.Location,
}
for i, t := range tasks {
// Get the fingerprinting method to use
method := e.Taskfile.Method
if t.Method != "" {
method = t.Method
}
upToDate, err := fingerprint.IsTaskUpToDate(context.Background(), t,
fingerprint.WithMethod(method),
fingerprint.WithTempDir(e.TempDir),
fingerprint.WithDry(e.Dry),
fingerprint.WithLogger(e.Logger),
)
if err != nil {
return nil, err
}
o.Tasks[i] = editors.Task{
Name: t.Name(),
Desc: t.Desc,
Summary: t.Summary,
UpToDate: upToDate,
}
var g errgroup.Group
for i := range tasks {
task := tasks[i]
j := i
g.Go(func() error {
// Get the fingerprinting method to use
method := e.Taskfile.Method
if task.Method != "" {
method = task.Method
}
upToDate, err := fingerprint.IsTaskUpToDate(context.Background(), task,
fingerprint.WithMethod(method),
fingerprint.WithTempDir(e.TempDir),
fingerprint.WithDry(e.Dry),
fingerprint.WithLogger(e.Logger),
)
if err != nil {
return err
}
o.Tasks[j] = editors.Task{
Name: task.Name(),
Desc: task.Desc,
Summary: task.Summary,
UpToDate: upToDate,
Location: &editors.Location{
Line: task.Location.Line,
Column: task.Location.Column,
Taskfile: task.Location.Taskfile,
},
}
return nil
})
}
return o, nil
return o, g.Wait()
}

View File

@ -1,14 +1,23 @@
package editors
// Output wraps task list output for use in editor integrations (e.g. VSCode, etc)
type Output struct {
Tasks []Task `json:"tasks"`
}
// Task describes a single task
type Task struct {
Name string `json:"name"`
Desc string `json:"desc"`
Summary string `json:"summary"`
UpToDate bool `json:"up_to_date"`
}
type (
// Taskfile wraps task list output for use in editor integrations (e.g. VSCode, etc)
Taskfile struct {
Tasks []Task `json:"tasks"`
Location string `json:"location"`
}
// Task describes a single task
Task struct {
Name string `json:"name"`
Desc string `json:"desc"`
Summary string `json:"summary"`
UpToDate bool `json:"up_to_date"`
Location *Location `json:"location"`
}
// Location describes a task's location in a taskfile
Location struct {
Line int `json:"line"`
Column int `json:"column"`
Taskfile string `json:"taskfile"`
}
)

18
taskfile/location.go Normal file
View File

@ -0,0 +1,18 @@
package taskfile
type Location struct {
Line int
Column int
Taskfile string
}
func (l *Location) DeepCopy() *Location {
if l == nil {
return nil
}
return &Location{
Line: l.Line,
Column: l.Column,
Taskfile: l.Taskfile,
}
}

View File

@ -65,7 +65,9 @@ func Merge(t1, t2 *Taskfile, includedTaskfile *IncludedTaskfile, namespaces ...s
}
// Add the task to the merged taskfile
t1.Tasks[taskNameWithNamespace(k, namespaces...)] = task
taskNameWithNamespace := taskNameWithNamespace(k, namespaces...)
task.Task = taskNameWithNamespace
t1.Tasks[taskNameWithNamespace] = task
}
return nil

View File

@ -176,12 +176,18 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, string, error) {
}
}
for name, task := range t.Tasks {
// Set the location of the Taskfile
t.Location = path
for _, task := range t.Tasks {
// If the task is not defined, create a new one
if task == nil {
task = &taskfile.Task{}
t.Tasks[name] = task
}
task.Task = name
// Set the location of the taskfile for each task
if task.Location.Taskfile == "" {
task.Location.Taskfile = path
}
}
return t, readerNode.Dir, nil

View File

@ -6,9 +6,6 @@ import (
"gopkg.in/yaml.v3"
)
// Tasks represents a group of tasks
type Tasks map[string]*Task
// Task represents a task
type Task struct {
Task string
@ -39,6 +36,7 @@ type Task struct {
IncludedTaskfileVars *Vars
IncludedTaskfile *IncludedTaskfile
Platforms []*Platform
Location *Location
}
func (t *Task) Name() string {
@ -162,6 +160,7 @@ func (t *Task) DeepCopy() *Task {
IncludedTaskfileVars: t.IncludedTaskfileVars.DeepCopy(),
IncludedTaskfile: t.IncludedTaskfile.DeepCopy(),
Platforms: deepCopySlice(t.Platforms),
Location: t.Location.DeepCopy(),
}
return c
}

View File

@ -15,6 +15,7 @@ var (
// Taskfile represents a Taskfile.yml
type Taskfile struct {
Location string
Version *semver.Version
Expansions int
Output Output

45
taskfile/tasks.go Normal file
View File

@ -0,0 +1,45 @@
package taskfile
import (
"fmt"
"gopkg.in/yaml.v3"
)
// Tasks represents a group of tasks
type Tasks map[string]*Task
func (t *Tasks) UnmarshalYAML(node *yaml.Node) error {
switch node.Kind {
case yaml.MappingNode:
tasks := map[string]*Task{}
if err := node.Decode(tasks); err != nil {
return err
}
for name := range tasks {
// Set the task's name
if tasks[name] == nil {
tasks[name] = &Task{
Task: name,
}
}
tasks[name].Task = name
// Set the task's location
for _, keys := range node.Content {
if keys.Value == name {
tasks[name].Location = &Location{
Line: keys.Line,
Column: keys.Column,
}
}
}
}
*t = Tasks(tasks)
return nil
}
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into tasks", node.Line, node.ShortTag())
}

View File

@ -66,6 +66,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
IncludeVars: origTask.IncludeVars,
IncludedTaskfileVars: origTask.IncludedTaskfileVars,
Platforms: origTask.Platforms,
Location: origTask.Location,
}
new.Dir, err = execext.Expand(new.Dir)
if err != nil {