Repository: go-task/task
Pull request #337 (2020-06-01 22:57:51)

Allow overriding the task name in the logger output
My attempt to solve issue described in #321 . Should work correctly though it needs review.

Simplest `Taskfile.yml` to demonstrate effects of this change:

```
version: '2'
tasks:
  default:
    deps:
      - task: test
        alias: "dep-foo"
    cmds:
      - task: test
        alias: "foo-bar"
      - task: test
  test:
    sources:
      - Taskfile.yml
    generates:
      - Taskfile.yml
```

Output before:

```
task: Task "test" is up to date
task: Task "test" is up to date
task: Task "test" is up to date
```

Expected output with change:

```
task: Task "dep-foo" is up to date
task: Task "foo-bar" is up to date
task: Task "test" is up to date
```

Also there were some concerns if name "alias" is a good one for such property. Of the top of my head I have two other options: "name-override" or "label". Are these any better?

adamwasila: I think I found sth that may be much more elegant solution to the problem I have. Here, I use alias (or label) on task itself and I can use variables to simply substitute it with any name I want when it is executed using deps or direct call. Example Taskfile with the syntax:

```
version: '3'
tasks:
  default:
    deps:
      - task: test
        vars: 
          ALIAS: IAMDEPTASK
    cmds:
      - task: test
        vars: 
          ALIAS: IAMSUBTASK
      - task: test
  test:
    alias: "{{.ALIAS}}"
    sources:
      - Taskfile.yml
    generates:
      - Taskfile.yml
```

As you may see, implementation is minimal and modifies just task struct but nothing else. Another advantage is it can be used to customize task name in every context, even if task is called directly.

Problems I found so far: in example above, last task currently generates message `task: Task "<no value>" is up to date` while it should use original name of the task in such case. But that seems trivial to fix.

I leaved all changes in this branch so far waiting for any comments, but if accepted only last commit will be one proposed to merge (updated with tests, documentation etc. if required).
andreynering: Hi @adamwasila,

I liked this approach, it seems really simple.

I like `label` much more than `alias`, though, specially because there's another feature request that would be called "alias" (https://github.com/go-task/task/issues/268) and this name makes more sense there than here.

Patch:
diff --git a/help.go b/help.go
index cfd6a109..0867ca5f 100644
--- a/help.go
+++ b/help.go
@@ -21,7 +21,7 @@ func (e *Executor) PrintTasksHelp() {
 	// Format in tab-separated columns with a tab stop of 8.
 	w := tabwriter.NewWriter(e.Stdout, 0, 8, 0, '\t', 0)
 	for _, task := range tasks {
-		fmt.Fprintf(w, "* %s: \t%s\n", task.Task, task.Desc)
+		fmt.Fprintf(w, "* %s: \t%s\n", task.Name(), task.Desc)
 	}
 	w.Flush()
 }
diff --git a/internal/summary/summary.go b/internal/summary/summary.go
index ea932187..baa4f481 100644
--- a/internal/summary/summary.go
+++ b/internal/summary/summary.go
@@ -56,7 +56,7 @@ func printTaskSummary(l *logger.Logger, t *taskfile.Task) {
 }
 
 func printTaskName(l *logger.Logger, t *taskfile.Task) {
-	l.Outf(logger.Default, "task: %s", t.Task)
+	l.Outf(logger.Default, "task: %s", t.Name())
 	l.Outf(logger.Default, "")
 }
 
