Version dev builds 0.1.0-dev-<timestamp>, and hand it to the container

de5c6b0 · Gabriel Morell · 2026-09-14 00:42

8 files +54 -6
Message
{commit_body(@commit)}

Files changed

modified .forgejo/workflows/android.yml
+12 −0
@@ -74,9 +74,21 @@ jobs:
74 74
75 75 - name: Build and sign the APK
76 76 if: steps.keystore.outputs.skip != 'true'
77 + env:
78 + RUN_NUMBER: ${{ github.run_number }}
77 79 run: |
80 + set -euo pipefail
81 +
82 + # One stamp for the whole run, computed here rather than
83 + # inside Gradle, so every artifact a run produces agrees on
84 + # its version even if the build is retried a step at a time.
85 + stamp=$(date -u +%s)
86 + echo "version: 0.1.0-dev-$stamp (versionCode $RUN_NUMBER)"
87 +
78 88 docker buildx build \
79 89 --target android-export \
90 + --build-arg GITHUB_RUN_NUMBER="$RUN_NUMBER" \
91 + --build-arg SOURCE_DATE_EPOCH="$stamp" \
80 92 --secret id=keystore,src=./release.jks \
81 93 --secret id=keystore_password,src=./keystore.pass \
82 94 --output type=local,dest=./apk \
modified clients/android/Dockerfile
+18 −1
@@ -81,9 +81,26 @@ RUN ./gradlew --no-daemon :app:dependencies --configuration releaseRuntimeClassp
81 81 FROM deps AS build
82 82
83 83 ARG BUILD_TOOLS=36.1.0
84 +
85 +# A container build inherits nothing from the runner's environment, so
86 +# the version has to be handed in explicitly. Without these, Gradle's
87 +# getenv lookups come back empty inside here and every run builds
88 +# versionCode 1 — the same filename with different bytes, which the
89 +# registry refuses with a 409.
90 +#
91 +# Declared in this stage rather than at the top so they don't invalidate
92 +# the SDK and dependency layers, which is most of the build time.
93 +ARG GITHUB_RUN_NUMBER
94 +ARG SOURCE_DATE_EPOCH
95 +ARG RELEASE_VERSION
96 +ENV GITHUB_RUN_NUMBER=${GITHUB_RUN_NUMBER} \
97 + SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} \
98 + RELEASE_VERSION=${RELEASE_VERSION}
99 +
84 100 COPY app ./app
85 101
86 −RUN ./gradlew --no-daemon :app:assembleRelease
102 +RUN echo "building versionCode=${GITHUB_RUN_NUMBER:-1}" \
103 + && ./gradlew --no-daemon :app:assembleRelease
87 104
88 105 # Sign as a separate step from Gradle so the keystore never reaches a
89 106 # build script, a Gradle cache, or an image layer. BuildKit secrets are
modified clients/android/app/build.gradle.kts
+24 −5
@@ -4,10 +4,27 @@ plugins {
4 4 alias(libs.plugins.kotlin.serialization)
5 5 }
6 6
7 −// Bumped by hand for a real release; the build metadata after it comes
8 −// from CI.
7 +// Bumped by hand; everything after it is generated.
9 8 val baseVersion = "0.1.0"
10 9
10 +// Seconds, and taken from the environment when it's there. CI sets it
11 +// once per run so every artifact from that run agrees; a local build
12 +// computes it, which is fine because local builds are never published.
13 +//
14 +// SOURCE_DATE_EPOCH first because it's the cross-toolchain convention
15 +// for exactly this, and honouring it means a reproducible-build harness
16 +// that already sets it gets a reproducible versionName for free.
17 +val buildTimestamp: Long =
18 + (System.getenv("SOURCE_DATE_EPOCH") ?: System.getenv("BUILD_TIMESTAMP"))
19 + ?.toLongOrNull()
20 + ?: (System.currentTimeMillis() / 1000)
21 +
22 +// A real release overrides the whole string; until there is one, every
23 +// build says so in its name rather than claiming to be 0.1.0.
24 +val appVersionName: String =
25 + System.getenv("RELEASE_VERSION")?.takeIf { it.isNotBlank() }
26 + ?: "$baseVersion-dev-$buildTimestamp"
27 +
11 28 android {
12 29 namespace = "io.neiam.apolloscrib"
13 30 compileSdk {
@@ -34,9 +51,11 @@ android {
34 51 // never published.
35 52 versionCode = (System.getenv("GITHUB_RUN_NUMBER") ?: "").toIntOrNull() ?: 1
36 53
37 − // The commit is what you want when someone reports a bug
38 − // against a build. Local builds just say "dev".
39 − versionName = "$baseVersion+" + ((System.getenv("GITHUB_SHA") ?: "dev").take(7))
54 + // Not the commit: versionCode is the CI run number, and a run
55 + // knows its own commit, so the sha is one lookup away and the
56 + // timestamp orders builds at a glance in a list that versionCode
57 + // alone renders as bare integers.
58 + versionName = appVersionName
40 59 }
41 60
42 61 buildTypes {

Parents: bbabd50