@makefully/adaptfully 4.2.2 → 4.3.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/CHANGELOG.md +11 -0
- package/README.md +4 -0
- package/lib/node/artifacts.js +55 -9
- package/lib/node/deploy.js +7 -4
- package/lib/node/index.js +2 -2
- package/lib/node/pipeline.js +101 -27
- package/lib/node/report.js +7 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## 4.3.0 — 2026-09-11
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Sequential multi-platform stages** — `adaptfully release steam,android,ios` (or `--platforms steam,android,ios`) runs each platform in order. Failures are collected; the command exits non-zero if any platform failed.
|
|
10
|
+
- Multi-platform extracts land in `output/<platform>/` so sibling results are preserved. Only that folder’s prior `artifacts/` / wrapfully status files are cleared before each extract (single-platform still uses `output/`).
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Build report failures throw instead of calling `process.exit`, so sequential platform runs can continue and report a summary.
|
|
15
|
+
|
|
5
16
|
## 4.2.2 — 2026-09-10
|
|
6
17
|
|
|
7
18
|
### Added
|
package/README.md
CHANGED
|
@@ -30,6 +30,8 @@ adaptfully prebuild web # deploy/ → output/web-prebuild/
|
|
|
30
30
|
adaptfully build steam # Yap /yap/wrapfully chore → artifact zip
|
|
31
31
|
adaptfully deploy web --deployment web-prod # Yap deploy chore
|
|
32
32
|
adaptfully release android --encrypt # optional envelope encryption
|
|
33
|
+
adaptfully release steam,android,ios # sequential platforms; extracts to output/<platform>/
|
|
34
|
+
adaptfully release --platforms steam,android # same, flag form
|
|
33
35
|
adaptfully steam-publish # one-time: log in with steamcmd → assets/meta/deployments/steam/steam.json
|
|
34
36
|
```
|
|
35
37
|
|
|
@@ -45,6 +47,8 @@ adaptfully steam-publish # one-time: log in with steamcmd
|
|
|
45
47
|
| `android-keystore` | One-time local setup: generate debug/release keystores and write `android` `build.json` (also updates `.gitignore`) |
|
|
46
48
|
| `apple-signing` | One-time local setup: CSR → Apple `.cer` → `.p12` / provisioning profiles under `ios/apple/` (also updates `.gitignore`) |
|
|
47
49
|
|
|
50
|
+
Comma-separated platforms (or `--platforms`) run **sequentially**. Multi-platform extracts go to `output/<platform>/` so sibling results are not overwritten; only that folder’s prior `artifacts/` / status files are cleared before each extract. A single platform still extracts to `output/` for backward compatibility.
|
|
51
|
+
|
|
48
52
|
**Server** means the Showfully Yap base (`SHOWFULLY_SERVER` / `wrapfully.json` `showfullyServer` or `server`), default `https://make.makefullystudios.com/`. Wrapfully workers claim chores with a separate service token.
|
|
49
53
|
|
|
50
54
|
**Encryption (optional):** `--encrypt` or `"encrypt": true` wraps the chore to the Makefully Wrapfully fleet public key (override with `--encrypt-public-key`). Results are decrypted locally with an ephemeral `resultPriv` kept only for that chore.
|
package/lib/node/artifacts.js
CHANGED
|
@@ -17,13 +17,31 @@ export function buildOutputDir(pkg, outputRoot = 'output') {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* Where a platform's Wrapfully zip is extracted.
|
|
21
|
+
* Multi-platform runs use `output/<platformKey>/` so siblings are not overwritten.
|
|
22
|
+
* Single-platform runs keep `output/` for backward compatibility.
|
|
22
23
|
*
|
|
23
|
-
* @param {string}
|
|
24
|
+
* @param {string} outputRoot
|
|
25
|
+
* @param {string} [platformKey]
|
|
26
|
+
* @param {{ multiPlatform?: boolean }} [options]
|
|
27
|
+
* @returns {string}
|
|
24
28
|
*/
|
|
25
|
-
export function
|
|
29
|
+
export function resolveExtractRoot(outputRoot, platformKey, options = {}) {
|
|
26
30
|
const root = path.resolve(outputRoot);
|
|
31
|
+
if (options.multiPlatform && platformKey) {
|
|
32
|
+
return path.join(root, platformKey);
|
|
33
|
+
}
|
|
34
|
+
return root;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Remove prior extract artifacts in `extractRoot` only (artifacts/, status,
|
|
39
|
+
* manifest). Does not wipe sibling platform folders under output/.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} [extractRoot='output']
|
|
42
|
+
*/
|
|
43
|
+
export function clearStaleBuildExtract(extractRoot = 'output') {
|
|
44
|
+
const root = path.resolve(extractRoot);
|
|
27
45
|
const stalePaths = [
|
|
28
46
|
path.join(root, 'artifacts'),
|
|
29
47
|
path.join(root, MANIFEST_NAME),
|
|
@@ -39,17 +57,34 @@ export function clearStaleBuildExtract(outputRoot = 'output') {
|
|
|
39
57
|
* Resolve the artifact directory from a prior `adaptfully build` (or compatible zip extract).
|
|
40
58
|
*
|
|
41
59
|
* @param {{ name: string, version: string, config?: { outputFolder?: string } }} pkg
|
|
42
|
-
* @param {{ outputRoot?: string, platformKey?: string }} [options]
|
|
60
|
+
* @param {{ outputRoot?: string, platformKey?: string, multiPlatform?: boolean }} [options]
|
|
43
61
|
* @returns {string}
|
|
44
62
|
*/
|
|
45
63
|
export function resolveBuildArtifactDir(pkg, options = {}) {
|
|
46
|
-
const
|
|
47
|
-
const
|
|
64
|
+
const outputRoot = buildOutputDir(pkg, options.outputRoot);
|
|
65
|
+
const candidates = [];
|
|
48
66
|
|
|
49
|
-
if (
|
|
67
|
+
if (options.platformKey) {
|
|
68
|
+
candidates.push(resolveExtractRoot(outputRoot, options.platformKey, { multiPlatform: true }));
|
|
69
|
+
}
|
|
70
|
+
candidates.push(outputRoot);
|
|
71
|
+
|
|
72
|
+
let artifactDir = null;
|
|
73
|
+
let manifestPath = null;
|
|
74
|
+
|
|
75
|
+
for (const candidate of candidates) {
|
|
76
|
+
const candidateManifest = path.join(candidate, MANIFEST_NAME);
|
|
77
|
+
if (fs.existsSync(candidateManifest)) {
|
|
78
|
+
artifactDir = candidate;
|
|
79
|
+
manifestPath = candidateManifest;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!artifactDir || !manifestPath) {
|
|
50
85
|
throw new Error(
|
|
51
86
|
'No prior build artifact found in '
|
|
52
|
-
+ `${
|
|
87
|
+
+ `${candidates.join(' or ')}. Run \`adaptfully build <platform>\` first or pass --artifact <path>.`,
|
|
53
88
|
);
|
|
54
89
|
}
|
|
55
90
|
|
|
@@ -77,3 +112,14 @@ export function resolveBuildArtifactDir(pkg, options = {}) {
|
|
|
77
112
|
|
|
78
113
|
return artifactDir;
|
|
79
114
|
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @param {string} value
|
|
118
|
+
* @returns {string[]}
|
|
119
|
+
*/
|
|
120
|
+
export function parsePlatformList(value) {
|
|
121
|
+
return String(value ?? '')
|
|
122
|
+
.split(',')
|
|
123
|
+
.map((entry) => entry.trim())
|
|
124
|
+
.filter(Boolean);
|
|
125
|
+
}
|
package/lib/node/deploy.js
CHANGED
|
@@ -197,6 +197,7 @@ export async function submitWrapfullyChore ({
|
|
|
197
197
|
* encrypt?: boolean,
|
|
198
198
|
* encryptPublicKey?: string,
|
|
199
199
|
* wrapfullyConfig?: object,
|
|
200
|
+
* extractRoot?: string,
|
|
200
201
|
* }} [options]
|
|
201
202
|
*/
|
|
202
203
|
export async function send (
|
|
@@ -213,6 +214,7 @@ export async function send (
|
|
|
213
214
|
const log = options.log ?? console.log;
|
|
214
215
|
const platformKey = options.platformKey ?? family;
|
|
215
216
|
const outputRoot = pkg.config?.outputFolder || 'output';
|
|
217
|
+
const extractRoot = path.resolve(options.extractRoot || outputRoot);
|
|
216
218
|
const accessToken = options.accessToken;
|
|
217
219
|
|
|
218
220
|
if (!accessToken) {
|
|
@@ -220,7 +222,8 @@ export async function send (
|
|
|
220
222
|
}
|
|
221
223
|
|
|
222
224
|
if (mode === 'extract') {
|
|
223
|
-
|
|
225
|
+
fs.mkdirSync(extractRoot, { recursive: true });
|
|
226
|
+
clearStaleBuildExtract(extractRoot);
|
|
224
227
|
}
|
|
225
228
|
|
|
226
229
|
let archiveStream;
|
|
@@ -336,8 +339,8 @@ export async function send (
|
|
|
336
339
|
}
|
|
337
340
|
|
|
338
341
|
const destination = mode === 'extract'
|
|
339
|
-
? unzipper.Extract({path: `${
|
|
340
|
-
: fs.createWriteStream(`${
|
|
342
|
+
? unzipper.Extract({path: `${extractRoot}/`, concurrency: 1})
|
|
343
|
+
: fs.createWriteStream(`${extractRoot}/${pkg.name}-${pkg.version}-${stage}-${family}.zip`);
|
|
341
344
|
|
|
342
345
|
try {
|
|
343
346
|
await pipeline(Readable.from(resultBuffer), destination);
|
|
@@ -348,6 +351,6 @@ export async function send (
|
|
|
348
351
|
}
|
|
349
352
|
|
|
350
353
|
if (mode === 'extract') {
|
|
351
|
-
printBuildReport(`${stage}-${family}`, pkg);
|
|
354
|
+
printBuildReport(`${stage}-${family}`, pkg, { extractRoot });
|
|
352
355
|
}
|
|
353
356
|
}
|
package/lib/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildOutputDir, clearStaleBuildExtract, resolveBuildArtifactDir } from './artifacts.js';
|
|
1
|
+
export { buildOutputDir, clearStaleBuildExtract, parsePlatformList, resolveBuildArtifactDir, resolveExtractRoot } from './artifacts.js';
|
|
2
2
|
export { createArchive, createDeployArchive, createReleaseArchive, createSourceArchive } from './archive.js';
|
|
3
3
|
export { loadProjectConfig, resolveServerUrl } from './config.js';
|
|
4
4
|
export {
|
|
@@ -18,7 +18,7 @@ export {
|
|
|
18
18
|
resolveMetaIcons,
|
|
19
19
|
resolvePlaceholderIconPath,
|
|
20
20
|
} from './icons.js';
|
|
21
|
-
export { adaptfullyFromCli, parseStageArgs, resolveWrapfullyRoute, runAdaptfullyStage } from './pipeline.js';
|
|
21
|
+
export { adaptfullyFromCli, parseStageArgs, resolveWrapfullyRoute, runAdaptfullyStage, runAdaptfullyStages } from './pipeline.js';
|
|
22
22
|
export { prebuildPlatform, prebuildOutputDir, resolveHtmlInjections } from './prebuild.js';
|
|
23
23
|
export { getPackageRoot, getRuntimeDir, resolveRuntimeScript } from './paths.js';
|
|
24
24
|
export {
|
package/lib/node/pipeline.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { loadProjectConfig, resolveServerUrl, resolveAccessToken, resolveEncryptFlag } from './config.js';
|
|
3
3
|
import { send } from './deploy.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
buildOutputDir,
|
|
6
|
+
parsePlatformList,
|
|
7
|
+
resolveBuildArtifactDir,
|
|
8
|
+
resolveExtractRoot,
|
|
9
|
+
} from './artifacts.js';
|
|
5
10
|
import { prebuildPlatform } from './prebuild.js';
|
|
6
11
|
import {
|
|
7
12
|
resolveBuildCredentialDirs,
|
|
@@ -44,7 +49,7 @@ export function resolveWrapfullyRoute(buildSpec) {
|
|
|
44
49
|
/**
|
|
45
50
|
* @param {AdaptfullyStage} stage
|
|
46
51
|
* @param {string} platformKey
|
|
47
|
-
* @param {{ pkg: object, deployFolder: string, server?: string, mode?: string, deployment?: string, artifactPath?: string, log?: (message: string) => void, outputRoot?: string, accessToken?: string, encrypt?: boolean, encryptPublicKey?: string, wrapfullyConfig?: object }} options
|
|
52
|
+
* @param {{ pkg: object, deployFolder: string, server?: string, mode?: string, deployment?: string, artifactPath?: string, log?: (message: string) => void, outputRoot?: string, accessToken?: string, encrypt?: boolean, encryptPublicKey?: string, wrapfullyConfig?: object, extractRoot?: string, multiPlatform?: boolean }} options
|
|
48
53
|
*/
|
|
49
54
|
export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
50
55
|
if (!VALID_STAGES.has(stage)) {
|
|
@@ -55,6 +60,9 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
55
60
|
const { pkg, deployFolder } = options;
|
|
56
61
|
const buildSpec = resolveBuildSpec(platformKey, pkg);
|
|
57
62
|
let deployments = resolveDeploymentsForPlatform(platformKey, pkg);
|
|
63
|
+
const outputRoot = buildOutputDir(pkg, options.outputRoot);
|
|
64
|
+
const extractRoot = options.extractRoot
|
|
65
|
+
?? resolveExtractRoot(outputRoot, platformKey, { multiPlatform: options.multiPlatform === true });
|
|
58
66
|
|
|
59
67
|
if (options.deployment) {
|
|
60
68
|
if (!deployments.includes(options.deployment)) {
|
|
@@ -77,6 +85,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
77
85
|
artifactPath = resolveBuildArtifactDir(pkg, {
|
|
78
86
|
outputRoot: options.outputRoot,
|
|
79
87
|
platformKey,
|
|
88
|
+
multiPlatform: options.multiPlatform,
|
|
80
89
|
});
|
|
81
90
|
}
|
|
82
91
|
|
|
@@ -88,7 +97,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
88
97
|
});
|
|
89
98
|
|
|
90
99
|
if (stage === 'prebuild') {
|
|
91
|
-
return { prebuiltDir, platformKey, buildSpec };
|
|
100
|
+
return { prebuiltDir, platformKey, buildSpec, extractRoot };
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
const gameId = `${pkg.name}-${pkg.version}`;
|
|
@@ -97,6 +106,15 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
97
106
|
const sent = [];
|
|
98
107
|
|
|
99
108
|
const wrapfullyRoute = resolveWrapfullyRoute(buildSpec);
|
|
109
|
+
const sendOptionsBase = {
|
|
110
|
+
log,
|
|
111
|
+
platformKey,
|
|
112
|
+
accessToken: options.accessToken,
|
|
113
|
+
encrypt: options.encrypt,
|
|
114
|
+
encryptPublicKey: options.encryptPublicKey,
|
|
115
|
+
wrapfullyConfig: options.wrapfullyConfig,
|
|
116
|
+
extractRoot,
|
|
117
|
+
};
|
|
100
118
|
|
|
101
119
|
if (stage === 'release') {
|
|
102
120
|
const deploymentDirs = deployments.map((key) => resolvePublishDir(key));
|
|
@@ -111,6 +129,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
111
129
|
deploymentDirs.map((dir) => path.resolve(dir)).join(', ') || '(none)'
|
|
112
130
|
}`,
|
|
113
131
|
);
|
|
132
|
+
log(`adaptfully: extract → ${extractRoot}`);
|
|
114
133
|
|
|
115
134
|
await send(
|
|
116
135
|
gameId,
|
|
@@ -122,18 +141,13 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
122
141
|
pkg,
|
|
123
142
|
options.mode ?? 'extract',
|
|
124
143
|
{
|
|
125
|
-
|
|
126
|
-
platformKey,
|
|
144
|
+
...sendOptionsBase,
|
|
127
145
|
deploymentDirs: deploymentDirs.map((dir) => path.resolve(dir)),
|
|
128
|
-
accessToken: options.accessToken,
|
|
129
|
-
encrypt: options.encrypt,
|
|
130
|
-
encryptPublicKey: options.encryptPublicKey,
|
|
131
|
-
wrapfullyConfig: options.wrapfullyConfig,
|
|
132
146
|
},
|
|
133
147
|
);
|
|
134
148
|
|
|
135
149
|
sent.push({ deploymentKey: 'release', stage, family: buildSpec.family });
|
|
136
|
-
return { prebuiltDir, platformKey, buildSpec, deployments: sent, artifactPath };
|
|
150
|
+
return { prebuiltDir, platformKey, buildSpec, deployments: sent, artifactPath, extractRoot };
|
|
137
151
|
}
|
|
138
152
|
|
|
139
153
|
for (const deploymentKey of deployments) {
|
|
@@ -156,6 +170,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
156
170
|
}`,
|
|
157
171
|
);
|
|
158
172
|
}
|
|
173
|
+
log(`adaptfully: extract → ${extractRoot}`);
|
|
159
174
|
|
|
160
175
|
await send(
|
|
161
176
|
gameId,
|
|
@@ -167,23 +182,62 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
167
182
|
pkg,
|
|
168
183
|
options.mode ?? 'extract',
|
|
169
184
|
{
|
|
170
|
-
|
|
185
|
+
...sendOptionsBase,
|
|
171
186
|
publishDir,
|
|
172
187
|
deploymentDirs,
|
|
173
|
-
platformKey,
|
|
174
188
|
deploymentKey: wrapStage === 'deploy' ? deploymentKey : undefined,
|
|
175
189
|
artifactPath,
|
|
176
|
-
accessToken: options.accessToken,
|
|
177
|
-
encrypt: options.encrypt,
|
|
178
|
-
encryptPublicKey: options.encryptPublicKey,
|
|
179
|
-
wrapfullyConfig: options.wrapfullyConfig,
|
|
180
190
|
},
|
|
181
191
|
);
|
|
182
192
|
|
|
183
193
|
sent.push({ deploymentKey, stage: wrapStage, family: buildSpec.family });
|
|
184
194
|
}
|
|
185
195
|
|
|
186
|
-
return { prebuiltDir, platformKey, buildSpec, deployments: sent, artifactPath };
|
|
196
|
+
return { prebuiltDir, platformKey, buildSpec, deployments: sent, artifactPath, extractRoot };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Run a stage for one or more platforms sequentially.
|
|
201
|
+
* Multi-platform extracts land in `output/<platformKey>/` so outputs do not overwrite.
|
|
202
|
+
*
|
|
203
|
+
* @param {AdaptfullyStage} stage
|
|
204
|
+
* @param {string[]} platformKeys
|
|
205
|
+
* @param {Parameters<typeof runAdaptfullyStage>[2]} options
|
|
206
|
+
*/
|
|
207
|
+
export async function runAdaptfullyStages(stage, platformKeys, options) {
|
|
208
|
+
const log = options.log ?? console.log;
|
|
209
|
+
const multiPlatform = platformKeys.length > 1;
|
|
210
|
+
/** @type {{ platformKey: string, ok: boolean, result?: object, error?: Error }[]} */
|
|
211
|
+
const results = [];
|
|
212
|
+
|
|
213
|
+
if (multiPlatform) {
|
|
214
|
+
log(`adaptfully: sequential ${stage} for ${platformKeys.join(', ')}`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
for (const platformKey of platformKeys) {
|
|
218
|
+
log(`adaptfully: ——— ${stage} ${platformKey} ———`);
|
|
219
|
+
try {
|
|
220
|
+
const result = await runAdaptfullyStage(stage, platformKey, {
|
|
221
|
+
...options,
|
|
222
|
+
multiPlatform,
|
|
223
|
+
});
|
|
224
|
+
results.push({ platformKey, ok: true, result });
|
|
225
|
+
} catch (err) {
|
|
226
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
227
|
+
console.error(`adaptfully: ${stage} ${platformKey} failed: ${error.message}`);
|
|
228
|
+
results.push({ platformKey, ok: false, error });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const failed = results.filter((entry) => !entry.ok);
|
|
233
|
+
if (failed.length) {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`adaptfully: ${failed.length}/${results.length} platform(s) failed: `
|
|
236
|
+
+ failed.map((entry) => entry.platformKey).join(', '),
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return results;
|
|
187
241
|
}
|
|
188
242
|
|
|
189
243
|
/**
|
|
@@ -202,16 +256,23 @@ export async function adaptfullyFromCli(argv = process.argv) {
|
|
|
202
256
|
}
|
|
203
257
|
|
|
204
258
|
const stage = command;
|
|
205
|
-
const {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
259
|
+
const {
|
|
260
|
+
positionals,
|
|
261
|
+
deployment,
|
|
262
|
+
artifactPath,
|
|
263
|
+
encrypt,
|
|
264
|
+
encryptPublicKey,
|
|
265
|
+
platforms,
|
|
266
|
+
} = parseStageArgs(argv.slice(3));
|
|
267
|
+
const platformArg = platforms || positionals[0];
|
|
268
|
+
const cliServer = platforms ? positionals[0] : positionals[1];
|
|
269
|
+
const mode = platforms ? (positionals[1] ?? 'extract') : (positionals[2] ?? 'extract');
|
|
209
270
|
|
|
210
|
-
if (!stage || !
|
|
271
|
+
if (!stage || !platformArg) {
|
|
211
272
|
throw new Error(
|
|
212
273
|
'Usage:\n'
|
|
213
|
-
+ ' adaptfully <prebuild|build|deploy|release> <platform> [showfullyServer] [mode]\n'
|
|
214
|
-
+ ' [--deployment <key>] [--artifact <path>] [--encrypt] [--encrypt-public-key <pem|path>]\n'
|
|
274
|
+
+ ' adaptfully <prebuild|build|deploy|release> <platform[,platform...]> [showfullyServer] [mode]\n'
|
|
275
|
+
+ ' [--platforms a,b,c] [--deployment <key>] [--artifact <path>] [--encrypt] [--encrypt-public-key <pem|path>]\n'
|
|
215
276
|
+ ' adaptfully steam-publish [--username U] [--password P] [--deployment steam] [--output path]\n'
|
|
216
277
|
+ ' adaptfully google-publish [--from service-account.json] [--deployment android] [--output path]\n'
|
|
217
278
|
+ ' adaptfully apple-publish [--deployment ios] [--category C] [--identity I] [--username U] [--password P]\n'
|
|
@@ -224,6 +285,9 @@ export async function adaptfullyFromCli(argv = process.argv) {
|
|
|
224
285
|
+ ' deploy Yap deploy chore with prior artifact + deployment credentials\n'
|
|
225
286
|
+ ' release Yap release chore (build + configured deployments)\n'
|
|
226
287
|
+ '\n'
|
|
288
|
+
+ ' Multiple platforms (comma-separated or --platforms) run sequentially.\n'
|
|
289
|
+
+ ' Multi-platform extracts go to output/<platform>/ so siblings are preserved.\n'
|
|
290
|
+
+ '\n'
|
|
227
291
|
+ ' --deployment <key> Target a single named deployment.\n'
|
|
228
292
|
+ ' --artifact <path> Prior build artifact directory (deploy only; default: ./output/ after build).\n'
|
|
229
293
|
+ ' --encrypt Envelope-encrypt chore to Wrapfully (optional; default key embedded).\n'
|
|
@@ -242,13 +306,18 @@ export async function adaptfullyFromCli(argv = process.argv) {
|
|
|
242
306
|
);
|
|
243
307
|
}
|
|
244
308
|
|
|
309
|
+
const platformKeys = parsePlatformList(platformArg);
|
|
310
|
+
if (!platformKeys.length) {
|
|
311
|
+
throw new Error('At least one platform is required.');
|
|
312
|
+
}
|
|
313
|
+
|
|
245
314
|
const { pkg, wrapfullyConfig } = await loadProjectConfig();
|
|
246
315
|
const server = resolveServerUrl(wrapfullyConfig, cliServer);
|
|
247
316
|
const accessToken = resolveAccessToken(wrapfullyConfig);
|
|
248
317
|
const encryptFlag = resolveEncryptFlag(wrapfullyConfig, encrypt);
|
|
249
318
|
const deployFolder = pkg.config?.deployFolder || 'deploy';
|
|
250
319
|
|
|
251
|
-
return
|
|
320
|
+
return runAdaptfullyStages(/** @type {AdaptfullyStage} */ (stage), platformKeys, {
|
|
252
321
|
pkg,
|
|
253
322
|
deployFolder,
|
|
254
323
|
server,
|
|
@@ -264,7 +333,7 @@ export async function adaptfullyFromCli(argv = process.argv) {
|
|
|
264
333
|
|
|
265
334
|
/**
|
|
266
335
|
* @param {string[]} args
|
|
267
|
-
* @returns {{ positionals: string[], deployment?: string, artifactPath?: string, encrypt?: boolean, encryptPublicKey?: string }}
|
|
336
|
+
* @returns {{ positionals: string[], deployment?: string, artifactPath?: string, encrypt?: boolean, encryptPublicKey?: string, platforms?: string }}
|
|
268
337
|
*/
|
|
269
338
|
export function parseStageArgs(args) {
|
|
270
339
|
/** @type {string[]} */
|
|
@@ -273,6 +342,7 @@ export function parseStageArgs(args) {
|
|
|
273
342
|
let artifactPath;
|
|
274
343
|
let encrypt;
|
|
275
344
|
let encryptPublicKey;
|
|
345
|
+
let platforms;
|
|
276
346
|
|
|
277
347
|
for (let i = 0; i < args.length; i++) {
|
|
278
348
|
const arg = args[i];
|
|
@@ -281,6 +351,10 @@ export function parseStageArgs(args) {
|
|
|
281
351
|
deployment = args[++i];
|
|
282
352
|
} else if (arg.startsWith('--deployment=')) {
|
|
283
353
|
deployment = arg.slice('--deployment='.length);
|
|
354
|
+
} else if (arg === '--platforms' && args[i + 1]) {
|
|
355
|
+
platforms = args[++i];
|
|
356
|
+
} else if (arg.startsWith('--platforms=')) {
|
|
357
|
+
platforms = arg.slice('--platforms='.length);
|
|
284
358
|
} else if (arg === '--artifact' && args[i + 1]) {
|
|
285
359
|
artifactPath = args[++i];
|
|
286
360
|
} else if (arg.startsWith('--artifact=')) {
|
|
@@ -296,5 +370,5 @@ export function parseStageArgs(args) {
|
|
|
296
370
|
}
|
|
297
371
|
}
|
|
298
372
|
|
|
299
|
-
return { positionals, deployment, artifactPath, encrypt, encryptPublicKey };
|
|
373
|
+
return { positionals, deployment, artifactPath, encrypt, encryptPublicKey, platforms };
|
|
300
374
|
}
|
package/lib/node/report.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* @param {string} builder
|
|
5
6
|
* @param {{ name: string, version: string }} pkg
|
|
7
|
+
* @param {{ extractRoot?: string }} [options]
|
|
6
8
|
*/
|
|
7
|
-
export function printBuildReport(builder, pkg) {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
9
|
+
export function printBuildReport(builder, pkg, options = {}) {
|
|
10
|
+
const extractRoot = path.resolve(options.extractRoot || './output');
|
|
11
|
+
const statusPath = path.join(extractRoot, 'wrapfully-status.json');
|
|
12
|
+
const legacyPath = path.join(extractRoot, `${pkg.name}-${pkg.version}-${builder}.txt`);
|
|
10
13
|
|
|
11
14
|
let status = null;
|
|
12
15
|
if (fs.existsSync(statusPath)) {
|
|
@@ -30,8 +33,7 @@ export function printBuildReport(builder, pkg) {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
if (!status.ok) {
|
|
33
|
-
|
|
34
|
-
process.exit(1);
|
|
36
|
+
throw new Error('Wrapfully build finished with errors.');
|
|
35
37
|
}
|
|
36
38
|
return;
|
|
37
39
|
}
|