Semantic Versioning, Semantic Release, and a Go-native implementation

How Semantic Versioning and Semantic Release fit together — the standard, the automation contract that turns commit history into version tags, and why I re-implemented the Node.js tool in Go to remove the JavaScript toolchain from CI pipelines that don’t otherwise need one.

July 20, 2026 · 12 min · Omar Crosby

Conventional Commits, and the thinking they encourage

A working tour of Conventional Commits — the format, the reason it makes each changeset better before any tool touches it, how to identify good scopes, what the Angular convention adds on top, and where the whole thing fits into the release-automation ecosystem (semantic-release, release-please, cocogitto, git-cliff, commitlint).

July 20, 2026 · 18 min · Omar Crosby

Distributing CLI tools with a personal Homebrew tap

How to publish Python, Go, and Rust command-line tools through your own Homebrew tap — including a personal GitHub account, GoReleaser and cargo-dist for platform builds, and go-semantic-release for automatic version bumps that flow all the way through to brew upgrade.

July 20, 2026 · 14 min · Omar Crosby

Static analysis for Go: what golangci-lint catches, and why it belongs in CI

Code review catches the bugs a human happens to notice. Static analysis catches the bugs a specific, well-defined check is built to notice — every time, on every line, before anyone opens the diff. Those are different guarantees, and the difference matters most for the bug classes reviewers are worst at: an HTTP response body that never gets closed three call sites deep, an error return silently discarded in a one-line change, a security-sensitive value generated with the wrong random source. None of these look wrong at a glance. All of them are mechanically detectable. ...

July 9, 2026 · 21 min · Omar Crosby

Testing Go with Ginkgo and Gomega without giving up go test

If you’ve never looked at Ginkgo and Gomega, there’s a decent chance you’re picturing something that replaces go test — a separate test runner, a separate CI step, another tool your team has to adopt wholesale before anyone sees a benefit. That picture is wrong, and it’s worth correcting up front, because it’s the single biggest reason Go developers who’d genuinely enjoy Ginkgo never try it. Here’s the fact that should change your mind: a Ginkgo spec is a Go test. It compiles into the same test binary, it runs when you type go test ./..., and your existing CI pipeline doesn’t need to know Ginkgo exists. What Ginkgo adds is a richer vocabulary for organizing specs — nested Describe/Context/It blocks instead of a flat list of Test* functions — plus first-class suite lifecycle (BeforeSuite/AfterSuite), table-driven specs, async timeouts, and labels for slicing a suite into subsets. Gomega adds the assertion language (Expect(x).To(Equal(y))) that makes failures read like a sentence instead of a %v != %v diff. ...

July 9, 2026 · 12 min · Omar Crosby