diff --git a/internal/taskfile/task.go b/internal/taskfile/task.go
index d39999cf..40c66b58 100644
--- a/internal/taskfile/task.go
+++ b/internal/taskfile/task.go
@@ -12,6 +12,7 @@ type Task struct {
 	Task          string
 	Cmds          []*Cmd
 	Deps          []*Dep
+	Label         string
 	Desc          string
 	Summary       string
 	Sources       []string
@@ -32,6 +33,13 @@ var (
 	ErrCantUnmarshalTask = errors.New("task: can't unmarshal task value")
 )
 
+func (t *Task) Name() string {
+	if t.Label != "" {
+		return t.Label
+	}
+	return t.Task
+}
+
 func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	var cmd Cmd
 	if err := unmarshal(&cmd); err == nil && cmd.Cmd != "" {
@@ -48,6 +56,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	var task struct {
 		Cmds          []*Cmd
 		Deps          []*Dep
+		Label         string
 		Desc          string
 		Summary       string
 		Sources       []string
@@ -65,6 +74,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := unmarshal(&task); err == nil {
 		t.Cmds = task.Cmds
 		t.Deps = task.Deps
+		t.Label = task.Label
 		t.Desc = task.Desc
 		t.Summary = task.Summary
 		t.Sources = task.Sources
diff --git a/status.go b/status.go
index 5421c1ca..83f383e6 100644
--- a/status.go
+++ b/status.go
@@ -22,7 +22,7 @@ func (e *Executor) Status(ctx context.Context, calls ...taskfile.Call) error {
 			return err
 		}
 		if !isUpToDate {
-			return fmt.Errorf(`task: Task "%s" is not up-to-date`, t.Task)
+			return fmt.Errorf(`task: Task "%s" is not up-to-date`, t.Name())
 		}
 	}
 	return nil
diff --git a/task.go b/task.go
index f5439138..2807dd7f 100644
--- a/task.go
+++ b/task.go
@@ -272,7 +272,7 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
 
 		if upToDate && preCondMet {
 			if !e.Silent {
-				e.Logger.Errf(logger.Magenta, `task: Task "%s" is up to date`, t.Task)
+				e.Logger.Errf(logger.Magenta, `task: Task "%s" is up to date`, t.Name())
 			}
 			return nil
 		}
diff --git a/variables.go b/variables.go
index dfab8764..4470d296 100644
--- a/variables.go
+++ b/variables.go
@@ -32,6 +32,7 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
 
 	new := taskfile.Task{
 		Task:        origTask.Task,
+		Label:       r.Replace(origTask.Label),
 		Desc:        r.Replace(origTask.Desc),
 		Summary:     r.Replace(origTask.Summary),
 		Sources:     r.ReplaceSlice(origTask.Sources),


Test patch:
diff --git a/task_test.go b/task_test.go
index 03185bcb..e8bbe438 100644
--- a/task_test.go
+++ b/task_test.go
@@ -384,6 +384,90 @@ func TestStatusChecksum(t *testing.T) {
 	assert.Equal(t, `task: Task "build" is up to date`+"\n", buff.String())
 }
 
+func TestLabelUpToDate(t *testing.T) {
+	const dir = "testdata/label_uptodate"
+
+	var buff bytes.Buffer
+	e := task.Executor{
+		Dir:    dir,
+		Stdout: &buff,
+		Stderr: &buff,
+	}
+	assert.NoError(t, e.Setup())
+	assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "foo"}))
+	assert.Contains(t, buff.String(), "foobar")
+}
+
+func TestLabelSummary(t *testing.T) {
+	const dir = "testdata/label_summary"
+
+	var buff bytes.Buffer
+	e := task.Executor{
+		Dir:     dir,
+		Summary: true,
+		Stdout:  &buff,
+		Stderr:  &buff,
+	}
+	assert.NoError(t, e.Setup())
+	assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "foo"}))
+	assert.Contains(t, buff.String(), "foobar")
+}
+
+func TestLabelInStatus(t *testing.T) {
+	const dir = "testdata/label_status"
+
+	e := task.Executor{
+		Dir: dir,
+	}
+	assert.NoError(t, e.Setup())
+	err := e.Status(context.Background(), taskfile.Call{Task: "foo"})
+	if assert.Error(t, err) {
+		assert.Contains(t, err.Error(), "foobar")
+	}
+}
+
+func TestLabelWithVariableExpansion(t *testing.T) {
+	const dir = "testdata/label_var"
+
+	var buff bytes.Buffer
+	e := task.Executor{
+		Dir:    dir,
+		Stdout: &buff,
+		Stderr: &buff,
+	}
+	assert.NoError(t, e.Setup())
+	assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "foo"}))
+	assert.Contains(t, buff.String(), "foobaz")
+}
+
+func TestLabelInSummary(t *testing.T) {
+	const dir = "testdata/label_summary"
+
+	var buff bytes.Buffer
+	e := task.Executor{
+		Dir:    dir,
+		Stdout: &buff,
+		Stderr: &buff,
+	}
+	assert.NoError(t, e.Setup())
+	assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "foo"}))
+	assert.Contains(t, buff.String(), "foobar")
+}
+
+func TestLabelInList(t *testing.T) {
+	const dir = "testdata/label_list"
+
+	var buff bytes.Buffer
+	e := task.Executor{
+		Dir:    dir,
+		Stdout: &buff,
+		Stderr: &buff,
+	}
+	assert.NoError(t, e.Setup())
+	e.PrintTasksHelp()
+	assert.Contains(t, buff.String(), "foobar")
+}
+
 func TestStatusVariables(t *testing.T) {
 	const dir = "testdata/status_vars"
 
diff --git a/testdata/label_list/Taskfile.yml b/testdata/label_list/Taskfile.yml
new file mode 100644
index 00000000..5c7db94b
--- /dev/null
+++ b/testdata/label_list/Taskfile.yml
@@ -0,0 +1,6 @@
+version: '3'
+
+tasks:
+  foo:
+    label: "foobar"
+    desc: "task description"
diff --git a/testdata/label_status/Taskfile.yml b/testdata/label_status/Taskfile.yml
new file mode 100644
index 00000000..79747464
--- /dev/null
+++ b/testdata/label_status/Taskfile.yml
@@ -0,0 +1,7 @@
+version: '3'
+
+tasks:
+  foo:
+    label: "foobar"
+    status:
+      - "false"
\ No newline at end of file
diff --git a/testdata/label_summary/Taskfile.yml b/testdata/label_summary/Taskfile.yml
new file mode 100644
index 00000000..c649c09f
--- /dev/null
+++ b/testdata/label_summary/Taskfile.yml
@@ -0,0 +1,8 @@
+version: '3'
+
+tasks:
+  foo:
+    label: "foobar"
+    desc: description
+    status:
+      - echo "I'm ok"
\ No newline at end of file
diff --git a/testdata/label_uptodate/Taskfile.yml b/testdata/label_uptodate/Taskfile.yml
new file mode 100644
index 00000000..2219f4a6
--- /dev/null
+++ b/testdata/label_uptodate/Taskfile.yml
@@ -0,0 +1,7 @@
+version: '3'
+
+tasks:
+  foo:
+    label: "foobar"
+    status:
+      - echo "I'm ok"
\ No newline at end of file
diff --git a/testdata/label_var/Taskfile.yml b/testdata/label_var/Taskfile.yml
new file mode 100644
index 00000000..b47a76ac
--- /dev/null
+++ b/testdata/label_var/Taskfile.yml
@@ -0,0 +1,10 @@
+version: '3'
+
+vars:
+  BAR: baz
+
+tasks:
+  foo:
+    label: "foo{{.BAR}}"
+    status:
+      - echo "I'm ok"
\ No newline at end of file