feat(android-release): derive Android version code from release tag

The release workflow now derives versionName and versionCode from the tag
and validates the tag format. It updates multiple project files in the
runner workspace without committing changes back to the repository.
A verification step ensures the generated Android properties are correct.

- Tag parsing validates vMAJOR.MINOR.PATCH and enforces minor/patch <= 999
- VersionCode computed as major*1e6 + minor*1e3 + patch and applied
- Added post-build verification of Android versionName and versionCode
This commit is contained in:
2026-08-26 00:54:20 +02:00
parent aca5562f81
commit 455b68e562
2 changed files with 89 additions and 9 deletions
+72 -4
View File
@@ -67,18 +67,80 @@ jobs:
- name: Install JavaScript dependencies - name: Install JavaScript dependencies
run: npm ci run: npm ci
- name: Check release tag and app version - name: Apply version from release tag
run: | run: |
if [ "${GITHUB_REF_TYPE}" != "tag" ]; then if [ "${GITHUB_REF_TYPE}" != "tag" ]; then
echo "Release builds must run on a tag such as v0.1.0." >&2 echo "Release builds must run on a tag such as v0.1.0." >&2
exit 1 exit 1
fi fi
APP_VERSION="$(node -p "require('./src-tauri/tauri.conf.json').version")"
if [ "${GITHUB_REF_NAME}" != "v${APP_VERSION}" ]; then RELEASE_VERSION="${GITHUB_REF_NAME#v}"
echo "Tag ${GITHUB_REF_NAME} does not match app version v${APP_VERSION}." >&2 if [[ ! "${RELEASE_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Tag ${GITHUB_REF_NAME} must use the format vMAJOR.MINOR.PATCH." >&2
exit 1 exit 1
fi fi
IFS=. read -r VERSION_MAJOR VERSION_MINOR VERSION_PATCH <<< "${RELEASE_VERSION}"
if (( 10#${VERSION_MINOR} > 999 || 10#${VERSION_PATCH} > 999 )); then
echo "Minor and patch versions must not exceed 999." >&2
exit 1
fi
ANDROID_VERSION_CODE=$((10#${VERSION_MAJOR} * 1000000 + 10#${VERSION_MINOR} * 1000 + 10#${VERSION_PATCH}))
if (( ANDROID_VERSION_CODE < 1 || ANDROID_VERSION_CODE > 2100000000 )); then
echo "Derived Android versionCode ${ANDROID_VERSION_CODE} is outside the allowed range." >&2
exit 1
fi
RELEASE_VERSION="${RELEASE_VERSION}" \
ANDROID_VERSION_CODE="${ANDROID_VERSION_CODE}" \
GITHUB_REF_NAME="${GITHUB_REF_NAME}" \
node -e '
const fs = require("fs");
const version = process.env.RELEASE_VERSION;
const versionCode = process.env.ANDROID_VERSION_CODE;
function updateJson(path, update) {
const value = JSON.parse(fs.readFileSync(path, "utf8"));
update(value);
fs.writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
}
updateJson("package.json", value => { value.version = version; });
updateJson("package-lock.json", value => {
value.version = version;
value.packages[""].version = version;
});
updateJson("src-tauri/tauri.conf.json", value => { value.version = version; });
const cargoTomlPath = "src-tauri/Cargo.toml";
const cargoToml = fs.readFileSync(cargoTomlPath, "utf8").replace(
/(\[package\][\s\S]*?\nversion = ")[^"]+("\n)/,
`$1${version}$2`
);
fs.writeFileSync(cargoTomlPath, cargoToml);
const cargoLockPath = "src-tauri/Cargo.lock";
const cargoLock = fs.readFileSync(cargoLockPath, "utf8").replace(
/(\[\[package\]\]\nname = "lockscreenwallpaper"\nversion = ")[^"]+("\n)/,
`$1${version}$2`
);
fs.writeFileSync(cargoLockPath, cargoLock);
const fdroidPath = ".fdroid.yml";
let fdroid = fs.readFileSync(fdroidPath, "utf8");
fdroid = fdroid
.replace(/^ - versionName: .*$/m, ` - versionName: ${version}`)
.replace(/^ versionCode: .*$/m, ` versionCode: ${versionCode}`)
.replace(/^ commit: .*$/m, ` commit: ${process.env.GITHUB_REF_NAME}`)
.replace(/^CurrentVersion: .*$/m, `CurrentVersion: ${version}`)
.replace(/^CurrentVersionCode: .*$/m, `CurrentVersionCode: ${versionCode}`);
fs.writeFileSync(fdroidPath, fdroid);
'
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> "${GITEA_ENV}"
echo "ANDROID_VERSION_CODE=${ANDROID_VERSION_CODE}" >> "${GITEA_ENV}"
echo "Building ${GITHUB_REF_NAME} with Android versionCode ${ANDROID_VERSION_CODE}."
- name: Validate signing secrets - name: Validate signing secrets
run: | run: |
for SECRET_NAME in \ for SECRET_NAME in \
@@ -105,6 +167,12 @@ jobs:
- name: Build unsigned release APK - name: Build unsigned release APK
run: npm run tauri -- android build --apk --ci run: npm run tauri -- android build --apk --ci
- name: Verify generated Android version
run: |
TAURI_PROPERTIES="src-tauri/gen/android/app/tauri.properties"
grep -Fx "tauri.android.versionName=${RELEASE_VERSION}" "${TAURI_PROPERTIES}"
grep -Fx "tauri.android.versionCode=${ANDROID_VERSION_CODE}" "${TAURI_PROPERTIES}"
- name: Align and sign APK - name: Align and sign APK
run: | run: |
UNSIGNED_APK="src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release-unsigned.apk" UNSIGNED_APK="src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release-unsigned.apk"
+17 -5
View File
@@ -49,10 +49,18 @@ Der native Android-Code liegt als lokales Tauri-Plugin in `plugins/android`. Er
## Signierte Android-Releases mit Gitea Actions ## Signierte Android-Releases mit Gitea Actions
Der Workflow `.gitea/workflows/android-release.yml` baut bei Tags wie `v0.1.0` Der Workflow `.gitea/workflows/android-release.yml` baut bei Tags wie `v1.2.3`
eine signierte Universal-APK. Der Tag muss der Version in eine signierte Universal-APK. Der Tag ist dabei die Quelle für alle
`src-tauri/tauri.conf.json` mit vorangestelltem `v` entsprechen. Der Workflow Versionsnummern im Build. Die Pipeline setzt vorübergehend die Versionen in
kann außerdem manuell über die Actions-Oberfläche gestartet werden. `package.json`, `package-lock.json`, `src-tauri/tauri.conf.json`,
`src-tauri/Cargo.toml`, `src-tauri/Cargo.lock` und `.fdroid.yml`. Diese Änderungen
gelten nur im Arbeitsverzeichnis des Runners und werden nicht zurück ins
Repository geschrieben.
Aus `v1.2.3` erzeugt Tauri den Android-`versionCode` `1002003` nach dem Schema
`major * 1000000 + minor * 1000 + patch`. Der Workflow kann außerdem manuell
über die Actions-Oberfläche gestartet werden, wenn dabei ein Versions-Tag als
Ref ausgewählt wird.
In den Repository-Einstellungen unter **Settings → Actions → Secrets** müssen In den Repository-Einstellungen unter **Settings → Actions → Secrets** müssen
folgende Secrets angelegt werden: folgende Secrets angelegt werden:
@@ -99,7 +107,11 @@ Weitere Einzelheiten stehen in der [Datenschutzerklärung](PRIVACY.md).
## Veröffentlichungen ## Veröffentlichungen
Für eine neue Veröffentlichung müssen die Version in `package.json`, `src-tauri/tauri.conf.json` und `src-tauri/Cargo.toml` gemeinsam erhöht und ein passender Git-Tag angelegt werden, beispielsweise `v0.1.0`. Der Android-`versionCode` muss bei jeder Veröffentlichung steigen. Für ein Gitea-Release genügt ein neuer, höherer Versions-Tag wie `v0.1.1`; die
Pipeline übernimmt daraus alle Versionen für den Build. Für dauerhaft im
Repository gepflegte Versionsstände und F-Droid-Releases sollten die Versionen
in `package.json`, `src-tauri/tauri.conf.json`, `src-tauri/Cargo.toml` und
`.fdroid.yml` zusätzlich im Quellcode aktualisiert werden.
Die Metadaten für F-Droid liegen unter `fastlane/metadata/android`. Das Buildrezept für F-Droid befindet sich in `.fdroid.yml`. Die Metadaten für F-Droid liegen unter `fastlane/metadata/android`. Das Buildrezept für F-Droid befindet sich in `.fdroid.yml`.