@makefully/adaptfully 4.2.2 → 5.0.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 +17 -0
- package/README.md +10 -4
- package/lib/node/artifacts.js +54 -8
- package/lib/node/deploy.js +7 -4
- package/lib/node/index.js +2 -2
- package/lib/node/pipeline.js +97 -28
- package/lib/node/report.js +7 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## 5.0.0 — 2026-09-11
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- **Breaking:** Wrapfully extracts always land in `output/<platform>/` (including single-platform `build` / `release` / `deploy`). Sequential runs no longer overwrite siblings. Deploy still falls back to a legacy flat `output/` artifact if present.
|
|
10
|
+
|
|
11
|
+
## 4.3.0 — 2026-09-11
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **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.
|
|
16
|
+
- 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/`).
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Build report failures throw instead of calling `process.exit`, so sequential platform runs can continue and report a summary.
|
|
21
|
+
|
|
5
22
|
## 4.2.2 — 2026-09-10
|
|
6
23
|
|
|
7
24
|
### 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; each → 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**. Build/deploy/release extracts always go to `output/<platform>/` so sibling results are not overwritten; only that folder’s prior `artifacts/` / status files are cleared before each extract.
|
|
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.
|
|
@@ -279,7 +283,7 @@ import {
|
|
|
279
283
|
|
|
280
284
|
## Wrapfully deploy
|
|
281
285
|
|
|
282
|
-
After prebuild, the build and deploy stages zip `output/<platform>-prebuild/` and POST it to a Wrapfully build server. Artifacts are saved to `./output
|
|
286
|
+
After prebuild, the build and deploy stages zip `output/<platform>-prebuild/` and POST it to a Wrapfully build server. Artifacts are saved to `./output/<platform>/`.
|
|
283
287
|
|
|
284
288
|
## Quick start
|
|
285
289
|
|
|
@@ -318,7 +322,7 @@ npx adaptfully apple-publish [--deployment ios] [--category C] [--identity I] [-
|
|
|
318
322
|
|----------|---------|-------------|
|
|
319
323
|
| `platform` | — | Platform key from `config.platforms` (`web`, `steam`, etc.) |
|
|
320
324
|
| `server` | see below | Wrapfully server base URL (`build` and `deploy` only) |
|
|
321
|
-
| `mode` | `extract` | `extract` unpacks the response zip into `./output
|
|
325
|
+
| `mode` | `extract` | `extract` unpacks the response zip into `./output/<platform>/`; any other value saves `./output/<platform>/{name}-{version}-{builder}.zip` |
|
|
322
326
|
|
|
323
327
|
Examples:
|
|
324
328
|
|
|
@@ -398,7 +402,9 @@ mygame/
|
|
|
398
402
|
│ └── index.html
|
|
399
403
|
├── output/
|
|
400
404
|
│ ├── web-prebuild/ # after adaptfully prebuild web
|
|
401
|
-
│
|
|
405
|
+
│ ├── steam-prebuild/ # after adaptfully prebuild steam
|
|
406
|
+
│ ├── web/ # after adaptfully build/release web
|
|
407
|
+
│ └── steam/ # after adaptfully build/release steam
|
|
402
408
|
└── assets/
|
|
403
409
|
└── meta/ # shared files packaged as meta/ in the zip
|
|
404
410
|
├── icon-foreground.png
|
|
@@ -723,7 +729,7 @@ To sign the app, place your certificate at `assets/meta/deployments/<deployment>
|
|
|
723
729
|
|
|
724
730
|
## Response
|
|
725
731
|
|
|
726
|
-
The server responds with a zip stream containing build artifacts (`.apk`, `.aab`, `.ipa`, `.app`, `.exe`, etc.) and optional status files. By default the client extracts this into `./output
|
|
732
|
+
The server responds with a zip stream containing build artifacts (`.apk`, `.aab`, `.ipa`, `.app`, `.exe`, etc.) and optional status files. By default the client extracts this into `./output/<platform>/`. Use a non-`extract` mode value to save the raw response zip instead.
|
|
727
733
|
|
|
728
734
|
Every build also includes `wrapfully-status.json` with structured `success`, `warn`, and `error` events. The client prints these after extraction and exits with code 1 if any errors were reported, so build failures do not crash the server silently.
|
|
729
735
|
|
package/lib/node/artifacts.js
CHANGED
|
@@ -17,13 +17,30 @@ export function buildOutputDir(pkg, outputRoot = 'output') {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* Where a platform's Wrapfully zip is extracted: always `output/<platformKey>/`
|
|
21
|
+
* so sequential single-platform and multi-platform runs share one layout.
|
|
22
|
+
* Without a platform key, falls back to `outputRoot`.
|
|
22
23
|
*
|
|
23
|
-
* @param {string}
|
|
24
|
+
* @param {string} outputRoot
|
|
25
|
+
* @param {string} [platformKey]
|
|
26
|
+
* @returns {string}
|
|
24
27
|
*/
|
|
25
|
-
export function
|
|
28
|
+
export function resolveExtractRoot(outputRoot, platformKey) {
|
|
26
29
|
const root = path.resolve(outputRoot);
|
|
30
|
+
if (platformKey) {
|
|
31
|
+
return path.join(root, platformKey);
|
|
32
|
+
}
|
|
33
|
+
return root;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Remove prior extract artifacts in `extractRoot` only (artifacts/, status,
|
|
38
|
+
* manifest). Does not wipe sibling platform folders under output/.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} [extractRoot='output']
|
|
41
|
+
*/
|
|
42
|
+
export function clearStaleBuildExtract(extractRoot = 'output') {
|
|
43
|
+
const root = path.resolve(extractRoot);
|
|
27
44
|
const stalePaths = [
|
|
28
45
|
path.join(root, 'artifacts'),
|
|
29
46
|
path.join(root, MANIFEST_NAME),
|
|
@@ -37,19 +54,37 @@ export function clearStaleBuildExtract(outputRoot = 'output') {
|
|
|
37
54
|
|
|
38
55
|
/**
|
|
39
56
|
* Resolve the artifact directory from a prior `adaptfully build` (or compatible zip extract).
|
|
57
|
+
* Prefers `output/<platform>/`; still accepts a legacy flat `output/` extract.
|
|
40
58
|
*
|
|
41
59
|
* @param {{ name: string, version: string, config?: { outputFolder?: string } }} pkg
|
|
42
60
|
* @param {{ outputRoot?: string, platformKey?: string }} [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));
|
|
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 }} 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);
|
|
58
66
|
|
|
59
67
|
if (options.deployment) {
|
|
60
68
|
if (!deployments.includes(options.deployment)) {
|
|
@@ -88,7 +96,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
88
96
|
});
|
|
89
97
|
|
|
90
98
|
if (stage === 'prebuild') {
|
|
91
|
-
return { prebuiltDir, platformKey, buildSpec };
|
|
99
|
+
return { prebuiltDir, platformKey, buildSpec, extractRoot };
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
const gameId = `${pkg.name}-${pkg.version}`;
|
|
@@ -97,6 +105,15 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
97
105
|
const sent = [];
|
|
98
106
|
|
|
99
107
|
const wrapfullyRoute = resolveWrapfullyRoute(buildSpec);
|
|
108
|
+
const sendOptionsBase = {
|
|
109
|
+
log,
|
|
110
|
+
platformKey,
|
|
111
|
+
accessToken: options.accessToken,
|
|
112
|
+
encrypt: options.encrypt,
|
|
113
|
+
encryptPublicKey: options.encryptPublicKey,
|
|
114
|
+
wrapfullyConfig: options.wrapfullyConfig,
|
|
115
|
+
extractRoot,
|
|
116
|
+
};
|
|
100
117
|
|
|
101
118
|
if (stage === 'release') {
|
|
102
119
|
const deploymentDirs = deployments.map((key) => resolvePublishDir(key));
|
|
@@ -111,6 +128,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
111
128
|
deploymentDirs.map((dir) => path.resolve(dir)).join(', ') || '(none)'
|
|
112
129
|
}`,
|
|
113
130
|
);
|
|
131
|
+
log(`adaptfully: extract → ${extractRoot}`);
|
|
114
132
|
|
|
115
133
|
await send(
|
|
116
134
|
gameId,
|
|
@@ -122,18 +140,13 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
122
140
|
pkg,
|
|
123
141
|
options.mode ?? 'extract',
|
|
124
142
|
{
|
|
125
|
-
|
|
126
|
-
platformKey,
|
|
143
|
+
...sendOptionsBase,
|
|
127
144
|
deploymentDirs: deploymentDirs.map((dir) => path.resolve(dir)),
|
|
128
|
-
accessToken: options.accessToken,
|
|
129
|
-
encrypt: options.encrypt,
|
|
130
|
-
encryptPublicKey: options.encryptPublicKey,
|
|
131
|
-
wrapfullyConfig: options.wrapfullyConfig,
|
|
132
145
|
},
|
|
133
146
|
);
|
|
134
147
|
|
|
135
148
|
sent.push({ deploymentKey: 'release', stage, family: buildSpec.family });
|
|
136
|
-
return { prebuiltDir, platformKey, buildSpec, deployments: sent, artifactPath };
|
|
149
|
+
return { prebuiltDir, platformKey, buildSpec, deployments: sent, artifactPath, extractRoot };
|
|
137
150
|
}
|
|
138
151
|
|
|
139
152
|
for (const deploymentKey of deployments) {
|
|
@@ -156,6 +169,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
156
169
|
}`,
|
|
157
170
|
);
|
|
158
171
|
}
|
|
172
|
+
log(`adaptfully: extract → ${extractRoot}`);
|
|
159
173
|
|
|
160
174
|
await send(
|
|
161
175
|
gameId,
|
|
@@ -167,23 +181,58 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
167
181
|
pkg,
|
|
168
182
|
options.mode ?? 'extract',
|
|
169
183
|
{
|
|
170
|
-
|
|
184
|
+
...sendOptionsBase,
|
|
171
185
|
publishDir,
|
|
172
186
|
deploymentDirs,
|
|
173
|
-
platformKey,
|
|
174
187
|
deploymentKey: wrapStage === 'deploy' ? deploymentKey : undefined,
|
|
175
188
|
artifactPath,
|
|
176
|
-
accessToken: options.accessToken,
|
|
177
|
-
encrypt: options.encrypt,
|
|
178
|
-
encryptPublicKey: options.encryptPublicKey,
|
|
179
|
-
wrapfullyConfig: options.wrapfullyConfig,
|
|
180
189
|
},
|
|
181
190
|
);
|
|
182
191
|
|
|
183
192
|
sent.push({ deploymentKey, stage: wrapStage, family: buildSpec.family });
|
|
184
193
|
}
|
|
185
194
|
|
|
186
|
-
return { prebuiltDir, platformKey, buildSpec, deployments: sent, artifactPath };
|
|
195
|
+
return { prebuiltDir, platformKey, buildSpec, deployments: sent, artifactPath, extractRoot };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Run a stage for one or more platforms sequentially.
|
|
200
|
+
* Each platform extracts to `output/<platformKey>/`.
|
|
201
|
+
*
|
|
202
|
+
* @param {AdaptfullyStage} stage
|
|
203
|
+
* @param {string[]} platformKeys
|
|
204
|
+
* @param {Parameters<typeof runAdaptfullyStage>[2]} options
|
|
205
|
+
*/
|
|
206
|
+
export async function runAdaptfullyStages(stage, platformKeys, options) {
|
|
207
|
+
const log = options.log ?? console.log;
|
|
208
|
+
/** @type {{ platformKey: string, ok: boolean, result?: object, error?: Error }[]} */
|
|
209
|
+
const results = [];
|
|
210
|
+
|
|
211
|
+
if (platformKeys.length > 1) {
|
|
212
|
+
log(`adaptfully: sequential ${stage} for ${platformKeys.join(', ')}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for (const platformKey of platformKeys) {
|
|
216
|
+
log(`adaptfully: ——— ${stage} ${platformKey} ———`);
|
|
217
|
+
try {
|
|
218
|
+
const result = await runAdaptfullyStage(stage, platformKey, options);
|
|
219
|
+
results.push({ platformKey, ok: true, result });
|
|
220
|
+
} catch (err) {
|
|
221
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
222
|
+
console.error(`adaptfully: ${stage} ${platformKey} failed: ${error.message}`);
|
|
223
|
+
results.push({ platformKey, ok: false, error });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const failed = results.filter((entry) => !entry.ok);
|
|
228
|
+
if (failed.length) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
`adaptfully: ${failed.length}/${results.length} platform(s) failed: `
|
|
231
|
+
+ failed.map((entry) => entry.platformKey).join(', '),
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return results;
|
|
187
236
|
}
|
|
188
237
|
|
|
189
238
|
/**
|
|
@@ -202,16 +251,23 @@ export async function adaptfullyFromCli(argv = process.argv) {
|
|
|
202
251
|
}
|
|
203
252
|
|
|
204
253
|
const stage = command;
|
|
205
|
-
const {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
254
|
+
const {
|
|
255
|
+
positionals,
|
|
256
|
+
deployment,
|
|
257
|
+
artifactPath,
|
|
258
|
+
encrypt,
|
|
259
|
+
encryptPublicKey,
|
|
260
|
+
platforms,
|
|
261
|
+
} = parseStageArgs(argv.slice(3));
|
|
262
|
+
const platformArg = platforms || positionals[0];
|
|
263
|
+
const cliServer = platforms ? positionals[0] : positionals[1];
|
|
264
|
+
const mode = platforms ? (positionals[1] ?? 'extract') : (positionals[2] ?? 'extract');
|
|
209
265
|
|
|
210
|
-
if (!stage || !
|
|
266
|
+
if (!stage || !platformArg) {
|
|
211
267
|
throw new Error(
|
|
212
268
|
'Usage:\n'
|
|
213
|
-
+ ' adaptfully <prebuild|build|deploy|release> <platform> [showfullyServer] [mode]\n'
|
|
214
|
-
+ ' [--deployment <key>] [--artifact <path>] [--encrypt] [--encrypt-public-key <pem|path>]\n'
|
|
269
|
+
+ ' adaptfully <prebuild|build|deploy|release> <platform[,platform...]> [showfullyServer] [mode]\n'
|
|
270
|
+
+ ' [--platforms a,b,c] [--deployment <key>] [--artifact <path>] [--encrypt] [--encrypt-public-key <pem|path>]\n'
|
|
215
271
|
+ ' adaptfully steam-publish [--username U] [--password P] [--deployment steam] [--output path]\n'
|
|
216
272
|
+ ' adaptfully google-publish [--from service-account.json] [--deployment android] [--output path]\n'
|
|
217
273
|
+ ' adaptfully apple-publish [--deployment ios] [--category C] [--identity I] [--username U] [--password P]\n'
|
|
@@ -224,8 +280,11 @@ export async function adaptfullyFromCli(argv = process.argv) {
|
|
|
224
280
|
+ ' deploy Yap deploy chore with prior artifact + deployment credentials\n'
|
|
225
281
|
+ ' release Yap release chore (build + configured deployments)\n'
|
|
226
282
|
+ '\n'
|
|
283
|
+
+ ' Multiple platforms (comma-separated or --platforms) run sequentially.\n'
|
|
284
|
+
+ ' Extracts always go to output/<platform>/ so siblings are preserved.\n'
|
|
285
|
+
+ '\n'
|
|
227
286
|
+ ' --deployment <key> Target a single named deployment.\n'
|
|
228
|
-
+ ' --artifact <path> Prior build artifact directory (deploy only; default: ./output
|
|
287
|
+
+ ' --artifact <path> Prior build artifact directory (deploy only; default: ./output/<platform>/ after build).\n'
|
|
229
288
|
+ ' --encrypt Envelope-encrypt chore to Wrapfully (optional; default key embedded).\n'
|
|
230
289
|
+ ' --encrypt-public-key <pem|path> Override Wrapfully public key when encrypting.\n'
|
|
231
290
|
+ '\n'
|
|
@@ -242,13 +301,18 @@ export async function adaptfullyFromCli(argv = process.argv) {
|
|
|
242
301
|
);
|
|
243
302
|
}
|
|
244
303
|
|
|
304
|
+
const platformKeys = parsePlatformList(platformArg);
|
|
305
|
+
if (!platformKeys.length) {
|
|
306
|
+
throw new Error('At least one platform is required.');
|
|
307
|
+
}
|
|
308
|
+
|
|
245
309
|
const { pkg, wrapfullyConfig } = await loadProjectConfig();
|
|
246
310
|
const server = resolveServerUrl(wrapfullyConfig, cliServer);
|
|
247
311
|
const accessToken = resolveAccessToken(wrapfullyConfig);
|
|
248
312
|
const encryptFlag = resolveEncryptFlag(wrapfullyConfig, encrypt);
|
|
249
313
|
const deployFolder = pkg.config?.deployFolder || 'deploy';
|
|
250
314
|
|
|
251
|
-
return
|
|
315
|
+
return runAdaptfullyStages(/** @type {AdaptfullyStage} */ (stage), platformKeys, {
|
|
252
316
|
pkg,
|
|
253
317
|
deployFolder,
|
|
254
318
|
server,
|
|
@@ -264,7 +328,7 @@ export async function adaptfullyFromCli(argv = process.argv) {
|
|
|
264
328
|
|
|
265
329
|
/**
|
|
266
330
|
* @param {string[]} args
|
|
267
|
-
* @returns {{ positionals: string[], deployment?: string, artifactPath?: string, encrypt?: boolean, encryptPublicKey?: string }}
|
|
331
|
+
* @returns {{ positionals: string[], deployment?: string, artifactPath?: string, encrypt?: boolean, encryptPublicKey?: string, platforms?: string }}
|
|
268
332
|
*/
|
|
269
333
|
export function parseStageArgs(args) {
|
|
270
334
|
/** @type {string[]} */
|
|
@@ -273,6 +337,7 @@ export function parseStageArgs(args) {
|
|
|
273
337
|
let artifactPath;
|
|
274
338
|
let encrypt;
|
|
275
339
|
let encryptPublicKey;
|
|
340
|
+
let platforms;
|
|
276
341
|
|
|
277
342
|
for (let i = 0; i < args.length; i++) {
|
|
278
343
|
const arg = args[i];
|
|
@@ -281,6 +346,10 @@ export function parseStageArgs(args) {
|
|
|
281
346
|
deployment = args[++i];
|
|
282
347
|
} else if (arg.startsWith('--deployment=')) {
|
|
283
348
|
deployment = arg.slice('--deployment='.length);
|
|
349
|
+
} else if (arg === '--platforms' && args[i + 1]) {
|
|
350
|
+
platforms = args[++i];
|
|
351
|
+
} else if (arg.startsWith('--platforms=')) {
|
|
352
|
+
platforms = arg.slice('--platforms='.length);
|
|
284
353
|
} else if (arg === '--artifact' && args[i + 1]) {
|
|
285
354
|
artifactPath = args[++i];
|
|
286
355
|
} else if (arg.startsWith('--artifact=')) {
|
|
@@ -296,5 +365,5 @@ export function parseStageArgs(args) {
|
|
|
296
365
|
}
|
|
297
366
|
}
|
|
298
367
|
|
|
299
|
-
return { positionals, deployment, artifactPath, encrypt, encryptPublicKey };
|
|
368
|
+
return { positionals, deployment, artifactPath, encrypt, encryptPublicKey, platforms };
|
|
300
369
|
}
|
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
|
}
|