Commit Graph
2 Commits
Author SHA1 Message Date
mikeandClaude Opus 5 8c4d8da4e9 Attach ./bin and ./assets to a release
`release` now uploads every file in the project's ./bin and ./assets when
those directories exist. Nothing to configure, and nothing happens for a
project that has neither.

This is the part deliberately left out when `release` was written,
because it is where the three providers stop resembling each other:

  Gitea   multipart POST to .../releases/<id>/assets?name=<name>
  GitHub  raw POST to the separate upload host the release object names
          in upload_url, whose RFC 6570 template suffix has to go first
  GitLab  a release stores links, not files: the file goes into the
          project's generic package registry and the release gets a
          package link pointing at it

So findRelease and createRelease now return a releaseRef carrying the id
and, for GitHub, that upload host -- the id alone cannot address an
upload. Uploads stream from disk rather than buffering: these are whole
binaries, and the Gitea multipart body is assembled through a pipe.

Only regular files directly in those directories are taken. Symlinks are
skipped, which matters here: build.sh leaves bin/mgsh pointing at one of
its siblings, and uploading the same 9M twice under two names helps
nobody. A name present in both directories is used from bin and reported
for assets. Re-releasing a tag replaces same-named assets rather than
failing on them, since rebuilding and publishing again is the normal
reason to do it, and a file that fails does not stop the rest.

Each provider's request shape is pinned down against the recording
stand-in, and the whole chain was run once end to end -- real repository,
real binaries, a fake Gitea that also serves git-http-backend so the tag
push is real too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 20:13:09 +02:00
mikeandClaude Opus 5 915ef1783a Add release: publish tagged releases on the mirror servers
`release [@name ...] <tag> [notes]` does the whole chain in one step —
create the annotated tag, push it to the internal server, then push it to
each selected mirror and turn it into a release object there. Target
selection reuses pushremote's @name mechanism, so the two behave alike.

Notes are generated when none are given: the tag's own annotation when it
carries more than the default, otherwise the commit subjects since the
previous tag, capped at 50 lines. `tag add v1.0 "why this exists"` now
takes a message, which is what that fallback reads; before, the
annotation was always just the tag name.

Tags ending in -rc/-alpha/-beta/-pre are marked as pre-releases on Gitea
and GitHub. Releasing the same tag twice updates the existing release;
a tag that already points at a different commit stops the command, since
moving a published tag makes one version mean different things per
server. A repository that is not on the mirror yet is reported instead of
being created as a side effect.

Binary assets are deliberately out of scope: Gitea attaches them to the
release, GitHub uses a separate upload host, and GitLab does not host
them at all but wants a link into its package registry.

The providers differ in path shape and field names -- GitLab addresses
projects by URL-encoded path, calls the notes "description" and has no
pre-release flag -- so this comes with a recording httptest stand-in that
asserts the exact requests for all three. That harness also covers
authUser, repoExists and the auth header forms, which had no test at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 15:47:05 +02:00