2019-02-24 16:25:27 +01:00
|
|
|
package summary
|
|
|
|
|
|
|
|
|
|
import (
|
2025-11-16 18:02:41 +01:00
|
|
|
"fmt"
|
|
|
|
|
"os"
|
2019-03-04 12:03:28 +01:00
|
|
|
"strings"
|
|
|
|
|
|
2020-08-16 15:48:19 -03:00
|
|
|
"github.com/go-task/task/v3/internal/logger"
|
2023-12-29 20:32:03 +00:00
|
|
|
"github.com/go-task/task/v3/taskfile/ast"
|
2019-02-24 16:25:27 +01:00
|
|
|
)
|
|
|
|
|
|
2025-02-23 18:30:42 +00:00
|
|
|
func PrintTasks(l *logger.Logger, t *ast.Taskfile, c []string) {
|
2019-03-04 12:25:42 +01:00
|
|
|
for i, call := range c {
|
2020-01-20 13:38:18 +00:00
|
|
|
PrintSpaceBetweenSummaries(l, i)
|
2025-02-23 18:30:42 +00:00
|
|
|
if task, ok := t.Tasks.Get(call); ok {
|
2024-12-30 17:54:36 +00:00
|
|
|
PrintTask(l, task)
|
|
|
|
|
}
|
2019-03-04 12:25:42 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-20 13:38:18 +00:00
|
|
|
func PrintSpaceBetweenSummaries(l *logger.Logger, i int) {
|
2019-03-04 12:27:10 +01:00
|
|
|
spaceRequired := i > 0
|
|
|
|
|
if !spaceRequired {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, "\n")
|
|
|
|
|
l.Outf(logger.Default, "\n")
|
2019-03-04 12:27:10 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func PrintTask(l *logger.Logger, t *ast.Task) {
|
2019-02-24 18:20:59 +01:00
|
|
|
printTaskName(l, t)
|
2019-03-04 13:04:04 +01:00
|
|
|
printTaskDescribingText(t, l)
|
2025-11-16 18:02:41 +01:00
|
|
|
printTaskVars(l, t)
|
|
|
|
|
printTaskEnv(l, t)
|
|
|
|
|
printTaskRequires(l, t)
|
2019-03-04 13:04:04 +01:00
|
|
|
printTaskDependencies(l, t)
|
2022-10-01 22:39:44 +00:00
|
|
|
printTaskAliases(l, t)
|
2019-03-04 13:04:04 +01:00
|
|
|
printTaskCommands(l, t)
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func printTaskDescribingText(t *ast.Task, l *logger.Logger) {
|
2019-02-24 18:20:59 +01:00
|
|
|
if hasSummary(t) {
|
|
|
|
|
printTaskSummary(l, t)
|
2019-02-24 18:26:16 +01:00
|
|
|
} else if hasDescription(t) {
|
2019-02-24 18:20:59 +01:00
|
|
|
printTaskDescription(l, t)
|
2019-02-24 18:26:16 +01:00
|
|
|
} else {
|
2019-02-24 19:14:15 +01:00
|
|
|
printNoDescriptionOrSummary(l)
|
2019-02-24 18:20:59 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func hasSummary(t *ast.Task) bool {
|
2019-02-24 19:14:15 +01:00
|
|
|
return t.Summary != ""
|
2019-02-24 16:26:46 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func printTaskSummary(l *logger.Logger, t *ast.Task) {
|
2019-02-24 19:14:15 +01:00
|
|
|
lines := strings.Split(t.Summary, "\n")
|
2019-02-24 18:26:16 +01:00
|
|
|
for i, line := range lines {
|
|
|
|
|
notLastLine := i+1 < len(lines)
|
|
|
|
|
if notLastLine || line != "" {
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, "%s\n", line)
|
2019-02-24 18:26:16 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func printTaskName(l *logger.Logger, t *ast.Task) {
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, "task: ")
|
|
|
|
|
l.Outf(logger.Green, "%s\n", t.Name())
|
|
|
|
|
l.Outf(logger.Default, "\n")
|
2019-02-24 16:25:27 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func printTaskAliases(l *logger.Logger, t *ast.Task) {
|
2022-10-01 22:39:44 +00:00
|
|
|
if len(t.Aliases) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, "\n")
|
|
|
|
|
l.Outf(logger.Default, "aliases:\n")
|
2022-10-01 22:39:44 +00:00
|
|
|
for _, alias := range t.Aliases {
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, " - ")
|
|
|
|
|
l.Outf(logger.Cyan, "%s\n", alias)
|
2022-10-01 22:39:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func hasDescription(t *ast.Task) bool {
|
2019-02-24 19:14:15 +01:00
|
|
|
return t.Desc != ""
|
2019-02-24 18:26:16 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func printTaskDescription(l *logger.Logger, t *ast.Task) {
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, "%s\n", t.Desc)
|
2019-02-24 18:26:16 +01:00
|
|
|
}
|
|
|
|
|
|
2019-02-24 19:14:15 +01:00
|
|
|
func printNoDescriptionOrSummary(l *logger.Logger) {
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, "(task does not have description or summary)\n")
|
2019-02-24 16:25:27 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func printTaskDependencies(l *logger.Logger, t *ast.Task) {
|
2019-03-04 12:46:02 +01:00
|
|
|
if len(t.Deps) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
2019-02-24 16:25:27 +01:00
|
|
|
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, "\n")
|
|
|
|
|
l.Outf(logger.Default, "dependencies:\n")
|
2019-03-04 12:46:02 +01:00
|
|
|
|
|
|
|
|
for _, d := range t.Deps {
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, " - %s\n", d.Task)
|
2019-02-24 16:25:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 20:32:03 +00:00
|
|
|
func printTaskCommands(l *logger.Logger, t *ast.Task) {
|
2019-03-04 12:28:26 +01:00
|
|
|
if len(t.Cmds) == 0 {
|
2019-03-04 12:28:11 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, "\n")
|
|
|
|
|
l.Outf(logger.Default, "commands:\n")
|
2019-03-04 12:28:11 +01:00
|
|
|
for _, c := range t.Cmds {
|
|
|
|
|
isCommand := c.Cmd != ""
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Default, " - ")
|
2019-03-04 12:28:11 +01:00
|
|
|
if isCommand {
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Yellow, "%s\n", c.Cmd)
|
2019-03-04 12:28:11 +01:00
|
|
|
} else {
|
2023-04-27 01:20:06 +01:00
|
|
|
l.Outf(logger.Green, "Task: %s\n", c.Task)
|
2019-02-24 16:25:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-16 18:02:41 +01:00
|
|
|
|
|
|
|
|
// printTaskVars prints the variables defined in a task in YAML format.
|
|
|
|
|
// It displays the vars section with proper indentation and formatting.
|
|
|
|
|
// Filters out OS environment variables, auto-generated Task variables, and Taskfile env vars.
|
|
|
|
|
// Returns early if the task has no variables defined.
|
|
|
|
|
func printTaskVars(l *logger.Logger, t *ast.Task) {
|
|
|
|
|
if t.Vars == nil || t.Vars.Len() == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a set of OS environment variable names to filter them out
|
|
|
|
|
osEnvVars := getEnvVarNames()
|
|
|
|
|
|
|
|
|
|
// Create a set of Taskfile env variable names to avoid duplication
|
|
|
|
|
taskfileEnvVars := make(map[string]bool)
|
|
|
|
|
if t.Env != nil {
|
|
|
|
|
for key := range t.Env.All() {
|
|
|
|
|
taskfileEnvVars[key] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if there are any non-environment variables to display
|
|
|
|
|
hasNonEnvVars := false
|
|
|
|
|
for key := range t.Vars.All() {
|
|
|
|
|
if !isEnvVar(key, osEnvVars) && !taskfileEnvVars[key] {
|
|
|
|
|
hasNonEnvVars = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !hasNonEnvVars {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l.Outf(logger.Default, "\n")
|
|
|
|
|
l.Outf(logger.Default, "vars:\n")
|
|
|
|
|
|
|
|
|
|
for key, value := range t.Vars.All() {
|
|
|
|
|
// Only display variables that are not from OS environment or Taskfile env
|
|
|
|
|
if !isEnvVar(key, osEnvVars) && !taskfileEnvVars[key] {
|
|
|
|
|
formattedValue := formatVarValue(value)
|
|
|
|
|
l.Outf(logger.Yellow, " %s: %s\n", key, formattedValue)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// printTaskEnv prints the environment variables defined in a task in YAML format.
|
|
|
|
|
// It displays the env section with proper indentation and formatting.
|
|
|
|
|
// Filters out OS environment variables and auto-generated Task variables.
|
|
|
|
|
// Returns early if the task has no environment variables defined.
|
|
|
|
|
func printTaskEnv(l *logger.Logger, t *ast.Task) {
|
|
|
|
|
if t.Env == nil || t.Env.Len() == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a set of OS environment variable names to filter them out
|
|
|
|
|
envVars := getEnvVarNames()
|
|
|
|
|
|
|
|
|
|
// Check if there are any non-environment variables to display
|
|
|
|
|
hasNonEnvVars := false
|
|
|
|
|
for key := range t.Env.All() {
|
|
|
|
|
if !isEnvVar(key, envVars) {
|
|
|
|
|
hasNonEnvVars = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !hasNonEnvVars {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l.Outf(logger.Default, "\n")
|
|
|
|
|
l.Outf(logger.Default, "env:\n")
|
|
|
|
|
|
|
|
|
|
for key, value := range t.Env.All() {
|
|
|
|
|
// Only display variables that are not from OS environment
|
|
|
|
|
if !isEnvVar(key, envVars) {
|
|
|
|
|
formattedValue := formatVarValue(value)
|
|
|
|
|
l.Outf(logger.Yellow, " %s: %s\n", key, formattedValue)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// formatVarValue formats a variable value based on its type.
|
|
|
|
|
// Handles static values, shell commands (sh:), references (ref:), and maps.
|
|
|
|
|
func formatVarValue(v ast.Var) string {
|
|
|
|
|
// Shell command - check this first before Value
|
|
|
|
|
// because dynamic vars may have both Sh and an empty Value
|
|
|
|
|
if v.Sh != nil {
|
|
|
|
|
return fmt.Sprintf("sh: %s", *v.Sh)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reference
|
|
|
|
|
if v.Ref != "" {
|
|
|
|
|
return fmt.Sprintf("ref: %s", v.Ref)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Static value
|
|
|
|
|
if v.Value != nil {
|
|
|
|
|
// Check if it's a map or complex type
|
|
|
|
|
if m, ok := v.Value.(map[string]any); ok {
|
|
|
|
|
return formatMap(m, 4)
|
|
|
|
|
}
|
|
|
|
|
// Simple string value
|
|
|
|
|
return fmt.Sprintf(`"%v"`, v.Value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return `""`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// formatMap formats a map value with proper indentation for YAML.
|
|
|
|
|
func formatMap(m map[string]any, indent int) string {
|
|
|
|
|
if len(m) == 0 {
|
|
|
|
|
return "{}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var result strings.Builder
|
|
|
|
|
result.WriteString("\n")
|
|
|
|
|
spaces := strings.Repeat(" ", indent)
|
|
|
|
|
|
|
|
|
|
for k, v := range m {
|
|
|
|
|
result.WriteString(fmt.Sprintf("%s%s: %v\n", spaces, k, v))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// printTaskRequires prints the required variables for a task in YAML format.
|
|
|
|
|
// It displays the requires section with proper indentation and formatting.
|
|
|
|
|
// Returns early if the task has no required variables.
|
|
|
|
|
func printTaskRequires(l *logger.Logger, t *ast.Task) {
|
|
|
|
|
if t.Requires == nil || len(t.Requires.Vars) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l.Outf(logger.Default, "\n")
|
|
|
|
|
l.Outf(logger.Default, "requires:\n")
|
|
|
|
|
l.Outf(logger.Default, " vars:\n")
|
|
|
|
|
|
|
|
|
|
for _, v := range t.Requires.Vars {
|
|
|
|
|
// If the variable has enum constraints, format accordingly
|
|
|
|
|
if len(v.Enum) > 0 {
|
|
|
|
|
l.Outf(logger.Yellow, " - %s:\n", v.Name)
|
|
|
|
|
l.Outf(logger.Yellow, " enum:\n")
|
|
|
|
|
for _, enumValue := range v.Enum {
|
|
|
|
|
l.Outf(logger.Yellow, " - %s\n", enumValue)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Simple required variable
|
|
|
|
|
l.Outf(logger.Yellow, " - %s\n", v.Name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getEnvVarNames returns a set of all OS environment variable names.
|
|
|
|
|
func getEnvVarNames() map[string]bool {
|
|
|
|
|
envMap := make(map[string]bool)
|
|
|
|
|
for _, e := range os.Environ() {
|
|
|
|
|
parts := strings.SplitN(e, "=", 2)
|
|
|
|
|
if len(parts) > 0 {
|
|
|
|
|
envMap[parts[0]] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return envMap
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isEnvVar checks if a variable is from OS environment or auto-generated by Task.
|
|
|
|
|
func isEnvVar(key string, envVars map[string]bool) bool {
|
|
|
|
|
// Filter out auto-generated Task variables
|
|
|
|
|
if strings.HasPrefix(key, "TASK_") ||
|
|
|
|
|
strings.HasPrefix(key, "CLI_") ||
|
|
|
|
|
strings.HasPrefix(key, "ROOT_") ||
|
|
|
|
|
key == "TASK" ||
|
|
|
|
|
key == "TASKFILE" ||
|
|
|
|
|
key == "TASKFILE_DIR" ||
|
|
|
|
|
key == "USER_WORKING_DIR" ||
|
|
|
|
|
key == "ALIAS" ||
|
|
|
|
|
key == "MATCH" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
// Filter out OS environment variables
|
|
|
|
|
return envVars[key]
|
|
|
|
|
}
|