/ Taskfile.yml
Taskfile.yml
1 # yaml-language-server: $schema=https://taskfile.dev/schema.json 2 version: "3" 3 dotenv: [".env"] 4 vars: 5 SHELL: /usr/bin/env bash -o pipefail 6 DOTFILES_HOME: "{{.USER_WORKING_DIR}}" 7 DOTFILES_CONFIG: "{{.DOTFILES_HOME}}/etc/config" 8 DOTFILES_PROFILE: "{{.DOTFILES_HOME}}/etc/profile" 9 DOTFILES_RC: "{{.DOTFILES_HOME}}/etc/rc" 10 DOTFILES_SCRIPTS: "{{.DOTFILES_HOME}}/scripts" 11 includes: 12 common:install:core: 13 taskfile: ./tasks/common/install/core/Taskfile.yml 14 linux:install:apt: 15 taskfile: ./tasks/linux/install/apt/Taskfile.yml 16 macos:install:brew: 17 taskfile: ./tasks/macos/install/brew/Taskfile.yml 18 macos:install:core: 19 taskfile: ./tasks/macos/install/core/Taskfile.yml 20 macos:install:docker: 21 taskfile: ./tasks/macos/install/docker/Taskfile.yml 22 macos:install:go: 23 taskfile: ./tasks/macos/install/go/Taskfile.yml 24 macos:install:java: 25 taskfile: ./tasks/macos/install/java/Taskfile.yml 26 macos:install:k8s: 27 taskfile: ./tasks/macos/install/k8s/Taskfile.yml 28 macos:install:hammerspoon: 29 taskfile: ./tasks/macos/install/hammerspoon/Taskfile.yml 30 macos:install:rust: 31 taskfile: ./tasks/macos/install/rust/Taskfile.yml 32 agents: 33 taskfile: ./tasks/agents/Taskfile.yml 34 tasks: 35 default: 36 cmds: 37 - task: list 38 silent: true 39 list: 40 desc: Lists available commands 41 cmds: 42 - task -l 43 hooks: 44 desc: Setup git hooks locally 45 cmds: 46 - cp scripts/hooks/* .git/hooks/ 47 silent: true 48 test:lua: 49 desc: "Run Lua Gherkin features (byfeature-style output with colors) and Busted specs" 50 dir: "{{.DOTFILES_HOME}}" 51 cmds: 52 - cmd: "LUA_PATH='{{.DOTFILES_HOME}}/lua_modules/share/lua/5.4/?.lua;{{.DOTFILES_HOME}}/lua_modules/share/lua/5.4/?/init.lua;;' LUA_CPATH='{{.DOTFILES_HOME}}/lua_modules/lib/lua/5.4/?.so;;' lua tests/run_features.lua" 53 - cmd: "LUA_PATH='{{.DOTFILES_HOME}}/lua_modules/share/lua/5.4/?.lua;{{.DOTFILES_HOME}}/lua_modules/share/lua/5.4/?/init.lua;;' LUA_CPATH='{{.DOTFILES_HOME}}/lua_modules/lib/lua/5.4/?.so;;' lua {{.DOTFILES_HOME}}/lua_modules/lib/luarocks/rocks-5.4/busted/2.3.0-1/bin/busted tests/spec --no-coverage" 54 precommit: 55 desc: Verifies and fix requirements for new commits 56 cmds: 57 - scripts/hooks/pre-commit 58 markdownlint: 59 desc: Lint Markdown with markdownlint-cli (.markdownlint.yaml) 60 dir: "{{.TASKFILE_DIR}}" 61 cmds: 62 - cmd: "markdownlint -c .markdownlint.yaml '**/*.md' -i CHANGELOG.md" 63 yamlfmt: 64 desc: "Format YAML files with yamlfmt (install with: go install github.com/google/yamlfmt/cmd/yamlfmt@latest)" 65 dir: "{{.TASKFILE_DIR}}" 66 cmds: 67 - | 68 find . \( -name "*.yaml" -o -name "*.yml" \) \ 69 -not -path "./.git/*" \ 70 -not -path "./node_modules/*" \ 71 -not -path "./.devbox/*" \ 72 -exec yamlfmt -w {} + 2>/dev/null || true 73 jsonfmt: 74 desc: Format JSON with jq (sort keys, validate) 75 dir: "{{.TASKFILE_DIR}}" 76 cmds: 77 - | 78 for f in $(git ls-files '*.json' 2>/dev/null); do 79 [ -f "$f" ] && jq -e . "$f" >/dev/null 2>&1 && jq -S . "$f" > "$f.tmp" && mv "$f.tmp" "$f" || true 80 done 81 version:next: 82 desc: "Calculate next semver from conventional commits since last v* tag (feat→minor, fix→patch, breaking→major)" 83 dir: "{{.TASKFILE_DIR}}" 84 cmds: 85 - scripts/calc-next-version.sh 86 changelog: 87 silent: true 88 desc: Generates CHANGELOG 89 cmds: 90 - echo "Updating Changelog" 91 - cmd: |- 92 export RUST_LOG=error 93 git cliff --context \ 94 | jq '.[].commits.[] |= (. + {extra: {date: ( .committer.timestamp | strftime("%Y-%m-%d") )}} ) | sort_by(.commits.[].commit.committer.timestamp)' \ 95 | jq -S 'walk(if type == "array" then sort_by(.timestamp) | reverse else . end)' \ 96 | git cliff --from-context - > CHANGELOG.md 97 - cmd: git add {{.USER_WORKING_DIR}}/CHANGELOG.md 98 changelog:rewrite-history: 99 desc: "Rewrite all commit messages to conventional format (DESTRUCTIVE; backup first, then force-push)" 100 dir: "{{.TASKFILE_DIR}}" 101 cmds: 102 - | 103 echo "This rewrites git history (new SHAs). Backup first: git clone --mirror . ../.dotfiles-backup.git" 104 echo "After running: git push --force-with-lease" 105 read -p "Continue? [y/N] " r; [[ "$r" != "y" && "$r" != "Y" ]] && exit 1 106 git filter-branch -f --msg-filter "{{.TASKFILE_DIR}}/scripts/rewrite-commit-messages.sh" -- --all 107 devbox:install-cli: 108 desc: Install Devbox CLI (required before devbox:install; uses official install script) 109 dir: "{{.TASKFILE_DIR}}" 110 cmds: 111 - | 112 if command -v devbox >/dev/null 2>&1; then 113 echo "devbox already installed: $(devbox version 2>/dev/null || devbox --version 2>/dev/null || true)" 114 exit 0 115 fi 116 echo "Installing Devbox via official script (https://www.jetify.com/docs/devbox/installing-devbox)..." 117 echo "Devbox may install Nix if not present. Run as non-root on Linux." 118 curl -fsSL https://get.jetify.com/devbox | bash 119 devbox:install: 120 desc: Install devbox dependencies (run once after clone or when devbox.json changes) 121 dir: "{{.TASKFILE_DIR}}" 122 preconditions: 123 - sh: command -v devbox 124 msg: "devbox not in PATH. Run 'task devbox:install-cli' first, then retry." 125 - sh: test -f "{{.TASKFILE_DIR}}/devbox.json" 126 msg: "devbox.json not found in project root." 127 cmds: 128 - devbox install 129 devbox:shell: 130 desc: Enter devbox shell with all dev tools on PATH 131 dir: "{{.TASKFILE_DIR}}" 132 preconditions: 133 - sh: command -v devbox 134 msg: "devbox not in PATH. Run 'task devbox:install-cli' first." 135 - sh: test -f "{{.TASKFILE_DIR}}/devbox.json" 136 msg: "devbox.json not found in project root." 137 cmds: 138 - devbox shell 139 devbox:add: 140 desc: "Add a package to devbox.json and pull globally. Usage: task devbox:add -- <package@version>" 141 dir: "{{.TASKFILE_DIR}}" 142 preconditions: 143 - sh: command -v devbox 144 msg: "devbox not in PATH. Run 'task devbox:install-cli' first." 145 - sh: test -f "{{.TASKFILE_DIR}}/devbox.json" 146 msg: "devbox.json not found in project root." 147 - sh: '[ -n "{{.CLI_ARGS}}" ]' 148 msg: "No package specified. Usage: task devbox:add -- <package@version>" 149 cmds: 150 - devbox add {{.CLI_ARGS}} 151 - devbox global pull {{.TASKFILE_DIR}}/devbox.json -f 152 devbox:gc: 153 desc: Run Nix garbage collection and store optimisation to reclaim disk space 154 dir: "{{.TASKFILE_DIR}}" 155 cmds: 156 - nix-collect-garbage -d 157 - nix-store --optimise 158 nvim:update: 159 desc: Download and install the latest Neovim nightly from upstream (always runs) 160 cmds: 161 - task: common:install:core:nvim:update 162 nvim:deps: 163 desc: Install and verify all Neovim external deps (tree-sitter via prebuilt binary; rest via devbox) 164 dir: "{{.TASKFILE_DIR}}" 165 cmds: 166 - | 167 # tree-sitter: nixpkgs tops out at 0.25.x; nvim-treesitter requires 0.26.1+ 168 # cargo build fails on Linux due to clang/system header path issues, so use the prebuilt binary. 169 TS_VERSION="0.26.7" 170 if command -v tree-sitter >/dev/null 2>&1 && tree-sitter --version 2>/dev/null | grep -qE '0\.2[6-9]\.'; then 171 echo " ✓ tree-sitter ($(tree-sitter --version | head -1))" 172 else 173 case "$(uname -s)-$(uname -m)" in 174 Linux-x86_64) TS_ASSET="tree-sitter-linux-x64" ;; 175 Linux-aarch64) TS_ASSET="tree-sitter-linux-arm64" ;; 176 Darwin-x86_64) TS_ASSET="tree-sitter-macos-x64" ;; 177 Darwin-arm64) TS_ASSET="tree-sitter-macos-arm64" ;; 178 *) echo " ✗ unsupported platform for tree-sitter prebuilt binary" >&2; exit 1 ;; 179 esac 180 echo " ↳ downloading tree-sitter v${TS_VERSION} (${TS_ASSET})..." 181 URL="https://github.com/tree-sitter/tree-sitter/releases/download/v${TS_VERSION}/${TS_ASSET}.gz" 182 curl -fsSL "$URL" | gunzip -c > "${HOME}/.local/bin/tree-sitter" 183 chmod +x "${HOME}/.local/bin/tree-sitter" 184 echo " ✓ tree-sitter ($(tree-sitter --version | head -1))" 185 fi 186 - | 187 ok=1 188 for tool in stylua shfmt ruff prettierd gopls rust-analyzer gofumpt golangci-lint govulncheck dlv chafa viu; do 189 if command -v "$tool" >/dev/null 2>&1; then 190 echo " ✓ $tool" 191 else 192 echo " ✗ $tool - not found (run 'devbox install' or 'devbox global pull devbox.json -f')" >&2 193 ok=0 194 fi 195 done 196 [ "$ok" -eq 1 ] || exit 1 197 - echo "All deps present. For LuaRocks run 'task nvim:luarocks-build', for blink.cmp native lib run 'task nvim:blink-build'." 198 nvim:luarocks-build: 199 desc: Run LuaRocks.nvim build once (compiles local LuaRocks; then setup() installs rocks) 200 dir: "{{.TASKFILE_DIR}}" 201 cmds: 202 - | 203 PLUGIN_DIR=$(find "${XDG_DATA_HOME:-$HOME/.local/share}/nvim/site/pack" -maxdepth 4 -type d -name "luarocks.nvim" 2>/dev/null | head -1) 204 if [ -z "$PLUGIN_DIR" ]; then 205 echo "luarocks.nvim not found in pack dir. Start nvim once so plugins are installed, then run this task again." >&2 206 exit 1 207 fi 208 if [ ! -f "$PLUGIN_DIR/build.lua" ]; then 209 echo "build.lua not found in $PLUGIN_DIR" >&2 210 exit 1 211 fi 212 echo "Running LuaRocks.nvim build in $PLUGIN_DIR ..." 213 LUA51_PREFIX=$(ls -d /nix/store/*lua-5.1*[^.drv] 2>/dev/null | head -1) 214 if [ -n "$LUA51_PREFIX" ] && [ -f "$LUA51_PREFIX/bin/lua" ]; then 215 TMPLUA=$(mktemp -d) 216 mkdir -p "$TMPLUA/bin" "$TMPLUA/include" 217 ln -s "$LUA51_PREFIX/bin/lua" "$TMPLUA/bin/lua5.1" 218 ln -s "$LUA51_PREFIX/include" "$TMPLUA/include/lua5.1" 219 export PATH="$TMPLUA/bin:$PATH" 220 fi 221 cd "$PLUGIN_DIR" && nvim -l build.lua 222 [ -n "$TMPLUA" ] && rm -rf "$TMPLUA" 223 nvim:blink-build: 224 desc: Build blink.cmp native fuzzy lib from source via cargo (fixes blink_cmp_fuzzy checkhealth warning) 225 dir: "{{.TASKFILE_DIR}}" 226 cmds: 227 - | 228 PLUGIN_DIR=$(find "${XDG_DATA_HOME:-$HOME/.local/share}/nvim/site/pack" -maxdepth 4 -type d -name "blink.cmp" 2>/dev/null | head -1) 229 if [ -z "$PLUGIN_DIR" ]; then 230 echo "blink.cmp not found in pack dir. Start nvim once so plugins are installed, then run this task again." >&2 231 exit 1 232 fi 233 echo "Building blink.cmp native fuzzy lib in $PLUGIN_DIR ..." 234 cd "$PLUGIN_DIR" && cargo build --release 235 echo "Done. Restart Neovim and run :checkhealth to verify." 236 nvim:pack-lock-sync: 237 desc: Sync nvim-pack-lock.json with full SHAs from installed plugins (fixes vim.pack lockfile checkhealth errors) 238 dir: "{{.TASKFILE_DIR}}" 239 cmds: 240 - nvim -l {{.TASKFILE_DIR}}/scripts/nvim-pack-lock-sync.lua 241 nvim:reset: 242 desc: "Backup ~/.local/share/nvim, ~/.local/state/nvim, ~/.cache/nvim with timestamped suffix (e.g. nvim.bak-YYYYMMDD-HHMMSS). Leaves ~/.config/nvim untouched so your config (or symlink) stays; start nvim and pack will auto-install plugins from scratch like Lazy did." 243 dir: "{{.TASKFILE_DIR}}" 244 cmds: 245 - ./scripts/backup-nvim-dirs.sh 246 nvim:restore: 247 desc: "Rollback to the most recent nvim backup (nvim.bak-*). Stashes any current dirs as nvim.broken-TIMESTAMP before restoring, so nothing is lost." 248 dir: "{{.TASKFILE_DIR}}" 249 cmds: 250 - ./scripts/restore-nvim-dirs.sh 251 linux:install:all: 252 desc: Install base packages and core setup on Linux (apt + common core) 253 cmds: 254 - task: linux:install:apt:all 255 - task: common:install:core:all 256 macos:install:all: 257 desc: Install all MacOS required tools 258 cmds: 259 - task: macos:install:brew:all 260 - task: macos:install:core:all 261 - task: macos:install:docker:all 262 - task: macos:install:go:all 263 - task: macos:install:k8s:all 264 - task: macos:install:java:all 265 - task: macos:install:npm:all 266 - task: macos:install:python:all 267 - task: macos:install:rust:all