build.prebuild and a Capacitor web-asset staleness guard for apple build / play build
apple build and play build run build.prebuild (or apple.prebuild / play.prebuild) first, once per flow run; --no-prebuild skips it, --dry only prints it. A Capacitor project's copied public/index.html must then be newer than the last source commit and <webDir>/index.html, else the build stops (--allow-stale-web overrides). check warns when stale without a prebuild; the build output and dry plan show the web bundle's sha256 and mtime. The Capacitor project is also found in a monorepo (apps/native etc.); several ask for play.build.dir / apple.build.*. Pitfall 23.
This commit is contained in:
parent
f694af80eb
commit
5fbb9e63e3
14 changed files with 600 additions and 25 deletions
|
|
@ -1,6 +1,8 @@
|
|||
// Build a signed release Android App Bundle.
|
||||
// storebound play build [--version-code N] [--version-name 1.2.0] [--flavor prod] [--dir android] [--module app]
|
||||
// [--out build/android] [--dry] [--json]
|
||||
// [--out build/android] [--no-prebuild] [--allow-stale-web] [--dry] [--json]
|
||||
// First the prebuild (build.prebuild / play.prebuild: e.g. the web build + npx cap sync; once per flow run), then a
|
||||
// Capacitor project's copied web assets (android/app/src/main/assets/public) must be newer than the source.
|
||||
// Finds the Gradle project (android/ of Capacitor, React Native and Flutter apps, the root of a native one, a Unity
|
||||
// export with launcher/ + unityLibrary/), takes the next free versionCode from Google Play (play next-version-code)
|
||||
// unless --version-code is given, runs `gradlew :app:bundleRelease` (Flutter: flutter build appbundle) and copies the
|
||||
|
|
@ -17,6 +19,7 @@ import { done, log, printJson, warn } from '../lib/log';
|
|||
import { pump } from '../lib/runner';
|
||||
import { aabInfo, findBundles, gradleArgs, pickGradle, signingEnv } from '../lib/gradle';
|
||||
import { nextVersionCode } from '../lib/release';
|
||||
import { capacitorProject, webStep } from '../lib/web-assets';
|
||||
import { playClient } from './client';
|
||||
import { usedVersionCodes } from './next-version-code';
|
||||
|
||||
|
|
@ -28,7 +31,12 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
const pkg = need(config.play?.packageName, 'play.packageName');
|
||||
const cfg = config.play?.build ?? {};
|
||||
const flavor = a.get('flavor') ?? cfg.flavor;
|
||||
const t = pickGradle(root, { dir: a.get('dir') ?? cfg.dir, module: a.get('module') ?? cfg.module, flavor });
|
||||
const dir = a.get('dir') ?? cfg.dir;
|
||||
// Capacitor in a monorepo (apps/native/android): play.build.dir / --dir wins, else the one Capacitor project found
|
||||
const cap = capacitorProject(root, dir);
|
||||
const sub = !dir && cap?.dir ? cap.dir : '';
|
||||
const t = pickGradle(sub ? join(root, sub) : root, { dir, module: a.get('module') ?? cfg.module, flavor });
|
||||
if (sub) t.notes.unshift(`Capacitor project: ${sub} (${sub}/${cap!.config}; the only one found; set play.build.dir to use another)`);
|
||||
const dry = a.has('dry');
|
||||
const json = a.has('json');
|
||||
const out = resolve(a.get('out') ?? 'build/android');
|
||||
|
|
@ -52,8 +60,10 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
const plan = { framework: t.framework, dir: relative(root, t.dir) || '.', module: t.module, task: t.framework === 'flutter' ? 'flutter build appbundle' : t.task,
|
||||
versionCode: code || null, versionName: versionName ?? null, signing: signing ? `upload key from ${process.env.ANDROID_KEYSTORE ? 'env' : '.storebound/credentials.json'} (alias ${signing.keyAlias})` : 'the project\'s own signingConfig',
|
||||
command: argv.join(' '), out: relative(root, out) || '.', notes: t.notes };
|
||||
const webOpts = { config, root, cap, store: 'play' as const, tag: TAG, noPrebuild: a.has('no-prebuild'), allowStale: a.has('allow-stale-web') };
|
||||
if (dry) {
|
||||
if (json) { printJson(plan); return; }
|
||||
const web = await webStep({ ...webOpts, dry: true, quiet: json });
|
||||
if (json) { printJson({ ...plan, web }); return; }
|
||||
log(TAG, `${t.framework}: ${plan.dir} ${plan.task}, versionCode ${code || '?'}${versionName ? `, versionName ${versionName}` : ''}`);
|
||||
log(TAG, `signing: ${plan.signing}`);
|
||||
for (const n of t.notes) log(TAG, n);
|
||||
|
|
@ -61,6 +71,7 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
done(TAG, 'build planned (dry run)');
|
||||
return;
|
||||
}
|
||||
const web = await webStep({ ...webOpts, dry: false });
|
||||
if (signing && !existsSync(signing.storeFile)) throw new Error('ANDROID_KEYSTORE: the keystore file does not exist');
|
||||
if (!signing) warn(TAG, 'no ANDROID_KEYSTORE: the project\'s own release signingConfig must sign, else Play refuses the bundle');
|
||||
for (const n of t.notes) log(TAG, n);
|
||||
|
|
@ -85,7 +96,7 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
if (code && info.versionCode !== code) warn(TAG, `the AAB has versionCode ${info.versionCode}, not ${code}: the build file sets it itself; read -PversionCode there or pass that number to play upload knowingly`);
|
||||
const dest = join(out, `${info.packageName}-${info.versionCode}.aab`);
|
||||
copyFileSync(aab, dest);
|
||||
const result = { aab: dest, packageName: info.packageName, versionCode: info.versionCode, versionName: info.versionName ?? null };
|
||||
const result = { aab: dest, packageName: info.packageName, versionCode: info.versionCode, versionName: info.versionName ?? null, web: web.bundle };
|
||||
if (json) printJson(result);
|
||||
done(TAG, `${relative(root, dest)}: ${info.packageName} ${info.versionName ?? ''} (${info.versionCode}). Next: storebound play upload ${relative(root, dest)} --track internal --dry`);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue