apple listing: a new version inherits the previous version's release type when apple.releaseType is unset; warn when the config differs

This commit is contained in:
CRTkafa 2026-10-29 19:59:49 +07:00
parent f5296cc9e9
commit 6ebb656018
5 changed files with 31 additions and 3 deletions

View file

@ -157,6 +157,7 @@ export function listingPlanLines(p: AppleListingPlan): string[] {
const v = p.versionPlan;
const out = [`Version ${p.version} (${platformLabel(p.platform)}; App Store Connect has: ${v.existing.length ? v.existing.map(x => `${x.versionString} ${x.state} ${platformLabel(x.platform)}`).join(', ') : `no ${platformLabel(p.platform)} version yet`})`];
out.push(` ${v.action === 'refuse' ? 'REFUSE' : v.action.toUpperCase()}: ${v.reason}`);
if (v.warning) out.push(` WARN: ${v.warning}`);
for (const ch of v.changes) out.push(` ${ch.field}: ${v.action === 'create' ? short(ch.to) : `${short(ch.from)} -> ${short(ch.to)}`}`);
if (p.build) out.push(`Build: ${p.build.action === 'refuse' ? 'REFUSE: ' : ''}${p.build.reason}`);
out.push(`App info ${p.appInfo.state ? `(${p.appInfo.state})` : ''}: name, subtitle, privacy policy URL per locale · ${counts(p.appInfo.locales)}`);

View file

@ -38,6 +38,8 @@ export interface VersionPlan {
/** The editable version that is kept or updated. */
id?: string;
reason: string;
/** Said in the dry run and the real run (e.g. a release type that differs from the previous version's). */
warning?: string;
existing: VersionInfo[];
changes: FieldDiff[];
attributes: Record<string, string>;
@ -103,9 +105,17 @@ export function planVersion(rows: { id: string; attributes: Record<string, unkno
if (busy) return refuse(`version ${busy.versionString} is ${busy.state}; App Store Connect allows one version in progress (${busy.state === 'PENDING_DEVELOPER_RELEASE'
? `release it first: storebound apple release --manual-release --version ${busy.versionString} --dry, then without --dry`
: busy.state === 'WAITING_FOR_REVIEW' || busy.state === 'IN_REVIEW' ? 'wait for the review, or remove it from review in App Store Connect' : 'wait for its release or remove it from review'})`);
const attributes: Record<string, string> = { platform, versionString: want, copyright: attrs.copyright, releaseType: attrs.releaseType ?? 'MANUAL' };
// without apple.releaseType a new version keeps the release type of the newest one before it (Acme 2026-10-29: an
// app the owner set to release after approval got a MANUAL 2.0.2 and would have sat unreleased); a first version is MANUAL
const prev = others.slice().sort((a, b) => compareVersions(b.versionString, a.versionString))[0];
const prevType = prev ? rows.find(r => r.id === prev.id)?.attributes.releaseType : undefined;
const inherited = !attrs.releaseType && typeof prevType === 'string' && ['MANUAL', 'AFTER_APPROVAL'].includes(prevType) ? prevType : undefined;
const attributes: Record<string, string> = { platform, versionString: want, copyright: attrs.copyright, releaseType: attrs.releaseType ?? inherited ?? 'MANUAL' };
if (attributes.releaseType === 'SCHEDULED' && attrs.earliestReleaseDate) attributes.earliestReleaseDate = attrs.earliestReleaseDate;
return { ...base, action: 'create', reason: `create version ${want} (no editable ${PLATFORM_LABEL[platform] ?? platform} version)`, changes: Object.entries(attributes).map(([field, to]) => ({ field, from: null, to })), attributes };
const why = attrs.releaseType ? 'apple.releaseType' : inherited ? `as version ${prev!.versionString}` : prev ? `version ${prev.versionString} has ${String(prevType ?? 'no readable type')}` : 'first version';
return { ...base, action: 'create', reason: `create version ${want} (no editable ${PLATFORM_LABEL[platform] ?? platform} version), release type ${attributes.releaseType} (${why})`,
changes: Object.entries(attributes).map(([field, to]) => ({ field, from: null, to })), attributes,
...(attrs.releaseType && typeof prevType === 'string' && prevType !== attrs.releaseType ? { warning: `release type ${attrs.releaseType} (apple.releaseType) differs from version ${prev!.versionString} (${prevType})` } : {}) };
}
// ---- translation drafts ----