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