# Build and Deployment

This guide documents the build and release paths that exist in the current
repository. The `Makefile` and `.gitlab-ci.yml` remain the executable sources
of truth.

## Requirements

- Go 1.27.0 or later
- Node.js 22.12+ (or supported newer LTS/current) and npm
- Make
- `tar`, `zip`, and `unzip` for release archive creation/verification
- Git when build commit metadata is desired

Install both Go and frontend dependencies before a clean build:

```bash
make deps
make frontend-deps
make frontend
```

`make frontend` copies the exact npm-managed htmx and Alpine distributions
into the embedded static tree and rebuilds Tailwind. Runtime use remains
offline and does not depend on a CDN. See
[Frontend Dependencies](FRONTEND_DEPENDENCIES.md).

## Local builds

```bash
# Current platform
make build

# Run the current-platform build
make run

# All six release targets, in parallel
make build-all-parallel

# Platform groups
make build-linux
make build-windows
make build-macos
```

Individual release targets are:

| Target | Output |
|---|---|
| `make build-linux-amd64` | `dist/mpv-manager-linux-amd64` |
| `make build-linux-arm64` | `dist/mpv-manager-linux-arm64` |
| `make build-win-x86_64` | `dist/mpv-manager-win-x86_64.exe` |
| `make build-win-arm64` | `dist/mpv-manager-win-arm64.exe` |
| `make build-macos-intel` | `dist/mpv-manager-macos-intel` |
| `make build-macos-arm` | `dist/mpv-manager-macos-arm` |

Windows amd64 uses the x86-64-v2 baseline. The macOS binaries require macOS
13 or later, matching Go 1.27's Darwin support floor. Release builds are
CGO-free.

Use `make clean` to remove release output and `make clean-all` only when the
Go caches should also be cleared.

## Version identity

The build version is injected into
`gitgud.io/mike/mpv-manager/pkg/version.CurrentVersion`. It is a string
variable by design; linker `-X` cannot replace a constant.

```bash
make build VERSION=v1.3.0
./dist/mpv-manager --version --json
```

The Makefile strips a leading `v`. The JSON probe must report the exact
normalized version and these stable fields:

```json
{
  "product": "mpv-manager",
  "component": "manager-portable",
  "version": "1.3.0",
  "goos": "linux",
  "goarch": "amd64"
}
```

Build time and Git commit are included when supplied. The updater runs the
same probe against a staged replacement and compares product, component,
version, OS, and architecture before committing it.

Release binaries must also embed the public Ed25519 trust ring used for signed
release metadata:

```bash
make build VERSION=v1.3.0 \
  MANIFEST_PUBLIC_KEYS='stable-2026-01=<base64-public-key>' \
  MANIFEST_KEY_VALIDITY='stable-2026-01=<not-before-unix>:<not-after-unix>'
```

Prerelease Make builds load the public RC trust from `release/rc-trust.mk`.
The deployed QA artifacts and the freshness requirement for later rebuilds are
documented in [release channels](RELEASE_CHANNELS.md). Stable builds still
require their production trust configuration.

An empty ring is allowed for local/offline development but causes network
release metadata to fail closed. `make release` refuses an empty ring.

Package-manager builds must disable raw self-update while retaining the public
key ring so MPV/application release metadata can still be authenticated:

```bash
make build \
  MANIFEST_PUBLIC_KEYS='stable-2026-01=<base64-public-key>' \
  MANIFEST_KEY_VALIDITY='stable-2026-01=<not-before-unix>:<not-after-unix>' \
  SELF_UPDATE_FLAG="-X 'gitgud.io/mike/mpv-manager/pkg/version.SelfUpdateDisabled=true'"
```

## Release build helpers

