# ultimate-gojust

A drop-in Justfile that covers the full Go project lifecycle: project scaffolding, building with version injection, cross-compilation, testing with coverage, linting, security scanning, hot reload, Docker, and database migrations. It's the `just`-based sibling of `ultimate-gomake` (same author, same features, different runner).

## How it works

The justfile is a single file you copy into your project root. It uses `just`'s `env_var_or_default()` for a configuration cascade: CLI args override env vars, which override `.env` file values, which override hardcoded defaults. This means you can do `just GOOS=darwin build` without editing anything.

### Version embedding

The build recipe automatically extracts version info from git and injects it via ldflags:

```just
version := `git describe --tags --always --dirty 2>/dev/null || echo "dev"`
git_commit := `git rev-parse --short HEAD 2>/dev/null || echo "unknown"`

ld_flags := "-s -w \
    -X '$(go list -m)/pkg/version.Version=" + version + "' \
    -X '$(go list -m)/pkg/version.Commit=" + git_commit + "' \
    -X '$(go list -m)/pkg/version.Branch=" + git_branch + "' \
    -X '$(go list -m)/pkg/version.BuildTime=" + build_time + "' \
    -X '$(go list -m)/pkg/version.BuildBy=" + build_by + "'"
```

This expects a `pkg/version` package with exported string vars. The `-s -w` flags strip debug info and DWARF tables for smaller binaries.

### Cross-compilation

The `build-all` recipe loops over seven OS/arch combinations (linux amd64/arm64/armv7, darwin amd64/arm64, windows amd64/arm64), builds static binaries with `CGO_ENABLED=0`, and tarballs each output. The Windows builds get `.exe` suffixed automatically.

### Dev tooling

`just deps` installs golangci-lint, gofumpt, govulncheck, mockgen, and Air (hot reloader). `just dev` downloads an Air config if missing and starts watching for changes. `just lint` runs golangci-lint with `--fix`. `just security` runs govulncheck.

### Database migrations

Uses golang-migrate with PostgreSQL and MySQL support. `just db-migrate` runs pending migrations, `just db-rollback` reverts one step, `just db-reset` drops everything. All read `DATABASE_URL` from the environment.

## Entrypoint convention

The repo assumes `main/main.go` as the build entrypoint, which is uncommon — the standard Go convention is `cmd/<name>/main.go` for projects with one or more binaries. The build recipe would need adjustment for `cmd/` layouts:

```just
build:
    mkdir -p {{bin_dir}}
    {{go}} build \
        -ldflags '{{ld_flags}}' \
        -o {{bin_dir}}/{{project_name}} \
        ./cmd/{{project_name}}
```

For multi-binary projects, you'd loop over directories under `cmd/`.

## Interesting patterns to borrow

The most reusable parts for any Go Justfile:

- **ldflags version injection** — wire git metadata into binaries at compile time, no code generation needed
- **Configuration cascade** via `env_var_or_default()` — makes the same Justfile work across dev, CI, and production without forks
- **Cross-compile loop** — a compact way to produce release binaries for all platforms
- **Tool pinning** via `go install ...@latest` in a `deps` recipe — keeps the team on the same toolchain

## Limitations

- Single-binary only — no built-in support for `cmd/` multi-binary layouts
- Tool versions pinned to `@latest` rather than specific versions, which can cause CI flakiness
- The `init` recipe downloads a `.gitignore` from gitignore.io (an external dependency that may go away)
- No Makefile equivalent included in this repo (but `ultimate-gomake` exists separately)

49 stars, MIT license. Repo: https://github.com/binbandit/ultimate-gojust
