fix(repro): add --internal flag to fix-pg-map-id #102
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| permissions: | |
| contents: write | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| # REPRODUCIBILITY: Set deterministic locale and timezone for consistent builds | |
| env: | |
| TZ: UTC | |
| LANG: en_US.UTF-8 | |
| LC_ALL: en_US.UTF-8 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| # REPRODUCIBILITY: Pin Java 17 to match F-Droid build server | |
| # Different Java versions can produce different R8/DEX output | |
| - name: Setup Java 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| - name: Setup Android SDK | |
| uses: android-actions/setup-android@v3 | |
| # REPRODUCIBILITY: Install FRESH SDK components to match F-Droid exactly | |
| # GitHub may have outdated cached versions - remove and reinstall to get latest revision | |
| # F-Droid downloads platform-34-ext7_r03.zip - we need the same | |
| - name: Install pinned SDK components | |
| run: | | |
| # Remove pre-installed platform to ensure we get latest revision | |
| rm -rf $ANDROID_HOME/platforms/android-34 | |
| sdkmanager "platforms;android-34" "build-tools;34.0.0" | |
| echo "BUILD_TOOLS_VERSION=34.0.0" >> $GITHUB_ENV | |
| # Show what revision was installed | |
| ls -la $ANDROID_HOME/platforms/android-34/ | |
| - name: Add Android SDK tools to PATH | |
| run: | | |
| # Use build-tools 34.0.0 for F-Droid reproducibility (v35+ breaks apksigcopier) | |
| BUILD_TOOLS_DIR="$ANDROID_HOME/build-tools/34.0.0" | |
| echo "$BUILD_TOOLS_DIR" >> $GITHUB_PATH | |
| echo "BUILD_TOOLS_DIR=$BUILD_TOOLS_DIR" >> $GITHUB_ENV | |
| echo "📦 Build tools: $BUILD_TOOLS_DIR" | |
| echo "📦 Java: $(java -version 2>&1 | head -1)" | |
| ls -la $BUILD_TOOLS_DIR/zipalign $BUILD_TOOLS_DIR/apksigner 2>/dev/null || echo "Tools check" | |
| - name: Cache Gradle packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | |
| restore-keys: | | |
| ${{ runner.os }}-gradle- | |
| - name: Make gradlew executable | |
| run: chmod +x gradlew | |
| - name: Extract version info | |
| run: | | |
| TAG_NAME=${GITHUB_REF#refs/tags/} | |
| echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV | |
| # Parse semantic version: vMAJOR.MINOR.PATCH -> code = MAJOR*10000 + MINOR*100 + PATCH | |
| VERSION=${TAG_NAME#v} | |
| MAJOR=$(echo $VERSION | cut -d. -f1) | |
| MINOR=$(echo $VERSION | cut -d. -f2) | |
| PATCH=$(echo $VERSION | cut -d. -f3 | sed 's/[^0-9].*//') | |
| VERSION_CODE=$((MAJOR * 10000 + MINOR * 100 + PATCH)) | |
| echo "VERSION=$VERSION" >> $GITHUB_ENV | |
| echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV | |
| echo "📦 Version: $VERSION (code: $VERSION_CODE)" | |
| - name: Verify tag matches build.gradle version | |
| run: | | |
| TAG_VERSION=${GITHUB_REF_NAME#v} | |
| # Extract VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH from build.gradle | |
| GRADLE_MAJOR=$(grep "VERSION_MAJOR" build.gradle | head -1 | sed 's/.*= *//' | tr -d ' ') | |
| GRADLE_MINOR=$(grep "VERSION_MINOR" build.gradle | head -1 | sed 's/.*= *//' | tr -d ' ') | |
| GRADLE_PATCH=$(grep "VERSION_PATCH" build.gradle | head -1 | sed 's/.*= *//' | tr -d ' ') | |
| GRADLE_VERSION="${GRADLE_MAJOR}.${GRADLE_MINOR}.${GRADLE_PATCH}" | |
| echo "🏷️ Git Tag Version: $TAG_VERSION" | |
| echo "📦 Gradle Version: $GRADLE_VERSION" | |
| if [ "$TAG_VERSION" != "$GRADLE_VERSION" ]; then | |
| echo "::error::VERSION MISMATCH! Git tag ($TAG_VERSION) does not match build.gradle ($GRADLE_VERSION)" | |
| echo "Please update VERSION_MAJOR/MINOR/PATCH in build.gradle to match the tag." | |
| exit 1 | |
| fi | |
| echo "✅ Version match confirmed!" | |
| # Decode keystore for later signing (do NOT set RELEASE_KEYSTORE env var here | |
| # to ensure build.gradle builds unsigned APK) | |
| - name: Decode signing keystore | |
| run: echo "${{ secrets.SIGNING_KEY }}" | base64 -d > ${{ github.workspace }}/release.keystore | |
| - name: Print R8 Version | |
| run: ./gradlew printR8Version | |
| - name: Clone reproducible-apk-tools | |
| run: git clone https://github.com/obfusk/reproducible-apk-tools.git | |
| # REPRODUCIBILITY: Build EACH ABI separately to match F-Droid | |
| # F-Droid builds each ABI as a separate job with sed to modify build.gradle | |
| # Building all ABIs together causes different AAPT2 resource compilation | |
| - name: Build APKs per-ABI (matching F-Droid) | |
| run: | | |
| # Create final output directory (separate from build/outputs to survive clean) | |
| mkdir -p final_apks | |
| for ABI in armeabi-v7a arm64-v8a x86_64; do | |
| echo "=========================================" | |
| echo "🔨 Building $ABI APK..." | |
| echo "=========================================" | |
| # Reset build.gradle to original state | |
| git checkout build.gradle | |
| # Apply same sed command as F-Droid prebuild | |
| # This changes: include 'armeabi-v7a', 'arm64-v8a', 'x86_64' | |
| # To: include '$ABI' | |
| sed -i -e "s/include 'armeabi-v7a'.*/include '$ABI'/" build.gradle | |
| # Verify the change | |
| echo "Modified splits.abi.include:" | |
| grep "include '" build.gradle | grep -v "//" | |
| # Clean and build this single ABI | |
| ./gradlew clean assembleRelease --stacktrace --no-build-cache | |
| # Find the output APK | |
| BUILT_APK=$(find build/outputs/apk/release -name "*.apk" -type f | head -1) | |
| if [ -n "$BUILT_APK" ]; then | |
| # Extract version from filename | |
| VERSION_NAME=$(echo "$BUILT_APK" | grep -oP 'v\d+\.\d+\.\d+' || echo "v${{ env.VERSION }}") | |
| FINAL_NAME="CleverKeys-${VERSION_NAME}-${ABI}.apk" | |
| FINAL_PATH="final_apks/$FINAL_NAME" | |
| # Apply F-Droid postbuild steps to this APK | |
| echo "📦 Applying reproducibility fixes to $FINAL_NAME..." | |
| # POSTBUILD STEP 1: Remove non-deterministic META-INF files | |
| # Use reproducible-apk-tools instead of inline python (preserves file permissions) | |
| python3 ${{ github.workspace }}/reproducible-apk-tools/inplace-fix.py \ | |
| rm-files "$BUILT_APK" 'META-INF/*' | |
| # POSTBUILD STEP 2: Fix pg-map-id and zipalign | |
| # Use --internal to handle zipalign internally (avoids external tool compatibility) | |
| python3 ${{ github.workspace }}/reproducible-apk-tools/inplace-fix.py \ | |
| --page-size 16 --internal fix-pg-map-id "$BUILT_APK" 0000000 | |
| # Move to final directory (survives clean) | |
| mv "$BUILT_APK" "$FINAL_PATH" | |
| echo "✅ Built: $FINAL_NAME → saved to $FINAL_PATH" | |
| else | |
| echo "❌ ERROR: No APK found for $ABI" | |
| exit 1 | |
| fi | |
| echo "" | |
| done | |
| # Restore original build.gradle | |
| git checkout build.gradle | |
| # Copy all APKs to expected location for release step | |
| mkdir -p build/outputs/apk/release | |
| cp final_apks/*.apk build/outputs/apk/release/ | |
| echo "=========================================" | |
| echo "📦 All APKs built:" | |
| ls -la build/outputs/apk/release/*.apk | |
| echo "=========================================" | |
| # Sign the APKs with our release key after fixes | |
| # inplace-fix.py already did zipalign with -P 16 | |
| - name: Sign release APKs | |
| run: | | |
| cd build/outputs/apk/release | |
| for apk in *.apk; do | |
| echo "Signing $apk..." | |
| # Sign with apksigner (APK already zipaligned by inplace-fix.py) | |
| $BUILD_TOOLS_DIR/apksigner sign \ | |
| --ks ${{ github.workspace }}/release.keystore \ | |
| --ks-pass pass:${{ secrets.KEY_STORE_PASSWORD }} \ | |
| --ks-key-alias ${{ secrets.ALIAS }} \ | |
| --key-pass pass:${{ secrets.KEY_PASSWORD }} \ | |
| "$apk" | |
| # Verify signature | |
| $BUILD_TOOLS_DIR/apksigner verify "$apk" && echo "✅ $apk verified" | |
| done | |
| - name: List release APKs | |
| run: | | |
| cd build/outputs/apk/release | |
| echo "=== Release APKs ===" | |
| ls -la CleverKeys-*.apk || echo "No APKs found!" | |
| echo "" | |
| echo "📦 Version: ${{ env.VERSION }} (code: ${{ env.VERSION_CODE }})" | |
| - name: Generate changelog | |
| run: | | |
| # Extract changelog from recent commits | |
| echo "## What's New in ${{ env.TAG_NAME }}" > CHANGELOG.md | |
| echo "" >> CHANGELOG.md | |
| # Get commits since last tag | |
| LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | |
| if [ -n "$LAST_TAG" ]; then | |
| git log $LAST_TAG..HEAD --pretty=format:"- %s (%h)" --grep="feat\|fix\|perf\|refactor" >> CHANGELOG.md | |
| else | |
| echo "- Initial release with neural swipe typing" >> CHANGELOG.md | |
| echo "- Complete ONNX transformer integration" >> CHANGELOG.md | |
| echo "- Hardware acceleration support" >> CHANGELOG.md | |
| echo "- Privacy-first local processing" >> CHANGELOG.md | |
| fi | |
| echo "" >> CHANGELOG.md | |
| echo "## Build Information" >> CHANGELOG.md | |
| # Plain text format for F-Droid UpdateCheckData regex parsing | |
| echo "Version: ${{ env.VERSION }}" >> CHANGELOG.md | |
| echo "VersionCode: ${{ env.VERSION_CODE }}" >> CHANGELOG.md | |
| echo "" >> CHANGELOG.md | |
| echo "- **Package**: tribixbite.cleverkeys" >> CHANGELOG.md | |
| echo "- **Min Android**: 5.0 (API 21)" >> CHANGELOG.md | |
| echo "- **Target Android**: 14 (API 34)" >> CHANGELOG.md | |
| echo "" >> CHANGELOG.md | |
| echo "## Install Options" >> CHANGELOG.md | |
| echo "| Source | Link |" >> CHANGELOG.md | |
| echo "|--------|------|" >> CHANGELOG.md | |
| echo "| GitHub | Download APK below for your device |" >> CHANGELOG.md | |
| echo "| F-Droid | Coming soon (auto-update enabled) |" >> CHANGELOG.md | |
| echo "" >> CHANGELOG.md | |
| echo "## APK Variants" >> CHANGELOG.md | |
| echo "| ABI | Devices | VersionCode |" >> CHANGELOG.md | |
| echo "|-----|---------|-------------|" >> CHANGELOG.md | |
| echo "| arm64 | Most modern phones (2016+) | $((${{ env.VERSION_CODE }} * 10 + 2)) |" >> CHANGELOG.md | |
| echo "| armv7 | Older 32-bit devices | $((${{ env.VERSION_CODE }} * 10 + 1)) |" >> CHANGELOG.md | |
| echo "| x86_64 | Emulators, Chromebooks | $((${{ env.VERSION_CODE }} * 10 + 3)) |" >> CHANGELOG.md | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: build/outputs/apk/release/CleverKeys-*.apk | |
| name: CleverKeys ${{ env.TAG_NAME }} | |
| tag_name: ${{ env.TAG_NAME }} | |
| body_path: CHANGELOG.md | |
| draft: false | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload to artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: cleverkeys-release-${{ env.TAG_NAME }} | |
| path: | | |
| build/outputs/apk/release/CleverKeys-*.apk | |
| CHANGELOG.md | |
| retention-days: 365 | |
| - name: Release summary | |
| run: | | |
| echo "## Release ${{ env.TAG_NAME }} Published!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Version Info" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Version**: ${{ env.VERSION }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Base VersionCode**: ${{ env.VERSION_CODE }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Download" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Release Page](https://github.com/${{ github.repository }}/releases/tag/${{ env.TAG_NAME }})" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### APK Variants" >> $GITHUB_STEP_SUMMARY | |
| echo "| ABI | VersionCode | Use For |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-----|-------------|---------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| arm64 | $((${{ env.VERSION_CODE }} * 10 + 2)) | Most modern phones |" >> $GITHUB_STEP_SUMMARY | |
| echo "| armv7 | $((${{ env.VERSION_CODE }} * 10 + 1)) | Older 32-bit devices |" >> $GITHUB_STEP_SUMMARY | |
| echo "| x86_64 | $((${{ env.VERSION_CODE }} * 10 + 3)) | Emulators, Chromebooks |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Distribution" >> $GITHUB_STEP_SUMMARY | |
| echo "- GitHub Release: ✅ Available now" >> $GITHUB_STEP_SUMMARY | |
| echo "- F-Droid: Auto-update will pick up this version" >> $GITHUB_STEP_SUMMARY | |
| notify: | |
| runs-on: ubuntu-latest | |
| needs: release | |
| if: success() | |
| steps: | |
| - name: Release notification | |
| run: | | |
| echo "CleverKeys ${{ github.ref_name }} has been successfully released!" | |
| echo "Users can now download the latest APK with neural swipe typing." |