Taskfile - 比 Makefile 更好用的構建工具
- Taskfile 是什麼
Taskfile 通過 yaml 來描述各種執行任務, 其核心採用 go 編寫; 相較於 Makefile 的 tab 分割和 bash 結合語法 Taskfile 顯得更加現代化和易於使用 (雖然會變成 yaml 工程師). Taskfile 內置了動態變量、操作系統等環境變量識別等高級功能都更貼合現代化的 Coding 方式。
總體來說如果你是一個對 Makefile 不太熟悉的人, 又期望通過類似 Makefile 的工具完成一些批量任務, 那麼相對於 Makefile 來說 Taskfile 會更加便於入門, 學習曲線更低且速度也足夠快。
- 安裝及使用
安裝 go-task
對於 mac 用戶來說官方提供了 brew 安裝方式:
$ brew install go-task/tap/go-task
對於 Linux 用戶, 官方提供了部分 Linux 發行版的安裝包, 但由於其只有一個二進制文件, 所以官方也提供了快速安裝腳本:
# For Default Installation 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
如果本地已經有了 Go 語言開發環境也可以直接通過 go 命令安裝:
$ go install github.com/go-task/task/v3/cmd/task@latest
快速開始
安裝完成後, 只需要編寫一個 Taskfile.yml
的 yaml 文件, 然後就可以通過 task
命令運行相應的任務:
version: '3'
tasks:
build:
cmds:
- echo "執行 build 任務"
docker:
cmds:
- echo "打包 docker 鏡像"
如果需要設置默認執行任務, 只需要創建一個名字爲 default
的任務即可:
version: '3'
tasks:
default:
cmds:
- echo "這是默認任務"
build:
cmds:
- echo "執行 build 任務"
docker:
cmds:
- echo "打包 docker 鏡像"
- 進階使用
環境變量
Taskfile 支持引用三種環境變量:
-
Shell 環境變量
-
Taskfile 內定義的環境變量
-
變量文件內定義的環境變量
如果需要引用 Shell 內的環境變量只需要使用 $ 變量名
方式直接引用即可:
version: '3'
tasks:
default:
cmds:
- echo "$ABCD"
同樣在 Taskfile 內也可以定義環境變量:
version: '3'
env:
TENV2: "t2" # 全局環境變量
tasks:
default:
cmds:
- echo "$TENV1"
- echo "$TENV2"
env:
TENV1: "t1" # 單個 task 環境變量
除了這種直接引用變量的方式, Taskfile 也支持類似 docker-compose 一樣讀取 env 文件來加載環境變量; Taskfile 會默認加載同級目錄下的 .env
文件, 也可以在 Taskfile 內通過 dotenv
命令來配置特定文件:
version: '3'
dotenv: [".env", ".testenv"]
tasks:
default:
cmds:
- echo "$ABCD"
- echo "$TESTENV"
增強變量
除了標準的環境變量以外, 在 Taskfile 中還內置了一種使用更加廣泛的增強變量 vars
; 該變量模式可以通過 go 的模版引擎進行讀取 (插值引用), 且具有環境變量不具備的特殊特性. 以下爲 vars 變量的示例:
version: '3'
# 全局 var 變量
vars:
GLOBAL_VAR: "global var"
tasks:
testvar:
# task var 變量
vars:
TASK_VAR: "task var"
cmds:
- "echo {{.GLOBAL_VAR}}"
- "echo {{.TASK_VAR}}"
除了上面與環境變量類似的使用以外, vars 增強變量還支持動態定義; 常見的場景, 比如我們想每次 task 執行時都獲取當前的 git commit id, 此時可以使用 vars 的動態定義特性:
version: '3'
tasks:
build:
cmds:
- go build -ldflags="-X main.Version={{.GIT_COMMIT}}" main.go
vars:
# 每次任務執行時, GIT_COMMIT 都會調用 shell 命令來生成這個變量
GIT_COMMIT:
sh: git log -n 1 --format=%h
vars 變量還內置了一些特殊的預定義變量, 例如 {{.TASK}}
變量永遠表示當前的任務名稱、{{.CLI_ARGS}}
可以引用命令行輸入等.
version: '3'
tasks:
yarn:
cmds:
- yarn {{.CLI_ARGS}}
此時如果執行 task yarn -- install
, 那麼 {{.CLI_ARGS}}
值將會變成 install
從而執行 yarn install
命令.
除此之外, vars 變量還具備一些其他特性, 比如跨任務引用時可進行覆蓋傳遞等, 這些特性將會在後面介紹.
執行目錄
Taskfile 內定義的 task 默認在當前目錄下執行, 如果期望在其他目錄執行, 無需手動編寫 cd
等命令, 可以直接通過配置 dir
參數來設置執行目錄:
version: '3'
tasks:
test1:
dir: /tmp # 在指定目錄執行
cmds:
- "ls"
任務依賴
在 CI 等環境的使用中, 我們常常需要定義任務的執行順序和依賴關係; Taskfile 中通過 deps
配置來提供任務依賴關係的支持:
version: '3'
tasks:
build-jar:
cmds:
- echo "編譯 jar 包..."
build-static:
cmds:
- echo "編譯前端 UI..."
build-docker:
deps: [build-jar, build-static]
cmds:
- echo "打包 docker 鏡像..."
任務調用
當我們在 Taskfile 中定義了多個任務時, 很可能一些任務具有一定的相似性, 此時我們可以通過任務互相調用和 vars 變量動態覆蓋的方式來定義模版 Task:
version: '3'
tasks:
docker:
cmds:
#- docker build -t {{.IMAGE_NAME}} {{.BUILD_CONTEXT}}
- echo {{.IMAGE_NAME}} {{.BUILD_CONTEXT}}
build-backend:
cmds:
- task: docker # 引用其他 task
vars: { # 動態傳入變量
IMAGE_NAME: "backend",
BUILD_CONTEXT: "maven/target"
}
build-frontend:
cmds:
- task: docker
vars: {
IMAGE_NAME: "frontend",
BUILD_CONTEXT: "public"
}
default: # default 用於在命令行不顯示輸入任何 task 名稱時調用
cmds:
- task: build-backend
- task: build-frontend
引入其他文件
Taskfile 支持通過 includes
關鍵字來引入其他 Taskfile, 從而方便 Taskfile 的結構化處理.
需要注意的是, 由於引入的文件中可能會包含多特 task, 所以在使用時需要對引入的文件進行命名, 且通過命名引用目標 task:
version: '3'
includes:
file1: ./file1.yaml # 直接引用 yaml 文件
dir2: ./dir2 # 引用目錄時默認引用該目錄下的 Taskfile.yaml
在引入其他 Taskfile 時, 默認情況下會在當前主 Taskfile 目錄下執行命令, 我們同樣可以通過 dir
參數來控制引入的 Taskfile 內的 task 在特定目錄下執行:
version: '3'
includes:
dir1: ./dirtest.yaml # 直接在當前目錄執行
dir2:
taskfile: ./dirtest.yaml
dir: /tmp # 在指定目錄執行
defer 處理
熟悉 go 語言的同學應該知道, go 裏面有個很方便的關鍵字 defer
; 該指令用於定義在最終代碼收尾時要執行的動作, 常見的比如資源清理等. Taskfile 中同樣支持了該指令, 可以方便我們在任務執行期間完成一些清理操作:
version: '3'
tasks:
default: # default 用於在命令行不顯示輸入任何 task 名稱時調用
cmds:
- wget -q https://github.com/containerd/nerdctl/releases/download/v0.19.0/nerdctl-full-0.19.0-linux-amd64.tar.gz
# 定義清理動作
- defer: rm -f nerdctl-full-0.19.0-linux-amd64.tar.gz
- tar -zxf nerdctl-full-0.19.0-linux-amd64.tar.gz
當然, defer 指令除了直接寫命令以外, 還可以引用其他 task 完成清理:
version: '3'
tasks:
cleanup:
cmds:
- rm -f {{.FILE}}
default: # default 用於在命令行不顯示輸入任何 task 名稱時調用
cmds:
- wget -q https://github.com/containerd/nerdctl/releases/download/v0.19.0/nerdctl-full-0.19.0-linux-amd64.tar.gz
# 引用其他 task 進行清理, 同時也可以傳遞動態變量
- defer: {task: cleanup, vars: {FILE: nerdctl-full-0.19.0-linux-amd64.tar.gz}}
- tar -zxf nerdctl-full-0.19.0-linux-amd64.tar.gz
- 高級應用
動態檢測
輸出檢測
在某些時候, 一些任務我們可能期望進行緩存處理, 比如說已經下載好了文件就不要重複運行下載; 針對於這種需求, Taskfile 允許我們定義源文件和生成的文件, 通過這組文件的 hash 值來確定是否需要執行該任務:
version: '3'
tasks:
default:
cmds:
- wget -q https://github.com/containerd/nerdctl/releases/download/v0.19.0/nerdctl-full-0.19.0-linux-amd64.tar.gz
sources:
- testfile
generates:
- nerdctl-full-0.19.0-linux-amd64.tar.gz
從上圖中可以看到, 當首次執行任務時會生成 .task
目錄, 該目錄包含文件的 hash 值; 當重複執行任務時, 如果 hash 值不改變則真實任務不會真正執行. Taskfile 默認有兩種文件檢測的方式: checksum
、timestamp
, checksum
執行文件的 hash 檢測 (默認), 該模式只需要定義 sources
配置; timestamp
執行文件的時間戳檢測, 該模式需要同時定義 sources
和 generates
配置.
version: '3'
tasks:
build:
cmds:
- go build .
sources:
- ./*.go
generates:
- app{{exeExt}}
method: checksum # 指定檢測方式
除了內置的兩種檢測模式外, 我們還可以通過 status
配置來定義自己的檢測命令, 如果命令執行結果爲 0, 則認爲文件是最新的, 不需要執行任務:
version: '3'
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
輸入檢測
上面的輸出檢測用於檢測任務生成的文件結果等, 在某些情況下我們可能期望在運行任務之前來判斷某個條件, 在完全不執行的情況下確定任務是否需要運行; 此時我們可以使用 preconditions
配置指令:
version: '3'
tasks:
generate-files:
cmds:
- mkdir directory
- touch directory/file1.txt
- touch directory/file2.txt
# test existence of files
preconditions:
- test -f .env
- sh: "[ 1 = 0 ]"
msg: "One doesn't equal Zero, Halting"
Go 模版引擎
在上面變量環節中已經展示了一部分模版引擎的使用, 實際上 Taskfile 內集成了 slim-sprig[1] 庫, 該庫中提供了一些比較便利的方法, 這些方法都可以在模版引擎內使用:
version: '3'
tasks:
print-date:
cmds:
- echo {{now | date "2006-01-02"}}
關於這些方法和模版引擎的使用具體請參考 Go Template 相關文檔以及 slim-sprig[2] 文檔.
交互式終端
有些任務命令可能需要交互式終端來執行, 此時可以爲 task 設置 interactive
選項; 當 interactive
設置爲 true
時, task 在運行時可以打開交互式終端:
version: '3'
tasks:
cmds:
- vim my-file.txt
interactive: true
更多關於 Taskfile 的細節使用請閱讀其官方文檔 [3], 本文限於篇幅不在過多闡述。
引用鏈接
[1]
slim-sprig: https://go-task.github.io/slim-sprig/
[2]
slim-sprig: https://go-task.github.io/slim-sprig/
[3]
官方文檔: https://taskfile.dev/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/ahwxtGtzIgefTYHx0A-mtA