play release: read the production kind inside the release's own edit (no extra edit); the not-sent-for-review tests approve their first release
This commit is contained in:
parent
ae9d26d3f6
commit
db52afce1d
2 changed files with 14 additions and 14 deletions
|
|
@ -57,17 +57,10 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
const gated = tracks.find(t => t.track === 'production' && (t.status === 'completed' || t.status === 'inProgress'));
|
||||
const notes = readPlayCopy(ctx).filter(c => c.whatsNew).map(c => ({ language: c.lang, text: c.whatsNew }));
|
||||
refusePlayNotes(ctx, notes, `play release notes${a.has('dry') ? ' (dry run)' : ''}`);
|
||||
// update of a published app: no owner step; the first production release: the owner's (exit 3 OWNER_STEP with --yes)
|
||||
let early: Awaited<ReturnType<typeof playClient>> | undefined;
|
||||
const client = async (): Promise<Awaited<ReturnType<typeof playClient>>> => (early ??= await playClient(root, pkg));
|
||||
let kind: ReturnType<typeof playReleaseKind> | null = null;
|
||||
if (gated) {
|
||||
const p0 = await client();
|
||||
const prod = await p0.read(async id => (await p0.call<{ releases?: PlayTrackRelease[] }>('GET', `${p0.API}/edits/${id}/tracks/production`).catch(() => ({ releases: [] }))).releases ?? []);
|
||||
kind = playReleaseKind(prod);
|
||||
if (a.has('dry')) log('play', `${kind.kind === 'update' ? 'update of a published app' : 'FIRST production release (the owner approves it once: --first-release)'}: ${kind.why}`);
|
||||
else if (!enforceFirstRelease(ctx, kind, { store: 'play', what: 'the first production release', consoleUrl: consoleUrl('play.publishing') })) return;
|
||||
}
|
||||
// update of a published app: no owner step; the first production release: the owner's (exit 3 OWNER_STEP with --yes).
|
||||
// The kind is read inside the release's own edit (no extra edit), before anything is uploaded.
|
||||
const seen: { kind?: ReturnType<typeof playReleaseKind> } = {};
|
||||
let refused = false;
|
||||
if (live && !a.has('dry') && !(await confirm(ctx, `Release to PRODUCTION as "${live.status}" (public once Google approves)?`))) return;
|
||||
|
||||
if (aab) {
|
||||
|
|
@ -76,11 +69,17 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
if (sdkWhy) throw new Error(`${aab}: not released, ${sdkWhy}`);
|
||||
}
|
||||
shipReport({ track: tracks.map(t => t.track).join(','), url: consoleUrl(playTrackPage(tracks.length === 1 ? tracks[0]!.track : undefined)) });
|
||||
const play = await client();
|
||||
const play = await playClient(root, pkg);
|
||||
let released = fixed ?? '';
|
||||
let nothing = false;
|
||||
try {
|
||||
await play.edit(async (id, ctl) => {
|
||||
if (gated) {
|
||||
const prod = (await play.call<{ releases?: PlayTrackRelease[] }>('GET', `${play.API}/edits/${id}/tracks/production`).catch(() => ({ releases: [] }))).releases ?? [];
|
||||
const kind = (seen.kind = playReleaseKind(prod));
|
||||
if (a.has('dry')) log('play', `${kind.kind === 'update' ? 'update of a published app' : 'FIRST production release (the owner approves it once: --first-release)'}: ${kind.why}`);
|
||||
else if (!enforceFirstRelease(ctx, kind, { store: 'play', what: 'the first production release', consoleUrl: consoleUrl('play.publishing') })) { refused = true; ctl.unchanged(); return; }
|
||||
}
|
||||
let code = fixed ?? '';
|
||||
let uploaded = false;
|
||||
if (aab) {
|
||||
|
|
@ -123,6 +122,7 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
throw new Error(`${(e as Error).message}\n\nThis app has never been published: the API may only create DRAFT releases. Re-run with --production draft, then send it from the Console (skill play-first-release).`);
|
||||
throw e;
|
||||
}
|
||||
if (refused) return;
|
||||
// the ship-step contract: every track holds this release already (and no upload): nothing to do, exit 7
|
||||
if (nothing && !a.has('dry')) shipNoop({ build: released || undefined, state: tracks.map(t => t.status).join(',') });
|
||||
const prod = tracks.find(t => t.track === 'production');
|
||||
|
|
@ -133,6 +133,6 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
}
|
||||
// machine-readable result for CI scripts (a Jenkins stage reads it instead of calling the Play API itself)
|
||||
if (a.has('json')) printJson({ versionCode: released ? Number(released) : null, sha256: aab ? createHash('sha256').update(readFileSync(aab)).digest('hex') : null, name: a.get('name') ?? null,
|
||||
tracks: tracks.map(t => ({ track: t.track, status: t.status, userFraction: t.status === 'inProgress' ? Number(fraction ?? 0.1) : null })), dry: a.has('dry'), ...(kind ? { releaseKind: kind.kind } : {}) });
|
||||
tracks: tracks.map(t => ({ track: t.track, status: t.status, userFraction: t.status === 'inProgress' ? Number(fraction ?? 0.1) : null })), dry: a.has('dry'), ...(seen.kind ? { releaseKind: seen.kind.kind } : {}) });
|
||||
done('play', 'release done');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ afterEach(() => { uninstallStores(); });
|
|||
|
||||
const edits = (what: string): string[] => s.calls.filter(c => c.method === 'POST' && c.path.includes(`:${what}`)).map(c => c.path.replace(/^.*\/edits\//, ''));
|
||||
const release = (p: ReturnType<typeof project>, extra: string[] = []) =>
|
||||
capture(() => playRelease(p.ctx(['--version-code', '5', '--internal', 'completed', '--production', 'completed', '--name', '1.0.1 (5)', '--yes', ...extra])));
|
||||
capture(() => playRelease(p.ctx(['--version-code', '5', '--internal', 'completed', '--production', 'completed', '--name', '1.0.1 (5)', '--yes', '--first-release', ...extra])));
|
||||
|
||||
describe('Play refuses the automatic send for review', () => {
|
||||
test('the 400 is recognised by its message (and a bad-request reason), nothing else', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue