Skip to content

chore: update test dependencies and normalize app version parsing #20

chore: update test dependencies and normalize app version parsing

chore: update test dependencies and normalize app version parsing #20

Workflow file for this run

name: GitHub Release (gms + foss)
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
tag:
description: "Tag to build/release"
required: true
type: string
permissions:
contents: write
pull-requests: write
jobs:
# ── Resolve tag and version metadata (fast, shared by all jobs) ──
meta:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.rel.outputs.tag }}
sha: ${{ steps.rel.outputs.sha }}
ref: ${{ steps.ref.outputs.ref }}
app_version: ${{ steps.ver.outputs.app_version }}
build_number: ${{ steps.ver.outputs.build_number }}
full_version: ${{ steps.ver.outputs.full_version }}
prerelease: ${{ steps.pre.outputs.prerelease }}
steps:
- name: Resolve ref (tag)
id: ref
shell: bash
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "ref=refs/tags/${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
else
echo "ref=${{ github.ref }}" >> "$GITHUB_OUTPUT"
fi
- uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ steps.ref.outputs.ref }}
- name: Resolve release metadata
id: rel
shell: bash
run: |
set -euo pipefail
TAG=""
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG="${{ inputs.tag }}"
else
TAG="${GITHUB_REF_NAME}"
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Read version from tag
id: ver
shell: bash
run: |
TAG="${{ steps.rel.outputs.tag }}"
SEMVER="${TAG#v}"
APP_VERSION="${SEMVER%%-*}"
BUILD_NUMBER="$(git rev-list --count HEAD)"
echo "app_version=$APP_VERSION" >> "$GITHUB_OUTPUT"
echo "build_number=$BUILD_NUMBER" >> "$GITHUB_OUTPUT"
echo "full_version=$SEMVER" >> "$GITHUB_OUTPUT"
- name: Determine prerelease flag
id: pre
shell: bash
run: |
set -euo pipefail
TAG="${{ steps.rel.outputs.tag }}"
if [[ "$TAG" == *-* ]]; then
echo "prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "prerelease=false" >> "$GITHUB_OUTPUT"
fi
# ── GMS APK build ──
build-gms:
needs: meta
runs-on: ubuntu-latest
env:
JAVA_VERSION: "21"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.meta.outputs.ref }}
- name: Setup Flutter (from .flutter-version)
uses: subosito/flutter-action@v2
with:
flutter-version-file: .flutter-version
channel: stable
cache: true
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: ${{ env.JAVA_VERSION }}
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Write android/local.properties
shell: bash
run: |
set -e
SDK_DIR="${ANDROID_SDK_ROOT:-$ANDROID_HOME}"
FLUTTER_SDK="${FLUTTER_HOME:-$(dirname "$(dirname "$(readlink -f "$(which flutter)")")")}"
{
echo "sdk.dir=${SDK_DIR}"
echo "flutter.sdk=${FLUTTER_SDK}"
} > android/local.properties
- name: Make gradlew executable
run: chmod +x android/gradlew
- name: Decode keystore
env:
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
run: echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > android/dawarich-upload.jks
- name: Create keystore.properties
run: |
cat > android/keystore.properties <<'EOF'
storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}
keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}
storeFile=../dawarich-upload.jks
EOF
- name: Flutter pub get
run: flutter pub get
- name: Run build_runner
run: dart run build_runner build --delete-conflicting-outputs
- name: Build APK (GMS)
shell: bash
run: |
set -euo pipefail
flutter build apk --release --flavor gms \
--build-name=${{ needs.meta.outputs.app_version }} \
--build-number=${{ needs.meta.outputs.build_number }}
- name: Upload GMS artifact
uses: actions/upload-artifact@v4
with:
name: gms-apk
path: build/app/outputs/flutter-apk/app-gms-release.apk
retention-days: 5
# ── FOSS APK build (parallel to GMS) ──
build-foss:
needs: meta
runs-on: ubuntu-latest
env:
JAVA_VERSION: "21"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.meta.outputs.ref }}
- name: Setup Flutter (from .flutter-version)
uses: subosito/flutter-action@v2
with:
flutter-version-file: .flutter-version
channel: stable
cache: true
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: ${{ env.JAVA_VERSION }}
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Write android/local.properties
shell: bash
run: |
set -e
SDK_DIR="${ANDROID_SDK_ROOT:-$ANDROID_HOME}"
FLUTTER_SDK="${FLUTTER_HOME:-$(dirname "$(dirname "$(readlink -f "$(which flutter)")")")}"
{
echo "sdk.dir=${SDK_DIR}"
echo "flutter.sdk=${FLUTTER_SDK}"
} > android/local.properties
- name: Make gradlew executable
run: chmod +x android/gradlew
- name: Decode keystore
env:
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
run: echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > android/dawarich-upload.jks
- name: Create keystore.properties
run: |
cat > android/keystore.properties <<'EOF'
storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}
keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}
storeFile=../dawarich-upload.jks
EOF
- name: Switch pubspec to FOSS
shell: bash
run: |
set -euo pipefail
cp pubspec-foss.yaml pubspec.yaml
cp pubspec-foss.lock pubspec.lock
- name: Flutter pub get
run: flutter pub get
- name: Run build_runner
run: dart run build_runner build --delete-conflicting-outputs
- name: FOSS proprietary dependency check
shell: bash
run: |
chmod +x tools/check_proprietary_deps.sh
tools/check_proprietary_deps.sh fossReleaseRuntimeClasspath
- name: Build APK (FOSS)
shell: bash
run: |
set -euo pipefail
flutter build apk --release --flavor foss \
--build-name=${{ needs.meta.outputs.app_version }} \
--build-number=${{ needs.meta.outputs.build_number }}
- name: Upload FOSS artifact
uses: actions/upload-artifact@v4
with:
name: foss-apk
path: build/app/outputs/flutter-apk/app-foss-release.apk
retention-days: 5
# ── Create GitHub Release (waits for both builds) ──
release:
needs: [meta, build-gms, build-foss]
runs-on: ubuntu-latest
steps:
- name: Download GMS artifact
uses: actions/download-artifact@v4
with:
name: gms-apk
path: dist
- name: Download FOSS artifact
uses: actions/download-artifact@v4
with:
name: foss-apk
path: dist
- name: Rename artifacts
shell: bash
run: |
set -euo pipefail
VER="${{ needs.meta.outputs.app_version }}"
BN="${{ needs.meta.outputs.build_number }}"
mv dist/app-gms-release.apk "dist/dawarich-${VER}+${BN}-gms.apk"
mv dist/app-foss-release.apk "dist/dawarich-${VER}+${BN}-foss.apk"
ls -la dist
- name: Create GitHub Release and upload assets
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.meta.outputs.tag }}
target_commitish: ${{ needs.meta.outputs.sha }}
files: dist/*
generate_release_notes: false
fail_on_unmatched_files: true
prerelease: ${{ needs.meta.outputs.prerelease }}
# ── F-Droid changelog (non-blocking, runs after meta, independent of release) ──
changelog:
needs: meta
runs-on: ubuntu-latest
# This job must never block the release
continue-on-error: true
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.meta.outputs.ref }}
- name: Generate and push F-Droid changelog via PR
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
BUILD_NUMBER="${{ needs.meta.outputs.build_number }}"
TAG="${{ needs.meta.outputs.tag }}"
CHANGELOG_DIR="fastlane/metadata/android/en-US/changelogs"
CHANGELOG="${CHANGELOG_DIR}/${BUILD_NUMBER}.txt"
WHATSNEW="distribution/whatsnew/whatsnew-en-US"
BRANCH="chore/fdroid-changelog-${BUILD_NUMBER}"
# Generate the changelog file
mkdir -p "$CHANGELOG_DIR"
if [ -f "$WHATSNEW" ]; then
cp "$WHATSNEW" "$CHANGELOG"
else
echo "See https://github.com/sunstep/dawarich-android/releases/tag/${TAG}" \
> "$CHANGELOG"
fi
# Skip if the file already exists on main
git fetch origin main
if git show "origin/main:${CHANGELOG}" &>/dev/null; then
echo "Changelog ${BUILD_NUMBER}.txt already exists on main, skipping."
exit 0
fi
# Save to temp before switching branches
cp "$CHANGELOG" /tmp/changelog.txt
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Create a new branch from main, add the file, force-push, open PR
# Force-push handles retries where the branch already exists from a previous failed run
git checkout -b "$BRANCH" origin/main
mkdir -p "$(dirname "$CHANGELOG")"
cp /tmp/changelog.txt "$CHANGELOG"
git add "$CHANGELOG"
git commit -m "chore: add F-Droid changelog for build ${BUILD_NUMBER} [skip ci]"
git push --force origin "$BRANCH"
# Only create a PR if one doesn't already exist for this branch
EXISTING_PR=$(gh pr list --head "$BRANCH" --base main --json number --jq '.[0].number // empty')
if [ -n "$EXISTING_PR" ]; then
echo "PR #${EXISTING_PR} already exists for branch ${BRANCH}, skipping creation."
PR_NUMBER="$EXISTING_PR"
else
PR_URL=$(gh pr create \
--base main \
--head "$BRANCH" \
--title "chore: F-Droid changelog for ${TAG}" \
--body "Auto-generated F-Droid changelog for build ${BUILD_NUMBER} (${TAG})." \
--label "automated")
PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$')
echo "Created PR #${PR_NUMBER}"
fi
# Merge the PR: try auto-merge first, fall back to immediate merge if PR is already clean
if ! gh pr merge "$PR_NUMBER" --auto --squash 2>/dev/null; then
echo "Auto-merge unavailable (PR may already be clean). Merging immediately."
gh pr merge "$PR_NUMBER" --squash
fi