Auto-sync Android version from package.json (no more manual gradle bumps)

Adds scripts/sync-android-version.mjs which writes versionName (semver) and a
monotonic versionCode (major*10000+minor*100+patch) into android/app/build.gradle
from package.json. Wired into `npm run android:build` and `android:sync`, plus a
standalone `npm run android:version`. Now you bump ONE number (package.json) and
never hit Zapstore's "already exists" again. Exits quietly if android/ isn't
generated yet.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-07-30 22:38:13 +07:00
parent 38343eb438
commit 41595159d9
2 changed files with 56 additions and 2 deletions

View file

@ -10,9 +10,10 @@
"test": "npm i --silent && tsc --noEmit && eslint && vitest run --reporter=dot --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'All tests passed!'",
"deploy": "npm i --silent && npm run build && npx -y nostr-deploy-cli deploy --skip-setup",
"android:init": "npm run android:build:apk && npx cap add android && npx cap sync android",
"android:sync": "npm run android:build:apk && npx cap sync android",
"android:sync": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs",
"android:open": "npx cap open android",
"android:build": "npm run android:build:apk && npx cap sync android && cd android && ./gradlew assembleRelease",
"android:version": "node scripts/sync-android-version.mjs",
"android:build": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && cd android && ./gradlew assembleRelease",
"android:build:apk": "CAPACITOR_BUILD=1 vite build && sed -i 's|<script type=\"module\" src=\"/shakespeare_tailwind[^\"]*\\.js\"></script>||g' dist/index.html && sed -i 's|<style type=\"text/tailwindcss\">|<style>|g' dist/index.html && cp dist/index.html dist/404.html"
},
"dependencies": {

View file

@ -0,0 +1,53 @@
#!/usr/bin/env node
/**
* Sync the Android app version from package.json into android/app/build.gradle.
*
* Single source of truth = package.json "version" (semver, e.g. "1.0.92").
* - versionName ← the semver string verbatim ("1.0.92")
* - versionCode ← a monotonic integer derived as
* major*10000 + minor*100 + patch ("1.0.92" → 10092)
*
* This runs automatically before `npm run android:build`, so you only ever
* bump ONE number (package.json) and never hit Zapstore's "already exists".
*
* If android/ hasn't been generated yet (fresh checkout), it exits quietly.
*/
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
const gradlePath = join(root, 'android', 'app', 'build.gradle');
if (!existsSync(gradlePath)) {
console.log('[sync-android-version] android/ not generated yet — skipping.');
process.exit(0);
}
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
const version = String(pkg.version || '').trim();
const m = version.match(/^(\d+)\.(\d+)\.(\d+)/);
if (!m) {
console.error(`[sync-android-version] package.json version "${version}" is not semver (x.y.z).`);
process.exit(1);
}
const [, major, minor, patch] = m.map(Number);
const versionName = version;
const versionCode = major * 10000 + minor * 100 + patch;
let gradle = readFileSync(gradlePath, 'utf8');
const beforeCode = gradle.match(/versionCode\s+(\d+)/)?.[1];
const beforeName = gradle.match(/versionName\s+"([^"]+)"/)?.[1];
gradle = gradle
.replace(/versionCode\s+\d+/, `versionCode ${versionCode}`)
.replace(/versionName\s+"[^"]+"/, `versionName "${versionName}"`);
writeFileSync(gradlePath, gradle);
console.log(
`[sync-android-version] ${beforeName} (${beforeCode}) → ${versionName} (${versionCode})`,
);