Taskfile.yaml

  1# https://taskfile.dev
  2
  3version: "3"
  4
  5vars:
  6  VERSION:
  7    sh: git describe --long 2>/dev/null || echo ""
  8  RACE:
  9    sh: test -f race.log && echo "1" || echo ""
 10
 11env:
 12  CGO_ENABLED: 0
 13  GOEXPERIMENT: greenteagc
 14
 15tasks:
 16  lint:install:
 17    desc: Install golangci-lint
 18    cmds:
 19      - go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
 20    env:
 21      GOTOOLCHAIN: go1.25.0
 22
 23  lint:
 24    desc: Run base linters
 25    cmds:
 26      - task: lint:log
 27      - golangci-lint run --path-mode=abs --config=".golangci.yml" --timeout=5m
 28    env:
 29      GOEXPERIMENT: null
 30
 31  lint:log:
 32    desc: Check that log messages start with capital letters
 33    cmds:
 34      - ./scripts/check_log_capitalization.sh
 35
 36  lint:fix:
 37    desc: Run base linters and fix issues
 38    cmds:
 39      - golangci-lint run --path-mode=abs --config=".golangci.yml" --timeout=5m --fix
 40    env:
 41      GOEXPERIMENT: null
 42
 43  build:
 44    desc: Run build
 45    vars:
 46      LDFLAGS: '{{if .VERSION}}-ldflags="-X github.com/charmbracelet/crush/internal/version.Version={{.VERSION}}"{{end}}'
 47    cmds:
 48      - "go build -v {{if .RACE}}-race{{end}} {{.LDFLAGS}} ."
 49    sources:
 50      - ./**/*.go
 51      - go.mod
 52    generates:
 53      - crush{{exeExt}}
 54
 55  run:
 56    desc: Run build
 57    cmds:
 58      - task: build
 59      - "./crush{{exeExt}} {{.CLI_ARGS}} {{if .RACE}}2>race.log{{end}}"
 60
 61  run:catwalk:
 62    desc: Run build with local Catwalk
 63    env:
 64      CATWALK_URL: http://localhost:8080
 65    cmds:
 66      - task: build
 67      - ./crush{{exeExt}} {{.CLI_ARGS}}
 68
 69  run:onboarding:
 70    desc: Run build with custom config to test onboarding
 71    env:
 72      CRUSH_GLOBAL_DATA: tmp/onboarding/data
 73      CRUSH_GLOBAL_CONFIG: tmp/onboarding/config
 74    cmds:
 75      - task: build
 76      - rm -rf tmp/onboarding
 77      - ./crush{exeExt} {{.CLI_ARGS}}
 78
 79  test:
 80    desc: Run tests
 81    cmds:
 82      - go test -race -failfast ./... {{.CLI_ARGS}}
 83
 84  test:record:
 85    desc: Run tests and record all VCR cassettes again
 86    aliases: [record]
 87    cmds:
 88      - rm -r internal/agent/testdata
 89      - go test -v -count=1 -timeout=1h ./internal/agent
 90
 91  fmt:
 92    desc: Run gofumpt
 93    cmds:
 94      - gofumpt -w .
 95
 96  fmt:html:
 97    desc: Run prettier on HTML/CSS/JS files
 98    cmds:
 99      - prettier --write internal/cmd/stats/index.html internal/cmd/stats/index.css internal/cmd/stats/index.js
