Skip to content

fix: stabilize WebView operations and UI components #32

fix: stabilize WebView operations and UI components

fix: stabilize WebView operations and UI components #32

Workflow file for this run

name: Release
on:
push:
branches: [ "main" ]
tags:
- 'v*'
workflow_dispatch:
inputs:
tag_name:
description: 'Tag name (e.g. v1.0.8)'
required: false
default: ''
permissions:
contents: write
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
release:
name: Build & Publish Release
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Compute and Increment Version
id: version_step
run: |
RUN_NUM="${{ github.run_number }}"
CALC_CODE=$((100 + RUN_NUM))
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
TAG="${{ github.ref_name }}"
VER="${TAG#v}"
elif [ -n "${{ inputs.tag_name }}" ]; then
TAG="${{ inputs.tag_name }}"
VER="${TAG#v}"
else
VER="1.0.${CALC_CODE}"
TAG="v${VER}"
fi
echo "APP_VERSION_CODE=${CALC_CODE}" >> $GITHUB_ENV
echo "APP_VERSION_NAME=${VER}" >> $GITHUB_ENV
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "version=${VER}" >> $GITHUB_OUTPUT
echo "version_code=${CALC_CODE}" >> $GITHUB_OUTPUT
echo "Target Tag: ${TAG} (Version Name: ${VER}, Version Code: ${CALC_CODE})"
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'microsoft'
- name: Setup Gradle Build Cache
uses: gradle/actions/setup-gradle@v4
with:
cache-read-only: false
- name: Setup Android Release Keystore
run: |
if [ -n "${{ secrets.RELEASE_KEYSTORE_BASE64 }}" ]; then
echo "Decoding permanent release.keystore from GitHub Secret..."
echo "${{ secrets.RELEASE_KEYSTORE_BASE64 }}" | base64 -d > release.keystore
elif [ -f release.keystore ]; then
echo "Using existing release.keystore from workspace..."
else
echo "Decoding permanent deterministic release.keystore to guarantee seamless in-place updates..."
echo "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" | base64 -d > release.keystore
fi
if [ ! -f debug.keystore ]; then
cp release.keystore debug.keystore || true
fi
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build Release APK
run: ./gradlew assembleRelease --build-cache --parallel -Dorg.gradle.jvmargs="-Xmx4096m -XX:+UseParallelGC" --stacktrace
- name: Prepare Release Assets
id: prepare_asset
run: |
TAG="${{ steps.version_step.outputs.tag }}"
VER="${{ steps.version_step.outputs.version }}"
mkdir -p release-assets
APK_NAME="Feather-Browser-${TAG}.apk"
FOUND_APK=$(find app/build/outputs/apk/release -name "*.apk" 2>/dev/null | head -n 1)
if [ -z "$FOUND_APK" ]; then
FOUND_APK=$(find . -name "*release*.apk" 2>/dev/null | head -n 1)
fi
if [ -n "$FOUND_APK" ] && [ -f "$FOUND_APK" ]; then
cp "$FOUND_APK" "release-assets/${APK_NAME}"
elif [ -f app/build/outputs/apk/release/app-release.apk ]; then
cp app/build/outputs/apk/release/app-release.apk "release-assets/${APK_NAME}"
else
echo "Error: Release APK not found!"
find . -name "*.apk"
exit 1
fi
cd release-assets
sha256sum "${APK_NAME}" > "${APK_NAME}.sha256"
echo "apk_name=${APK_NAME}" >> $GITHUB_OUTPUT
- name: Upload APK as Workflow Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.prepare_asset.outputs.apk_name }}
path: release-assets/*
retention-days: 90
- name: Publish GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ steps.version_step.outputs.tag }}"
VER="${{ steps.version_step.outputs.version }}"
echo "Publishing release for ${TAG}..."
# Delete existing release & tag on GitHub if re-running or updating
gh release delete "${TAG}" --yes --cleanup-tag 2>/dev/null || true
# Create release and upload all assets with GitHub CLI
gh release create "${TAG}" release-assets/* \
--title "Feather Browser ${TAG}" \
--generate-notes \
--latest \
--target "${{ github.sha }}"