Files
aliasvault/.github/workflows/release.yml
2026-07-24 21:24:39 +02:00

270 lines
11 KiB
YAML

name: Release
# Browser extension and mobile app release builds. Docker images are built by the separate
# release-docker.yml workflow, which can target a self-hosted runner.
on:
release:
types: [published]
workflow_dispatch:
inputs:
version_tag:
description: 'Release version (e.g., 0.26.2). Auto-detected from release/* branch name if empty.'
required: false
type: string
build_browser_extensions:
description: 'Build browser extensions'
required: false
default: true
type: boolean
build_mobile_apps:
description: 'Build mobile apps'
required: false
default: true
type: boolean
jobs:
# Guard job to prevent releases from main branch
valid-release:
if: github.event_name == 'release'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Check tag target
run: |
BRANCHES=$(git branch -r --contains $GITHUB_SHA)
echo "Tag is contained in:"
echo "$BRANCHES"
if ! echo "$BRANCHES" | grep -q "origin/release/"; then
echo "❌ Releases must come from a release/* branch, please recreate the release from a release branch"
exit 1
fi
echo "✅ Tag is on a release branch"
# Detect version from input, branch name, or release tag
detect-version:
if: always() && (github.event_name != 'release' || needs.valid-release.result == 'success')
needs: [valid-release]
runs-on: ubuntu-latest
outputs:
version: ${{ steps.detect.outputs.version }}
browser_extension_version_matches: ${{ steps.check-app-versions.outputs.browser_extension_matches }}
mobile_app_version_matches: ${{ steps.check-app-versions.outputs.mobile_app_matches }}
chrome_extension_asset_exists: ${{ steps.check-release-assets.outputs.chrome_extension_asset_exists }}
firefox_extension_assets_exist: ${{ steps.check-release-assets.outputs.firefox_extension_assets_exist }}
edge_extension_asset_exists: ${{ steps.check-release-assets.outputs.edge_extension_asset_exists }}
android_apk_asset_exists: ${{ steps.check-release-assets.outputs.android_apk_asset_exists }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
sparse-checkout: |
.github/actions/detect-release-version
apps/browser-extension/package.json
apps/mobile-app/app.json
- name: Detect version
id: detect
uses: ./.github/actions/detect-release-version
with:
version_tag: ${{ inputs.version_tag }}
- name: Check app versions match release tag
id: check-app-versions
run: |
VERSION="${{ steps.detect.outputs.version }}"
if [ -z "$VERSION" ]; then
# No version tag, allow builds (workflow_dispatch without version)
echo "browser_extension_matches=true" >> $GITHUB_OUTPUT
echo "mobile_app_matches=true" >> $GITHUB_OUTPUT
echo "No release version specified, all builds allowed"
exit 0
fi
# Check browser extension version
BROWSER_EXT_VERSION=$(node -p "require('./apps/browser-extension/package.json').version")
echo "Browser extension version: $BROWSER_EXT_VERSION"
echo "Release version: $VERSION"
if [ "$BROWSER_EXT_VERSION" = "$VERSION" ]; then
echo "✅ Browser extension version matches release tag"
echo "browser_extension_matches=true" >> $GITHUB_OUTPUT
else
echo "⚠️ Browser extension version ($BROWSER_EXT_VERSION) does not match release tag ($VERSION)"
echo "Browser extensions will NOT be uploaded to release"
echo "browser_extension_matches=false" >> $GITHUB_OUTPUT
fi
# Check mobile app version
MOBILE_APP_VERSION=$(node -p "require('./apps/mobile-app/app.json').expo.version")
echo "Mobile app version: $MOBILE_APP_VERSION"
if [ "$MOBILE_APP_VERSION" = "$VERSION" ]; then
echo "✅ Mobile app version matches release tag"
echo "mobile_app_matches=true" >> $GITHUB_OUTPUT
else
echo "⚠️ Mobile app version ($MOBILE_APP_VERSION) does not match release tag ($VERSION)"
echo "Android APK will NOT be uploaded to release"
echo "mobile_app_matches=false" >> $GITHUB_OUTPUT
fi
- name: Check if release assets already exist
id: check-release-assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.detect.outputs.version }}"
if [ -z "$VERSION" ]; then
echo "chrome_extension_asset_exists=false" >> $GITHUB_OUTPUT
echo "firefox_extension_assets_exist=false" >> $GITHUB_OUTPUT
echo "edge_extension_asset_exists=false" >> $GITHUB_OUTPUT
echo "android_apk_asset_exists=false" >> $GITHUB_OUTPUT
echo "No version specified, asset existence checks skipped"
exit 0
fi
# List assets on existing release (draft or published). Empty if release does not exist.
ASSETS=$(gh release view "$VERSION" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets[].name' 2>/dev/null || true)
if [ -z "$ASSETS" ]; then
echo "No release found at tag $VERSION (or release has no assets)"
fi
has_asset() {
echo "$ASSETS" | grep -Fxq "$1"
}
# Chrome
if has_asset "aliasvault-${VERSION}-chrome.zip"; then
echo "✅ Chrome extension asset exists on release $VERSION"
echo "chrome_extension_asset_exists=true" >> $GITHUB_OUTPUT
else
echo "❌ Chrome extension asset missing"
echo "chrome_extension_asset_exists=false" >> $GITHUB_OUTPUT
fi
# Firefox (must have both the extension zip and the sources zip)
if has_asset "aliasvault-${VERSION}-firefox.zip" && has_asset "aliasvault-${VERSION}-browser-extension-sources.zip"; then
echo "✅ Firefox extension + sources assets exist on release $VERSION"
echo "firefox_extension_assets_exist=true" >> $GITHUB_OUTPUT
else
echo "❌ Firefox extension and/or sources asset missing"
echo "firefox_extension_assets_exist=false" >> $GITHUB_OUTPUT
fi
# Edge
if has_asset "aliasvault-${VERSION}-edge.zip"; then
echo "✅ Edge extension asset exists on release $VERSION"
echo "edge_extension_asset_exists=true" >> $GITHUB_OUTPUT
else
echo "❌ Edge extension asset missing"
echo "edge_extension_asset_exists=false" >> $GITHUB_OUTPUT
fi
# Android APK
if has_asset "aliasvault-${VERSION}-android.apk"; then
echo "✅ Android APK asset exists on release $VERSION"
echo "android_apk_asset_exists=true" >> $GITHUB_OUTPUT
else
echo "❌ Android APK asset missing"
echo "android_apk_asset_exists=false" >> $GITHUB_OUTPUT
fi
upload-install-script:
needs: [valid-release, detect-version]
if: always() && (github.event_name != 'release' || needs.valid-release.result == 'success')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Upload install.sh to release
if: github.event_name == 'release'
uses: softprops/action-gh-release@v3
with:
files: install.sh
token: ${{ secrets.GITHUB_TOKEN }}
build-chrome-extension:
needs: [valid-release, detect-version]
# Skip on release events when the asset already exists (prep run already attached it).
# On workflow_dispatch the build always runs when the flag is set, and re-uploads with --clobber.
if: always() && (github.event_name != 'release' || needs.valid-release.result == 'success') && (github.event_name == 'release' || inputs.build_browser_extensions) && needs.detect-version.outputs.browser_extension_version_matches == 'true' && (github.event_name != 'release' || needs.detect-version.outputs.chrome_extension_asset_exists != 'true')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Build Chrome Extension
uses: ./.github/actions/build-browser-extension
with:
browser: chrome
release_tag: ${{ needs.detect-version.outputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-firefox-extension:
needs: [valid-release, detect-version]
if: always() && (github.event_name != 'release' || needs.valid-release.result == 'success') && (github.event_name == 'release' || inputs.build_browser_extensions) && needs.detect-version.outputs.browser_extension_version_matches == 'true' && (github.event_name != 'release' || needs.detect-version.outputs.firefox_extension_assets_exist != 'true')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Build Firefox Extension
uses: ./.github/actions/build-browser-extension
with:
browser: firefox
release_tag: ${{ needs.detect-version.outputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-edge-extension:
needs: [valid-release, detect-version]
if: always() && (github.event_name != 'release' || needs.valid-release.result == 'success') && (github.event_name == 'release' || inputs.build_browser_extensions) && needs.detect-version.outputs.browser_extension_version_matches == 'true' && (github.event_name != 'release' || needs.detect-version.outputs.edge_extension_asset_exists != 'true')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Build Edge Extension
uses: ./.github/actions/build-browser-extension
with:
browser: edge
release_tag: ${{ needs.detect-version.outputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-android-release:
needs: [valid-release, detect-version]
if: always() && (github.event_name != 'release' || needs.valid-release.result == 'success') && (github.event_name == 'release' || inputs.build_mobile_apps) && needs.detect-version.outputs.mobile_app_version_matches == 'true' && (github.event_name != 'release' || needs.detect-version.outputs.android_apk_asset_exists != 'true')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Build Android App
uses: ./.github/actions/build-android-app
with:
signed: true
release_tag: ${{ needs.detect-version.outputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}