SkateSpots/scripts/inject-signing-config.mjs

98 lines
3.9 KiB
JavaScript

#!/usr/bin/env node
/**
* Inject the Android release signing configuration.
*
* WHY THIS EXISTS
* ───────────────
* The Android project (android/) is generated and NOT tracked in git —
* `npm run android:init` recreates it with `cap add android`. Release signing
* therefore has to be re-applied after every regeneration, and its secrets must
* never be committed. Previously the keystore path, alias and passwords were
* hardcoded inline in android/app/build.gradle.
*
* This script (idempotent, part of the android build, same pattern as the other
* scripts/inject-*.mjs helpers):
* 1. Removes any previously managed signing block.
* 2. Removes a legacy hardcoded signingConfigs block (inline passwords).
* 3. Writes a managed signingConfigs block into android/app/build.gradle that
* reads secrets from the gitignored keystore.properties at the repo root.
*
* It exits quietly (0) when android/ isn't generated yet, or when
* keystore.properties is absent — so debug-only builds without a keystore still
* work.
*/
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 buildGradle = join(root, 'android', 'app', 'build.gradle');
const keystoreProps = join(root, 'keystore.properties');
const BEGIN = '// >>> managed by scripts/inject-signing-config.mjs';
const END = '// <<< managed by scripts/inject-signing-config.mjs <<<';
if (!existsSync(buildGradle)) {
console.log('[inject-signing-config] android/ not generated yet — skipping.');
process.exit(0);
}
if (!existsSync(keystoreProps)) {
console.log('[inject-signing-config] keystore.properties not found — skipping release signing.');
process.exit(0);
}
const managedLines = [
`${BEGIN} >>>`,
'// Release signing is read from keystore.properties at the repo root',
'// (gitignored). Edit that file, not this block.',
'def _keystoreProps = new Properties()',
"def _keystorePropsFile = rootProject.file('../keystore.properties')",
'if (_keystorePropsFile.exists()) {',
' _keystorePropsFile.withInputStream { _keystoreProps.load(it) }',
'}',
'signingConfigs {',
' release {',
' if (_keystorePropsFile.exists()) {',
" storeFile rootProject.file(_keystoreProps['storeFile'])",
" storePassword _keystoreProps['storePassword']",
" keyAlias _keystoreProps['keyAlias']",
" keyPassword _keystoreProps['keyPassword']",
' }',
' }',
'}',
END,
];
const managed = managedLines.map((l) => ' ' + l).join('\n');
let src = readFileSync(buildGradle, 'utf8');
const before = src;
// 1. Drop any previously managed block so the script is idempotent.
const bIdx = src.indexOf(BEGIN);
if (bIdx !== -1) {
const eIdx = src.indexOf(END, bIdx);
if (eIdx !== -1) {
const lineStart = src.lastIndexOf('\n', bIdx);
const lineEnd = src.indexOf('\n', eIdx);
src = src.slice(0, lineStart) + (lineEnd === -1 ? '' : src.slice(lineEnd));
}
}
// 2. Drop a legacy hardcoded signingConfigs block (has an inline keyPassword).
src = src.replace(/\n[ \t]*signingConfigs\s*\{[\s\S]*?keyPassword\s+"[^"]*"\s*\}\s*\}/g, '');
// 3. Insert the managed block immediately after the `android {` opening.
const androidIdx = src.indexOf('android {');
if (androidIdx === -1) {
console.error('[inject-signing-config] could not find `android {` in build.gradle — aborting.');
process.exit(1);
}
const lineEnd = src.indexOf('\n', androidIdx);
src = src.slice(0, lineEnd + 1) + managed + '\n' + src.slice(lineEnd + 1);
if (src === before) {
console.log('[inject-signing-config] already up to date.');
} else {
writeFileSync(buildGradle, src);
console.log('[inject-signing-config] ✓ Wrote managed release signing config into android/app/build.gradle.');
}