mirror of
https://github.com/go-task/task.git
synced 2024-12-14 10:52:43 +02:00
commit
d516b238b1
3
.gitignore
vendored
3
.gitignore
vendored
@ -18,3 +18,6 @@
|
||||
dist/
|
||||
|
||||
.DS_Store
|
||||
|
||||
# intellij idea/goland
|
||||
.idea/
|
||||
|
@ -17,7 +17,7 @@ var (
|
||||
version = "master"
|
||||
)
|
||||
|
||||
const usage = `Usage: task [-ilfwvsd] [--init] [--list] [--force] [--watch] [--verbose] [--silent] [--dir] [--dry] [task...]
|
||||
const usage = `Usage: task [-ilfwvsd] [--init] [--list] [--force] [--watch] [--verbose] [--silent] [--dir] [--dry] [--summary] [task...]
|
||||
|
||||
Runs the specified task(s). Falls back to the "default" task if no task name
|
||||
was specified, or lists all tasks if an unknown task name was specified.
|
||||
@ -56,6 +56,7 @@ func main() {
|
||||
verbose bool
|
||||
silent bool
|
||||
dry bool
|
||||
summary bool
|
||||
dir string
|
||||
output string
|
||||
)
|
||||
@ -69,6 +70,7 @@ func main() {
|
||||
pflag.BoolVarP(&verbose, "verbose", "v", false, "enables verbose mode")
|
||||
pflag.BoolVarP(&silent, "silent", "s", false, "disables echoing")
|
||||
pflag.BoolVar(&dry, "dry", false, "compiles and prints tasks in the order that they would be run, without executing them")
|
||||
pflag.BoolVar(&summary, "summary", false, "show summary about a task")
|
||||
pflag.StringVarP(&dir, "dir", "d", "", "sets directory of execution")
|
||||
pflag.StringVarP(&output, "output", "o", "", "sets output style: [interleaved|group|prefixed]")
|
||||
pflag.Parse()
|
||||
@ -96,6 +98,7 @@ func main() {
|
||||
Silent: silent,
|
||||
Dir: dir,
|
||||
Dry: dry,
|
||||
Summary: summary,
|
||||
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
|
@ -542,6 +542,51 @@ would print the following output:
|
||||
* test: Run all the go tests.
|
||||
```
|
||||
|
||||
## Display summary of task
|
||||
|
||||
Running `task --summary task-name` will show a summary of a task
|
||||
The following Taskfile:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
tasks:
|
||||
release:
|
||||
deps: [build]
|
||||
summary: |
|
||||
Release your project to github
|
||||
|
||||
It will build your project before starting the release it.
|
||||
Please make sure that you have set GITHUB_TOKEN before starting.
|
||||
cmds:
|
||||
- your-release-tool
|
||||
|
||||
build:
|
||||
cmds:
|
||||
- your-build-tool
|
||||
```
|
||||
|
||||
with running ``task --summary release`` would print the following output:
|
||||
|
||||
```
|
||||
task: release
|
||||
|
||||
Release your project to github
|
||||
|
||||
It will build your project before starting the release it.
|
||||
Please make sure that you have set GITHUB_TOKEN before starting.
|
||||
|
||||
dependencies:
|
||||
- build
|
||||
|
||||
commands:
|
||||
- your-release-tool
|
||||
```
|
||||
If a summary is missing, the description will be printed.
|
||||
If the task does not have a summary or a description, a warning is printed.
|
||||
|
||||
Please note: *showing the summary will not execute the command*.
|
||||
|
||||
## Silent mode
|
||||
|
||||
Silent mode disables echoing of commands before Task runs it.
|
||||
|
103
internal/summary/summary.go
Normal file
103
internal/summary/summary.go
Normal file
@ -0,0 +1,103 @@
|
||||
package summary
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
)
|
||||
|
||||
func PrintTasks(l *logger.Logger, t *taskfile.Taskfile, c []taskfile.Call) {
|
||||
for i, call := range c {
|
||||
printSpaceBetweenSummaries(l, i)
|
||||
PrintTask(l, t.Tasks[call.Task])
|
||||
}
|
||||
}
|
||||
|
||||
func printSpaceBetweenSummaries(l *logger.Logger, i int) {
|
||||
spaceRequired := i > 0
|
||||
if !spaceRequired {
|
||||
return
|
||||
}
|
||||
|
||||
l.Outf("")
|
||||
l.Outf("")
|
||||
}
|
||||
|
||||
func PrintTask(l *logger.Logger, t *taskfile.Task) {
|
||||
printTaskName(l, t)
|
||||
printTaskDescribingText(t, l)
|
||||
printTaskDependencies(l, t)
|
||||
printTaskCommands(l, t)
|
||||
}
|
||||
|
||||
func printTaskDescribingText(t *taskfile.Task, l *logger.Logger) {
|
||||
if hasSummary(t) {
|
||||
printTaskSummary(l, t)
|
||||
} else if hasDescription(t) {
|
||||
printTaskDescription(l, t)
|
||||
} else {
|
||||
printNoDescriptionOrSummary(l)
|
||||
}
|
||||
}
|
||||
|
||||
func hasSummary(t *taskfile.Task) bool {
|
||||
return t.Summary != ""
|
||||
}
|
||||
|
||||
func printTaskSummary(l *logger.Logger, t *taskfile.Task) {
|
||||
lines := strings.Split(t.Summary, "\n")
|
||||
for i, line := range lines {
|
||||
notLastLine := i+1 < len(lines)
|
||||
if notLastLine || line != "" {
|
||||
l.Outf(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printTaskName(l *logger.Logger, t *taskfile.Task) {
|
||||
l.Outf("task: %s", t.Task)
|
||||
l.Outf("")
|
||||
}
|
||||
|
||||
func hasDescription(t *taskfile.Task) bool {
|
||||
return t.Desc != ""
|
||||
}
|
||||
|
||||
func printTaskDescription(l *logger.Logger, t *taskfile.Task) {
|
||||
l.Outf(t.Desc)
|
||||
}
|
||||
|
||||
func printNoDescriptionOrSummary(l *logger.Logger) {
|
||||
l.Outf("(task does not have description or summary)")
|
||||
}
|
||||
|
||||
func printTaskDependencies(l *logger.Logger, t *taskfile.Task) {
|
||||
if len(t.Deps) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
l.Outf("")
|
||||
l.Outf("dependencies:")
|
||||
|
||||
for _, d := range t.Deps {
|
||||
l.Outf(" - %s", d.Task)
|
||||
}
|
||||
}
|
||||
|
||||
func printTaskCommands(l *logger.Logger, t *taskfile.Task) {
|
||||
if len(t.Cmds) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
l.Outf("")
|
||||
l.Outf("commands:")
|
||||
for _, c := range t.Cmds {
|
||||
isCommand := c.Cmd != ""
|
||||
if isCommand {
|
||||
l.Outf(" - %s", c.Cmd)
|
||||
} else {
|
||||
l.Outf(" - Task: %s", c.Task)
|
||||
}
|
||||
}
|
||||
}
|
173
internal/summary/summary_test.go
Normal file
173
internal/summary/summary_test.go
Normal file
@ -0,0 +1,173 @@
|
||||
package summary_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/summary"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPrintsDependenciesIfPresent(t *testing.T) {
|
||||
buffer, l := createDummyLogger()
|
||||
task := &taskfile.Task{
|
||||
Deps: []*taskfile.Dep{
|
||||
{Task: "dep1"},
|
||||
{Task: "dep2"},
|
||||
{Task: "dep3"},
|
||||
},
|
||||
}
|
||||
|
||||
summary.PrintTask(&l, task)
|
||||
|
||||
assert.Contains(t, buffer.String(), "\ndependencies:\n - dep1\n - dep2\n - dep3\n")
|
||||
}
|
||||
|
||||
func createDummyLogger() (*bytes.Buffer, logger.Logger) {
|
||||
buffer := &bytes.Buffer{}
|
||||
l := logger.Logger{
|
||||
Stderr: buffer,
|
||||
Stdout: buffer,
|
||||
Verbose: false,
|
||||
}
|
||||
return buffer, l
|
||||
}
|
||||
|
||||
func TestDoesNotPrintDependenciesIfMissing(t *testing.T) {
|
||||
buffer, l := createDummyLogger()
|
||||
task := &taskfile.Task{
|
||||
Deps: []*taskfile.Dep{},
|
||||
}
|
||||
|
||||
summary.PrintTask(&l, task)
|
||||
|
||||
assert.NotContains(t, buffer.String(), "dependencies:")
|
||||
}
|
||||
|
||||
func TestPrintTaskName(t *testing.T) {
|
||||
buffer, l := createDummyLogger()
|
||||
task := &taskfile.Task{
|
||||
Task: "my-task-name",
|
||||
}
|
||||
|
||||
summary.PrintTask(&l, task)
|
||||
|
||||
assert.Contains(t, buffer.String(), "task: my-task-name\n")
|
||||
}
|
||||
|
||||
func TestPrintTaskCommandsIfPresent(t *testing.T) {
|
||||
buffer, l := createDummyLogger()
|
||||
task := &taskfile.Task{
|
||||
Cmds: []*taskfile.Cmd{
|
||||
{Cmd: "command-1"},
|
||||
{Cmd: "command-2"},
|
||||
{Task: "task-1"},
|
||||
},
|
||||
}
|
||||
|
||||
summary.PrintTask(&l, task)
|
||||
|
||||
assert.Contains(t, buffer.String(), "\ncommands:\n")
|
||||
assert.Contains(t, buffer.String(), "\n - command-1\n")
|
||||
assert.Contains(t, buffer.String(), "\n - command-2\n")
|
||||
assert.Contains(t, buffer.String(), "\n - Task: task-1\n")
|
||||
}
|
||||
|
||||
func TestDoesNotPrintCommandIfMissing(t *testing.T) {
|
||||
buffer, l := createDummyLogger()
|
||||
task := &taskfile.Task{
|
||||
Cmds: []*taskfile.Cmd{},
|
||||
}
|
||||
|
||||
summary.PrintTask(&l, task)
|
||||
|
||||
assert.NotContains(t, buffer.String(), "commands")
|
||||
}
|
||||
|
||||
func TestLayout(t *testing.T) {
|
||||
buffer, l := createDummyLogger()
|
||||
task := &taskfile.Task{
|
||||
Task: "sample-task",
|
||||
Summary: "line1\nline2\nline3\n",
|
||||
Deps: []*taskfile.Dep{
|
||||
{Task: "dependency"},
|
||||
},
|
||||
Cmds: []*taskfile.Cmd{
|
||||
{Cmd: "command"},
|
||||
},
|
||||
}
|
||||
|
||||
summary.PrintTask(&l, task)
|
||||
|
||||
assert.Equal(t, expectedOutput(), buffer.String())
|
||||
}
|
||||
|
||||
func expectedOutput() string {
|
||||
expected := `task: sample-task
|
||||
|
||||
line1
|
||||
line2
|
||||
line3
|
||||
|
||||
dependencies:
|
||||
- dependency
|
||||
|
||||
commands:
|
||||
- command
|
||||
`
|
||||
return expected
|
||||
}
|
||||
|
||||
func TestPrintDescriptionAsFallback(t *testing.T) {
|
||||
buffer, l := createDummyLogger()
|
||||
taskWithoutSummary := &taskfile.Task{
|
||||
Desc: "description",
|
||||
}
|
||||
|
||||
taskWithSummary := &taskfile.Task{
|
||||
Desc: "description",
|
||||
Summary: "summary",
|
||||
}
|
||||
taskWithoutSummaryOrDescription := &taskfile.Task{}
|
||||
|
||||
summary.PrintTask(&l, taskWithoutSummary)
|
||||
|
||||
assert.Contains(t, buffer.String(), "description")
|
||||
|
||||
buffer.Reset()
|
||||
summary.PrintTask(&l, taskWithSummary)
|
||||
|
||||
assert.NotContains(t, buffer.String(), "description")
|
||||
|
||||
buffer.Reset()
|
||||
summary.PrintTask(&l, taskWithoutSummaryOrDescription)
|
||||
|
||||
assert.Contains(t, buffer.String(), "\n(task does not have description or summary)\n")
|
||||
|
||||
}
|
||||
|
||||
func TestPrintAllWithSpaces(t *testing.T) {
|
||||
buffer, l := createDummyLogger()
|
||||
|
||||
t1 := &taskfile.Task{Task: "t1"}
|
||||
t2 := &taskfile.Task{Task: "t2"}
|
||||
t3 := &taskfile.Task{Task: "t3"}
|
||||
|
||||
tasks := make(taskfile.Tasks, 3)
|
||||
tasks["t1"] = t1
|
||||
tasks["t2"] = t2
|
||||
tasks["t3"] = t3
|
||||
|
||||
summary.PrintTasks(&l,
|
||||
&taskfile.Taskfile{Tasks: tasks},
|
||||
[]taskfile.Call{{Task: "t1"}, {Task: "t2"}, {Task: "t3"}})
|
||||
|
||||
assert.True(t, strings.HasPrefix(buffer.String(), "task: t1"))
|
||||
assert.Contains(t, buffer.String(), "\n(task does not have description or summary)\n\n\ntask: t2")
|
||||
assert.Contains(t, buffer.String(), "\n(task does not have description or summary)\n\n\ntask: t3")
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package taskfile
|
||||
|
||||
// Tasks representas a group of tasks
|
||||
// Tasks represents a group of tasks
|
||||
type Tasks map[string]*Task
|
||||
|
||||
// Task represents a task
|
||||
@ -9,6 +9,7 @@ type Task struct {
|
||||
Cmds []*Cmd
|
||||
Deps []*Dep
|
||||
Desc string
|
||||
Summary string
|
||||
Sources []string
|
||||
Generates []string
|
||||
Status []string
|
||||
|
7
task.go
7
task.go
@ -13,6 +13,7 @@ import (
|
||||
"github.com/go-task/task/v2/internal/execext"
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/output"
|
||||
"github.com/go-task/task/v2/internal/summary"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v2/internal/taskfile/read"
|
||||
"github.com/go-task/task/v2/internal/taskfile/version"
|
||||
@ -36,6 +37,7 @@ type Executor struct {
|
||||
Verbose bool
|
||||
Silent bool
|
||||
Dry bool
|
||||
Summary bool
|
||||
|
||||
Stdin io.Reader
|
||||
Stdout io.Writer
|
||||
@ -62,6 +64,11 @@ func (e *Executor) Run(ctx context.Context, calls ...taskfile.Call) error {
|
||||
}
|
||||
}
|
||||
|
||||
if e.Summary {
|
||||
summary.PrintTasks(e.Logger, e.Taskfile, calls)
|
||||
return nil
|
||||
}
|
||||
|
||||
if e.Watch {
|
||||
return e.watchTasks(calls...)
|
||||
}
|
||||
|
22
task_test.go
22
task_test.go
@ -553,3 +553,25 @@ func TestIncludesCallingRoot(t *testing.T) {
|
||||
}
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestSummary(t *testing.T) {
|
||||
const dir = "testdata/summary"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Summary: true,
|
||||
Silent: true,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "task-with-summary"}, taskfile.Call{Task: "other-task-with-summary"}))
|
||||
assert.Equal(t, readTestFixture(t, dir, "task-with-summary.txt"), buff.String())
|
||||
}
|
||||
|
||||
func readTestFixture(t *testing.T, dir string, file string) string {
|
||||
b, err := ioutil.ReadFile(dir + "/" + file)
|
||||
assert.NoError(t, err, "error reading text fixture")
|
||||
return string(b)
|
||||
}
|
||||
|
26
testdata/summary/Taskfile.yml
vendored
Normal file
26
testdata/summary/Taskfile.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
version: 2
|
||||
|
||||
tasks:
|
||||
task-with-summary:
|
||||
deps: [dependend-task-1, dependend-task-2]
|
||||
summary: |
|
||||
summary of task-with-summary - line 1
|
||||
line 2
|
||||
line 3
|
||||
cmds:
|
||||
- echo 'task-with-summary was executed'
|
||||
- echo 'another command'
|
||||
- exit 0
|
||||
|
||||
other-task-with-summary:
|
||||
summary: summary of other-task-with-summary
|
||||
cmds:
|
||||
- echo 'other-task-with-summary was executed'
|
||||
|
||||
dependend-task-1:
|
||||
cmds:
|
||||
- echo 'dependend-task-1 was executed'
|
||||
|
||||
dependend-task-2:
|
||||
cmds:
|
||||
- echo 'dependend-task-2 was executed'
|
22
testdata/summary/task-with-summary.txt
vendored
Normal file
22
testdata/summary/task-with-summary.txt
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
task: task-with-summary
|
||||
|
||||
summary of task-with-summary - line 1
|
||||
line 2
|
||||
line 3
|
||||
|
||||
dependencies:
|
||||
- dependend-task-1
|
||||
- dependend-task-2
|
||||
|
||||
commands:
|
||||
- echo 'task-with-summary was executed'
|
||||
- echo 'another command'
|
||||
- exit 0
|
||||
|
||||
|
||||
task: other-task-with-summary
|
||||
|
||||
summary of other-task-with-summary
|
||||
|
||||
commands:
|
||||
- echo 'other-task-with-summary was executed'
|
Loading…
Reference in New Issue
Block a user