Game Center switch before submit: apple submit / resubmit and signing ensure create gameCenterDetails and gameCenterAppVersions when Game Center is in use (config, entitlements or the built IPA), shown in the dry run; validate blocks on either missing; fake 409 BUILD_INDICATES_GAME_CENTER_ENABLED until both exist; pitfall 89

This commit is contained in:
CRTkafa 2026-10-21 05:33:53 +07:00
parent dd9e059036
commit 163e666834
9 changed files with 152 additions and 26 deletions

View file

@ -11,6 +11,7 @@
// App Store profile per bundle id (apple.bundleId + apple.signing.extraBundleIds) and installs it for Xcode.
// Every write is shown first (--dry shows only that) and asks once before anything is created. Developer ID
// certificates need the Account Holder: the API's 403 is explained. Pure planning: cli/lib/signing.ts.
import { ensureGcSwitch, gcSwitchPlan, readGcSwitch } from './game-center';
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { homedir, tmpdir } from 'node:os';
import { basename, dirname, join, relative, resolve as resolvePath } from 'node:path';
@ -313,6 +314,10 @@ export async function run(ctx: Ctx): Promise<void> {
return !p || p.create ? [`POST /v1/profiles {name=..., profileType="${profileType}"} # ${id}: ${p?.why ?? 'with the new certificate'}`] : [];
})),
];
// GAME_CENTER on the App ID: the app and its editable version need the Game Center switch too (apple game-center)
const gcSw = capabilitySpecs(s, config.games?.gameCenter === true).some(w => w.type === 'GAME_CENTER') ? await (async () => { try { return await readGcSwitch(c, await c.app(), await c.editableVersion()); } catch { return null; /* no app record yet: apple game-center later */ } })() : null;
const gcPlan = gcSw ? gcSwitchPlan(gcSw) : [];
plan.push(...gcPlan);
log(TAG, scope.why);
if (needCert && state.certificate.limit && state.certificate.onTeam >= state.certificate.limit)
warn(TAG, `the team already has ${state.certificate.onTeam} valid ${certType} certificates (limit ${state.certificate.limit}): Apple will refuse a new one until one is revoked (owner decision, developer.apple.com > Certificates)`);
@ -331,6 +336,7 @@ export async function run(ctx: Ctx): Promise<void> {
const responses = await execute(c.asc, capPlan.create, { dry: false, tag: TAG });
if (capPlan.create.length) await checkCapabilitiesStuck(c, bundleId, capabilitySpecs(s, config.games?.gameCenter === true).map(w => w.type), responses);
if (gcPlan.length && gcSw) await ensureGcSwitch(c, gcSw, TAG);
if (!scope.profiles) {
printCapabilityReport(await capabilityReport(c, config, root), TAG);
cleanup();