games: one config section for Game Center and Play Games Services (shared leaderboards and achievements); apple game-center (gameCenterDetails, gameCenterAppVersions, leaderboards, achievements and localizations, upsert by vendor id, read back); play games (Games Configuration API upsert, no POST retry); signing ensure adds GAME_CENTER when games.gameCenter

This commit is contained in:
CRTkafa 2026-10-21 04:59:51 +07:00
parent eebb3a830b
commit ca7289b173
8 changed files with 653 additions and 6 deletions

View file

@ -167,7 +167,7 @@ export async function capabilityReport(c: Asc, config: ShipConfig, root: string)
const bundleId = config.apple!.bundleId;
const b = await findBundleId(c, bundleId);
const appId = b ? (b.capabilities as string[]) : null;
const cfg = capabilitySpecs(config.apple?.signing).map(x => x.type);
const cfg = capabilitySpecs(config.apple?.signing, config.games?.gameCenter === true).map(x => x.type);
const project = readProjectEntitlements(root);
let build: BuildEntitlements | null = null;
try { build = builtIpaEntitlements(root, config); } catch { /* unreadable IPA: compared without it */ }
@ -238,7 +238,7 @@ export async function run(ctx: Ctx): Promise<void> {
const bundles = new Map<string, J | null>();
for (const id of ids) bundles.set(id, await findBundleId(c, id));
const main = bundles.get(bundleId);
const capPlan = main ? planCapabilities(main.id, main.capabilities ?? [], capabilitySpecs(s)) : { create: [], present: [], extra: [] };
const capPlan = main ? planCapabilities(main.id, main.capabilities ?? [], capabilitySpecs(s, config.games?.gameCenter === true)) : { create: [], present: [], extra: [] };
const certs: ApiCert[] = await c.all(`/v1/certificates?filter[certificateType]=${certType}&limit=200`);
const keys = localKeys(root);
const identities = keychainIdentities();
@ -258,7 +258,7 @@ export async function run(ctx: Ctx): Promise<void> {
}
const state: SigningState = {
bundleId, teamId: s.teamId ?? main?.attributes?.seedId ?? null, registered: !!main,
capabilities: { present: capPlan.present, missing: capabilitySpecs(s).filter(w => !capPlan.present.includes(w.type)).map(w => w.type), extra: capPlan.extra },
capabilities: { present: capPlan.present, missing: capabilitySpecs(s, config.games?.gameCenter === true).filter(w => !capPlan.present.includes(w.type)).map(w => w.type), extra: capPlan.extra },
certificate: { type: certType, chosen: choice.cert?.attributes.name ?? choice.cert?.attributes.displayName ?? null, why: choice.why,
onTeam: certs.filter(x => Date.parse(x.attributes.expirationDate ?? '') > Date.now()).length, withKey: choice.usable.length, limit: CERT_LIMIT[certType] ?? null },
profiles: ids.map(id => {
@ -330,7 +330,7 @@ export async function run(ctx: Ctx): Promise<void> {
if (plan.length && !(await confirm(ctx, `Create ${plan.length} item(s) on the Apple Developer team (${[capPlan.create.length && `${capPlan.create.length} capabilities`, needCert && `a ${certType} certificate`, plan.length - capPlan.create.length - (needCert ? 1 : 0) && 'provisioning profiles'].filter(Boolean).join(', ')})?`))) return;
const responses = await execute(c.asc, capPlan.create, { dry: false, tag: TAG });
if (capPlan.create.length) await checkCapabilitiesStuck(c, bundleId, capabilitySpecs(s).map(w => w.type), responses);
if (capPlan.create.length) await checkCapabilitiesStuck(c, bundleId, capabilitySpecs(s, config.games?.gameCenter === true).map(w => w.type), responses);
if (!scope.profiles) {
printCapabilityReport(await capabilityReport(c, config, root), TAG);
cleanup();