Build and Test / Build and Test (push) Successful in 1m12s
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]>
197 lines
8.4 KiB
Markdown
197 lines
8.4 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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/minideb` publishes 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 with `413 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.
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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):
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
unset GITEA_TOKEN
|
|
```
|