mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 02:29:55 +02:00
ci: add coordinated release pipeline
This commit is contained in:
141
.github/workflows/android-release.yml
vendored
Normal file
141
.github/workflows/android-release.yml
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
name: Android release package
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: android-release-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build signed Android APK and AAB
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10.0.LTS"
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||
with:
|
||||
gradle-home-cache-strict-match: true
|
||||
|
||||
- name: Install Rust 1.91
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1
|
||||
with:
|
||||
toolchain: "1.91.0"
|
||||
targets: aarch64-linux-android,x86_64-linux-android
|
||||
|
||||
- name: Cache Cargo
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: android-release-cargo-1.91.0-${{ hashFiles('Cargo.lock') }}
|
||||
restore-keys: |
|
||||
android-release-cargo-1.91.0-
|
||||
|
||||
- name: Set up Android SDK
|
||||
uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3
|
||||
with:
|
||||
packages: "platform-tools platforms;android-36 build-tools;36.0.0"
|
||||
|
||||
- name: Set up Android NDK
|
||||
id: setup-ndk
|
||||
uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1
|
||||
with:
|
||||
ndk-version: r27c
|
||||
link-to-sdk: true
|
||||
add-to-path: false
|
||||
|
||||
- name: Export Android NDK location
|
||||
run: |
|
||||
echo "ANDROID_NDK_HOME=${{ steps.setup-ndk.outputs.ndk-path }}" >> "$GITHUB_ENV"
|
||||
echo "ANDROID_NDK_ROOT=${{ steps.setup-ndk.outputs.ndk-path }}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Resolve canonical version
|
||||
id: version
|
||||
run: |
|
||||
packaging/version/resolve-version.sh verify >/dev/null
|
||||
echo "app=$(packaging/version/resolve-version.sh product)" >> "$GITHUB_OUTPUT"
|
||||
echo "code=$(packaging/version/resolve-version.sh android-code)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Validate signing configuration
|
||||
env:
|
||||
KEYSTORE_BASE64: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_BASE64 }}
|
||||
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_PASSWORD }}
|
||||
KEY_ALIAS: ${{ secrets.ANDROID_UPLOAD_KEY_ALIAS }}
|
||||
KEY_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEY_PASSWORD }}
|
||||
UPLOAD_CERT_SHA256: ${{ vars.ANDROID_UPLOAD_CERT_SHA256 }}
|
||||
run: |
|
||||
for name in \
|
||||
KEYSTORE_BASE64 \
|
||||
KEYSTORE_PASSWORD \
|
||||
KEY_ALIAS \
|
||||
KEY_PASSWORD \
|
||||
UPLOAD_CERT_SHA256; do
|
||||
if [ -z "${!name:-}" ]; then
|
||||
echo "Missing Android release signing configuration: $name" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Decode upload keystore
|
||||
env:
|
||||
KEYSTORE_BASE64: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_BASE64 }}
|
||||
run: |
|
||||
keystore="$RUNNER_TEMP/vnidrop-upload.jks"
|
||||
printf '%s' "$KEYSTORE_BASE64" | base64 --decode > "$keystore"
|
||||
chmod 600 "$keystore"
|
||||
test -s "$keystore"
|
||||
echo "VNIDROP_ANDROID_KEYSTORE_PATH=$keystore" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build and verify signed release
|
||||
env:
|
||||
VNIDROP_ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_PASSWORD }}
|
||||
VNIDROP_ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_UPLOAD_KEY_ALIAS }}
|
||||
VNIDROP_ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEY_PASSWORD }}
|
||||
VNIDROP_ANDROID_UPLOAD_CERT_SHA256: ${{ vars.ANDROID_UPLOAD_CERT_SHA256 }}
|
||||
run: packaging/android/build-release.sh
|
||||
|
||||
- name: Remove upload keystore
|
||||
if: always()
|
||||
run: rm -f "$RUNNER_TEMP/vnidrop-upload.jks"
|
||||
|
||||
- name: Upload Android artifacts
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: vnidrop-${{ steps.version.outputs.app }}-android-release
|
||||
path: build/release/android/
|
||||
if-no-files-found: error
|
||||
retention-days: 90
|
||||
compression-level: 0
|
||||
|
||||
- name: Summarize Android package
|
||||
run: |
|
||||
echo "### Android release package" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Version: ${{ steps.version.outputs.app }}" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Version code: ${{ steps.version.outputs.code }}" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Signing: upload certificate verified" >> "$GITHUB_STEP_SUMMARY"
|
||||
84
.github/workflows/apple-release.yml
vendored
84
.github/workflows/apple-release.yml
vendored
@@ -1,20 +1,19 @@
|
||||
name: Apple release (macOS DMG)
|
||||
|
||||
# Builds, signs, notarizes, and publishes the direct-download macOS build:
|
||||
# Builds, signs, notarizes, and uploads the direct-download macOS build:
|
||||
# - a Developer ID–signed, notarized VniDrop-<version>.dmg,
|
||||
# - a Sparkle appcast.xml (both attached to the GitHub Release), and
|
||||
# - an updated Homebrew cask pushed to the sudosylabs/homebrew-vnidrop tap.
|
||||
# - a Sparkle appcast.xml.
|
||||
#
|
||||
# The central release workflow publishes these artifacts and updates Homebrew.
|
||||
#
|
||||
# The App Store / TestFlight build is NOT produced here — that goes through Xcode
|
||||
# Organizer / App Store Connect. This workflow only covers direct distribution.
|
||||
#
|
||||
# Trigger: push the canonical vMAJOR.MINOR.PATCH tag (must point at a commit on
|
||||
# master), or run manually using the version committed in version.properties.
|
||||
# Called by the central tag-release workflow, or run manually to validate the
|
||||
# signed/notarized direct-download artifact.
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -33,8 +32,6 @@ jobs:
|
||||
name: Build & notarize DMG
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 90
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.app }}
|
||||
steps:
|
||||
@@ -82,7 +79,7 @@ jobs:
|
||||
run: brew install xcodegen swiftlint create-dmg
|
||||
|
||||
- name: Install Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
|
||||
- name: Download Sparkle tools
|
||||
# generate_appcast + sign_update ship in the Sparkle release tarball.
|
||||
@@ -151,68 +148,3 @@ jobs:
|
||||
apple/dist/appcast.xml
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
- name: Publish GitHub Release
|
||||
if: github.event_name == 'push' && github.ref_type == 'tag'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tag="$GITHUB_REF_NAME"
|
||||
version="${tag#v}"
|
||||
if gh release view "$tag" >/dev/null 2>&1; then
|
||||
echo "Release $tag already exists; refusing to replace assets" >&2
|
||||
exit 1
|
||||
fi
|
||||
gh release create "$tag" \
|
||||
"apple/dist/VniDrop-${version}.dmg" \
|
||||
"apple/dist/appcast.xml" \
|
||||
--verify-tag \
|
||||
--title "VniDrop $version" \
|
||||
--generate-notes
|
||||
|
||||
update-cask:
|
||||
name: Update Homebrew cask
|
||||
needs: build
|
||||
if: github.event_name == 'push' && github.ref_type == 'tag'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Download DMG artifact
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
name: vnidrop-${{ needs.build.outputs.version }}-macos-dmg
|
||||
path: dist
|
||||
|
||||
- name: Render cask
|
||||
env:
|
||||
VERSION: ${{ needs.build.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sha="$(sha256sum "dist/VniDrop-${VERSION}.dmg" | cut -d' ' -f1)"
|
||||
sed -e "s/^ version \".*\"/ version \"${VERSION}\"/" \
|
||||
-e "s/^ sha256 \".*\"/ sha256 \"${sha}\"/" \
|
||||
packaging/homebrew/vnidrop.rb > /tmp/vnidrop.rb
|
||||
echo "Rendered cask:"; cat /tmp/vnidrop.rb
|
||||
|
||||
- name: Push to tap
|
||||
env:
|
||||
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
||||
VERSION: ${{ needs.build.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git clone "https://x-access-token:${TAP_TOKEN}@github.com/sudosylabs/homebrew-vnidrop.git" tap
|
||||
mkdir -p tap/Casks
|
||||
cp /tmp/vnidrop.rb tap/Casks/vnidrop.rb
|
||||
cd tap
|
||||
git config user.name "vnidrop-release-bot"
|
||||
git config user.email "release-bot@users.noreply.github.com"
|
||||
git add Casks/vnidrop.rb
|
||||
git commit -m "vnidrop ${VERSION}" || { echo "no cask changes"; exit 0; }
|
||||
git push
|
||||
|
||||
75
.github/workflows/linux-packages.yml
vendored
75
.github/workflows/linux-packages.yml
vendored
@@ -22,9 +22,7 @@ on:
|
||||
- "Makefile"
|
||||
- "config.mk"
|
||||
- "make/**"
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -212,74 +210,3 @@ jobs:
|
||||
echo "- Version: ${{ steps.version.outputs.app }}-1" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Architecture: x86_64" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Build environment: Fedora 43" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
publish-release:
|
||||
name: Publish GitHub Release assets
|
||||
if: github.event_name == 'push' && github.ref_type == 'tag'
|
||||
needs:
|
||||
- build-deb
|
||||
- build-rpm
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout release history
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Verify tag is on master
|
||||
run: |
|
||||
if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/master; then
|
||||
echo "Release tags must point to a commit on master" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download Linux artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
pattern: vnidrop-*-linux-*-x64
|
||||
path: build/release/linux
|
||||
merge-multiple: true
|
||||
|
||||
- name: Verify artifacts and checksums
|
||||
run: |
|
||||
cd build/release/linux
|
||||
shopt -s nullglob
|
||||
deb_packages=(*.deb)
|
||||
rpm_packages=(*.rpm)
|
||||
checksum_files=(*.sha256)
|
||||
if (( ${#deb_packages[@]} != 1 || ${#rpm_packages[@]} != 1 || ${#checksum_files[@]} != 2 )); then
|
||||
echo "Expected one DEB, one RPM, and two checksum sidecars" >&2
|
||||
exit 1
|
||||
fi
|
||||
version=${GITHUB_REF_NAME#v}
|
||||
if [[ ${deb_packages[0]} != "vnidrop_${version}-1_amd64.deb" || ${rpm_packages[0]} != "vnidrop-${version}-1.x86_64.rpm" ]]; then
|
||||
echo "Downloaded package names do not match tag $GITHUB_REF_NAME" >&2
|
||||
exit 1
|
||||
fi
|
||||
sha256sum --check "${checksum_files[@]}"
|
||||
sha256sum "${deb_packages[@]}" "${rpm_packages[@]}" > SHA256SUMS
|
||||
rm -- "${checksum_files[@]}"
|
||||
|
||||
- name: Publish GitHub Release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
run: |
|
||||
tag=${GITHUB_REF_NAME}
|
||||
version=${tag#v}
|
||||
if gh release view "$tag" >/dev/null 2>&1; then
|
||||
echo "GitHub Release $tag already exists; refusing to replace its assets" >&2
|
||||
exit 1
|
||||
fi
|
||||
gh release create "$tag" \
|
||||
build/release/linux/*.deb \
|
||||
build/release/linux/*.rpm \
|
||||
build/release/linux/SHA256SUMS \
|
||||
--verify-tag \
|
||||
--title "VniDrop $version" \
|
||||
--generate-notes
|
||||
|
||||
53
.github/workflows/release-checks.yml
vendored
Normal file
53
.github/workflows/release-checks.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: Release pipeline checks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/android-release.yml"
|
||||
- ".github/workflows/apple-release.yml"
|
||||
- ".github/workflows/linux-packages.yml"
|
||||
- ".github/workflows/release-checks.yml"
|
||||
- ".github/workflows/release.yml"
|
||||
- ".github/workflows/windows-store.yml"
|
||||
- "packaging/android/**"
|
||||
- "packaging/release/**"
|
||||
- "packaging/version/**"
|
||||
- "version.properties"
|
||||
- "Makefile"
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- ".github/workflows/android-release.yml"
|
||||
- ".github/workflows/apple-release.yml"
|
||||
- ".github/workflows/linux-packages.yml"
|
||||
- ".github/workflows/release-checks.yml"
|
||||
- ".github/workflows/release.yml"
|
||||
- ".github/workflows/windows-store.yml"
|
||||
- "packaging/android/**"
|
||||
- "packaging/release/**"
|
||||
- "packaging/version/**"
|
||||
- "version.properties"
|
||||
- "Makefile"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: release-checks-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
scripts:
|
||||
name: Validate release scripts
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Run release checks
|
||||
run: make check-release
|
||||
369
.github/workflows/release.yml
vendored
Normal file
369
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: vnidrop-release
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
preflight:
|
||||
name: Verify release tag
|
||||
if: ${{ vars.RELEASE_PIPELINE_ENABLED == 'true' }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.app }}
|
||||
android_code: ${{ steps.version.outputs.android_code }}
|
||||
|
||||
steps:
|
||||
- name: Checkout release history
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Verify canonical beta tag on current master
|
||||
id: version
|
||||
run: |
|
||||
set -euo pipefail
|
||||
packaging/version/resolve-version.sh verify >/dev/null
|
||||
version="$(packaging/version/resolve-version.sh product)"
|
||||
channel="$(packaging/version/resolve-version.sh channel)"
|
||||
master_sha="$(git rev-parse origin/master)"
|
||||
if [ "$GITHUB_SHA" != "$master_sha" ]; then
|
||||
echo "Release tags must point at the current master commit" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$channel" != "beta" ]; then
|
||||
echo "Only beta closed-testing releases are enabled" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "app=$version" >> "$GITHUB_OUTPUT"
|
||||
echo "android_code=$(packaging/version/resolve-version.sh android-code)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Refuse an existing GitHub Release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
||||
echo "GitHub Release $GITHUB_REF_NAME already exists" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
linux:
|
||||
name: Linux packages
|
||||
needs: preflight
|
||||
uses: ./.github/workflows/linux-packages.yml
|
||||
|
||||
windows:
|
||||
name: Windows Store package
|
||||
needs: preflight
|
||||
uses: ./.github/workflows/windows-store.yml
|
||||
|
||||
macos:
|
||||
name: Signed and notarized macOS package
|
||||
needs: preflight
|
||||
uses: ./.github/workflows/apple-release.yml
|
||||
secrets: inherit
|
||||
|
||||
android:
|
||||
name: Signed Android package
|
||||
needs: preflight
|
||||
uses: ./.github/workflows/android-release.yml
|
||||
secrets: inherit
|
||||
|
||||
play-closed-testing:
|
||||
name: Stage Play closed-testing draft
|
||||
needs:
|
||||
- preflight
|
||||
- linux
|
||||
- windows
|
||||
- macos
|
||||
- android
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
environment: play-closed-testing
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Download signed Android artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
name: vnidrop-${{ needs.preflight.outputs.version }}-android-release
|
||||
path: build/release/android
|
||||
|
||||
- name: Validate closed-testing configuration
|
||||
env:
|
||||
WORKLOAD_IDENTITY_PROVIDER: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
|
||||
PLAY_SERVICE_ACCOUNT: ${{ vars.GCP_PLAY_SERVICE_ACCOUNT }}
|
||||
PLAY_PACKAGE_NAME: ${{ vars.PLAY_PACKAGE_NAME }}
|
||||
PLAY_CLOSED_TRACK: ${{ vars.PLAY_CLOSED_TRACK }}
|
||||
PLAY_APP_SIGNING_CERT_SHA256: ${{ vars.PLAY_APP_SIGNING_CERT_SHA256 }}
|
||||
run: |
|
||||
for name in \
|
||||
WORKLOAD_IDENTITY_PROVIDER \
|
||||
PLAY_SERVICE_ACCOUNT \
|
||||
PLAY_PACKAGE_NAME \
|
||||
PLAY_CLOSED_TRACK \
|
||||
PLAY_APP_SIGNING_CERT_SHA256; do
|
||||
if [ -z "${!name:-}" ]; then
|
||||
echo "Missing Play closed-testing configuration: $name" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
case "${PLAY_CLOSED_TRACK,,}" in
|
||||
production|*:production)
|
||||
echo "Production Play tracks are forbidden" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [ "$PLAY_PACKAGE_NAME" != "com.vnidrop.app" ]; then
|
||||
echo "Unexpected Play package name: $PLAY_PACKAGE_NAME" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Authenticate to Google with GitHub OIDC
|
||||
id: google-auth
|
||||
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3
|
||||
with:
|
||||
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
|
||||
service_account: ${{ vars.GCP_PLAY_SERVICE_ACCOUNT }}
|
||||
token_format: access_token
|
||||
access_token_scopes: https://www.googleapis.com/auth/androidpublisher
|
||||
|
||||
- name: Stage AAB and download Play-signed APK
|
||||
env:
|
||||
GOOGLE_PLAY_ACCESS_TOKEN: ${{ steps.google-auth.outputs.access_token }}
|
||||
PLAY_PACKAGE_NAME: ${{ vars.PLAY_PACKAGE_NAME }}
|
||||
PLAY_CLOSED_TRACK: ${{ vars.PLAY_CLOSED_TRACK }}
|
||||
PLAY_APP_SIGNING_CERT_SHA256: ${{ vars.PLAY_APP_SIGNING_CERT_SHA256 }}
|
||||
VERSION: ${{ needs.preflight.outputs.version }}
|
||||
VERSION_CODE: ${{ needs.preflight.outputs.android_code }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
shopt -s nullglob
|
||||
bundles=(build/release/android/*.aab)
|
||||
if [ "${#bundles[@]}" -ne 1 ]; then
|
||||
echo "Expected exactly one signed AAB" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p build/release/play
|
||||
python3 packaging/android/publish_play.py \
|
||||
--bundle "${bundles[0]}" \
|
||||
--package-name "$PLAY_PACKAGE_NAME" \
|
||||
--track "$PLAY_CLOSED_TRACK" \
|
||||
--version-code "$VERSION_CODE" \
|
||||
--release-name "$VERSION" \
|
||||
--expected-app-certificate "$PLAY_APP_SIGNING_CERT_SHA256" \
|
||||
--apk-output "build/release/play/VniDrop-${VERSION}-${VERSION_CODE}-play-universal.apk" \
|
||||
--metadata-output build/release/play/play-release.json
|
||||
|
||||
- name: Set up Android SDK verification tools
|
||||
uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3
|
||||
with:
|
||||
packages: "platform-tools build-tools;36.0.0"
|
||||
|
||||
- name: Verify Play-signed universal APK
|
||||
env:
|
||||
EXPECTED_CERT_SHA256: ${{ vars.PLAY_APP_SIGNING_CERT_SHA256 }}
|
||||
VERSION: ${{ needs.preflight.outputs.version }}
|
||||
VERSION_CODE: ${{ needs.preflight.outputs.android_code }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
apk="build/release/play/VniDrop-${VERSION}-${VERSION_CODE}-play-universal.apk"
|
||||
apksigner_path="$(
|
||||
find "$ANDROID_SDK_ROOT/build-tools" -type f -name apksigner -perm -111 |
|
||||
sort -r |
|
||||
head -1
|
||||
)"
|
||||
apkanalyzer_path="$(
|
||||
find "$ANDROID_SDK_ROOT/cmdline-tools" -type f -name apkanalyzer -perm -111 |
|
||||
sort -r |
|
||||
head -1
|
||||
)"
|
||||
if [ -z "$apksigner_path" ] || [ -z "$apkanalyzer_path" ]; then
|
||||
echo "Android SDK verification tools were not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
"$apksigner_path" verify --verbose --print-certs "$apk" \
|
||||
> build/release/play/apksigner-report.txt
|
||||
actual="$(
|
||||
awk -F': ' '/Signer #1 certificate SHA-256 digest:/ {print $2; exit}' \
|
||||
build/release/play/apksigner-report.txt |
|
||||
tr -d '[:space:]:' |
|
||||
tr '[:upper:]' '[:lower:]'
|
||||
)"
|
||||
expected="$(
|
||||
printf '%s' "$EXPECTED_CERT_SHA256" |
|
||||
tr -d '[:space:]:' |
|
||||
tr '[:upper:]' '[:lower:]'
|
||||
)"
|
||||
if [ -z "$actual" ] || [ "$actual" != "$expected" ]; then
|
||||
echo "Play APK signing certificate mismatch" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$("$apkanalyzer_path" manifest application-id "$apk")" != "com.vnidrop.app" ]; then
|
||||
echo "Play APK package name mismatch" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$("$apkanalyzer_path" manifest version-name "$apk")" != "$VERSION" ]; then
|
||||
echo "Play APK version name mismatch" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$("$apkanalyzer_path" manifest version-code "$apk")" != "$VERSION_CODE" ]; then
|
||||
echo "Play APK version code mismatch" >&2
|
||||
exit 1
|
||||
fi
|
||||
rm build/release/play/apksigner-report.txt
|
||||
(
|
||||
cd build/release/play
|
||||
sha256sum \
|
||||
"VniDrop-${VERSION}-${VERSION_CODE}-play-universal.apk" \
|
||||
play-release.json \
|
||||
> SHA256SUMS
|
||||
)
|
||||
|
||||
- name: Upload Play-signed APK
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: vnidrop-${{ needs.preflight.outputs.version }}-android-play
|
||||
path: build/release/play/
|
||||
if-no-files-found: error
|
||||
retention-days: 90
|
||||
compression-level: 0
|
||||
|
||||
publish-github:
|
||||
name: Publish coordinated GitHub Release
|
||||
needs:
|
||||
- preflight
|
||||
- linux
|
||||
- windows
|
||||
- macos
|
||||
- play-closed-testing
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Download Debian package
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
name: vnidrop-${{ needs.preflight.outputs.version }}-linux-deb-x64
|
||||
path: build/release/downloads/deb
|
||||
|
||||
- name: Download RPM package
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
name: vnidrop-${{ needs.preflight.outputs.version }}-linux-rpm-x64
|
||||
path: build/release/downloads/rpm
|
||||
|
||||
- name: Download macOS package
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
name: vnidrop-${{ needs.preflight.outputs.version }}-macos-dmg
|
||||
path: build/release/downloads/macos
|
||||
|
||||
- name: Download Windows Store package
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
name: vnidrop-${{ needs.preflight.outputs.version }}-windows-store-x64
|
||||
path: build/release/downloads/windows
|
||||
|
||||
- name: Download Play-signed APK
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
name: vnidrop-${{ needs.preflight.outputs.version }}-android-play
|
||||
path: build/release/downloads/play
|
||||
|
||||
- name: Verify and assemble public release assets
|
||||
run: packaging/release/assemble-release.sh
|
||||
|
||||
- name: Attest release provenance
|
||||
uses: actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 # v4
|
||||
with:
|
||||
subject-path: build/release/final/*
|
||||
|
||||
- name: Create GitHub Release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release create "$GITHUB_REF_NAME" \
|
||||
build/release/final/* \
|
||||
--repo "$GITHUB_REPOSITORY" \
|
||||
--verify-tag \
|
||||
--title "VniDrop ${{ needs.preflight.outputs.version }}" \
|
||||
--generate-notes
|
||||
|
||||
update-homebrew:
|
||||
name: Update Homebrew cask
|
||||
needs:
|
||||
- preflight
|
||||
- macos
|
||||
- publish-github
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Download macOS package
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
name: vnidrop-${{ needs.preflight.outputs.version }}-macos-dmg
|
||||
path: dist
|
||||
|
||||
- name: Render Homebrew cask
|
||||
env:
|
||||
VERSION: ${{ needs.preflight.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sha="$(sha256sum "dist/VniDrop-${VERSION}.dmg" | cut -d' ' -f1)"
|
||||
sed -e "s/^ version \".*\"/ version \"${VERSION}\"/" \
|
||||
-e "s/^ sha256 \".*\"/ sha256 \"${sha}\"/" \
|
||||
packaging/homebrew/vnidrop.rb > /tmp/vnidrop.rb
|
||||
|
||||
- name: Push cask to tap
|
||||
env:
|
||||
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
||||
VERSION: ${{ needs.preflight.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git clone \
|
||||
"https://x-access-token:${TAP_TOKEN}@github.com/sudosylabs/homebrew-vnidrop.git" \
|
||||
tap
|
||||
mkdir -p tap/Casks
|
||||
cp /tmp/vnidrop.rb tap/Casks/vnidrop.rb
|
||||
cd tap
|
||||
git config user.name "vnidrop-release-bot"
|
||||
git config user.email "release-bot@users.noreply.github.com"
|
||||
git add Casks/vnidrop.rb
|
||||
git commit -m "vnidrop ${VERSION}" || {
|
||||
echo "Homebrew cask already matches ${VERSION}"
|
||||
exit 0
|
||||
}
|
||||
git push
|
||||
4
.github/workflows/windows-store.yml
vendored
4
.github/workflows/windows-store.yml
vendored
@@ -19,9 +19,7 @@ on:
|
||||
- "gradle/**"
|
||||
- "gradlew"
|
||||
- "gradlew.bat"
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
||||
Reference in New Issue
Block a user