Repository navigation
Expand file tree
/
Copy path.goreleaser.yaml
More file actions
278 lines (265 loc) · 12.4 KB
/
Copy path.goreleaser.yaml
File metadata and controls
278 lines (265 loc) · 12.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# GoReleaser configuration for mecatl (https://goreleaser.com).
#
# SCOPE — this file owns EXACTLY three things:
# 1. the darwin/linux binary ARCHIVES (mecated + mecatui, one tarball per
# platform, mirroring the `install` Taskfile target),
# 2. the GitHub RELEASE object those archives attach to,
# 3. the `mecatl` CASK in stacklok/homebrew-tap.
#
# It does NOT build container images. ko (.ko.yaml) remains the single owner of
# every mecatl image; the `builds:` here and the `builds:` in .ko.yaml are
# deliberately separate and MUST keep the same linker stamp (see ldflags below).
#
# The GoReleaser BINARY version is pinned in three places that move together:
# - .github/workflows/release.yml -> goreleaser-action `version:`
# - .github/workflows/ci.yml -> goreleaser-action `version:` (install-only)
# - Taskfile.yml -> GORELEASER_VERSION
# Nothing below uses a config field newer than v2.13, so the pin can float up
# freely; GoReleaser loads this file STRICTLY (pkg/config: yaml.UnmarshalStrict),
# so a field newer than the pinned binary is a hard failure, not a warning.
#
# Validate offline: task release:check
# Dry-run locally: task release:snapshot && task release:verify
version: 2
project_name: mecatl
builds:
# mecated and mecatui are SEPARATE builds so each gets its own binary name;
# they are archived TOGETHER (see archives.ids) because the cask pipe rejects
# more than one archive per OS/arch.
#
# `id` and `binary` both default to project_name ("mecatl"). Leaving either
# unset would collide the two builds and produce two binaries called `mecatl`.
- id: mecated
main: ./cmd/mecated
binary: mecated
# The Taskfile does not set this, but .ko.yaml does, and a Homebrew-installed
# binary must be static: no cgo, so no libc coupling to the builder image.
env:
- CGO_ENABLED=0
goos: [darwin, linux]
goarch: [amd64, arm64]
# -trimpath and -s -w match .ko.yaml exactly; mod_timestamp makes the output
# byte-stable across re-runs of the same tag (matters for the re-publish path).
flags:
- -trimpath
mod_timestamp: "{{ .CommitTimestamp }}"
# THE ONLY stamped symbol in this repo is buildinfo.BuildID — there is no
# `main.version`. GoReleaser's DEFAULT ldflags stamp four `main.*` symbols
# that do not exist here, silently, and leave BuildID unset — so every
# Homebrew user would see `mecated dev+<vcs-rev>`. `task release:verify` and
# the smoke-darwin-arm64 CI job are the tripwires for exactly that regression
# (casks, unlike formulae, have no `test` block).
#
# `v{{ .Version }}`, NOT `{{ .Version }}`: GoReleaser strips the leading `v`
# from .Version, whereas .ko.yaml and the Taskfile both stamp the `git
# describe` form WITH the `v` (e.g. `v0.0.29`). Re-adding it keeps
# `--version` byte-identical across ko, Task and GoReleaser builds.
# Not `{{ .Tag }}` either: under --snapshot that reports the LAST tag, which
# would lie about what was built.
#
# The product-metrics ingest key (stacklok/infra#5604): {{ .Env.MECATL_METRICS_INGEST_KEY }}
# reads the plain key the release workflow extracts from the MECATL_METRICS_KEY
# secret (a {"mecatl": "<key>"} JSON blob — see .github/workflows/release.yml)
# into that env var BEFORE this step runs. An empty/unset value renders as a
# bare trailing `=`, which is a harmless empty-string ldflag: NewProvider
# refuses to construct on an empty bakedKey, so a run with no key configured
# degrades to the same never-phones-home posture as any local/dev build.
ldflags:
- -s -w
- -X github.com/stacklok/mecatl/internal/buildinfo.BuildID=v{{ .Version }}
- -X github.com/stacklok/mecatl/internal/adapter/productmetrics.bakedKey={{ .Env.MECATL_METRICS_INGEST_KEY }}
- id: mecatui
main: ./cmd/mecatui
binary: mecatui
env:
- CGO_ENABLED=0
goos: [darwin, linux]
goarch: [amd64, arm64]
flags:
- -trimpath
mod_timestamp: "{{ .CommitTimestamp }}"
ldflags:
- -s -w
- -X github.com/stacklok/mecatl/internal/buildinfo.BuildID=v{{ .Version }}
- -X github.com/stacklok/mecatl/internal/adapter/productmetrics.bakedKey={{ .Env.MECATL_METRICS_INGEST_KEY }}
# NOTE: no `gomod:` block, deliberately. `gomod.proxy` defaults to false; setting
# it true would make GoReleaser fetch github.com/stacklok/mecatl/engine from
# proxy.golang.org, where it does not exist as a published version — the root
# module reaches it via `replace ... => ./engine`. That is a total release
# failure, not a degradation. The go.work workspace is used as-is, exactly as
# `task build` uses it; GOWORK must be left alone.
archives:
# ONE archive per platform carrying BOTH binaries. `ids` selects BUILD ids and
# the archive pipe groups the matching binaries by platform, so each tarball
# gets mecated AND mecatui.
#
# This is what lets the cask install both: homebrew_casks.binaries below
# lists mecated and mecatui, and the cask links each from the archive root.
- id: mecatl
ids: [mecated, mecatui]
# `formats` is a LIST since v2.6; the singular `format` is deprecated.
# No format_overrides: there is no windows target here, so no zip. (Windows
# does compile — every unix-tagged file has an `_other`/`_unsupported`
# sibling and there is no cgo — but Homebrew does not serve it. Windows
# packaging would be scoop/winget, separately.)
formats: [tar.gz]
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
# The default `files` globs LICENSE*/README*/CHANGELOG*, which ships the
# repo's Apache-2.0 LICENSE (its section 4(a) wants it included).
#
# Do NOT set wrap_in_directory: the generated `binary "mecated"` stanzas
# expect the binaries at the archive ROOT.
checksum:
# sha256 (the default) is required: the release workflow feeds this exact file
# to actions/attest-build-provenance's `subject-checksums`.
name_template: checksums.txt
sboms:
# One SPDX-JSON SBOM per ARCHIVE, matching the per-image SBOMs the ko jobs
# attach. Requires `syft` on PATH (anchore/sbom-action/download-syft in CI).
#
# `args` is set EXPLICITLY to drop syft's default trailing `--enrich all`,
# which performs ONLINE lookups mid-release — latency and flake between
# "images pushed" and "release published", for no added assurance here.
- id: archive-sbom
artifacts: archive
documents:
- "${artifact}.spdx.json"
args: ["$artifact", "--output", "spdx-json=$document"]
signs:
# Keyless cosign, the same OIDC identity and Rekor trail as the image
# signatures the ko jobs produce. `--bundle` writes cert+signature into ONE
# .sigstore.json, which is what `cosign verify-blob --bundle` consumes.
#
# Two entries, each with an explicit `id` (both would otherwise default to
# `default` and collide): the ARCHIVES (parity with signing each image by
# digest) and CHECKSUMS.TXT (the single root a consumer verifies once, then
# checks every artifact against with `sha256sum --check`).
- id: archives
cmd: cosign
args:
- sign-blob
- "--bundle=${signature}"
- "${artifact}"
- "--yes"
artifacts: archive
signature: "${artifact}.sigstore.json"
output: true
- id: checksums
cmd: cosign
args:
- sign-blob
- "--bundle=${signature}"
- "${artifact}"
- "--yes"
artifacts: checksum
signature: "${artifact}.sigstore.json"
output: true
homebrew_casks:
# Casks live in the tap's Casks/ directory (the default). The previous `mecatl`
# formula is retired from the tap with a tap_migrations.json entry, so existing
# installs move to the cask on `brew update`.
#
# `ids` is deliberately unset (empty = all archives). Note it would select
# ARCHIVE ids here, not build ids; there is exactly one archive, so omitting
# it is both correct and unambiguous.
- name: mecatl
# A prerelease must NOT bump the tap. `release.prerelease: auto` only marks
# the GitHub Release; without this, a vX.Y.Z-rc1 tag would still push a
# cask and hand every `brew install stacklok/tap/mecatl` user an rc as
# the stable version. "auto" skips the tap push exactly when
# ctx.Semver.Prerelease is non-empty, so a plain vX.Y.Z is unaffected.
skip_upload: auto
# Both binaries in the one archive; the cask links each into the prefix.
binaries: [mecated, mecatui]
homepage: "https://github.com/stacklok/mecatl"
# Homebrew style (Cask/Desc) rejects a description that starts with the
# cask name, so this must not begin with "Mecatl". Verified by
# `brew style` in task release:verify.
description: "Agent harness for cloud-native workloads, with server and terminal UI"
commit_author:
name: stacklokbot
email: info@stacklok.com
repository:
owner: stacklok
name: homebrew-tap
# No `branch:` (defaults to the tap's default branch, main) and no
# `pull_request:` — a direct commit, matching modelith and toolhive.
#
# Minted per run as a scoped GitHub App installation token; see
# release.yml. NEVER the workflow's own GITHUB_TOKEN, which cannot write
# to another repository.
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
# Homebrew quarantines cask downloads, and the darwin binaries are not
# notarized, so Gatekeeper would refuse to run them. This strips the
# quarantine attribute from both binaries after install.
#
# Written as a raw postflight_steps stanza because the hooks.post.install
# option writes the Ruby postflight block Homebrew has deprecated, and
# GoReleaser's install_steps replacement is not in a stable release yet.
# The body matches what install_steps generates. {{staged_path}} is a
# Homebrew token, escaped so GoReleaser's own templating passes it through.
# custom_block lands at the TOP of the cask, which is why release:verify
# skips Cask/StanzaOrder.
custom_block: |
postflight_steps do
on_macos do
run "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "{{ "{{staged_path}}" }}/mecated"]
run "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "{{ "{{staged_path}}" }}/mecatui"]
end
end
changelog:
# `github` uses the compare API and needs the FULL local tag graph for the
# previous-tag lookup — hence fetch-depth: 0 in release.yml.
use: github
sort: asc
# mecatl uses conventional commits WITH scopes (`fix(mecatui): ...`), so every
# pattern tolerates the optional `(scope)` and the breaking-change `!`.
filters:
exclude:
- '^docs(\([^)]*\))?!?:'
- '^chore(\([^)]*\))?!?:'
- '^test(\([^)]*\))?!?:'
- '^ci(\([^)]*\))?!?:'
groups:
- title: Features
regexp: '^feat(\([^)]*\))?!?:'
order: 0
- title: Fixes
regexp: '^fix(\([^)]*\))?!?:'
order: 1
- title: Other changes
order: 999
release:
# No mecatl tag has carried a prerelease suffix yet, so `auto` is a no-op
# today and correctly marks a future vX.Y.Z-rc1 as a prerelease.
prerelease: auto
# THE RE-PUBLISH SWITCH. `workflow_dispatch` re-runs `release --clean` against
# a tag whose Release already exists; without this every asset upload fails
# with "already_exists". With it, GoReleaser deletes the colliding asset and
# retries. `keep-existing` (the default, stated explicitly) additionally
# protects hand-edited release notes from being clobbered.
#
# NOT self-healing: a run that dies BETWEEN "release created" and "assets
# uploaded" leaves a DRAFT, which a lookup by tag does not return, so the next
# attempt tries to create the release again and fails. Recovery is
# gh release delete <tag> --cleanup-tag=false --yes
# before re-dispatching. Do NOT "fix" that with use_existing_draft: true —
# that flips the lookup to draft-only and breaks the common re-publish case.
mode: keep-existing
replace_existing_artifacts: true
header: |
## Install
```sh
brew install stacklok/tap/mecatl
```
Installs both `mecated` (the server) and `mecatui` (the terminal UI).
footer: |
## Verify
```sh
cosign verify-blob \
--certificate-identity 'https://github.com/stacklok/mecatl/.github/workflows/release.yml@refs/tags/{{ .Tag }}' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
--bundle checksums.txt.sigstore.json checksums.txt
sha256sum --check --ignore-missing checksums.txt
gh attestation verify mecatl_{{ .Version }}_darwin_arm64.tar.gz --repo stacklok/mecatl
```