Updates are agent steps: --yes ships an update of a live app (Play production, App Store submit / release) without an owner gate; the first release stays the owner's (exit 3 OWNER_STEP, --first-release); apple release is a ship step

This commit is contained in:
CRTkafa 2026-10-26 18:09:50 +07:00
parent c247b7e54a
commit ae9d26d3f6
28 changed files with 562 additions and 44 deletions

View file

@ -45,7 +45,11 @@ const CONFIG: ShipConfig = {
/** The live shape: version 1.0.0 REJECTED (Invalid Binary) with build 7, submission rs-old UNRESOLVED_ISSUES holding the
* version and the gems IAP; pro was never added; build 8 uploaded and VALID. */
/** The app was on sale before (an update, not a first release): version 0.9.0 READY_FOR_SALE. */
function onSale(): void { s.asc.put({ type: 'appStoreVersions', id: 'ver-0', attributes: { versionString: '0.9.0', appVersionState: 'READY_FOR_SALE', platform: 'IOS' }, rels: { app: APP } }); }
function rejected(o: { pro?: boolean; ver?: string; gems?: string } = {}): void {
onSale();
s.asc.put({ type: 'appStoreVersions', id: 'ver-1', attributes: { versionString: '1.0.0', appVersionState: 'REJECTED', platform: 'IOS' }, rels: { app: APP } });
s.asc.put({ type: 'builds', id: 'b-7', attributes: { version: '7', processingState: 'VALID', usesNonExemptEncryption: false }, rels: { app: APP, appStoreVersion: 'ver-1' } });
s.asc.put({ type: 'builds', id: 'b-8', attributes: { version: '8', processingState: 'VALID', usesNonExemptEncryption: false }, rels: { app: APP } });
@ -181,6 +185,7 @@ describe('apple resubmit --build <n>', () => {
describe('apple submit --build <n> (a first submission, the desktop owner action)', () => {
/** Version 1.0.0 in Prepare for Submission without a build, build 8 VALID, the gems IAP ready, no open submission. */
function fresh(): void {
onSale();
s.asc.put({ type: 'appStoreVersions', id: 'ver-1', attributes: { versionString: '1.0.0', appVersionState: 'PREPARE_FOR_SUBMISSION', platform: 'IOS' }, rels: { app: APP } });
s.asc.put({ type: 'builds', id: 'b-8', attributes: { version: '8', processingState: 'VALID', usesNonExemptEncryption: false }, rels: { app: APP } });
s.asc.put({ type: 'inAppPurchases', id: 'iap-gems', attributes: { productId: 'com.example.notes.gems', inAppPurchaseType: 'CONSUMABLE', state: 'READY_TO_SUBMIT' }, rels: { app: APP } });
@ -199,7 +204,7 @@ describe('apple submit --build <n> (a first submission, the desktop owner action
expect(r.out).toMatch(/submission\s+new draft\s+-\s+create/);
expect(r.out).toMatch(/app version 1\.0\.0/);
expect(r.out).toContain('com.example.notes.gems');
expect(r.out).toContain('Submitting is the owner');
expect(r.out).toContain('update of an app on sale');
process.env.STOREBOUND_MACHINE = '1';
try {
const j = await capture(() => appleSubmit(p.ctx(['--build', '8', '--json'])));