release: bundle .wgt in the CI tarball + finalize-release.sh for the signed apk

- release.yml: build the Tizen .wgt before the source tarball and bundle it in
  (ScreenTinker.wgt at the tarball root). The signed Android APK is added by the
  local finalize step (the keystore stays off CI).
- scripts/finalize-release.sh: after the release workflow publishes a tag, build
  the signed APK locally, pull the CI-built unsigned .wgt from the release,
  assemble a complete tarball (source + apk + wgt at the root, where /download/apk
  resolves the apk after extraction), and upload the apk + complete tarball.
- .gitignore: ignore *.wgt and *.tar.gz so finalize temp files cannot be committed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
ScreenTinker 2026-06-10 14:12:29 -05:00
parent 4f56199bc7
commit fb17b242ce
3 changed files with 59 additions and 10 deletions

View file

@ -68,24 +68,25 @@ jobs:
echo "prev=$PREV" >> "$GITHUB_OUTPUT"
echo "Releasing ${GITHUB_REF_NAME} (version $(cat VERSION)); previous tag: ${PREV:-<none>}"
- name: Build source tarball
- name: Build Tizen .wgt (unsigned in CI)
run: |
chmod +x tizen/build-wgt.sh
( cd tizen && ./build-wgt.sh ) # no Tizen CLI on the runner => unsigned zip
cp tizen/ScreenTinker.wgt ScreenTinker.wgt
ls -la ScreenTinker.wgt
- name: Build source tarball (bundles the .wgt; the signed apk is added by scripts/finalize-release.sh)
run: |
OUT="screentinker-${{ steps.ver.outputs.version }}.tar.gz"
tar czf "$OUT" \
--exclude='node_modules' --exclude='.git' --exclude='.github' \
--exclude='*.db' --exclude='*.db-wal' --exclude='*.db-shm' --exclude='*.db.*' \
--exclude='server/uploads' --exclude='server/certs' --exclude='server/test' \
--exclude='*.apk' --exclude='*.wgt' \
server frontend scripts VERSION README.md LICENSE .env.example
--exclude='*.apk' \
server frontend scripts VERSION README.md LICENSE .env.example ScreenTinker.wgt
echo "TARBALL=$OUT" >> "$GITHUB_ENV"
ls -la "$OUT"
- name: Build Tizen .wgt (unsigned in CI)
run: |
chmod +x tizen/build-wgt.sh
( cd tizen && ./build-wgt.sh ) # no Tizen CLI on the runner => unsigned zip
ls -la tizen/ScreenTinker.wgt
- name: Generate release notes
run: |
PREV="${{ steps.ver.outputs.prev }}"
@ -101,12 +102,13 @@ jobs:
fi
echo
echo "### Artifacts"
echo "- \`${TARBALL}\` - server + frontend source tarball (Node 20; see the README to run)."
echo "- \`${TARBALL}\` - bundle: server + frontend source + the Tizen .wgt (the signed Android APK is added at the root during release finalization)."
echo "- \`ScreenTinker.wgt\` - Tizen TV web app, **unsigned - for inspection only**."
echo " Sign it with your own Samsung certificate (Tizen Studio + a profile that includes"
echo " your TV's DUID) to install, or - easiest - point a Tizen TV browser / URL Launcher"
echo " at \`https://<your-instance>/player\` (no signing needed)."
echo "- Docker image: \`ghcr.io/screentinker/screentinker:${{ steps.ver.outputs.version }}\` (also \`:latest\`)."
echo "- \`ScreenTinker.apk\` - signed Android player (attached during release finalization)."
} > RELEASE_NOTES.md
cat RELEASE_NOTES.md

2
.gitignore vendored
View file

@ -26,6 +26,8 @@ android/local.properties
android/release-key.jks
*.apk
*.aab
*.wgt
*.tar.gz
# IDE / Editor
.claude/

45
scripts/finalize-release.sh Executable file
View file

@ -0,0 +1,45 @@
#!/bin/bash
# Finalize a release with the artifacts that need the LOCAL signing keystore
# (which never goes into CI). After the release workflow has published the tag's
# GitHub Release (source tarball + unsigned .wgt + docker image), run this to:
# 1. build the SIGNED Android APK locally,
# 2. pull the CI-built unsigned .wgt back down from the release,
# 3. assemble a COMPLETE source tarball that bundles BOTH binaries
# (extract it and ScreenTinker.apk sits at the root, ready for /download/apk),
# 4. upload the APK + the complete tarball to the release (replacing the
# source-only tarball CI uploaded).
#
# KEYSTORE_PASSWORD=... KEY_PASSWORD=... scripts/finalize-release.sh
#
# Requires: Android SDK + the release keystore (android/release-key.jks), the
# Tizen .wgt already on the release, and an authenticated gh CLI.
set -euo pipefail
cd "$(dirname "$0")/.."
VERSION="$(cat VERSION)"
TAG="v$VERSION"
: "${KEYSTORE_PASSWORD:?set KEYSTORE_PASSWORD}"
: "${KEY_PASSWORD:?set KEY_PASSWORD}"
cleanup() { rm -f ScreenTinker.apk ScreenTinker.wgt "screentinker-$VERSION.tar.gz"; }
trap cleanup EXIT
echo "==> Building signed APK $VERSION"
( cd android && KEYSTORE_PASSWORD="$KEYSTORE_PASSWORD" KEY_PASSWORD="$KEY_PASSWORD" ./gradlew assembleRelease )
cp android/app/build/outputs/apk/release/app-release.apk ScreenTinker.apk
echo "==> Pulling the CI-built unsigned .wgt from release $TAG"
gh release download "$TAG" -p ScreenTinker.wgt --clobber
echo "==> Assembling complete tarball (source + apk + wgt)"
OUT="screentinker-$VERSION.tar.gz"
tar czf "$OUT" \
--exclude='node_modules' --exclude='.git' --exclude='.github' \
--exclude='*.db' --exclude='*.db-wal' --exclude='*.db-shm' --exclude='*.db.*' \
--exclude='server/uploads' --exclude='server/certs' --exclude='server/test' \
server frontend scripts VERSION README.md LICENSE .env.example \
ScreenTinker.apk ScreenTinker.wgt
echo "==> Uploading APK + complete tarball to $TAG"
gh release upload "$TAG" "$OUT" ScreenTinker.apk --clobber
echo "==> Done: $TAG now carries the standalone APK and a tarball bundling apk + wgt."