From d43414492237ac608f2f5a08309bf5c39672d284 Mon Sep 17 00:00:00 2001 From: Nik Clayton Date: Thu, 28 Sep 2023 13:50:02 +0200 Subject: [PATCH] ci: Upload orangeRelease to Google Play (internal track) (#134) Start building infrastructure to automatically build and deploy the `orangeRelease` variant to Google Play. The variant needs an automatically incrementing `versionCode`. That is derived from the count of all commits. Change the separator between the version and the build metadata in the `versionName` from `-` to `+` to be consistent with semantic versioning. This is still an experiment, so the workflow is triggered manually and only uploads to the internal track --- .../upload-orange-release-google-play.yml | 86 +++++++++++++++++++ app/build.gradle | 14 ++- app/getGitSha.gradle | 27 ------ app/gitTools.gradle | 47 ++++++++++ 4 files changed, 145 insertions(+), 29 deletions(-) create mode 100644 .github/workflows/upload-orange-release-google-play.yml delete mode 100644 app/getGitSha.gradle create mode 100644 app/gitTools.gradle diff --git a/.github/workflows/upload-orange-release-google-play.yml b/.github/workflows/upload-orange-release-google-play.yml new file mode 100644 index 000000000..e46dd068f --- /dev/null +++ b/.github/workflows/upload-orange-release-google-play.yml @@ -0,0 +1,86 @@ +name: Upload orangeRelease to Google Play + +on: + workflow_dispatch: + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: Gradle Wrapper Validation + uses: gradle/wrapper-validation-action@v1 + + - name: Copy CI gradle.properties + run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties + + - name: Gradle Build Action + uses: gradle/gradle-build-action@v2 + with: + cache-read-only: ${{ github.ref != 'refs/heads/main' }} + + - name: Test + run: ./gradlew app:testOrangeReleaseUnitTest --stacktrace + + - name: Build APK + run: ./gradlew assembleOrangeRelease --stacktrace + + - name: Build AAB + run: ./gradlew :app:bundleOrangeRelease --stacktrace + + - uses: r0adkll/sign-android-release@v1.0.4 + name: Sign app APK + id: sign_app_apk + with: + releaseDirectory: app/build/outputs/apk/orange/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.SIGNING_KEY_ALIAS }} + keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} + env: + BUILD_TOOLS_VERSION: "34.0.0" + + - uses: r0adkll/sign-android-release@v1.0.4 + name: Sign app AAB + id: sign_app_aab + with: + releaseDirectory: app/build/outputs/bundle/orangeRelease + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.SIGNING_KEY_ALIAS }} + keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} + env: + BUILD_TOOLS_VERSION: "34.0.0" + + - name: Upload APK Release Asset + id: upload-release-asset-apk + uses: actions/upload-artifact@v3 + with: + name: app-release.apk + path: ${{steps.sign_app_apk.outputs.signedReleaseFile}} + + - name: Generate whatsnew + id: generate-whatsnew + run: | + mkdir -p googleplay/whatsnew + git log -1 --pretty=format:"%s" > googleplay/whatsnew/whatsnew-en-US + + - name: Upload AAB to Google Play + id: upload-release-asset-aab + uses: r0adkll/upload-google-play@v1.1.2 + with: + serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_KEY }} + packageName: app.pachli.current + releaseFiles: ${{steps.sign_app_aab.outputs.signedReleaseFile}} + track: internal + whatsNewDirectory: googleplay/whatsnew + status: completed + mappingFile: app/build/outputs/mapping/orangeRelease/mapping.txt diff --git a/app/build.gradle b/app/build.gradle index 80e76dcd5..597351b5f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,9 +7,10 @@ plugins { alias(libs.plugins.aboutlibraries) } -apply from: 'getGitSha.gradle' +apply from: 'gitTools.gradle' final def gitSha = ext.getGitSha() +final def gitRevCount = ext.getGitRevCount() // The app name final def APP_NAME = "Pachli" @@ -55,7 +56,7 @@ android { orange { resValue "string", "app_name", APP_NAME + " Current" applicationIdSuffix ".current" - versionNameSuffix "-" + gitSha + versionNameSuffix "+" + gitSha } } @@ -103,7 +104,16 @@ android { } applicationVariants.configureEach { variant -> + tasks.register("printVersionInfo${variant.name.capitalize()}") { + notCompatibleWithConfigurationCache("Should always print the version info") + println variant.versionCode + " " + variant.versionName + } variant.outputs.configureEach { + // Set the "orange" release versionCode to the number of commits on the + // branch, to ensure the versionCode updates on every release. + if (variant.buildType.name == "release" && variant.flavorName == "orange") { + versionCodeOverride = gitRevCount + } outputFileName = "Pachli_${variant.versionName}_${variant.versionCode}_${gitSha}_" + "${variant.flavorName}_${buildType.name}.apk" } diff --git a/app/getGitSha.gradle b/app/getGitSha.gradle deleted file mode 100644 index 53315b2bc..000000000 --- a/app/getGitSha.gradle +++ /dev/null @@ -1,27 +0,0 @@ -import org.gradle.api.provider.ValueSourceParameters -import javax.inject.Inject - -// Must wrap this in a ValueSource in order to get well-defined fail behavior without confusing Gradle on repeat builds. -abstract class GitShaValueSource implements ValueSource { - @Inject abstract ExecOperations getExecOperations() - - @Override String obtain() { - try { - def output = new ByteArrayOutputStream() - - execOperations.exec { - it.commandLine 'git', 'rev-parse', '--short=8', 'HEAD' - it.standardOutput = output - } - return output.toString().trim() - } catch (GradleException ignore) { - // Git executable unavailable, or we are not building in a git repo. Fall through: - } - return "unknown" - } -} - -// Export closure -ext.getGitSha = { - providers.of(GitShaValueSource) {}.get() -} diff --git a/app/gitTools.gradle b/app/gitTools.gradle new file mode 100644 index 000000000..3920b0878 --- /dev/null +++ b/app/gitTools.gradle @@ -0,0 +1,47 @@ +import org.gradle.api.provider.ValueSourceParameters +import javax.inject.Inject + +// Must wrap this in a ValueSource in order to get well-defined fail behavior without confusing Gradle on repeat builds. +abstract class GitShaValueSource implements ValueSource { + @Inject abstract ExecOperations getExecOperations() + + @Override String obtain() { + try { + def output = new ByteArrayOutputStream() + + execOperations.exec { + it.commandLine 'git', 'rev-parse', '--short=8', 'HEAD' + it.standardOutput = output + } + return output.toString().trim() + } catch (GradleException ignore) { + // Git executable unavailable, or we are not building in a git repo. Fall through: + } + return "unknown" + } +} + +/** Returns the number of revisions up to the current commit */ +abstract class GitRevCountSource implements ValueSource { + @Inject abstract ExecOperations getExecOperations() + + @Override Integer obtain() { + try { + def output = new ByteArrayOutputStream() + + execOperations.exec { + it.commandLine 'git', 'rev-list', '--first-parent', '--count', 'HEAD' + it.standardOutput = output + } + + return output.toString().trim().toInteger() + } catch (GradleException ignore) { + // Git executable unavailable, or we are not building in a git repo. Fall through: + } + return -1 + } +} + +ext.getGitSha = { providers.of(GitShaValueSource) {}.get() } + +ext.getGitRevCount = { providers.of(GitRevCountSource) {}.get() }