@mpgd/cli 0.35.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/android-bundle-signer.d.ts +2 -0
- package/dist/android-bundle-signer.js +38 -0
- package/dist/android-signing-session.d.ts +22 -0
- package/dist/android-signing-session.js +198 -0
- package/dist/artifact-inspection-environment.d.ts +2 -0
- package/dist/artifact-inspection-environment.js +31 -0
- package/dist/asc-pin.json +26 -0
- package/dist/capacitor-shell-starter.d.ts +1 -0
- package/dist/capacitor-shell-starter.js +9 -6
- package/dist/deploy-planning.d.ts +64 -0
- package/dist/deploy-planning.js +471 -0
- package/dist/deploy-process.d.ts +28 -0
- package/dist/deploy-process.js +197 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +409 -10
- package/dist/ios-ipa-inspection.js +151 -0
- package/dist/ios-keychain-import.swift +92 -0
- package/dist/ios-plist.d.ts +2 -0
- package/dist/ios-plist.js +75 -0
- package/dist/ios-signing-profile.d.ts +12 -0
- package/dist/ios-signing-profile.js +60 -0
- package/dist/ios-signing-session.d.ts +22 -0
- package/dist/ios-signing-session.js +256 -0
- package/dist/kit-upgrade-target-readiness.d.ts +8 -0
- package/dist/kit-upgrade-target-readiness.js +119 -0
- package/dist/kit-upgrade.d.ts +2 -0
- package/dist/kit-upgrade.js +3 -0
- package/dist/native-build-info.json +5 -0
- package/dist/native-build-target.js +12032 -0
- package/dist/native-deploy-run.d.ts +35 -0
- package/dist/native-deploy-run.js +462 -0
- package/dist/native-deploy-submission.d.ts +40 -0
- package/dist/native-deploy-submission.js +244 -0
- package/dist/native-deploy-workflow.d.ts +11 -0
- package/dist/native-deploy-workflow.js +328 -0
- package/dist/play-internal-submission.d.ts +32 -0
- package/dist/play-internal-submission.js +247 -0
- package/dist/play-publisher-port.d.ts +30 -0
- package/dist/play-publisher-port.js +1 -0
- package/dist/play-sdk-adapter.js +78 -0
- package/dist/release-state.d.ts +140 -0
- package/dist/release-state.js +1046 -0
- package/dist/release-workspace.d.ts +61 -0
- package/dist/release-workspace.js +504 -0
- package/dist/testflight-submission.d.ts +49 -0
- package/dist/testflight-submission.js +462 -0
- package/package.json +18 -13
- package/templates/phaser-game/README.md +23 -8
- package/templates/phaser-game/src/main.ts +34 -33
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
2
|
+
const reasonLabels = {
|
|
3
|
+
abort: 'aborted',
|
|
4
|
+
exit: 'failed',
|
|
5
|
+
spawn: 'could not start',
|
|
6
|
+
timeout: 'timed out',
|
|
7
|
+
};
|
|
8
|
+
export class ReleaseProcessError extends Error {
|
|
9
|
+
reason;
|
|
10
|
+
output;
|
|
11
|
+
exitCode;
|
|
12
|
+
constructor(reason, output, exitCode) {
|
|
13
|
+
super(`Release process ${reasonLabels[reason]}${output === '' ? '.' : `:\n${output}`}`);
|
|
14
|
+
this.name = 'ReleaseProcessError';
|
|
15
|
+
this.reason = reason;
|
|
16
|
+
this.output = output;
|
|
17
|
+
if (exitCode !== undefined) {
|
|
18
|
+
this.exitCode = exitCode;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const defaultMaxOutputBytes = 256 * 1024;
|
|
23
|
+
const sensitiveEnvironmentKey = /(?:^|_)(?:PASSWORD|TOKEN|SECRET|CREDENTIAL|PRIVATE_KEY|API_KEY)(?:_|$)|^GIT_CONFIG_VALUE_\d+$/iu;
|
|
24
|
+
/** Execute a release step without streaming unredacted child output to logs. */
|
|
25
|
+
export async function runReleaseProcess(input) {
|
|
26
|
+
if (!Number.isSafeInteger(input.timeoutMs) || input.timeoutMs < 1) {
|
|
27
|
+
throw new Error('Release process timeoutMs must be a positive integer.');
|
|
28
|
+
}
|
|
29
|
+
const outputLimit = input.maxOutputBytes ?? defaultMaxOutputBytes;
|
|
30
|
+
if (!Number.isSafeInteger(outputLimit) || outputLimit < 1) {
|
|
31
|
+
throw new Error('Release process maxOutputBytes must be a positive integer.');
|
|
32
|
+
}
|
|
33
|
+
if (input.signal?.aborted) {
|
|
34
|
+
throw new ReleaseProcessError('abort', '');
|
|
35
|
+
}
|
|
36
|
+
const environment = input.environment ?? process.env;
|
|
37
|
+
const secrets = [
|
|
38
|
+
input.stdin ?? '',
|
|
39
|
+
...(input.secretValues ?? []),
|
|
40
|
+
...Object.entries(environment)
|
|
41
|
+
.filter(([key]) => sensitiveEnvironmentKey.test(key))
|
|
42
|
+
.map(([, value]) => value ?? ''),
|
|
43
|
+
].filter((value) => value.length > 0);
|
|
44
|
+
const launch = resolveReleaseCommand(input.command, input.args, environment);
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
let child;
|
|
47
|
+
try {
|
|
48
|
+
child = spawn(launch.command, [...launch.args], {
|
|
49
|
+
cwd: input.cwd,
|
|
50
|
+
env: environment,
|
|
51
|
+
stdio: [input.stdin === undefined ? 'ignore' : 'pipe', 'pipe', 'pipe'],
|
|
52
|
+
detached: process.platform !== 'win32',
|
|
53
|
+
shell: false,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
reject(new ReleaseProcessError('spawn', ''));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const stdoutChunks = [];
|
|
61
|
+
const stderrChunks = [];
|
|
62
|
+
let capturedBytes = 0;
|
|
63
|
+
let truncated = false;
|
|
64
|
+
let stdoutTruncated = false;
|
|
65
|
+
let stderrTruncated = false;
|
|
66
|
+
let stopReason;
|
|
67
|
+
let settled = false;
|
|
68
|
+
let escalation;
|
|
69
|
+
if (input.stdin !== undefined) {
|
|
70
|
+
child.stdin?.on('error', () => {
|
|
71
|
+
// The child may exit before consuming a short secret input.
|
|
72
|
+
});
|
|
73
|
+
child.stdin?.end(input.stdin);
|
|
74
|
+
}
|
|
75
|
+
const capture = (stream, chunk) => {
|
|
76
|
+
const available = Math.max(0, outputLimit - capturedBytes);
|
|
77
|
+
if (available > 0) {
|
|
78
|
+
const selected = chunk.subarray(0, available);
|
|
79
|
+
(stream === 'stdout' ? stdoutChunks : stderrChunks).push(selected);
|
|
80
|
+
capturedBytes += selected.length;
|
|
81
|
+
}
|
|
82
|
+
if (chunk.length > available) {
|
|
83
|
+
truncated = true;
|
|
84
|
+
if (stream === 'stdout') {
|
|
85
|
+
stdoutTruncated = true;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
stderrTruncated = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
child.stdout?.on('data', (chunk) => capture('stdout', chunk));
|
|
93
|
+
child.stderr?.on('data', (chunk) => capture('stderr', chunk));
|
|
94
|
+
const renderOutput = () => {
|
|
95
|
+
const longestSecretBytes = secrets.reduce((longest, secret) => Math.max(longest, Buffer.byteLength(secret)), 0);
|
|
96
|
+
const renderStream = (chunks, wasTruncated) => {
|
|
97
|
+
const captured = Buffer.concat(chunks);
|
|
98
|
+
const safeBytes = wasTruncated
|
|
99
|
+
? captured.subarray(0, Math.max(0, captured.length - longestSecretBytes))
|
|
100
|
+
: captured;
|
|
101
|
+
let output = safeBytes.toString('utf8');
|
|
102
|
+
for (const secret of [...new Set(secrets)].sort((a, b) => b.length - a.length)) {
|
|
103
|
+
output = output.replaceAll(secret, '[REDACTED]');
|
|
104
|
+
}
|
|
105
|
+
return output;
|
|
106
|
+
};
|
|
107
|
+
const output = [
|
|
108
|
+
renderStream(stdoutChunks, stdoutTruncated),
|
|
109
|
+
renderStream(stderrChunks, stderrTruncated),
|
|
110
|
+
].filter((part) => part !== '').join('\n');
|
|
111
|
+
return truncated ? `${output}\n[output truncated]` : output;
|
|
112
|
+
};
|
|
113
|
+
const terminate = (reason) => {
|
|
114
|
+
if (settled || stopReason !== undefined) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
stopReason = reason;
|
|
118
|
+
killReleaseProcess(child.pid, 'SIGTERM');
|
|
119
|
+
escalation = setTimeout(() => killReleaseProcess(child.pid, 'SIGKILL'), 2_000);
|
|
120
|
+
escalation.unref();
|
|
121
|
+
};
|
|
122
|
+
const onAbort = () => terminate('abort');
|
|
123
|
+
input.signal?.addEventListener('abort', onAbort, { once: true });
|
|
124
|
+
if (input.signal?.aborted) {
|
|
125
|
+
onAbort();
|
|
126
|
+
}
|
|
127
|
+
const timeout = setTimeout(() => terminate('timeout'), input.timeoutMs);
|
|
128
|
+
timeout.unref();
|
|
129
|
+
const cleanup = () => {
|
|
130
|
+
settled = true;
|
|
131
|
+
clearTimeout(timeout);
|
|
132
|
+
if (escalation !== undefined) {
|
|
133
|
+
clearTimeout(escalation);
|
|
134
|
+
}
|
|
135
|
+
input.signal?.removeEventListener('abort', onAbort);
|
|
136
|
+
};
|
|
137
|
+
child.once('error', () => {
|
|
138
|
+
if (settled) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
cleanup();
|
|
142
|
+
reject(new ReleaseProcessError('spawn', renderOutput()));
|
|
143
|
+
});
|
|
144
|
+
child.once('close', (code) => {
|
|
145
|
+
if (settled) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (stopReason !== undefined) {
|
|
149
|
+
// The direct child may exit while a build tool it spawned is still alive.
|
|
150
|
+
killReleaseProcess(child.pid, 'SIGKILL');
|
|
151
|
+
}
|
|
152
|
+
cleanup();
|
|
153
|
+
const output = renderOutput();
|
|
154
|
+
if (stopReason !== undefined) {
|
|
155
|
+
reject(new ReleaseProcessError(stopReason, output));
|
|
156
|
+
}
|
|
157
|
+
else if (code !== 0) {
|
|
158
|
+
reject(new ReleaseProcessError('exit', output, code ?? undefined));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
resolve({
|
|
162
|
+
output,
|
|
163
|
+
truncated,
|
|
164
|
+
...(input.captureMachineStdout === true
|
|
165
|
+
? { machineStdout: Buffer.concat(stdoutChunks).toString('utf8') }
|
|
166
|
+
: {}),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
function resolveReleaseCommand(command, args, environment) {
|
|
173
|
+
if (process.platform !== 'win32' || command !== 'pnpm') {
|
|
174
|
+
return { command, args };
|
|
175
|
+
}
|
|
176
|
+
const pnpmScript = environment.npm_execpath;
|
|
177
|
+
if (pnpmScript === undefined || !/\.[cm]?js$/iu.test(pnpmScript)) {
|
|
178
|
+
throw new Error('Windows release steps require a pnpm JavaScript entrypoint. Run via pnpm.');
|
|
179
|
+
}
|
|
180
|
+
return { command: process.execPath, args: [pnpmScript, ...args] };
|
|
181
|
+
}
|
|
182
|
+
function killReleaseProcess(pid, signal) {
|
|
183
|
+
if (pid === undefined) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
if (process.platform === 'win32') {
|
|
188
|
+
spawnSync('taskkill', ['/PID', String(pid), '/T', '/F'], { stdio: 'ignore' });
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
process.kill(-pid, signal);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// The process may have exited between a timeout and termination.
|
|
196
|
+
}
|
|
197
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
export { renderGameAcceptanceMarkdown, resolveGameAcceptanceReleaseManifestFile, runGameAcceptance, defaultGameAcceptanceCommandTimeoutMs, maximumGameplayE2EReportBytes, type GameAcceptanceCommandResult, type GameAcceptanceCommandRunner, type GameAcceptanceReport, type GameAcceptanceStatus, type GameAcceptanceStep, type GameAcceptanceStepResult, type GameAcceptanceStepStatus, type RunGameAcceptanceInput, type RunGameAcceptanceResult, } from './game-acceptance.js';
|
|
2
2
|
export { applyCapacitorShellStarter, materializeCapacitorShellStarter, planCapacitorShellStarter, type CapacitorShellCommandRunner, type CapacitorShellStarterInput, type CapacitorShellStarterPlan, } from './capacitor-shell-starter.js';
|
|
3
|
+
export { ReleaseProcessError, runReleaseProcess, type ReleaseProcessInput, type ReleaseProcessResult, } from './deploy-process.js';
|
|
4
|
+
export { installPinnedReleaseDependencies, pinNativeDeploymentPlan, preparePinnedReleaseWorkspace, runPinnedNativeBuild, withPinnedReleaseWorkspace, type PinnedNativeBuildResult, type PinnedReleaseInput, type PinnedReleaseWorkspace, } from './release-workspace.js';
|
|
5
|
+
export { withAndroidUploadSigningSession, type AndroidUploadSigningInput, } from './android-signing-session.js';
|
|
6
|
+
export { checkpointNativeSubmission, readNativeReleaseStatus, reclaimNativeSubmission, releaseNativeSubmissionLease, recordNativeReleaseBuild, reserveNativeRelease, type ImmutableNativeBuildRecord, type NativeReleaseStatus, type NativeReleaseReservation, type NativeReleaseReservationInput, type NativeSubmissionCheckpoint, type NativeSubmissionStatus, type RecordNativeBuildInput, } from './release-state.js';
|
|
7
|
+
export { runNativeDeployment, readStoreCredential, type RunNativeDeploymentInput, } from './native-deploy-run.js';
|
|
8
|
+
export { submitRecordedNativeTarget, type NativeStoreCredential, type SubmitRecordedNativeTargetInput, } from './native-deploy-submission.js';
|
|
9
|
+
export { PlaySubmissionUncertainError, submitVerifiedAndroidBundle, type PlayInternalSubmissionInput, type PlayInternalSubmissionResult, } from './play-internal-submission.js';
|
|
10
|
+
export { IosSubmissionUncertainError, submitVerifiedIosBuild, type IosTestFlightStatus, type IosTestFlightSubmissionInput, type IosTestFlightSubmissionResult, } from './testflight-submission.js';
|
|
3
11
|
export { createBrowserGameplayE2EDriver, type BrowserGameplayE2EInspectInput, type BrowserGameplayE2EPage, type BrowserGameplayE2EScreenshotOptions, type BrowserGameplayE2EViewport, type CreateBrowserGameplayE2EDriverInput, } from './browser-gameplay-e2e.js';
|
|
4
12
|
export { collectGameplayE2EPathEvidence, defaultGameplayE2EReportFile, maximumGameplayE2EStates, parseGameplayE2EPlan, readGameplayE2EPlan, renderGameplayE2EMarkdown, resolveGameplayE2EReportFile, runGameplayE2E, type GameplayE2EAction, type GameplayE2EActionResult, type GameplayE2EDriver, type GameplayE2EHashLimits, type GameplayE2EInputAction, type GameplayE2EObservation, type GameplayE2EPauseResumeAction, type GameplayE2EPathEvidence, type GameplayE2EPlan, type GameplayE2EReport, type GameplayE2EResultStatus, type GameplayE2EState, type GameplayE2EStateResult, type GameplayE2EStatus, type RunGameplayE2EInput, type RunGameplayE2EResult, } from './gameplay-e2e.js';
|
|
5
13
|
export { cloudflarePagesDeploymentProfiles, hostedPwaDeploymentHosts, isSupportedHostedPwaProfile, verifyHostedPwaDeployment, type CloudflarePagesDeploymentProfile, type HostedPwaDeploymentHost, type HostedPwaDeploymentVerification, type VerifyHostedPwaDeploymentInput, } from './hosted-pwa-deployment.js';
|