There is no CI: the instance has no act_runner and none is planned, so releases are cut by hand. That makes `make check` the only thing standing between a mistake and the tracker, and it is one command: gofmt, vet, the suite with the cache defeated, `go mod verify`, a vendored build, and `kettle gen skills --check`. The last one is the invariant worth having — the plugin's SKILL.md command reference is generated from the binary's registry, so a flag that changed cannot ship with documentation that recommends the old one. `cli/cmd/release` publishes to Gitea using the same SDK the binary already vendors, which is a pleasing thing to be able to say: nothing third-party handles the artifacts. It is a second binary rather than a `kettle` subcommand on purpose — `kettle`'s command tree is what generates the plugin's skills, so a verb there ships to every operator, and publishing a release is build infrastructure. It is idempotent end to end: an existing release for the tag is reused, an asset of the same name is replaced rather than doubled, and a retried run converges instead of duplicating. `make release` refuses three things, each with its own message: a dirty working tree, a TAG that is not what `git describe` reports, and a tag the remote does not have. A release built from uncommitted code is unreproducible and nobody finds out until they need to reproduce it. `kettle version` reports the stamp, the toolchain and the VCS revision. The default is `dev`, and a hand build says so and means it — a binary out of somebody's working tree is not a release and must not claim to be one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3.2 KiB
AGENTS.md — internal/wire (ADDRESSES)
How this project addresses one repository and one issue, and nothing else.
Two types, Repo and Key, and the parsing that reads them.
Imports the standard library and nothing else — no HTTP, no filesystem, no
configuration, no SDK, and above all not issue. An
identifier that reached for any of those would drag every user of it into that
layer. Two tests hold it, see internal/AGENTS.md.
| file | what is in it |
|---|---|
key.go |
Repo, Key, ParseRepo, ParseKey, Key.In, and the String methods |
key_test.go |
every spelling above, and what a malformed one answers |
layering_test.go |
the two tests that keep this package at the bottom |
Four spellings, one address
wire.ParseKey("42") // Key{Number: 42} — repo zero: "this project's"
wire.ParseKey("#42") // the same, copied out of a body
wire.ParseKey("owner/repo#42") // qualified, out of the ledger
wire.ParseKey("https://git.example.com/owner/repo/issues/42")
All four because all four are what somebody has in hand — a number from a receipt,
a #42 copied out of an issue body, a qualified key out of the ledger, a URL pasted
from a browser. Refusing three of them buys nothing.
Key.Repo is zero when the caller named a number and nothing else, which is the
common case on a command line: 42 means "42 in this project's repository", and
which repository that is, is the client's business. Key.In(repo) fills it in.
Repo.Zero() requires both halves — half a name addresses nothing.
Why a key is not a bare number
Key has to survive being written to a file and read back: it is what the
number → slug ledger is keyed by and what the gitea: metadata field holds. A
number is ambiguous the moment a dependency lives in another repository, and
dependencies are allowed to. So a key is a repository and a number, always, and
String() spells it owner/repo#42.
Why this package still exists after the SDK
The JSON shapes used to live here too, because the transport and the bridge both
had to name a Gitea issue and neither may import the other. They are
code.gitea.io/sdk/gitea's now.
What the SDK has no answer for is addressing. It takes an owner, a name and an
int64, and never parses. So the parsing stays, and so does the pair of types it
produces — the values that go into the ledger, into the gitea: field, and into
every receipt. The longer version of that history is in
internal/AGENTS.md.
What does not belong here
Anything that does something with an address: fetching, storing, resolving a
repository from configuration. This package parses and prints. Callers are
gitea, mapping and
cmd.
Keeping this file true
- Scope:
key.goand its tests — the two types and the spellings they accept. - Update it when a spelling is added or dropped, a type gains a field, or the
zero-value meaning of
Key.Repochanges. - Do not add a third type here without an argument for why it is an address. Anything that is a payload belongs to the SDK; anything that is a fact about work belongs to the domain.