bitnami/minideb ships its base layer as an uncompressed 133 MB tar; with the containerd image store docker push sends it as-is and Cloudflare in front of Gitea answers 413. Build with force-compression=true (base layer becomes ~43 MB) and document why. Co-Authored-By: Claude Fable 5.1 <[email protected]>
8.4 KiB
Publishing to Gitea
Releases are cut by hand. Each one needs a Gitea personal access token
with the write:repository and write:package scopes, which is why none of
this is automated: the token should only ever exist in your own shell or
keychain.
On a Mac that has pushed before, git already holds the token in the login keychain and nothing needs exporting. Elsewhere, create one at Gitea → Settings → Applications → Generate New Token and export it once per shell session:
export GITEA_TOKEN='<paste-your-token>'
There is no Java or Maven on the Mac; every build step below runs in a container, so Docker is the only local requirement.
0. Where the code comes from
origin is this Gitea repository; upstream is
https://github.com/purnell569/MusicBot, the fork this copy was taken from.
git remote -v
# origin https://gitea.milesward.dev/mward4/MusicBot.git
# upstream https://github.com/purnell569/MusicBot.git
To pick up a new upstream version:
git fetch upstream --tags
git merge upstream/main
Upstream's own tags are kept in this repository under upstream/<tag>
(upstream/v0.7.1, …) so they never collide with this repository's release
tags. After a fetch, copy any new upstream tag across before tagging here:
git tag upstream/v0.7.2 v0.7.2 && git tag -d v0.7.2
1. Cut the version
The version is <version> in pom.xml and tracks upstream's (0.7.1). Do
not bump it independently; a merge from upstream brings the new number with
it. Then update the IMAGE_TAG and GIT_REF defaults in
scripts/build-and-publish-unraid.sh, the pinned tag in the README, and
commit. Tag with single quotes — the name starts with a dollar sign:
git tag -a v0.7.1 -m '$uicide Music Bot v0.7.1'
Tags are vMAJOR.MINOR.PATCH and match the pom version; the image carries the
same number without the v (0.7.1) plus a moving latest.
2. Push the code and the tags
git push origin main --follow-tags && git push origin 'refs/tags/upstream/*'
With a token in the environment rather than the keychain, prefix each git
command with git -c "http.extraHeader=Authorization: token $GITEA_TOKEN".
3. Validate
Runs the same thing upstream's CI runs: 676 unit tests and 48 integration tests, then packages the JAR. The named volume keeps the Maven repository between runs so the second run is a couple of minutes.
docker run --rm -v "$PWD":/build -w /build -v musicbot-m2:/root/.m2 maven:3.9.12-eclipse-temurin-25-alpine mvn -B -ntp verify
Expect BUILD SUCCESS and target/JMusicBot-0.7.1-All.jar. This is the full
JAR (all platforms' natives), the one to attach to the release; the Docker
build uses the docker Maven profile, which strips the Windows and macOS
natives.
4. Build the image
The Maven stage runs on the builder's native architecture (the JAR is
architecture-neutral), so only the jlink and runtime stages run under
emulation when building linux/amd64 on Apple Silicon. Two flags matter:
--provenance=false --sbom=false: Unraid's Docker cannot load the attestation manifests BuildKit attaches by default.--output type=docker,compression=gzip,force-compression=true:bitnami/minidebpublishes its base layer as an uncompressed 133 MB tar. A daemon using the containerd image store pushes blobs exactly as stored, and Gitea sits behind Cloudflare, which rejects any request body over 100 MB with413 Payload Too Large. Forcing gzip on every layer takes that one to about 43 MB; the JAR layer (61 MB) and the JRE layer (41 MB) are already under the limit.
docker buildx build --pull --platform linux/amd64 --provenance=false --sbom=false --build-arg "GIT_SHA=$(git rev-parse HEAD)" --build-arg VERSION=0.7.1 --build-arg "BUILD_TIMESTAMP=$(git log -1 --format=%cI)" -t gitea.milesward.dev/mward4/musicbot:0.7.1 -t gitea.milesward.dev/mward4/musicbot:latest --output type=docker,compression=gzip,force-compression=true .
Smoke test: an empty, writable data directory must produce a config.txt and
the "edit it and start again" message, exit code 0. A named volume is used
because Colima only shares $HOME into the VM; a bind mount of a path outside
it silently becomes an empty root-owned directory inside the VM.
docker volume create musicbot-smoke && docker run --rm -v musicbot-smoke:/musicbot alpine:3.20 sh -c 'touch /musicbot/.keep && chown -R 99:100 /musicbot' && docker run --rm --platform linux/amd64 --user 99:100 -v musicbot-smoke:/musicbot gitea.milesward.dev/mward4/musicbot:0.7.1; docker run --rm -v musicbot-smoke:/musicbot alpine:3.20 ls -la /musicbot; docker volume rm musicbot-smoke
5. Push the image
Never run docker login or docker logout for gitea.milesward.dev on a
Mac where git keeps the token in the keychain. Docker's osxkeychain
credential helper maps to the same keychain item as git's: login fails with
"The specified item already exists in the keychain (-25299)", and logout
silently deletes the credential git was using, so the next git push fails
with a bare 401. Write the auth into a throwaway config instead — a config
that already contains an auths entry makes the CLI skip the helper:
export DOCKER_CONFIG="$(mktemp -d)" && printf '{"auths":{"gitea.milesward.dev":{"auth":"%s"}}}' "$(printf 'mward4:%s' "$GITEA_TOKEN" | base64 | tr -d '\n')" > "$DOCKER_CONFIG/config.json" && docker push gitea.milesward.dev/mward4/musicbot:0.7.1 && docker push gitea.milesward.dev/mward4/musicbot:latest; rm -rf "$DOCKER_CONFIG"; unset DOCKER_CONFIG
On a Colima host, export DOCKER_HOST="unix://$HOME/.colima/default/docker.sock"
first: an isolated DOCKER_CONFIG has no currentContext, and the CLI would
otherwise look for /var/run/docker.sock.
On a fresh machine, scripts/build-and-publish-unraid.sh does the clone,
build and push in one pass using that same private-config approach:
GITEA_TOKEN="$GITEA_TOKEN" ./scripts/build-and-publish-unraid.sh
6. Verify the pull
The repo and package are public, so this needs no credentials — which is
exactly how Unraid will fetch it. An empty DOCKER_CONFIG keeps the keychain
out of the test:
export DOCKER_CONFIG="$(mktemp -d)" && docker pull --platform linux/amd64 gitea.milesward.dev/mward4/musicbot:0.7.1; rm -rf "$DOCKER_CONFIG"; unset DOCKER_CONFIG
7. Create the release
One release per version, on the vX.Y.Z tag, named $uicide Music Bot vX.Y.Z,
with the pull command and what changed. Gitea only accepts the attachment
types in its allow-list (.zip, .txt, … but not .jar), so the JAR ships
zipped alongside a checksum file:
cd target && cp JMusicBot-0.7.1-All.jar JMusicBot-0.7.1.jar && zip -q JMusicBot-0.7.1.zip JMusicBot-0.7.1.jar && shasum -a 256 JMusicBot-0.7.1.jar JMusicBot-0.7.1.zip > SHA256SUMS.txt && cd ..
Create the release and upload the two files (the release id comes back in
the first response):
curl -s -X POST https://gitea.milesward.dev/api/v1/repos/mward4/MusicBot/releases -H "Authorization: token $GITEA_TOKEN" -H 'Content-Type: application/json' -d @release.json
curl -s -X POST "https://gitea.milesward.dev/api/v1/repos/mward4/MusicBot/releases/<id>/assets?name=JMusicBot-0.7.1.zip" -H "Authorization: token $GITEA_TOKEN" -F attachment=@target/JMusicBot-0.7.1.zip
curl -s -X POST "https://gitea.milesward.dev/api/v1/repos/mward4/MusicBot/releases/<id>/assets?name=SHA256SUMS.txt" -H "Authorization: token $GITEA_TOKEN" -F attachment=@target/SHA256SUMS.txt
release.json is {"tag_name":"v0.7.1","target_commitish":"main","name":"$uicide Music Bot v0.7.1","body":"…","draft":false,"prerelease":false}.
8. Deploy on Unraid
Add a container with Repository set to:
gitea.milesward.dev/mward4/musicbot:0.7.1
(or :latest). Map /musicbot to /mnt/user/appdata/musicbot, no ports,
bridge networking, and --user 99:100 in Extra Parameters so the bot runs as
Unraid's usual nobody:users and the appdata folder needs no chown. Or import
deploy/unraid/musicbot.xml into
/boot/config/plugins/dockerMan/templates-user/ to get all of that prefilled.
First start writes config.txt into the appdata folder and stops. Set token
and owner in it, start again. To upgrade an existing container, change the
tag and apply; config.txt, serversettings.json and Playlists/ all live in
the appdata mount and carry over.
Afterwards
If a token was exported, make sure it is not left in the shell:
unset GITEA_TOKEN