mirror of
https://github.com/go-task/task.git
synced 2026-06-24 13:15:51 +00:00
Compare commits
79 Commits
v3.43.0
...
bump-versi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c30a8066d | ||
|
|
26ef693417 | ||
|
|
952f32d388 | ||
|
|
e72c35f79f | ||
|
|
72991d4f04 | ||
|
|
6f965e3043 | ||
|
|
1c6d686356 | ||
|
|
dac5aa1954 | ||
|
|
303bd6ccb2 | ||
|
|
f736cfaaf1 | ||
|
|
53f97889bc | ||
|
|
fe2da74ea3 | ||
|
|
64fb66895b | ||
|
|
d2bd834c81 | ||
|
|
8a43ca5d8f | ||
|
|
a10a9faabf | ||
|
|
3d3ed0e403 | ||
|
|
47dc87a2c9 | ||
|
|
3b0a746f85 | ||
|
|
281edfe5b3 | ||
|
|
7289ffce0b | ||
|
|
61e1af50ff | ||
|
|
715a143735 | ||
|
|
a0b1605634 | ||
|
|
69fc13bd13 | ||
|
|
b42a52ba77 | ||
|
|
cb812476b3 | ||
|
|
b09c6870fe | ||
|
|
86e4a3aac7 | ||
|
|
7782bc92ae | ||
|
|
9cc2d65091 | ||
|
|
b932e539d9 | ||
|
|
be45eb04d9 | ||
|
|
6b878980dc | ||
|
|
cd910abd45 | ||
|
|
6e524bb2fa | ||
|
|
b4c8f5a0fe | ||
|
|
09f85844ba | ||
|
|
d54d2ccabc | ||
|
|
cf81ab3112 | ||
|
|
aaa7b7772d | ||
|
|
71eb8cdeea | ||
|
|
68ce8b1d84 | ||
|
|
5323990c72 | ||
|
|
ec4e68d601 | ||
|
|
bb5b045293 | ||
|
|
89f29cb75b | ||
|
|
da4ce5b0a5 | ||
|
|
fb68a5f79a | ||
|
|
f40f389cb4 | ||
|
|
a459eeaabb | ||
|
|
84f02a822f | ||
|
|
55d1aa260d | ||
|
|
e7084cdf26 | ||
|
|
ca55e9b621 | ||
|
|
6528b36caa | ||
|
|
f8736c5f77 | ||
|
|
6896accf86 | ||
|
|
c12ed49acb | ||
|
|
d1bfd3e9f7 | ||
|
|
fc17343fcc | ||
|
|
d3e9be1520 | ||
|
|
d850d03c96 | ||
|
|
0058f18676 | ||
|
|
b3c4007756 | ||
|
|
9e8fd54be9 | ||
|
|
a33544101a | ||
|
|
1c35358fcc | ||
|
|
13daa6dc35 | ||
|
|
20c1ffe098 | ||
|
|
bd8ccb8d03 | ||
|
|
8162b05f59 | ||
|
|
68d5095761 | ||
|
|
6cb0a5a2f2 | ||
|
|
08056924e0 | ||
|
|
39706105e1 | ||
|
|
bf4e7960cb | ||
|
|
3d36616e9e | ||
|
|
3976e8372a |
20
.github/workflows/lint.yml
vendored
20
.github/workflows/lint.yml
vendored
@@ -23,9 +23,9 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v7
|
uses: golangci/golangci-lint-action@v8
|
||||||
with:
|
with:
|
||||||
version: v2.0.2
|
version: v2.1.0
|
||||||
|
|
||||||
lint-jsonschema:
|
lint-jsonschema:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -56,3 +56,19 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
core.setFailed('website/versioned_docs has changed. Instead you need to update the docs in the website/docs folder.')
|
core.setFailed('website/versioned_docs has changed. Instead you need to update the docs in the website/docs folder.')
|
||||||
|
check_schema:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Get changed files in the docs folder
|
||||||
|
id: changed-files-specific
|
||||||
|
uses: tj-actions/changed-files@v46
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
website/static/schema.json
|
||||||
|
website/static/schema-taskrc.json
|
||||||
|
- uses: actions/github-script@v7
|
||||||
|
if: steps.changed-files-specific.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.setFailed('schema.json or schema-taskrc.json has changed. Instead you need to update next-schema.json or next-schema-taskrc.json.')
|
||||||
|
|||||||
29
.github/workflows/release-nightly.yml
vendored
Normal file
29
.github/workflows/release-nightly.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
name: Realease nightly
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: 0 0 * * *
|
||||||
|
jobs:
|
||||||
|
goreleaser:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.24.x
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v6
|
||||||
|
with:
|
||||||
|
distribution: goreleaser-pro
|
||||||
|
version: latest
|
||||||
|
args: release --clean --nightly
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{secrets.GH_PAT}}
|
||||||
|
GORELEASER_KEY: ${{secrets.GORELEASER_KEY}}
|
||||||
@@ -5,8 +5,10 @@ formatters:
|
|||||||
- gofmt
|
- gofmt
|
||||||
- gofumpt
|
- gofumpt
|
||||||
- goimports
|
- goimports
|
||||||
|
- gci
|
||||||
settings:
|
settings:
|
||||||
gofmt:
|
gofmt:
|
||||||
|
simplify: true
|
||||||
rewrite-rules:
|
rewrite-rules:
|
||||||
- pattern: interface{}
|
- pattern: interface{}
|
||||||
replacement: any
|
replacement: any
|
||||||
@@ -15,6 +17,12 @@ formatters:
|
|||||||
goimports:
|
goimports:
|
||||||
local-prefixes:
|
local-prefixes:
|
||||||
- github.com/go-task
|
- github.com/go-task
|
||||||
|
gci:
|
||||||
|
sections:
|
||||||
|
- standard
|
||||||
|
- default
|
||||||
|
- prefix(github.com/go-task)
|
||||||
|
- localmodule
|
||||||
exclusions:
|
exclusions:
|
||||||
generated: lax
|
generated: lax
|
||||||
paths:
|
paths:
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ gomod:
|
|||||||
proxy: true
|
proxy: true
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- name_template: "{{.Binary}}_{{.Os}}_{{.Arch}}"
|
- name_template: '{{.Binary}}_{{.Os}}_{{.Arch}}'
|
||||||
files:
|
files:
|
||||||
- README.md
|
- README.md
|
||||||
- LICENSE
|
- LICENSE
|
||||||
@@ -48,24 +48,35 @@ archives:
|
|||||||
release:
|
release:
|
||||||
draft: true
|
draft: true
|
||||||
|
|
||||||
|
|
||||||
|
git:
|
||||||
|
ignore_tags:
|
||||||
|
- "{{if not .IsNightly}}nightly{{end}}"
|
||||||
|
|
||||||
|
nightly:
|
||||||
|
publish_release: true
|
||||||
|
keep_single_release: true
|
||||||
|
version_template: "{{incminor .Version}}-nightly"
|
||||||
|
|
||||||
snapshot:
|
snapshot:
|
||||||
version_template: "{{.Version}}"
|
version_template: '{{.Version}}'
|
||||||
|
|
||||||
checksum:
|
checksum:
|
||||||
name_template: "task_checksums.txt"
|
name_template: 'task_checksums.txt'
|
||||||
|
|
||||||
nfpms:
|
nfpms:
|
||||||
- vendor: Task
|
- vendor: Task
|
||||||
homepage: https://taskfile.dev
|
homepage: https://taskfile.dev
|
||||||
maintainer: The Task authors <task@taskfile.dev>
|
maintainer: The Task authors <task@taskfile.dev>
|
||||||
description: Simple task runner written in Go
|
description: Simple task runner written in Go
|
||||||
|
section: golang
|
||||||
license: MIT
|
license: MIT
|
||||||
conflicts:
|
conflicts:
|
||||||
- taskwarrior
|
- taskwarrior
|
||||||
formats:
|
formats:
|
||||||
- deb
|
- deb
|
||||||
- rpm
|
- rpm
|
||||||
file_name_template: "{{.ProjectName}}_{{.Os}}_{{.Arch}}"
|
file_name_template: '{{.ProjectName}}_{{.Os}}_{{.Arch}}'
|
||||||
contents:
|
contents:
|
||||||
- src: completion/bash/task.bash
|
- src: completion/bash/task.bash
|
||||||
dst: /etc/bash_completion.d/task
|
dst: /etc/bash_completion.d/task
|
||||||
@@ -83,8 +94,7 @@ brews:
|
|||||||
repository:
|
repository:
|
||||||
owner: go-task
|
owner: go-task
|
||||||
name: homebrew-tap
|
name: homebrew-tap
|
||||||
test:
|
test: system "#{bin}/task", "--help"
|
||||||
system "#{bin}/task", "--help"
|
|
||||||
install: |-
|
install: |-
|
||||||
bin.install "task"
|
bin.install "task"
|
||||||
bash_completion.install "completion/bash/task.bash" => "task"
|
bash_completion.install "completion/bash/task.bash" => "task"
|
||||||
@@ -107,7 +117,7 @@ winget:
|
|||||||
commit_author:
|
commit_author:
|
||||||
name: task-bot
|
name: task-bot
|
||||||
email: 106601941+task-bot@users.noreply.github.com
|
email: 106601941+task-bot@users.noreply.github.com
|
||||||
commit_msg_template: "chore: bump {{.PackageIdentifier}} to {{.Tag}}"
|
commit_msg_template: 'chore: release {{.PackageIdentifier}} {{.Tag}}'
|
||||||
release_notes_url: https://github.com/go-task/task/releases/tag/{{.Tag}}
|
release_notes_url: https://github.com/go-task/task/releases/tag/{{.Tag}}
|
||||||
tags:
|
tags:
|
||||||
- build
|
- build
|
||||||
@@ -121,13 +131,15 @@ winget:
|
|||||||
- task-runner
|
- task-runner
|
||||||
- taskfile
|
- taskfile
|
||||||
- tool
|
- tool
|
||||||
skip_upload: true
|
|
||||||
repository:
|
repository:
|
||||||
owner: microsoft
|
owner: go-task
|
||||||
name: winget-pkgs
|
name: winget-pkgs
|
||||||
|
branch: 'chore/task-{{.Version}}'
|
||||||
pull_request:
|
pull_request:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
draft: false
|
||||||
|
check_boxes: true
|
||||||
base:
|
base:
|
||||||
owner: go-task
|
owner: microsoft
|
||||||
name: winget-pkgs
|
name: winget-pkgs
|
||||||
branch: "bump-task-to-{{.Tag}}"
|
branch: master
|
||||||
|
|||||||
53
CHANGELOG.md
53
CHANGELOG.md
@@ -1,6 +1,57 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v3.43.0 - 2025-04-21
|
## v3.44.1 - 2025-07-23
|
||||||
|
|
||||||
|
- Internal tasks will no longer be shown as suggestions since they cannot be
|
||||||
|
called (#2309, #2323 by @maxmzkrcensys)
|
||||||
|
- Fixed install script for some ARM platforms (#1516, #2291 by @trulede).
|
||||||
|
- Fixed a regression where fingerprinting was not working correctly if the path
|
||||||
|
to you Taskfile contained a space (#2321, #2322 by @pd93).
|
||||||
|
- Reverted a breaking change to `randInt` (#2312, #2316 by @pd93).
|
||||||
|
- Made new variables `TEST_NAME` and `TEST_DIR` available in fixture tests
|
||||||
|
(#2265 by @pd93).
|
||||||
|
|
||||||
|
## v3.44.0 - 2025-06-08
|
||||||
|
|
||||||
|
- Added `uuid`, `randInt` and `randIntN` template functions (#1346, #2225 by
|
||||||
|
@pd93).
|
||||||
|
- Added new `CLI_ARGS_LIST` array variable which contains the arguments passed
|
||||||
|
to Task after the `--` (the same as `CLI_ARGS`, but an array instead of a
|
||||||
|
string). (#2138, #2139, #2140 by @pd93).
|
||||||
|
- Added `toYaml` and `fromYaml` templating functions (#2217, #2219 by @pd93).
|
||||||
|
- Added `task` field the `--list --json` output (#2256 by @aleksandersh).
|
||||||
|
- Added the ability to
|
||||||
|
[pin included taskfiles](https://taskfile.dev/next/experiments/remote-taskfiles/#manual-checksum-pinning)
|
||||||
|
by specifying a checksum. This works with both local and remote Taskfiles
|
||||||
|
(#2222, #2223 by @pd93).
|
||||||
|
- When using the
|
||||||
|
[Remote Taskfiles experiment](https://github.com/go-task/task/issues/1317),
|
||||||
|
any credentials used in the URL will now be redacted in Task's output (#2100,
|
||||||
|
#2220 by @pd93).
|
||||||
|
- Fixed fuzzy suggestions not working when misspelling a task name (#2192, #2200
|
||||||
|
by @vmaerten).
|
||||||
|
- Fixed a bug where taskfiles in directories containing spaces created
|
||||||
|
directories in the wrong location (#2208, #2216 by @pd93).
|
||||||
|
- Added support for dual JSON schema files, allowing changes without affecting
|
||||||
|
the current schema. The current schemas will only be updated during releases.
|
||||||
|
(#2211 by @vmaerten).
|
||||||
|
- Improved fingerprint documentation by specifying that the method can be set at
|
||||||
|
the root level to apply to all tasks (#2233 by @vmaerten).
|
||||||
|
- Fixed some watcher regressions after #2048 (#2199, #2202, #2241, #2196 by
|
||||||
|
@wazazaby, #2271 by @andreynering).
|
||||||
|
|
||||||
|
## v3.43.3 - 2025-04-27
|
||||||
|
|
||||||
|
Reverted the changes made in #2113 and #2186 that affected the
|
||||||
|
`USER_WORKING_DIR` and built-in variables. This fixes #2206, #2195, #2207 and
|
||||||
|
#2208.
|
||||||
|
|
||||||
|
## v3.43.2 - 2025-04-21
|
||||||
|
|
||||||
|
- Fixed regresion of `CLI_ARGS` being exposed as the wrong type (#2190, #2191 by
|
||||||
|
@vmaerten).
|
||||||
|
|
||||||
|
## v3.43.1 - 2025-04-21
|
||||||
|
|
||||||
- Significant improvements were made to the watcher. We migrated from
|
- Significant improvements were made to the watcher. We migrated from
|
||||||
[watcher](https://github.com/radovskyb/watcher) to
|
[watcher](https://github.com/radovskyb/watcher) to
|
||||||
|
|||||||
16
Taskfile.yml
16
Taskfile.yml
@@ -53,9 +53,12 @@ tasks:
|
|||||||
generate:fixtures:
|
generate:fixtures:
|
||||||
desc: Runs tests and generates golden fixture files
|
desc: Runs tests and generates golden fixture files
|
||||||
aliases: [gen:fixtures, g:fixtures]
|
aliases: [gen:fixtures, g:fixtures]
|
||||||
|
env:
|
||||||
|
GOLDIE_UPDATE: 'true'
|
||||||
|
GOLDIE_TEMPLATE: 'true'
|
||||||
cmds:
|
cmds:
|
||||||
- find ./testdata -name '*.golden' -delete
|
- find ./testdata -name '*.golden' -delete
|
||||||
- go test -update ./...
|
- go test ./...
|
||||||
|
|
||||||
install:mockery:
|
install:mockery:
|
||||||
desc: Installs mockgen; a tool to generate mock files
|
desc: Installs mockgen; a tool to generate mock files
|
||||||
@@ -87,6 +90,7 @@ tasks:
|
|||||||
sources:
|
sources:
|
||||||
- './**/*.go'
|
- './**/*.go'
|
||||||
- .golangci.yml
|
- .golangci.yml
|
||||||
|
- go.mod
|
||||||
cmds:
|
cmds:
|
||||||
- golangci-lint run
|
- golangci-lint run
|
||||||
|
|
||||||
@@ -95,9 +99,19 @@ tasks:
|
|||||||
sources:
|
sources:
|
||||||
- './**/*.go'
|
- './**/*.go'
|
||||||
- .golangci.yml
|
- .golangci.yml
|
||||||
|
- go.mod
|
||||||
cmds:
|
cmds:
|
||||||
- golangci-lint run --fix
|
- golangci-lint run --fix
|
||||||
|
|
||||||
|
format:
|
||||||
|
desc: Runs golangci-lint and formats any Go files
|
||||||
|
aliases: [fmt, f]
|
||||||
|
sources:
|
||||||
|
- './**/*.go'
|
||||||
|
- .golangci.yml
|
||||||
|
cmds:
|
||||||
|
- golangci-lint fmt
|
||||||
|
|
||||||
sleepit:build:
|
sleepit:build:
|
||||||
desc: Builds the sleepit test helper
|
desc: Builds the sleepit test helper
|
||||||
sources:
|
sources:
|
||||||
|
|||||||
24
args/args.go
24
args/args.go
@@ -20,17 +20,7 @@ func Get() ([]string, []string, error) {
|
|||||||
if doubleDashPos == -1 {
|
if doubleDashPos == -1 {
|
||||||
return args, nil, nil
|
return args, nil, nil
|
||||||
}
|
}
|
||||||
|
return args[:doubleDashPos], args[doubleDashPos:], nil
|
||||||
var quotedCliArgs []string
|
|
||||||
for _, arg := range args[doubleDashPos:] {
|
|
||||||
quotedCliArg, err := syntax.Quote(arg, syntax.LangBash)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
quotedCliArgs = append(quotedCliArgs, quotedCliArg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return args[:doubleDashPos], quotedCliArgs, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses command line argument: tasks and global variables
|
// Parse parses command line argument: tasks and global variables
|
||||||
@@ -51,6 +41,18 @@ func Parse(args ...string) ([]*task.Call, *ast.Vars) {
|
|||||||
return calls, globals
|
return calls, globals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ToQuotedString(args []string) (string, error) {
|
||||||
|
var quotedCliArgs []string
|
||||||
|
for _, arg := range args {
|
||||||
|
quotedCliArg, err := syntax.Quote(arg, syntax.LangBash)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
quotedCliArgs = append(quotedCliArgs, quotedCliArg)
|
||||||
|
}
|
||||||
|
return strings.Join(quotedCliArgs, " "), nil
|
||||||
|
}
|
||||||
|
|
||||||
func splitVar(s string) (string, string) {
|
func splitVar(s string) (string, string) {
|
||||||
pair := strings.SplitN(s, "=", 2)
|
pair := strings.SplitN(s, "=", 2)
|
||||||
return pair[0], pair[1]
|
return pair[0], pair[1]
|
||||||
|
|||||||
@@ -16,10 +16,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
changelogSource = "CHANGELOG.md"
|
changelogSource = "CHANGELOG.md"
|
||||||
changelogTarget = "website/docs/changelog.mdx"
|
changelogTarget = "website/docs/changelog.mdx"
|
||||||
docsSource = "website/docs"
|
docsSource = "website/docs"
|
||||||
docsTarget = "website/versioned_docs/version-latest"
|
docsTarget = "website/versioned_docs/version-latest"
|
||||||
|
schemaSource = "website/static/next-schema.json"
|
||||||
|
schemaTarget = "website/static/schema.json"
|
||||||
|
schemaTaskrcSource = "website/static/next-schema-taskrc.json"
|
||||||
|
schemaTaskrcTarget = "website/static/schema-taskrc.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -83,6 +87,10 @@ func release() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := schema(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,3 +183,13 @@ func docs() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func schema() error {
|
||||||
|
if err := copy.Copy(schemaSource, schemaTarget); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := copy.Copy(schemaTaskrcSource, schemaTaskrcTarget); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/go-task/task/v3"
|
"github.com/go-task/task/v3"
|
||||||
"github.com/go-task/task/v3/args"
|
"github.com/go-task/task/v3/args"
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
"github.com/go-task/task/v3/internal/experiments"
|
"github.com/go-task/task/v3/experiments"
|
||||||
"github.com/go-task/task/v3/internal/filepathext"
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/internal/flags"
|
"github.com/go-task/task/v3/internal/flags"
|
||||||
"github.com/go-task/task/v3/internal/logger"
|
"github.com/go-task/task/v3/internal/logger"
|
||||||
@@ -76,7 +76,7 @@ func run() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, args, err := args.Get()
|
args, _, err := args.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -144,18 +144,23 @@ func run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse the remaining arguments
|
// Parse the remaining arguments
|
||||||
argv, cliArgs, err := args.Get()
|
cliArgsPreDash, cliArgsPostDash, err := args.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
calls, globals := args.Parse(argv...)
|
calls, globals := args.Parse(cliArgsPreDash...)
|
||||||
|
|
||||||
// If there are no calls, run the default task instead
|
// If there are no calls, run the default task instead
|
||||||
if len(calls) == 0 {
|
if len(calls) == 0 {
|
||||||
calls = append(calls, &task.Call{Task: "default"})
|
calls = append(calls, &task.Call{Task: "default"})
|
||||||
}
|
}
|
||||||
|
|
||||||
globals.Set("CLI_ARGS", ast.Var{Value: cliArgs})
|
cliArgsPostDashQuoted, err := args.ToQuotedString(cliArgsPostDash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
globals.Set("CLI_ARGS", ast.Var{Value: cliArgsPostDashQuoted})
|
||||||
|
globals.Set("CLI_ARGS_LIST", ast.Var{Value: cliArgsPostDash})
|
||||||
globals.Set("CLI_FORCE", ast.Var{Value: flags.Force || flags.ForceAll})
|
globals.Set("CLI_FORCE", ast.Var{Value: flags.Force || flags.ForceAll})
|
||||||
globals.Set("CLI_SILENT", ast.Var{Value: flags.Silent})
|
globals.Set("CLI_SILENT", ast.Var{Value: flags.Silent})
|
||||||
globals.Set("CLI_VERBOSE", ast.Var{Value: flags.Verbose})
|
globals.Set("CLI_VERBOSE", ast.Var{Value: flags.Verbose})
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const (
|
|||||||
CodeTaskfileNetworkTimeout
|
CodeTaskfileNetworkTimeout
|
||||||
CodeTaskfileInvalid
|
CodeTaskfileInvalid
|
||||||
CodeTaskfileCycle
|
CodeTaskfileCycle
|
||||||
|
CodeTaskfileDoesNotMatchChecksum
|
||||||
)
|
)
|
||||||
|
|
||||||
// Task related exit codes
|
// Task related exit codes
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package errors
|
package errors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -46,8 +47,9 @@ func (err *TaskRunError) Code() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (err *TaskRunError) TaskExitCode() int {
|
func (err *TaskRunError) TaskExitCode() int {
|
||||||
if c, ok := interp.IsExitStatus(err.Err); ok {
|
var exit interp.ExitStatus
|
||||||
return int(c)
|
if errors.As(err.Err, &exit) {
|
||||||
|
return int(exit)
|
||||||
}
|
}
|
||||||
return err.Code()
|
return err.Code()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,3 +187,24 @@ func (err TaskfileCycleError) Error() string {
|
|||||||
func (err TaskfileCycleError) Code() int {
|
func (err TaskfileCycleError) Code() int {
|
||||||
return CodeTaskfileCycle
|
return CodeTaskfileCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TaskfileDoesNotMatchChecksum is returned when a Taskfile's checksum does not
|
||||||
|
// match the one pinned in the parent Taskfile.
|
||||||
|
type TaskfileDoesNotMatchChecksum struct {
|
||||||
|
URI string
|
||||||
|
ExpectedChecksum string
|
||||||
|
ActualChecksum string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *TaskfileDoesNotMatchChecksum) Error() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"task: The checksum of the Taskfile at %q does not match!\ngot: %q\nwant: %q",
|
||||||
|
err.URI,
|
||||||
|
err.ActualChecksum,
|
||||||
|
err.ExpectedChecksum,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *TaskfileDoesNotMatchChecksum) Code() int {
|
||||||
|
return CodeTaskfileDoesNotMatchChecksum
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -123,7 +122,6 @@ type dirOption struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *dirOption) ApplyToExecutor(e *Executor) {
|
func (o *dirOption) ApplyToExecutor(e *Executor) {
|
||||||
e.UserWorkingDir, _ = filepath.Abs(o.dir)
|
|
||||||
e.Dir = o.dir
|
e.Dir = o.dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/go-task/task/v3"
|
"github.com/go-task/task/v3"
|
||||||
"github.com/go-task/task/v3/internal/experiments"
|
"github.com/go-task/task/v3/experiments"
|
||||||
"github.com/go-task/task/v3/internal/filepathext"
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
)
|
)
|
||||||
@@ -50,7 +50,8 @@ func NewExecutorTest(t *testing.T, opts ...ExecutorTestOption) {
|
|||||||
task: "default",
|
task: "default",
|
||||||
vars: map[string]any{},
|
vars: map[string]any{},
|
||||||
TaskTest: TaskTest{
|
TaskTest: TaskTest{
|
||||||
experiments: map[*experiments.Experiment]int{},
|
experiments: map[*experiments.Experiment]int{},
|
||||||
|
fixtureTemplateData: map[string]any{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Apply the functional options
|
// Apply the functional options
|
||||||
@@ -232,7 +233,7 @@ func TestEmptyTaskfile(t *testing.T) {
|
|||||||
task.WithDir("testdata/empty_taskfile"),
|
task.WithDir("testdata/empty_taskfile"),
|
||||||
),
|
),
|
||||||
WithSetupError(),
|
WithSetupError(),
|
||||||
WithPostProcessFn(PPRemoveAbsolutePaths),
|
WithFixtureTemplating(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +368,7 @@ func TestSpecialVars(t *testing.T) {
|
|||||||
task.WithVersionCheck(true),
|
task.WithVersionCheck(true),
|
||||||
),
|
),
|
||||||
WithTask(test),
|
WithTask(test),
|
||||||
WithPostProcessFn(PPRemoveAbsolutePaths),
|
WithFixtureTemplating(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -551,7 +552,7 @@ func TestStatus(t *testing.T) {
|
|||||||
task.WithVerbose(true),
|
task.WithVerbose(true),
|
||||||
),
|
),
|
||||||
WithTask("gen-silent-baz"),
|
WithTask("gen-silent-baz"),
|
||||||
WithPostProcessFn(PPRemoveAbsolutePaths),
|
WithFixtureTemplating(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,7 +778,7 @@ func TestForCmds(t *testing.T) {
|
|||||||
task.WithForce(true),
|
task.WithForce(true),
|
||||||
),
|
),
|
||||||
WithTask(test.name),
|
WithTask(test.name),
|
||||||
WithPostProcessFn(PPRemoveAbsolutePaths),
|
WithFixtureTemplating(),
|
||||||
}
|
}
|
||||||
if test.wantErr {
|
if test.wantErr {
|
||||||
opts = append(opts, WithRunError())
|
opts = append(opts, WithRunError())
|
||||||
@@ -822,7 +823,7 @@ func TestForDeps(t *testing.T) {
|
|||||||
task.WithOutputStyle(ast.Output{Name: "group"}),
|
task.WithOutputStyle(ast.Output{Name: "group"}),
|
||||||
),
|
),
|
||||||
WithTask(test.name),
|
WithTask(test.name),
|
||||||
WithPostProcessFn(PPRemoveAbsolutePaths),
|
WithFixtureTemplating(),
|
||||||
WithPostProcessFn(PPSortedLines),
|
WithPostProcessFn(PPSortedLines),
|
||||||
}
|
}
|
||||||
if test.wantErr {
|
if test.wantErr {
|
||||||
@@ -937,3 +938,53 @@ func TestVarInheritance(t *testing.T) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFuzzyModel(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("fuzzy"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/fuzzy"),
|
||||||
|
),
|
||||||
|
WithTask("instal"),
|
||||||
|
WithRunError(),
|
||||||
|
)
|
||||||
|
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("not-fuzzy"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/fuzzy"),
|
||||||
|
),
|
||||||
|
WithTask("install"),
|
||||||
|
)
|
||||||
|
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("intern"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/fuzzy"),
|
||||||
|
),
|
||||||
|
WithTask("intern"),
|
||||||
|
WithRunError(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIncludeChecksum(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("correct"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/includes_checksum/correct"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("incorrect"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/includes_checksum/incorrect"),
|
||||||
|
),
|
||||||
|
WithSetupError(),
|
||||||
|
WithFixtureTemplating(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/experiments"
|
"github.com/go-task/task/v3/experiments"
|
||||||
"github.com/go-task/task/v3/taskrc/ast"
|
"github.com/go-task/task/v3/taskrc/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/go-task/task/v3"
|
"github.com/go-task/task/v3"
|
||||||
"github.com/go-task/task/v3/internal/experiments"
|
"github.com/go-task/task/v3/experiments"
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,7 +44,8 @@ func NewFormatterTest(t *testing.T, opts ...FormatterTestOption) {
|
|||||||
task: "default",
|
task: "default",
|
||||||
vars: map[string]any{},
|
vars: map[string]any{},
|
||||||
TaskTest: TaskTest{
|
TaskTest: TaskTest{
|
||||||
experiments: map[*experiments.Experiment]int{},
|
experiments: map[*experiments.Experiment]int{},
|
||||||
|
fixtureTemplateData: map[string]any{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Apply the functional options
|
// Apply the functional options
|
||||||
@@ -218,3 +219,17 @@ func TestListDescInterpolation(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJsonListFormat(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
NewFormatterTest(t,
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/json_list_format"),
|
||||||
|
),
|
||||||
|
WithListOptions(task.ListOptions{
|
||||||
|
FormatTaskListAsJSON: true,
|
||||||
|
}),
|
||||||
|
WithFixtureTemplating(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
21
go.mod
21
go.mod
@@ -4,8 +4,8 @@ go 1.23.0
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Ladicle/tabwriter v1.0.0
|
github.com/Ladicle/tabwriter v1.0.0
|
||||||
github.com/Masterminds/semver/v3 v3.3.1
|
github.com/Masterminds/semver/v3 v3.4.0
|
||||||
github.com/alecthomas/chroma/v2 v2.16.0
|
github.com/alecthomas/chroma/v2 v2.20.0
|
||||||
github.com/chainguard-dev/git-urls v1.0.2
|
github.com/chainguard-dev/git-urls v1.0.2
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/dominikbraun/graph v0.23.0
|
github.com/dominikbraun/graph v0.23.0
|
||||||
@@ -13,22 +13,23 @@ require (
|
|||||||
github.com/fatih/color v1.18.0
|
github.com/fatih/color v1.18.0
|
||||||
github.com/fsnotify/fsnotify v1.9.0
|
github.com/fsnotify/fsnotify v1.9.0
|
||||||
github.com/go-git/go-billy/v5 v5.6.2
|
github.com/go-git/go-billy/v5 v5.6.2
|
||||||
github.com/go-git/go-git/v5 v5.16.0
|
github.com/go-git/go-git/v5 v5.16.2
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0
|
github.com/go-task/slim-sprig/v3 v3.0.0
|
||||||
github.com/go-task/template v0.1.0
|
github.com/go-task/template v0.2.0
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||||
github.com/otiai10/copy v1.14.1
|
github.com/otiai10/copy v1.14.1
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.5.1
|
github.com/puzpuzpuz/xsync/v3 v3.5.1
|
||||||
github.com/sajari/fuzzy v1.0.0
|
github.com/sajari/fuzzy v1.0.0
|
||||||
github.com/sebdah/goldie/v2 v2.5.5
|
github.com/sebdah/goldie/v2 v2.7.1
|
||||||
github.com/spf13/pflag v1.0.6
|
github.com/spf13/pflag v1.0.7
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/zeebo/xxh3 v1.0.2
|
github.com/zeebo/xxh3 v1.0.2
|
||||||
golang.org/x/sync v0.13.0
|
golang.org/x/sync v0.16.0
|
||||||
golang.org/x/term v0.31.0
|
golang.org/x/term v0.33.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
mvdan.cc/sh/v3 v3.11.0
|
mvdan.cc/sh/v3 v3.12.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -55,6 +56,6 @@ require (
|
|||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
golang.org/x/crypto v0.37.0 // indirect
|
golang.org/x/crypto v0.37.0 // indirect
|
||||||
golang.org/x/net v0.39.0 // indirect
|
golang.org/x/net v0.39.0 // indirect
|
||||||
golang.org/x/sys v0.32.0 // indirect
|
golang.org/x/sys v0.34.0 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
72
go.sum
72
go.sum
@@ -2,21 +2,19 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
|||||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9Dg=
|
github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9Dg=
|
||||||
github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4=
|
github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4=
|
||||||
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
|
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||||
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
|
|
||||||
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
|
||||||
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||||
github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
|
github.com/alecthomas/chroma/v2 v2.19.0 h1:Im+SLRgT8maArxv81mULDWN8oKxkzboH07CHesxElq4=
|
||||||
github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
|
github.com/alecthomas/chroma/v2 v2.19.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
|
||||||
github.com/alecthomas/chroma/v2 v2.16.0 h1:QC5ZMizk67+HzxFDjQ4ASjni5kWBTGiigRG1u23IGvA=
|
github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw=
|
||||||
github.com/alecthomas/chroma/v2 v2.16.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
|
github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA=
|
||||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
@@ -25,8 +23,6 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
|
|||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiwNkJrVcKQ=
|
github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiwNkJrVcKQ=
|
||||||
github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o=
|
github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o=
|
||||||
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
|
||||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||||
@@ -36,8 +32,6 @@ github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGL
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
|
||||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
|
||||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo=
|
github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo=
|
||||||
@@ -50,8 +44,6 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc
|
|||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
|
||||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
|
||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||||
@@ -62,22 +54,20 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN
|
|||||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60=
|
github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM=
|
||||||
github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k=
|
github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||||
github.com/go-git/go-git/v5 v5.15.0 h1:f5Qn0W0F7ry1iN0ZwIU5m/n7/BKB4hiZfc+zlZx7ly0=
|
|
||||||
github.com/go-git/go-git/v5 v5.15.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
|
||||||
github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ=
|
|
||||||
github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
|
||||||
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
|
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
|
||||||
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/go-task/template v0.1.0 h1:ym/r2G937RZA1bsgiWedNnY9e5kxDT+3YcoAnuIetTE=
|
github.com/go-task/template v0.2.0 h1:xW7ek0o65FUSTbKcSNeg2Vyf/I7wYXFgLUznptvviBE=
|
||||||
github.com/go-task/template v0.1.0/go.mod h1:RgwRaZK+kni/hJJ7/AaOE2lPQFPbAdji/DyhC6pxo4k=
|
github.com/go-task/template v0.2.0/go.mod h1:dbdoUb6qKnHQi1y6o+IdIrs0J4o/SEhSTA6bbzZmdtc=
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
@@ -121,16 +111,16 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
|
|||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY=
|
github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY=
|
||||||
github.com/sajari/fuzzy v1.0.0/go.mod h1:OjYR6KxoWOe9+dOlXeiCJd4dIbED4Oo8wpS89o0pwOo=
|
github.com/sajari/fuzzy v1.0.0/go.mod h1:OjYR6KxoWOe9+dOlXeiCJd4dIbED4Oo8wpS89o0pwOo=
|
||||||
github.com/sebdah/goldie/v2 v2.5.5 h1:rx1mwF95RxZ3/83sdS4Yp7t2C5TCokvWP4TBRbAyEWY=
|
github.com/sebdah/goldie/v2 v2.7.1 h1:PkBHymaYdtvEkZV7TmyqKxdmn5/Vcj+8TpATWZjnG5E=
|
||||||
github.com/sebdah/goldie/v2 v2.5.5/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
github.com/sebdah/goldie/v2 v2.7.1/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
|
||||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
@@ -146,21 +136,15 @@ github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN
|
|||||||
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
|
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
|
||||||
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
|
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
|
||||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
|
||||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
|
||||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
|
||||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
|
||||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -170,18 +154,14 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
|
||||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
|
||||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
||||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
|
||||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -193,5 +173,5 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
mvdan.cc/sh/v3 v3.11.0 h1:q5h+XMDRfUGUedCqFFsjoFjrhwf2Mvtt1rkMvVz0blw=
|
mvdan.cc/sh/v3 v3.12.0 h1:ejKUR7ONP5bb+UGHGEG/k9V5+pRVIyD+LsZz7o8KHrI=
|
||||||
mvdan.cc/sh/v3 v3.11.0/go.mod h1:LRM+1NjoYCzuq/WZ6y44x14YNAI0NK7FLPeQSaFagGg=
|
mvdan.cc/sh/v3 v3.12.0/go.mod h1:Se6Cj17eYSn+sNooLZiEUnNNmNxg0imoYlTu4CyaGyg=
|
||||||
|
|||||||
1
help.go
1
help.go
@@ -149,6 +149,7 @@ func (e *Executor) ToEditorOutput(tasks []*ast.Task, noStatus bool) (*editors.Ta
|
|||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
o.Tasks[i] = editors.Task{
|
o.Tasks[i] = editors.Task{
|
||||||
Name: tasks[i].Name(),
|
Name: tasks[i].Name(),
|
||||||
|
Task: tasks[i].Task,
|
||||||
Desc: tasks[i].Desc,
|
Desc: tasks[i].Desc,
|
||||||
Summary: tasks[i].Summary,
|
Summary: tasks[i].Summary,
|
||||||
Aliases: aliases,
|
Aliases: aliases,
|
||||||
|
|||||||
@@ -64,21 +64,15 @@ get_binaries() {
|
|||||||
case "$PLATFORM" in
|
case "$PLATFORM" in
|
||||||
darwin/amd64) BINARIES="task" ;;
|
darwin/amd64) BINARIES="task" ;;
|
||||||
darwin/arm64) BINARIES="task" ;;
|
darwin/arm64) BINARIES="task" ;;
|
||||||
darwin/armv5) BINARIES="task" ;;
|
darwin/arm) BINARIES="task" ;;
|
||||||
darwin/armv6) BINARIES="task" ;;
|
|
||||||
darwin/armv7) BINARIES="task" ;;
|
|
||||||
linux/386) BINARIES="task" ;;
|
linux/386) BINARIES="task" ;;
|
||||||
linux/amd64) BINARIES="task" ;;
|
linux/amd64) BINARIES="task" ;;
|
||||||
linux/arm64) BINARIES="task" ;;
|
linux/arm64) BINARIES="task" ;;
|
||||||
linux/armv5) BINARIES="task" ;;
|
linux/arm) BINARIES="task" ;;
|
||||||
linux/armv6) BINARIES="task" ;;
|
|
||||||
linux/armv7) BINARIES="task" ;;
|
|
||||||
windows/386) BINARIES="task" ;;
|
windows/386) BINARIES="task" ;;
|
||||||
windows/amd64) BINARIES="task" ;;
|
windows/amd64) BINARIES="task" ;;
|
||||||
windows/arm64) BINARIES="task" ;;
|
windows/arm64) BINARIES="task" ;;
|
||||||
windows/armv5) BINARIES="task" ;;
|
windows/arm) BINARIES="task" ;;
|
||||||
windows/armv6) BINARIES="task" ;;
|
|
||||||
windows/armv7) BINARIES="task" ;;
|
|
||||||
*)
|
*)
|
||||||
log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
|
log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ type (
|
|||||||
// Task describes a single task
|
// Task describes a single task
|
||||||
Task struct {
|
Task struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Task string `json:"task"`
|
||||||
Desc string `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
Summary string `json:"summary"`
|
Summary string `json:"summary"`
|
||||||
Aliases []string `json:"aliases"`
|
Aliases []string `json:"aliases"`
|
||||||
|
|||||||
2
internal/env/env.go
vendored
2
internal/env/env.go
vendored
@@ -5,7 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/experiments"
|
"github.com/go-task/task/v3/experiments"
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -106,25 +106,17 @@ func ExpandLiteral(s string) (string, error) {
|
|||||||
if s == "" {
|
if s == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
s = escape(s)
|
|
||||||
p := syntax.NewParser()
|
p := syntax.NewParser()
|
||||||
var words []*syntax.Word
|
word, err := p.Document(strings.NewReader(s))
|
||||||
err := p.Words(strings.NewReader(s), func(w *syntax.Word) bool {
|
|
||||||
words = append(words, w)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if len(words) == 0 {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
cfg := &expand.Config{
|
cfg := &expand.Config{
|
||||||
Env: expand.FuncEnviron(os.Getenv),
|
Env: expand.FuncEnviron(os.Getenv),
|
||||||
ReadDir2: os.ReadDir,
|
ReadDir2: os.ReadDir,
|
||||||
GlobStar: true,
|
GlobStar: true,
|
||||||
}
|
}
|
||||||
return expand.Literal(cfg, words[0])
|
return expand.Literal(cfg, word)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpandFields is a wrapper around [expand.Fields]. It will escape the input
|
// ExpandFields is a wrapper around [expand.Fields]. It will escape the input
|
||||||
@@ -146,6 +138,7 @@ func ExpandFields(s string) ([]string, error) {
|
|||||||
Env: expand.FuncEnviron(os.Getenv),
|
Env: expand.FuncEnviron(os.Getenv),
|
||||||
ReadDir2: os.ReadDir,
|
ReadDir2: os.ReadDir,
|
||||||
GlobStar: true,
|
GlobStar: true,
|
||||||
|
NullGlob: true,
|
||||||
}
|
}
|
||||||
return expand.Fields(cfg, words...)
|
return expand.Fields(cfg, words...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ 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/internal/env"
|
"github.com/go-task/task/v3/internal/env"
|
||||||
"github.com/go-task/task/v3/internal/experiments"
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package fsnotifyext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
@@ -11,7 +10,6 @@ import (
|
|||||||
type Deduper struct {
|
type Deduper struct {
|
||||||
w *fsnotify.Watcher
|
w *fsnotify.Watcher
|
||||||
waitTime time.Duration
|
waitTime time.Duration
|
||||||
mutex sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDeduper(w *fsnotify.Watcher, waitTime time.Duration) *Deduper {
|
func NewDeduper(w *fsnotify.Watcher, waitTime time.Duration) *Deduper {
|
||||||
@@ -21,31 +19,28 @@ func NewDeduper(w *fsnotify.Watcher, waitTime time.Duration) *Deduper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Deduper) GetChan() chan fsnotify.Event {
|
// GetChan returns a chan of deduplicated [fsnotify.Event].
|
||||||
|
//
|
||||||
|
// [fsnotify.Chmod] operations will be skipped.
|
||||||
|
func (d *Deduper) GetChan() <-chan fsnotify.Event {
|
||||||
channel := make(chan fsnotify.Event)
|
channel := make(chan fsnotify.Event)
|
||||||
timers := make(map[string]*time.Timer)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
timers := make(map[string]*time.Timer)
|
||||||
for {
|
for {
|
||||||
event, ok := <-d.w.Events
|
event, ok := <-d.w.Events
|
||||||
switch {
|
switch {
|
||||||
case !ok:
|
case !ok:
|
||||||
return
|
return
|
||||||
case event.Op == fsnotify.Chmod:
|
case event.Has(fsnotify.Chmod):
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
d.mutex.Lock()
|
|
||||||
timer, ok := timers[event.String()]
|
timer, ok := timers[event.String()]
|
||||||
d.mutex.Unlock()
|
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
timer = time.AfterFunc(math.MaxInt64, func() { channel <- event })
|
timer = time.AfterFunc(math.MaxInt64, func() { channel <- event })
|
||||||
timer.Stop()
|
timer.Stop()
|
||||||
|
|
||||||
d.mutex.Lock()
|
|
||||||
timers[event.String()] = timer
|
timers[event.String()] = timer
|
||||||
d.mutex.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.Reset(d.waitTime)
|
timer.Reset(d.waitTime)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import (
|
|||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
|
||||||
"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/internal/env"
|
"github.com/go-task/task/v3/internal/env"
|
||||||
"github.com/go-task/task/v3/internal/experiments"
|
|
||||||
"github.com/go-task/task/v3/internal/term"
|
"github.com/go-task/task/v3/internal/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ package templater
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"maps"
|
"maps"
|
||||||
|
"math/rand/v2"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"mvdan.cc/sh/v3/shell"
|
"mvdan.cc/sh/v3/shell"
|
||||||
"mvdan.cc/sh/v3/syntax"
|
"mvdan.cc/sh/v3/syntax"
|
||||||
|
|
||||||
@@ -18,58 +21,27 @@ var templateFuncs template.FuncMap
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
taskFuncs := template.FuncMap{
|
taskFuncs := template.FuncMap{
|
||||||
"OS": func() string { return runtime.GOOS },
|
"OS": os,
|
||||||
"ARCH": func() string { return runtime.GOARCH },
|
"ARCH": arch,
|
||||||
"numCPU": func() int { return runtime.NumCPU() },
|
"numCPU": runtime.NumCPU,
|
||||||
"catLines": func(s string) string {
|
"catLines": catLines,
|
||||||
s = strings.ReplaceAll(s, "\r\n", " ")
|
"splitLines": splitLines,
|
||||||
return strings.ReplaceAll(s, "\n", " ")
|
"fromSlash": filepath.FromSlash,
|
||||||
},
|
"toSlash": filepath.ToSlash,
|
||||||
"splitLines": func(s string) []string {
|
"exeExt": exeExt,
|
||||||
s = strings.ReplaceAll(s, "\r\n", "\n")
|
"shellQuote": shellQuote,
|
||||||
return strings.Split(s, "\n")
|
"splitArgs": splitArgs,
|
||||||
},
|
"IsSH": IsSH, // Deprecated
|
||||||
"fromSlash": func(path string) string {
|
"joinPath": filepath.Join,
|
||||||
return filepath.FromSlash(path)
|
"relPath": filepath.Rel,
|
||||||
},
|
"merge": merge,
|
||||||
"toSlash": func(path string) string {
|
"spew": spew.Sdump,
|
||||||
return filepath.ToSlash(path)
|
"fromYaml": fromYaml,
|
||||||
},
|
"mustFromYaml": mustFromYaml,
|
||||||
"exeExt": func() string {
|
"toYaml": toYaml,
|
||||||
if runtime.GOOS == "windows" {
|
"mustToYaml": mustToYaml,
|
||||||
return ".exe"
|
"uuid": uuid.New,
|
||||||
}
|
"randIntN": rand.IntN,
|
||||||
return ""
|
|
||||||
},
|
|
||||||
"shellQuote": func(str string) (string, error) {
|
|
||||||
return syntax.Quote(str, syntax.LangBash)
|
|
||||||
},
|
|
||||||
"splitArgs": func(s string) ([]string, error) {
|
|
||||||
return shell.Fields(s, nil)
|
|
||||||
},
|
|
||||||
// IsSH is deprecated.
|
|
||||||
"IsSH": func() bool { return true },
|
|
||||||
"joinPath": func(elem ...string) string {
|
|
||||||
return filepath.Join(elem...)
|
|
||||||
},
|
|
||||||
"relPath": func(basePath, targetPath string) (string, error) {
|
|
||||||
return filepath.Rel(basePath, targetPath)
|
|
||||||
},
|
|
||||||
"merge": func(base map[string]any, v ...map[string]any) map[string]any {
|
|
||||||
cap := len(v)
|
|
||||||
for _, m := range v {
|
|
||||||
cap += len(m)
|
|
||||||
}
|
|
||||||
result := make(map[string]any, cap)
|
|
||||||
maps.Copy(result, base)
|
|
||||||
for _, m := range v {
|
|
||||||
maps.Copy(result, m)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
},
|
|
||||||
"spew": func(v any) string {
|
|
||||||
return spew.Sdump(v)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// aliases
|
// aliases
|
||||||
@@ -83,3 +55,78 @@ func init() {
|
|||||||
templateFuncs = template.FuncMap(sprig.TxtFuncMap())
|
templateFuncs = template.FuncMap(sprig.TxtFuncMap())
|
||||||
maps.Copy(templateFuncs, taskFuncs)
|
maps.Copy(templateFuncs, taskFuncs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func os() string {
|
||||||
|
return runtime.GOOS
|
||||||
|
}
|
||||||
|
|
||||||
|
func arch() string {
|
||||||
|
return runtime.GOARCH
|
||||||
|
}
|
||||||
|
|
||||||
|
func catLines(s string) string {
|
||||||
|
s = strings.ReplaceAll(s, "\r\n", " ")
|
||||||
|
return strings.ReplaceAll(s, "\n", " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitLines(s string) []string {
|
||||||
|
s = strings.ReplaceAll(s, "\r\n", "\n")
|
||||||
|
return strings.Split(s, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func exeExt() string {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
return ".exe"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func shellQuote(str string) (string, error) {
|
||||||
|
return syntax.Quote(str, syntax.LangBash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitArgs(s string) ([]string, error) {
|
||||||
|
return shell.Fields(s, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: now always returns true
|
||||||
|
func IsSH() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func merge(base map[string]any, v ...map[string]any) map[string]any {
|
||||||
|
cap := len(v)
|
||||||
|
for _, m := range v {
|
||||||
|
cap += len(m)
|
||||||
|
}
|
||||||
|
result := make(map[string]any, cap)
|
||||||
|
maps.Copy(result, base)
|
||||||
|
for _, m := range v {
|
||||||
|
maps.Copy(result, m)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromYaml(v string) any {
|
||||||
|
output, _ := mustFromYaml(v)
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustFromYaml(v string) (any, error) {
|
||||||
|
var output any
|
||||||
|
err := yaml.Unmarshal([]byte(v), &output)
|
||||||
|
return output, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func toYaml(v any) string {
|
||||||
|
output, _ := yaml.Marshal(v)
|
||||||
|
return string(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustToYaml(v any) (string, error) {
|
||||||
|
output, err := yaml.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(output), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import (
|
|||||||
"maps"
|
"maps"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-task/template"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/deepcopy"
|
"github.com/go-task/task/v3/internal/deepcopy"
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
"github.com/go-task/template"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cache is a help struct that allow us to call "replaceX" funcs multiple
|
// Cache is a help struct that allow us to call "replaceX" funcs multiple
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -46,6 +48,10 @@ func getCommit(info *debug.BuildInfo) string {
|
|||||||
// However, it can also be overridden at build time using:
|
// However, it can also be overridden at build time using:
|
||||||
// -ldflags="-X 'github.com/go-task/task/v3/internal/version.version=vX.X.X'".
|
// -ldflags="-X 'github.com/go-task/task/v3/internal/version.version=vX.X.X'".
|
||||||
func GetVersion() string {
|
func GetVersion() string {
|
||||||
|
// If its a development version, we bump the minor version.
|
||||||
|
if commit != "" || dirty {
|
||||||
|
return semver.MustParse(version).IncMinor().String()
|
||||||
|
}
|
||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +67,7 @@ func GetVersionWithBuildInfo() string {
|
|||||||
buildMetadata = append(buildMetadata, "dirty")
|
buildMetadata = append(buildMetadata, "dirty")
|
||||||
}
|
}
|
||||||
if len(buildMetadata) > 0 {
|
if len(buildMetadata) > 0 {
|
||||||
return version + "+" + strings.Join(buildMetadata, ".")
|
return GetVersion() + "+" + strings.Join(buildMetadata, ".")
|
||||||
}
|
}
|
||||||
return version
|
return GetVersion()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
3.43.0
|
3.44.1
|
||||||
|
|||||||
58
internal/version/version_test.go
Normal file
58
internal/version/version_test.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVersionTxt(t *testing.T) {
|
||||||
|
// Check that the version.txt is a valid semver version.
|
||||||
|
require.NotEmpty(t, GetVersion(), "version.txt is not semver compliant")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetVersion(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
version string
|
||||||
|
commit string
|
||||||
|
dirty bool
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"1.2.3", "", false, "1.2.3"},
|
||||||
|
{"1.2.3", "", true, "1.3.0"},
|
||||||
|
{"1.2.3", "abcdefg", false, "1.3.0"},
|
||||||
|
{"1.2.3", "abcdefg", true, "1.3.0"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
version = tt.version
|
||||||
|
commit = tt.commit
|
||||||
|
dirty = tt.dirty
|
||||||
|
t.Run(tt.want, func(t *testing.T) {
|
||||||
|
require.Equal(t, tt.want, GetVersion())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetVersionWithBuildInfo(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
version string
|
||||||
|
commit string
|
||||||
|
dirty bool
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"1.2.3", "", false, "1.2.3"},
|
||||||
|
{"1.2.3", "", true, "1.3.0+dirty"},
|
||||||
|
{"1.2.3", "abcdefg", false, "1.3.0+abcdefg"},
|
||||||
|
{"1.2.3", "abcdefg", true, "1.3.0+abcdefg.dirty"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
version = tt.version
|
||||||
|
commit = tt.commit
|
||||||
|
dirty = tt.dirty
|
||||||
|
t.Run(tt.want, func(t *testing.T) {
|
||||||
|
require.Equal(t, tt.want, GetVersionWithBuildInfo())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@go-task/cli",
|
"name": "@go-task/cli",
|
||||||
"version": "3.43.0",
|
"version": "3.44.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@go-task/cli",
|
"name": "@go-task/cli",
|
||||||
"version": "3.43.0",
|
"version": "3.44.1",
|
||||||
"description": "A task runner / simpler Make alternative written in Go",
|
"description": "A task runner / simpler Make alternative written in Go",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "go-npm install",
|
"postinstall": "go-npm install",
|
||||||
|
|||||||
5
setup.go
5
setup.go
@@ -95,7 +95,7 @@ func (e *Executor) readTaskfile(node taskfile.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) setupFuzzyModel() {
|
func (e *Executor) setupFuzzyModel() {
|
||||||
if e.Taskfile != nil {
|
if e.Taskfile == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +104,9 @@ func (e *Executor) setupFuzzyModel() {
|
|||||||
|
|
||||||
var words []string
|
var words []string
|
||||||
for name, task := range e.Taskfile.Tasks.All(nil) {
|
for name, task := range e.Taskfile.Tasks.All(nil) {
|
||||||
|
if task.Internal {
|
||||||
|
continue
|
||||||
|
}
|
||||||
words = append(words, name)
|
words = append(words, name)
|
||||||
words = slices.Concat(words, task.Aliases)
|
words = slices.Concat(words, task.Aliases)
|
||||||
}
|
}
|
||||||
|
|||||||
15
task.go
15
task.go
@@ -8,6 +8,9 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
"mvdan.cc/sh/v3/interp"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
"github.com/go-task/task/v3/internal/env"
|
"github.com/go-task/task/v3/internal/env"
|
||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
@@ -19,9 +22,6 @@ import (
|
|||||||
"github.com/go-task/task/v3/internal/summary"
|
"github.com/go-task/task/v3/internal/summary"
|
||||||
"github.com/go-task/task/v3/internal/templater"
|
"github.com/go-task/task/v3/internal/templater"
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -220,13 +220,13 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error {
|
|||||||
e.Logger.VerboseErrf(logger.Yellow, "task: error cleaning status on error: %v\n", err2)
|
e.Logger.VerboseErrf(logger.Yellow, "task: error cleaning status on error: %v\n", err2)
|
||||||
}
|
}
|
||||||
|
|
||||||
exitCode, isExitError := interp.IsExitStatus(err)
|
var exitCode interp.ExitStatus
|
||||||
if isExitError {
|
if errors.As(err, &exitCode) {
|
||||||
if t.IgnoreError {
|
if t.IgnoreError {
|
||||||
e.Logger.VerboseErrf(logger.Yellow, "task: task error ignored: %v\n", err)
|
e.Logger.VerboseErrf(logger.Yellow, "task: task error ignored: %v\n", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
deferredExitCode = exitCode
|
deferredExitCode = uint8(exitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if call.Indirect {
|
if call.Indirect {
|
||||||
@@ -356,7 +356,8 @@ func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *Call, i in
|
|||||||
if closeErr := closer(err); closeErr != nil {
|
if closeErr := closer(err); closeErr != nil {
|
||||||
e.Logger.Errf(logger.Red, "task: unable to close writer: %v\n", closeErr)
|
e.Logger.Errf(logger.Red, "task: unable to close writer: %v\n", closeErr)
|
||||||
}
|
}
|
||||||
if _, isExitError := interp.IsExitStatus(err); isExitError && cmd.IgnoreError {
|
var exitCode interp.ExitStatus
|
||||||
|
if errors.As(err, &exitCode) && cmd.IgnoreError {
|
||||||
e.Logger.VerboseErrf(logger.Yellow, "task: [%s] command error ignored: %v\n", t.Name(), err)
|
e.Logger.VerboseErrf(logger.Yellow, "task: [%s] command error ignored: %v\n", t.Name(), err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
91
task_test.go
91
task_test.go
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"maps"
|
||||||
rand "math/rand/v2"
|
rand "math/rand/v2"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@@ -27,7 +28,7 @@ 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/internal/experiments"
|
"github.com/go-task/task/v3/experiments"
|
||||||
"github.com/go-task/task/v3/internal/filepathext"
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
)
|
)
|
||||||
@@ -42,9 +43,11 @@ type (
|
|||||||
FormatterTestOption
|
FormatterTestOption
|
||||||
}
|
}
|
||||||
TaskTest struct {
|
TaskTest struct {
|
||||||
name string
|
name string
|
||||||
experiments map[*experiments.Experiment]int
|
experiments map[*experiments.Experiment]int
|
||||||
postProcessFns []PostProcessFn
|
postProcessFns []PostProcessFn
|
||||||
|
fixtureTemplateData map[string]any
|
||||||
|
fixtureTemplatingEnabled bool
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -79,7 +82,22 @@ func (tt *TaskTest) writeFixture(
|
|||||||
if goldenFileSuffix != "" {
|
if goldenFileSuffix != "" {
|
||||||
goldenFileName += "-" + goldenFileSuffix
|
goldenFileName += "-" + goldenFileSuffix
|
||||||
}
|
}
|
||||||
g.Assert(t, goldenFileName, b)
|
// Create a set of data to be made available to every test fixture
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
require.NoError(t, err)
|
||||||
|
if tt.fixtureTemplatingEnabled {
|
||||||
|
fixtureTemplateData := map[string]any{
|
||||||
|
"TEST_NAME": t.Name(),
|
||||||
|
"TEST_DIR": wd,
|
||||||
|
}
|
||||||
|
// If the test has additional template data, copy it into the map
|
||||||
|
if tt.fixtureTemplateData != nil {
|
||||||
|
maps.Copy(fixtureTemplateData, tt.fixtureTemplateData)
|
||||||
|
}
|
||||||
|
g.AssertWithTemplate(t, goldenFileName, fixtureTemplateData, b)
|
||||||
|
} else {
|
||||||
|
g.Assert(t, goldenFileName, b)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeFixtureBuffer is a wrapper for writing the main output of the task to a
|
// writeFixtureBuffer is a wrapper for writing the main output of the task to a
|
||||||
@@ -234,23 +252,52 @@ func (opt *setupErrorTestOption) applyToFormatterTest(t *FormatterTest) {
|
|||||||
t.wantSetupError = true
|
t.wantSetupError = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithFixtureTemplating enables templating for the golden fixture files with
|
||||||
|
// the default set of data. This is useful if the golden file is dynamic in some
|
||||||
|
// way (e.g. contains user-specific directories). To add more data, see
|
||||||
|
// WithFixtureTemplateData.
|
||||||
|
func WithFixtureTemplating() TestOption {
|
||||||
|
return &fixtureTemplatingTestOption{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fixtureTemplatingTestOption struct{}
|
||||||
|
|
||||||
|
func (opt *fixtureTemplatingTestOption) applyToExecutorTest(t *ExecutorTest) {
|
||||||
|
t.fixtureTemplatingEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *fixtureTemplatingTestOption) applyToFormatterTest(t *FormatterTest) {
|
||||||
|
t.fixtureTemplatingEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFixtureTemplateData adds data to the golden fixture file templates. Keys
|
||||||
|
// given here will override any existing values. This option will also enable
|
||||||
|
// global templating, so you do not need to call WithFixtureTemplating as well.
|
||||||
|
func WithFixtureTemplateData(key string, value any) TestOption {
|
||||||
|
return &fixtureTemplateDataTestOption{key, value}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fixtureTemplateDataTestOption struct {
|
||||||
|
k string
|
||||||
|
v any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *fixtureTemplateDataTestOption) applyToExecutorTest(t *ExecutorTest) {
|
||||||
|
t.fixtureTemplatingEnabled = true
|
||||||
|
t.fixtureTemplateData[opt.k] = opt.v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *fixtureTemplateDataTestOption) applyToFormatterTest(t *FormatterTest) {
|
||||||
|
t.fixtureTemplatingEnabled = true
|
||||||
|
t.fixtureTemplateData[opt.k] = opt.v
|
||||||
|
}
|
||||||
|
|
||||||
// Post-processing
|
// Post-processing
|
||||||
|
|
||||||
// A PostProcessFn is a function that can be applied to the output of a test
|
// A PostProcessFn is a function that can be applied to the output of a test
|
||||||
// fixture before the file is written.
|
// fixture before the file is written.
|
||||||
type PostProcessFn func(*testing.T, []byte) []byte
|
type PostProcessFn func(*testing.T, []byte) []byte
|
||||||
|
|
||||||
// PPRemoveAbsolutePaths removes any absolute paths from the output of the task.
|
|
||||||
// This is useful when the task output contains paths that are can be different
|
|
||||||
// in different environments such as home directories. The function looks for
|
|
||||||
// any paths that contain the current working directory and truncates them.
|
|
||||||
func PPRemoveAbsolutePaths(t *testing.T, b []byte) []byte {
|
|
||||||
t.Helper()
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
require.NoError(t, err)
|
|
||||||
return bytes.ReplaceAll(b, []byte(wd), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PPSortedLines sorts the lines of the output of the task. This is useful when
|
// PPSortedLines sorts the lines of the output of the task. This is useful when
|
||||||
// the order of the output is not important, but the output is expected to be
|
// the order of the output is not important, but the output is expected to be
|
||||||
// the same each time the task is run (e.g. when running tasks in parallel).
|
// the same each time the task is run (e.g. when running tasks in parallel).
|
||||||
@@ -702,6 +749,7 @@ func TestIncludesRemote(t *testing.T) {
|
|||||||
enableExperimentForTest(t, &experiments.RemoteTaskfiles, 1)
|
enableExperimentForTest(t, &experiments.RemoteTaskfiles, 1)
|
||||||
|
|
||||||
dir := "testdata/includes_remote"
|
dir := "testdata/includes_remote"
|
||||||
|
os.RemoveAll(filepath.Join(dir, ".task", "remote"))
|
||||||
|
|
||||||
srv := httptest.NewServer(http.FileServer(http.Dir(dir)))
|
srv := httptest.NewServer(http.FileServer(http.Dir(dir)))
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
@@ -777,8 +825,8 @@ func TestIncludesRemote(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for j, e := range executors {
|
for _, e := range executors {
|
||||||
t.Run(fmt.Sprint(j), func(t *testing.T) {
|
t.Run(e.name, func(t *testing.T) {
|
||||||
require.NoError(t, e.executor.Setup())
|
require.NoError(t, e.executor.Setup())
|
||||||
|
|
||||||
for k, taskCall := range taskCalls {
|
for k, taskCall := range taskCalls {
|
||||||
@@ -933,6 +981,7 @@ func TestIncludesHttp(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range tcs {
|
for _, tc := range tcs {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
task, err := e.CompiledTask(&task.Call{Task: tc.name})
|
task, err := e.CompiledTask(&task.Call{Task: tc.name})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, tc.dir, task.Dir)
|
assert.Equal(t, tc.dir, task.Dir)
|
||||||
@@ -1964,10 +2013,6 @@ task: [included3:task1] echo "VAR_1 is included-default-var1"
|
|||||||
VAR_1 is included-default-var1
|
VAR_1 is included-default-var1
|
||||||
task: [included3:task1] echo "VAR_2 is included-default-var2"
|
task: [included3:task1] echo "VAR_2 is included-default-var2"
|
||||||
VAR_2 is included-default-var2
|
VAR_2 is included-default-var2
|
||||||
task: [included4:task1] echo "VAR_1 is included4-var1"
|
|
||||||
VAR_1 is included4-var1
|
|
||||||
task: [included4:task1] echo "VAR_2 is included-default-var2"
|
|
||||||
VAR_2 is included-default-var2
|
|
||||||
`)
|
`)
|
||||||
require.NoError(t, e.Run(context.Background(), &task.Call{Task: "task1"}))
|
require.NoError(t, e.Run(context.Background(), &task.Call{Task: "task1"}))
|
||||||
t.Log(buff.String())
|
t.Log(buff.String())
|
||||||
@@ -2151,7 +2196,7 @@ func TestUserWorkingDirectory(t *testing.T) {
|
|||||||
|
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
e := task.NewExecutor(
|
e := task.NewExecutor(
|
||||||
task.WithEntrypoint("testdata/user_working_dir/Taskfile.yml"),
|
task.WithDir("testdata/user_working_dir"),
|
||||||
task.WithStdout(&buff),
|
task.WithStdout(&buff),
|
||||||
task.WithStderr(&buff),
|
task.WithStderr(&buff),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type (
|
|||||||
AdvancedImport bool
|
AdvancedImport bool
|
||||||
Vars *Vars
|
Vars *Vars
|
||||||
Flatten bool
|
Flatten bool
|
||||||
|
Checksum string
|
||||||
}
|
}
|
||||||
// Includes is an ordered map of namespaces to includes.
|
// Includes is an ordered map of namespaces to includes.
|
||||||
Includes struct {
|
Includes struct {
|
||||||
@@ -165,6 +166,7 @@ func (include *Include) UnmarshalYAML(node *yaml.Node) error {
|
|||||||
Aliases []string
|
Aliases []string
|
||||||
Excludes []string
|
Excludes []string
|
||||||
Vars *Vars
|
Vars *Vars
|
||||||
|
Checksum string
|
||||||
}
|
}
|
||||||
if err := node.Decode(&includedTaskfile); err != nil {
|
if err := node.Decode(&includedTaskfile); err != nil {
|
||||||
return errors.NewTaskfileDecodeError(err, node)
|
return errors.NewTaskfileDecodeError(err, node)
|
||||||
@@ -178,6 +180,7 @@ func (include *Include) UnmarshalYAML(node *yaml.Node) error {
|
|||||||
include.AdvancedImport = true
|
include.AdvancedImport = true
|
||||||
include.Vars = includedTaskfile.Vars
|
include.Vars = includedTaskfile.Vars
|
||||||
include.Flatten = includedTaskfile.Flatten
|
include.Flatten = includedTaskfile.Flatten
|
||||||
|
include.Checksum = includedTaskfile.Checksum
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,5 +203,7 @@ func (include *Include) DeepCopy() *Include {
|
|||||||
AdvancedImport: include.AdvancedImport,
|
AdvancedImport: include.AdvancedImport,
|
||||||
Vars: include.Vars.DeepCopy(),
|
Vars: include.Vars.DeepCopy(),
|
||||||
Flatten: include.Flatten,
|
Flatten: include.Flatten,
|
||||||
|
Aliases: deepcopy.Slice(include.Aliases),
|
||||||
|
Checksum: include.Checksum,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
giturls "github.com/chainguard-dev/git-urls"
|
giturls "github.com/chainguard-dev/git-urls"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
"github.com/go-task/task/v3/internal/experiments"
|
"github.com/go-task/task/v3/experiments"
|
||||||
"github.com/go-task/task/v3/internal/fsext"
|
"github.com/go-task/task/v3/internal/fsext"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,6 +17,8 @@ type Node interface {
|
|||||||
Parent() Node
|
Parent() Node
|
||||||
Location() string
|
Location() string
|
||||||
Dir() string
|
Dir() string
|
||||||
|
Checksum() string
|
||||||
|
Verify(checksum string) bool
|
||||||
ResolveEntrypoint(entrypoint string) (string, error)
|
ResolveEntrypoint(entrypoint string) (string, error)
|
||||||
ResolveDir(dir string) (string, error)
|
ResolveDir(dir string) (string, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
package taskfile
|
package taskfile
|
||||||
|
|
||||||
type (
|
type (
|
||||||
NodeOption func(*BaseNode)
|
NodeOption func(*baseNode)
|
||||||
// BaseNode is a generic node that implements the Parent() methods of the
|
// baseNode is a generic node that implements the Parent() methods of the
|
||||||
// NodeReader interface. It does not implement the Read() method and it
|
// NodeReader interface. It does not implement the Read() method and it
|
||||||
// designed to be embedded in other node types so that this boilerplate code
|
// designed to be embedded in other node types so that this boilerplate code
|
||||||
// does not need to be repeated.
|
// does not need to be repeated.
|
||||||
BaseNode struct {
|
baseNode struct {
|
||||||
parent Node
|
parent Node
|
||||||
dir string
|
dir string
|
||||||
|
checksum string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewBaseNode(dir string, opts ...NodeOption) *BaseNode {
|
func NewBaseNode(dir string, opts ...NodeOption) *baseNode {
|
||||||
node := &BaseNode{
|
node := &baseNode{
|
||||||
parent: nil,
|
parent: nil,
|
||||||
dir: dir,
|
dir: dir,
|
||||||
}
|
}
|
||||||
@@ -27,15 +28,29 @@ func NewBaseNode(dir string, opts ...NodeOption) *BaseNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WithParent(parent Node) NodeOption {
|
func WithParent(parent Node) NodeOption {
|
||||||
return func(node *BaseNode) {
|
return func(node *baseNode) {
|
||||||
node.parent = parent
|
node.parent = parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *BaseNode) Parent() Node {
|
func WithChecksum(checksum string) NodeOption {
|
||||||
|
return func(node *baseNode) {
|
||||||
|
node.checksum = checksum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *baseNode) Parent() Node {
|
||||||
return node.parent
|
return node.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *BaseNode) Dir() string {
|
func (node *baseNode) Dir() string {
|
||||||
return node.dir
|
return node.dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (node *baseNode) Checksum() string {
|
||||||
|
return node.checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *baseNode) Verify(checksum string) bool {
|
||||||
|
return node.checksum == "" || node.checksum == checksum
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ import (
|
|||||||
const remoteCacheDir = "remote"
|
const remoteCacheDir = "remote"
|
||||||
|
|
||||||
type CacheNode struct {
|
type CacheNode struct {
|
||||||
*BaseNode
|
*baseNode
|
||||||
source RemoteNode
|
source RemoteNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCacheNode(source RemoteNode, dir string) *CacheNode {
|
func NewCacheNode(source RemoteNode, dir string) *CacheNode {
|
||||||
return &CacheNode{
|
return &CacheNode{
|
||||||
BaseNode: &BaseNode{
|
baseNode: &baseNode{
|
||||||
dir: filepath.Join(dir, remoteCacheDir),
|
dir: filepath.Join(dir, remoteCacheDir),
|
||||||
},
|
},
|
||||||
source: source,
|
source: source,
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
|
|
||||||
// A FileNode is a node that reads a taskfile from the local filesystem.
|
// A FileNode is a node that reads a taskfile from the local filesystem.
|
||||||
type FileNode struct {
|
type FileNode struct {
|
||||||
*BaseNode
|
*baseNode
|
||||||
Entrypoint string
|
entrypoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileNode(entrypoint, dir string, opts ...NodeOption) (*FileNode, error) {
|
func NewFileNode(entrypoint, dir string, opts ...NodeOption) (*FileNode, error) {
|
||||||
@@ -25,13 +25,13 @@ func NewFileNode(entrypoint, dir string, opts ...NodeOption) (*FileNode, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &FileNode{
|
return &FileNode{
|
||||||
BaseNode: base,
|
baseNode: base,
|
||||||
Entrypoint: entrypoint,
|
entrypoint: entrypoint,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *FileNode) Location() string {
|
func (node *FileNode) Location() string {
|
||||||
return node.Entrypoint
|
return node.entrypoint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *FileNode) Read() ([]byte, error) {
|
func (node *FileNode) Read() ([]byte, error) {
|
||||||
@@ -63,7 +63,7 @@ func (node *FileNode) ResolveEntrypoint(entrypoint string) (string, error) {
|
|||||||
|
|
||||||
// NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
|
// NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
|
||||||
// This means that files are included relative to one another
|
// This means that files are included relative to one another
|
||||||
entrypointDir := filepath.Dir(node.Entrypoint)
|
entrypointDir := filepath.Dir(node.entrypoint)
|
||||||
return filepathext.SmartJoin(entrypointDir, path), nil
|
return filepathext.SmartJoin(entrypointDir, path), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +79,6 @@ func (node *FileNode) ResolveDir(dir string) (string, error) {
|
|||||||
|
|
||||||
// NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
|
// NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
|
||||||
// This means that files are included relative to one another
|
// This means that files are included relative to one another
|
||||||
entrypointDir := filepath.Dir(node.Entrypoint)
|
entrypointDir := filepath.Dir(node.entrypoint)
|
||||||
return filepathext.SmartJoin(entrypointDir, path), nil
|
return filepathext.SmartJoin(entrypointDir, path), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import (
|
|||||||
|
|
||||||
// An GitNode is a node that reads a Taskfile from a remote location via Git.
|
// An GitNode is a node that reads a Taskfile from a remote location via Git.
|
||||||
type GitNode struct {
|
type GitNode struct {
|
||||||
*BaseNode
|
*baseNode
|
||||||
URL *url.URL
|
url *url.URL
|
||||||
rawUrl string
|
rawUrl string
|
||||||
ref string
|
ref string
|
||||||
path string
|
path string
|
||||||
@@ -40,23 +40,20 @@ func NewGitNode(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
basePath, path := func() (string, string) {
|
basePath, path := splitURLOnDoubleSlash(u)
|
||||||
x := strings.Split(u.Path, "//")
|
|
||||||
return x[0], x[1]
|
|
||||||
}()
|
|
||||||
ref := u.Query().Get("ref")
|
ref := u.Query().Get("ref")
|
||||||
|
|
||||||
rawUrl := u.String()
|
rawUrl := u.Redacted()
|
||||||
|
|
||||||
u.RawQuery = ""
|
u.RawQuery = ""
|
||||||
u.Path = basePath
|
u.Path = basePath
|
||||||
|
|
||||||
if u.Scheme == "http" && !insecure {
|
if u.Scheme == "http" && !insecure {
|
||||||
return nil, &errors.TaskfileNotSecureError{URI: entrypoint}
|
return nil, &errors.TaskfileNotSecureError{URI: u.Redacted()}
|
||||||
}
|
}
|
||||||
return &GitNode{
|
return &GitNode{
|
||||||
BaseNode: base,
|
baseNode: base,
|
||||||
URL: u,
|
url: u,
|
||||||
rawUrl: rawUrl,
|
rawUrl: rawUrl,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
path: path,
|
path: path,
|
||||||
@@ -79,7 +76,7 @@ func (node *GitNode) ReadContext(_ context.Context) ([]byte, error) {
|
|||||||
fs := memfs.New()
|
fs := memfs.New()
|
||||||
storer := memory.NewStorage()
|
storer := memory.NewStorage()
|
||||||
_, err := git.Clone(storer, fs, &git.CloneOptions{
|
_, err := git.Clone(storer, fs, &git.CloneOptions{
|
||||||
URL: node.URL.String(),
|
URL: node.url.String(),
|
||||||
ReferenceName: plumbing.ReferenceName(node.ref),
|
ReferenceName: plumbing.ReferenceName(node.ref),
|
||||||
SingleBranch: true,
|
SingleBranch: true,
|
||||||
Depth: 1,
|
Depth: 1,
|
||||||
@@ -102,7 +99,7 @@ func (node *GitNode) ReadContext(_ context.Context) ([]byte, error) {
|
|||||||
|
|
||||||
func (node *GitNode) ResolveEntrypoint(entrypoint string) (string, error) {
|
func (node *GitNode) ResolveEntrypoint(entrypoint string) (string, error) {
|
||||||
dir, _ := filepath.Split(node.path)
|
dir, _ := filepath.Split(node.path)
|
||||||
resolvedEntrypoint := fmt.Sprintf("%s//%s", node.URL, filepath.Join(dir, entrypoint))
|
resolvedEntrypoint := fmt.Sprintf("%s//%s", node.url, filepath.Join(dir, entrypoint))
|
||||||
if node.ref != "" {
|
if node.ref != "" {
|
||||||
return fmt.Sprintf("%s?ref=%s", resolvedEntrypoint, node.ref), nil
|
return fmt.Sprintf("%s?ref=%s", resolvedEntrypoint, node.ref), nil
|
||||||
}
|
}
|
||||||
@@ -127,11 +124,23 @@ func (node *GitNode) ResolveDir(dir string) (string, error) {
|
|||||||
|
|
||||||
func (node *GitNode) CacheKey() string {
|
func (node *GitNode) CacheKey() string {
|
||||||
checksum := strings.TrimRight(checksum([]byte(node.Location())), "=")
|
checksum := strings.TrimRight(checksum([]byte(node.Location())), "=")
|
||||||
prefix := filepath.Base(filepath.Dir(node.path))
|
lastDir := filepath.Base(filepath.Dir(node.path))
|
||||||
lastDir := filepath.Base(node.path)
|
prefix := filepath.Base(node.path)
|
||||||
// Means it's not "", nor "." nor "/", so it's a valid directory
|
// Means it's not "", nor "." nor "/", so it's a valid directory
|
||||||
if len(lastDir) > 1 {
|
if len(lastDir) > 1 {
|
||||||
prefix = fmt.Sprintf("%s-%s", lastDir, prefix)
|
prefix = fmt.Sprintf("%s.%s", lastDir, prefix)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("git.%s.%s.%s", node.url.Host, prefix, checksum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitURLOnDoubleSlash(u *url.URL) (string, string) {
|
||||||
|
x := strings.Split(u.Path, "//")
|
||||||
|
switch len(x) {
|
||||||
|
case 0:
|
||||||
|
return "", ""
|
||||||
|
case 1:
|
||||||
|
return x[0], ""
|
||||||
|
default:
|
||||||
|
return x[0], x[1]
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s.%s", prefix, checksum)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGitNode_ssh(t *testing.T) {
|
func TestGitNode_ssh(t *testing.T) {
|
||||||
@@ -13,8 +14,8 @@ func TestGitNode_ssh(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "main", node.ref)
|
assert.Equal(t, "main", node.ref)
|
||||||
assert.Equal(t, "Taskfile.yml", node.path)
|
assert.Equal(t, "Taskfile.yml", node.path)
|
||||||
assert.Equal(t, "ssh://git@github.com/foo/bar.git//Taskfile.yml?ref=main", node.rawUrl)
|
assert.Equal(t, "ssh://git@github.com/foo/bar.git//Taskfile.yml?ref=main", node.Location())
|
||||||
assert.Equal(t, "ssh://git@github.com/foo/bar.git", node.URL.String())
|
assert.Equal(t, "ssh://git@github.com/foo/bar.git", node.url.String())
|
||||||
entrypoint, err := node.ResolveEntrypoint("common.yml")
|
entrypoint, err := node.ResolveEntrypoint("common.yml")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "ssh://git@github.com/foo/bar.git//common.yml?ref=main", entrypoint)
|
assert.Equal(t, "ssh://git@github.com/foo/bar.git//common.yml?ref=main", entrypoint)
|
||||||
@@ -27,8 +28,8 @@ func TestGitNode_sshWithDir(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "main", node.ref)
|
assert.Equal(t, "main", node.ref)
|
||||||
assert.Equal(t, "directory/Taskfile.yml", node.path)
|
assert.Equal(t, "directory/Taskfile.yml", node.path)
|
||||||
assert.Equal(t, "ssh://git@github.com/foo/bar.git//directory/Taskfile.yml?ref=main", node.rawUrl)
|
assert.Equal(t, "ssh://git@github.com/foo/bar.git//directory/Taskfile.yml?ref=main", node.Location())
|
||||||
assert.Equal(t, "ssh://git@github.com/foo/bar.git", node.URL.String())
|
assert.Equal(t, "ssh://git@github.com/foo/bar.git", node.url.String())
|
||||||
entrypoint, err := node.ResolveEntrypoint("common.yml")
|
entrypoint, err := node.ResolveEntrypoint("common.yml")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "ssh://git@github.com/foo/bar.git//directory/common.yml?ref=main", entrypoint)
|
assert.Equal(t, "ssh://git@github.com/foo/bar.git//directory/common.yml?ref=main", entrypoint)
|
||||||
@@ -41,8 +42,8 @@ func TestGitNode_https(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "main", node.ref)
|
assert.Equal(t, "main", node.ref)
|
||||||
assert.Equal(t, "Taskfile.yml", node.path)
|
assert.Equal(t, "Taskfile.yml", node.path)
|
||||||
assert.Equal(t, "https://github.com/foo/bar.git//Taskfile.yml?ref=main", node.rawUrl)
|
assert.Equal(t, "https://github.com/foo/bar.git//Taskfile.yml?ref=main", node.Location())
|
||||||
assert.Equal(t, "https://github.com/foo/bar.git", node.URL.String())
|
assert.Equal(t, "https://github.com/foo/bar.git", node.url.String())
|
||||||
entrypoint, err := node.ResolveEntrypoint("common.yml")
|
entrypoint, err := node.ResolveEntrypoint("common.yml")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "https://github.com/foo/bar.git//common.yml?ref=main", entrypoint)
|
assert.Equal(t, "https://github.com/foo/bar.git//common.yml?ref=main", entrypoint)
|
||||||
@@ -55,8 +56,8 @@ func TestGitNode_httpsWithDir(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "main", node.ref)
|
assert.Equal(t, "main", node.ref)
|
||||||
assert.Equal(t, "directory/Taskfile.yml", node.path)
|
assert.Equal(t, "directory/Taskfile.yml", node.path)
|
||||||
assert.Equal(t, "https://github.com/foo/bar.git//directory/Taskfile.yml?ref=main", node.rawUrl)
|
assert.Equal(t, "https://github.com/foo/bar.git//directory/Taskfile.yml?ref=main", node.Location())
|
||||||
assert.Equal(t, "https://github.com/foo/bar.git", node.URL.String())
|
assert.Equal(t, "https://github.com/foo/bar.git", node.url.String())
|
||||||
entrypoint, err := node.ResolveEntrypoint("common.yml")
|
entrypoint, err := node.ResolveEntrypoint("common.yml")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "https://github.com/foo/bar.git//directory/common.yml?ref=main", entrypoint)
|
assert.Equal(t, "https://github.com/foo/bar.git//directory/common.yml?ref=main", entrypoint)
|
||||||
@@ -65,18 +66,28 @@ func TestGitNode_httpsWithDir(t *testing.T) {
|
|||||||
func TestGitNode_CacheKey(t *testing.T) {
|
func TestGitNode_CacheKey(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
node, err := NewGitNode("https://github.com/foo/bar.git//directory/Taskfile.yml?ref=main", "", false)
|
tests := []struct {
|
||||||
assert.NoError(t, err)
|
entrypoint string
|
||||||
key := node.CacheKey()
|
expectedKey string
|
||||||
assert.Equal(t, "Taskfile.yml-directory.f1ddddac425a538870230a3e38fc0cded4ec5da250797b6cab62c82477718fbb", key)
|
}{
|
||||||
|
{
|
||||||
|
entrypoint: "https://github.com/foo/bar.git//directory/Taskfile.yml?ref=main",
|
||||||
|
expectedKey: "git.github.com.directory.Taskfile.yml.f1ddddac425a538870230a3e38fc0cded4ec5da250797b6cab62c82477718fbb",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entrypoint: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
|
||||||
|
expectedKey: "git.github.com.Taskfile.yml.39d28c1ff36f973705ae188b991258bbabaffd6d60bcdde9693d157d00d5e3a4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entrypoint: "https://github.com/foo/bar.git//multiple/directory/Taskfile.yml?ref=main",
|
||||||
|
expectedKey: "git.github.com.directory.Taskfile.yml.1b6d145e01406dcc6c0aa572e5a5d1333be1ccf2cae96d18296d725d86197d31",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
node, err = NewGitNode("https://github.com/foo/bar.git//Taskfile.yml?ref=main", "", false)
|
for _, tt := range tests {
|
||||||
assert.NoError(t, err)
|
node, err := NewGitNode(tt.entrypoint, "", false)
|
||||||
key = node.CacheKey()
|
require.NoError(t, err)
|
||||||
assert.Equal(t, "Taskfile.yml-..39d28c1ff36f973705ae188b991258bbabaffd6d60bcdde9693d157d00d5e3a4", key)
|
key := node.CacheKey()
|
||||||
|
assert.Equal(t, tt.expectedKey, key)
|
||||||
node, err = NewGitNode("https://github.com/foo/bar.git//multiple/directory/Taskfile.yml?ref=main", "", false)
|
}
|
||||||
assert.NoError(t, err)
|
|
||||||
key = node.CacheKey()
|
|
||||||
assert.Equal(t, "Taskfile.yml-directory.1b6d145e01406dcc6c0aa572e5a5d1333be1ccf2cae96d18296d725d86197d31", key)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ import (
|
|||||||
|
|
||||||
// An HTTPNode is a node that reads a Taskfile from a remote location via HTTP.
|
// An HTTPNode is a node that reads a Taskfile from a remote location via HTTP.
|
||||||
type HTTPNode struct {
|
type HTTPNode struct {
|
||||||
*BaseNode
|
*baseNode
|
||||||
URL *url.URL // stores url pointing actual remote file. (e.g. with Taskfile.yml)
|
url *url.URL // stores url pointing actual remote file. (e.g. with Taskfile.yml)
|
||||||
entrypoint string // stores entrypoint url. used for building graph vertices.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPNode(
|
func NewHTTPNode(
|
||||||
@@ -33,18 +32,16 @@ func NewHTTPNode(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if url.Scheme == "http" && !insecure {
|
if url.Scheme == "http" && !insecure {
|
||||||
return nil, &errors.TaskfileNotSecureError{URI: entrypoint}
|
return nil, &errors.TaskfileNotSecureError{URI: url.Redacted()}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &HTTPNode{
|
return &HTTPNode{
|
||||||
BaseNode: base,
|
baseNode: base,
|
||||||
URL: url,
|
url: url,
|
||||||
entrypoint: entrypoint,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *HTTPNode) Location() string {
|
func (node *HTTPNode) Location() string {
|
||||||
return node.entrypoint
|
return node.url.Redacted()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *HTTPNode) Read() ([]byte, error) {
|
func (node *HTTPNode) Read() ([]byte, error) {
|
||||||
@@ -52,14 +49,13 @@ func (node *HTTPNode) Read() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (node *HTTPNode) ReadContext(ctx context.Context) ([]byte, error) {
|
func (node *HTTPNode) ReadContext(ctx context.Context) ([]byte, error) {
|
||||||
url, err := RemoteExists(ctx, node.URL)
|
url, err := RemoteExists(ctx, *node.url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
node.URL = url
|
req, err := http.NewRequest("GET", url.String(), nil)
|
||||||
req, err := http.NewRequest("GET", node.URL.String(), nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.TaskfileFetchFailedError{URI: node.URL.String()}
|
return nil, errors.TaskfileFetchFailedError{URI: node.Location()}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
|
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
|
||||||
@@ -67,12 +63,12 @@ func (node *HTTPNode) ReadContext(ctx context.Context) ([]byte, error) {
|
|||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, errors.TaskfileFetchFailedError{URI: node.URL.String()}
|
return nil, errors.TaskfileFetchFailedError{URI: node.Location()}
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return nil, errors.TaskfileFetchFailedError{
|
return nil, errors.TaskfileFetchFailedError{
|
||||||
URI: node.URL.String(),
|
URI: node.Location(),
|
||||||
HTTPStatusCode: resp.StatusCode,
|
HTTPStatusCode: resp.StatusCode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,7 +87,7 @@ func (node *HTTPNode) ResolveEntrypoint(entrypoint string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return node.URL.ResolveReference(ref).String(), nil
|
return node.url.ResolveReference(ref).String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *HTTPNode) ResolveDir(dir string) (string, error) {
|
func (node *HTTPNode) ResolveDir(dir string) (string, error) {
|
||||||
@@ -116,12 +112,12 @@ func (node *HTTPNode) ResolveDir(dir string) (string, error) {
|
|||||||
|
|
||||||
func (node *HTTPNode) CacheKey() string {
|
func (node *HTTPNode) CacheKey() string {
|
||||||
checksum := strings.TrimRight(checksum([]byte(node.Location())), "=")
|
checksum := strings.TrimRight(checksum([]byte(node.Location())), "=")
|
||||||
dir, filename := filepath.Split(node.entrypoint)
|
dir, filename := filepath.Split(node.url.Path)
|
||||||
lastDir := filepath.Base(dir)
|
lastDir := filepath.Base(dir)
|
||||||
prefix := filename
|
prefix := filename
|
||||||
// Means it's not "", nor "." nor "/", so it's a valid directory
|
// Means it's not "", nor "." nor "/", so it's a valid directory
|
||||||
if len(lastDir) > 1 {
|
if len(lastDir) > 1 {
|
||||||
prefix = fmt.Sprintf("%s-%s", lastDir, filename)
|
prefix = fmt.Sprintf("%s.%s", lastDir, filename)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s.%s", prefix, checksum)
|
return fmt.Sprintf("http.%s.%s.%s", node.url.Host, prefix, checksum)
|
||||||
}
|
}
|
||||||
|
|||||||
49
taskfile/node_http_test.go
Normal file
49
taskfile/node_http_test.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package taskfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHTTPNode_CacheKey(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
entrypoint string
|
||||||
|
expectedKey string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
entrypoint: "https://github.com",
|
||||||
|
expectedKey: "http.github.com..996e1f714b08e971ec79e3bea686287e66441f043177999a13dbc546d8fe402a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entrypoint: "https://github.com/Taskfile.yml",
|
||||||
|
expectedKey: "http.github.com.Taskfile.yml.85b3c3ad71b78dc74e404c7b4390fc13672925cb644a4d26c21b9f97c17b5fc0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entrypoint: "https://github.com/foo",
|
||||||
|
expectedKey: "http.github.com.foo.df3158dafc823e6847d9bcaf79328446c4877405e79b100723fa6fd545ed3e2b",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entrypoint: "https://github.com/foo/Taskfile.yml",
|
||||||
|
expectedKey: "http.github.com.foo.Taskfile.yml.aea946ea7eb6f6bb4e159e8b840b6b50975927778b2e666df988c03bbf10c4c4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entrypoint: "https://github.com/foo/bar",
|
||||||
|
expectedKey: "http.github.com.foo.bar.d3514ad1d4daedf9cc2825225070b49ebc8db47fa5177951b2a5b9994597570c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entrypoint: "https://github.com/foo/bar/Taskfile.yml",
|
||||||
|
expectedKey: "http.github.com.bar.Taskfile.yml.b9cf01e01e47c0e96ea536e1a8bd7b3a6f6c1f1881bad438990d2bfd4ccd0ac0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
node, err := NewHTTPNode(tt.entrypoint, "", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
key := node.CacheKey()
|
||||||
|
assert.Equal(t, tt.expectedKey, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,12 +12,12 @@ import (
|
|||||||
|
|
||||||
// A StdinNode is a node that reads a taskfile from the standard input stream.
|
// A StdinNode is a node that reads a taskfile from the standard input stream.
|
||||||
type StdinNode struct {
|
type StdinNode struct {
|
||||||
*BaseNode
|
*baseNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStdinNode(dir string) (*StdinNode, error) {
|
func NewStdinNode(dir string) (*StdinNode, error) {
|
||||||
return &StdinNode{
|
return &StdinNode{
|
||||||
BaseNode: NewBaseNode(dir),
|
baseNode: NewBaseNode(dir),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -249,7 +249,8 @@ func (r *Reader) include(ctx context.Context, node Node) error {
|
|||||||
Aliases: include.Aliases,
|
Aliases: include.Aliases,
|
||||||
AdvancedImport: include.AdvancedImport,
|
AdvancedImport: include.AdvancedImport,
|
||||||
Excludes: include.Excludes,
|
Excludes: include.Excludes,
|
||||||
Vars: templater.ReplaceVars(include.Vars, cache),
|
Vars: include.Vars,
|
||||||
|
Checksum: include.Checksum,
|
||||||
}
|
}
|
||||||
if err := cache.Err(); err != nil {
|
if err := cache.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -267,6 +268,7 @@ func (r *Reader) include(ctx context.Context, node Node) error {
|
|||||||
|
|
||||||
includeNode, err := NewNode(entrypoint, include.Dir, r.insecure,
|
includeNode, err := NewNode(entrypoint, include.Dir, r.insecure,
|
||||||
WithParent(node),
|
WithParent(node),
|
||||||
|
WithChecksum(include.Checksum),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if include.Optional {
|
if include.Optional {
|
||||||
@@ -362,7 +364,24 @@ func (r *Reader) readNodeContent(ctx context.Context, node Node) ([]byte, error)
|
|||||||
if node, isRemote := node.(RemoteNode); isRemote {
|
if node, isRemote := node.(RemoteNode); isRemote {
|
||||||
return r.readRemoteNodeContent(ctx, node)
|
return r.readRemoteNodeContent(ctx, node)
|
||||||
}
|
}
|
||||||
return node.Read()
|
|
||||||
|
// Read the Taskfile
|
||||||
|
b, err := node.Read()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the given checksum doesn't match the sum pinned in the Taskfile
|
||||||
|
checksum := checksum(b)
|
||||||
|
if !node.Verify(checksum) {
|
||||||
|
return nil, &errors.TaskfileDoesNotMatchChecksum{
|
||||||
|
URI: node.Location(),
|
||||||
|
ExpectedChecksum: node.Checksum(),
|
||||||
|
ActualChecksum: checksum,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) readRemoteNodeContent(ctx context.Context, node RemoteNode) ([]byte, error) {
|
func (r *Reader) readRemoteNodeContent(ctx context.Context, node RemoteNode) ([]byte, error) {
|
||||||
@@ -427,17 +446,29 @@ func (r *Reader) readRemoteNodeContent(ctx context.Context, node RemoteNode) ([]
|
|||||||
}
|
}
|
||||||
|
|
||||||
r.debugf("found remote file at %q\n", node.Location())
|
r.debugf("found remote file at %q\n", node.Location())
|
||||||
checksum := checksum(downloadedBytes)
|
|
||||||
prompt := cache.ChecksumPrompt(checksum)
|
|
||||||
|
|
||||||
// Prompt the user if required
|
// If the given checksum doesn't match the sum pinned in the Taskfile
|
||||||
if prompt != "" {
|
checksum := checksum(downloadedBytes)
|
||||||
if err := func() error {
|
if !node.Verify(checksum) {
|
||||||
r.promptMutex.Lock()
|
return nil, &errors.TaskfileDoesNotMatchChecksum{
|
||||||
defer r.promptMutex.Unlock()
|
URI: node.Location(),
|
||||||
return r.promptf(prompt, node.Location())
|
ExpectedChecksum: node.Checksum(),
|
||||||
}(); err != nil {
|
ActualChecksum: checksum,
|
||||||
return nil, &errors.TaskfileNotTrustedError{URI: node.Location()}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no manual checksum pin, run the automatic checks
|
||||||
|
if node.Checksum() == "" {
|
||||||
|
// Prompt the user if required
|
||||||
|
prompt := cache.ChecksumPrompt(checksum)
|
||||||
|
if prompt != "" {
|
||||||
|
if err := func() error {
|
||||||
|
r.promptMutex.Lock()
|
||||||
|
defer r.promptMutex.Unlock()
|
||||||
|
return r.promptf(prompt, node.Location())
|
||||||
|
}(); err != nil {
|
||||||
|
return nil, &errors.TaskfileNotTrustedError{URI: node.Location()}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ var (
|
|||||||
// at the given URL with any of the default Taskfile files names. If any of
|
// at the given URL with any of the default Taskfile files names. If any of
|
||||||
// these match a file, the first matching path will be returned. If no files are
|
// these match a file, the first matching path will be returned. If no files are
|
||||||
// found, an error will be returned.
|
// found, an error will be returned.
|
||||||
func RemoteExists(ctx context.Context, u *url.URL) (*url.URL, error) {
|
func RemoteExists(ctx context.Context, u url.URL) (*url.URL, error) {
|
||||||
// Create a new HEAD request for the given URL to check if the resource exists
|
// Create a new HEAD request for the given URL to check if the resource exists
|
||||||
req, err := http.NewRequestWithContext(ctx, "HEAD", u.String(), nil)
|
req, err := http.NewRequestWithContext(ctx, "HEAD", u.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.TaskfileFetchFailedError{URI: u.String()}
|
return nil, errors.TaskfileFetchFailedError{URI: u.Redacted()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request the given URL
|
// Request the given URL
|
||||||
@@ -49,7 +49,7 @@ func RemoteExists(ctx context.Context, u *url.URL) (*url.URL, error) {
|
|||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return nil, fmt.Errorf("checking remote file: %w", ctx.Err())
|
return nil, fmt.Errorf("checking remote file: %w", ctx.Err())
|
||||||
}
|
}
|
||||||
return nil, errors.TaskfileFetchFailedError{URI: u.String()}
|
return nil, errors.TaskfileFetchFailedError{URI: u.Redacted()}
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ func RemoteExists(ctx context.Context, u *url.URL) (*url.URL, error) {
|
|||||||
if resp.StatusCode == http.StatusOK && slices.ContainsFunc(allowedContentTypes, func(s string) bool {
|
if resp.StatusCode == http.StatusOK && slices.ContainsFunc(allowedContentTypes, func(s string) bool {
|
||||||
return strings.Contains(contentType, s)
|
return strings.Contains(contentType, s)
|
||||||
}) {
|
}) {
|
||||||
return u, nil
|
return &u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the request was not successful, append the default Taskfile names to
|
// If the request was not successful, append the default Taskfile names to
|
||||||
@@ -78,7 +78,7 @@ func RemoteExists(ctx context.Context, u *url.URL) (*url.URL, error) {
|
|||||||
// Try the alternative URL
|
// Try the alternative URL
|
||||||
resp, err = http.DefaultClient.Do(req)
|
resp, err = http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.TaskfileFetchFailedError{URI: u.String()}
|
return nil, errors.TaskfileFetchFailedError{URI: u.Redacted()}
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
@@ -88,5 +88,5 @@ func RemoteExists(ctx context.Context, u *url.URL) (*url.URL, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.TaskfileNotFoundError{URI: u.String(), Walk: false}
|
return nil, errors.TaskfileNotFoundError{URI: u.Redacted(), Walk: false}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
task: Missing schema version in Taskfile "/testdata/empty_taskfile/Taskfile.yml"
|
task: Missing schema version in Taskfile "{{.TEST_DIR}}/testdata/empty_taskfile/Taskfile.yml"
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
task: Failed to parse /testdata/for/cmds/Taskfile.yml:
|
task: Failed to parse {{.TEST_DIR}}/testdata/for/cmds/Taskfile.yml:
|
||||||
matrix reference ".NOT_A_LIST" must resolve to a list
|
matrix reference ".NOT_A_LIST" must resolve to a list
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
matrix reference ".NOT_A_LIST" must resolve to a list
|
matrix reference ".NOT_A_LIST" must resolve to a list
|
||||||
task: Failed to parse /testdata/for/deps/Taskfile.yml:
|
task: Failed to parse {{.TEST_DIR}}/testdata/for/deps/Taskfile.yml:
|
||||||
|
|||||||
9
testdata/fuzzy/Taskfile.yml
vendored
Normal file
9
testdata/fuzzy/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
version: 3
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
install: echo 'install'
|
||||||
|
|
||||||
|
internal:
|
||||||
|
internal: true
|
||||||
|
cmds:
|
||||||
|
- echo "internal"
|
||||||
1
testdata/fuzzy/testdata/TestFuzzyModel-fuzzy-err-run.golden
vendored
Normal file
1
testdata/fuzzy/testdata/TestFuzzyModel-fuzzy-err-run.golden
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
task: Task "instal" does not exist. Did you mean "install"?
|
||||||
1
testdata/fuzzy/testdata/TestFuzzyModel-fuzzy.golden
vendored
Normal file
1
testdata/fuzzy/testdata/TestFuzzyModel-fuzzy.golden
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
task: No tasks with description available. Try --list-all to list all tasks
|
||||||
1
testdata/fuzzy/testdata/TestFuzzyModel-intern-err-run.golden
vendored
Normal file
1
testdata/fuzzy/testdata/TestFuzzyModel-intern-err-run.golden
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
task: Task "intern" does not exist
|
||||||
1
testdata/fuzzy/testdata/TestFuzzyModel-intern.golden
vendored
Normal file
1
testdata/fuzzy/testdata/TestFuzzyModel-intern.golden
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
task: No tasks with description available. Try --list-all to list all tasks
|
||||||
2
testdata/fuzzy/testdata/TestFuzzyModel-not-fuzzy.golden
vendored
Normal file
2
testdata/fuzzy/testdata/TestFuzzyModel-not-fuzzy.golden
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
task: [install] echo 'install'
|
||||||
|
install
|
||||||
14
testdata/include_with_vars/Taskfile.yml
vendored
14
testdata/include_with_vars/Taskfile.yml
vendored
@@ -1,23 +1,16 @@
|
|||||||
version: "3"
|
version: "3"
|
||||||
|
|
||||||
vars:
|
|
||||||
VAR_1: included4-var1
|
|
||||||
|
|
||||||
includes:
|
includes:
|
||||||
included1:
|
included1:
|
||||||
taskfile: include/Taskfile.include.yml
|
taskfile: include/Taskfile.include1.yml
|
||||||
vars:
|
vars:
|
||||||
VAR_1: included1-var1
|
VAR_1: included1-var1
|
||||||
included2:
|
included2:
|
||||||
taskfile: include/Taskfile.include.yml
|
taskfile: include/Taskfile.include2.yml
|
||||||
vars:
|
vars:
|
||||||
VAR_1: included2-var1
|
VAR_1: included2-var1
|
||||||
included3:
|
included3:
|
||||||
taskfile: include/Taskfile.include.yml
|
taskfile: include/Taskfile.include3.yml
|
||||||
included4:
|
|
||||||
taskfile: include/Taskfile.include.yml
|
|
||||||
vars:
|
|
||||||
VAR_1: "{{.VAR_1}}"
|
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
task1:
|
task1:
|
||||||
@@ -25,4 +18,3 @@ tasks:
|
|||||||
- task: included1:task1
|
- task: included1:task1
|
||||||
- task: included2:task1
|
- task: included2:task1
|
||||||
- task: included3:task1
|
- task: included3:task1
|
||||||
- task: included4:task1
|
|
||||||
|
|||||||
11
testdata/include_with_vars/include/Taskfile.include2.yml
vendored
Normal file
11
testdata/include_with_vars/include/Taskfile.include2.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
vars:
|
||||||
|
VAR_1: '{{.VAR_1 | default "included-default-var1"}}'
|
||||||
|
VAR_2: '{{.VAR_2 | default "included-default-var2"}}'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
task1:
|
||||||
|
cmds:
|
||||||
|
- echo "VAR_1 is {{.VAR_1}}"
|
||||||
|
- echo "VAR_2 is {{.VAR_2}}"
|
||||||
11
testdata/include_with_vars/include/Taskfile.include3.yml
vendored
Normal file
11
testdata/include_with_vars/include/Taskfile.include3.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
vars:
|
||||||
|
VAR_1: '{{.VAR_1 | default "included-default-var1"}}'
|
||||||
|
VAR_2: '{{.VAR_2 | default "included-default-var2"}}'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
task1:
|
||||||
|
cmds:
|
||||||
|
- echo "VAR_1 is {{.VAR_1}}"
|
||||||
|
- echo "VAR_2 is {{.VAR_2}}"
|
||||||
12
testdata/includes_checksum/correct/Taskfile.yml
vendored
Normal file
12
testdata/includes_checksum/correct/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
included:
|
||||||
|
taskfile: ../included.yml
|
||||||
|
internal: true
|
||||||
|
checksum: c97f39eb96fe3fa5fe2a610d244b8449897b06f0c93821484af02e0999781bf5
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
cmds:
|
||||||
|
- task: included:default
|
||||||
2
testdata/includes_checksum/correct/testdata/TestIncludeChecksum-correct.golden
vendored
Normal file
2
testdata/includes_checksum/correct/testdata/TestIncludeChecksum-correct.golden
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
task: [included:default] echo "Hello, World!"
|
||||||
|
Hello, World!
|
||||||
12
testdata/includes_checksum/correct_remote/Taskfile.yml
vendored
Normal file
12
testdata/includes_checksum/correct_remote/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
included:
|
||||||
|
taskfile: https://taskfile.dev
|
||||||
|
internal: true
|
||||||
|
checksum: c153e97e0b3a998a7ed2e61064c6ddaddd0de0c525feefd6bba8569827d8efe9
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
cmds:
|
||||||
|
- task: included:default
|
||||||
6
testdata/includes_checksum/included.yml
vendored
Normal file
6
testdata/includes_checksum/included.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
cmds:
|
||||||
|
- echo "Hello, World!"
|
||||||
12
testdata/includes_checksum/incorrect/Taskfile.yml
vendored
Normal file
12
testdata/includes_checksum/incorrect/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
included:
|
||||||
|
taskfile: ../included.yml
|
||||||
|
internal: true
|
||||||
|
checksum: foo
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
cmds:
|
||||||
|
- task: included:default
|
||||||
3
testdata/includes_checksum/incorrect/testdata/TestIncludeChecksum-incorrect-err-setup.golden
vendored
Normal file
3
testdata/includes_checksum/incorrect/testdata/TestIncludeChecksum-incorrect-err-setup.golden
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
task: The checksum of the Taskfile at "{{.TEST_DIR}}/testdata/includes_checksum/included.yml" does not match!
|
||||||
|
got: "c97f39eb96fe3fa5fe2a610d244b8449897b06f0c93821484af02e0999781bf5"
|
||||||
|
want: "foo"
|
||||||
0
testdata/includes_checksum/incorrect/testdata/TestIncludeChecksum-incorrect.golden
vendored
Normal file
0
testdata/includes_checksum/incorrect/testdata/TestIncludeChecksum-incorrect.golden
vendored
Normal file
6
testdata/json_list_format/Taskfile.yml
vendored
Normal file
6
testdata/json_list_format/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
foo:
|
||||||
|
label: "foobar"
|
||||||
|
desc: "task description"
|
||||||
18
testdata/json_list_format/testdata/TestJsonListFormat.golden
vendored
Normal file
18
testdata/json_list_format/testdata/TestJsonListFormat.golden
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"name": "foobar",
|
||||||
|
"task": "foo",
|
||||||
|
"desc": "task description",
|
||||||
|
"summary": "",
|
||||||
|
"aliases": [],
|
||||||
|
"up_to_date": false,
|
||||||
|
"location": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 3,
|
||||||
|
"taskfile": "{{.TEST_DIR}}/testdata/json_list_format/Taskfile.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"location": "{{.TEST_DIR}}/testdata/json_list_format/Taskfile.yml"
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars
|
{{.TEST_DIR}}/testdata/special_vars
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars/included
|
{{.TEST_DIR}}/testdata/special_vars/included
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars/included/Taskfile.yml
|
{{.TEST_DIR}}/testdata/special_vars/included/Taskfile.yml
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars
|
{{.TEST_DIR}}/testdata/special_vars
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars/foo
|
{{.TEST_DIR}}/testdata/special_vars/foo
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars
|
{{.TEST_DIR}}/testdata/special_vars
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars/Taskfile.yml
|
{{.TEST_DIR}}/testdata/special_vars/Taskfile.yml
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars
|
{{.TEST_DIR}}/testdata/special_vars
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars/included
|
{{.TEST_DIR}}/testdata/special_vars/included
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars/included/Taskfile.yml
|
{{.TEST_DIR}}/testdata/special_vars/included/Taskfile.yml
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars
|
{{.TEST_DIR}}/testdata/special_vars
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars/foo
|
{{.TEST_DIR}}/testdata/special_vars/foo
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars
|
{{.TEST_DIR}}/testdata/special_vars
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/testdata/special_vars/Taskfile.yml
|
{{.TEST_DIR}}/testdata/special_vars/Taskfile.yml
|
||||||
|
|||||||
176
testdata/vars/any/Taskfile.yml
vendored
176
testdata/vars/any/Taskfile.yml
vendored
@@ -2,107 +2,113 @@ version: '3'
|
|||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
default:
|
default:
|
||||||
- task: dynamic
|
|
||||||
- task: string
|
|
||||||
- task: bool
|
|
||||||
- task: int
|
|
||||||
- task: string-array
|
|
||||||
- task: map
|
- task: map
|
||||||
- task: for-string
|
- task: nested-map
|
||||||
- task: for-int
|
- task: slice
|
||||||
- task: for-map
|
- task: ref
|
||||||
- task: for-multi-layer-map
|
- task: ref-sh
|
||||||
|
- task: ref-dep
|
||||||
dynamic:
|
- task: ref-resolver
|
||||||
vars:
|
- task: json
|
||||||
STRING_A: '$echo "A"'
|
|
||||||
STRING_B: '$echo {{.STRING_A}}B'
|
|
||||||
STRING_C: '$echo {{.STRING_B}}C'
|
|
||||||
cmds:
|
|
||||||
- echo '{{.STRING_C}}'
|
|
||||||
|
|
||||||
string:
|
|
||||||
vars:
|
|
||||||
STRING_A: 'A'
|
|
||||||
STRING_B: '{{.STRING_A}}B'
|
|
||||||
STRING_C: '{{.STRING_B}}C'
|
|
||||||
cmds:
|
|
||||||
- echo '{{.STRING_C}}'
|
|
||||||
|
|
||||||
bool:
|
|
||||||
vars:
|
|
||||||
BOOL_TRUE: true
|
|
||||||
BOOL_FALSE: false
|
|
||||||
BOOL_A: '{{and .BOOL_TRUE .BOOL_FALSE}}'
|
|
||||||
BOOL_B: '{{or .BOOL_TRUE .BOOL_FALSE}}'
|
|
||||||
BOOL_C: '{{not .BOOL_TRUE}}'
|
|
||||||
cmds:
|
|
||||||
- echo '{{if .BOOL_TRUE}}A:{{.BOOL_A}} B:{{.BOOL_B}} C:{{.BOOL_C}}{{end}}'
|
|
||||||
|
|
||||||
int:
|
|
||||||
vars:
|
|
||||||
INT_100: 100
|
|
||||||
INT_10: 10
|
|
||||||
cmds:
|
|
||||||
- echo '100 + 10 = {{add .INT_100 .INT_10}}'
|
|
||||||
- echo '100 - 10 = {{sub .INT_100 .INT_10}}'
|
|
||||||
- echo '100 * 10 = {{mul .INT_100 .INT_10}}'
|
|
||||||
- echo '100 / 10 = {{div .INT_100 .INT_10}}'
|
|
||||||
|
|
||||||
string-array:
|
|
||||||
vars:
|
|
||||||
ARRAY_1: ['A', 'B', 'C']
|
|
||||||
ARRAY_2: ['D', 'E', 'F']
|
|
||||||
cmds:
|
|
||||||
- echo '{{append .ARRAY_1 "D"}}'
|
|
||||||
- echo '{{concat .ARRAY_1 .ARRAY_2}}'
|
|
||||||
- echo '{{join " " .ARRAY_1}}'
|
|
||||||
|
|
||||||
map:
|
map:
|
||||||
vars:
|
vars:
|
||||||
MAP_1: {A: 1, B: 2, C: 3}
|
MAP:
|
||||||
MAP_2: {B: 4, C: 5, D: 6}
|
map: {"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}
|
||||||
MAP_3: {C: 7, D: 8, E: 9}
|
|
||||||
cmds:
|
cmds:
|
||||||
- echo '{{merge .MAP_1 .MAP_2 .MAP_3}}'
|
- task: print-story
|
||||||
|
vars:
|
||||||
|
VAR:
|
||||||
|
ref: .MAP
|
||||||
|
|
||||||
for-string:
|
nested-map:
|
||||||
vars:
|
vars:
|
||||||
LIST: [foo, bar, baz]
|
FOO: "foo"
|
||||||
|
nested:
|
||||||
|
map:
|
||||||
|
variables:
|
||||||
|
work: "{{.FOO}}"
|
||||||
cmds:
|
cmds:
|
||||||
- for:
|
- echo {{.nested.variables.work}}
|
||||||
var: LIST
|
|
||||||
cmd: echo {{.ITEM}}
|
|
||||||
|
|
||||||
for-int:
|
slice:
|
||||||
vars:
|
vars:
|
||||||
LIST: [1, 2, 3]
|
FOO: "foo"
|
||||||
|
BAR: "bar"
|
||||||
|
slice_variables_work: ["{{.FOO}}","{{.BAR}}"]
|
||||||
cmds:
|
cmds:
|
||||||
- for:
|
- echo {{index .slice_variables_work 0}} {{index .slice_variables_work 1}}
|
||||||
var: LIST
|
|
||||||
cmd: echo {{add .ITEM 100}}
|
|
||||||
|
|
||||||
for-map:
|
ref:
|
||||||
vars:
|
vars:
|
||||||
MAP:
|
MAP:
|
||||||
KEY_1: value_1
|
map: {"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}
|
||||||
KEY_2: value_2
|
MAP_REF:
|
||||||
KEY_3: value_3
|
ref: .MAP
|
||||||
cmds:
|
cmds:
|
||||||
- for:
|
- task: print-story
|
||||||
var: MAP
|
vars:
|
||||||
cmd: echo {{.KEY}} {{.ITEM}}
|
VAR:
|
||||||
|
ref: .MAP_REF
|
||||||
|
|
||||||
for-multi-layer-map:
|
ref-sh:
|
||||||
|
vars:
|
||||||
|
JSON_STRING:
|
||||||
|
sh: echo '{"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}'
|
||||||
|
JSON: "fromJson {{.JSON_STRING}}"
|
||||||
|
MAP_REF:
|
||||||
|
ref: .JSON
|
||||||
|
cmds:
|
||||||
|
- task: print-story
|
||||||
|
vars:
|
||||||
|
VAR:
|
||||||
|
ref: .MAP_REF
|
||||||
|
|
||||||
|
ref-dep:
|
||||||
vars:
|
vars:
|
||||||
MAP:
|
MAP:
|
||||||
KEY_1:
|
map: {"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}
|
||||||
SUBKEY: sub_value_1
|
deps:
|
||||||
KEY_2:
|
- task: print-story
|
||||||
SUBKEY: sub_value_2
|
vars:
|
||||||
KEY_3:
|
VAR:
|
||||||
SUBKEY: sub_value_3
|
ref: .MAP
|
||||||
|
|
||||||
|
ref-resolver:
|
||||||
|
vars:
|
||||||
|
MAP:
|
||||||
|
map: {"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}
|
||||||
|
MAP_REF:
|
||||||
|
ref: .MAP
|
||||||
cmds:
|
cmds:
|
||||||
- for:
|
- task: print-var
|
||||||
var: MAP
|
vars:
|
||||||
cmd: echo {{.KEY}} {{.ITEM.SUBKEY}}
|
VAR:
|
||||||
|
ref: (index .MAP_REF.children 0).name
|
||||||
|
|
||||||
|
json:
|
||||||
|
vars:
|
||||||
|
JSON_STRING:
|
||||||
|
sh: cat example.json
|
||||||
|
JSON:
|
||||||
|
ref: "fromJson .JSON_STRING"
|
||||||
|
cmds:
|
||||||
|
- task: print-story
|
||||||
|
vars:
|
||||||
|
VAR:
|
||||||
|
ref: .JSON
|
||||||
|
|
||||||
|
print-var:
|
||||||
|
cmds:
|
||||||
|
- echo "{{.VAR}}"
|
||||||
|
|
||||||
|
print-story:
|
||||||
|
cmds:
|
||||||
|
- >-
|
||||||
|
echo "{{.VAR.name}} has {{len .VAR.children}} children called
|
||||||
|
{{- $children := .VAR.children -}}
|
||||||
|
{{- range $i, $child := $children -}}
|
||||||
|
{{- if lt $i (sub (len $children) 1)}} {{$child.name -}},
|
||||||
|
{{- else}} and {{$child.name -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}"
|
||||||
|
|||||||
115
testdata/vars/any2/Taskfile.yml
vendored
115
testdata/vars/any2/Taskfile.yml
vendored
@@ -1,115 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
default:
|
|
||||||
- task: map
|
|
||||||
- task: nested-map
|
|
||||||
- task: slice
|
|
||||||
- task: ref
|
|
||||||
- task: ref-sh
|
|
||||||
- task: ref-dep
|
|
||||||
- task: ref-resolver
|
|
||||||
- task: json
|
|
||||||
|
|
||||||
map:
|
|
||||||
vars:
|
|
||||||
MAP:
|
|
||||||
map: {"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}
|
|
||||||
cmds:
|
|
||||||
- task: print-story
|
|
||||||
vars:
|
|
||||||
VAR:
|
|
||||||
ref: .MAP
|
|
||||||
|
|
||||||
nested-map:
|
|
||||||
vars:
|
|
||||||
FOO: "foo"
|
|
||||||
nested:
|
|
||||||
map:
|
|
||||||
variables:
|
|
||||||
work: "{{.FOO}}"
|
|
||||||
cmds:
|
|
||||||
- echo {{.nested.variables.work}}
|
|
||||||
|
|
||||||
slice:
|
|
||||||
vars:
|
|
||||||
FOO: "foo"
|
|
||||||
BAR: "bar"
|
|
||||||
slice_variables_work: ["{{.FOO}}","{{.BAR}}"]
|
|
||||||
cmds:
|
|
||||||
- echo {{index .slice_variables_work 0}} {{index .slice_variables_work 1}}
|
|
||||||
|
|
||||||
ref:
|
|
||||||
vars:
|
|
||||||
MAP:
|
|
||||||
map: {"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}
|
|
||||||
MAP_REF:
|
|
||||||
ref: .MAP
|
|
||||||
cmds:
|
|
||||||
- task: print-story
|
|
||||||
vars:
|
|
||||||
VAR:
|
|
||||||
ref: .MAP_REF
|
|
||||||
|
|
||||||
ref-sh:
|
|
||||||
vars:
|
|
||||||
JSON_STRING:
|
|
||||||
sh: echo '{"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}'
|
|
||||||
JSON:
|
|
||||||
json: "{{.JSON_STRING}}"
|
|
||||||
MAP_REF:
|
|
||||||
ref: .JSON
|
|
||||||
cmds:
|
|
||||||
- task: print-story
|
|
||||||
vars:
|
|
||||||
VAR:
|
|
||||||
ref: .MAP_REF
|
|
||||||
|
|
||||||
ref-dep:
|
|
||||||
vars:
|
|
||||||
MAP:
|
|
||||||
map: {"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}
|
|
||||||
deps:
|
|
||||||
- task: print-story
|
|
||||||
vars:
|
|
||||||
VAR:
|
|
||||||
ref: .MAP
|
|
||||||
|
|
||||||
ref-resolver:
|
|
||||||
vars:
|
|
||||||
MAP:
|
|
||||||
map: {"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}
|
|
||||||
MAP_REF:
|
|
||||||
ref: .MAP
|
|
||||||
cmds:
|
|
||||||
- task: print-var
|
|
||||||
vars:
|
|
||||||
VAR:
|
|
||||||
ref: (index .MAP_REF.children 0).name
|
|
||||||
|
|
||||||
json:
|
|
||||||
vars:
|
|
||||||
JSON_STRING:
|
|
||||||
sh: cat example.json
|
|
||||||
JSON:
|
|
||||||
ref: "fromJson .JSON_STRING"
|
|
||||||
cmds:
|
|
||||||
- task: print-story
|
|
||||||
vars:
|
|
||||||
VAR:
|
|
||||||
ref: .JSON
|
|
||||||
|
|
||||||
print-var:
|
|
||||||
cmds:
|
|
||||||
- echo "{{.VAR}}"
|
|
||||||
|
|
||||||
print-story:
|
|
||||||
cmds:
|
|
||||||
- >-
|
|
||||||
echo "{{.VAR.name}} has {{len .VAR.children}} children called
|
|
||||||
{{- $children := .VAR.children -}}
|
|
||||||
{{- range $i, $child := $children -}}
|
|
||||||
{{- if lt $i (sub (len $children) 1)}} {{$child.name -}},
|
|
||||||
{{- else}} and {{$child.name -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}"
|
|
||||||
133
watch.go
133
watch.go
@@ -19,6 +19,8 @@ import (
|
|||||||
"github.com/go-task/task/v3/internal/fingerprint"
|
"github.com/go-task/task/v3/internal/fingerprint"
|
||||||
"github.com/go-task/task/v3/internal/fsnotifyext"
|
"github.com/go-task/task/v3/internal/fsnotifyext"
|
||||||
"github.com/go-task/task/v3/internal/logger"
|
"github.com/go-task/task/v3/internal/logger"
|
||||||
|
"github.com/go-task/task/v3/internal/slicesext"
|
||||||
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultWaitTime = 100 * time.Millisecond
|
const defaultWaitTime = 100 * time.Millisecond
|
||||||
@@ -71,12 +73,9 @@ func (e *Executor) watchTasks(calls ...*Call) error {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case event, ok := <-eventsChan:
|
case event, ok := <-eventsChan:
|
||||||
switch {
|
if !ok {
|
||||||
case !ok:
|
|
||||||
cancel()
|
cancel()
|
||||||
return
|
return
|
||||||
case event.Op == fsnotify.Chmod:
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
e.Logger.VerboseErrf(logger.Magenta, "task: received watch event: %v\n", event)
|
e.Logger.VerboseErrf(logger.Magenta, "task: received watch event: %v\n", event)
|
||||||
|
|
||||||
@@ -88,17 +87,22 @@ func (e *Executor) watchTasks(calls ...*Call) error {
|
|||||||
for _, c := range calls {
|
for _, c := range calls {
|
||||||
c := c
|
c := c
|
||||||
go func() {
|
go func() {
|
||||||
|
if ShouldIgnore(event.Name) {
|
||||||
|
e.Logger.VerboseErrf(logger.Magenta, "task: event skipped for being an ignored dir: %s\n", event.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
t, err := e.GetTask(c)
|
t, err := e.GetTask(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Logger.Errf(logger.Red, "%v\n", err)
|
e.Logger.Errf(logger.Red, "%v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
baseDir := filepathext.SmartJoin(e.Dir, t.Dir)
|
baseDir := filepathext.SmartJoin(e.Dir, t.Dir)
|
||||||
files, err := fingerprint.Globs(baseDir, t.Sources)
|
files, err := e.collectSources(calls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Logger.Errf(logger.Red, "%v\n", err)
|
e.Logger.Errf(logger.Red, "%v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !event.Has(fsnotify.Remove) && !slices.Contains(files, event.Name) {
|
if !event.Has(fsnotify.Remove) && !slices.Contains(files, event.Name) {
|
||||||
relPath, _ := filepath.Rel(baseDir, event.Name)
|
relPath, _ := filepath.Rel(baseDir, event.Name)
|
||||||
e.Logger.VerboseErrf(logger.Magenta, "task: skipped for file not in sources: %s\n", relPath)
|
e.Logger.VerboseErrf(logger.Magenta, "task: skipped for file not in sources: %s\n", relPath)
|
||||||
@@ -161,65 +165,36 @@ func closeOnInterrupt(w *fsnotify.Watcher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) registerWatchedDirs(w *fsnotify.Watcher, calls ...*Call) error {
|
func (e *Executor) registerWatchedDirs(w *fsnotify.Watcher, calls ...*Call) error {
|
||||||
var registerTaskDirs func(*Call) error
|
files, err := e.collectSources(calls)
|
||||||
registerTaskDirs = func(c *Call) error {
|
if err != nil {
|
||||||
task, err := e.CompiledTask(c)
|
return err
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, d := range task.Deps {
|
|
||||||
if err := registerTaskDirs(&Call{Task: d.Task, Vars: d.Vars}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, c := range task.Cmds {
|
|
||||||
if c.Task != "" {
|
|
||||||
if err := registerTaskDirs(&Call{Task: c.Task, Vars: c.Vars}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
files, err := fingerprint.Globs(task.Dir, task.Sources)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range files {
|
|
||||||
d := filepath.Dir(f)
|
|
||||||
if isSet, ok := e.watchedDirs.Load(d); ok && isSet {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ShouldIgnoreFile(d) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := w.Add(d); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
e.watchedDirs.Store(d, true)
|
|
||||||
relPath, _ := filepath.Rel(e.Dir, d)
|
|
||||||
w.Events <- fsnotify.Event{Name: f, Op: fsnotify.Create}
|
|
||||||
e.Logger.VerboseOutf(logger.Green, "task: watching new dir: %v\n", relPath)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
for _, f := range files {
|
||||||
for _, c := range calls {
|
d := filepath.Dir(f)
|
||||||
if err := registerTaskDirs(c); err != nil {
|
if isSet, ok := e.watchedDirs.Load(d); ok && isSet {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ShouldIgnore(d) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := w.Add(d); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
e.watchedDirs.Store(d, true)
|
||||||
|
relPath, _ := filepath.Rel(e.Dir, d)
|
||||||
|
e.Logger.VerboseOutf(logger.Green, "task: watching new dir: %v\n", relPath)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShouldIgnoreFile(path string) bool {
|
var ignorePaths = []string{
|
||||||
ignorePaths := []string{
|
"/.task",
|
||||||
"/.task",
|
"/.git",
|
||||||
"/.git",
|
"/.hg",
|
||||||
"/.hg",
|
"/node_modules",
|
||||||
"/node_modules",
|
}
|
||||||
}
|
|
||||||
|
func ShouldIgnore(path string) bool {
|
||||||
for _, p := range ignorePaths {
|
for _, p := range ignorePaths {
|
||||||
if strings.Contains(path, fmt.Sprintf("%s/", p)) || strings.HasSuffix(path, p) {
|
if strings.Contains(path, fmt.Sprintf("%s/", p)) || strings.HasSuffix(path, p) {
|
||||||
return true
|
return true
|
||||||
@@ -227,3 +202,47 @@ func ShouldIgnoreFile(path string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Executor) collectSources(calls []*Call) ([]string, error) {
|
||||||
|
var sources []string
|
||||||
|
|
||||||
|
err := e.traverse(calls, func(task *ast.Task) error {
|
||||||
|
files, err := fingerprint.Globs(task.Dir, task.Sources)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sources = append(sources, files...)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return slicesext.UniqueJoin(sources), err
|
||||||
|
}
|
||||||
|
|
||||||
|
type traverseFunc func(*ast.Task) error
|
||||||
|
|
||||||
|
func (e *Executor) traverse(calls []*Call, yield traverseFunc) error {
|
||||||
|
for _, c := range calls {
|
||||||
|
task, err := e.CompiledTask(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, dep := range task.Deps {
|
||||||
|
if dep.Task != "" {
|
||||||
|
if err := e.traverse([]*Call{{Task: dep.Task, Vars: dep.Vars}}, yield); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, cmd := range task.Cmds {
|
||||||
|
if cmd.Task != "" {
|
||||||
|
if err := e.traverse([]*Call{{Task: cmd.Task, Vars: cmd.Vars}}, yield); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := yield(task); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,16 +31,17 @@ task: Started watching for tasks: default
|
|||||||
task: [default] echo "Task running!"
|
task: [default] echo "Task running!"
|
||||||
Task running!
|
Task running!
|
||||||
task: task "default" finished running
|
task: task "default" finished running
|
||||||
task: Task "default" is up to date
|
task: [default] echo "Task running!"
|
||||||
|
Task running!
|
||||||
task: task "default" finished running
|
task: task "default" finished running
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
e := task.NewExecutor(
|
e := task.NewExecutor(
|
||||||
task.ExecutorWithDir(dir),
|
task.WithDir(dir),
|
||||||
task.ExecutorWithStdout(&buff),
|
task.WithStdout(&buff),
|
||||||
task.ExecutorWithStderr(&buff),
|
task.WithStderr(&buff),
|
||||||
task.ExecutorWithWatch(true),
|
task.WithWatch(true),
|
||||||
)
|
)
|
||||||
|
|
||||||
require.NoError(t, e.Setup())
|
require.NoError(t, e.Setup())
|
||||||
@@ -49,10 +50,10 @@ task: task "default" finished running
|
|||||||
dirPath := filepathext.SmartJoin(dir, "src")
|
dirPath := filepathext.SmartJoin(dir, "src")
|
||||||
filePath := filepathext.SmartJoin(dirPath, "a")
|
filePath := filepathext.SmartJoin(dirPath, "a")
|
||||||
|
|
||||||
err := os.MkdirAll(dirPath, 0755)
|
err := os.MkdirAll(dirPath, 0o755)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = os.WriteFile(filePath, []byte("test"), 0644)
|
err = os.WriteFile(filePath, []byte("test"), 0o644)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
@@ -71,16 +72,16 @@ task: task "default" finished running
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(200 * time.Millisecond)
|
||||||
err = os.WriteFile(filePath, []byte("test updated"), 0644)
|
err = os.WriteFile(filePath, []byte("test updated"), 0o644)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
time.Sleep(150 * time.Millisecond)
|
time.Sleep(200 * time.Millisecond)
|
||||||
cancel()
|
cancel()
|
||||||
assert.Equal(t, expectedOutput, strings.TrimSpace(buff.String()))
|
assert.Equal(t, expectedOutput, strings.TrimSpace(buff.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldIgnoreFile(t *testing.T) {
|
func TestShouldIgnore(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
tt := []struct {
|
tt := []struct {
|
||||||
@@ -95,7 +96,7 @@ func TestShouldIgnoreFile(t *testing.T) {
|
|||||||
ct := ct
|
ct := ct
|
||||||
t.Run(fmt.Sprintf("ignore - %d", k), func(t *testing.T) {
|
t.Run(fmt.Sprintf("ignore - %d", k), func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
require.Equal(t, task.ShouldIgnoreFile(ct.path), ct.expect)
|
require.Equal(t, task.ShouldIgnore(ct.path), ct.expect)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,58 @@ sidebar_position: 14
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v3.43.0 - 2025-04-21
|
## v3.44.1 - 2025-07-23
|
||||||
|
|
||||||
|
- Internal tasks will no longer be shown as suggestions since they cannot be
|
||||||
|
called (#2309, #2323 by @maxmzkrcensys)
|
||||||
|
- Fixed install script for some ARM platforms (#1516, #2291 by @trulede).
|
||||||
|
- Fixed a regression where fingerprinting was not working correctly if the path
|
||||||
|
to you Taskfile contained a space (#2321, #2322 by @pd93).
|
||||||
|
- Reverted a breaking change to `randInt` (#2312, #2316 by @pd93).
|
||||||
|
- Made new variables `TEST_NAME` and `TEST_DIR` available in fixture tests
|
||||||
|
(#2265 by @pd93).
|
||||||
|
|
||||||
|
## v3.44.0 - 2025-06-08
|
||||||
|
|
||||||
|
- Added `uuid`, `randInt` and `randIntN` template functions (#1346, #2225 by
|
||||||
|
@pd93).
|
||||||
|
- Added new `CLI_ARGS_LIST` array variable which contains the arguments passed
|
||||||
|
to Task after the `--` (the same as `CLI_ARGS`, but an array instead of a
|
||||||
|
string). (#2138, #2139, #2140 by @pd93).
|
||||||
|
- Added `toYaml` and `fromYaml` templating functions (#2217, #2219 by @pd93).
|
||||||
|
- Added `task` field the `--list --json` output (#2256 by @aleksandersh).
|
||||||
|
- Added the ability to
|
||||||
|
[pin included taskfiles](https://taskfile.dev/next/experiments/remote-taskfiles/#manual-checksum-pinning)
|
||||||
|
by specifying a checksum. This works with both local and remote Taskfiles
|
||||||
|
(#2222, #2223 by @pd93).
|
||||||
|
- When using the
|
||||||
|
[Remote Taskfiles experiment](https://github.com/go-task/task/issues/1317),
|
||||||
|
any credentials used in the URL will now be redacted in Task's output (#2100,
|
||||||
|
#2220 by @pd93).
|
||||||
|
- Fixed fuzzy suggestions not working when misspelling a task name (#2192, #2200
|
||||||
|
by @vmaerten).
|
||||||
|
- Fixed a bug where taskfiles in directories containing spaces created
|
||||||
|
directories in the wrong location (#2208, #2216 by @pd93).
|
||||||
|
- Added support for dual JSON schema files, allowing changes without affecting
|
||||||
|
the current schema. The current schemas will only be updated during releases.
|
||||||
|
(#2211 by @vmaerten).
|
||||||
|
- Improved fingerprint documentation by specifying that the method can be set at
|
||||||
|
the root level to apply to all tasks (#2233 by @vmaerten).
|
||||||
|
- Fixed some watcher regressions after #2048 (#2199, #2202, #2241, #2196 by
|
||||||
|
@wazazaby, #2271 by @andreynering).
|
||||||
|
|
||||||
|
## v3.43.3 - 2025-04-27
|
||||||
|
|
||||||
|
Reverted the changes made in #2113 and #2186 that affected the
|
||||||
|
`USER_WORKING_DIR` and built-in variables. This fixes #2206, #2195, #2207 and
|
||||||
|
#2208.
|
||||||
|
|
||||||
|
## v3.43.2 - 2025-04-21
|
||||||
|
|
||||||
|
- Fixed regresion of `CLI_ARGS` being exposed as the wrong type (#2190, #2191 by
|
||||||
|
@vmaerten).
|
||||||
|
|
||||||
|
## v3.43.1 - 2025-04-21
|
||||||
|
|
||||||
- Significant improvements were made to the watcher. We migrated from
|
- Significant improvements were made to the watcher. We migrated from
|
||||||
[watcher](https://github.com/radovskyb/watcher) to
|
[watcher](https://github.com/radovskyb/watcher) to
|
||||||
|
|||||||
@@ -43,12 +43,16 @@ Studio Code][vscode-task].
|
|||||||
## 2. Making changes
|
## 2. Making changes
|
||||||
|
|
||||||
- **Code style** - Try to maintain the existing code style where possible. Go
|
- **Code style** - Try to maintain the existing code style where possible. Go
|
||||||
code should be formatted by [`gofumpt`][gofumpt] and linted using
|
code should be formatted and linted by [`golangci-lint`][golangci-lint]. This
|
||||||
[`golangci-lint`][golangci-lint]. Any Markdown or TypeScript files should be
|
wraps the [`gofumpt`][gofumpt] and [`gci`][gci] formatters and a number of
|
||||||
formatted and linted by [Prettier][prettier]. This style is enforced by our CI
|
linters. We recommend that you take a look at the [golangci-lint
|
||||||
to ensure that we have a consistent style across the project. You can use the
|
docs][golangci-lint-docs] for a guide on how to setup your editor to
|
||||||
`task lint` command to lint the code locally and the `task lint:fix` command
|
auto-format your code. Any Markdown or TypeScript files should be formatted
|
||||||
to automatically fix any issues that are found.
|
and linted by [Prettier][prettier]. This style is enforced by our CI to ensure
|
||||||
|
that we have a consistent style across the project. You can use the `task
|
||||||
|
lint` command to lint the code locally and the `task lint:fix` command to try
|
||||||
|
to automatically fix any issues that are found. You can also use the `task
|
||||||
|
fmt` command to auto-format the files if your editor doesn't do it for you.
|
||||||
- **Documentation** - Ensure that you add/update any relevant documentation. See
|
- **Documentation** - Ensure that you add/update any relevant documentation. See
|
||||||
the [updating documentation](#updating-documentation) section below.
|
the [updating documentation](#updating-documentation) section below.
|
||||||
- **Tests** - Ensure that you add/update any relevant tests and that all tests
|
- **Tests** - Ensure that you add/update any relevant tests and that all tests
|
||||||
@@ -73,8 +77,9 @@ install the extension.
|
|||||||
Task uses [Docusaurus][docusaurus] to host a documentation server. The code for
|
Task uses [Docusaurus][docusaurus] to host a documentation server. The code for
|
||||||
this is located in the core Task repository. This can be setup and run locally
|
this is located in the core Task repository. This can be setup and run locally
|
||||||
by using `task website` (requires `nodejs` & `yarn`). All content is written in
|
by using `task website` (requires `nodejs` & `yarn`). All content is written in
|
||||||
Markdown and is located in the `website/docs` directory. All Markdown documents
|
[MDX][mdx] (an extension of Markdown) and is located in the `website/docs`
|
||||||
should have an 80 character line wrap limit (enforced by Prettier).
|
directory. All Markdown documents should have an 80 character line wrap limit
|
||||||
|
(enforced by Prettier).
|
||||||
|
|
||||||
When making a change, consider whether a change to the [Usage Guide](/usage) is
|
When making a change, consider whether a change to the [Usage Guide](/usage) is
|
||||||
necessary. This document contains descriptions and examples of how to use Task
|
necessary. This document contains descriptions and examples of how to use Task
|
||||||
@@ -154,7 +159,9 @@ If you have questions, feel free to ask them in the `#help` forum channel on our
|
|||||||
[vscode-task]: https://github.com/go-task/vscode-task
|
[vscode-task]: https://github.com/go-task/vscode-task
|
||||||
[go]: https://go.dev
|
[go]: https://go.dev
|
||||||
[gofumpt]: https://github.com/mvdan/gofumpt
|
[gofumpt]: https://github.com/mvdan/gofumpt
|
||||||
|
[gci]: https://github.com/daixiang0/gci
|
||||||
[golangci-lint]: https://golangci-lint.run
|
[golangci-lint]: https://golangci-lint.run
|
||||||
|
[golangci-lint-docs]: https://golangci-lint.run/welcome/integrations/
|
||||||
[prettier]: https://prettier.io
|
[prettier]: https://prettier.io
|
||||||
[nodejs]: https://nodejs.org/en/
|
[nodejs]: https://nodejs.org/en/
|
||||||
[yarn]: https://yarnpkg.com/
|
[yarn]: https://yarnpkg.com/
|
||||||
@@ -166,4 +173,5 @@ If you have questions, feel free to ask them in the `#help` forum channel on our
|
|||||||
[discord-server]: https://discord.gg/6TY36E39UK
|
[discord-server]: https://discord.gg/6TY36E39UK
|
||||||
[discussion]: https://github.com/go-task/task/discussions
|
[discussion]: https://github.com/go-task/task/discussions
|
||||||
[conventional-commits]: https://www.conventionalcommits.org
|
[conventional-commits]: https://www.conventionalcommits.org
|
||||||
|
[mdx]: https://mdxjs.com/
|
||||||
{/* prettier-ignore-end */}
|
{/* prettier-ignore-end */}
|
||||||
|
|||||||
@@ -182,9 +182,11 @@ includes:
|
|||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
|
### Automatic checksums
|
||||||
|
|
||||||
Running commands from sources that you do not control is always a potential
|
Running commands from sources that you do not control is always a potential
|
||||||
security risk. For this reason, we have added some checks when using remote
|
security risk. For this reason, we have added some automatic checks when using
|
||||||
Taskfiles:
|
remote Taskfiles:
|
||||||
|
|
||||||
1. When running a task from a remote Taskfile for the first time, Task will
|
1. When running a task from a remote Taskfile for the first time, Task will
|
||||||
print a warning to the console asking you to check that you are sure that you
|
print a warning to the console asking you to check that you are sure that you
|
||||||
@@ -209,6 +211,38 @@ flag. Before enabling this flag, you should:
|
|||||||
containing a commit hash) to prevent Task from automatically accepting a
|
containing a commit hash) to prevent Task from automatically accepting a
|
||||||
prompt that says a remote Taskfile has changed.
|
prompt that says a remote Taskfile has changed.
|
||||||
|
|
||||||
|
### Manual checksum pinning
|
||||||
|
|
||||||
|
Alternatively, if you expect the contents of your remote files to be a constant
|
||||||
|
value, you can pin the checksum of the included file instead:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
included:
|
||||||
|
taskfile: https://taskfile.dev
|
||||||
|
checksum: c153e97e0b3a998a7ed2e61064c6ddaddd0de0c525feefd6bba8569827d8efe9
|
||||||
|
```
|
||||||
|
|
||||||
|
This will disable the automatic checksum prompts discussed above. However, if
|
||||||
|
the checksums do not match, Task will exit immediately with an error. When
|
||||||
|
setting this up for the first time, you may not know the correct value of the
|
||||||
|
checksum. There are a couple of ways you can obtain this:
|
||||||
|
|
||||||
|
1. Add the include normally without the `checksum` key. The first time you run
|
||||||
|
the included Taskfile, a `.task/remote` temporary directory is created. Find
|
||||||
|
the correct set of files for your included Taskfile and open the file that
|
||||||
|
ends with `.checksum`. You can copy the contents of this file and paste it
|
||||||
|
into the `checksum` key of your include. This method is safest as it allows
|
||||||
|
you to inspect the downloaded Taskfile before you pin it.
|
||||||
|
2. Alternatively, add the include with a temporary random value in the
|
||||||
|
`checksum` key. When you try to run the Taskfile, you will get an error that
|
||||||
|
will report the incorrect expected checksum and the actual checksum. You can
|
||||||
|
copy the actual checksum and replace your temporary random value.
|
||||||
|
|
||||||
|
### TLS
|
||||||
|
|
||||||
Task currently supports both `http` and `https` URLs. However, the `http`
|
Task currently supports both `http` and `https` URLs. However, the `http`
|
||||||
requests will not execute by default unless you run the task with the
|
requests will not execute by default unless you run the task with the
|
||||||
`--insecure` flag. This is to protect you from accidentally running a remote
|
`--insecure` flag. This is to protect you from accidentally running a remote
|
||||||
|
|||||||
@@ -36,6 +36,14 @@ repository [[package](https://formulae.brew.sh/formula/go-task)]
|
|||||||
brew install go-task
|
brew install go-task
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### [Macports][macports] ![][macos] ![][community] \{#macports}
|
||||||
|
|
||||||
|
Task repository is tracked by Macports [[package](https://ports.macports.org/port/go-task/details/)] [[source](https://github.com/macports/macports-ports/blob/master/devel/go-task/Portfile)]:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
port install go-task
|
||||||
|
```
|
||||||
|
|
||||||
### [Snap][snapcraft] ![][macos] ![][linux] \{#snap}
|
### [Snap][snapcraft] ![][macos] ![][linux] \{#snap}
|
||||||
|
|
||||||
Task is available on [Snapcraft][snapcraft] [[source](https://github.com/go-task/snap/blob/main/snap/snapcraft.yaml)], but keep in mind that your Linux
|
Task is available on [Snapcraft][snapcraft] [[source](https://github.com/go-task/snap/blob/main/snap/snapcraft.yaml)], but keep in mind that your Linux
|
||||||
@@ -104,6 +112,14 @@ pacman -S go-task
|
|||||||
dnf install go-task
|
dnf install go-task
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### FreeBSD ([Ports][freebsdports]) ![][freebsd] ![][community] \{#freebsd}
|
||||||
|
|
||||||
|
[[package](https://cgit.freebsd.org/ports/tree/devel/task)] [[source](https://cgit.freebsd.org/ports/tree/devel/task/Makefile)]
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pkg install task
|
||||||
|
```
|
||||||
|
|
||||||
### NixOS ([nix][nix]) ![][nixos] ![][linux] ![][community] \{#nix}
|
### NixOS ([nix][nix]) ![][nixos] ![][linux] ![][community] \{#nix}
|
||||||
|
|
||||||
[[source](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/go/go-task/package.nix)]
|
[[source](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/go/go-task/package.nix)]
|
||||||
@@ -304,6 +320,7 @@ task --completion fish > ~/.config/fish/completions/task.fish
|
|||||||
|
|
||||||
{/* prettier-ignore-start */}
|
{/* prettier-ignore-start */}
|
||||||
[homebrew]: https://brew.sh
|
[homebrew]: https://brew.sh
|
||||||
|
[macports]: https://macports.org
|
||||||
[snapcraft]: https://snapcraft.io/task
|
[snapcraft]: https://snapcraft.io/task
|
||||||
[winget]: https://github.com/microsoft/winget-cli
|
[winget]: https://github.com/microsoft/winget-cli
|
||||||
[choco]: https://chocolatey.org
|
[choco]: https://chocolatey.org
|
||||||
@@ -317,6 +334,7 @@ task --completion fish > ~/.config/fish/completions/task.fish
|
|||||||
[aqua]: https://aquaproj.github.io
|
[aqua]: https://aquaproj.github.io
|
||||||
[pacstall]: https://github.com/pacstall/pacstall
|
[pacstall]: https://github.com/pacstall/pacstall
|
||||||
[pkgx]: https://pkgx.sh
|
[pkgx]: https://pkgx.sh
|
||||||
|
[freebsdports]: https://ports.freebsd.org/cgi/ports.cgi
|
||||||
|
|
||||||
[go]: https://golang.org
|
[go]: https://golang.org
|
||||||
[godownloader]: https://github.com/goreleaser/godownloader
|
[godownloader]: https://github.com/goreleaser/godownloader
|
||||||
@@ -332,4 +350,5 @@ task --completion fish > ~/.config/fish/completions/task.fish
|
|||||||
[nixos]: https://img.shields.io/badge/NixOS-5277C3?logo=nixos&logoColor=fff
|
[nixos]: https://img.shields.io/badge/NixOS-5277C3?logo=nixos&logoColor=fff
|
||||||
[debian]: https://img.shields.io/badge/Debian-A81D33?logo=debian&logoColor=fff
|
[debian]: https://img.shields.io/badge/Debian-A81D33?logo=debian&logoColor=fff
|
||||||
[ubuntu]: https://img.shields.io/badge/Ubuntu-E95420?logo=ubuntu&logoColor=fff
|
[ubuntu]: https://img.shields.io/badge/Ubuntu-E95420?logo=ubuntu&logoColor=fff
|
||||||
|
[freebsd]: https://img.shields.io/badge/FreeBSD-990000?logo=freebsd&logoColor=fff
|
||||||
{/* prettier-ignore-end */}
|
{/* prettier-ignore-end */}
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ structure:
|
|||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
|
"task": "",
|
||||||
"desc": "",
|
"desc": "",
|
||||||
"summary": "",
|
"summary": "",
|
||||||
"up_to_date": false,
|
"up_to_date": false,
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ toc_max_heading_level: 5
|
|||||||
| `internal` | `bool` | `false` | Stops any task in the included Taskfile from being callable on the command line. These commands will also be omitted from the output when used with `--list`. |
|
| `internal` | `bool` | `false` | Stops any task in the included Taskfile from being callable on the command line. These commands will also be omitted from the output when used with `--list`. |
|
||||||
| `aliases` | `[]string` | | Alternative names for the namespace of the included Taskfile. |
|
| `aliases` | `[]string` | | Alternative names for the namespace of the included Taskfile. |
|
||||||
| `vars` | `map[string]Variable` | | A set of variables to apply to the included Taskfile. |
|
| `vars` | `map[string]Variable` | | A set of variables to apply to the included Taskfile. |
|
||||||
|
| `checksum` | `string` | | The checksum of the file you expect to include. If the checksum does not match, the file will not be included. |
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user