mirror of
https://github.com/go-task/task.git
synced 2025-06-15 00:15:10 +02:00
Merge branch 'master' into feature/include
This commit is contained in:
@ -9,6 +9,6 @@ trim_trailing_whitespace = true
|
|||||||
indent_style = tab
|
indent_style = tab
|
||||||
indent_size = 8
|
indent_size = 8
|
||||||
|
|
||||||
[*.{md,yml,yaml,json,toml}]
|
[*.{md,yml,yaml,json,toml,htm,html}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
787
README.md
787
README.md
@ -1,789 +1,12 @@
|
|||||||
[](https://travis-ci.org/go-task/task)
|
[](https://travis-ci.org/go-task/task)
|
||||||
|
|
||||||
# Task - A task runner / simpler Make alternative written in Go
|
# Task
|
||||||
|
|
||||||
> We recently released version 2.0.0 of Task. The Taskfile changed a bit.
|
Task is a task runner / build tool that aims to be simpler and easier to use
|
||||||
Please, check the [Taskfile versions](TASKFILE_VERSIONS.md) document to see
|
than, for example, [GNU Make][make].
|
||||||
what changed and how to upgrade.
|
|
||||||
|
|
||||||
Task is a simple tool that allows you to easily run development and build
|
---
|
||||||
tasks. Task is written in Golang, but can be used to develop any language.
|
|
||||||
It aims to be simpler and easier to use then [GNU Make][make].
|
|
||||||
|
|
||||||
- [Installation](#installation)
|
See [taskfile.org](https://taskfile.org) for documentation.
|
||||||
- [Go](#go)
|
|
||||||
- [Homebrew](#homebrew)
|
|
||||||
- [Snap](#snap)
|
|
||||||
- [Binary](#binary)
|
|
||||||
- [Usage](#usage)
|
|
||||||
- [Environment](#environment)
|
|
||||||
- [OS specific task](#os-specific-task)
|
|
||||||
- [Task directory](#task-directory)
|
|
||||||
- [Task dependencies](#task-dependencies)
|
|
||||||
- [Calling another task](#calling-another-task)
|
|
||||||
- [Prevent unnecessary work](#prevent-unnecessary-work)
|
|
||||||
- [Variables](#variables)
|
|
||||||
- [Dynamic variables](#dynamic-variables)
|
|
||||||
- [Go's template engine](#gos-template-engine)
|
|
||||||
- [Help](#help)
|
|
||||||
- [Silent mode](#silent-mode)
|
|
||||||
- [Dry run mode](#dry-run-mode)
|
|
||||||
- [Ignore errors](#ignore-errors)
|
|
||||||
- [Output syntax](#output-syntax)
|
|
||||||
- [Watch tasks](#watch-tasks-experimental)
|
|
||||||
- [Examples](#examples)
|
|
||||||
- [Alternative task runners](#alternative-task-runners)
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### Go
|
|
||||||
|
|
||||||
If you have a [Golang][golang] environment setup, you can simply run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go get -u -v github.com/go-task/task/cmd/task
|
|
||||||
```
|
|
||||||
|
|
||||||
### Homebrew
|
|
||||||
|
|
||||||
If you're on macOS and have [Homebrew][homebrew] installed, getting Task is
|
|
||||||
as simple as running:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew install go-task/tap/go-task
|
|
||||||
```
|
|
||||||
|
|
||||||
### Snap
|
|
||||||
|
|
||||||
Task is available for [Snapcraft][snapcraft], but keep in mind that your
|
|
||||||
Linux distribution should allow classic confinement for Snaps to Task work
|
|
||||||
right:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo snap install task
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install script
|
|
||||||
|
|
||||||
We also have a [install script][installscript], which is very useful on
|
|
||||||
scanarios like CIs. Many thanks to [godownloader][godownloader] for easily
|
|
||||||
generating this script.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -s https://raw.githubusercontent.com/go-task/task/master/install-task.sh | sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Binary
|
|
||||||
|
|
||||||
Or you can download the binary from the [releases][releases] page and add to
|
|
||||||
your `PATH`. DEB and RPM packages are also available.
|
|
||||||
The `task_checksums.txt` file contains the sha256 checksum for each file.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Create a file called `Taskfile.yml` in the root of your project.
|
|
||||||
The `cmds` attribute should contain the commands of a task.
|
|
||||||
The example below allows compiling a Go app and uses [Minify][minify] to concat
|
|
||||||
and minify multiple CSS files into a single one.
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
build:
|
|
||||||
cmds:
|
|
||||||
- go build -v -i main.go
|
|
||||||
|
|
||||||
assets:
|
|
||||||
cmds:
|
|
||||||
- minify -o public/style.css src/css
|
|
||||||
```
|
|
||||||
|
|
||||||
Running the tasks is as simple as running:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
task assets build
|
|
||||||
```
|
|
||||||
|
|
||||||
Task uses [github.com/mvdan/sh](https://github.com/mvdan/sh), a native Go sh
|
|
||||||
interpreter. So you can write sh/bash commands and it will work even on
|
|
||||||
Windows, where `sh` or `bash` are usually not available. Just remember any
|
|
||||||
executable called must be available by the OS or in PATH.
|
|
||||||
|
|
||||||
If you ommit a task name, "default" will be assumed.
|
|
||||||
|
|
||||||
### Environment
|
|
||||||
|
|
||||||
You can specify environment variables that are added when running a command:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
build:
|
|
||||||
cmds:
|
|
||||||
- echo $hallo
|
|
||||||
env:
|
|
||||||
hallo: welt
|
|
||||||
```
|
|
||||||
|
|
||||||
### OS specific task
|
|
||||||
|
|
||||||
If you add a `Taskfile_{{GOOS}}.yml` you can override or amend your Taskfile
|
|
||||||
based on the operating system.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
Taskfile.yml:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
build:
|
|
||||||
cmds:
|
|
||||||
- echo "default"
|
|
||||||
```
|
|
||||||
|
|
||||||
Taskfile_linux.yml:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
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`, `Taskfile_linux.yml`, or `Taskvars_darwin.yml`. See the
|
|
||||||
[variables section](#variables) below.
|
|
||||||
|
|
||||||
### Task directory
|
|
||||||
|
|
||||||
By default, tasks will be executed in the directory where the Taskfile is
|
|
||||||
located. But you can easily make the task run in another folder informing
|
|
||||||
`dir`:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
serve:
|
|
||||||
dir: public/www
|
|
||||||
cmds:
|
|
||||||
# run http server
|
|
||||||
- caddy
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task dependencies
|
|
||||||
|
|
||||||
You may have tasks that depend on others. Just pointing them on `deps` will
|
|
||||||
make them run automatically before running the parent task:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
build:
|
|
||||||
deps: [assets]
|
|
||||||
cmds:
|
|
||||||
- go build -v -i main.go
|
|
||||||
|
|
||||||
assets:
|
|
||||||
cmds:
|
|
||||||
- minify -o public/style.css src/css
|
|
||||||
```
|
|
||||||
|
|
||||||
In the above example, `assets` will always run right before `build` if you run
|
|
||||||
`task build`.
|
|
||||||
|
|
||||||
A task can have only dependencies and no commands to group tasks together:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
assets:
|
|
||||||
deps: [js, css]
|
|
||||||
|
|
||||||
js:
|
|
||||||
cmds:
|
|
||||||
- minify -o public/script.js src/js
|
|
||||||
|
|
||||||
css:
|
|
||||||
cmds:
|
|
||||||
- minify -o public/style.css src/css
|
|
||||||
```
|
|
||||||
|
|
||||||
If there is more than one dependency, they always run in parallel for better
|
|
||||||
performance.
|
|
||||||
|
|
||||||
If you want to pass information to dependencies, you can do that the same
|
|
||||||
manner as you would to [call another task](#calling-another-task):
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
default:
|
|
||||||
deps:
|
|
||||||
- task: echo_sth
|
|
||||||
vars: {TEXT: "before 1"}
|
|
||||||
- task: echo_sth
|
|
||||||
vars: {TEXT: "before 2"}
|
|
||||||
cmds:
|
|
||||||
- echo "after"
|
|
||||||
|
|
||||||
echo_sth:
|
|
||||||
cmds:
|
|
||||||
- echo {{.TEXT}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Calling another task
|
|
||||||
|
|
||||||
When a task has many dependencies, they are executed concurrently. This will
|
|
||||||
often result in a faster build pipeline. But in some situations you may need
|
|
||||||
to call other tasks serially. In this case, just use the following syntax:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
main-task:
|
|
||||||
cmds:
|
|
||||||
- task: task-to-be-called
|
|
||||||
- task: another-task
|
|
||||||
- echo "Both done"
|
|
||||||
|
|
||||||
task-to-be-called:
|
|
||||||
cmds:
|
|
||||||
- echo "Task to be called"
|
|
||||||
|
|
||||||
another-task:
|
|
||||||
cmds:
|
|
||||||
- echo "Another task"
|
|
||||||
```
|
|
||||||
|
|
||||||
Overriding variables in the called task is as simple as informing `vars`
|
|
||||||
attribute:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
main-task:
|
|
||||||
cmds:
|
|
||||||
- task: write-file
|
|
||||||
vars: {FILE: "hello.txt", CONTENT: "Hello!"}
|
|
||||||
- task: write-file
|
|
||||||
vars: {FILE: "world.txt", CONTENT: "World!"}
|
|
||||||
|
|
||||||
write-file:
|
|
||||||
cmds:
|
|
||||||
- echo "{{.CONTENT}}" > {{.FILE}}
|
|
||||||
```
|
|
||||||
|
|
||||||
The above syntax is also supported in `deps`.
|
|
||||||
|
|
||||||
### Prevent unnecessary work
|
|
||||||
|
|
||||||
If a task generates something, you can inform Task the source and generated
|
|
||||||
files, so Task will prevent to run them if not necessary.
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
build:
|
|
||||||
deps: [js, css]
|
|
||||||
cmds:
|
|
||||||
- go build -v -i main.go
|
|
||||||
|
|
||||||
js:
|
|
||||||
cmds:
|
|
||||||
- minify -o public/script.js src/js
|
|
||||||
sources:
|
|
||||||
- src/js/**/*.js
|
|
||||||
generates:
|
|
||||||
- public/script.js
|
|
||||||
|
|
||||||
css:
|
|
||||||
cmds:
|
|
||||||
- minify -o public/style.css src/css
|
|
||||||
sources:
|
|
||||||
- src/css/**/*.css
|
|
||||||
generates:
|
|
||||||
- public/style.css
|
|
||||||
```
|
|
||||||
|
|
||||||
`sources` and `generates` can be files or file patterns. When both are given,
|
|
||||||
Task will compare the modification date/time of the 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`.
|
|
||||||
|
|
||||||
If you prefer this check to be made by the content of the files, instead of
|
|
||||||
its timestamp, just set the `method` property to `checksum`.
|
|
||||||
You will probably want to ignore the `.task` folder in your `.gitignore` file
|
|
||||||
(It's there that Task stores the last checksum).
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
build:
|
|
||||||
cmds:
|
|
||||||
- go build .
|
|
||||||
sources:
|
|
||||||
- ./*.go
|
|
||||||
generates:
|
|
||||||
- app{{exeExt}}
|
|
||||||
method: checksum
|
|
||||||
```
|
|
||||||
|
|
||||||
> TIP: method `none` skips any validation and always run the task.
|
|
||||||
|
|
||||||
Alternatively, you can inform a sequence of tests as `status`. If no error
|
|
||||||
is returned (exit status 0), the task is considered up-to-date:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
generate-files:
|
|
||||||
cmds:
|
|
||||||
- mkdir directory
|
|
||||||
- touch directory/file1.txt
|
|
||||||
- touch directory/file2.txt
|
|
||||||
# test existence of files
|
|
||||||
status:
|
|
||||||
- test -d directory
|
|
||||||
- test -f directory/file1.txt
|
|
||||||
- test -f directory/file2.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
You can use `--force` or `-f` if you want to force a task to run even when
|
|
||||||
up-to-date.
|
|
||||||
|
|
||||||
Also, `task --status [tasks]...` will exit with a non-zero exit code if any of
|
|
||||||
the tasks are not up-to-date.
|
|
||||||
|
|
||||||
### Variables
|
|
||||||
|
|
||||||
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 locally in the task
|
|
||||||
- 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
|
|
||||||
- Environment variables
|
|
||||||
|
|
||||||
Example of sending parameters with environment variables:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ TASK_VARIABLE=a-value task do-something
|
|
||||||
```
|
|
||||||
|
|
||||||
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. Variables given in this form are only visible to the task called
|
|
||||||
right before.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ task write-file FILE=file.txt "CONTENT=Hello, World!" print "MESSAGE=All done!"
|
|
||||||
```
|
|
||||||
|
|
||||||
Example of locally declared vars:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
print-var:
|
|
||||||
cmds:
|
|
||||||
echo "{{.VAR}}"
|
|
||||||
vars:
|
|
||||||
VAR: Hello!
|
|
||||||
```
|
|
||||||
|
|
||||||
Example of global vars in a `Taskfile.yml`:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
vars:
|
|
||||||
GREETING: Hello from Taskfile!
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
greet:
|
|
||||||
cmds:
|
|
||||||
- echo "{{.GREETING}}"
|
|
||||||
```
|
|
||||||
|
|
||||||
Example of `Taskvars.yml` file:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
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:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
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.
|
|
||||||
The value will be treated as a command and the output assigned. If there is one
|
|
||||||
or more trailing newlines, the last newline will be trimmed.
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
build:
|
|
||||||
cmds:
|
|
||||||
- go build -ldflags="-X main.Version={{.GIT_COMMIT}}" main.go
|
|
||||||
vars:
|
|
||||||
GIT_COMMIT:
|
|
||||||
sh: git log -n 1 --format=%h
|
|
||||||
```
|
|
||||||
|
|
||||||
This works for all types of variables.
|
|
||||||
|
|
||||||
### Go's template engine
|
|
||||||
|
|
||||||
Task parse commands as [Go's template engine][gotemplate] before executing
|
|
||||||
them. Variables are accessible through dot syntax (`.VARNAME`).
|
|
||||||
|
|
||||||
All functions by the Go's [sprig lib](http://masterminds.github.io/sprig/)
|
|
||||||
are available. The following example gets the current date in a given format:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
print-date:
|
|
||||||
cmds:
|
|
||||||
- echo {{now | date "2006-01-02"}}
|
|
||||||
```
|
|
||||||
|
|
||||||
Task also adds the following functions:
|
|
||||||
|
|
||||||
- `OS`: Returns operating system. Possible values are "windows", "linux",
|
|
||||||
"darwin" (macOS) and "freebsd".
|
|
||||||
- `ARCH`: return the architecture Task was compiled to: "386", "amd64", "arm"
|
|
||||||
or "s390x".
|
|
||||||
- `splitLines`: Splits Unix (\n) and Windows (\r\n) styled newlines.
|
|
||||||
- `catLines`: Replaces Unix (\n) and Windows (\r\n) styled newlines with a space.
|
|
||||||
- `toSlash`: Does nothing on Unix, but on Windows converts a string from `\`
|
|
||||||
path format to `/`.
|
|
||||||
- `fromSlash`: Oposite of `toSlash`. Does nothing on Unix, but on Windows
|
|
||||||
converts a string from `\` path format to `/`.
|
|
||||||
- `exeExt`: Returns the right executable extension for the current OS
|
|
||||||
(`".exe"` for Windows, `""` for others).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
print-os:
|
|
||||||
cmds:
|
|
||||||
- echo '{{OS}} {{ARCH}}'
|
|
||||||
- echo '{{if eq OS "windows"}}windows-command{{else}}unix-command{{end}}'
|
|
||||||
# This will be path/to/file on Unix but path\to\file on Windows
|
|
||||||
- echo '{{fromSlash "path/to/file"}}'
|
|
||||||
enumerated-file:
|
|
||||||
vars:
|
|
||||||
CONTENT: |
|
|
||||||
foo
|
|
||||||
bar
|
|
||||||
cmds:
|
|
||||||
- |
|
|
||||||
cat << EOF > output.txt
|
|
||||||
{{range $i, $line := .CONTENT | splitLines -}}
|
|
||||||
{{printf "%3d" $i}}: {{$line}}
|
|
||||||
{{end}}EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
### Help
|
|
||||||
|
|
||||||
Running `task --list` (or `task -l`) lists all tasks with a description.
|
|
||||||
The following taskfile:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
build:
|
|
||||||
desc: Build the go binary.
|
|
||||||
cmds:
|
|
||||||
- go build -v -i main.go
|
|
||||||
|
|
||||||
test:
|
|
||||||
desc: Run all the go tests.
|
|
||||||
cmds:
|
|
||||||
- go test -race ./...
|
|
||||||
|
|
||||||
js:
|
|
||||||
cmds:
|
|
||||||
- minify -o public/script.js src/js
|
|
||||||
|
|
||||||
css:
|
|
||||||
cmds:
|
|
||||||
- minify -o public/style.css src/css
|
|
||||||
```
|
|
||||||
|
|
||||||
would print the following output:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
* build: Build the go binary.
|
|
||||||
* test: Run all the go tests.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Silent mode
|
|
||||||
|
|
||||||
Silent mode disables echoing of commands before Task runs it.
|
|
||||||
For the following Taskfile:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
echo:
|
|
||||||
cmds:
|
|
||||||
- echo "Print something"
|
|
||||||
```
|
|
||||||
|
|
||||||
Normally this will be print:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
echo "Print something"
|
|
||||||
Print something
|
|
||||||
```
|
|
||||||
|
|
||||||
With silent mode on, the below will be print instead:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
Print something
|
|
||||||
```
|
|
||||||
|
|
||||||
There's three ways to enable silent mode:
|
|
||||||
|
|
||||||
* At command level:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
echo:
|
|
||||||
cmds:
|
|
||||||
- cmd: echo "Print something"
|
|
||||||
silent: true
|
|
||||||
```
|
|
||||||
|
|
||||||
* At task level:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
echo:
|
|
||||||
cmds:
|
|
||||||
- echo "Print something"
|
|
||||||
silent: true
|
|
||||||
```
|
|
||||||
|
|
||||||
* Or globally with `--silent` or `-s` flag
|
|
||||||
|
|
||||||
If you want to suppress stdout instead, just redirect a command to `/dev/null`:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
echo:
|
|
||||||
cmds:
|
|
||||||
- echo "This will print nothing" > /dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dry run mode
|
|
||||||
|
|
||||||
Dry run mode (`--dry`) compiles and steps through each task, printing the commands
|
|
||||||
that would be run without executing them. This is useful for debugging your Taskfiles.
|
|
||||||
|
|
||||||
## Ignore errors
|
|
||||||
|
|
||||||
You have the option to ignore errors during command execution.
|
|
||||||
Given the following Taskfile:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
echo:
|
|
||||||
cmds:
|
|
||||||
- exit 1
|
|
||||||
- echo "Hello World"
|
|
||||||
```
|
|
||||||
|
|
||||||
Task will abort the execution after running `exit 1` because the status code `1` stands for `EXIT_FAILURE`.
|
|
||||||
However it is possible to continue with execution using `ignore_error`:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
echo:
|
|
||||||
cmds:
|
|
||||||
- cmd: exit 1
|
|
||||||
ignore_error: true
|
|
||||||
- echo "Hello World"
|
|
||||||
```
|
|
||||||
|
|
||||||
`ignore_error` can also be set for a task, which mean errors will be supressed
|
|
||||||
for all commands. But keep in mind this option won't propagate to other tasks
|
|
||||||
called either by `deps` or `cmds`!
|
|
||||||
|
|
||||||
## Output syntax
|
|
||||||
|
|
||||||
By default, Task just redirect the STDOUT and STDERR of the running commands
|
|
||||||
to the shell in real time. This is good for having live feedback for log
|
|
||||||
printed by commands, but the output can become messy if you have multiple
|
|
||||||
commands running at the same time and printing lots of stuff.
|
|
||||||
|
|
||||||
To make this more customizable, there are currently three different output
|
|
||||||
options you can choose:
|
|
||||||
|
|
||||||
- `interleaved` (default)
|
|
||||||
- `group`
|
|
||||||
- `prefixed`
|
|
||||||
|
|
||||||
To choose another one, just set it to root in the Taskfile:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
output: 'group'
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
The `group` output will print the entire output of a command once, after it
|
|
||||||
finishes, so you won't have live feedback for commands that take a long time
|
|
||||||
to run.
|
|
||||||
|
|
||||||
The `prefix` output will prefix every line printed by a command with
|
|
||||||
`[task-name] ` as the prefix, but you can customize the prefix for a command
|
|
||||||
with the `prefix:` attribute:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '2'
|
|
||||||
|
|
||||||
output: prefixed
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
default:
|
|
||||||
deps:
|
|
||||||
- task: print
|
|
||||||
vars: {TEXT: foo}
|
|
||||||
- task: print
|
|
||||||
vars: {TEXT: bar}
|
|
||||||
- task: print
|
|
||||||
vars: {TEXT: baz}
|
|
||||||
|
|
||||||
print:
|
|
||||||
cmds:
|
|
||||||
- echo "{{.TEXT}}"
|
|
||||||
prefix: "print-{{.TEXT}}"
|
|
||||||
silent: true
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ task default
|
|
||||||
[print-foo] foo
|
|
||||||
[print-bar] bar
|
|
||||||
[print-baz] baz
|
|
||||||
```
|
|
||||||
|
|
||||||
## Watch tasks
|
|
||||||
|
|
||||||
If you give a `--watch` or `-w` argument, 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.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
The [go-task/examples][examples] intends to be a collection of Taskfiles for
|
|
||||||
various use cases.
|
|
||||||
(It still lacks many examples, though. Contributions are welcome).
|
|
||||||
|
|
||||||
## Alternative task runners
|
|
||||||
|
|
||||||
- YAML based:
|
|
||||||
- [rliebz/tusk][tusk]
|
|
||||||
- Go based:
|
|
||||||
- [magefile/mage][mage]
|
|
||||||
- Make based or similar:
|
|
||||||
- [casey/just][just]
|
|
||||||
|
|
||||||
### Sponsors
|
|
||||||
|
|
||||||
[][opencollective]
|
|
||||||
|
|
||||||
### Backers
|
|
||||||
|
|
||||||
[][opencollective]
|
|
||||||
|
|
||||||
### Contributors
|
|
||||||
|
|
||||||
[][contributors]
|
|
||||||
|
|
||||||
[make]: https://www.gnu.org/software/make/
|
[make]: https://www.gnu.org/software/make/
|
||||||
[releases]: https://github.com/go-task/task/releases
|
|
||||||
[golang]: https://golang.org/
|
|
||||||
[gotemplate]: https://golang.org/pkg/text/template/
|
|
||||||
[tusk]: https://github.com/rliebz/tusk
|
|
||||||
[mage]: https://github.com/magefile/mage
|
|
||||||
[just]: https://github.com/casey/just
|
|
||||||
[sh]: https://github.com/mvdan/sh
|
|
||||||
[minify]: https://github.com/tdewolff/minify/tree/master/cmd/minify
|
|
||||||
[examples]: https://github.com/go-task/examples
|
|
||||||
[snapcraft]: https://snapcraft.io/
|
|
||||||
[homebrew]: https://brew.sh/
|
|
||||||
[installscript]: https://github.com/go-task/task/blob/master/install-task.sh
|
|
||||||
[godownloader]: https://github.com/goreleaser/godownloader
|
|
||||||
[opencollective]: https://opencollective.com/task
|
|
||||||
[contributors]: https://github.com/go-task/task/graphs/contributors
|
|
||||||
|
13
Taskfile.yml
13
Taskfile.yml
@ -60,9 +60,10 @@ tasks:
|
|||||||
- goreleaser --snapshot --rm-dist
|
- goreleaser --snapshot --rm-dist
|
||||||
|
|
||||||
generate-install-script:
|
generate-install-script:
|
||||||
desc: Generate install script using https://githbub.com/goreleaser/godownloader
|
desc: Generate install script using https://github.com/goreleaser/godownloader
|
||||||
cmds:
|
cmds:
|
||||||
- godownloader --repo go-task/task -o install-task.sh
|
- godownloader --repo go-task/task -o install-task.sh
|
||||||
|
- cp ./install-task.sh ./docs/install.sh
|
||||||
|
|
||||||
ci:
|
ci:
|
||||||
cmds:
|
cmds:
|
||||||
@ -79,3 +80,13 @@ tasks:
|
|||||||
cmds:
|
cmds:
|
||||||
- echo '{{.GO_PACKAGES}}'
|
- echo '{{.GO_PACKAGES}}'
|
||||||
silent: true
|
silent: true
|
||||||
|
|
||||||
|
docs:install:
|
||||||
|
desc: Installs docsify to work the on the documentation site
|
||||||
|
cmds:
|
||||||
|
- npm install docsify-cli -g
|
||||||
|
|
||||||
|
docs:serve:
|
||||||
|
desc: Serves the documentation site locally
|
||||||
|
cmds:
|
||||||
|
- docsify serve docs
|
||||||
|
@ -87,6 +87,11 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
if !watch {
|
||||||
|
ctx = getSignalContext()
|
||||||
|
}
|
||||||
|
|
||||||
e := task.Executor{
|
e := task.Executor{
|
||||||
Force: force,
|
Force: force,
|
||||||
Watch: watch,
|
Watch: watch,
|
||||||
@ -95,7 +100,7 @@ func main() {
|
|||||||
Dir: dir,
|
Dir: dir,
|
||||||
Dry: dry,
|
Dry: dry,
|
||||||
|
|
||||||
Context: getSignalContext(),
|
Context: ctx,
|
||||||
|
|
||||||
Stdin: os.Stdin,
|
Stdin: os.Stdin,
|
||||||
Stdout: os.Stdout,
|
Stdout: os.Stdout,
|
||||||
|
0
docs/.nojekyll
Normal file
0
docs/.nojekyll
Normal file
1
docs/CNAME
Normal file
1
docs/CNAME
Normal file
@ -0,0 +1 @@
|
|||||||
|
taskfile.org
|
46
docs/README.md
Normal file
46
docs/README.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# Task
|
||||||
|
|
||||||
|
Task is a task runner / build tool that aims to be simpler and easier to use
|
||||||
|
than, for example, [GNU Make][make].
|
||||||
|
|
||||||
|
Since it's written in [Go][go], Task is just a single binary and has no other
|
||||||
|
dependencies, which means you don't need to mess with any complicated install
|
||||||
|
setups just to use a build tool.
|
||||||
|
|
||||||
|
Once [installed](installation), you just need to describe your build tasks
|
||||||
|
using a simple [YAML][yaml] schema in a file called `Taskfile.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
hello:
|
||||||
|
cmds:
|
||||||
|
- echo 'Hello World from Task!'
|
||||||
|
silent: true
|
||||||
|
```
|
||||||
|
|
||||||
|
And call it by running `task hello` from you terminal.
|
||||||
|
|
||||||
|
The above example is just the start, you can take a look at the [usage](usage)
|
||||||
|
guide to check the full schema documentation and Task features.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [Easy installation](installation): just download a single binary, add to
|
||||||
|
$PATH and you're done! Or you can also install using [Homebrew][homebrew] or
|
||||||
|
[Snapcraft][snapcraft] if you want;
|
||||||
|
- Available on CIs: by adding [this simple command](installation#install-script)
|
||||||
|
to install on your CI script and you're done to use Task as part of your CI pipeline;
|
||||||
|
- Truly cross-platform: while most build tools only work well on Linux or macOS,
|
||||||
|
Task also supports Windows thanks to [this awesome shell interpreter for Go][sh];
|
||||||
|
- Great for code generation: you can easily [prevent a task from running](usage#prevent-unnecessary-work)
|
||||||
|
if a given set of files haven't changed since last run (based either on its
|
||||||
|
timestamp or content).
|
||||||
|
|
||||||
|
[make]: https://www.gnu.org/software/make/
|
||||||
|
[go]: https://golang.org/
|
||||||
|
[yaml]: http://yaml.org/
|
||||||
|
[homebrew]: https://brew.sh/
|
||||||
|
[snapcraft]: https://snapcraft.io/
|
||||||
|
[sh]: https://mvdan.cc/sh
|
8
docs/_sidebar.md
Normal file
8
docs/_sidebar.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- [Installation](installation)
|
||||||
|
- [Usage](usage)
|
||||||
|
- [Taskfile Versions](taskfile_versions)
|
||||||
|
- [Examples](examples)
|
||||||
|
- [Releasing Task](releasing_task)
|
||||||
|
- [Alternative Task Runners](alternative_task_runners)
|
||||||
|
- [Sponsors and Backers](sponsors_and_backers)
|
||||||
|
- [Github](https://github.com/go-task/task)
|
17
docs/alternative_task_runners.md
Normal file
17
docs/alternative_task_runners.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# 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
|
7
docs/examples.md
Normal file
7
docs/examples.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Examples
|
||||||
|
|
||||||
|
The [go-task/examples][examples] intends to be a collection of Taskfiles for
|
||||||
|
various use cases.
|
||||||
|
(It still lacks many examples, though. Contributions are welcome).
|
||||||
|
|
||||||
|
[examples]: https://github.com/go-task/examples
|
BIN
docs/favicon.ico
Normal file
BIN
docs/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
31
docs/index.html
Normal file
31
docs/index.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Task</title>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
|
<meta name="description" content="A task runner / simpler Make alternative written in Go">
|
||||||
|
<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="//unpkg.com/docsify-themeable/dist/css/theme-simple.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script>
|
||||||
|
window.$docsify = {
|
||||||
|
name: 'Task',
|
||||||
|
repo: 'go-task/task',
|
||||||
|
ga: 'UA-126286662-1',
|
||||||
|
themeColor: '#83d0f2',
|
||||||
|
loadSidebar: true,
|
||||||
|
auto2top: true,
|
||||||
|
maxLevel: 3,
|
||||||
|
subMaxLevel: 3
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||||
|
<script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
|
||||||
|
<script src="//unpkg.com/docsify-themeable"></script>
|
||||||
|
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||||
|
<script src="//unpkg.com/prismjs/components/prism-yaml.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
390
docs/install.sh
Executable file
390
docs/install.sh
Executable file
@ -0,0 +1,390 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
# Code generated by godownloader on 2018-04-07T17:47:38Z. DO NOT EDIT.
|
||||||
|
#
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
this=$1
|
||||||
|
cat <<EOF
|
||||||
|
$this: download go binaries for go-task/task
|
||||||
|
|
||||||
|
Usage: $this [-b] bindir [-d] [tag]
|
||||||
|
-b sets bindir or installation directory, Defaults to ./bin
|
||||||
|
-d turns on debug logging
|
||||||
|
[tag] is a tag from
|
||||||
|
https://github.com/go-task/task/releases
|
||||||
|
If tag is missing, then the latest will be used.
|
||||||
|
|
||||||
|
Generated by godownloader
|
||||||
|
https://github.com/goreleaser/godownloader
|
||||||
|
|
||||||
|
EOF
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_args() {
|
||||||
|
#BINDIR is ./bin unless set be ENV
|
||||||
|
# over-ridden by flag below
|
||||||
|
|
||||||
|
BINDIR=${BINDIR:-./bin}
|
||||||
|
while getopts "b:dh?" arg; do
|
||||||
|
case "$arg" in
|
||||||
|
b) BINDIR="$OPTARG" ;;
|
||||||
|
d) log_set_priority 10 ;;
|
||||||
|
h | \?) usage "$0" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
TAG=$1
|
||||||
|
}
|
||||||
|
# this function wraps all the destructive operations
|
||||||
|
# if a curl|bash cuts off the end of the script due to
|
||||||
|
# network, either nothing will happen or will syntax error
|
||||||
|
# out preventing half-done work
|
||||||
|
execute() {
|
||||||
|
tmpdir=$(mktmpdir)
|
||||||
|
log_debug "downloading files into ${tmpdir}"
|
||||||
|
http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
|
||||||
|
http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
|
||||||
|
hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
|
||||||
|
srcdir="${tmpdir}"
|
||||||
|
(cd "${tmpdir}" && untar "${TARBALL}")
|
||||||
|
install -d "${BINDIR}"
|
||||||
|
for binexe in "task" ; do
|
||||||
|
if [ "$OS" = "windows" ]; then
|
||||||
|
binexe="${binexe}.exe"
|
||||||
|
fi
|
||||||
|
install "${srcdir}/${binexe}" "${BINDIR}/"
|
||||||
|
log_info "installed ${BINDIR}/${binexe}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
is_supported_platform() {
|
||||||
|
platform=$1
|
||||||
|
found=1
|
||||||
|
case "$platform" in
|
||||||
|
windows/386) found=0 ;;
|
||||||
|
windows/amd64) found=0 ;;
|
||||||
|
darwin/386) found=0 ;;
|
||||||
|
darwin/amd64) found=0 ;;
|
||||||
|
linux/386) found=0 ;;
|
||||||
|
linux/amd64) found=0 ;;
|
||||||
|
esac
|
||||||
|
case "$platform" in
|
||||||
|
darwin/386) found=1 ;;
|
||||||
|
esac
|
||||||
|
return $found
|
||||||
|
}
|
||||||
|
check_platform() {
|
||||||
|
if is_supported_platform "$PLATFORM"; then
|
||||||
|
# optional logging goes here
|
||||||
|
true
|
||||||
|
else
|
||||||
|
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
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
tag_to_version() {
|
||||||
|
if [ -z "${TAG}" ]; then
|
||||||
|
log_info "checking GitHub for latest tag"
|
||||||
|
else
|
||||||
|
log_info "checking GitHub for tag '${TAG}'"
|
||||||
|
fi
|
||||||
|
REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
|
||||||
|
if test -z "$REALTAG"; then
|
||||||
|
log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# if version starts with 'v', remove it
|
||||||
|
TAG="$REALTAG"
|
||||||
|
VERSION=${TAG#v}
|
||||||
|
}
|
||||||
|
adjust_format() {
|
||||||
|
# change format (tar.gz or zip) based on ARCH
|
||||||
|
case ${ARCH} in
|
||||||
|
windows) FORMAT=zip ;;
|
||||||
|
esac
|
||||||
|
true
|
||||||
|
}
|
||||||
|
adjust_os() {
|
||||||
|
# adjust archive name based on OS
|
||||||
|
true
|
||||||
|
}
|
||||||
|
adjust_arch() {
|
||||||
|
# adjust archive name based on ARCH
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
cat /dev/null <<EOF
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
https://github.com/client9/shlib - portable posix shell functions
|
||||||
|
Public domain - http://unlicense.org
|
||||||
|
https://github.com/client9/shlib/blob/master/LICENSE.md
|
||||||
|
but credit (and pull requests) appreciated.
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
EOF
|
||||||
|
is_command() {
|
||||||
|
command -v "$1" >/dev/null
|
||||||
|
}
|
||||||
|
echoerr() {
|
||||||
|
echo "$@" 1>&2
|
||||||
|
}
|
||||||
|
log_prefix() {
|
||||||
|
echo "$0"
|
||||||
|
}
|
||||||
|
_logp=6
|
||||||
|
log_set_priority() {
|
||||||
|
_logp="$1"
|
||||||
|
}
|
||||||
|
log_priority() {
|
||||||
|
if test -z "$1"; then
|
||||||
|
echo "$_logp"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
[ "$1" -le "$_logp" ]
|
||||||
|
}
|
||||||
|
log_tag() {
|
||||||
|
case $1 in
|
||||||
|
0) echo "emerg" ;;
|
||||||
|
1) echo "alert" ;;
|
||||||
|
2) echo "crit" ;;
|
||||||
|
3) echo "err" ;;
|
||||||
|
4) echo "warning" ;;
|
||||||
|
5) echo "notice" ;;
|
||||||
|
6) echo "info" ;;
|
||||||
|
7) echo "debug" ;;
|
||||||
|
*) echo "$1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
log_debug() {
|
||||||
|
log_priority 7 || return 0
|
||||||
|
echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
|
||||||
|
}
|
||||||
|
log_info() {
|
||||||
|
log_priority 6 || return 0
|
||||||
|
echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
|
||||||
|
}
|
||||||
|
log_err() {
|
||||||
|
log_priority 3 || return 0
|
||||||
|
echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
|
||||||
|
}
|
||||||
|
log_crit() {
|
||||||
|
log_priority 2 || return 0
|
||||||
|
echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
|
||||||
|
}
|
||||||
|
uname_os() {
|
||||||
|
os=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||||
|
case "$os" in
|
||||||
|
msys_nt) os="windows" ;;
|
||||||
|
esac
|
||||||
|
echo "$os"
|
||||||
|
}
|
||||||
|
uname_arch() {
|
||||||
|
arch=$(uname -m)
|
||||||
|
case $arch in
|
||||||
|
x86_64) arch="amd64" ;;
|
||||||
|
x86) arch="386" ;;
|
||||||
|
i686) arch="386" ;;
|
||||||
|
i386) arch="386" ;;
|
||||||
|
aarch64) arch="arm64" ;;
|
||||||
|
armv5*) arch="arm5" ;;
|
||||||
|
armv6*) arch="arm6" ;;
|
||||||
|
armv7*) arch="arm7" ;;
|
||||||
|
esac
|
||||||
|
echo ${arch}
|
||||||
|
}
|
||||||
|
uname_os_check() {
|
||||||
|
os=$(uname_os)
|
||||||
|
case "$os" in
|
||||||
|
darwin) return 0 ;;
|
||||||
|
dragonfly) return 0 ;;
|
||||||
|
freebsd) return 0 ;;
|
||||||
|
linux) return 0 ;;
|
||||||
|
android) return 0 ;;
|
||||||
|
nacl) return 0 ;;
|
||||||
|
netbsd) return 0 ;;
|
||||||
|
openbsd) return 0 ;;
|
||||||
|
plan9) return 0 ;;
|
||||||
|
solaris) return 0 ;;
|
||||||
|
windows) return 0 ;;
|
||||||
|
esac
|
||||||
|
log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
uname_arch_check() {
|
||||||
|
arch=$(uname_arch)
|
||||||
|
case "$arch" in
|
||||||
|
386) return 0 ;;
|
||||||
|
amd64) return 0 ;;
|
||||||
|
arm64) return 0 ;;
|
||||||
|
armv5) return 0 ;;
|
||||||
|
armv6) return 0 ;;
|
||||||
|
armv7) return 0 ;;
|
||||||
|
ppc64) return 0 ;;
|
||||||
|
ppc64le) return 0 ;;
|
||||||
|
mips) return 0 ;;
|
||||||
|
mipsle) return 0 ;;
|
||||||
|
mips64) return 0 ;;
|
||||||
|
mips64le) return 0 ;;
|
||||||
|
s390x) return 0 ;;
|
||||||
|
amd64p32) return 0 ;;
|
||||||
|
esac
|
||||||
|
log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
untar() {
|
||||||
|
tarball=$1
|
||||||
|
case "${tarball}" in
|
||||||
|
*.tar.gz | *.tgz) tar -xzf "${tarball}" ;;
|
||||||
|
*.tar) tar -xf "${tarball}" ;;
|
||||||
|
*.zip) unzip "${tarball}" ;;
|
||||||
|
*)
|
||||||
|
log_err "untar unknown archive format for ${tarball}"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
mktmpdir() {
|
||||||
|
test -z "$TMPDIR" && TMPDIR="$(mktemp -d)"
|
||||||
|
mkdir -p "${TMPDIR}"
|
||||||
|
echo "${TMPDIR}"
|
||||||
|
}
|
||||||
|
http_download_curl() {
|
||||||
|
local_file=$1
|
||||||
|
source_url=$2
|
||||||
|
header=$3
|
||||||
|
if [ -z "$header" ]; then
|
||||||
|
code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
|
||||||
|
else
|
||||||
|
code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
|
||||||
|
fi
|
||||||
|
if [ "$code" != "200" ]; then
|
||||||
|
log_debug "http_download_curl received HTTP status $code"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
http_download_wget() {
|
||||||
|
local_file=$1
|
||||||
|
source_url=$2
|
||||||
|
header=$3
|
||||||
|
if [ -z "$header" ]; then
|
||||||
|
wget -q -O "$local_file" "$source_url"
|
||||||
|
else
|
||||||
|
wget -q --header "$header" -O "$local_file" "$source_url"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
http_download() {
|
||||||
|
log_debug "http_download $2"
|
||||||
|
if is_command curl; then
|
||||||
|
http_download_curl "$@"
|
||||||
|
return
|
||||||
|
elif is_command wget; then
|
||||||
|
http_download_wget "$@"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
log_crit "http_download unable to find wget or curl"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
http_copy() {
|
||||||
|
tmp=$(mktemp)
|
||||||
|
http_download "${tmp}" "$1" "$2" || return 1
|
||||||
|
body=$(cat "$tmp")
|
||||||
|
rm -f "${tmp}"
|
||||||
|
echo "$body"
|
||||||
|
}
|
||||||
|
github_release() {
|
||||||
|
owner_repo=$1
|
||||||
|
version=$2
|
||||||
|
test -z "$version" && version="latest"
|
||||||
|
giturl="https://github.com/${owner_repo}/releases/${version}"
|
||||||
|
json=$(http_copy "$giturl" "Accept:application/json")
|
||||||
|
test -z "$json" && return 1
|
||||||
|
version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
|
||||||
|
test -z "$version" && return 1
|
||||||
|
echo "$version"
|
||||||
|
}
|
||||||
|
hash_sha256() {
|
||||||
|
TARGET=${1:-/dev/stdin}
|
||||||
|
if is_command gsha256sum; then
|
||||||
|
hash=$(gsha256sum "$TARGET") || return 1
|
||||||
|
echo "$hash" | cut -d ' ' -f 1
|
||||||
|
elif is_command sha256sum; then
|
||||||
|
hash=$(sha256sum "$TARGET") || return 1
|
||||||
|
echo "$hash" | cut -d ' ' -f 1
|
||||||
|
elif is_command shasum; then
|
||||||
|
hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
|
||||||
|
echo "$hash" | cut -d ' ' -f 1
|
||||||
|
elif is_command openssl; then
|
||||||
|
hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
|
||||||
|
echo "$hash" | cut -d ' ' -f a
|
||||||
|
else
|
||||||
|
log_crit "hash_sha256 unable to find command to compute sha-256 hash"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
hash_sha256_verify() {
|
||||||
|
TARGET=$1
|
||||||
|
checksums=$2
|
||||||
|
if [ -z "$checksums" ]; then
|
||||||
|
log_err "hash_sha256_verify checksum file not specified in arg2"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
BASENAME=${TARGET##*/}
|
||||||
|
want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
|
||||||
|
if [ -z "$want" ]; then
|
||||||
|
log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
got=$(hash_sha256 "$TARGET")
|
||||||
|
if [ "$want" != "$got" ]; then
|
||||||
|
log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
cat /dev/null <<EOF
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
End of functions from https://github.com/client9/shlib
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
EOF
|
||||||
|
|
||||||
|
PROJECT_NAME="task"
|
||||||
|
OWNER=go-task
|
||||||
|
REPO="task"
|
||||||
|
BINARY=task
|
||||||
|
FORMAT=tar.gz
|
||||||
|
OS=$(uname_os)
|
||||||
|
ARCH=$(uname_arch)
|
||||||
|
PREFIX="$OWNER/$REPO"
|
||||||
|
|
||||||
|
# use in logging routines
|
||||||
|
log_prefix() {
|
||||||
|
echo "$PREFIX"
|
||||||
|
}
|
||||||
|
PLATFORM="${OS}/${ARCH}"
|
||||||
|
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
|
||||||
|
|
||||||
|
uname_os_check "$OS"
|
||||||
|
uname_arch_check "$ARCH"
|
||||||
|
|
||||||
|
parse_args "$@"
|
||||||
|
|
||||||
|
check_platform
|
||||||
|
|
||||||
|
tag_to_version
|
||||||
|
|
||||||
|
adjust_format
|
||||||
|
|
||||||
|
adjust_os
|
||||||
|
|
||||||
|
adjust_arch
|
||||||
|
|
||||||
|
log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"
|
||||||
|
|
||||||
|
NAME=${BINARY}_${OS}_${ARCH}
|
||||||
|
TARBALL=${NAME}.${FORMAT}
|
||||||
|
TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
|
||||||
|
CHECKSUM=task_checksums.txt
|
||||||
|
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}
|
||||||
|
|
||||||
|
|
||||||
|
execute
|
53
docs/installation.md
Normal file
53
docs/installation.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Installation
|
||||||
|
|
||||||
|
## Binary
|
||||||
|
|
||||||
|
Or you can download the binary from the [releases][releases] page and add to
|
||||||
|
your $PATH. DEB and RPM packages are also available.
|
||||||
|
The `task_checksums.txt` file contains the sha256 checksum for each file.
|
||||||
|
|
||||||
|
## Homebrew
|
||||||
|
|
||||||
|
If you're on macOS and have [Homebrew][homebrew] installed, getting Task is
|
||||||
|
as simple as running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install go-task/tap/go-task
|
||||||
|
```
|
||||||
|
|
||||||
|
## Snap
|
||||||
|
|
||||||
|
Task is available for [Snapcraft][snapcraft], but keep in mind that your
|
||||||
|
Linux distribution should allow classic confinement for Snaps to Task work
|
||||||
|
right:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo snap install task
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go
|
||||||
|
|
||||||
|
If you have a [Go][go] environment setup, you can simply run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get -u -v github.com/go-task/task/cmd/task
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install script
|
||||||
|
|
||||||
|
We also have a [install script][installscript], which is very useful on
|
||||||
|
scanarios like CIs. Many thanks to [godownloader][godownloader] for allowing
|
||||||
|
easily generating this script.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s https://taskfile.org/install.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
> This method will download the binary on the local `./bin` directory by default.
|
||||||
|
|
||||||
|
[go]: https://golang.org/
|
||||||
|
[snapcraft]: https://snapcraft.io/
|
||||||
|
[homebrew]: https://brew.sh/
|
||||||
|
[installscript]: https://github.com/go-task/task/blob/master/install-task.sh
|
||||||
|
[releases]: https://github.com/go-task/task/releases
|
||||||
|
[godownloader]: https://github.com/goreleaser/godownloader
|
16
docs/sponsors_and_backers.md
Normal file
16
docs/sponsors_and_backers.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Sponsors and Backers
|
||||||
|
|
||||||
|
## Sponsors
|
||||||
|
|
||||||
|
[][opencollective]
|
||||||
|
|
||||||
|
## Backers
|
||||||
|
|
||||||
|
[][opencollective]
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
[][contributors]
|
||||||
|
|
||||||
|
[opencollective]: https://opencollective.com/task
|
||||||
|
[contributors]: https://github.com/go-task/task/graphs/contributors
|
@ -1,9 +1,9 @@
|
|||||||
# Taskfile version
|
# Taskfile Versions
|
||||||
|
|
||||||
The Taskfile syntax and features changed with time. This document explains what
|
The Taskfile syntax and features changed with time. This document explains what
|
||||||
changed on each version and how to upgrade your Taskfile.
|
changed on each version and how to upgrade your Taskfile.
|
||||||
|
|
||||||
# What the Taskfile version mean
|
## What the Taskfile version mean
|
||||||
|
|
||||||
The Taskfile version follows the Task version. E.g. the change to Taskfile
|
The Taskfile version follows the Task version. E.g. the change to Taskfile
|
||||||
version `2` means that Task `v2.0.0` should be release to support it.
|
version `2` means that Task `v2.0.0` should be release to support it.
|
||||||
@ -18,7 +18,7 @@ available, but not `3.0.0+`.
|
|||||||
In the first version of the `Taskfile`, the `version:` key was not available,
|
In the first version of the `Taskfile`, the `version:` key was not available,
|
||||||
because the tasks was in the root of the YAML document. Like this:
|
because the tasks was in the root of the YAML document. Like this:
|
||||||
|
|
||||||
```yml
|
```yaml
|
||||||
echo:
|
echo:
|
||||||
cmds:
|
cmds:
|
||||||
- echo "Hello, World!"
|
- echo "Hello, World!"
|
||||||
@ -37,7 +37,7 @@ At version 2, we introduced the `version:` key, to allow us to envolve Task
|
|||||||
with new features without breaking existing Taskfiles. The new syntax is as
|
with new features without breaking existing Taskfiles. The new syntax is as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
```yml
|
```yaml
|
||||||
version: '2'
|
version: '2'
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
@ -49,7 +49,7 @@ tasks:
|
|||||||
Version 2 allows you to write global variables directly in the Taskfile,
|
Version 2 allows you to write global variables directly in the Taskfile,
|
||||||
if you don't want to create a `Taskvars.yml`:
|
if you don't want to create a `Taskvars.yml`:
|
||||||
|
|
||||||
```yml
|
```yaml
|
||||||
version: '2'
|
version: '2'
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
@ -72,7 +72,7 @@ The variable priority order changed to the following:
|
|||||||
A new global option was added to configure the number of variables expansions
|
A new global option was added to configure the number of variables expansions
|
||||||
(which default to 2):
|
(which default to 2):
|
||||||
|
|
||||||
```yml
|
```yaml
|
||||||
version: '2'
|
version: '2'
|
||||||
|
|
||||||
expansions: 3
|
expansions: 3
|
||||||
@ -96,7 +96,7 @@ Version 2.1 includes a global `output` option, to allow having more control
|
|||||||
over how commands output are printed to the console
|
over how commands output are printed to the console
|
||||||
(see [documentation][output] for more info):
|
(see [documentation][output] for more info):
|
||||||
|
|
||||||
```yml
|
```yaml
|
||||||
version: '2'
|
version: '2'
|
||||||
|
|
||||||
output: prefixed
|
output: prefixed
|
||||||
@ -109,9 +109,9 @@ tasks:
|
|||||||
```
|
```
|
||||||
|
|
||||||
From this version it's not also possible to ignore errors of a command or task
|
From this version it's not also possible to ignore errors of a command or task
|
||||||
(check documentatio [here][ignore_errors]):
|
(check documentation [here][ignore_errors]):
|
||||||
|
|
||||||
```yml
|
```yaml
|
||||||
version: '2'
|
version: '2'
|
||||||
|
|
||||||
tasks:
|
tasks:
|
669
docs/usage.md
Normal file
669
docs/usage.md
Normal file
@ -0,0 +1,669 @@
|
|||||||
|
# Usage
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Create a file called `Taskfile.yml` in the root of your project.
|
||||||
|
The `cmds` attribute should contain the commands of a task.
|
||||||
|
The example below allows compiling a Go app and uses [Minify][minify] to concat
|
||||||
|
and minify multiple CSS files into a single one.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
build:
|
||||||
|
cmds:
|
||||||
|
- go build -v -i main.go
|
||||||
|
|
||||||
|
assets:
|
||||||
|
cmds:
|
||||||
|
- minify -o public/style.css src/css
|
||||||
|
```
|
||||||
|
|
||||||
|
Running the tasks is as simple as running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
task assets build
|
||||||
|
```
|
||||||
|
|
||||||
|
Task uses [github.com/mvdan/sh](https://github.com/mvdan/sh), a native Go sh
|
||||||
|
interpreter. So you can write sh/bash commands and it will work even on
|
||||||
|
Windows, where `sh` or `bash` are usually not available. Just remember any
|
||||||
|
executable called must be available by the OS or in PATH.
|
||||||
|
|
||||||
|
If you ommit a task name, "default" will be assumed.
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
You can specify environment variables that are added when running a command:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
build:
|
||||||
|
cmds:
|
||||||
|
- echo $hallo
|
||||||
|
env:
|
||||||
|
hallo: welt
|
||||||
|
```
|
||||||
|
|
||||||
|
## OS specific task
|
||||||
|
|
||||||
|
If you add a `Taskfile_{{GOOS}}.yml` you can override or amend your Taskfile
|
||||||
|
based on the operating system.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
Taskfile.yml:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
build:
|
||||||
|
cmds:
|
||||||
|
- echo "default"
|
||||||
|
```
|
||||||
|
|
||||||
|
Taskfile_linux.yml:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
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`, `Taskfile_linux.yml`, or `Taskvars_darwin.yml`. See the
|
||||||
|
[variables section](#variables) below.
|
||||||
|
|
||||||
|
## Task directory
|
||||||
|
|
||||||
|
By default, tasks will be executed in the directory where the Taskfile is
|
||||||
|
located. But you can easily make the task run in another folder informing
|
||||||
|
`dir`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
serve:
|
||||||
|
dir: public/www
|
||||||
|
cmds:
|
||||||
|
# run http server
|
||||||
|
- caddy
|
||||||
|
```
|
||||||
|
|
||||||
|
## Task dependencies
|
||||||
|
|
||||||
|
You may have tasks that depend on others. Just pointing them on `deps` will
|
||||||
|
make them run automatically before running the parent task:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
build:
|
||||||
|
deps: [assets]
|
||||||
|
cmds:
|
||||||
|
- go build -v -i main.go
|
||||||
|
|
||||||
|
assets:
|
||||||
|
cmds:
|
||||||
|
- minify -o public/style.css src/css
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above example, `assets` will always run right before `build` if you run
|
||||||
|
`task build`.
|
||||||
|
|
||||||
|
A task can have only dependencies and no commands to group tasks together:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
assets:
|
||||||
|
deps: [js, css]
|
||||||
|
|
||||||
|
js:
|
||||||
|
cmds:
|
||||||
|
- minify -o public/script.js src/js
|
||||||
|
|
||||||
|
css:
|
||||||
|
cmds:
|
||||||
|
- minify -o public/style.css src/css
|
||||||
|
```
|
||||||
|
|
||||||
|
If there is more than one dependency, they always run in parallel for better
|
||||||
|
performance.
|
||||||
|
|
||||||
|
If you want to pass information to dependencies, you can do that the same
|
||||||
|
manner as you would to [call another task](#calling-another-task):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
deps:
|
||||||
|
- task: echo_sth
|
||||||
|
vars: {TEXT: "before 1"}
|
||||||
|
- task: echo_sth
|
||||||
|
vars: {TEXT: "before 2"}
|
||||||
|
cmds:
|
||||||
|
- echo "after"
|
||||||
|
|
||||||
|
echo_sth:
|
||||||
|
cmds:
|
||||||
|
- echo {{.TEXT}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Calling another task
|
||||||
|
|
||||||
|
When a task has many dependencies, they are executed concurrently. This will
|
||||||
|
often result in a faster build pipeline. But in some situations you may need
|
||||||
|
to call other tasks serially. In this case, just use the following syntax:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
main-task:
|
||||||
|
cmds:
|
||||||
|
- task: task-to-be-called
|
||||||
|
- task: another-task
|
||||||
|
- echo "Both done"
|
||||||
|
|
||||||
|
task-to-be-called:
|
||||||
|
cmds:
|
||||||
|
- echo "Task to be called"
|
||||||
|
|
||||||
|
another-task:
|
||||||
|
cmds:
|
||||||
|
- echo "Another task"
|
||||||
|
```
|
||||||
|
|
||||||
|
Overriding variables in the called task is as simple as informing `vars`
|
||||||
|
attribute:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
main-task:
|
||||||
|
cmds:
|
||||||
|
- task: write-file
|
||||||
|
vars: {FILE: "hello.txt", CONTENT: "Hello!"}
|
||||||
|
- task: write-file
|
||||||
|
vars: {FILE: "world.txt", CONTENT: "World!"}
|
||||||
|
|
||||||
|
write-file:
|
||||||
|
cmds:
|
||||||
|
- echo "{{.CONTENT}}" > {{.FILE}}
|
||||||
|
```
|
||||||
|
|
||||||
|
The above syntax is also supported in `deps`.
|
||||||
|
|
||||||
|
## Prevent unnecessary work
|
||||||
|
|
||||||
|
If a task generates something, you can inform Task the source and generated
|
||||||
|
files, so Task will prevent to run them if not necessary.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
build:
|
||||||
|
deps: [js, css]
|
||||||
|
cmds:
|
||||||
|
- go build -v -i main.go
|
||||||
|
|
||||||
|
js:
|
||||||
|
cmds:
|
||||||
|
- minify -o public/script.js src/js
|
||||||
|
sources:
|
||||||
|
- src/js/**/*.js
|
||||||
|
generates:
|
||||||
|
- public/script.js
|
||||||
|
|
||||||
|
css:
|
||||||
|
cmds:
|
||||||
|
- minify -o public/style.css src/css
|
||||||
|
sources:
|
||||||
|
- src/css/**/*.css
|
||||||
|
generates:
|
||||||
|
- public/style.css
|
||||||
|
```
|
||||||
|
|
||||||
|
`sources` and `generates` can be files or file patterns. When both are given,
|
||||||
|
Task will compare the modification date/time of the 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`.
|
||||||
|
|
||||||
|
If you prefer this check to be made by the content of the files, instead of
|
||||||
|
its timestamp, just set the `method` property to `checksum`.
|
||||||
|
You will probably want to ignore the `.task` folder in your `.gitignore` file
|
||||||
|
(It's there that Task stores the last checksum).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
build:
|
||||||
|
cmds:
|
||||||
|
- go build .
|
||||||
|
sources:
|
||||||
|
- ./*.go
|
||||||
|
generates:
|
||||||
|
- app{{exeExt}}
|
||||||
|
method: checksum
|
||||||
|
```
|
||||||
|
|
||||||
|
> TIP: method `none` skips any validation and always run the task.
|
||||||
|
|
||||||
|
Alternatively, you can inform a sequence of tests as `status`. If no error
|
||||||
|
is returned (exit status 0), the task is considered up-to-date:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
generate-files:
|
||||||
|
cmds:
|
||||||
|
- mkdir directory
|
||||||
|
- touch directory/file1.txt
|
||||||
|
- touch directory/file2.txt
|
||||||
|
# test existence of files
|
||||||
|
status:
|
||||||
|
- test -d directory
|
||||||
|
- test -f directory/file1.txt
|
||||||
|
- test -f directory/file2.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use `--force` or `-f` if you want to force a task to run even when
|
||||||
|
up-to-date.
|
||||||
|
|
||||||
|
Also, `task --status [tasks]...` will exit with a non-zero exit code if any of
|
||||||
|
the tasks are not up-to-date.
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
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 locally in the task
|
||||||
|
- 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
|
||||||
|
- Environment variables
|
||||||
|
|
||||||
|
Example of sending parameters with environment variables:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ TASK_VARIABLE=a-value task do-something
|
||||||
|
```
|
||||||
|
|
||||||
|
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. Variables given in this form are only visible to the task called
|
||||||
|
right before.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ task write-file FILE=file.txt "CONTENT=Hello, World!" print "MESSAGE=All done!"
|
||||||
|
```
|
||||||
|
|
||||||
|
Example of locally declared vars:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
print-var:
|
||||||
|
cmds:
|
||||||
|
echo "{{.VAR}}"
|
||||||
|
vars:
|
||||||
|
VAR: Hello!
|
||||||
|
```
|
||||||
|
|
||||||
|
Example of global vars in a `Taskfile.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
GREETING: Hello from Taskfile!
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
greet:
|
||||||
|
cmds:
|
||||||
|
- 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: '2'
|
||||||
|
|
||||||
|
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.
|
||||||
|
The value will be treated as a command and the output assigned. If there is one
|
||||||
|
or more trailing newlines, the last newline will be trimmed.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
build:
|
||||||
|
cmds:
|
||||||
|
- go build -ldflags="-X main.Version={{.GIT_COMMIT}}" main.go
|
||||||
|
vars:
|
||||||
|
GIT_COMMIT:
|
||||||
|
sh: git log -n 1 --format=%h
|
||||||
|
```
|
||||||
|
|
||||||
|
This works for all types of variables.
|
||||||
|
|
||||||
|
## Go's template engine
|
||||||
|
|
||||||
|
Task parse commands as [Go's template engine][gotemplate] before executing
|
||||||
|
them. Variables are accessible through dot syntax (`.VARNAME`).
|
||||||
|
|
||||||
|
All functions by the Go's [sprig lib](http://masterminds.github.io/sprig/)
|
||||||
|
are available. The following example gets the current date in a given format:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
print-date:
|
||||||
|
cmds:
|
||||||
|
- echo {{now | date "2006-01-02"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Task also adds the following functions:
|
||||||
|
|
||||||
|
- `OS`: Returns operating system. Possible values are "windows", "linux",
|
||||||
|
"darwin" (macOS) and "freebsd".
|
||||||
|
- `ARCH`: return the architecture Task was compiled to: "386", "amd64", "arm"
|
||||||
|
or "s390x".
|
||||||
|
- `splitLines`: Splits Unix (\n) and Windows (\r\n) styled newlines.
|
||||||
|
- `catLines`: Replaces Unix (\n) and Windows (\r\n) styled newlines with a space.
|
||||||
|
- `toSlash`: Does nothing on Unix, but on Windows converts a string from `\`
|
||||||
|
path format to `/`.
|
||||||
|
- `fromSlash`: Oposite of `toSlash`. Does nothing on Unix, but on Windows
|
||||||
|
converts a string from `\` path format to `/`.
|
||||||
|
- `exeExt`: Returns the right executable extension for the current OS
|
||||||
|
(`".exe"` for Windows, `""` for others).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
print-os:
|
||||||
|
cmds:
|
||||||
|
- echo '{{OS}} {{ARCH}}'
|
||||||
|
- echo '{{if eq OS "windows"}}windows-command{{else}}unix-command{{end}}'
|
||||||
|
# This will be path/to/file on Unix but path\to\file on Windows
|
||||||
|
- echo '{{fromSlash "path/to/file"}}'
|
||||||
|
enumerated-file:
|
||||||
|
vars:
|
||||||
|
CONTENT: |
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
cmds:
|
||||||
|
- |
|
||||||
|
cat << EOF > output.txt
|
||||||
|
{{range $i, $line := .CONTENT | splitLines -}}
|
||||||
|
{{printf "%3d" $i}}: {{$line}}
|
||||||
|
{{end}}EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
## Help
|
||||||
|
|
||||||
|
Running `task --list` (or `task -l`) lists all tasks with a description.
|
||||||
|
The following taskfile:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
build:
|
||||||
|
desc: Build the go binary.
|
||||||
|
cmds:
|
||||||
|
- go build -v -i main.go
|
||||||
|
|
||||||
|
test:
|
||||||
|
desc: Run all the go tests.
|
||||||
|
cmds:
|
||||||
|
- go test -race ./...
|
||||||
|
|
||||||
|
js:
|
||||||
|
cmds:
|
||||||
|
- minify -o public/script.js src/js
|
||||||
|
|
||||||
|
css:
|
||||||
|
cmds:
|
||||||
|
- minify -o public/style.css src/css
|
||||||
|
```
|
||||||
|
|
||||||
|
would print the following output:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
* build: Build the go binary.
|
||||||
|
* test: Run all the go tests.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Silent mode
|
||||||
|
|
||||||
|
Silent mode disables echoing of commands before Task runs it.
|
||||||
|
For the following Taskfile:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
echo:
|
||||||
|
cmds:
|
||||||
|
- echo "Print something"
|
||||||
|
```
|
||||||
|
|
||||||
|
Normally this will be print:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
echo "Print something"
|
||||||
|
Print something
|
||||||
|
```
|
||||||
|
|
||||||
|
With silent mode on, the below will be print instead:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
Print something
|
||||||
|
```
|
||||||
|
|
||||||
|
There's three ways to enable silent mode:
|
||||||
|
|
||||||
|
* At command level:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
echo:
|
||||||
|
cmds:
|
||||||
|
- cmd: echo "Print something"
|
||||||
|
silent: true
|
||||||
|
```
|
||||||
|
|
||||||
|
* At task level:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
echo:
|
||||||
|
cmds:
|
||||||
|
- echo "Print something"
|
||||||
|
silent: true
|
||||||
|
```
|
||||||
|
|
||||||
|
* Or globally with `--silent` or `-s` flag
|
||||||
|
|
||||||
|
If you want to suppress stdout instead, just redirect a command to `/dev/null`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
echo:
|
||||||
|
cmds:
|
||||||
|
- echo "This will print nothing" > /dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dry run mode
|
||||||
|
|
||||||
|
Dry run mode (`--dry`) compiles and steps through each task, printing the commands
|
||||||
|
that would be run without executing them. This is useful for debugging your Taskfiles.
|
||||||
|
|
||||||
|
## Ignore errors
|
||||||
|
|
||||||
|
You have the option to ignore errors during command execution.
|
||||||
|
Given the following Taskfile:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
echo:
|
||||||
|
cmds:
|
||||||
|
- exit 1
|
||||||
|
- echo "Hello World"
|
||||||
|
```
|
||||||
|
|
||||||
|
Task will abort the execution after running `exit 1` because the status code `1` stands for `EXIT_FAILURE`.
|
||||||
|
However it is possible to continue with execution using `ignore_error`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
echo:
|
||||||
|
cmds:
|
||||||
|
- cmd: exit 1
|
||||||
|
ignore_error: true
|
||||||
|
- echo "Hello World"
|
||||||
|
```
|
||||||
|
|
||||||
|
`ignore_error` can also be set for a task, which mean errors will be supressed
|
||||||
|
for all commands. But keep in mind this option won't propagate to other tasks
|
||||||
|
called either by `deps` or `cmds`!
|
||||||
|
|
||||||
|
## Output syntax
|
||||||
|
|
||||||
|
By default, Task just redirect the STDOUT and STDERR of the running commands
|
||||||
|
to the shell in real time. This is good for having live feedback for log
|
||||||
|
printed by commands, but the output can become messy if you have multiple
|
||||||
|
commands running at the same time and printing lots of stuff.
|
||||||
|
|
||||||
|
To make this more customizable, there are currently three different output
|
||||||
|
options you can choose:
|
||||||
|
|
||||||
|
- `interleaved` (default)
|
||||||
|
- `group`
|
||||||
|
- `prefixed`
|
||||||
|
|
||||||
|
To choose another one, just set it to root in the Taskfile:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
output: 'group'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
The `group` output will print the entire output of a command once, after it
|
||||||
|
finishes, so you won't have live feedback for commands that take a long time
|
||||||
|
to run.
|
||||||
|
|
||||||
|
The `prefix` output will prefix every line printed by a command with
|
||||||
|
`[task-name] ` as the prefix, but you can customize the prefix for a command
|
||||||
|
with the `prefix:` attribute:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
output: prefixed
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
deps:
|
||||||
|
- task: print
|
||||||
|
vars: {TEXT: foo}
|
||||||
|
- task: print
|
||||||
|
vars: {TEXT: bar}
|
||||||
|
- task: print
|
||||||
|
vars: {TEXT: baz}
|
||||||
|
|
||||||
|
print:
|
||||||
|
cmds:
|
||||||
|
- echo "{{.TEXT}}"
|
||||||
|
prefix: "print-{{.TEXT}}"
|
||||||
|
silent: true
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ task default
|
||||||
|
[print-foo] foo
|
||||||
|
[print-bar] bar
|
||||||
|
[print-baz] baz
|
||||||
|
```
|
||||||
|
|
||||||
|
## Watch tasks
|
||||||
|
|
||||||
|
If you give a `--watch` or `-w` argument, 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.
|
||||||
|
|
||||||
|
[gotemplate]: https://golang.org/pkg/text/template/
|
||||||
|
[minify]: https://github.com/tdewolff/minify/tree/master/cmd/minify
|
@ -14,9 +14,12 @@ import (
|
|||||||
// Taskfile reads a Taskfile for a given directory
|
// Taskfile reads a Taskfile for a given directory
|
||||||
func Taskfile(dir string) (*taskfile.Taskfile, error) {
|
func Taskfile(dir string) (*taskfile.Taskfile, error) {
|
||||||
path := filepath.Join(dir, "Taskfile.yml")
|
path := filepath.Join(dir, "Taskfile.yml")
|
||||||
|
if _, err := os.Stat(path); err != nil {
|
||||||
|
return nil, fmt.Errorf(`No Taskfile.yml found. Use "task --init" to create a new one`)
|
||||||
|
}
|
||||||
t, err := readTaskfile(path)
|
t, err := readTaskfile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(`No Taskfile.yml found. Use "task --init" to create a new one`)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for namespace, path := range t.Includes {
|
for namespace, path := range t.Includes {
|
||||||
|
@ -12,9 +12,9 @@ import (
|
|||||||
// Status returns an error if any the of given tasks is not up-to-date
|
// Status returns an error if any the of given tasks is not up-to-date
|
||||||
func (e *Executor) Status(calls ...taskfile.Call) error {
|
func (e *Executor) Status(calls ...taskfile.Call) error {
|
||||||
for _, call := range calls {
|
for _, call := range calls {
|
||||||
t, ok := e.Taskfile.Tasks[call.Task]
|
t, err := e.CompiledTask(call)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return &taskNotFoundError{taskName: call.Task}
|
return err
|
||||||
}
|
}
|
||||||
isUpToDate, err := isTaskUpToDate(e.Context, t)
|
isUpToDate, err := isTaskUpToDate(e.Context, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
28
watch.go
28
watch.go
@ -2,7 +2,10 @@ package task
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-task/task/internal/taskfile"
|
"github.com/go-task/task/internal/taskfile"
|
||||||
@ -40,6 +43,8 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closeOnInterrupt(w)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -66,6 +71,7 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
|||||||
e.Logger.Errf("%v", err)
|
e.Logger.Errf("%v", err)
|
||||||
}
|
}
|
||||||
case <-w.Closed:
|
case <-w.Closed:
|
||||||
|
cancel()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,6 +90,19 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
|||||||
return w.Start(time.Second)
|
return w.Start(time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isContextError(err error) bool {
|
||||||
|
return err == context.Canceled || err == context.DeadlineExceeded
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeOnInterrupt(w *watcher.Watcher) {
|
||||||
|
ch := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(ch, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-ch
|
||||||
|
w.Close()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Call) error {
|
func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Call) error {
|
||||||
oldWatchedFiles := make(map[string]struct{})
|
oldWatchedFiles := make(map[string]struct{})
|
||||||
for f := range w.WatchedFiles() {
|
for f := range w.WatchedFiles() {
|
||||||
@ -140,12 +159,3 @@ func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Ca
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isContextError(err error) bool {
|
|
||||||
switch err {
|
|
||||||
case context.Canceled, context.DeadlineExceeded:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user