Skip to content

Developer guide — knife

Prerequisites

Tool Version Purpose
Go 1.26+ Build and test
make any Task runner
golangci-lint latest Linting
goreleaser latest Release builds

Install golangci-lint:

go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

Install goreleaser:

go install github.com/goreleaser/goreleaser/v2@latest

Clone and build

git clone https://gitlab.com/cozybadgerde/applications/knife.git
cd knife
make build

The binary is written to build/knife. Run it directly:

./build/knife --help

Running tests

All tests use net/http/httptest and do not require a running snackbox server.

make test

Do not call go test directly — always use make test so that any future pre-test steps defined in the Makefile are included.

Linting

make lint

This runs golangci-lint run ./.... Fix all reported issues before opening a merge request. Code must also pass gofmt formatting.

Regenerating the API client

The generated client in internal/client/snackbox.gen.go is produced from api/openapi.yaml. After updating the OpenAPI spec:

make generate

Do not edit snackbox.gen.go manually. Any manual changes will be lost the next time make generate is run.

Creating a release

Snapshot (local testing)

make dist

This runs goreleaser release --snapshot --clean and places binaries in dist/. A snapshot build does not require a git tag.

Tagged release

  1. Create and push a semver tag:

bash git tag v1.2.3 git push origin v1.2.3

  1. The CI pipeline picks up the tag and runs goreleaser to publish the release to GitLab. The .goreleaser.yaml file in the repo root controls what is built and uploaded.

Commit message format

knife follows the Conventional Commits specification. A template is provided in .gitmessage:

type(scope): short description

Body (optional): explain the why, not the what.

Footer (optional): BREAKING CHANGE: ..., Closes #issue

Common types: feat, fix, refactor, test, docs, chore, ci.

Configure git to use the template:

git config commit.template .gitmessage

Adding a new command

  1. Create the command file in cmd/. Use an existing file such as cmd/me.go as a reference.

bash touch cmd/widgets.go

  1. Define the command struct and subcommands using cobra.Command.

  2. Register the commands in the file's init() function:

go func init() { rootCmd.AddCommand(widgetsCmd) widgetsCmd.AddCommand(widgetsListCmd, widgetsGetCmd) // register flags here }

  1. Write the test file alongside the command file:

bash touch cmd/widgets_test.go

Tests must cover every exported function and every RunE handler. Use net/http/httptest to mock the snackbox API — no live server should be required.

  1. Run tests and lint to verify:

bash make test make lint

  1. Open a merge request following the commit message conventions above.