diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index 13ebe16d..d7da91b8 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -63,6 +63,34 @@ jobs: echo "${{ secrets.REGISTRY_TOKEN }}" \ | docker login git.fabledsword.com -u "${{ github.actor }}" --password-stdin + # In-app update flow (#397): on tag pushes only, fetch the APK + # that flutter.yml is attaching to this same release. flutter.yml + # runs in parallel; poll up to 15 min for the asset to appear. + # On main pushes (or if the APK never lands), client/ stays empty + # and the endpoints return 404 — graceful degradation. + - name: Fetch APK for bundled in-app update channel + if: steps.guard.outputs.ready == 'true' && startsWith(github.ref, 'refs/tags/v') + shell: bash + env: + RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} + run: | + TAG="${GITHUB_REF#refs/tags/}" + REPO="${GITHUB_REPOSITORY}" + APK_URL="https://git.fabledsword.com/${REPO}/releases/download/${TAG}/minstrel-${TAG}.apk" + echo "Polling ${APK_URL} (up to 15 min for flutter.yml to attach)..." + for i in $(seq 1 30); do + if curl -fsSL -H "Authorization: token ${RELEASE_TOKEN}" \ + -o client/minstrel.apk "$APK_URL"; then + echo "Got APK on attempt $i" + echo "${TAG}" > client/minstrel.apk.version + ls -lh client/ + exit 0 + fi + echo "APK not ready yet (attempt $i/30), sleeping 30s..." + sleep 30 + done + echo "::warning::APK never appeared at ${APK_URL} after 15 min — image will ship without bundled update channel" + - name: Build and push if: steps.guard.outputs.ready == 'true' run: docker buildx build --push ${{ steps.tags.outputs.args }} . diff --git a/.gitignore b/.gitignore index 6cf722a0..1d68ff13 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,11 @@ # Test binary, built with `go test -c` *.test +# Bundled Android APK + version sidecar (#397). Populated by CI for +# tag releases; never committed. README in client/ explains the flow. +client/minstrel.apk +client/minstrel.apk.version + # Output of the go coverage tool, specifically when used with LiteIDE *.out diff --git a/Dockerfile b/Dockerfile index 07b8f17b..34cc41ad 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,14 +36,11 @@ COPY config.example.yaml /etc/smartmusic/config.yaml RUN mkdir -p /app/data /app/client && chown -R minstrel:minstrel /app WORKDIR /app -# In-app update channel (#397): bundled Android APK + sidecar version -# file. CI populates these on tag releases via a build context COPY; -# leaving the COPY commented during scaffold means the endpoints return -# 404 until the CI sequencing lands. Operators can also drop these in -# at runtime via a volume mount on /app/client. -# -# COPY minstrel.apk /app/client/minstrel.apk -# COPY minstrel.apk.version /app/client/minstrel.apk.version +# In-app update channel (#397). client/ in the build context holds +# minstrel.apk + minstrel.apk.version (populated by release.yml on tag +# pushes; .gitkeep + README otherwise). Endpoints return 404 when the +# APK files aren't present, so non-tag images degrade gracefully. +COPY --chown=minstrel:minstrel client/ /app/client/ USER minstrel EXPOSE 4533 diff --git a/client/.gitkeep b/client/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/client/README.md b/client/README.md new file mode 100644 index 00000000..29e8de6c --- /dev/null +++ b/client/README.md @@ -0,0 +1,35 @@ +# Bundled client assets + +Holds the Android APK (`minstrel.apk` + `minstrel.apk.version`) that the +server serves via `/api/client/version` and `/api/client/apk` for the +in-app update flow (#397). + +## Production + +CI populates this directory on tag releases: +1. `flutter.yml` builds `app-release.apk` and attaches it to the + Forgejo release as `minstrel-.apk`. +2. `release.yml` waits for that asset to appear, downloads it into + this directory as `minstrel.apk`, writes the tag string to + `minstrel.apk.version`, and `docker buildx build` includes both + via `COPY client/ /app/client/`. + +## Development + +Empty directory works fine — the endpoints return 404 and the Flutter +update banner stays hidden ("no update channel" graceful degradation). + +To smoke-test the update flow locally, drop a real APK + a version +file into this directory: + +```sh +cp /path/to/app-release.apk client/minstrel.apk +echo "v0.2.0" > client/minstrel.apk.version +``` + +## Why a directory and not embed.FS? + +The APK is 30-60 MB. Embedding bloats the Go binary and slows +`go build` for everyone, even when the APK isn't being changed. +File-on-disk also lets operators override at runtime via volume +mount on `/app/client/` if they want to ship their own build.