name: Make Release on: workflow_call: inputs: base_version: description: 'The base version for the release (e.g., 2.3.0)' required: true type: string tag_name: description: 'The tag that triggered the release' required: true type: string commit_sha: description: 'The commit SHA to build and tag' required: false type: string channel: description: 'The channel to create a release for or promote to' required: true type: string secrets: GSERVICES: required: true KEYSTORE: required: true KEYSTORE_FILENAME: required: true KEYSTORE_PROPERTIES: required: true DATADOG_APPLICATION_ID: required: true DATADOG_CLIENT_TOKEN: required: true GOOGLE_MAPS_API_KEY: required: true GOOGLE_PLAY_JSON_KEY: required: true GRADLE_ENCRYPTION_KEY: required: true GRADLE_CACHE_URL: required: false GRADLE_CACHE_USERNAME: required: false GRADLE_CACHE_PASSWORD: required: false INTERNAL_BUILDS_HOST: required: false INTERNAL_BUILDS_HOST_PAT: required: false concurrency: group: ${{ github.workflow }}-${{ inputs.tag_name }} cancel-in-progress: true permissions: contents: write pull-requests: read id-token: write attestations: write jobs: prepare-build-info: runs-on: ubuntu-latest outputs: APP_VERSION_NAME: ${{ steps.get_version_name.outputs.APP_VERSION_NAME }} APP_VERSION_CODE: ${{ steps.calculate_version_code.outputs.versionCode }} env: GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} steps: - name: Checkout code uses: actions/checkout@v6 with: ref: ${{ inputs.tag_name }} fetch-depth: 0 submodules: 'recursive' - name: Determine Version Name from Tag id: get_version_name run: echo "APP_VERSION_NAME=$(echo ${{ inputs.tag_name }} | sed 's/-.*//' | sed 's/v//')" >> $GITHUB_OUTPUT - name: Extract VERSION_CODE_OFFSET from config.properties id: get_version_code_offset run: | OFFSET=$(grep '^VERSION_CODE_OFFSET=' config.properties | cut -d'=' -f2) echo "VERSION_CODE_OFFSET=$OFFSET" >> $GITHUB_OUTPUT - name: Calculate Version Code from Git Commit Count id: calculate_version_code run: | COMMIT_COUNT=$(git rev-list --count HEAD) OFFSET=${{ steps.get_version_code_offset.outputs.VERSION_CODE_OFFSET }} VERSION_CODE=$((COMMIT_COUNT + OFFSET)) echo "versionCode=$VERSION_CODE" >> $GITHUB_OUTPUT shell: bash release-google: runs-on: ubuntu-latest needs: [prepare-build-info] environment: Release env: GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} steps: - name: Checkout code uses: actions/checkout@v6 with: ref: ${{ inputs.tag_name }} fetch-depth: 0 submodules: 'recursive' - name: Set up JDK 17 uses: actions/setup-java@v5 with: java-version: '17' distribution: 'jetbrains' - name: Setup Gradle uses: gradle/actions/setup-gradle@v5 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} build-scan-publish: true build-scan-terms-of-use-url: 'https://gradle.com/terms-of-service' build-scan-terms-of-use-agree: 'yes' - name: Load secrets env: GSERVICES: ${{ secrets.GSERVICES }} KEYSTORE: ${{ secrets.KEYSTORE }} KEYSTORE_FILENAME: ${{ secrets.KEYSTORE_FILENAME }} KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_PROPERTIES }} DATADOG_APPLICATION_ID: ${{ secrets.DATADOG_APPLICATION_ID }} DATADOG_CLIENT_TOKEN: ${{ secrets.DATADOG_CLIENT_TOKEN }} GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }} GOOGLE_PLAY_JSON_KEY: ${{ secrets.GOOGLE_PLAY_JSON_KEY }} run: | rm -f ./app/google-services.json echo $GSERVICES > ./app/google-services.json echo $KEYSTORE | base64 -di > ./app/$KEYSTORE_FILENAME echo "$KEYSTORE_PROPERTIES" > ./keystore.properties echo "datadogApplicationId=$DATADOG_APPLICATION_ID" >> ./secrets.properties echo "datadogClientToken=$DATADOG_CLIENT_TOKEN" >> ./secrets.properties echo "MAPS_API_KEY=$GOOGLE_MAPS_API_KEY" >> ./secrets.properties echo "$GOOGLE_PLAY_JSON_KEY" > ./fastlane/play-store-credentials.json - name: Setup Fastlane uses: ruby/setup-ruby@v1 with: ruby-version: '3.4.9' bundler-cache: true - name: Build and Deploy Google Play to Internal Track with Fastlane env: VERSION_NAME: ${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }} VERSION_CODE: ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }} run: bundle exec fastlane internal - name: List outputs run: ls -R app/build/outputs/ - name: Upload Google AAB artifact if: always() uses: actions/upload-artifact@v7 with: name: google-aab path: app/build/outputs/bundle/googleRelease/app-google-release.aab retention-days: 1 - name: Upload Google APK artifact if: always() uses: actions/upload-artifact@v7 with: name: google-apk path: app/build/outputs/apk/google/release/*.apk retention-days: 1 - name: Attest Google AAB provenance if: success() uses: actions/attest-build-provenance@v4 with: subject-path: app/build/outputs/bundle/googleRelease/app-google-release.aab - name: Attest Google APK provenance if: success() uses: actions/attest-build-provenance@v4 with: subject-path: app/build/outputs/apk/google/release/*.apk release-fdroid: runs-on: ubuntu-latest needs: [prepare-build-info] environment: Release env: GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} steps: - name: Checkout code uses: actions/checkout@v6 with: ref: ${{ inputs.tag_name }} fetch-depth: 0 submodules: 'recursive' - name: Set up JDK 17 uses: actions/setup-java@v5 with: java-version: '17' distribution: 'jetbrains' - name: Setup Gradle uses: gradle/actions/setup-gradle@v5 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} build-scan-publish: true build-scan-terms-of-use-url: 'https://gradle.com/terms-of-service' build-scan-terms-of-use-agree: 'yes' - name: Load secrets env: KEYSTORE: ${{ secrets.KEYSTORE }} KEYSTORE_FILENAME: ${{ secrets.KEYSTORE_FILENAME }} KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_PROPERTIES }} run: | echo $KEYSTORE | base64 -di > ./app/$KEYSTORE_FILENAME echo "$KEYSTORE_PROPERTIES" > ./keystore.properties - name: Setup Fastlane uses: ruby/setup-ruby@v1 with: ruby-version: '3.4.9' bundler-cache: true - name: Build F-Droid with Fastlane env: VERSION_NAME: ${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }} VERSION_CODE: ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }} run: bundle exec fastlane fdroid_build - name: List outputs run: ls -R app/build/outputs/ - name: Upload F-Droid APK artifact if: always() uses: actions/upload-artifact@v7 with: name: fdroid-apk path: app/build/outputs/apk/fdroid/release/*.apk retention-days: 1 - name: Attest F-Droid APK provenance if: success() uses: actions/attest-build-provenance@v4 with: subject-path: app/build/outputs/apk/fdroid/release/*.apk release-desktop: runs-on: ${{ matrix.os }} needs: [prepare-build-info] environment: Release strategy: fail-fast: false matrix: os: [macos-latest, windows-latest, ubuntu-22.04, ubuntu-22.04-arm] env: GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} steps: - name: Checkout code uses: actions/checkout@v6 with: ref: ${{ inputs.tag_name }} fetch-depth: 0 submodules: 'recursive' - name: Set up JDK 17 uses: actions/setup-java@v5 with: java-version: '17' distribution: 'jetbrains' - name: Setup Gradle uses: gradle/actions/setup-gradle@v5 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} build-scan-publish: true build-scan-terms-of-use-url: 'https://gradle.com/terms-of-service' build-scan-terms-of-use-agree: 'yes' - name: Install dependencies for AppImage if: runner.os == 'Linux' run: sudo apt-get update && sudo apt-get install -y libfuse2 - name: Package Native Distributions env: ORG_GRADLE_PROJECT_appVersionName: ${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }} APPIMAGE_EXTRACT_AND_RUN: 1 run: ./gradlew :desktop:packageReleaseDistributionForCurrentOS --no-daemon - name: List Desktop Binaries if: runner.os == 'Linux' run: ls -R desktop/build/compose/binaries/main-release - name: Upload Desktop Artifacts if: always() uses: actions/upload-artifact@v7 with: name: desktop-${{ runner.os }}-${{ runner.arch }} path: | desktop/build/compose/binaries/main-release/*/*.dmg desktop/build/compose/binaries/main-release/*/*.msi desktop/build/compose/binaries/main-release/*/*.exe desktop/build/compose/binaries/main-release/*/*.deb desktop/build/compose/binaries/main-release/*/*.rpm desktop/build/compose/binaries/main-release/*/*.AppImage retention-days: 1 if-no-files-found: ignore github-release: runs-on: ubuntu-latest needs: [prepare-build-info, release-google, release-fdroid, release-desktop] env: INTERNAL_BUILDS_HOST: ${{ secrets.INTERNAL_BUILDS_HOST }} permissions: contents: write id-token: write attestations: write steps: - name: Checkout code uses: actions/checkout@v6 with: ref: ${{ inputs.tag_name }} - name: Download all artifacts uses: actions/download-artifact@v8 with: path: ./artifacts - name: Create or Update GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ inputs.tag_name }} target_commitish: ${{ inputs.commit_sha || github.sha }} name: ${{ inputs.tag_name }} (${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}) generate_release_notes: true files: ./artifacts/**/* draft: true prerelease: true - name: Create or Update internal GitHub Release continue-on-error: true if: ${{ env.INTERNAL_BUILDS_HOST != '' }} uses: softprops/action-gh-release@v2 with: repository: ${{ secrets.INTERNAL_BUILDS_HOST }} token: ${{ secrets.INTERNAL_BUILDS_HOST_PAT }} tag_name: ${{ inputs.tag_name }} name: ${{ inputs.tag_name }} (${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}) generate_release_notes: false files: ./artifacts/**/* draft: false prerelease: true