Please don't take this the wrong way, but I do not accept outside contributions for any of my projects. I simply don't have the mental bandwidth to review anything, and it's my name on the thing, so I'm responsible for any problems it causes; thus, the risk-reward is highly asymmetric from my perspective. I'd also have to worry about other "stakeholders," which seems unwise for tools I mostly make for myself for free. Feel free to submit issues, and even PRs if you want to illustrate a proposed fix, but know I won't merge them directly. Instead, I'll have Claude or Codex review submissions via gh and independently decide whether and how to address them. Bug reports in particular are welcome. Sorry if this offends, but I want to avoid wasted time and hurt feelings. I understand this isn't in sync with the prevailing open-source ethos that seeks community contributions, but it's the only way I can move at this velocity and keep my sanity.
The rest of this document is a developer reference for anyone building NTM locally, running tests, or filing issues with reproduction steps.
- Go 1.25+
- tmux (for testing)
- golangci-lint (for linting)
go build ./cmd/ntmgo test ./...golangci-lint runThe ntm upgrade command downloads release assets from GitHub Releases. For this to work, internal/cli/upgrade.go must know exactly what asset names GoReleaser produces.
This creates a naming contract between two files:
.goreleaser.yaml: Defines asset names viaarchives.name_templateinternal/cli/upgrade.go: Contains logic to find and match assets
If these drift apart, users get "no suitable release asset found" errors. The contract is enforced by TestUpgradeAssetNamingContract in internal/cli/cli_test.go.
Archives (tar.gz/zip):
ntm_{version}_{os}_{arch}.{ext}
Raw Binaries:
ntm_{os}_{arch}
Special Cases:
| Case | Convention | Reason |
|---|---|---|
| macOS | Uses all instead of arch |
Universal binary (arm64+amd64) |
| Windows | Uses .zip instead of .tar.gz |
Native Windows archive format |
| ARM Linux | Uses armv7 suffix |
Distinguish from arm64 |
Platform Examples:
| Platform | Archive Name | Binary Pattern |
|---|---|---|
| macOS ARM | ntm_1.4.1_darwin_all.tar.gz |
ntm_darwin_all |
| macOS Intel | ntm_1.4.1_darwin_all.tar.gz |
ntm_darwin_all |
| Linux x64 | ntm_1.4.1_linux_amd64.tar.gz |
ntm_linux_amd64 |
| Linux ARM64 | ntm_1.4.1_linux_arm64.tar.gz |
ntm_linux_arm64 |
| Linux ARM (32-bit) | ntm_1.4.1_linux_armv7.tar.gz |
ntm_linux_armv7 |
| Windows | ntm_1.4.1_windows_amd64.zip |
ntm_windows_amd64 |
Note: The "Binary Pattern" column shows the asset name prefix used by upgrade.go to find assets. The actual binary inside archives is always named ntm (or ntm.exe on Windows).
Before making ANY changes to asset naming:
-
Understand the contract:
- Read this document fully
- Review
TestUpgradeAssetNamingContractininternal/cli/cli_test.go
-
Update both files together:
-
.goreleaser.yaml: Updatearchives.name_template -
internal/cli/upgrade.go: UpdategetAssetName()andgetArchiveAssetName() -
internal/cli/cli_test.go: UpdateTestUpgradeAssetNamingContractexpected values
-
-
Verify locally:
go test -v -run TestUpgradeAsset ./internal/cli/Optional helpers:
make upgrade-contract make pre-commit
make pre-commitonly runs the contract tests when relevant files are staged. -
CI will validate:
upgrade-checkjob tests against latest release- If naming changed, expect CI to fail until new release with new naming
-
After release:
upgrade-verifyjob confirms all platforms can find assets
Error: "no suitable release asset found for X/Y"
This means upgrade.go couldn't find a matching asset. The error now shows:
- A diagnostic box with platform and tried names
- Available assets with platform annotations
- Troubleshooting hints and links
Common causes:
-
Naming convention mismatch:
- Check actual names at https://github.com/Dicklesworthstone/ntm/releases/latest
- Compare against
TestUpgradeAssetNamingContractexpectations
-
GoReleaser config changed:
- Check recent changes to
.goreleaser.yaml - Verify
archives.name_templatematchesupgrade.gologic
- Check recent changes to
-
New platform not supported:
- Add platform to
getAssetName()/getArchiveAssetName() - Add test case to
TestUpgradeAssetNamingContract
- Add platform to
Error: CI upgrade-check failing
The current code can't find assets from the latest release. Either:
- Roll back the code change, or
- Cut a new release with compatible naming
The upgrade system has multiple protection layers:
- Contract Tests (
TestUpgradeAssetNamingContract): Catch naming drift at development time - CI Upgrade Check: Test against real releases before merge
- Post-Release Verification: Verify all platforms after release
- Enhanced Error Messages: Guide users to diagnose issues themselves
- Follow standard Go conventions
- Run
gofmtbefore committing - Write tests for new functionality
- Keep functions focused and small
Open an issue on GitHub for questions or discussion.