Building a CLI Tool in Go: Part 3 - Testing & Release

SERIES · BUILDING A CLI TOOL IN GO
3 / 3 View series

We’ve got a working CLI from Part 1 and Part 2. Now let’s make sure it doesn’t break and ship it properly.

Integration Tests with testscript

The testscript package lets you write integration tests that feel like shell scripts:

// integration_test.go
package main

import (
	"os"
	"testing"

	"github.com/rogpeppe/go-internal/testscript"
)

func TestMain(m *testing.M) {
	os.Exit(testscript.RunMain(m, map[string]func() int{
		"ddd": mainReturnCode,
	}))
}

func TestCLI(t *testing.T) {
	testscript.Run(t, testscript.Params{
		Dir: "testdata/scripts",
	})
}
# testdata/scripts/scan.txtar
exec ddd scan .
stdout 'scanning'
! stderr .

-- go.mod --
module test
-- main.go --
package main

GoReleaser Config

# .goreleaser.yaml
version: 2
builds:
  - env:
      - CGO_ENABLED=0
    goos:
      - linux
      - darwin
      - windows
    goarch:
      - amd64
      - arm64
    ldflags:
      - -s -w -X main.version={{.Version}}

archives:
  - formats: ['tar.gz']
    name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"

brews:
  - repository:
      owner: fparch
      name: homebrew-tap
    homepage: "https://despairdrivendevelopment.com"
    description: "A CLI that does things"

changelog:
  sort: asc
  filters:
    exclude:
      - '^docs:'
      - '^test:'

GitHub Actions Release Workflow

# .github/workflows/release.yml
name: Release
on:
  push:
    tags: ['v*']

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-go@v5
        with:
          go-version: '1.22'
      - uses: goreleaser/goreleaser-action@v6
        with:
          version: '~> v2'
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

The Full Picture

This series covered:

  1. Project setup — structure, Cobra basics
  2. Commands & config — subcommands, Viper, testing
  3. Testing & release — integration tests, GoReleaser, CI

The complete source is on GitHub:

fparch/ddd-cli View the complete source on GitHub

I help teams build and ship developer tools, internal platforms, and cloud infrastructure. Get in touch →

I help teams modernize legacy systems with AI-assisted development guardrails that keep the agents productive and the production safe. fitzpatricksoftware.com