console plans: guardrails from a real run (2026-10-21): health none label and Sign in details Yes/No + Add details (old labels as altLabels, verify accepts both), finance boxes on step 1, App Privacy Additional Setup Required OK, verify from DOM input states (verify.capture, --from), Save + confirm before every Next on Play pages, IARC Digital purchases boxes and an exact-label in-page helper that refuses patterns and blanket answers; review contact found in parent folders, the profile and more key shapes with the files checked listed; one-line errors for missing required values (Args.required); pitfalls 86-87, tests
This commit is contained in:
parent
a6dab8f3aa
commit
335a4124ab
23 changed files with 486 additions and 74 deletions
|
|
@ -165,8 +165,7 @@ function options(ctx: Ctx): void {
|
|||
|
||||
function exportIpa(ctx: Ctx): void {
|
||||
const a = ctx.args;
|
||||
const archive = a.get('archive');
|
||||
if (!archive || archive === 'true') throw new Error('usage: storebound apple adhoc export --archive <App.xcarchive> [--out build/adhoc] [--dry]');
|
||||
const archive = a.required('archive', 'App.xcarchive', 'Xcode: Product > Archive, or storebound apple build');
|
||||
if (!existsSync(archive)) throw new Error(`${archive}: no such archive (Xcode: Product > Archive, or xcodebuild archive)`);
|
||||
const plistRel = a.str('plist', 'build/ExportOptions.plist');
|
||||
const plist = ctx.loaded.resolve(plistRel);
|
||||
|
|
|
|||
|
|
@ -195,8 +195,7 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
const { config, root } = ctx.loaded;
|
||||
const a = ctx.args;
|
||||
if (a._[0] === 'pull') return pull(ctx);
|
||||
const version = a.get('version');
|
||||
if (!version) throw new Error('usage: apple listing --version 1.0.0 [--build N] [--include-drafts] [--dry] [--json]');
|
||||
const version = a.required('version', 'x.y.z', 'storebound apple status shows the editable version');
|
||||
const dry = a.has('dry');
|
||||
const c = await ascClient(root, need(config.apple?.bundleId, 'apple.bundleId'), config.apple?.appId);
|
||||
const appId = await c.app();
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ export async function submitVersion(ctx: Ctx, mode: 'submit' | 'resubmit'): Prom
|
|||
const TAG = mode;
|
||||
const { config, root } = ctx.loaded;
|
||||
const a = ctx.args;
|
||||
const number = a.get('build');
|
||||
if (!number || !/^\d+(\.\d+)*$/.test(number)) throw new Error(`usage: apple ${mode} --build <n> [--version x.y.z] [--dry] [--yes]: the build number you just uploaded (never "the latest")`);
|
||||
const number = a.required('build', 'n', 'the build number you just uploaded, never "the latest"; storebound apple testflight status lists them');
|
||||
if (!/^\d+(\.\d+)*$/.test(number)) throw new Error(`--build ${number}: a build number like 42 or 1.0.3 (the one you just uploaded, never "the latest")`);
|
||||
const c = await ascClient(root, need(config.apple?.bundleId, 'apple.bundleId'), config.apple?.appId);
|
||||
const appId = await c.app();
|
||||
const ids = [...(config.products ?? []).filter(p => sellsOn(config, p, 'apple')).map(p => p.id), ...allSubscriptions(config.subscriptions).filter(x => sellsOn(config, x.sub, 'apple')).map(x => x.sub.id)];
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import { refuseTemplate } from '../lib/template-answers';
|
||||
import type { Ctx } from '../lib/ctx';
|
||||
import { need } from '../lib/ctx';
|
||||
import { reviewContact, reviewDemoAccount } from '../lib/credentials';
|
||||
import { findReviewContact, noContactMessage, reviewDemoAccount } from '../lib/credentials';
|
||||
import { reviewDetailPlan } from '../lib/review-details';
|
||||
import { done, log } from '../lib/log';
|
||||
import { createOnce } from '../lib/upsert';
|
||||
|
|
@ -29,11 +29,15 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
if (a?.contactEmail) { contact = { contactFirstName: a.contactFirstName, contactLastName: a.contactLastName, contactPhone: a.contactPhone, contactEmail: a.contactEmail }; break; }
|
||||
}
|
||||
if (!contact) throw new Error(`app ${from} has no review contact on its recent versions`);
|
||||
} else {
|
||||
const rc = reviewContact(root);
|
||||
}
|
||||
let checked: string[] = [];
|
||||
if (!from) {
|
||||
const found = findReviewContact(root);
|
||||
checked = found.checked;
|
||||
const rc = found.contact;
|
||||
if (rc) contact = { contactFirstName: rc.firstName, contactLastName: rc.lastName, contactPhone: rc.phone, contactEmail: rc.email };
|
||||
}
|
||||
if (!contact) throw new Error('no review contact: add "reviewContact" to .storebound/credentials.json or pass --contact-from <app id>');
|
||||
if (!contact) throw new Error(noContactMessage(root, checked));
|
||||
|
||||
const { attributes, summary } = reviewDetailPlan(config, contact, reviewDemoAccount(root));
|
||||
if (ctx.args.has('dry')) { log('apple', `would set review details (contact ${from ? 'copied from ' + from : 'from credentials'}, ${summary})`); return; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue