Compare commits

...

56 Commits

Author SHA1 Message Date
Andrey Nering
45dbbcd179 v3.2.0 2021-01-07 13:08:07 -03:00
Andrey Nering
83d25bfa00 Refactor: Fix import order
It should be: stdlib > libs > app
2021-01-07 11:48:33 -03:00
Andrey Nering
299e27af15 Fix build 2021-01-07 11:39:36 -03:00
Andrey Nering
ec4cd5ed48 Fix .task directory location
Closes #247
2021-01-07 11:36:09 -03:00
Andrey Nering
59d2733b88 Make dynamic variables run on the right directory
It was always running in the main Taskfile dir, even when the variable was
declared in an included taskfile in another directory or when task had a
custom dir.

Closes #384
2021-01-07 11:26:11 -03:00
Andrey Nering
cbdd088188 Remove manual event trigger 2021-01-05 11:36:30 -03:00
Andrey Nering
2d52485d7b Watch: Clear vars cache between runs
Closes #365
2021-01-05 11:19:34 -03:00
Andrey Nering
d830178ef8 Do more watch fixes
This improves the work done on #423
2021-01-05 10:48:04 -03:00
James Wendel
049984b4cc Update watch.go 2021-01-03 21:26:09 -07:00
James Wendel
d261a986ab Update watch.go
Watch: Stop removing and addings files all the time.
2021-01-03 17:08:16 -07:00
Andrey Nering
9b2e25735b v3.1.0 2021-01-03 19:37:09 -03:00
Andrey Nering
e09e75b0ba Fix a bug when the checksum up-to-date resolution is used by a task with a custom label: attribute
Closes #412

Co-authored-by: Adam Wasila <adam.wasila@gmail.com>
2021-01-03 19:22:38 -03:00
Andrey Nering
6630113fef Release ARMv6 and ARM64 binaries on Linux
Closes #375
Closes #418
2021-01-03 19:12:38 -03:00
Andrey Nering
b2f08c9c20 Merge pull request #415 from felladrin/patch-1
Fix duplicate task name on "Short task syntax" example
2021-01-02 11:02:49 -03:00
Andrey Nering
6a4315b7e7 Merge pull request #407 from bryceschober/patch-1
Use {{default}} for an overriding usage
2021-01-01 19:21:50 -03:00
Andrey Nering
8b3e62ff6d Add forgotten CHANGELOG entry for #358
Ref #121
2021-01-01 19:06:00 -03:00
Andrey Nering
f1d3f6740d Update CHANGELOG.md 2021-01-01 18:57:28 -03:00
Andrey Nering
9ccd1d920c .gitignore: Add /tmp 2021-01-01 18:30:14 -03:00
Andrey Nering
9674d75ff6 Evaluate included taskfiles in order of declaration
Closes #393
2021-01-01 18:27:50 -03:00
Andrey Nering
22fd74846d Use interp.Params("-e") intead of running "set -e" manually
This is an improvement for ac8e344173
2021-01-01 17:32:42 -03:00
Andrey Nering
777645888a New logo and color 2020-12-27 19:07:38 -03:00
Andrey Nering
ac8e344173 Run "set -e" automatically for every command
Without this, multiline command strings won't always exit when they fail.

Closes #403
2020-12-27 17:15:12 -03:00
Andrey Nering
16fad60833 execext: Small refactor 2020-12-27 16:51:00 -03:00
Andrey Nering
cb96a39b46 v3.0.1 2020-12-26 15:34:17 -03:00
Andrey Nering
a540634b5b Add about: to issue templates 2020-12-26 15:27:15 -03:00
Andrey Nering
e15576bc47 Update issue templates 2020-12-26 15:24:46 -03:00
Andrey Nering
95359760ae Documentation: go get is actually supported
Closes #395
2020-12-26 15:06:39 -03:00
Andrey Nering
be209cb7b6 Merge pull request #406 from ezhukov/patch-2
Update curl arguments in installation.md
2020-12-26 15:00:04 -03:00
Victor Nogueira
f5eb80759b Fix duplicate task name on "Short task syntax" example
To make it a valid YAML file and avoid the error:

```
yaml: unmarshal errors:
  line 6: mapping key "build" already defined at line 4
```
2020-12-07 13:00:25 +02:00
Andrey Nering
9f125502f8 Update Taskfile.yml
We now use modules. Dep is history
2020-12-05 19:10:49 -03:00
Andrey Nering
3f856c4b1c Merge pull request #414 from go-task/mvdan/sh-3.2.1
Upgrade mvdan/sh to v3.2.1
2020-12-05 19:04:48 -03:00
Andrey Nering
f55fb1e3a5 Upgrade mvdan/sh to v3.2.1 2020-12-05 18:59:34 -03:00
Bryce Schober
bf88bd5da5 Use {{default}} for an overriding usage
Fixes documentation confusion raised in #376.
2020-11-18 17:09:44 -08:00
Eugene Zhukov
b7112e02db Update curl arguments in installation.md
Double -s argument does not make sense according to curl manual page.
-s stands for silent, while -S (capital S) stands for showing the error.
When used in combination, curl shows an error message if it fails, but disables progress meter.

Finally, in the end of sh command there is -d, which stands for debug and contradicts -sS curl arguments.
I suggest to remove curl silencers all together, because more debug is better in CIs. I also suggest to use --location instead of -L for clarity.
2020-11-17 10:02:06 +02:00
Andrey Nering
b136166fc9 Merge pull request #387 from sheldonhull/patch-1
feat: improve installation script documentation for shell installs
2020-11-08 11:46:58 -03:00
sheldonhull
75727c3d68 fix: improve curl command install
- works on macOS
- works in Linux (tested in docker container)
2020-10-16 18:12:26 -05:00
sheldonhull
6c625b3359 fix: typo on curl install comment
fix from url to curl
2020-10-14 22:30:19 -05:00
Andrey Nering
60759a4e3b Post-fixes and CHANGELOG for #385 2020-10-12 21:16:09 -03:00
Andrey Nering
582a66bb2f Merge pull request #385 from chris-garrett/dev/378-missing-env
Resolves #378 - allow for missing env files as they may be bootstrapped.
2020-10-12 21:12:08 -03:00
Andrey Nering
d78f78bb5c Fix panic for empty tasks
Closes #338
Closes #362

Co-authored-by: Bharath Kumar <shettybharath4@gmail.com>
2020-10-12 21:03:13 -03:00
sheldonhull
71b7d062d5 feat: improve installation script documentation for shell installs
- The default didn't work well for me out of the gate.
- This is the modified version to support passing in the arguments easily as well as an example for installing to `/usr/local/bin` for using in Codespaces or equivalent development workflow.
2020-10-07 14:57:25 -05:00
Chris Garrett
c6138a0660 #378 - allow for missing env files as they may be bootstrapped. 2020-10-03 16:39:58 -06:00
Andrey Nering
ce4ac97269 Documentation updates 2020-09-06 14:33:28 -03:00
Andrey Nering
2088a86512 Merge pull request #372 from go-task/go-1-15
CI: Update Go version to 1.15.x
2020-09-05 17:59:55 -03:00
Andrey Nering
e296fe2b98 Merge pull request #371 from onedr0p/patch-1
Make fish completions compatible with MacOS
2020-09-05 17:59:24 -03:00
Andrey Nering
96b8890ecc CI: Update Go version to 1.15.x 2020-09-05 17:57:24 -03:00
Devin Buhl
db6fae2f5b Make completion compatible with MacOS 2020-09-03 18:52:36 -04:00
Andrey Nering
6743cdbb65 README: Add downloads badge 2020-08-25 18:15:51 -03:00
Andrey Nering
71466c9a27 Merge pull request #358 from damian-szulc/feature/allow-to-use-as-external-lib
Allow usage as an external library
2020-08-24 22:14:57 -03:00
Andrey Nering
1bdf7e3192 v3: Post-release improvements to the documentation
Closes #367
2020-08-24 21:43:08 -03:00
Andrey Nering
7285f3c844 Merge pull request #364 from shilangyu/fish-completions
Added fish completions
2020-08-24 21:20:04 -03:00
Andrey Nering
eb257d3aa7 Merge pull request #366 from jonasagx/patch-1
typo and grammar fixes
2020-08-24 21:17:36 -03:00
Jonas Galvão Xavier
87f11491d9 typo and grammar fixes 2020-08-22 13:33:04 -07:00
shilangyu
5735a02473 added fish completions 2020-08-22 11:59:17 +00:00
Damian Szulc
47dd9b5a03 Move args and taskfile packages to root directory 2020-08-19 10:59:58 +02:00
Andrey Nering
7652d7889b Some documentation improvements after the release of v3
Thanks @marco-m
2020-08-17 09:46:55 -03:00
70 changed files with 621 additions and 376 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,3 @@
open_collective: task
patreon: andreynering
custom: 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A&currency_code=BRL&source=url'

View File

@@ -1,6 +0,0 @@
<!--
If relevant, include the following information:
- Task version
- OS
- Example Taskfile showing the issue
-->

14
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,14 @@
---
name: Bug Report
about: Use the template to report bugs and issues
labels: bug
---
- Task version:
- Operating System:
### Example Taskfile showing the issue
```yaml
```

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Questions, Ideas and General Discussions
url: https://github.com/go-task/task/discussions
about: Ask questions and discuss general ideas with the community

View File

@@ -0,0 +1,12 @@
---
name: Feature Request
about: Use the template to make feature requests
labels: feature
---
Describe in detail what feature do you want to see in Task.
Give examples if possible.
Please, search if this wasn't proposed before, and if this is more like an idea
than a strong feature request, consider opening a
[discussion](https://github.com/go-task/task/discussions) instead.

View File

@@ -15,7 +15,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.14.x
go-version: 1.15.x
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v1

View File

@@ -5,7 +5,7 @@ jobs:
name: Test
strategy:
matrix:
go-version: [1.13.x, 1.14.x]
go-version: [1.14.x, 1.15.x]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{matrix.platform}}
steps:

1
.gitignore vendored
View File

@@ -27,3 +27,4 @@ tags
/bin
/testdata/vars/v1
/tmp

View File

@@ -8,6 +8,10 @@ build:
goarch:
- 386
- amd64
- arm
- arm64
goarm:
- 6
ignore:
- goos: darwin
goarch: 386

View File

