mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-08 23:54:39 +00:00
Enable distributing the `amy` CLI via Homebrew-core (mainline formulae). Homebrew-core builds in a network-sandboxed env, so a from-source Gradle build can't resolve Maven deps there; the accepted pattern for JVM tools is a pre-built no-JRE jar bundle + `depends_on "openjdk"`. installDist already produces exactly that (bin/amy + lib/*.jar, no bundled runtime). - create-release.yml: publish `amy-<version>-jvm.tar.gz` (the installDist tree) as a release asset on the linux leg. Pure JVM bytecode, so one platform-independent artifact serves every OS. - packaging/homebrew/amy.rb: reference formula (depends_on openjdk, livecheck for BrewTestBot auto-bumps, `amy --help` smoke test). Not consumed by any build here — it's the artifact to submit to Homebrew/homebrew-core. - BUILDING.md: homebrew-core submission runbook; note that the desktop app is already on mainline Homebrew (homebrew/cask); document name-collision and pre-built-jar review caveats. - asset-name.sh: document the jvm bundle naming exception. Verified locally: :cli:installDist builds with only a JDK (no Android SDK), and the extracted bundle runs via JAVA_HOME (`amy --help` exits 0). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015sso31DfSF9B6EFCVkEqWD
526 lines
22 KiB
YAML
526 lines
22 KiB
YAML
name: Create Release Assets
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
|
|
workflow_dispatch:
|
|
inputs:
|
|
dry_run:
|
|
description: 'Dry run: build assets but do not publish to GH Release or trigger bump workflows'
|
|
type: boolean
|
|
default: false
|
|
test_tag:
|
|
description: 'Synthetic tag name for dry-run (e.g. vX.YY.Z-dryrun); ignored on tag push'
|
|
type: string
|
|
default: 'v0.0.0-dryrun'
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
env:
|
|
# Asset naming contract: amethyst-desktop-<version>-<family>-<arch>.<ext>
|
|
# Single source of truth in scripts/asset-name.sh.
|
|
# appimagetool pinned release — bump via Dependabot, verify SHA256 via env var below.
|
|
# We used to use linuxdeploy here, but it auto-walks the AppDir with ldd to
|
|
# bundle deps — that fights jpackage's self-contained JRE (libjvm.so has
|
|
# $ORIGIN RPATH so ldd can't resolve it standalone). appimagetool only
|
|
# embeds the AppDir as-is, which is what we actually want.
|
|
APPIMAGETOOL_URL: https://github.com/AppImage/appimagetool/releases/download/1.9.0/appimagetool-x86_64.AppImage
|
|
APPIMAGETOOL_SHA256: 46fdd785094c7f6e545b61afcfb0f3d98d8eab243f644b4b17698c01d06083d1
|
|
|
|
jobs:
|
|
# ---------------------------------------------------------------------------
|
|
# Desktop build matrix. Each leg uploads directly to the GH Release via
|
|
# softprops/action-gh-release@v2 (upsert by tag_name). No artifact round-trip.
|
|
# ---------------------------------------------------------------------------
|
|
build-desktop:
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- { os: macos-14, arch: arm64, family: macos, tasks: "packageReleaseDmg" }
|
|
- { os: windows-latest, arch: x64, family: windows, tasks: "packageReleaseMsi createReleaseDistributable" }
|
|
- { os: ubuntu-latest, arch: x64, family: linux, tasks: "packageReleaseDeb packageReleaseRpm" }
|
|
- { os: ubuntu-latest, arch: x64, family: linux-portable, tasks: "createReleaseAppImage createReleaseDistributable" }
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 45
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Set up JDK 21
|
|
uses: actions/setup-java@v5
|
|
with:
|
|
distribution: 'temurin'
|
|
java-version: 21
|
|
|
|
- name: Resolve tag + version
|
|
id: ver
|
|
env:
|
|
DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }}
|
|
TEST_TAG: ${{ github.event.inputs.test_tag || '' }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
|
|
TAG="${TEST_TAG:-v0.0.0-dryrun}"
|
|
else
|
|
TAG="${GITHUB_REF_NAME}"
|
|
fi
|
|
VER="${TAG#v}"
|
|
TOML_VER=$(grep -E '^app\s*=' gradle/libs.versions.toml | head -1 | cut -d'"' -f2)
|
|
# On dry-run we only require that TOML has a version; on real tag push we require exact match.
|
|
if [[ "${GITHUB_EVENT_NAME}" != "workflow_dispatch" ]]; then
|
|
if [[ "$TOML_VER" != "$VER" ]]; then
|
|
echo "::error::gradle/libs.versions.toml app=$TOML_VER but tag is $TAG"
|
|
exit 1
|
|
fi
|
|
fi
|
|
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
echo "version=$VER" >> "$GITHUB_OUTPUT"
|
|
echo "toml=$TOML_VER" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Install RPM tooling (deb+rpm leg only)
|
|
if: matrix.family == 'linux'
|
|
run: sudo apt-get update && sudo apt-get install -y rpm fakeroot
|
|
|
|
- name: Fetch appimagetool (linux-portable only, SHA-verified)
|
|
if: matrix.family == 'linux-portable'
|
|
run: |
|
|
set -euo pipefail
|
|
# appimagetool 1.9.0 validates the .desktop file via desktop-file-validate.
|
|
sudo apt-get update && sudo apt-get install -y desktop-file-utils
|
|
curl -fsSL --retry 3 "$APPIMAGETOOL_URL" -o desktopApp/packaging/appimage/appimagetool-x86_64.AppImage
|
|
actual=$(sha256sum desktopApp/packaging/appimage/appimagetool-x86_64.AppImage | awk '{print $1}')
|
|
if [[ "$actual" != "$APPIMAGETOOL_SHA256" ]]; then
|
|
echo "::error::appimagetool SHA256 mismatch. Expected $APPIMAGETOOL_SHA256, got $actual"
|
|
exit 1
|
|
fi
|
|
chmod +x desktopApp/packaging/appimage/appimagetool-x86_64.AppImage
|
|
|
|
# macOS only: import the Developer ID Application cert into a throwaway
|
|
# keychain so jpackage's codesign pass can find it. Soft-gated — if the
|
|
# MAC_CERTIFICATE_P12 secret isn't set (forks, or before Apple creds are
|
|
# provisioned) the DMG is built UNSIGNED, exactly as before. notarytool
|
|
# runs as part of the gradle task when the identity env is exported below.
|
|
- name: Import Apple Developer ID certificate (macOS leg, if configured)
|
|
if: matrix.family == 'macos'
|
|
id: mac_keychain
|
|
env:
|
|
CERT_P12: ${{ secrets.MAC_CERTIFICATE_P12 }}
|
|
CERT_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ -z "${CERT_P12:-}" ]]; then
|
|
echo "::notice::MAC_CERTIFICATE_P12 not set — building UNSIGNED DMG."
|
|
echo "signing=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
KEYCHAIN="$RUNNER_TEMP/amethyst-signing.keychain-db"
|
|
KEYCHAIN_PWD="$(openssl rand -base64 24)"
|
|
CERT_PATH="$RUNNER_TEMP/developer_id.p12"
|
|
security create-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN"
|
|
security set-keychain-settings -lut 21600 "$KEYCHAIN"
|
|
security unlock-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN"
|
|
echo "$CERT_P12" | base64 --decode > "$CERT_PATH"
|
|
security import "$CERT_PATH" -P "$CERT_PASSWORD" \
|
|
-k "$KEYCHAIN" -T /usr/bin/codesign -T /usr/bin/productsign
|
|
# Let codesign use the private key without an interactive UI prompt.
|
|
security set-key-partition-list -S apple-tool:,apple:,codesign: \
|
|
-s -k "$KEYCHAIN_PWD" "$KEYCHAIN" >/dev/null
|
|
# Prepend our keychain to the user search list so codesign sees it.
|
|
security list-keychains -d user -s "$KEYCHAIN" \
|
|
$(security list-keychains -d user | sed -e 's/[\"[:space:]]//g')
|
|
rm -f "$CERT_PATH"
|
|
echo "signing=true" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Build desktop artifacts
|
|
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
|
|
env:
|
|
# Empty on non-macOS legs and on the macOS leg when no cert is
|
|
# configured — the gradle macOS{} block skips signing when the
|
|
# identity is blank.
|
|
AMETHYST_MAC_SIGN_IDENTITY: ${{ steps.mac_keychain.outputs.signing == 'true' && secrets.MAC_SIGN_IDENTITY || '' }}
|
|
AMETHYST_NOTARY_APPLE_ID: ${{ secrets.MAC_NOTARY_APPLE_ID }}
|
|
AMETHYST_NOTARY_PASSWORD: ${{ secrets.MAC_NOTARY_PASSWORD }}
|
|
AMETHYST_NOTARY_TEAM_ID: ${{ secrets.MAC_NOTARY_TEAM_ID }}
|
|
with:
|
|
max_attempts: 2
|
|
timeout_minutes: 15
|
|
command: ./gradlew --no-daemon :desktopApp:${{ matrix.tasks }}
|
|
|
|
# jpackage pins libicu to the build host's version (libicu74 on
|
|
# ubuntu-24.04). Rewrite the .deb so it installs across Debian/Ubuntu.
|
|
- name: Relax libicu dependency in .deb
|
|
if: matrix.family == 'linux'
|
|
run: |
|
|
set -euo pipefail
|
|
chmod +x scripts/relax-deb-libicu.sh
|
|
scripts/relax-deb-libicu.sh desktopApp/build/compose/binaries/main-release/deb/*.deb
|
|
|
|
- name: Build portable archives (windows + linux-portable)
|
|
if: matrix.family == 'windows' || matrix.family == 'linux-portable'
|
|
run: |
|
|
set -euo pipefail
|
|
VER="${{ steps.ver.outputs.version }}"
|
|
APP="desktopApp/build/compose/binaries/main-release/app"
|
|
mkdir -p desktopApp/build/portable
|
|
if [[ "${{ matrix.family }}" == "windows" ]]; then
|
|
( cd "$APP" && 7z a -tzip "../../../../portable/amethyst-desktop-${VER}-windows-x64.zip" Amethyst/ )
|
|
else
|
|
( cd "$APP" && tar czf "../../../../portable/amethyst-desktop-${VER}-linux-x64.tar.gz" Amethyst/ )
|
|
fi
|
|
|
|
- name: Collect + rename assets
|
|
run: |
|
|
set -euo pipefail
|
|
# shellcheck source=scripts/asset-name.sh
|
|
source scripts/asset-name.sh
|
|
# collect_assets normalizes linux-portable → linux internally.
|
|
collect_assets "${{ matrix.family }}" "${{ matrix.arch }}" "${{ steps.ver.outputs.version }}" dist
|
|
|
|
- name: Enforce asset size budget (1 GB per asset)
|
|
run: |
|
|
set -euo pipefail
|
|
fail=0
|
|
for f in dist/*; do
|
|
if [[ -f "$f" ]]; then
|
|
size=$(wc -c < "$f")
|
|
mb=$(( size / 1048576 ))
|
|
if (( size > 1073741824 )); then
|
|
echo "::error file=$f::asset is ${mb} MB — exceeds 1 GB budget"
|
|
fail=1
|
|
else
|
|
echo "OK: $f — ${mb} MB"
|
|
fi
|
|
fi
|
|
done
|
|
[[ "$fail" == 0 ]]
|
|
|
|
- name: Classify release
|
|
id: classify
|
|
run: |
|
|
TAG="${{ steps.ver.outputs.tag }}"
|
|
# Stable = exactly vMAJOR.MINOR.PATCH; everything else is prerelease.
|
|
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "prerelease=false" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "prerelease=true" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Upload to GH Release (skip on dry-run)
|
|
if: github.event_name != 'workflow_dispatch' || github.event.inputs.dry_run != 'true'
|
|
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
|
with:
|
|
files: dist/*
|
|
tag_name: ${{ steps.ver.outputs.tag }}
|
|
prerelease: ${{ steps.classify.outputs.prerelease }}
|
|
draft: false
|
|
fail_on_unmatched_files: true
|
|
generate_release_notes: false # Android job writes release notes (last-writer-wins race)
|
|
|
|
- name: Dry-run summary
|
|
if: github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true'
|
|
run: |
|
|
echo "### Dry-run: ${{ matrix.family }}/${{ matrix.arch }}" >> "$GITHUB_STEP_SUMMARY"
|
|
echo "" >> "$GITHUB_STEP_SUMMARY"
|
|
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
|
ls -la dist >> "$GITHUB_STEP_SUMMARY"
|
|
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Amy CLI build matrix. Each leg produces a self-contained amy bundle with a
|
|
# minimal jlink'd JRE — no system Java required on the user's machine.
|
|
#
|
|
# amyImage task (all legs): cli/build/amy-image/amy/ → amy-*.tar.gz
|
|
# jpackageDeb / jpackageRpm: cli/build/jpackage/amy_*.deb + amy-*.rpm
|
|
#
|
|
# macOS legs ship only the tarball. We deliberately avoid jpackage --type
|
|
# app-image on macOS because it produces an .app bundle (burying the binary
|
|
# at Contents/MacOS/amy) — wrong UX for a CLI.
|
|
#
|
|
# Windows is intentionally deferred — cli/ has not been validated on Windows
|
|
# yet (data-dir path handling, file locking on groups/<gid>.mls, line endings
|
|
# in identity.json).
|
|
#
|
|
# Asset naming: amy-<version>-<family>-<arch>.<ext>. See scripts/asset-name.sh.
|
|
# ---------------------------------------------------------------------------
|
|
build-cli:
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- { os: macos-14, arch: arm64, family: macos, tasks: "amyImage" }
|
|
- { os: ubuntu-latest, arch: x64, family: linux, tasks: "amyImage jpackageDeb jpackageRpm" }
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 30
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Set up JDK 21
|
|
uses: actions/setup-java@v5
|
|
with:
|
|
distribution: 'temurin'
|
|
java-version: 21
|
|
|
|
- name: Resolve tag + version
|
|
id: ver
|
|
env:
|
|
DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }}
|
|
TEST_TAG: ${{ github.event.inputs.test_tag || '' }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
|
|
TAG="${TEST_TAG:-v0.0.0-dryrun}"
|
|
else
|
|
TAG="${GITHUB_REF_NAME}"
|
|
fi
|
|
VER="${TAG#v}"
|
|
TOML_VER=$(grep -E '^app\s*=' gradle/libs.versions.toml | head -1 | cut -d'"' -f2)
|
|
# On dry-run we only require that TOML has a version; on real tag push we require exact match.
|
|
if [[ "${GITHUB_EVENT_NAME}" != "workflow_dispatch" ]]; then
|
|
if [[ "$TOML_VER" != "$VER" ]]; then
|
|
echo "::error::gradle/libs.versions.toml app=$TOML_VER but tag is $TAG"
|
|
exit 1
|
|
fi
|
|
fi
|
|
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
echo "version=$VER" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Install RPM tooling (linux only)
|
|
if: matrix.family == 'linux'
|
|
run: sudo apt-get update && sudo apt-get install -y rpm fakeroot
|
|
|
|
- name: Build amy artifacts
|
|
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
|
|
with:
|
|
max_attempts: 2
|
|
timeout_minutes: 15
|
|
command: ./gradlew --no-daemon :cli:${{ matrix.tasks }}
|
|
|
|
# jpackage pins libicu to the build host's version (libicu74 on
|
|
# ubuntu-24.04). Rewrite the .deb so it installs across Debian/Ubuntu.
|
|
- name: Relax libicu dependency in .deb
|
|
if: matrix.family == 'linux'
|
|
run: |
|
|
set -euo pipefail
|
|
chmod +x scripts/relax-deb-libicu.sh
|
|
scripts/relax-deb-libicu.sh cli/build/jpackage/*.deb
|
|
|
|
- name: Collect + rename assets
|
|
run: |
|
|
set -euo pipefail
|
|
# shellcheck source=scripts/asset-name.sh
|
|
source scripts/asset-name.sh
|
|
collect_cli_assets "${{ matrix.family }}" "${{ matrix.arch }}" "${{ steps.ver.outputs.version }}" dist
|
|
|
|
# Homebrew-core ships a no-JRE jar bundle and depends_on "openjdk" — it
|
|
# cannot use the jlink tarball above (bundled runtime) nor build from
|
|
# source (its sandbox blocks Gradle's Maven downloads). installDist
|
|
# (bin/amy + lib/*.jar, no runtime/) is exactly that bundle. It is pure
|
|
# JVM bytecode, so one platform-independent asset serves every OS; we cut
|
|
# it on the linux leg only. amyImage depends on installDist, so the
|
|
# cli/build/install/amy tree already exists here.
|
|
- name: Package no-JRE jvm bundle for Homebrew (linux leg only)
|
|
if: matrix.family == 'linux'
|
|
run: |
|
|
set -euo pipefail
|
|
VER="${{ steps.ver.outputs.version }}"
|
|
SRC="cli/build/install/amy"
|
|
test -x "$SRC/bin/amy"
|
|
( cd "$SRC" && tar czf "$OLDPWD/dist/amy-${VER}-jvm.tar.gz" bin lib )
|
|
echo "Collected: dist/amy-${VER}-jvm.tar.gz"
|
|
|
|
- name: Enforce CLI size budget (200 MB per asset)
|
|
run: |
|
|
set -euo pipefail
|
|
# The plan at cli/plans/2026-04-21-cli-distribution.md §size-budget
|
|
# targets < 80 MB, but :commons currently leaks Compose + Skiko as
|
|
# transitive deps (~40 MB of unused UI jars). Budget is set to
|
|
# 200 MB until commons is split into core + ui modules — track that
|
|
# as a follow-up. Until then, this gate just catches pathological
|
|
# regressions (e.g. accidental :amethyst dep pulling Android libs).
|
|
fail=0
|
|
for f in dist/*; do
|
|
if [[ -f "$f" ]]; then
|
|
size=$(wc -c < "$f")
|
|
mb=$(( size / 1048576 ))
|
|
if (( size > 209715200 )); then
|
|
echo "::error file=$f::asset is ${mb} MB — exceeds 200 MB amy budget"
|
|
fail=1
|
|
else
|
|
echo "OK: $f — ${mb} MB"
|
|
fi
|
|
fi
|
|
done
|
|
[[ "$fail" == 0 ]]
|
|
|
|
- name: Classify release
|
|
id: classify
|
|
run: |
|
|
TAG="${{ steps.ver.outputs.tag }}"
|
|
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "prerelease=false" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "prerelease=true" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Upload to GH Release (skip on dry-run)
|
|
if: github.event_name != 'workflow_dispatch' || github.event.inputs.dry_run != 'true'
|
|
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
|
with:
|
|
files: dist/*
|
|
tag_name: ${{ steps.ver.outputs.tag }}
|
|
prerelease: ${{ steps.classify.outputs.prerelease }}
|
|
draft: false
|
|
fail_on_unmatched_files: true
|
|
generate_release_notes: false # Android job writes release notes (last-writer-wins race)
|
|
|
|
- name: Dry-run summary
|
|
if: github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true'
|
|
run: |
|
|
echo "### Dry-run: amy ${{ matrix.family }}/${{ matrix.arch }}" >> "$GITHUB_STEP_SUMMARY"
|
|
echo "" >> "$GITHUB_STEP_SUMMARY"
|
|
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
|
ls -la dist >> "$GITHUB_STEP_SUMMARY"
|
|
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Android build + sign + direct-upload. Logic preserved from previous workflow;
|
|
# uses softprops/action-gh-release@v2 instead of deprecated upload-release-asset.
|
|
# ---------------------------------------------------------------------------
|
|
deploy-android:
|
|
if: github.event_name != 'workflow_dispatch' # dry-run skips Android (tag-push only)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 60
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Set up JDK 21
|
|
uses: actions/setup-java@v5
|
|
with:
|
|
distribution: 'temurin'
|
|
java-version: 21
|
|
|
|
- name: Cache gradle
|
|
uses: actions/cache@v5
|
|
with:
|
|
path: |
|
|
~/.gradle/caches
|
|
~/.gradle/wrapper
|
|
key: ${{ runner.os }}-android-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'gradle/libs.versions.toml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-android-gradle-
|
|
|
|
- name: Build AAB
|
|
run: ./gradlew clean bundleRelease --stacktrace
|
|
|
|
- name: Sign AAB (Google Play)
|
|
uses: r0adkll/sign-android-release@349ebdef58775b1e0d8099458af0816dc79b6407 # v1
|
|
with:
|
|
releaseDirectory: amethyst/build/outputs/bundle/playRelease
|
|
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
|
alias: ${{ secrets.KEY_ALIAS }}
|
|
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
|
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
|
env:
|
|
BUILD_TOOLS_VERSION: "36.0.0"
|
|
|
|
- name: Sign AAB (F-Droid)
|
|
uses: r0adkll/sign-android-release@349ebdef58775b1e0d8099458af0816dc79b6407 # v1
|
|
with:
|
|
releaseDirectory: amethyst/build/outputs/bundle/fdroidRelease
|
|
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
|
alias: ${{ secrets.KEY_ALIAS }}
|
|
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
|
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
|
env:
|
|
BUILD_TOOLS_VERSION: "36.0.0"
|
|
|
|
- name: Build APK
|
|
run: ./gradlew assembleRelease --stacktrace
|
|
|
|
- name: Sign APK (Google Play)
|
|
uses: r0adkll/sign-android-release@349ebdef58775b1e0d8099458af0816dc79b6407 # v1
|
|
with:
|
|
releaseDirectory: amethyst/build/outputs/apk/play/release
|
|
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
|
alias: ${{ secrets.KEY_ALIAS }}
|
|
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
|
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
|
env:
|
|
BUILD_TOOLS_VERSION: "36.0.0"
|
|
|
|
- name: Sign APK (F-Droid)
|
|
uses: r0adkll/sign-android-release@349ebdef58775b1e0d8099458af0816dc79b6407 # v1
|
|
with:
|
|
releaseDirectory: amethyst/build/outputs/apk/fdroid/release
|
|
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
|
alias: ${{ secrets.KEY_ALIAS }}
|
|
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
|
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
|
env:
|
|
BUILD_TOOLS_VERSION: "36.0.0"
|
|
|
|
- name: Collect Android assets (rename to canonical scheme)
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p dist
|
|
TAG="${GITHUB_REF_NAME}"
|
|
|
|
# Play APKs (5 variants)
|
|
for variant in universal x86 x86_64 arm64-v8a armeabi-v7a; do
|
|
cp "amethyst/build/outputs/apk/play/release/amethyst-play-${variant}-release-unsigned-signed.apk" \
|
|
"dist/amethyst-googleplay-${variant}-${TAG}.apk"
|
|
done
|
|
|
|
# F-Droid APKs (5 variants)
|
|
for variant in universal x86 x86_64 arm64-v8a armeabi-v7a; do
|
|
cp "amethyst/build/outputs/apk/fdroid/release/amethyst-fdroid-${variant}-release-unsigned-signed.apk" \
|
|
"dist/amethyst-fdroid-${variant}-${TAG}.apk"
|
|
done
|
|
|
|
# AABs
|
|
cp "amethyst/build/outputs/bundle/playRelease/amethyst-play-release.aab" \
|
|
"dist/amethyst-googleplay-${TAG}.aab"
|
|
cp "amethyst/build/outputs/bundle/fdroidRelease/amethyst-fdroid-release.aab" \
|
|
"dist/amethyst-fdroid-${TAG}.aab"
|
|
ls -la dist
|
|
|
|
- name: Classify release
|
|
id: classify
|
|
run: |
|
|
TAG="${GITHUB_REF_NAME}"
|
|
# Stable = exactly vMAJOR.MINOR.PATCH; everything else is prerelease.
|
|
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "prerelease=false" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "prerelease=true" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Upload Android assets to GH Release
|
|
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
|
with:
|
|
files: dist/*
|
|
tag_name: ${{ github.ref_name }}
|
|
prerelease: ${{ steps.classify.outputs.prerelease }}
|
|
draft: false
|
|
fail_on_unmatched_files: true
|
|
generate_release_notes: true
|
|
|
|
- name: Publish Quartz Lib
|
|
run: ./gradlew publishAllPublicationsToMavenCentral --no-configuration-cache
|
|
env:
|
|
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USERNAME }}
|
|
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }}
|
|
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_PRIVATE_KEY }}
|
|
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }}
|