validate: macOS versions need Mac screenshots, Play reads survive an ended edit; macOS build numbers across platforms; Mac build prebuild + apple.macAppCheck; signing wording off the Mac; dry flows plan uploads

This commit is contained in:
CRTkafa 2026-11-02 18:16:25 +07:00
parent b1f1b206d3
commit f5da7c9f7a
21 changed files with 519 additions and 57 deletions

View file

@ -20,7 +20,7 @@ import { dirname, join, relative } from 'node:path';
import type { Args } from './lib/args';
import { CONFIG_NAMES, loadConfig, type ShipConfig } from './lib/config';
import {
type CondCtx, expand, type Flow, flowsOfFile, kindOf, type Mode, parseParams, planStep, type PlannedStep, resumePoint, type RunState, startIndex,
type CondCtx, type DryPending, expand, type Flow, flowsOfFile, kindOf, missingParams, type Mode, noteDry, parseParams, planStep, plannedForDryInput, type PlannedStep, resumePoint, type RunState, startIndex,
type StepResult, validateFlows,
} from './lib/flow';
import { DECLINED_MARK } from './lib/ctx';
@ -170,6 +170,12 @@ async function runFlow(args: Args, root: string): Promise<void> {
const subParams = expand(flow, all, 'steps').params;
const vars: Record<string, string> = { ...subParams, ...flow.params, ...(from ? last?.vars ?? {} : {}), ...params };
const c = await condCtx(root);
vars['config.testflight.internal'] = (c.config?.apple?.testflight?.groups ?? []).filter(g => g.internal).map(g => g.name).join(',');
if (!args.has('resume')) {
const missing = missingParams(vars);
if (missing.length) throw new Error(`${name} needs ${missing.map(k => `${k}=<value>`).join(' ')} (storebound flow run ${name} ${missing.map(k => `${k}=...`).join(' ')})`);
}
const pending: DryPending = { built: new Set(), uploaded: new Set() };
const prebuilt = prebuildsDone();
const state: RunState = { flow: name, mode, startedAt: new Date().toISOString(), vars, results: [], ok: true };
const env = process.env as Record<string, string | undefined>;
@ -196,12 +202,20 @@ async function runFlow(args: Args, root: string): Promise<void> {
state.results.push(r); save();
continue;
}
const planned = plannedForDryInput(p, mode, pending);
if (planned) {
r.status = 'planned'; r.detail = planned;
if (!json) log(TAG, `${label}: ${describe(p)} (${planned})`);
state.results.push(r); save();
continue;
}
if (!json) log(TAG, `${label}: ${describe(p)}${p.dryAdded ? ' (dry run)' : ''}`);
const t = Date.now();
const x = await exec(p, root, json, prebuilt.size ? { [PREBUILD_DONE_ENV]: [...prebuilt].join('\n') } : {});
r.exitCode = x.code; r.ms = Date.now() - t;
if (x.code === 0) {
r.status = 'ok';
noteDry(p, pending);
const pre = p.argv ? prebuildRan(p.argv, c.config) : null;
if (pre) prebuilt.add(pre);
if (p.capture) {