mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 22:03:13 -06:00
The rc2 workflow built autorun.zip and then published a release without it: the edit that was supposed to add it to the gh release create asset list never applied, and nothing asserted that it had. Built artifacts that quietly fail to ship are worse than ones that fail loudly — the release looked green. Attached to rc2 by hand; from rc3 the workflow does it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
185 lines
7.6 KiB
YAML
185 lines
7.6 KiB
YAML
name: Release
|
|
|
|
# Fires when a version tag is pushed (e.g. v1.8.0). Builds + publishes artifacts
|
|
# only - nothing here deploys to production.
|
|
on:
|
|
push:
|
|
tags: ['v*']
|
|
|
|
permissions:
|
|
contents: write # create the GitHub Release
|
|
packages: write # push the image to ghcr.io
|
|
|
|
concurrency:
|
|
group: release-${{ github.ref }}
|
|
cancel-in-progress: false # never cancel a release mid-publish
|
|
|
|
jobs:
|
|
# Fail-fast: a hand-pushed tag that disagrees with VERSION must not publish
|
|
# anything (the artifacts would report the wrong version). Gates everything.
|
|
verify:
|
|
name: Verify tag matches VERSION
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- name: Assert pushed tag equals VERSION
|
|
run: |
|
|
TAG="${GITHUB_REF_NAME#v}"
|
|
FILE="$(cat VERSION)"
|
|
echo "pushed tag: ${GITHUB_REF_NAME} (stripped: $TAG) VERSION file: $FILE"
|
|
if [ "$TAG" != "$FILE" ]; then
|
|
echo "::error::Tag ${GITHUB_REF_NAME} does not match VERSION ($FILE) - refusing to publish."
|
|
exit 1
|
|
fi
|
|
echo "OK: tag matches VERSION ($FILE)"
|
|
|
|
test:
|
|
name: Tests
|
|
needs: verify
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
working-directory: server
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: '20'
|
|
cache: npm
|
|
cache-dependency-path: server/package-lock.json
|
|
- run: npm ci
|
|
- run: npm test
|
|
|
|
artifacts:
|
|
name: Tarball + Tizen .wgt + GitHub Release
|
|
needs: test
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0 # full history, for release notes
|
|
|
|
- name: Resolve version + previous tag
|
|
id: ver
|
|
run: |
|
|
VERSION="$(cat VERSION)"
|
|
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
|
|
PREV="$(git describe --tags --abbrev=0 "${GITHUB_REF_NAME}^" 2>/dev/null || true)"
|
|
echo "prev=$PREV" >> "$GITHUB_OUTPUT"
|
|
# #80: a version carrying a -suffix (e.g. 1.9.0-rc1) is a pre-release.
|
|
case "$VERSION" in *-*) PRE=true ;; *) PRE=false ;; esac
|
|
echo "prerelease=$PRE" >> "$GITHUB_OUTPUT"
|
|
echo "Releasing ${GITHUB_REF_NAME} (version $VERSION, prerelease=$PRE); previous tag: ${PREV:-<none>}"
|
|
|
|
- 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 BrightSign autorun.zip (single-file player installer)
|
|
run: |
|
|
chmod +x scripts/build-autorun-zip.sh
|
|
./scripts/build-autorun-zip.sh -o autorun.zip
|
|
ls -la autorun.zip
|
|
|
|
- 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' \
|
|
server frontend scripts docs VERSION README.md LICENSE .env.example ScreenTinker.wgt brightsign
|
|
echo "TARBALL=$OUT" >> "$GITHUB_ENV"
|
|
ls -la "$OUT"
|
|
|
|
- name: Generate release notes
|
|
run: |
|
|
PREV="${{ steps.ver.outputs.prev }}"
|
|
{
|
|
echo "## ScreenTinker ${{ steps.ver.outputs.tag }}"
|
|
echo
|
|
echo "### Changes"
|
|
if [ -n "$PREV" ]; then
|
|
git log --no-merges --pretty='- %s' "${PREV}..${{ steps.ver.outputs.tag }}"
|
|
else
|
|
echo "_First tagged release. Most recent changes:_"
|
|
git log --no-merges --pretty='- %s' -n 30 "${{ steps.ver.outputs.tag }}"
|
|
fi
|
|
echo
|
|
echo "### Artifacts"
|
|
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 "- \`autorun.zip\` - BrightSign player installer. Drop it on the root of a player's"
|
|
echo " storage (microSD, USB, or internal flash) and power-cycle: it unpacks itself and"
|
|
echo " reboots into the player. Edit \`screentinker.json\` inside the archive first to"
|
|
echo " point it at your own server."
|
|
if [ "${{ steps.ver.outputs.prerelease }}" = "true" ]; then
|
|
echo "- Docker image: \`ghcr.io/screentinker/screentinker:${{ steps.ver.outputs.version }}\` (pre-release - \`:latest\` is NOT moved)."
|
|
else
|
|
echo "- Docker image: \`ghcr.io/screentinker/screentinker:${{ steps.ver.outputs.version }}\` (also \`:latest\`)."
|
|
fi
|
|
echo "- \`ScreenTinker.apk\` - signed Android player (attached during release finalization)."
|
|
} > RELEASE_NOTES.md
|
|
cat RELEASE_NOTES.md
|
|
|
|
- name: Create GitHub Release
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
# #80: pre-release tags publish as a GitHub *pre-release* (not "Latest"),
|
|
# which also keeps the /releases/latest API pointing at the last stable.
|
|
PRERELEASE_FLAG=""
|
|
[ "${{ steps.ver.outputs.prerelease }}" = "true" ] && PRERELEASE_FLAG="--prerelease"
|
|
gh release create "${{ steps.ver.outputs.tag }}" \
|
|
$PRERELEASE_FLAG \
|
|
--title "ScreenTinker ${{ steps.ver.outputs.tag }}" \
|
|
--notes-file RELEASE_NOTES.md \
|
|
"${TARBALL}" \
|
|
autorun.zip \
|
|
tizen/ScreenTinker.wgt
|
|
|
|
docker:
|
|
name: Docker image (amd64 + arm64) -> ghcr
|
|
needs: test
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- id: ver
|
|
run: |
|
|
VERSION="$(cat VERSION)"
|
|
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
# #80: move :latest only for final releases - a pre-release (1.9.0-rc1) must
|
|
# not repoint :latest onto untested code (anyone on :latest pulls it on restart).
|
|
TAGS="ghcr.io/screentinker/screentinker:$VERSION"
|
|
case "$VERSION" in
|
|
*-*) echo "Pre-release $VERSION: :latest will NOT be moved" ;;
|
|
*) TAGS="${TAGS}"$'\n'"ghcr.io/screentinker/screentinker:latest" ;;
|
|
esac
|
|
{ echo "tags<<__EOF__"; printf '%s\n' "$TAGS"; echo "__EOF__"; } >> "$GITHUB_OUTPUT"
|
|
- uses: docker/setup-qemu-action@v3
|
|
- uses: docker/setup-buildx-action@v3
|
|
- uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
- uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
platforms: linux/amd64,linux/arm64
|
|
push: true
|
|
tags: ${{ steps.ver.outputs.tags }}
|
|
|
|
# TODO (deferred): build + sign the Android APK in CI. Requires the release
|
|
# keystore + passwords as encrypted Actions secrets. For now the maintainer
|
|
# attaches a signed APK out-of-band (and self-hosters mount one at
|
|
# /data/ScreenTinker.apk).
|