100
101  modernize:
102    desc: Run modernize
103    cmds:
104      - go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -fix -test ./...
105
106  dev:
107    desc: Run with profiling enabled
108    env:
109      CRUSH_PROFILE: true
110    cmds:
111      - go run .
112
113  install:
114    desc: Install the application
115    vars:
116      LDFLAGS: '{{if .VERSION}}-ldflags="-X github.com/charmbracelet/crush/internal/version.Version={{.VERSION}}"{{end}}'
117    cmds:
118      - task: fetch-tags
119      - go install {{.LDFLAGS}} -v .
120    sources:
121      - ./**/*.go
122      - go.mod
123
124  profile:cpu:
125    desc: 10s CPU profile
126    cmds:
127      - go tool pprof -http :6061 'http://localhost:6060/debug/pprof/profile?seconds=10'
128
129  profile:heap:
130    desc: Heap profile
131    cmds:
132      - go tool pprof -http :6061 'http://localhost:6060/debug/pprof/heap'
133
134  profile:allocs:
135    desc: Allocations profile
136    cmds:
137      - go tool pprof -http :6061 'http://localhost:6060/debug/pprof/allocs'
138
139  schema:
140    desc: Generate JSON schema for configuration
141    cmds:
142      - go run main.go schema > schema.json
143      - echo "Generated schema.json"
144    generates:
145      - schema.json
146
147  hyper:
148    desc: Update Hyper embedded provider.json
149    cmds:
150      - go generate ./internal/agent/hyper/...
151    generates:
152      - ./internal/agent/hyper/provider.json
153
154  release:
155    desc: Create and push a new tag following semver
156    vars:
157      NEXT:
158        sh: svu next --always || go run github.com/caarlos0/svu/v3@latest next --always
159    prompt: "This will release {{.NEXT}}. Continue?"
160    preconditions:
161      - sh: '[ $(git symbolic-ref --short HEAD) = "main" ]'
162        msg: Not on main branch
163      - sh: "[ $(git status --porcelain=2 | wc -l) = 0 ]"
164        msg: "Git is dirty"
165      - sh: 'gh run list --workflow build.yml --commit $(git rev-parse HEAD) --status success --json conclusion -q ".[0].conclusion" | grep -q success'
166        msg: "Test build for this commit failed or not present"
167      - sh: 'gh run list --workflow snapshot.yml --commit $(git rev-parse HEAD) --status success --json conclusion -q ".[0].conclusion" | grep -q success'
168        msg: "Snapshot build for this commit failed or not present"
169    cmds:
170      - task: fetch-tags
171      - git commit --allow-empty -m "{{.NEXT}}"
172      - git tag --annotate --sign -m "{{.NEXT}}" {{.NEXT}} {{.CLI_ARGS}}
173      - echo "Pushing {{.NEXT}}..."
174      - git push origin main --follow-tags
175
176  fetch-tags:
177    cmds:
178      - git tag -d nightly || true
179      - git fetch --tags
180
181  deps:
182    desc: Update Fantasy and Catwalk
183    cmds:
184      - go get charm.land/fantasy
185      - go get charm.land/catwalk
186      - go mod tidy
187
188  release:fork:
189    desc: Create and push a fork release tag (combined workflow)
190    cmds:
191      - task: release:fork:tag
192      - task: release:fork:push
193
194  release:fork:tag:
195    desc: Create a fork release tag locally (without pushing)
196    vars:
197      UPSTREAM_VERSION:
198        sh: git tag -l "v*" | sort -V | tail -1 || echo "v0.0.0"
199      EXISTING_FORK_TAGS:
200        sh: git tag -l "{{.UPSTREAM_VERSION}}-fork.*" | wc -l
201      NEXT_NUM:
202        sh: echo $(({{.EXISTING_FORK_TAGS}} + 1))
203      TAG: "{{.UPSTREAM_VERSION}}-fork.{{.NEXT_NUM}}"
204    prompt: "Create fork release {{.TAG}}?"
205    preconditions:
206      - sh: '[ $(git symbolic-ref --short HEAD) = "dev" ]'
207        msg: Not on dev branch
208      - sh: "[ $(git status --porcelain=2 | wc -l) = 0 ]"
209        msg: "Git is dirty"
210    cmds:
211      - git tag -d nightly || true
212      - git fetch upstream --tags
213      - >-
214        crush run -m kimi-k2.5h "Please update the mentioned version in the top of the README to {{.TAG}}.
215        You only need to read the first 65 lines for the relevant bits.
216        If the content is already correct, you don't need to do anything.
217        Amend the commit at HEAD, updating its subject/message if necessary.
218        Use the skill."
219      - git show --stat HEAD
220      - defer:
221          task: release:fork:cleanup
222          vars:
223            TAG: "{{.TAG}}"
224      - task: release:fork:confirm
225      - git push --force-with-lease
226      - git tag -a {{.TAG}}
227      - echo "Tagged {{.TAG}} locally. Run 'task release:fork:push' to push."
228
229  release:fork:push:
230    desc: Push an existing fork release tag and notify module proxy
231    vars:
232      TAG:
233        sh: git describe --tags --abbrev=0 --match "*-fork.*" 2>/dev/null || echo ""
234    preconditions:
235      - sh: '[ -n "{{.TAG}}" ]'
236        msg: "No fork tag found. Run 'task release:fork:tag' first."
237      - sh: 'git tag -l "{{.TAG}}" | grep -q "{{.TAG}}"'
238        msg: "Tag {{.TAG}} does not exist locally"
239    prompt: "Push {{.TAG}} to remote and notify module proxy?"
240    cmds:
241      - git push soft {{.TAG}}
242      - echo "Released {{.TAG}}"
243      - go list -m git.secluded.site/crush@{{.TAG}} > /dev/null
244      - echo "Module proxy notified"
245
246  release:fork:confirm:
247    desc: Review LLM-generated commit and confirm release
248    internal: true
249    prompt: "Proceed with tagging?"
250
251  release:fork:cleanup:
252    desc: Undo LLM commit if release aborted
253    internal: true
254    cmds:
255      - git tag -d {{.TAG}} 2>/dev/null || true
256    status:
257      - git tag -l {{.TAG}} | grep -q {{.TAG}}