@heroiclands/package-build 0.5.0 → 0.6.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 +86 -0
- package/README.md +238 -2
- package/bin/package-build.mjs +482 -49
- package/bin/report.mjs +13 -4
- package/config.mjs +380 -1
- package/container.mjs +699 -0
- package/coverage.mjs +626 -0
- package/e2e.mjs +876 -0
- package/index.mjs +12 -0
- package/package.json +34 -12
- package/templates.mjs +224 -0
- package/types/config.d.mts +129 -0
- package/types/container.d.mts +359 -0
- package/types/coverage.d.mts +182 -0
- package/types/e2e.d.mts +351 -0
- package/types/index.d.mts +4 -0
- package/types/templates.d.mts +74 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,91 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 53dd83b: **Commands for the Foundry container and the end-to-end harness** (#18).
|
|
8
|
+
|
|
9
|
+
A package that declares a `compatibility` range is making a promise, and until
|
|
10
|
+
now exactly one repository could defend it: container lifecycle, world seeding
|
|
11
|
+
and the browser harness all lived in `SoHL/utils/`, so two of three HeroicLands
|
|
12
|
+
module repositories declared a range nothing could test.
|
|
13
|
+
|
|
14
|
+
Two new commands:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
package-build container <stage> <start|stop|restart|recreate|rm|status|logs|pull>
|
|
18
|
+
package-build e2e <seed|run|open|fast|sweep>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Nothing about the destination is restated.** A container mounts
|
|
22
|
+
`FOUNDRYVTT_<STAGE>_DATA` — the variable `deploy` already writes into — so
|
|
23
|
+
serving what was just deployed is the next step from one variable rather than a
|
|
24
|
+
second configuration. Stage ports, the container name, the world id and the GM
|
|
25
|
+
credentials all derive from what the repository already declares.
|
|
26
|
+
|
|
27
|
+
**The end-to-end stage is pinned to `compatibility.minimum`.** The claim and the
|
|
28
|
+
evidence for it are now literally the same number, so raising the pin is what it
|
|
29
|
+
should be: a decision to raise the supported floor. `FOUNDRYVTT_<STAGE>_VERSION`
|
|
30
|
+
still wins for a one-off, and `e2e sweep <build>` runs the full suite against a
|
|
31
|
+
build the repository does _not_ pin, so `compatibility.verified` can be evidence.
|
|
32
|
+
|
|
33
|
+
**The wait is for an active world, not an open port.** Foundry answers on its
|
|
34
|
+
port long before a world is serving, and a suite started then fails every spec
|
|
35
|
+
for no visible reason. A licence failure — which never recovers — is read out of
|
|
36
|
+
the container log and reported at once.
|
|
37
|
+
|
|
38
|
+
**What the suite _is_ stays the consumer's**, named in `packageBuild.e2e.suite`
|
|
39
|
+
the way `assetTransform` and `manifestFlags` are named. So does the seed world's
|
|
40
|
+
extra content, in `packageBuild.e2e.documents`. A **module** package additionally
|
|
41
|
+
gets `core.moduleConfiguration` seeded, without which its suite would run against
|
|
42
|
+
a world that never loaded it.
|
|
43
|
+
|
|
44
|
+
New configuration, all optional: `packageBuild.container.{image,stages}` and
|
|
45
|
+
`packageBuild.e2e.{stage,suite,build,world,gm,documents}`. New subpath exports
|
|
46
|
+
`./container` and `./e2e`. Adds `@foundryvtt/foundryvtt-cli` as a dependency —
|
|
47
|
+
seeding a world means compiling its LevelDB collections.
|
|
48
|
+
- 3c631c3: Add the two localization guards that keep a package translated: `lang coverage`
|
|
49
|
+
and `lang hardcoded` (#19).
|
|
50
|
+
|
|
51
|
+
`lang check` already asked whether a localization file is _shippable_. Neither
|
|
52
|
+
of the questions that decide whether it is _translated_ was asked anywhere but
|
|
53
|
+
in the Song of Heroic Lands repository, in two scripts of its own — and both
|
|
54
|
+
satellites ship `lang/` files with no guard at all.
|
|
55
|
+
|
|
56
|
+
**`lang coverage`** — every key the package references exists, and every key it
|
|
57
|
+
declares is referenced. The two halves are not the same severity: a referenced
|
|
58
|
+
key that is missing renders to a player as its own raw key string and fails the
|
|
59
|
+
run; a declared key nothing references is reported and does not, because no scan
|
|
60
|
+
sees every way a key is reached and a guard that fails over one teaches people
|
|
61
|
+
to switch it off.
|
|
62
|
+
|
|
63
|
+
**`lang hardcoded`** — every user-visible literal in the templates goes through
|
|
64
|
+
localization, and every template still compiles once it does. This is the
|
|
65
|
+
_reverse_ walk, and it is the reason both exist: coverage walks key → file and
|
|
66
|
+
is blind to a template that names no key whatsoever. Before the work that
|
|
67
|
+
prompted this guard, SoHL had 516 hardcoded English literals across 61
|
|
68
|
+
templates, and translating every key in `en.json` would have left every one of
|
|
69
|
+
them in English.
|
|
70
|
+
|
|
71
|
+
**What a repository states.** Which files to scan is configuration and defaults
|
|
72
|
+
to the conventional layout, so a repository that follows it declares nothing.
|
|
73
|
+
The escape hatches — a key retained despite looking unreferenced, a literal
|
|
74
|
+
allowed despite looking like prose — each carry a required `reason`, because
|
|
75
|
+
each is a claim a reviewer has to be able to check.
|
|
76
|
+
|
|
77
|
+
**What stays the repository's.** `packageBuild.lang.references` names a module
|
|
78
|
+
exporting `references(context) -> ReferenceSet`, contributing the keys only that
|
|
79
|
+
repository's conventions can find — SoHL's `defineType(prefix, def)` mints one
|
|
80
|
+
key per member of an enum by a rule of its own. Everything Foundry-shaped is
|
|
81
|
+
built in: `{{localize}}`, `game.i18n.localize` / `format`, keys in string and
|
|
82
|
+
template literals, a DataModel's `LOCALIZATION_PREFIXES`, and the field
|
|
83
|
+
`label` / `hint` keys Foundry mints off one.
|
|
84
|
+
|
|
85
|
+
Scripts are read through the **AST**, so a key named in a JSDoc `@example` is
|
|
86
|
+
neither required to exist nor able to keep a dead key alive. `typescript` and
|
|
87
|
+
`handlebars` become runtime dependencies for that reason.
|
|
88
|
+
|
|
3
89
|
## 0.5.0
|
|
4
90
|
|
|
5
91
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -41,6 +41,14 @@ The whole of assemble → validate → ship, one subpath each:
|
|
|
41
41
|
- **`lang`** — what a shippable Foundry localization file must satisfy: it
|
|
42
42
|
parses, its top level is an object, no key is both a leaf and a dotted prefix
|
|
43
43
|
of another, placeholders are single-braced, and key segments carry no data.
|
|
44
|
+
- **`coverage`** — whether the keys a package references and the keys it
|
|
45
|
+
declares are the same set. A referenced key that is missing renders to a
|
|
46
|
+
player as its own raw key string, so it fails the run; a declared key nothing
|
|
47
|
+
references is reported and does not.
|
|
48
|
+
- **`templates`** — the opposite question, which coverage cannot ask: whether
|
|
49
|
+
the markup's user-visible text goes through localization at all, rather than
|
|
50
|
+
sitting in the file in English — and whether each template still compiles once
|
|
51
|
+
it does.
|
|
44
52
|
- **`bundle`** — whether the manifest agrees with the file it points at.
|
|
45
53
|
Declared under `"esmodules"` the bundle must parse as a module; declared under
|
|
46
54
|
`"scripts"` it must declare **nothing** at top level, because every top-level
|
|
@@ -53,6 +61,12 @@ The whole of assemble → validate → ship, one subpath each:
|
|
|
53
61
|
a local copy or SFTP. Always a staged, atomic swap: a running Foundry holds
|
|
54
62
|
its LevelDB packs open, and replacing them in place leaves a directory LevelDB
|
|
55
63
|
"repairs" to zero.
|
|
64
|
+
- **`container`** — running what was just deployed. The Foundry data root a
|
|
65
|
+
deploy writes into is the directory a container mounts, so serving the result
|
|
66
|
+
is the next step from one variable rather than a second configuration.
|
|
67
|
+
- **`e2e`** — a disposable world, seeded with a Gamemaster whose password is
|
|
68
|
+
known, served until it is genuinely **active**, and a suite driven against it.
|
|
69
|
+
What the suite _is_ stays the repository's.
|
|
56
70
|
- **`text`** — locating a literal inside a file, so a finding names the line and
|
|
57
71
|
column it is about.
|
|
58
72
|
|
|
@@ -89,9 +103,40 @@ packageBuild:
|
|
|
89
103
|
|
|
90
104
|
lang:
|
|
91
105
|
sources: lang/*.json
|
|
92
|
-
# Printed after a failure — where this repository documents its
|
|
106
|
+
# Printed after a `lang check` failure — where this repository documents its
|
|
107
|
+
# key rules.
|
|
93
108
|
help: See kb/dev-docs/reference/localization-keys.md.
|
|
94
109
|
|
|
110
|
+
# `lang coverage` and `lang hardcoded`. Every one of these defaults to the
|
|
111
|
+
# conventional layout, so a repository that follows it states none of them.
|
|
112
|
+
primary: lang/en.json # the file coverage is measured against
|
|
113
|
+
scripts: src/**/*.{ts,mjs} # scanned for key references
|
|
114
|
+
templates: templates/**/*.hbs # scanned for references and for English
|
|
115
|
+
|
|
116
|
+
# Only when the package references a root its file does not yet declare;
|
|
117
|
+
# otherwise the roots are read from the file's own keys.
|
|
118
|
+
keyRoots: [SOHL, TYPES, TYPE]
|
|
119
|
+
|
|
120
|
+
# Optional. A module exporting `references(context) -> ReferenceSet`,
|
|
121
|
+
# contributing the keys only this repository's conventions can find. SoHL's
|
|
122
|
+
# `defineType(prefix, def)` mints one key per member of an enum by a rule of
|
|
123
|
+
# its own; no shared guard can know it, and no repository can compare the
|
|
124
|
+
# result against the file. See "Contributing generated keys" below.
|
|
125
|
+
references: ./utils/lang-references.mjs
|
|
126
|
+
|
|
127
|
+
# Keys reached in a way no scan can see, exempt from the unreferenced
|
|
128
|
+
# advisory. The reason is required: it is a claim a reviewer has to be able
|
|
129
|
+
# to check, and the honest fix for an unreferenced key is to delete it.
|
|
130
|
+
retained:
|
|
131
|
+
- prefix: SOHL.Gear.Action.
|
|
132
|
+
reason: Titles built as `${titlePrefix}.${shortcode}` — the prefix is a parameter.
|
|
133
|
+
|
|
134
|
+
# Template literals that are deliberately not localization keys. The escape
|
|
135
|
+
# hatch, not the rule.
|
|
136
|
+
allow:
|
|
137
|
+
- literal: item.system.code === 'pyrn'
|
|
138
|
+
reason: An expression example shown as a placeholder — code, not prose.
|
|
139
|
+
|
|
95
140
|
deploy:
|
|
96
141
|
# Prefix of the shared SFTP override variables. Default `SOHL`.
|
|
97
142
|
envPrefix: SOHL
|
|
@@ -135,6 +180,40 @@ packageBuild:
|
|
|
135
180
|
socket: true
|
|
136
181
|
grid: { distance: 5, units: ft }
|
|
137
182
|
primaryTokenAttribute: health
|
|
183
|
+
|
|
184
|
+
# Running the deployed package in a Foundry container. The four conventional
|
|
185
|
+
# stages — dev, qa, prod, test — need no entry at all: their data root is
|
|
186
|
+
# `FOUNDRYVTT_<STAGE>_DATA`, the same variable `deploy` writes into, and their
|
|
187
|
+
# ports are conventional. Declare a stage only when it is genuinely yours.
|
|
188
|
+
container:
|
|
189
|
+
stages:
|
|
190
|
+
# SoHL keeps the previous, pre-TypeScript system on an older Foundry.
|
|
191
|
+
# An empty `world` declares "never auto-launch" — it is managed by hand.
|
|
192
|
+
leg: { port: 30000, world: "", version: "12.331" }
|
|
193
|
+
|
|
194
|
+
e2e:
|
|
195
|
+
# The one thing the harness does not own. Standing Foundry up and seeding a
|
|
196
|
+
# world is nobody's local problem; what runs against it is entirely yours.
|
|
197
|
+
suite:
|
|
198
|
+
run: [npx, cypress, run]
|
|
199
|
+
open: [npx, cypress, open]
|
|
200
|
+
|
|
201
|
+
# What the fast loop can rebuild, in the order it must be built: the
|
|
202
|
+
# bundler empties the stage, so it goes first. `recreate` marks a target
|
|
203
|
+
# whose output Foundry reads once, at world launch.
|
|
204
|
+
build:
|
|
205
|
+
code: build:code
|
|
206
|
+
assets: build:assets
|
|
207
|
+
db: build:db
|
|
208
|
+
system: { script: build:system, recreate: true }
|
|
209
|
+
|
|
210
|
+
# Everything here is optional — it derives from the package id otherwise.
|
|
211
|
+
world: { id: sohl-e2e, title: SoHL E2E }
|
|
212
|
+
gm: { name: Gamemaster, password: sohl-e2e }
|
|
213
|
+
|
|
214
|
+
# Extra world collections, compiled from directories of JSON documents.
|
|
215
|
+
documents:
|
|
216
|
+
actors: cypress/fixtures/actors
|
|
138
217
|
```
|
|
139
218
|
|
|
140
219
|
### The manifest is generated, not stamped
|
|
@@ -198,9 +277,13 @@ npx package-build clean [--distclean]
|
|
|
198
277
|
npx package-build assets
|
|
199
278
|
npx package-build manifest
|
|
200
279
|
npx package-build lang check
|
|
280
|
+
npx package-build lang coverage [--unused]
|
|
281
|
+
npx package-build lang hardcoded
|
|
201
282
|
npx package-build bundle check
|
|
202
283
|
npx package-build release
|
|
203
284
|
npx package-build deploy <stage>
|
|
285
|
+
npx package-build container <stage> <start|stop|restart|recreate|rm|status|logs|pull>
|
|
286
|
+
npx package-build e2e <seed|run|open|fast|sweep>
|
|
204
287
|
```
|
|
205
288
|
|
|
206
289
|
Wrapped as npm scripts — SoHL spells them:
|
|
@@ -211,9 +294,15 @@ Wrapped as npm scripts — SoHL spells them:
|
|
|
211
294
|
"distclean": "package-build clean --distclean",
|
|
212
295
|
"build:assets": "package-build assets",
|
|
213
296
|
"lint:lang": "package-build lang check",
|
|
297
|
+
"lint:lang-coverage": "package-build lang coverage",
|
|
298
|
+
"lint:lang-hardcoded": "package-build lang hardcoded",
|
|
214
299
|
"lint:bundle-globals": "package-build bundle check",
|
|
215
300
|
"build:pack-release": "package-build release",
|
|
216
|
-
"push:qa": "package-build deploy qa"
|
|
301
|
+
"push:qa": "package-build deploy qa",
|
|
302
|
+
"container:dev": "package-build container dev",
|
|
303
|
+
"e2e:full": "package-build e2e run",
|
|
304
|
+
"e2e:fast": "package-build e2e fast",
|
|
305
|
+
"e2e:sweep": "package-build e2e sweep"
|
|
217
306
|
}
|
|
218
307
|
```
|
|
219
308
|
|
|
@@ -224,6 +313,46 @@ without renaming the first (`lang check`, `bundle check`). Flat `lang:check`
|
|
|
224
313
|
names would make every operation a new top-level command and hide which ones
|
|
225
314
|
belong together.
|
|
226
315
|
|
|
316
|
+
**What the two localization guards ask.** They are deliberate opposites, and
|
|
317
|
+
neither can answer the other's question. `lang coverage` walks _key → file_, so
|
|
318
|
+
it is completely blind to a template that names no key whatsoever; `lang
|
|
319
|
+
hardcoded` walks _text → key_, and catches exactly that. Before the work that
|
|
320
|
+
prompted the second, Song of Heroic Lands had **516 hardcoded English literals
|
|
321
|
+
across 61 templates** — translating every key in `en.json` would have left every
|
|
322
|
+
one of them in English.
|
|
323
|
+
|
|
324
|
+
**Contributing generated keys.** `packageBuild.lang.references` names a module
|
|
325
|
+
exporting `references(context)`, called once with
|
|
326
|
+
`{ config, rootDir, roots, files }` — `files` being the scanned sources as
|
|
327
|
+
`{ path, text }`, already read, so the contributor sees exactly the text the
|
|
328
|
+
built-in scan saw. It returns a reference set:
|
|
329
|
+
|
|
330
|
+
```js
|
|
331
|
+
export function references({ files }) {
|
|
332
|
+
return {
|
|
333
|
+
keys: [
|
|
334
|
+
// `exact` when the key is minted whole, so keys sitting beneath it do
|
|
335
|
+
// not vouch for it; `origin` is the verb phrase the message reads with.
|
|
336
|
+
{
|
|
337
|
+
key: "SOHL.Skill.CODE.lore",
|
|
338
|
+
file: "src/utils/constants.ts",
|
|
339
|
+
line: 42,
|
|
340
|
+
exact: true,
|
|
341
|
+
origin: "defineType generates",
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
namespaces: ["SOHL.Skill.CODE"], // families whose leaves are never named
|
|
345
|
+
patterns: ["SOHL.Skill.*.label"], // shapes, `*` standing for one segment
|
|
346
|
+
findings: [], // whatever the contributor could not resolve
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Everything Foundry-shaped is already built in — `{{localize}}`,
|
|
352
|
+
`game.i18n.localize` / `format`, keys in string and template literals, a
|
|
353
|
+
DataModel's `LOCALIZATION_PREFIXES`, the `FIELDS.<field>.label` / `.hint` keys Foundry
|
|
354
|
+
mints off one. A contributor is for what only the repository knows.
|
|
355
|
+
|
|
227
356
|
**What `bundle check` checks.** Three ways a package builds successfully and
|
|
228
357
|
still does not load, none of which a bundler can see, because each is a
|
|
229
358
|
disagreement between two files rather than a fault in either:
|
|
@@ -254,6 +383,113 @@ moved into configuration; the boilerplate lives in the CLI, once.
|
|
|
254
383
|
`--version` and `--help` answer in a directory with no configuration at all.
|
|
255
384
|
Running an actual command resolves it, and fails loudly when it is missing.
|
|
256
385
|
|
|
386
|
+
## Standing Foundry up, and running a suite against it
|
|
387
|
+
|
|
388
|
+
A package that claims a `compatibility` range is making a promise, and a
|
|
389
|
+
promise is only defended if something exercises it. Until now exactly one
|
|
390
|
+
repository could: the container lifecycle, the world seeding and the browser
|
|
391
|
+
harness all lived in `SoHL/utils/`, so two of the three HeroicLands module
|
|
392
|
+
repositories declared a range nothing could test.
|
|
393
|
+
|
|
394
|
+
**The seam already existed.** `package-build deploy <stage>` installs a staged
|
|
395
|
+
package into `FOUNDRYVTT_<STAGE>_DATA`; a container mounts that same directory
|
|
396
|
+
at `/data` and serves it. Running Foundry against what was just deployed is the
|
|
397
|
+
next step from one variable, not a second configuration — so nothing about the
|
|
398
|
+
destination, the stage, or the package identity is restated.
|
|
399
|
+
|
|
400
|
+
### Which Foundry build a run pins
|
|
401
|
+
|
|
402
|
+
`compatibility.minimum` is the oldest Foundry a package claims to run on, and
|
|
403
|
+
that claim is what the suite exists to defend. Testing above the floor tests a
|
|
404
|
+
configuration no user is promised while leaving the promised one unverified: a
|
|
405
|
+
regression that breaks the floor but works on a newer build passes in silence.
|
|
406
|
+
|
|
407
|
+
So **the end-to-end stage is pinned to `compatibility.minimum` itself**, read
|
|
408
|
+
from the top level of the shared configuration. The claim and the evidence are
|
|
409
|
+
the same number and cannot drift apart, and raising the pin is what it should
|
|
410
|
+
be — a decision to raise the supported floor, made by editing the claim.
|
|
411
|
+
|
|
412
|
+
`FOUNDRYVTT_<STAGE>_VERSION` still wins, so a contributor can sit on another
|
|
413
|
+
build without touching committed configuration. A floor that names no build
|
|
414
|
+
(`"14"`) cannot pin one; the run floats on the major tag, visibly, rather than
|
|
415
|
+
pretending to a precision it lacks.
|
|
416
|
+
|
|
417
|
+
### The sweep
|
|
418
|
+
|
|
419
|
+
Routine runs go against the floor, which leaves the other direction untested: a
|
|
420
|
+
new Foundry release can break a package and nothing notices until a user does.
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
npx package-build e2e sweep 14.367
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
That is the full suite — reseeded world and all — against a build the
|
|
427
|
+
repository does not pin. It must be the full path rather than the fast one: a
|
|
428
|
+
seeded world is stamped with the build that created it, and Foundry refuses to
|
|
429
|
+
auto-launch a world stamped by another. It takes the build as an argument and
|
|
430
|
+
has **no default**, because the product of a sweep is a citable result ("the
|
|
431
|
+
full suite passed on 14.367") and "the newest release" is not a constant any
|
|
432
|
+
repository can hold without rotting.
|
|
433
|
+
|
|
434
|
+
A green sweep is what licenses moving `compatibility.verified` to that build. A
|
|
435
|
+
red one is the early warning the sweep exists to produce.
|
|
436
|
+
|
|
437
|
+
### Waiting for a world, not for a port
|
|
438
|
+
|
|
439
|
+
Foundry answers on its port long before a world is serving. A suite started at
|
|
440
|
+
that moment fails every spec for no visible reason, which is the single most
|
|
441
|
+
expensive way an integration harness wastes an afternoon. So the wait is for
|
|
442
|
+
the join screen — the form a world renders only once it is **active** — and a
|
|
443
|
+
licence failure, which never recovers, is read out of the container log and
|
|
444
|
+
reported at once rather than after a three-minute timeout that explains
|
|
445
|
+
nothing.
|
|
446
|
+
|
|
447
|
+
### The fast loop
|
|
448
|
+
|
|
449
|
+
```
|
|
450
|
+
npx package-build e2e fast -- --spec cypress/e2e/skill.cy.js
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Rebuild what changed, redeploy, cycle the world, wait for it, re-run. It is one
|
|
454
|
+
command because every step of it has a quiet failure mode:
|
|
455
|
+
|
|
456
|
+
| Step | What goes wrong by hand |
|
|
457
|
+
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
458
|
+
| Build | The container serves the **built** package, not the source tree. |
|
|
459
|
+
| Order | A bundler empties the stage, so building it after the asset and pack passes silently discards them — and the deploy is a mirror. |
|
|
460
|
+
| Manifest | Read once at world launch, so it needs a container **recreate**, not a restart. A target declaring `recreate: true` forces one. |
|
|
461
|
+
| Restart | A running Foundry holds its packs open, so a content change is invisible until the world reopens them. |
|
|
462
|
+
| Stale lock | A container that died holding the data-root lock makes every later boot fail with a message that names no owner. |
|
|
463
|
+
| Readiness | `docker start` returns long before Foundry serves. |
|
|
464
|
+
| The suite | Editor and agent shells export `ELECTRON_RUN_AS_NODE`, which makes an Electron runner start as plain Node and die on its own flags. |
|
|
465
|
+
|
|
466
|
+
`--build` takes a comma-separated list of declared targets, `all`, or `none`;
|
|
467
|
+
an unrecognised one fails fast rather than half-deploying. `--recreate` forces
|
|
468
|
+
a recreate, `--no-run` stops once the environment is current, and everything
|
|
469
|
+
else — including anything after a bare `--` — is handed to the suite verbatim.
|
|
470
|
+
|
|
471
|
+
### What the seeded world holds
|
|
472
|
+
|
|
473
|
+
A world Foundry will launch without a migration prompt: `world.json`, and one
|
|
474
|
+
Gamemaster whose password is known, so a spec can log in deterministically. It
|
|
475
|
+
also carries one **active** scene, because an empty world auto-starts Foundry's
|
|
476
|
+
welcome tour (whose callout overlays sheets) and a world with no active scene
|
|
477
|
+
has no ready canvas.
|
|
478
|
+
|
|
479
|
+
For a **module** package it additionally writes `core.moduleConfiguration`,
|
|
480
|
+
switching the module on. A system is the world's own and `world.json` names it;
|
|
481
|
+
a module is not, and without that setting a module repository would stand its
|
|
482
|
+
suite up against a world that never loaded the thing under test.
|
|
483
|
+
|
|
484
|
+
Anything else — which actors, which journals — is the repository's, declared as
|
|
485
|
+
`packageBuild.e2e.documents` and compiled in beside the built-ins.
|
|
486
|
+
|
|
487
|
+
The world directory is wiped and rewritten on every seed. That is what makes a
|
|
488
|
+
run repeatable, and it is why `FOUNDRYVTT_<E2E_STAGE>_DATA` must be a separate,
|
|
489
|
+
empty directory: pointing it at a working stage would let the seed delete
|
|
490
|
+
worlds there, and would make the image reuse that stage's `Config/license.json`
|
|
491
|
+
in place of the key dedicated to the suite.
|
|
492
|
+
|
|
257
493
|
## Design
|
|
258
494
|
|
|
259
495
|
**The rules are pure, and I/O is confined to functions named for it.** A rule
|