```bash
# Build binaries, create archives, and generate BLAKE3SUMS.txt
make release VERSION=1.3.0 \
  MANIFEST_PUBLIC_KEYS='stable-2026-01=<base64-public-key>' \
  MANIFEST_KEY_VALIDITY='stable-2026-01=<not-before-unix>:<not-after-unix>'

# Only the six binaries (release targets also require embedded trust)
make release-build VERSION=1.3.0 \
  MANIFEST_PUBLIC_KEYS='stable-2026-01=<base64-public-key>' \
  MANIFEST_KEY_VALIDITY='stable-2026-01=<not-before-unix>:<not-after-unix>'

# Build checksum tool / regenerate checksums
make checksums
```

`make release` is a local artifact workflow. Publishing releases is handled by
GitLab CI.

## GitLab release pipeline

Merge requests, the default branch, and tags run:

- normal/race Go tests and coverage;
- `go mod tidy -diff`, vet, gofmt, and `govulncheck`;
- linker sentinel identity validation;
- `npm ci`, embedded-vendor freshness, Vitest, npm audit, and Tailwind
  freshness.

A semantic release tag additionally:

1. normalizes the tag for linker injection;
2. builds Linux amd64/arm64, Windows amd64/arm64, and macOS Intel/arm64;
3. generates and inspects versioned Windows resources for both architectures,
   then executes and validates the Linux amd64 release identity;
4. creates tar/zip downloads containing the license and third-party notices,
   creates `BLAKE3SUMS.txt`, and verifies it with `b3sum -c`;
5. waits for protected approval binding exact native Windows/macOS evidence to
   the four pipeline artifact digests;
6. preflights immutable package paths, then uploads raw updater binaries and
   user archives through a serialized GitLab generic-package publication;
7. generates and schema-validates an unsigned component candidate from a
   reviewed tag-bound provenance lock and the pipeline-local build artifacts;
8. obtains the Ed25519 signature from the isolated OIDC-authenticated signer;
9. independently verifies and uploads an immutable tag-scoped manifest;
10. atomically publishes and re-verifies the public stable manifest;
11. creates the GitLab release and its asset links.

See [GitLab CI](GITLAB_CI.md) for job names and artifact details.

The required protected variables, offline key-generation/rotation procedure,
and atomic publication endpoint contract are documented in
[GitLab CI](GITLAB_CI.md). Missing variables fail the tag pipeline before the
GitLab release is created.

## Release checklist

Before tagging:

```bash
go test ./...
go test -race ./...
go vet ./...
test -z "$(gofmt -l pkg cmd internal)"
go mod tidy -diff
go mod verify
npm ci
npm run vendor:frontend:check
npm test
npm audit --package-lock-only --audit-level=high
make build-all-parallel VERSION=1.3.0
```

For v1.3.0, platform Authenticode/Developer ID signing and notarization are
deferred to v1.4.0 while publisher verification completes. Updater manifest
signing remains required. Use the [current release checklist](RELEASE_READINESS_v1.3.0.md)
for final manual unsigned-artifact acceptance and release infrastructure gates.

Then complete the native updater qualification matrix on `win-dev` and
`macos-dev`, plus Linux native tests, before publishing. The required cases are
listed in [Self-update and Wails Review](SELF_UPDATE_AND_WAILS_REVIEW_2026-08-28.md).
The repeatable current-protocol subset can be run natively with
`make qualify-selfupdate`; it never targets a real installation.

Tag only from the intended release commit. GitLab must protect the `v*` tag
pattern; the pipeline independently enforces canonical SemVer and
`CI_COMMIT_REF_PROTECTED=true`:

```bash
git tag -a v1.3.0 -m "Release v1.3.0"
git push origin v1.3.0
```

After CI finishes, verify every artifact, checksum, identity, native signature
where applicable, update-manifest publication, and the supported historical
bootstrap before announcing the release. Exercise v1.1/v1.2 to v1.3 natively
on Linux/macOS after publication. On Windows, verify the documented one-time
manual replacement; the immutable old updater cannot reliably rename its own
running `.exe`. Automated Windows self-update qualification begins with an
update originating from v1.3.

---

See also: [Testing](TESTING.md) · [Troubleshooting](TROUBLESHOOTING.md) · [Project README](../README.md)
