mirror of
https://github.com/go-task/task.git
synced 2025-10-08 23:02:02 +02:00
feat: add some config to taskrc.yml (#2389)
Co-authored-by: Pete Davison <pd93.uk@outlook.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/taskrc"
|
"github.com/go-task/task/v3/taskrc"
|
||||||
|
"github.com/go-task/task/v3/taskrc/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
const envPrefix = "TASK_X_"
|
const envPrefix = "TASK_X_"
|
||||||
@@ -31,11 +32,15 @@ var (
|
|||||||
var xList []Experiment
|
var xList []Experiment
|
||||||
|
|
||||||
func Parse(dir string) {
|
func Parse(dir string) {
|
||||||
|
config, _ := taskrc.GetConfig(dir)
|
||||||
|
|
||||||
|
ParseWithConfig(dir, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseWithConfig(dir string, config *ast.TaskRC) {
|
||||||
// Read any .env files
|
// Read any .env files
|
||||||
readDotEnv(dir)
|
readDotEnv(dir)
|
||||||
|
|
||||||
config, _ := taskrc.GetConfig(dir)
|
|
||||||
|
|
||||||
// Initialize the experiments
|
// Initialize the experiments
|
||||||
GentleForce = New("GENTLE_FORCE", config, 1)
|
GentleForce = New("GENTLE_FORCE", config, 1)
|
||||||
RemoteTaskfiles = New("REMOTE_TASKFILES", config, 1)
|
RemoteTaskfiles = New("REMOTE_TASKFILES", config, 1)
|
||||||
|
@@ -5,7 +5,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
@@ -13,9 +12,10 @@ import (
|
|||||||
"github.com/go-task/task/v3"
|
"github.com/go-task/task/v3"
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
"github.com/go-task/task/v3/experiments"
|
"github.com/go-task/task/v3/experiments"
|
||||||
"github.com/go-task/task/v3/internal/env"
|
|
||||||
"github.com/go-task/task/v3/internal/sort"
|
"github.com/go-task/task/v3/internal/sort"
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
|
"github.com/go-task/task/v3/taskrc"
|
||||||
|
taskrcast "github.com/go-task/task/v3/taskrc/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
const usage = `Usage: task [flags...] [task...]
|
const usage = `Usage: task [flags...] [task...]
|
||||||
@@ -95,7 +95,9 @@ func init() {
|
|||||||
|
|
||||||
// Parse the experiments
|
// Parse the experiments
|
||||||
dir = cmp.Or(dir, filepath.Dir(entrypoint))
|
dir = cmp.Or(dir, filepath.Dir(entrypoint))
|
||||||
experiments.Parse(dir)
|
|
||||||
|
config, _ := taskrc.GetConfig(dir)
|
||||||
|
experiments.ParseWithConfig(dir, config)
|
||||||
|
|
||||||
// Parse the rest of the flags
|
// Parse the rest of the flags
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
@@ -104,10 +106,7 @@ func init() {
|
|||||||
log.Print(usage)
|
log.Print(usage)
|
||||||
pflag.PrintDefaults()
|
pflag.PrintDefaults()
|
||||||
}
|
}
|
||||||
offline, err := strconv.ParseBool(cmp.Or(env.GetTaskEnv("OFFLINE"), "false"))
|
|
||||||
if err != nil {
|
|
||||||
offline = false
|
|
||||||
}
|
|
||||||
pflag.BoolVar(&Version, "version", false, "Show Task version.")
|
pflag.BoolVar(&Version, "version", false, "Show Task version.")
|
||||||
pflag.BoolVarP(&Help, "help", "h", false, "Shows Task usage.")
|
pflag.BoolVarP(&Help, "help", "h", false, "Shows Task usage.")
|
||||||
pflag.BoolVarP(&Init, "init", "i", false, "Creates a new Taskfile.yml in the current folder.")
|
pflag.BoolVarP(&Init, "init", "i", false, "Creates a new Taskfile.yml in the current folder.")
|
||||||
@@ -118,9 +117,9 @@ func init() {
|
|||||||
pflag.StringVar(&TaskSort, "sort", "", "Changes the order of the tasks when listed. [default|alphanumeric|none].")
|
pflag.StringVar(&TaskSort, "sort", "", "Changes the order of the tasks when listed. [default|alphanumeric|none].")
|
||||||
pflag.BoolVar(&Status, "status", false, "Exits with non-zero exit code if any of the given tasks is not up-to-date.")
|
pflag.BoolVar(&Status, "status", false, "Exits with non-zero exit code if any of the given tasks is not up-to-date.")
|
||||||
pflag.BoolVar(&NoStatus, "no-status", false, "Ignore status when listing tasks as JSON")
|
pflag.BoolVar(&NoStatus, "no-status", false, "Ignore status when listing tasks as JSON")
|
||||||
pflag.BoolVar(&Insecure, "insecure", false, "Forces Task to download Taskfiles over insecure connections.")
|
pflag.BoolVar(&Insecure, "insecure", getConfig(config, config.Remote.Insecure, false), "Forces Task to download Taskfiles over insecure connections.")
|
||||||
pflag.BoolVarP(&Watch, "watch", "w", false, "Enables watch of the given task.")
|
pflag.BoolVarP(&Watch, "watch", "w", false, "Enables watch of the given task.")
|
||||||
pflag.BoolVarP(&Verbose, "verbose", "v", false, "Enables verbose mode.")
|
pflag.BoolVarP(&Verbose, "verbose", "v", getConfig(config, config.Verbose, false), "Enables verbose mode.")
|
||||||
pflag.BoolVarP(&Silent, "silent", "s", false, "Disables echoing.")
|
pflag.BoolVarP(&Silent, "silent", "s", false, "Disables echoing.")
|
||||||
pflag.BoolVarP(&AssumeYes, "yes", "y", false, "Assume \"yes\" as answer to all prompts.")
|
pflag.BoolVarP(&AssumeYes, "yes", "y", false, "Assume \"yes\" as answer to all prompts.")
|
||||||
pflag.BoolVarP(&Parallel, "parallel", "p", false, "Executes tasks provided on command line in parallel.")
|
pflag.BoolVarP(&Parallel, "parallel", "p", false, "Executes tasks provided on command line in parallel.")
|
||||||
@@ -134,7 +133,7 @@ func init() {
|
|||||||
pflag.StringVar(&Output.Group.End, "output-group-end", "", "Message template to print after a task's grouped output.")
|
pflag.StringVar(&Output.Group.End, "output-group-end", "", "Message template to print after a task's grouped output.")
|
||||||
pflag.BoolVar(&Output.Group.ErrorOnly, "output-group-error-only", false, "Swallow output from successful tasks.")
|
pflag.BoolVar(&Output.Group.ErrorOnly, "output-group-error-only", false, "Swallow output from successful tasks.")
|
||||||
pflag.BoolVarP(&Color, "color", "c", true, "Colored output. Enabled by default. Set flag to false or use NO_COLOR=1 to disable.")
|
pflag.BoolVarP(&Color, "color", "c", true, "Colored output. Enabled by default. Set flag to false or use NO_COLOR=1 to disable.")
|
||||||
pflag.IntVarP(&Concurrency, "concurrency", "C", 0, "Limit number of tasks to run concurrently.")
|
pflag.IntVarP(&Concurrency, "concurrency", "C", getConfig(config, config.Concurrency, 0), "Limit number of tasks to run concurrently.")
|
||||||
pflag.DurationVarP(&Interval, "interval", "I", 0, "Interval to watch for changes.")
|
pflag.DurationVarP(&Interval, "interval", "I", 0, "Interval to watch for changes.")
|
||||||
pflag.BoolVarP(&Global, "global", "g", false, "Runs global Taskfile, from $HOME/{T,t}askfile.{yml,yaml}.")
|
pflag.BoolVarP(&Global, "global", "g", false, "Runs global Taskfile, from $HOME/{T,t}askfile.{yml,yaml}.")
|
||||||
pflag.BoolVar(&Experiments, "experiments", false, "Lists all the available experiments and whether or not they are enabled.")
|
pflag.BoolVar(&Experiments, "experiments", false, "Lists all the available experiments and whether or not they are enabled.")
|
||||||
@@ -150,12 +149,11 @@ func init() {
|
|||||||
// Remote Taskfiles experiment will adds the "download" and "offline" flags
|
// Remote Taskfiles experiment will adds the "download" and "offline" flags
|
||||||
if experiments.RemoteTaskfiles.Enabled() {
|
if experiments.RemoteTaskfiles.Enabled() {
|
||||||
pflag.BoolVar(&Download, "download", false, "Downloads a cached version of a remote Taskfile.")
|
pflag.BoolVar(&Download, "download", false, "Downloads a cached version of a remote Taskfile.")
|
||||||
pflag.BoolVar(&Offline, "offline", offline, "Forces Task to only use local or cached Taskfiles.")
|
pflag.BoolVar(&Offline, "offline", getConfig(config, config.Remote.Offline, false), "Forces Task to only use local or cached Taskfiles.")
|
||||||
pflag.DurationVar(&Timeout, "timeout", time.Second*10, "Timeout for downloading remote Taskfiles.")
|
pflag.DurationVar(&Timeout, "timeout", getConfig(config, config.Remote.Timeout, time.Second*10), "Timeout for downloading remote Taskfiles.")
|
||||||
pflag.BoolVar(&ClearCache, "clear-cache", false, "Clear the remote cache.")
|
pflag.BoolVar(&ClearCache, "clear-cache", false, "Clear the remote cache.")
|
||||||
pflag.DurationVar(&CacheExpiryDuration, "expiry", 0, "Expiry duration for cached remote Taskfiles.")
|
pflag.DurationVar(&CacheExpiryDuration, "expiry", getConfig(config, config.Remote.Timeout, 0), "Expiry duration for cached remote Taskfiles.")
|
||||||
}
|
}
|
||||||
|
|
||||||
pflag.Parse()
|
pflag.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,3 +249,15 @@ func (o *flagsOption) ApplyToExecutor(e *task.Executor) {
|
|||||||
task.WithVersionCheck(true),
|
task.WithVersionCheck(true),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getConfig extracts a config value directly from a pointer field with a fallback default
|
||||||
|
func getConfig[T any](config *taskrcast.TaskRC, field *T, fallback T) T {
|
||||||
|
if config == nil {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
if field != nil {
|
||||||
|
return *field
|
||||||
|
}
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
@@ -1,27 +1,48 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"maps"
|
"maps"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
"github.com/Masterminds/semver/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TaskRC struct {
|
type TaskRC struct {
|
||||||
Version *semver.Version `yaml:"version"`
|
Version *semver.Version `yaml:"version"`
|
||||||
|
Verbose *bool `yaml:"verbose"`
|
||||||
|
Concurrency *int `yaml:"concurrency"`
|
||||||
|
Remote Remote `yaml:"remote"`
|
||||||
Experiments map[string]int `yaml:"experiments"`
|
Experiments map[string]int `yaml:"experiments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Remote struct {
|
||||||
|
Insecure *bool `yaml:"insecure"`
|
||||||
|
Offline *bool `yaml:"offline"`
|
||||||
|
Timeout *time.Duration `yaml:"timeout"`
|
||||||
|
CacheExpiry *time.Duration `yaml:"cache-expiry"`
|
||||||
|
}
|
||||||
|
|
||||||
// Merge combines the current TaskRC with another TaskRC, prioritizing non-nil fields from the other TaskRC.
|
// Merge combines the current TaskRC with another TaskRC, prioritizing non-nil fields from the other TaskRC.
|
||||||
func (t *TaskRC) Merge(other *TaskRC) {
|
func (t *TaskRC) Merge(other *TaskRC) {
|
||||||
if other == nil {
|
if other == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if t.Version == nil && other.Version != nil {
|
|
||||||
t.Version = other.Version
|
t.Version = cmp.Or(other.Version, t.Version)
|
||||||
}
|
|
||||||
if t.Experiments == nil && other.Experiments != nil {
|
if t.Experiments == nil && other.Experiments != nil {
|
||||||
t.Experiments = other.Experiments
|
t.Experiments = other.Experiments
|
||||||
} else if t.Experiments != nil && other.Experiments != nil {
|
} else if t.Experiments != nil && other.Experiments != nil {
|
||||||
maps.Copy(t.Experiments, other.Experiments)
|
maps.Copy(t.Experiments, other.Experiments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge Remote fields
|
||||||
|
t.Remote.Insecure = cmp.Or(other.Remote.Insecure, t.Remote.Insecure)
|
||||||
|
t.Remote.Offline = cmp.Or(other.Remote.Offline, t.Remote.Offline)
|
||||||
|
t.Remote.Timeout = cmp.Or(other.Remote.Timeout, t.Remote.Timeout)
|
||||||
|
t.Remote.CacheExpiry = cmp.Or(other.Remote.CacheExpiry, t.Remote.CacheExpiry)
|
||||||
|
|
||||||
|
t.Verbose = cmp.Or(other.Verbose, t.Verbose)
|
||||||
|
t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency)
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,8 @@ import { resolve } from 'path';
|
|||||||
import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs';
|
import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs';
|
||||||
import {
|
import {
|
||||||
groupIconMdPlugin,
|
groupIconMdPlugin,
|
||||||
groupIconVitePlugin
|
groupIconVitePlugin,
|
||||||
|
localIconLoader
|
||||||
} from 'vitepress-plugin-group-icons';
|
} from 'vitepress-plugin-group-icons';
|
||||||
import { team } from './team.ts';
|
import { team } from './team.ts';
|
||||||
import { taskDescription, taskName } from './meta.ts';
|
import { taskDescription, taskName } from './meta.ts';
|
||||||
@@ -99,7 +100,20 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [groupIconVitePlugin()],
|
plugins: [
|
||||||
|
groupIconVitePlugin({
|
||||||
|
customIcon: {
|
||||||
|
'.taskrc.yml': localIconLoader(
|
||||||
|
import.meta.url,
|
||||||
|
'./theme/icons/task.svg'
|
||||||
|
),
|
||||||
|
'Taskfile.yml': localIconLoader(
|
||||||
|
import.meta.url,
|
||||||
|
'./theme/icons/task.svg'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: [
|
alias: [
|
||||||
{
|
{
|
||||||
|
1
website/.vitepress/theme/icons/task.svg
Normal file
1
website/.vitepress/theme/icons/task.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" viewBox="0 0 375 375"><path fill="#29beb0" d="M 187.570312 190.933594 L 187.570312 375 L 30.070312 279.535156 L 30.070312 95.464844 Z"/><path fill="#69d2c8" d="M 187.570312 190.933594 L 187.570312 375 L 345.070312 279.535156 L 345.070312 95.464844 Z"/><path fill="#94dfd8" d="M 187.570312 190.933594 L 30.070312 95.464844 L 187.570312 0 L 345.070312 95.464844 Z"/></svg>
|
After Width: | Height: | Size: 435 B |
@@ -290,3 +290,64 @@ You can force Task to ignore the cache and download the latest version by using
|
|||||||
the `--download` flag.
|
the `--download` flag.
|
||||||
|
|
||||||
You can use the `--clear-cache` flag to clear all cached remote files.
|
You can use the `--clear-cache` flag to clear all cached remote files.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
This experiment adds a new `remote` section to the [configuration file](../reference/config.md).
|
||||||
|
|
||||||
|
- **Type**: `object`
|
||||||
|
- **Description**: Remote configuration settings for handling remote Taskfiles
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
remote:
|
||||||
|
insecure: false
|
||||||
|
offline: false
|
||||||
|
timeout: "30s"
|
||||||
|
cache-expiry: "24h"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `insecure`
|
||||||
|
|
||||||
|
- **Type**: `boolean`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Allow insecure connections when fetching remote Taskfiles
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
remote:
|
||||||
|
insecure: true
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `offline`
|
||||||
|
|
||||||
|
- **Type**: `boolean`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Work in offline mode, preventing remote Taskfile fetching
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
remote:
|
||||||
|
offline: true
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `timeout`
|
||||||
|
|
||||||
|
- **Type**: `string`
|
||||||
|
- **Default**: Not specified
|
||||||
|
- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$`
|
||||||
|
- **Description**: Timeout duration for remote operations (e.g., '30s', '5m')
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
remote:
|
||||||
|
timeout: "1m"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `cache-expiry`
|
||||||
|
|
||||||
|
- **Type**: `string`
|
||||||
|
- **Default**: Not specified
|
||||||
|
- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$`
|
||||||
|
- **Description**: Cache expiry duration for remote Taskfiles (e.g., '1h', '24h')
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
remote:
|
||||||
|
cache-expiry: "6h"
|
||||||
|
```
|
||||||
|
|
||||||
|
@@ -73,3 +73,44 @@ option_3: foo # Taken from $XDG_CONFIG_HOME/task/.taskrc.yml
|
|||||||
The experiments section allows you to enable Task's experimental features. These
|
The experiments section allows you to enable Task's experimental features. These
|
||||||
options are not enumerated here. Instead, please refer to our
|
options are not enumerated here. Instead, please refer to our
|
||||||
[experiments documentation](../experiments/index.md) for more information.
|
[experiments documentation](../experiments/index.md) for more information.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
experiments:
|
||||||
|
feature_name: 1
|
||||||
|
another_feature: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### `verbose`
|
||||||
|
|
||||||
|
- **Type**: `boolean`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Enable verbose output for all tasks
|
||||||
|
- **CLI equivalent**: [`-v, --verbose`](./cli.md#-v---verbose)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
verbose: true
|
||||||
|
```
|
||||||
|
|
||||||
|
### `concurrency`
|
||||||
|
|
||||||
|
- **Type**: `integer`
|
||||||
|
- **Minimum**: `1`
|
||||||
|
- **Description**: Number of concurrent tasks to run
|
||||||
|
- **CLI equivalent**: [`-C, --concurrency`](./cli.md#-c---concurrency-number)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
concurrency: 4
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example Configuration
|
||||||
|
|
||||||
|
Here's a complete example of a `.taskrc.yml` file with all available options:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Global settings
|
||||||
|
verbose: true
|
||||||
|
concurrency: 2
|
||||||
|
|
||||||
|
# Enable experimental features
|
||||||
|
experiments:
|
||||||
|
REMOTE_TASKFILES: 1
|
||||||
|
@@ -20,6 +20,40 @@
|
|||||||
"enum": [0, 1]
|
"enum": [0, 1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"remote": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Remote configuration settings",
|
||||||
|
"properties": {
|
||||||
|
"insecure": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Forces Task to download Taskfiles over insecure connections."
|
||||||
|
},
|
||||||
|
"offline": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Forces Task to only use local or cached Taskfiles."
|
||||||
|
},
|
||||||
|
"timeout": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Timeout for downloading remote Taskfiles (e.g., '30s', '5m')",
|
||||||
|
"pattern": "^[0-9]+(ns|us|µs|ms|s|m|h)$"
|
||||||
|
},
|
||||||
|
"cache-expiry": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Expiry duration for cached remote Taskfiles (e.g., '1h', '24h')",
|
||||||
|
"pattern": "^[0-9]+(ns|us|µs|ms|s|m|h)$"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"verbose": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Enable verbose output"
|
||||||
|
},
|
||||||
|
"concurrency": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Number of concurrent tasks to run",
|
||||||
|
"minimum": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
Reference in New Issue
Block a user