Skip to content

release v1.0.4

release v1.0.4 #35

Workflow file for this run

# Builds the double-click TinyPlay desktop apps for Windows and macOS (both
# Apple Silicon and Intel), with mpv bundled, and attaches them to a GitHub
# Release when you push a v* tag.
#
# Windows → TinyPlay-Setup-x64.exe (install / upgrade in place)
# macOS → TinyPlay-macos-arm64.dmg (Apple Silicon)
# TinyPlay-macos-intel.dmg (Intel)
# signed+notarized, drag TinyPlay.app to
# Applications. Before the signing
# secrets exist each falls back to an
# unsigned TinyPlay-macos-<arch>.zip so
# the build still runs.
#
# macOS is Developer ID signed + notarized + stapled when the signing secrets
# are present, so users are not blocked by Gatekeeper ("unidentified developer").
# The signing job only runs on tag pushes / manual dispatch — never on pull
# requests — so the certificate secrets are never exposed to untrusted forks.
# Windows artifacts are UNSIGNED for now (no Windows code-signing certificate);
# users may still see a SmartScreen "unknown publisher" prompt.
#
# The Intel macOS leg cross-builds from the arm64 runner: the Go core and
# Swift shell cross-compile natively, but bundling a real x86_64 mpv binary
# needs an x86_64 Homebrew prefix, which this job installs under Rosetta
# (adds a few minutes of extra job time versus the native arm64 leg).
name: release
on:
push:
tags: ["v*"]
workflow_dispatch:
permissions:
contents: write
jobs:
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Download & bundle mpv
shell: bash
# Also stages vulkan-1.dll (mpv imports it and Windows does not ship it)
# and fails the job if any bundled binary still has an unmet dependency.
run: bash ./windows/bundle-mpv.sh dist/mpv
- name: Embed exe icon
shell: bash
run: |
go install github.com/akavel/rsrc@latest
"$(go env GOPATH)/bin/rsrc" -ico assets/icon.ico -o cmd/tvremote/rsrc_windows.syso
- name: Build exe
shell: bash
run: |
set -euo pipefail
if [[ "$GITHUB_REF" == refs/tags/* ]]; then VER="${GITHUB_REF_NAME#v}"; else VER="0.0.0-dev"; fi
go build -ldflags "-H windowsgui -X main.version=$VER" -o dist/TinyPlay.exe ./cmd/tvremote
- name: Bundle third-party notices
shell: bash
run: cp THIRD_PARTY_NOTICES.md dist/THIRD_PARTY_NOTICES.md
- name: Build Windows installer
shell: pwsh
run: |
$compiler = "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe"
if (-not (Test-Path $compiler)) {
choco install innosetup --yes --no-progress
}
if (-not (Test-Path $compiler)) {
throw "Inno Setup compiler was not installed"
}
if ("${{ github.ref }}" -like "refs/tags/*") {
$version = "${{ github.ref_name }}".TrimStart('v')
} else {
$version = "0.0.0-dev"
}
& $compiler "/DMyAppVersion=$version" "windows\TinyPlay.iss"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- uses: actions/upload-artifact@v4
with:
name: TinyPlay-windows-setup
path: dist/TinyPlay-Setup-x64.exe
- name: Attach to release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: dist/TinyPlay-Setup-x64.exe
macos:
strategy:
fail-fast: false
matrix:
include:
- arch: arm64
goarch: arm64
label: arm64
- arch: x86_64
goarch: amd64
label: intel
runs-on: macos-14 # Apple Silicon; the intel leg cross-builds (see notes above)
env:
# 'true' only when the signing secrets exist; gates the sign step so the
# build still succeeds (unsigned) before you've added them.
HAS_SIGNING: ${{ secrets.MACOS_CERTIFICATE != '' && secrets.SIGN_IDENTITY != '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Build Go core (${{ matrix.goarch }})
run: GOOS=darwin GOARCH=${{ matrix.goarch }} go build -o build/tvremote-core-darwin-${{ matrix.goarch }} ./cmd/tvremote
- name: Install packaging tools (dylibbundler, create-dmg)
run: brew install dylibbundler create-dmg
- name: Install x86_64 Homebrew under Rosetta (intel leg only)
if: matrix.arch == 'x86_64'
run: |
set -euo pipefail
softwareupdate --install-rosetta --agree-to-license
if [ ! -x /usr/local/bin/brew ]; then
NONINTERACTIVE=1 arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
# GitHub's runner image ships a pre-existing python.org install under
# /Library/Frameworks/Python.framework with matching /usr/local/bin
# symlinks (idle3, pip3, ...). --overwrite only applies to the
# formula named on the command line, not transitive build
# dependencies, so when brewing mpv pulls in python@3.x (only to
# build man pages) as a dependency, `brew link` on THAT dependency
# still aborts on those pre-existing symlinks even with --overwrite
# here. mpv itself finishes installing regardless, so tolerate the
# failure and verify mpv is actually present instead of treating any
# non-zero exit as fatal.
arch -x86_64 /usr/local/bin/brew install --overwrite mpv || true
if ! arch -x86_64 /usr/local/bin/brew list mpv >/dev/null 2>&1; then
echo "mpv did not install successfully" >&2
exit 1
fi
- name: Download & bundle mpv (self-contained via dylibbundler)
run: |
set -euo pipefail
if [ "${{ matrix.arch }}" = "x86_64" ]; then
real_mpv=$(readlink -f /usr/local/bin/mpv)
else
brew install mpv
real_mpv=$(readlink -f "$(brew --prefix)/bin/mpv")
fi
mkdir -p mpvstage/bin/libs
cp "$real_mpv" mpvstage/bin/mpv
chmod u+w mpvstage/bin/mpv
# Copy every non-system dylib next to the binary and rewrite load paths
# so the bundle runs on a machine without Homebrew. -cd/-of/-od keep it
# non-interactive (it otherwise prompts to create/overwrite and aborts).
dylibbundler -cd -of -od -b -x mpvstage/bin/mpv -d mpvstage/bin/libs -p @executable_path/libs/
- name: Build .app
run: |
set -euo pipefail
if [[ "$GITHUB_REF" == refs/tags/* ]]; then VER="${GITHUB_REF_NAME#v}"; else VER="0.0.0-dev"; fi
ARCH="${{ matrix.arch }}" VERSION="$VER" MPV_DIR="$PWD/mpvstage" REQUIRE_BUNDLED_MPV=1 ./macos/build-app.sh
# Import the Developer ID cert into a keychain that persists for the whole
# job, so both the app-signing and DMG-signing steps below can use it.
- name: Import signing certificate
if: ${{ env.HAS_SIGNING == 'true' }}
env:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
run: ./macos/import-cert.sh
- name: Sign & notarize app
if: ${{ env.HAS_SIGNING == 'true' }}
env:
SIGN_IDENTITY: ${{ secrets.SIGN_IDENTITY }}
AC_API_KEY: ${{ secrets.AC_API_KEY }}
AC_KEY_ID: ${{ secrets.AC_KEY_ID }}
AC_ISSUER_ID: ${{ secrets.AC_ISSUER_ID }}
run: ./macos/sign-notarize.sh "$PWD/build/TinyPlay.app"
- name: Package signed DMG
if: ${{ env.HAS_SIGNING == 'true' }}
env:
SIGN_IDENTITY: ${{ secrets.SIGN_IDENTITY }}
AC_API_KEY: ${{ secrets.AC_API_KEY }}
AC_KEY_ID: ${{ secrets.AC_KEY_ID }}
AC_ISSUER_ID: ${{ secrets.AC_ISSUER_ID }}
run: ./macos/make-dmg.sh "$PWD/build/TinyPlay.app" "$PWD/TinyPlay-macos-${{ matrix.label }}.dmg"
- name: Package unsigned zip (fallback before secrets exist)
if: ${{ env.HAS_SIGNING != 'true' }}
run: |
cd build
ditto -c -k --keepParent "TinyPlay.app" "../TinyPlay-macos-${{ matrix.label }}.zip"
- uses: actions/upload-artifact@v4
with:
name: TinyPlay-macos-${{ matrix.label }}
path: |
TinyPlay-macos-${{ matrix.label }}.dmg
TinyPlay-macos-${{ matrix.label }}.zip
if-no-files-found: warn
- name: Attach to release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: |
TinyPlay-macos-${{ matrix.label }}.dmg
TinyPlay-macos-${{ matrix.label }}.zip