1# Go packaging and releases
2
3Read [../packaging.md](../packaging.md), [baseline.md](baseline.md),
4[mise.md](mise.md), and [cli.md](cli.md) before applying these Go release
5specifics.
6
7Packaging is part of the baseline when the project is meant to be installed, not
8an afterthought.
9
10## Choose the artifact
11
12- **Plain CLI/MCP server**: cross-compiled binaries are usually enough.
13- **System service**: add systemd/OpenRC files and consider nFPM packages.
14- **Desktop/Wails app**: use nFPM for Linux packages, desktop files, icons, and
15 WebKit runtime dependencies; use Wails/NSIS for Windows installers when needed.
16- **Library**: no binary packaging unless examples/tools are part of the repo.
17
18## Version gating
19
20Package tasks should fail on ambiguous versions. Prefer exact tags for release
21packages. For Git-tagged releases, a package task can gate on an exact tag:
22
23```sh
24version=$(git describe --tags --exact-match 2>/dev/null) || {
25 echo "Error: package builds require an exact vMAJOR.MINOR.PATCH tag" >&2
26 exit 1
27}
28version=${version#v}
29```
30
31For jj-backed projects, use the project's agreed jj/git-derived release command
32instead. Do not infer package versions from Go `BuildInfo` unless the project
33explicitly chose that policy. For development builds, `VERSION=dev` is fine; for
34packages, be stricter.
35
36## nFPM baseline
37
38```yaml
39# yaml-language-server: $schema=https://nfpm.goreleaser.com/static/schema.json
40name: example
41arch: ${GOARCH}
42version: ${VERSION}
43release: ${RELEASE:-1}
44section: utils
45priority: optional
46maintainer: Amolith <amolith@secluded.site>
47description: Short human description
48homepage: https://example.invalid
49license: LicenseRef-MutuaL-1.2
50
51contents:
52 - src: build/pkg/example
53 dst: /usr/bin/example
54```
55
56For Wails/Linux desktop apps, add package assets and WebKit dependencies:
57
58```yaml
59contents:
60 - src: build/pkg/example
61 dst: /usr/bin/example
62 - src: packaging/example.desktop
63 dst: /usr/share/applications/example.desktop
64 - src: dist/example.png
65 dst: /usr/share/icons/hicolor/512x512/apps/example.png
66
67overrides:
68 deb:
69 depends:
70 - libwebkit2gtk-4.1-0
71 recommends:
72 - xdg-utils
73 rpm:
74 depends:
75 - (webkit2gtk4.1 or libwebkit2gtk-4_1-0)
76 apk:
77 depends:
78 - webkit2gtk-4.1
79 archlinux:
80 depends:
81 - webkit2gtk-4.1
82```
83
84## mise package tasks
85
86Use hidden preparation tasks for version, icon conversion, package build, and
87optional compression. Visible tasks should be simple: `pkg`, `pkg:deb`,
88`pkg:rpm`, `pkg:apk`, `pkg:arch`.
89
90Minimal visible tasks look like this:
91
92```toml
93[tasks."pkg:deb"]
94description = "Build a deb package"
95env = { RELEASE = "1" }
96run = "nfpm package -f packaging/nfpm.yaml -p deb -t build/pkg"
97
98[tasks."pkg:rpm"]
99description = "Build an rpm package"
100env = { RELEASE = "1" }
101run = "nfpm package -f packaging/nfpm.yaml -p rpm -t build/pkg"
102```
103
104UPX is optional. Use it for Linux binaries when size matters; do not assume it
105works well for every OS or binary format.
106
107## Cross-compilation
108
109- `CGO_ENABLED=0` makes plain Go binaries easy to cross-compile.
110- For CLI, TUI, and MCP release binaries, prefer `netgo`, `osusergo`, optional
111 project-specific `static_build`, `-d -s -w -buildid=`, and
112 `-extldflags=-static` when dependencies are pure Go.
113- Treat Go VCS build metadata as a policy choice, not the package version source.
114 If a package needs exact version or commit strings, derive them in the package
115 task and inject them. If a release intentionally relies on Go `BuildInfo`, make
116 that explicit and consider `-buildvcs=true`.
117- Wails/Linux builds require native CGO and WebKitGTK.
118- Windows Wails cross-builds from Linux need mingw-w64; NSIS packages need
119 `makensis`.
120- macOS desktop builds require macOS unless a project has proven otherwise.
121
122Document these constraints in task descriptions and preconditions rather than
123letting users discover linker failures.