Engineering at Scale

I Ditched Makefiles for Taskfiles (And You Might Too)

So, confession time: I was that old school unix person who loved Makefiles. Like, really loved them. There was something about their structure and simplicity that just clicked with me, you know? I'd reach for Make for pretty much everything. But then this year happened, and I stumbled onto Taskfiles. Game changer. I've been using them for a few months now, and honestly? I'm converted. It's become my go-to build tool for literally everything. Started out just using it for my Go projects, but now I'm finding excuses to use it for all of my projects. Once you get the hang of it, it's hard to go back. If you're still riding the Makefile train (no judgment, I get it), maybe give Taskfiles a shot. You will be intrigued at minimum. Will everyone switch? Probably not. But if you're like me and appreciate tools that just work and are simple to use, it's worth an afternoon.

version: '3'

vars:
  BINARY_NAME: myapp
  MAIN_PATH: ./cmd/myapp
  BUILD_DIR: ./bin
  COVERAGE_FILE: coverage.out

env:
  CGO_ENABLED: 0
  GOOS: '{{OS}}'
  GOARCH: '{{ARCH}}'

tasks:
  install-golangci-lint:
    desc: Install golangci-lint if not present
    cmds:
      - go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
    status:
      - which golangci-lint
    silent: true

  build:
    desc: Build the application
    cmds:
      - mkdir -p {{.BUILD_DIR}}
      - go build -o {{.BUILD_DIR}}/{{.BINARY_NAME}} {{.MAIN_PATH}}
    sources:
      - '**/*.go'
      - go.mod
      - go.sum
    generates:
      - '{{.BUILD_DIR}}/{{.BINARY_NAME}}'

  build-prod:
    desc: Build optimized binary for production
    cmds:
      - mkdir -p {{.BUILD_DIR}}
      - go build -ldflags="-s -w" -o {{.BUILD_DIR}}/{{.BINARY_NAME}} {{.MAIN_PATH}}
    sources:
      - '**/*.go'
      - go.mod
      - go.sum
    generates:
      - '{{.BUILD_DIR}}/{{.BINARY_NAME}}'

  run:
    desc: Run the application
    deps: [build]
    cmds:
      - '{{.BUILD_DIR}}/{{.BINARY_NAME}}'

  test:
    desc: Run tests
    cmds:
      - go test -v ./...

  test-coverage:
    desc: Run tests with coverage
    cmds:
      - go test -v -coverprofile={{.COVERAGE_FILE}} ./...
      - go tool cover -html={{.COVERAGE_FILE}}

  test-race:
    desc: Run tests with race detector
    cmds:
      - go test -race -v ./...

  bench:
    desc: Run benchmarks
    cmds:
      - go test -bench=. -benchmem ./...

  lint:
    desc: Run golangci-lint
    deps: [install-golangci-lint]
    cmds:
      - golangci-lint run ./...

  tidy:
    desc: Tidy and verify go.mod
    cmds:
      - go mod tidy
      - go mod verify

  clean:
    desc: Clean build artifacts
    cmds:
      - rm -rf {{.BUILD_DIR}}
      - rm -f {{.COVERAGE_FILE}}
      - go clean -cache -testcache -modcache

  generate:
    desc: Run go generate
    cmds:
      - go generate ./...

  check:
    desc: Run all checks (fmt, vet, lint, test)
    deps: [fmt:check, vet, lint, test]

  ci:
    desc: Run CI pipeline locally
    cmds:
      - task: tidy
      - task: lint
      - task: test
      - task: build-prod