Skip to content

Update serena

Update serena #74

Workflow file for this run

name: Build and Release
on:
push:
branches: [main]
paths-ignore:
- "pubspec.yaml"
workflow_dispatch:
env:
PUB_SUMMARY_ONLY: true
KOTLIN_VERSION: "2.1.0"
jobs:
quality-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Setup Flutter from submodule
run: |
git submodule update --init --recursive flutter
chmod +x flutter/bin/*
echo "$PWD/flutter/bin" >> $GITHUB_PATH
flutter/bin/flutter --version
flutter/bin/flutter config --no-analytics
- name: Get dependencies
run: flutter pub get
- name: Verify formatting
run: dart format --set-exit-if-changed lib test
- name: Analyze code
run: dart analyze --no-fatal-warnings lib
- name: Run tests
run: flutter test
version-bump:
needs: quality-checks
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.bump.outputs.version }}
build_number: ${{ steps.bump.outputs.build_number }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: false
token: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Git
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Bump versions and generate changelog
id: bump
run: |
CURRENT_VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //' | sed 's/+.*//')
CURRENT_BUILD=$(grep '^version:' pubspec.yaml | sed 's/.*+//')
CURRENT_MSIX=$(grep 'msix_version:' pubspec.yaml | sed 's/.*msix_version: *//')
IFS='.' read -ra V <<< "$CURRENT_VERSION"
NEW_VERSION="${V[0]}.${V[1]}.$((${V[2]} + 1))"
NEW_BUILD=$((CURRENT_BUILD + 1))
CHANGELOG_NUMBER=$((NEW_BUILD * 10 + 3))
IFS='.' read -ra M <<< "$CURRENT_MSIX"
NEW_MSIX="${M[0]}.${M[1]}.$((${M[2]} + 1)).${M[3]}"
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "build_number=$NEW_BUILD" >> $GITHUB_OUTPUT
sed -i "s/^version: .*/version: $NEW_VERSION+$NEW_BUILD/" pubspec.yaml
sed -i "s/msix_version: .*/msix_version: $NEW_MSIX/" pubspec.yaml
CHANGELOG_FILE="fastlane/metadata/android/en-US/changelogs/$CHANGELOG_NUMBER.txt"
mkdir -p "$(dirname "$CHANGELOG_FILE")"
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -n "$LAST_TAG" ]; then
git --no-pager log --pretty=format:'%s' "$LAST_TAG"..HEAD
else
git --no-pager log --pretty=format:'%s'
fi | sort -u \
| grep -v "^Merge " \
| grep -v "^Release " \
| grep -v "^Bump " \
| grep -v "\[skip ci\]" \
| head -10 \
| sed 's/^/• /' > "$CHANGELOG_FILE"
[ -s "$CHANGELOG_FILE" ] || echo "• Bug fixes and improvements" > "$CHANGELOG_FILE"
mkdir -p fastlane/metadata/en-AU
cp "$CHANGELOG_FILE" fastlane/metadata/en-AU/release_notes.txt
mkdir -p assets/changelogs
cp "$CHANGELOG_FILE" "assets/changelogs/$(date +%s).txt"
- name: Commit and push version bump
run: |
git add pubspec.yaml fastlane/metadata assets/changelogs
git commit -m "Release ${{ steps.bump.outputs.version }} [skip ci]"
git push origin main
- name: Create and push tag
run: |
git tag "${{ steps.bump.outputs.version }}"
git push origin "${{ steps.bump.outputs.version }}"
build-android:
needs: version-bump
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: "zulu"
java-version: "17"
- name: Create brandon user directory structure (match F-Droid)
run: |
sudo mkdir -p /home/brandon
sudo chown $USER -R /home/brandon
- name: Move project to F-Droid location
run: |
cd ..
mv ${{ github.event.repository.name }} /home/brandon/fitbook
- name: Setup Flutter from submodule and get dependencies
working-directory: /home/brandon/fitbook
run: |
git submodule update --init --recursive flutter
echo "/home/brandon/fitbook/flutter/bin" >> $GITHUB_PATH
export PUB_CACHE=$(pwd)/.pub-cache
echo "PUB_CACHE=$(pwd)/.pub-cache" >> $GITHUB_ENV
flutter/bin/flutter config --no-analytics
flutter/bin/flutter pub get
- name: Strip non-deterministic build IDs from jni native library
working-directory: /home/brandon/fitbook
run: |
sed -i -e 's/-Wl,/-Wl,--build-id=none,/' \
.pub-cache/hosted/pub.dev/jni-*/src/CMakeLists.txt
- name: Decode Android keystore
working-directory: /home/brandon/fitbook
run: echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
- name: Build android
working-directory: /home/brandon/fitbook
run: |
echo "storePassword=${{ secrets.ANDROID_STORE_PASSWORD }}" > android/key.properties
echo "keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}" >> android/key.properties
echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" >> android/key.properties
echo "storeFile=keystore.jks" >> android/key.properties
# Use --split-per-abi WITH --target-platform to match F-Droid exactly.
# Without --split-per-abi: produces a universal APK with all ABI native
# libs and versionCode override = base*10+3 (wrong for x86_64 which needs +1).
# Without --target-platform: NativeAssetsManifest.json lists all 3 archs.
flutter build apk --release --split-per-abi --target-platform android-x64
flutter build apk --release --split-per-abi --target-platform android-arm64
flutter build apk --release --split-per-abi --target-platform android-arm
flutter build apk --release
mv build/app/outputs/flutter-apk/app-release.apk build/app/outputs/flutter-apk/fitbook.apk
flutter build appbundle
mkdir -p "${GITHUB_WORKSPACE}/build"
mv build/* "${GITHUB_WORKSPACE}/build"
- name: Upload Android artifacts
uses: actions/upload-artifact@v4
with:
name: android-builds
path: |
build/app/outputs/flutter-apk/app-*-release.apk
build/app/outputs/flutter-apk/fitbook.apk
build/app/outputs/bundle/release/app-release.aab
verify-reproducibility:
needs: [version-bump, build-android]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: "zulu"
java-version: "17"
- name: Create brandon user directory structure (match F-Droid)
run: |
sudo mkdir -p /home/brandon
sudo chown $USER -R /home/brandon
- name: Move project to F-Droid location
run: |
cd ..
mv ${{ github.event.repository.name }} /home/brandon/fitbook
- name: Setup Flutter from submodule and get dependencies
working-directory: /home/brandon/fitbook
run: |
git submodule update --init --recursive flutter
echo "/home/brandon/fitbook/flutter/bin" >> $GITHUB_PATH
export PUB_CACHE=$(pwd)/.pub-cache
echo "PUB_CACHE=$(pwd)/.pub-cache" >> $GITHUB_ENV
flutter/bin/flutter config --no-analytics
flutter/bin/flutter pub get
- name: Strip non-deterministic build IDs from jni native library
working-directory: /home/brandon/fitbook
run: |
sed -i -e 's/-Wl,/-Wl,--build-id=none,/' \
.pub-cache/hosted/pub.dev/jni-*/src/CMakeLists.txt
- name: Decode Android keystore
working-directory: /home/brandon/fitbook
run: echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
- name: Rebuild android independently
working-directory: /home/brandon/fitbook
run: |
echo "storePassword=${{ secrets.ANDROID_STORE_PASSWORD }}" > android/key.properties
echo "keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}" >> android/key.properties
echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" >> android/key.properties
echo "storeFile=keystore.jks" >> android/key.properties
# Same invocations as build-android, so the only difference between
# the two builds is the runner/checkout instance itself.
flutter build apk --release --split-per-abi --target-platform android-x64
flutter build apk --release --split-per-abi --target-platform android-arm64
flutter build apk --release --split-per-abi --target-platform android-arm
- name: Download reference build-android artifacts
uses: actions/download-artifact@v4
with:
name: android-builds
path: reference-build
- name: Compare rebuilt APKs against build-android output
working-directory: /home/brandon/fitbook
run: |
status=0
for apk in build/app/outputs/flutter-apk/app-*-release.apk; do
name=$(basename "$apk")
reference="${GITHUB_WORKSPACE}/reference-build/flutter-apk/$name"
if [ ! -f "$reference" ]; then
echo "::error::No reference artifact found for $name"
status=1
continue
fi
rebuilt_sha=$(sha256sum "$apk" | cut -d' ' -f1)
reference_sha=$(sha256sum "$reference" | cut -d' ' -f1)
if [ "$rebuilt_sha" != "$reference_sha" ]; then
echo "::error::$name is not reproducible: build-android=$reference_sha rebuild=$rebuilt_sha"
status=1
else
echo "$name reproducible: $rebuilt_sha"
fi
done
exit $status
build-linux:
needs: version-bump
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Flutter from submodule
run: |
git submodule update --init --recursive flutter
chmod +x flutter/bin/*
echo "${{ github.workspace }}/flutter/bin" >> $GITHUB_PATH
flutter/bin/flutter config --no-analytics
- name: Get Flutter dependencies
run: flutter pub get
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
- name: Build Linux
run: flutter build linux
- name: Create Linux zip
run: |
cd build/linux/x64/release/bundle
zip -r fitbook-linux.zip .
- name: Upload Linux artifacts
uses: actions/upload-artifact@v4
with:
name: linux-builds
path: build/linux/x64/release/bundle/fitbook-linux.zip
build-windows:
needs: version-bump
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Flutter from submodule
run: |
git submodule update --init --recursive flutter
chmod +x flutter/bin/*
echo "${{ github.workspace }}\flutter\bin" >> $env:GITHUB_PATH
flutter\bin\flutter config --no-analytics
- name: Get Flutter dependencies
run: flutter pub get
- name: Build Windows
run: flutter build windows
- name: Create Windows zip
run: Compress-Archive -Path ./build/windows/x64/runner/Release/* -DestinationPath ./fitbook-windows.zip
- name: Upload Windows artifacts
uses: actions/upload-artifact@v4
with:
name: windows-builds
path: fitbook-windows.zip
build-and-deploy-web:
needs: version-bump
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
permissions:
contents: write
pages: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Flutter from submodule
run: |
git submodule update --init --recursive flutter
chmod +x flutter/bin/*
echo "${{ github.workspace }}/flutter/bin" >> $GITHUB_PATH
flutter/bin/flutter config --no-analytics
- name: Get Flutter dependencies
run: flutter pub get
- name: Enable web support
run: flutter config --enable-web
- name: Build Flutter web
run: flutter build web --release --base-href /${{ github.event.repository.name }}/
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload to GitHub Pages
uses: actions/upload-pages-artifact@v3
with:
path: ./build/web
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
create-github-release:
needs:
[
version-bump,
build-android,
verify-reproducibility,
build-linux,
build-windows,
]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ needs.version-bump.outputs.version }}
name: ${{ needs.version-bump.outputs.version }}
body_path: fastlane/metadata/en-AU/release_notes.txt
files: |
android-builds/flutter-apk/app-*-release.apk
android-builds/flutter-apk/fitbook.apk
android-builds/bundle/release/app-release.aab
linux-builds/fitbook-linux.zip
windows-builds/fitbook-windows.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
deploy-windows-store:
needs: [version-bump, build-windows]
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Flutter from submodule
run: |
git submodule update --init --recursive flutter
echo "${{ github.workspace }}\flutter\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
flutter\bin\flutter config --no-analytics
- name: Get Flutter dependencies
run: flutter pub get
- name: Build MSIX
run: flutter pub run msix:create
- name: Setup .NET 9.0
uses: actions/setup-dotnet@v4
with:
dotnet-version: "9.0.x"
- name: Setup Microsoft Store CLI
uses: microsoft/setup-msstore-cli@v1
- name: Configure Microsoft Store CLI
run: msstore reconfigure --tenantId ${{ secrets.AZURE_TENANT_ID }} --clientId ${{ secrets.AZURE_CLIENT_ID }} --clientSecret ${{ secrets.AZURE_CLIENT_SECRET }} --sellerId ${{ secrets.MSSTORE_SELLER_ID }}
- name: Publish to Microsoft Store
run: msstore publish --inputDirectory build/windows/x64/runner/Release --appId ${{ secrets.PRODUCT_ID }} --packageRolloutPercentage 100 || true
virustotal:
needs: [create-github-release, version-bump]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download Android artifacts
uses: actions/download-artifact@v4
with:
name: android-builds
path: android-builds
- name: VirusTotal Scan
id: vt
uses: crazy-max/ghaction-virustotal@v4
with:
vt_api_key: ${{ secrets.VT_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
files: |
android-builds/flutter-apk/app-arm64-v8a-release.apk
android-builds/flutter-apk/app-armeabi-v7a-release.apk
android-builds/flutter-apk/app-x86_64-release.apk
- name: Append VirusTotal links to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ needs.version-bump.outputs.version }}
ANALYSIS: ${{ steps.vt.outputs.analysis }}
run: |
VT_SECTION=$'\n\n<details>\n<summary>VirusTotal Analysis</summary>\n\n'
IFS=',' read -ra ENTRIES <<< "$ANALYSIS"
for entry in "${ENTRIES[@]}"; do
filename=$(basename "${entry%%=*}")
url="${entry#*=}"
VT_SECTION+="- [${filename}](${url})"$'\n'
done
VT_SECTION+=$'\n</details>'
CURRENT_BODY=$(gh release view "$VERSION" --json body -q .body)
gh release edit "$VERSION" --notes "${CURRENT_BODY}${VT_SECTION}"