@@ -1,5 +1,44 @@
# Changelog
## v3.2.0
- Fix the `.task` directory being created in the task directory instead of the
Taskfile directory
([#247](https://github.com/go-task/task/issues/247)).
- Fix a bug where dynamic variables (those declared with `sh:`) were not
running in the task directory when the task has a custom dir or it was
in an included Taskfile
([#384](https://github.com/go-task/task/issues/384)).
- The watch feature (via the `--watch` flag) got a few different bug fixes and
should be more stable now
([#423](https://github.com/go-task/task/pull/423), [#365](https://github.com/go-task/task/issues/365)).
## v3.1.0
- Fix a bug when the checksum up-to-date resolution is used by a task
with a custom `label:` attribute
([#412](https://github.com/go-task/task/issues/412)).
- Starting from this release, we're releasing official ARMv6 and ARM64 binaries
for Linux
([#375](https://github.com/go-task/task/issues/375), [#418](https://github.com/go-task/task/issues/418)).
- Task now respects the order of declaration of included Taskfiles when
evaluating variables declaring by them
([#393](https://github.com/go-task/task/issues/393)).
- `set -e` is now automatically set on every command. This was done to fix an
issue where multiline string commands wouldn't really fail unless the
sentence was in the last line
([#403](https://github.com/go-task/task/issues/403)).
## v3.0.1
- Allow use as a library by moving the required packages out of the `internal`
directory
([#358](https://github.com/go-task/task/pull/358)).
- Do not error if a specified dotenv file does not exist
([#378](https://github.com/go-task/task/issues/378), [#385](https://github.com/go-task/task/pull/385)).
- Fix panic when you have empty tasks in your Taskfile
([#338](https://github.com/go-task/task/issues/338), [#362](https://github.com/go-task/task/pull/362)).
## v3.0.0
- On `v3`, all CLI variables will be considered global variables

View File

@@ -1,23 +1,15 @@
![Test](https://github.com/go-task/task/workflows/Test/badge.svg)
![GoReleaser](https://github.com/go-task/task/workflows/goreleaser/badge.svg)
<div align="center">
<a href="https://taskfile.dev">
<img src="docs/Logo.png" width="200px" height="200px" />
</a>
# Task
<h1>Task</h1>
Task is a task runner / build tool that aims to be simpler and easier to use
than, for example, [GNU Make](https://www.gnu.org/software/make/).
<p>
Task is a task runner / build tool that aims to be simpler and easier to use than, for example, <a href="https://www.gnu.org/software/make/">GNU Make<a>.
</p>
See [taskfile.dev](https://taskfile.dev) for documentation.
---
## Sponsors
[![Sponsors](https://opencollective.com/task/sponsors.svg?width=890)](https://opencollective.com/task)
## Backers
[![Backers](https://opencollective.com/task/backers.svg?width=890)](https://opencollective.com/task)
## Contributors
[![Contributors](https://opencollective.com/task/contributors.svg?width=890)](https://github.com/go-task/task/graphs/contributors)
<p>
See <a href="https://taskfile.dev">taskfile.dev</a> for the documentation.
</p>
</div>

View File

@@ -24,8 +24,14 @@ tasks:
env:
CGO_ENABLED: '0'
dl-deps:
desc: Downloads cli dependencies
mod:
desc: Downloads and tidy Go modules
cmds:
- go mod download
- go mod tidy
cli-deps:
desc: Downloads CLI dependencies
cmds:
- task: go-get
vars: {REPO: golang.org/x/lint/golint}
@@ -34,12 +40,6 @@ tasks:
- task: go-get
vars: {REPO: github.com/goreleaser/godownloader}
update-deps:
desc: Updates dependencies
cmds:
- dep ensure
- dep ensure -update
clean:
desc: Cleans temp files and folders
cmds:
@@ -62,7 +62,7 @@ tasks:
cmds:
- goreleaser --snapshot --rm-dist
generate-install-script:
gen-install-script:
desc: Generate install script using https://github.com/goreleaser/godownloader
cmds:
- godownloader --repo go-task/task -o install-task.sh

View File

@@ -3,7 +3,7 @@ package args
import (
"strings"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/taskfile"
)
// ParseV3 parses command line argument: tasks and global variables

View File

@@ -4,10 +4,10 @@ import (
"fmt"
"testing"
"github.com/go-task/task/v3/internal/args"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/stretchr/testify/assert"
"github.com/go-task/task/v3/args"
"github.com/go-task/task/v3/taskfile"
)
func TestArgsV3(t *testing.T) {

View File

@@ -9,12 +9,12 @@ import (
"path/filepath"
"syscall"
"github.com/go-task/task/v3"
"github.com/go-task/task/v3/internal/args"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/spf13/pflag"
"github.com/go-task/task/v3"
"github.com/go-task/task/v3/args"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/taskfile"
)
var (

24
completion/fish/task.fish Normal file
View File

@@ -0,0 +1,24 @@
function __task_get_tasks --description "Prints all available tasks with their description"
task -l | sed '1d' | awk '{ $1=""; print $0 }' | tr ': ', '\t' | string trim
end
complete -c task -d 'Runs the specified task(s). Falls back to the "default" task if no task name was specified, or lists all tasks if an unknown task name was
specified.' -xa "(__task_get_tasks)"
complete -c task -s c -l color -d 'colored output (default true)'
complete -c task -s d -l dir -d 'sets directory of execution'
complete -c task -l dry -d 'compiles and prints tasks in the order that they would be run, without executing them'
complete -c task -s f -l force -d 'forces execution even when the task is up-to-date'
complete -c task -s h -l help -d 'shows Task usage'
complete -c task -s i -l init -d 'creates a new Taskfile.yml in the current folder'
complete -c task -s l -l list -d 'lists tasks with description of current Taskfile'
complete -c task -s o -l output -d 'sets output style: [interleaved|group|prefixed]' -xa "interleaved group prefixed"
complete -c task -s p -l parallel -d 'executes tasks provided on command line in parallel'
complete -c task -s s -l silent -d 'disables echoing'
complete -c task -l status -d 'exits with non-zero exit code if any of the given tasks is not up-to-date'
complete -c task -l summary -d 'show summary about a task'
complete -c task -s t -l taskfile -d 'choose which Taskfile to run. Defaults to "Taskfile.yml"'
complete -c task -s v -l verbose -d 'enables verbose mode'
complete -c task -l version -d 'show Task version'
complete -c task -s w -l watch -d 'enables watch of the given task'

BIN
docs/Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -1,5 +1,9 @@
# Task
<div align="center">
<img id="logo" src="/Logo.png" height="250px" width="250px" />
</div>
Task is a task runner / build tool that aims to be simpler and easier to use
than, for example, [GNU Make][make].
@@ -38,18 +42,6 @@ guide to check the full schema documentation and Task features.
if a given set of files haven't changed since last run (based either on its
timestamp or content).
## Sponsors
[![Sponsors](https://opencollective.com/task/sponsors.svg?width=890)](https://opencollective.com/task)
## Backers
[![Backers](https://opencollective.com/task/backers.svg?width=890)](https://opencollective.com/task)
## Contributors
[![Contributors](https://opencollective.com/task/contributors.svg?width=890)](https://github.com/go-task/task/graphs/contributors)
[make]: https://www.gnu.org/software/make/
[go]: https://golang.org/
[yaml]: http://yaml.org/

View File

@@ -10,3 +10,8 @@ tasks:
desc: Serves the documentation site locally
cmds:
- docsify serve .
ico:
desc: Generate favicon.ico from Logo.png
cmds:
- convert -background transparent "Logo.png" -define icon:auto-resize=16,24,32,48,64,72,96,128,256 "favicon.ico"

View File

@@ -4,5 +4,5 @@
- [Taskfile Versions](taskfile_versions.md)
- [Examples](examples.md)
- [Releasing Task](releasing_task.md)
- [Alternative Task Runners](alternative_task_runners.md)
- [Donate](donate.md)
- [![GitHub](https://icongram.jgog.in/simple/github.svg?color=808080&size=16)GitHub](https://github.com/go-task/task)

View File

@@ -1,17 +0,0 @@
# Alternative task runners
## YAML based
- [rliebz/tusk][tusk]
## Go based
- [magefile/mage][mage]
## Make similar
- [casey/just][just]
[tusk]: https://github.com/rliebz/tusk
[mage]: https://github.com/magefile/mage
[just]: https://github.com/casey/just

35
docs/donate.md Normal file
View File

@@ -0,0 +1,35 @@
# Donate
If you find this project useful, you can consider donating by using one of the
channels listed below.
This is just a way of saying "thank you", it won't give you any benefits like
higher priority on issues or something similar.
## Open Collective
Task is on [Open Collective](https://opencollective.com/task) and you have
these options to donate:
- [$2 per month](https://opencollective.com/task/contribute/backer-4034/checkout)
- [$5 per month](https://opencollective.com/task/contribute/supporter-8404/checkout)
- [$20 per month](https://opencollective.com/task/contribute/sponsor-4035/checkout)
- [Custom value - One-time donation option supported](https://opencollective.com/task/donate)
## Patreon
I'm also on [Patreon](https://www.patreon.com/andreynering) if
you prefer:
- [$5 per month](https://www.patreon.com/join/andreynering/checkout?rid=4229277)
- [$10 per month](https://www.patreon.com/join/andreynering/checkout?rid=4229276)
- [$15 per month](https://www.patreon.com/join/andreynering/checkout?rid=4229275)
You can choose a custom value on any of the links above.
Patreon does not support one-time donation. As a workaround you can fire a
subscription and cancel it once the donation was succeded.
## PayPal
- [Any value - One-time donation](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A&currency_code=BRL&source=url)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 170 KiB

View File

@@ -8,6 +8,19 @@
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify-themeable/dist/css/theme-simple.css">
<meta name="google-site-verification" content="VGAYkbdmuaciIDGkBe-eAg9yfZg0C6ostgonbGxxOa0" />
<style>
#logo {
transition: all 0.7s ease;
}
#logo:hover {
-webkit-transform: rotateZ(360deg);
-ms-transform: rotateZ(360deg);
transform: rotateZ(360deg);
}
.app-name-link img {
width: 125px;
}
</style>
</head>
<body>
<div id="app"></div>
@@ -15,7 +28,8 @@
window.$docsify = {
name: 'Task',
repo: 'go-task/task',
themeColor: '#00add8',
logo: 'Logo.png',
themeColor: '#29beb0',
loadSidebar: true,
auto2top: true,
maxLevel: 3,

View File

@@ -73,7 +73,13 @@ scenarios like CIs. Many thanks to [GoDownloader][godownloader] for allowing
easily generating this script.
```bash
curl -sL https://taskfile.dev/install.sh | sh
# For Default Installion to ./bin with debug logging
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d
# For Installation To /usr/local/bin for userwide access with debug logging
# May require sudo sh
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
```
> This method will download the binary on the local `./bin` directory by default.
@@ -101,10 +107,13 @@ This installation method is community owned.
First, make sure you have [Go][go] properly installed and setup.
Task requires [Go Modules](https://github.com/golang/go/wiki/Modules) and
doesn't officially support installing via `go get` anymore.
You can easily install it globally by running:
Installing in another directory:
```bash
go get -u github.com/go-task/task/v3/cmd/task
```
Or you can install into another directory:
```bash
git clone https://github.com/go-task/task

View File

@@ -92,48 +92,8 @@ tasks:
- echo "Using $KEYNAME"
```
## Operating System specific tasks
If you add a `Taskfile_{{GOOS}}.yml` you can override or amend your Taskfile
based on the operating system.
Example:
Taskfile.yml:
```yaml
version: '3'
tasks:
build:
cmds:
- echo "default"
```
Taskfile_linux.yml:
```yaml
version: '3'
tasks:
build:
cmds:
- echo "linux"
```
Will print out `linux` and not `default`.
Keep in mind that the version of the files should match. Also, when redefining
a task the whole task is replaced, properties of the task are not merged.
It's also possible to have an OS specific `Taskvars.yml` file, like
`Taskvars_windows.yml`, `Taskvars_linux.yml`, or `Taskvars_darwin.yml`. See the
[variables section](#variables) below.
## Including other Taskfiles
> This feature is still experimental and may have bugs.
If you want to share tasks between different projects (Taskfiles), you can use
the importing mechanism to include other Taskfiles using the `includes` keyword:
@@ -150,6 +110,21 @@ namespace. So, you'd call `task docs:serve` to run the `serve` task from
`documentation/Taskfile.yml` or `task docker:build` to run the `build` task
from the `DockerTasks.yml` file.
### OS-specific Taskfiles
With `version: '2'`, task automatically includes any `Taskfile_{{OS}}.yml`
if it exists (for example: `Taskfile_windows.yml`, `Taskfile_linux.yml` or
`Taskfile_darwin.yml`). Since this behavior was a bit too implicit, it
was removed on version 3, but you still can have a similar behavior by
explicitly importing these files:
```yaml
version: '3'
includes:
build: ./Taskfile_{{OS}}.yml
```
### Directory of included Taskfile
By default, included Taskfile's tasks are ran in the current directory, even
@@ -294,16 +269,16 @@ attribute:
version: '3'
tasks:
main-task:
greet:
vars:
RECIPIENT: '{{default "World" .RECIPIENT}}'
cmds:
- task: write-file
vars: {FILE: "hello.txt", CONTENT: "Hello!"}
- task: write-file
vars: {FILE: "world.txt", CONTENT: "World!"}
- echo "Hello, {{.RECIPIENT}}!"
write-file:
greet-pessimistically:
cmds:
- echo "{{.CONTENT}}" > {{.FILE}}
- task: greet
vars: {RECIPIENT: "Cruel World"}
```
The above syntax is also supported in `deps`.
@@ -345,8 +320,8 @@ tasks:
- public/style.css
```
`sources` and `generates` can be files or file patterns. When both are given,
Task will compare the checksum of the files to determine if it's
`sources` and `generates` can be files or file patterns. When given,
Task will compare the checksum of the source files to determine if it's
necessary to run the task. If not, it will just print a message like
`Task "js" is up to date`.
You will probably want to ignore the `.task` folder in your `.gitignore` file
@@ -371,6 +346,10 @@ tasks:
> TIP: method `none` skips any validation and always run the task.
> NOTE: for the `checksum` (default) method to work, it's only necessary to
> inform the source files, but if you want to use the `timestamp` method, you
> also need to inform the generated files with `generates`.
### Using programmatic checks to indicate a task is up to date.
Alternatively, you can inform a sequence of tests as `status`. If no error
@@ -451,18 +430,19 @@ with any other tasks that depend on it.
```yaml
version: '3'
tasks:
task_will_fail:
task-will-fail:
preconditions:
- sh: "exit 1"
task_will_also_fail:
task-will-also-fail:
deps:
- task_will_fail
- task-will-fail
task_will_still_fail:
task-will-still-fail:
cmds:
- task: task_will_fail
- task: task-will-fail
- echo "I will not run"
```
@@ -472,10 +452,9 @@ When doing interpolation of variables, Task will look for the below.
They are listed below in order of importance (e.g. most important first):
- Variables declared in the task definition
- Variables given while calling a task from another.
- Variables given while calling a task from another
(See [Calling another task](#calling-another-task) above)
- Variables declared in the `vars:` option in the `Taskfile`
- Variables available in the `Taskvars.yml` file
- Global variables (those declared in the `vars:` option in the Taskfile)
- Environment variables
Example of sending parameters with environment variables:
@@ -484,11 +463,12 @@ Example of sending parameters with environment variables:
$ TASK_VARIABLE=a-value task do-something
```
> TIP: A special variable `.TASK` is always available containg the task name.
> TIP: A special variable `.TASK` is always available containing the task name.
Since some shells don't support above syntax to set environment variables
(Windows) tasks also accepts a similar style when not in the beginning of
the command.
```bash
$ task write-file FILE=file.txt "CONTENT=Hello, World!" print "MESSAGE=All done!"
```
@@ -520,38 +500,6 @@ tasks:
- echo "{{.GREETING}}"
```
Example of `Taskvars.yml` file:
```yaml
PROJECT_NAME: My Project
DEV_MODE: production
GIT_COMMIT: {sh: git log -n 1 --format=%h}
```
### Variables expansion
Variables are expanded 2 times by default. You can change that by setting the
`expansions:` option. Change that will be necessary if you compose many
variables together:
```yaml
version: '3'
expansions: 3
vars:
FOO: foo
BAR: bar
BAZ: baz
FOOBAR: "{{.FOO}}{{.BAR}}"
FOOBARBAZ: "{{.FOOBAR}}{{.BAZ}}"
tasks:
default:
cmds:
- echo "{{.FOOBARBAZ}}"
```
### Dynamic variables
The below syntax (`sh:` prop in a variable) is considered a dynamic variable.
@@ -712,7 +660,7 @@ Please note: *showing the summary will not execute the command*.
## Overriding task name
Sometimes you may want to override the task name print on summary, up-to-date
messates to STDOUT, etc. In this case you can just set `label:`, which can also
messages to STDOUT, etc. In this case you can just set `label:`, which can also
be interpolated with variables:
```yaml
@@ -917,7 +865,7 @@ $ task default
## Short task syntax
Starting on Task v3, you can now write tasks with a shorter syntax if they
have the default settings (e.g. no custom `env:`, `vars:`, `silent:` , etc):
have the default settings (e.g. no custom `env:`, `vars:`, `desc:`, `silent:` , etc):
```yaml
version: '3'
@@ -925,16 +873,16 @@ version: '3'
tasks:
build: go build -v -o ./app{{exeExt}} .
build:
run:
- task: build
- ./app{{exeExt}} -h localhost -p 8080
```
## Watch tasks
If you give a `--watch` or `-w` argument, task will watch for file changes
With the flags `--watch` or `-w` task will watch for file changes
and run the task again. This requires the `sources` attribute to be given,
so task know which files to watch.
so task knows which files to watch.
[gotemplate]: https://golang.org/pkg/text/template/
[minify]: https://github.com/tdewolff/minify/tree/master/cmd/minify

4
go.mod
View File

@@ -9,9 +9,9 @@ require (
github.com/radovskyb/watcher v1.0.5
github.com/spf13/pflag v1.0.3
github.com/stretchr/testify v1.5.1
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
mvdan.cc/sh/v3 v3.1.2
mvdan.cc/sh/v3 v3.2.1
)
go 1.13

30
go.sum
View File

@@ -1,5 +1,5 @@
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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=
@@ -15,25 +15,23 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-zglob v0.0.1 h1:xsEx/XUoVlI6yXjqBK062zYhRTZltCNmYPx6v+8DNaY=
github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
github.com/pkg/diff v0.0.0-20190930165518-531926345625/go.mod h1:kFj35MyHn14a6pIgWhm46KVjJr5CHys3eEYxkuKD1EI=
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/radovskyb/watcher v1.0.5 h1:wqt7gb+HjGacvFoLTKeT44C+XVPxu7bvHvKT1IvZ7rw=
github.com/radovskyb/watcher v1.0.5/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -42,27 +40,23 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867 h1:JoRuNIf+rpHl+VhScRQQvzbHed86tKkqwPMV34T8myw=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM=
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407 h1:5zh5atpUEdIc478E/ebrIaHLKcfVvG6dL/fGv7BcMoM=
golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mvdan.cc/editorconfig v0.1.1-0.20200121172147-e40951bde157/go.mod h1:Ge4atmRUYqueGppvJ7JNrtqpqokoJEFxYbP0Z+WeKS8=
mvdan.cc/sh/v3 v3.1.2 h1:PG5BYlwtrkZTbJXUy25r0/q9shB5ObttCaknkOIB1XQ=
mvdan.cc/sh/v3 v3.1.2/go.mod h1:F+Vm4ZxPJxDKExMLhvjuI50oPnedVXpfjNSrusiTOno=
mvdan.cc/sh/v3 v3.2.1 h1:uQBpiGM+rEuHse3Q+W7ajuJUeOtFVJUN/6GeX4/dUWE=
mvdan.cc/sh/v3 v3.2.1/go.mod h1:fPQmabBpREM/XQ9YXSU5ZFZ/Sm+PmKP9/vkFHgYKJEI=

View File

@@ -6,7 +6,7 @@ import (
"text/tabwriter"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/taskfile"
)
// PrintTasksHelp prints help os tasks that have a description

View File

@@ -1,12 +1,13 @@
package compiler
import (
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/taskfile"
)
// Compiler handles compilation of a task before its execution.
// E.g. variable merger, template processing, etc.
type Compiler interface {
GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error)
HandleDynamicVar(v taskfile.Var) (string, error)
HandleDynamicVar(v taskfile.Var, dir string) (string, error)
ResetCache()
}

View File

@@ -4,7 +4,7 @@ import (
"os"
"strings"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/taskfile"
)
// GetEnviron the all return all environment variables encapsulated on a

View File

@@ -4,14 +4,15 @@ import (
"bytes"
"context"
"fmt"
"path/filepath"
"strings"
"sync"
"github.com/go-task/task/v3/internal/compiler"
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/internal/templater"
"github.com/go-task/task/v3/taskfile"
)
var _ compiler.Compiler = &CompilerV2{}
@@ -37,8 +38,20 @@ type CompilerV2 struct {
// 4. Taskvars file variables
// 5. Environment variables
func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
vr := varResolver{c: c, vars: compiler.GetEnviron()}
// NOTE(@andreynering): We're manually joining these paths here because
// this is the raw task, not the compiled one.
dir := t.Dir
if !filepath.IsAbs(dir) {
dir = filepath.Join(c.Dir, dir)
}
vr := varResolver{
c: c,
dir: dir,
vars: compiler.GetEnviron(),
}
vr.vars.Set("TASK", taskfile.Var{Static: t.Task})
for _, vars := range []*taskfile.Vars{c.Taskvars, c.TaskfileVars, call.Vars, t.Vars} {
for i := 0; i < c.Expansions; i++ {
vr.merge(vars)
@@ -49,6 +62,7 @@ func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi
type varResolver struct {
c *CompilerV2
dir string
vars *taskfile.Vars
err error
}
@@ -63,7 +77,7 @@ func (vr *varResolver) merge(vars *taskfile.Vars) {
Static: tr.Replace(v.Static),
Sh: tr.Replace(v.Sh),
}
static, err := vr.c.HandleDynamicVar(v)
static, err := vr.c.HandleDynamicVar(v, vr.dir)
if err != nil {
vr.err = err
return err
@@ -74,7 +88,7 @@ func (vr *varResolver) merge(vars *taskfile.Vars) {
vr.err = tr.Err()
}
func (c *CompilerV2) HandleDynamicVar(v taskfile.Var) (string, error) {
func (c *CompilerV2) HandleDynamicVar(v taskfile.Var, dir string) (string, error) {
if v.Static != "" || v.Sh == "" {
return v.Static, nil
}
@@ -92,7 +106,7 @@ func (c *CompilerV2) HandleDynamicVar(v taskfile.Var) (string, error) {
var stdout bytes.Buffer
opts := &execext.RunCommandOptions{
Command: v.Sh,
Dir: c.Dir,
Dir: dir,
Stdout: &stdout,
Stderr: c.Logger.Stderr,
}
@@ -109,3 +123,11 @@ func (c *CompilerV2) HandleDynamicVar(v taskfile.Var) (string, error) {
return result, nil
}
// ResetCache clear the dymanic variables cache
func (c *CompilerV2) ResetCache() {
c.muDynamicCache.Lock()
defer c.muDynamicCache.Unlock()
c.dynamicCache = nil
}

View File

@@ -4,14 +4,15 @@ import (
"bytes"
"context"
"fmt"
"path/filepath"
"strings"
"sync"
"github.com/go-task/task/v3/internal/compiler"
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/internal/templater"
"github.com/go-task/task/v3/taskfile"
)
var _ compiler.Compiler = &CompilerV3{}
@@ -31,6 +32,13 @@ func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi
result := compiler.GetEnviron()
result.Set("TASK", taskfile.Var{Static: t.Task})
// NOTE(@andreynering): We're manually joining these paths here because
// this is the raw task, not the compiled one.
dir := t.Dir
if !filepath.IsAbs(dir) {
dir = filepath.Join(c.Dir, dir)
}
rangeFunc := func(k string, v taskfile.Var) error {
tr := templater.Templater{Vars: result, RemoveNoValue: true}
v = taskfile.Var{
@@ -40,7 +48,7 @@ func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi
if err := tr.Err(); err != nil {
return err
}
static, err := c.HandleDynamicVar(v)
static, err := c.HandleDynamicVar(v, dir)
if err != nil {
return err
}
@@ -61,7 +69,7 @@ func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi
return result, nil
}
func (c *CompilerV3) HandleDynamicVar(v taskfile.Var) (string, error) {
func (c *CompilerV3) HandleDynamicVar(v taskfile.Var, dir string) (string, error) {
if v.Static != "" || v.Sh == "" {
return v.Static, nil
}
@@ -79,7 +87,7 @@ func (c *CompilerV3) HandleDynamicVar(v taskfile.Var) (string, error) {
var stdout bytes.Buffer
opts := &execext.RunCommandOptions{
Command: v.Sh,
Dir: c.Dir,
Dir: dir,
Stdout: &stdout,
Stderr: c.Logger.Stderr,
}
@@ -96,3 +104,11 @@ func (c *CompilerV3) HandleDynamicVar(v taskfile.Var) (string, error) {
return result, nil
}
// ResetCache clear the dymanic variables cache
func (c *CompilerV3) ResetCache() {
c.muDynamicCache.Lock()
defer c.muDynamicCache.Unlock()
c.dynamicCache = nil
}

View File

@@ -46,16 +46,10 @@ func RunCommand(ctx context.Context, opts *RunCommandOptions) error {
}
r, err := interp.New(
interp.Params("-e"),
interp.Dir(opts.Dir),
interp.Env(expand.ListEnviron(environ...)),
interp.OpenHandler(func(ctx context.Context, path string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
if path == "/dev/null" {
return devNull{}, nil
}
return interp.DefaultOpenHandler()(ctx, path, flag, perm)
}),
interp.OpenHandler(openHandler),
interp.StdIO(opts.Stdin, opts.Stdout, opts.Stderr),
)
if err != nil {
@@ -86,3 +80,10 @@ func Expand(s string) (string, error) {
}
return "", nil
}
func openHandler(ctx context.Context, path string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
if path == "/dev/null" {
return devNull{}, nil
}
return interp.DefaultOpenHandler()(ctx, path, flag, perm)
}

View File

@@ -6,9 +6,9 @@ import (
"io"
"testing"
"github.com/go-task/task/v3/internal/output"
"github.com/stretchr/testify/assert"
"github.com/go-task/task/v3/internal/output"
)
func TestInterleaved(t *testing.T) {

View File

@@ -14,7 +14,8 @@ import (
// Checksum validades if a task is up to date by calculating its source
// files checksum
type Checksum struct {
Dir string
BaseDir string
TaskDir string
Task string
Sources []string
Generates []string
@@ -32,7 +33,7 @@ func (c *Checksum) IsUpToDate() (bool, error) {
data, _ := ioutil.ReadFile(checksumFile)
oldMd5 := strings.TrimSpace(string(data))
sources, err := globs(c.Dir, c.Sources)
sources, err := globs(c.TaskDir, c.Sources)
if err != nil {
return false, err
}
@@ -43,7 +44,7 @@ func (c *Checksum) IsUpToDate() (bool, error) {
}
if !c.Dry {
_ = os.MkdirAll(filepath.Join(c.Dir, ".task", "checksum"), 0755)
_ = os.MkdirAll(filepath.Join(c.BaseDir, ".task", "checksum"), 0755)
if err = ioutil.WriteFile(checksumFile, []byte(newMd5+"\n"), 0644); err != nil {
return false, err
}
@@ -52,7 +53,7 @@ func (c *Checksum) IsUpToDate() (bool, error) {
if len(c.Generates) > 0 {
// For each specified 'generates' field, check whether the files actually exist
for _, g := range c.Generates {
generates, err := glob(c.Dir, g)
generates, err := glob(c.TaskDir, g)
if os.IsNotExist(err) {
return false, nil
}
@@ -107,7 +108,7 @@ func (*Checksum) Kind() string {
}
func (c *Checksum) checksumFilePath() string {
return filepath.Join(c.Dir, ".task", "checksum", c.normalizeFilename(c.Task))
return filepath.Join(c.BaseDir, ".task", "checksum", c.normalizeFilename(c.Task))
}
var checksumFilenameRegexp = regexp.MustCompile("[^A-z0-9]")

View File

@@ -5,9 +5,9 @@ import (
"path/filepath"
"sort"
"github.com/go-task/task/v3/internal/execext"
"github.com/mattn/go-zglob"
"github.com/go-task/task/v3/internal/execext"
)
func globs(dir string, globs []string) ([]string, error) {

View File

@@ -4,7 +4,7 @@ import (
"strings"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/taskfile"
)
func PrintTasks(l *logger.Logger, t *taskfile.Taskfile, c []taskfile.Call) {

View File

@@ -5,11 +5,11 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/summary"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/stretchr/testify/assert"
"github.com/go-task/task/v3/taskfile"
)
func TestPrintsDependenciesIfPresent(t *testing.T) {

View File

@@ -1,40 +0,0 @@
package taskfile
import "errors"
var (
// ErrCantUnmarshalIncludedTaskfile is returned for invalid var YAML.
ErrCantUnmarshalIncludedTaskfile = errors.New("task: can't unmarshal included value")
)
// IncludedTaskfile represents information about included tasksfile
type IncludedTaskfile struct {
Taskfile string
Dir string
AdvancedImport bool
}
// IncludedTaskfiles represents information about included tasksfiles
type IncludedTaskfiles = map[string]IncludedTaskfile
// UnmarshalYAML implements yaml.Unmarshaler interface
func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
var str string
if err := unmarshal(&str); err == nil {
it.Taskfile = str
return nil
}
var includedTaskfile struct {
Taskfile string
Dir string
}
if err := unmarshal(&includedTaskfile); err == nil {
it.Dir = includedTaskfile.Dir
it.Taskfile = includedTaskfile.Taskfile
it.AdvancedImport = true
return nil
}
return ErrCantUnmarshalIncludedTaskfile
}

View File

@@ -5,7 +5,7 @@ import (
"strings"
"text/template"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/taskfile"
)
// Templater is a help struct that allow us to call "replaceX" funcs multiple

View File

@@ -6,7 +6,7 @@ import (
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/taskfile"
)
var (

View File

@@ -7,7 +7,7 @@ import (
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/status"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/taskfile"
)
// Status returns an error if any the of given tasks is not up-to-date
@@ -76,8 +76,9 @@ func (e *Executor) timestampChecker(t *taskfile.Task) status.Checker {
func (e *Executor) checksumChecker(t *taskfile.Task) status.Checker {
return &status.Checksum{
Dir: t.Dir,
Task: t.Task,
BaseDir: e.Dir,
TaskDir: t.Dir,
Task: t.Name(),
Sources: t.Sources,
Generates: t.Generates,
Dry: e.Dry,

12
task.go
View File

@@ -16,8 +16,8 @@ import (
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/output"
"github.com/go-task/task/v3/internal/summary"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/internal/taskfile/read"
"github.com/go-task/task/v3/taskfile"
"github.com/go-task/task/v3/taskfile/read"
"golang.org/x/sync/errgroup"
)
@@ -176,7 +176,7 @@ func (e *Executor) Setup() error {
if v < 2.1 && e.Taskfile.Output != "" {
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
}
if v < 2.2 && len(e.Taskfile.Includes) > 0 {
if v < 2.2 && e.Taskfile.Includes.Len() > 0 {
return fmt.Errorf(`task: Including Taskfiles is only available starting on Taskfile version v2.2`)
}
if v >= 3.0 && e.Taskfile.Expansions > 2 {
@@ -229,10 +229,14 @@ func (e *Executor) Setup() error {
}
if v < 3 {
for _, taskfile := range e.Taskfile.Includes {
err := e.Taskfile.Includes.Range(func(_ string, taskfile taskfile.IncludedTaskfile) error {
if taskfile.AdvancedImport {
return errors.New(`task: Import with additional parameters is only available starting on Taskfile version v3`)
}
return nil
})
if err != nil {
return err
}
}

View File

@@ -11,10 +11,10 @@ import (
"strings"
"testing"
"github.com/go-task/task/v3"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/stretchr/testify/assert"
"github.com/go-task/task/v3"
"github.com/go-task/task/v3/taskfile"
)
// fileContentTest provides a basic reusable test-case for running a Taskfile
@@ -56,6 +56,16 @@ func (fct fileContentTest) Run(t *testing.T) {
}
}
func TestEmptyTask(t *testing.T) {
e := &task.Executor{
Dir: "testdata/empty_task",
Stdout: ioutil.Discard,
Stderr: ioutil.Discard,
}
assert.NoError(t, e.Setup(), "e.Setup()")
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "default"}))
}
func TestEnv(t *testing.T) {
tt := fileContentTest{
Dir: "testdata/env",
@@ -293,16 +303,15 @@ func TestPrecondition(t *testing.T) {
}
func TestGenerates(t *testing.T) {
const dir = "testdata/generates"
const (
srcTask = "sub/src.txt"
relTask = "rel.txt"
absTask = "abs.txt"
absTask = "sub/abs.txt"
fileWithSpaces = "my text file.txt"
)
// This test does not work with a relative dir.
dir, err := filepath.Abs("testdata/generates")
assert.NoError(t, err)
var srcFile = filepath.Join(dir, srcTask)
for _, task := range []string{srcTask, relTask, absTask, fileWithSpaces} {
@@ -790,6 +799,18 @@ func TestWhenDirAttributeItCreatesMissingAndRunsInThatDir(t *testing.T) {
_ = os.RemoveAll(toBeCreated)
}
func TestDynamicVariablesShouldRunOnTheTaskDir(t *testing.T) {
tt := fileContentTest{
Dir: "testdata/dir/dynamic_var",
Target: "default",
TrimSpace: false,
Files: map[string]string{
"subdirectory/dir.txt": "subdirectory\n",
},
}
tt.Run(t)
}
func TestDisplaysErrorOnUnsupportedVersion(t *testing.T) {
e := task.Executor{
Dir: "testdata/version/v1",
@@ -819,7 +840,7 @@ func TestShortTaskNotation(t *testing.T) {
func TestDotenvShouldIncludeAllEnvFiles(t *testing.T) {
tt := fileContentTest{
Dir: "testdata/dotenv",
Dir: "testdata/dotenv/default",
Target: "default",
TrimSpace: false,
Files: map[string]string{
@@ -829,26 +850,9 @@ func TestDotenvShouldIncludeAllEnvFiles(t *testing.T) {
tt.Run(t)
}
func TestDotenvShouldErrorWithIncludeEnvPath(t *testing.T) {
const dir = "testdata/dotenv"
const entry = "Taskfile-errors1.yml"
var buff bytes.Buffer
e := task.Executor{
Dir: dir,
Entrypoint: entry,
Summary: true,
Stdout: &buff,
Stderr: &buff,
}
err := e.Setup()
assert.Error(t, err)
assert.Contains(t, err.Error(), "no such file")
}
func TestDotenvShouldErrorWhenIncludingDependantDotenvs(t *testing.T) {
const dir = "testdata/dotenv"
const entry = "Taskfile-errors2.yml"
const dir = "testdata/dotenv/error_included_envs"
const entry = "Taskfile.yml"
var buff bytes.Buffer
e := task.Executor{
@@ -863,3 +867,31 @@ func TestDotenvShouldErrorWhenIncludingDependantDotenvs(t *testing.T) {
assert.Error(t, err)
assert.Contains(t, err.Error(), "move the dotenv")
}
func TestDotenvShouldAllowMissingEnv(t *testing.T) {
tt := fileContentTest{
Dir: "testdata/dotenv/missing_env",
Target: "default",
TrimSpace: false,
Files: map[string]string{
"include.txt": "INCLUDE1='' INCLUDE2=''\n",
},
}
tt.Run(t)
}
func TestExitImmediately(t *testing.T) {
const dir = "testdata/exit_immediately"
var buff bytes.Buffer
e := task.Executor{
Dir: dir,
Stdout: &buff,
Stderr: &buff,
Silent: true,
}
assert.NoError(t, e.Setup())
assert.Error(t, e.Run(context.Background(), taskfile.Call{Task: "default"}))
assert.Contains(t, buff.String(), `"this_should_fail": executable file not found in $PATH`)
}

View File

@@ -0,0 +1,109 @@
package taskfile
import (
"errors"
"gopkg.in/yaml.v3"
)
var (
// ErrCantUnmarshalIncludedTaskfile is returned for invalid var YAML.
ErrCantUnmarshalIncludedTaskfile = errors.New("task: can't unmarshal included value")
)
// IncludedTaskfile represents information about included tasksfile
type IncludedTaskfile struct {
Taskfile string
Dir string
AdvancedImport bool
}
// IncludedTaskfiles represents information about included tasksfiles
type IncludedTaskfiles struct {
Keys []string
Mapping map[string]IncludedTaskfile
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (tfs *IncludedTaskfiles) UnmarshalYAML(node *yaml.Node) error {
if node.Kind != yaml.MappingNode {
return errors.New("task: includes is not a map")
}
// NOTE(@andreynering): on this style of custom unmarsheling,
// even number contains the keys, while odd numbers contains
// the values.
for i := 0; i < len(node.Content); i += 2 {
keyNode := node.Content[i]
valueNode := node.Content[i+1]
var v IncludedTaskfile
if err := valueNode.Decode(&v); err != nil {
return err
}
tfs.Set(keyNode.Value, v)
}
return nil
}
// Len returns the length of the map
func (tfs *IncludedTaskfiles) Len() int {
if tfs == nil {
return 0
}
return len(tfs.Keys)
}
// Merge merges the given IncludedTaskfiles into the caller one
func (tfs *IncludedTaskfiles) Merge(other *IncludedTaskfiles) {
other.Range(func(key string, value IncludedTaskfile) error {
tfs.Set(key, value)
return nil
})
}
// Set sets a value to a given key
func (tfs *IncludedTaskfiles) Set(key string, includedTaskfile IncludedTaskfile) {
if tfs.Mapping == nil {
tfs.Mapping = make(map[string]IncludedTaskfile, 1)
}
if !stringSliceContains(tfs.Keys, key) {
tfs.Keys = append(tfs.Keys, key)
}
tfs.Mapping[key] = includedTaskfile
}
// Range allows you to loop into the included taskfiles in its right order
func (tfs *IncludedTaskfiles) Range(yield func(key string, includedTaskfile IncludedTaskfile) error) error {
if tfs == nil {
return nil
}
for _, k := range tfs.Keys {
if err := yield(k, tfs.Mapping[k]); err != nil {
return err
}
}
return nil
}
// UnmarshalYAML implements yaml.Unmarshaler interface
func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
var str string
if err := unmarshal(&str); err == nil {
it.Taskfile = str
return nil
}
var includedTaskfile struct {
Taskfile string
Dir string
}
if err := unmarshal(&includedTaskfile); err == nil {
it.Dir = includedTaskfile.Dir
it.Taskfile = includedTaskfile.Taskfile
it.AdvancedImport = true
return nil
}
return ErrCantUnmarshalIncludedTaskfile
}

View File

@@ -22,11 +22,9 @@ func Merge(t1, t2 *Taskfile, namespaces ...string) error {
}
if t1.Includes == nil {
t1.Includes = make(IncludedTaskfiles)
}
for k, v := range t2.Includes {
t1.Includes[k] = v
t1.Includes = &IncludedTaskfiles{}
}
t1.Includes.Merge(t2.Includes)
if t1.Vars == nil {
t1.Vars = &Vars{}

View File

@@ -3,10 +3,10 @@ package taskfile_test
import (
"testing"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"github.com/go-task/task/v3/taskfile"
)
func TestPreconditionParse(t *testing.T) {

View File

@@ -7,11 +7,11 @@ import (
"path/filepath"
"runtime"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/internal/templater"
"github.com/joho/godotenv"
"gopkg.in/yaml.v3"
"github.com/go-task/task/v3/internal/templater"
"github.com/go-task/task/v3/taskfile"
)
var (
@@ -37,11 +37,15 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
return nil, err
}
if v >= 3.0 && len(t.Dotenv) > 0 {
if v >= 3.0 {
for _, dotEnvPath := range t.Dotenv {
if !filepath.IsAbs(dotEnvPath) {
dotEnvPath = filepath.Join(dir, dotEnvPath)
}
if _, err := os.Stat(dotEnvPath); os.IsNotExist(err) {
continue
}
envs, err := godotenv.Read(dotEnvPath)
if err != nil {
return nil, err
@@ -54,7 +58,7 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
}
}
for namespace, includedTask := range t.Includes {
err = t.Includes.Range(func(namespace string, includedTask taskfile.IncludedTaskfile) error {
if v >= 3.0 {
tr := templater.Templater{Vars: &taskfile.Vars{}, RemoveNoValue: true}
includedTask = taskfile.IncludedTaskfile{
@@ -63,7 +67,7 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
AdvancedImport: includedTask.AdvancedImport,
}
if err := tr.Err(); err != nil {
return nil, err
return err
}
}
@@ -75,21 +79,21 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
info, err := os.Stat(path)
if err != nil {
return nil, err
return err
}
if info.IsDir() {
path = filepath.Join(path, "Taskfile.yml")
}
includedTaskfile, err := readTaskfile(path)
if err != nil {
return nil, err
return err
}
if len(includedTaskfile.Includes) > 0 {
return nil, ErrIncludedTaskfilesCantHaveIncludes
if includedTaskfile.Includes.Len() > 0 {
return ErrIncludedTaskfilesCantHaveIncludes
}
if v >= 3.0 && len(includedTaskfile.Dotenv) > 0 {
return nil, ErrIncludedTaskfilesCantHaveDotenvs
return ErrIncludedTaskfilesCantHaveDotenvs
}
if includedTask.AdvancedImport {
@@ -101,8 +105,12 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
}
if err = taskfile.Merge(t, includedTaskfile, namespace); err != nil {
return nil, err
return err
}
return nil
})
if err != nil {
return nil, err
}
if v < 3.0 {
@@ -119,6 +127,10 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
}
for name, task := range t.Tasks {
if task == nil {
task = &taskfile.Task{}
t.Tasks[name] = task
}
task.Task = name
}

View File

@@ -6,9 +6,9 @@ import (
"path/filepath"
"runtime"
"github.com/go-task/task/v3/internal/taskfile"
"gopkg.in/yaml.v3"
"github.com/go-task/task/v3/taskfile"
)
// Taskvars reads a Taskvars for a given directory

10
taskfile/slice.go Normal file
View File

@@ -0,0 +1,10 @@
package taskfile
func stringSliceContains(s []string, str string) bool {
for _, v := range s {
if v == str {
return true
}
}
return false
}

View File

@@ -11,7 +11,7 @@ type Taskfile struct {
Expansions int
Output string
Method string
Includes IncludedTaskfiles
Includes *IncludedTaskfiles
Vars *Vars
Env *Vars
Tasks Tasks
@@ -26,12 +26,12 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
Expansions int
Output string
Method string
Includes IncludedTaskfiles
Includes *IncludedTaskfiles
Vars *Vars
Env *Vars
Tasks Tasks
Silent bool
Dotenv []string
Dotenv []string
}
if err := unmarshal(&taskfile); err != nil {
return err

View File

@@ -3,10 +3,10 @@ package taskfile_test
import (
"testing"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"github.com/go-task/task/v3/taskfile"
)
func TestCmdParse(t *testing.T) {

View File

@@ -53,21 +53,12 @@ func (vs *Vars) Set(key string, value Var) {
if vs.Mapping == nil {
vs.Mapping = make(map[string]Var, 1)
}
if !strSliceContains(vs.Keys, key) {
if !stringSliceContains(vs.Keys, key) {
vs.Keys = append(vs.Keys, key)
}
vs.Mapping[key] = value
}
func strSliceContains(s []string, str string) bool {
for _, v := range s {
if v == str {
return true
}
}
return false
}
// Range allows you to loop into the vars in its right order
func (vs *Vars) Range(yield func(key string, value Var) error) error {
if vs == nil {

1
testdata/dir/dynamic_var/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
subdirectory/dir.txt

11
testdata/dir/dynamic_var/Taskfile.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
version: '3'
tasks:
default:
cmds:
- echo '{{.FOLDER}}' > dir.txt
dir: subdirectory
vars:
FOLDER:
sh: basename $(pwd)
silent: true

View File

@@ -0,0 +1 @@
subdirectory

View File

@@ -1,8 +1,8 @@
version: '3'
dotenv: ['include1/.env', 'include1/envs/.env', 'file-does-not-exist']
dotenv: ['../include1/.env', '../include1/envs/.env']
tasks:
default:
cmds:
- echo "INCLUDE1='$INCLUDE1' INCLUDE2='$INCLUDE2'" > include-errors1.txt
- echo "INCLUDE1='$INCLUDE1' INCLUDE2='$INCLUDE2'" > include.txt

View File

@@ -1,7 +1,7 @@
version: '3'
includes:
include1: './include1'
include1: '../include1'
tasks:
default:

View File

@@ -1,6 +1,6 @@
version: '3'
dotenv: ['include1/.env', 'include1/envs/.env']
dotenv: ['.env']
tasks:
default:

4
testdata/empty_task/Taskfile.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
version: '3'
tasks:
default:

View File

@@ -0,0 +1,6 @@
version: '3'
tasks:
default: |
this_should_fail
echo "This shoudn't be print"

View File

@@ -4,7 +4,7 @@ vars:
BUILD_DIR: $pwd
tasks:
abs.txt:
sub/abs.txt:
desc: generates dest file based on absolute paths
deps:
- sub/src.txt

0
testdata/generates/sub/.keep vendored Normal file
View File

View File

@@ -6,8 +6,8 @@ import (
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/status"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/internal/templater"
"github.com/go-task/task/v3/taskfile"
)
// CompiledTask returns a copy of a task, but replacing variables in almost all
@@ -60,7 +60,7 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
new.Env.Merge(r.ReplaceVars(e.Taskfile.Env))
new.Env.Merge(r.ReplaceVars(origTask.Env))
err = new.Env.Range(func(k string, v taskfile.Var) error {
static, err := e.Compiler.HandleDynamicVar(v)
static, err := e.Compiler.HandleDynamicVar(v, new.Dir)
if err != nil {
return err
}

View File

@@ -4,20 +4,18 @@ import (
"context"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/taskfile"
"github.com/go-task/task/v3/taskfile"
"github.com/mattn/go-zglob"
"github.com/radovskyb/watcher"
)
var watchIgnoredDirs = []string{
".git",
"node_modules",
}
const watchInterval = 5 * time.Second
// watchTasks start watching the given tasks
func (e *Executor) watchTasks(calls ...taskfile.Call) error {
@@ -40,9 +38,6 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
w := watcher.New()
defer w.Close()
w.SetMaxEvents(1)
if err := w.Ignore(watchIgnoredDirs...); err != nil {
return err
}
closeOnInterrupt(w)
@@ -54,6 +49,9 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
cancel()
ctx, cancel = context.WithCancel(context.Background())
e.Compiler.ResetCache()
for _, c := range calls {
c := c
go func() {
@@ -65,9 +63,6 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
case err := <-w.Error:
switch err {
case watcher.ErrWatchedFileDeleted:
go func() {
w.TriggerEvent(watcher.Remove, nil)
}()
default:
e.Logger.Errf(logger.Red, "%v", err)
}
@@ -79,16 +74,16 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
}()
go func() {
// re-register each second because we can have new files
// re-register every 5 seconds because we can have new files, but this process is expensive to run
for {
if err := e.registerWatchedFiles(w, calls...); err != nil {
e.Logger.Errf(logger.Red, "%v", err)
}
time.Sleep(time.Second)
time.Sleep(watchInterval)
}
}()
return w.Start(time.Second)
return w.Start(watchInterval)
}
func isContextError(err error) bool {
@@ -109,16 +104,7 @@ func closeOnInterrupt(w *watcher.Watcher) {
}
func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Call) error {
oldWatchedFiles := make(map[string]struct{})
for f := range w.WatchedFiles() {
oldWatchedFiles[f] = struct{}{}
}
for f := range oldWatchedFiles {
if err := w.Remove(f); err != nil {
return err
}
}
watchedFiles := w.WatchedFiles()
var registerTaskFiles func(taskfile.Call) error
registerTaskFiles = func(c taskfile.Call) error {
@@ -146,12 +132,20 @@ func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Ca
return err
}
for _, f := range files {
if _, ok := oldWatchedFiles[f]; ok {
continue
}
if err := w.Add(f); err != nil {
absFile, err := filepath.Abs(f)
if err != nil {
return err
}
if shouldIgnoreFile(absFile) {
continue
}
if _, ok := watchedFiles[absFile]; ok {
continue
}
if err := w.Add(absFile); err != nil {
return err
}
e.Logger.VerboseOutf(logger.Green, "task: watching new file: %v", absFile)
}
}
return nil
@@ -164,3 +158,7 @@ func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Ca
}
return nil
}
func shouldIgnoreFile(path string) bool {
return strings.Contains(path, "/.git") || strings.Contains(path, "/.task") || strings.Contains(path, "/node_modules")
}