@ethlete/cli 3.0.0-next.16 → 3.0.0-next.18
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 +12 -0
- package/README.md +8 -0
- package/package.json +1 -1
- package/src/lib/api/api-context.d.ts +15 -0
- package/src/lib/api/api-context.js +23 -0
- package/src/lib/api/api-context.js.map +1 -0
- package/src/lib/api/api-state.d.ts +31 -0
- package/src/lib/api/api-state.js +80 -0
- package/src/lib/api/api-state.js.map +1 -0
- package/src/lib/api/definition.d.ts +37 -1
- package/src/lib/api/definition.js +12 -2
- package/src/lib/api/definition.js.map +1 -1
- package/src/lib/api/doctor.d.ts +16 -0
- package/src/lib/api/doctor.js +71 -0
- package/src/lib/api/doctor.js.map +1 -0
- package/src/lib/api/fingerprint.d.ts +18 -0
- package/src/lib/api/fingerprint.js +63 -0
- package/src/lib/api/fingerprint.js.map +1 -0
- package/src/lib/api/git.d.ts +2 -0
- package/src/lib/api/git.js +7 -1
- package/src/lib/api/git.js.map +1 -1
- package/src/lib/api/help.js +31 -4
- package/src/lib/api/help.js.map +1 -1
- package/src/lib/api/index.d.ts +4 -0
- package/src/lib/api/index.js +4 -0
- package/src/lib/api/index.js.map +1 -1
- package/src/lib/api/load-definitions.js +3 -0
- package/src/lib/api/load-definitions.js.map +1 -1
- package/src/lib/api/lock.d.ts +46 -0
- package/src/lib/api/lock.js +144 -0
- package/src/lib/api/lock.js.map +1 -0
- package/src/lib/api/parse-argv.d.ts +12 -0
- package/src/lib/api/parse-argv.js +31 -0
- package/src/lib/api/parse-argv.js.map +1 -0
- package/src/lib/api/run-locked.d.ts +14 -0
- package/src/lib/api/run-locked.js +62 -0
- package/src/lib/api/run-locked.js.map +1 -0
- package/src/lib/api/run-ready.d.ts +60 -0
- package/src/lib/api/run-ready.js +212 -0
- package/src/lib/api/run-ready.js.map +1 -0
- package/src/lib/api/run-snapshot.d.ts +33 -0
- package/src/lib/api/run-snapshot.js +124 -0
- package/src/lib/api/run-snapshot.js.map +1 -0
- package/src/lib/api/run-status.d.ts +9 -0
- package/src/lib/api/run-status.js +55 -0
- package/src/lib/api/run-status.js.map +1 -0
- package/src/lib/api/run.d.ts +1 -1
- package/src/lib/api/run.js +192 -9
- package/src/lib/api/run.js.map +1 -1
- package/src/lib/api/seeds.d.ts +55 -0
- package/src/lib/api/seeds.js +215 -0
- package/src/lib/api/seeds.js.map +1 -0
- package/src/lib/api/snapshot.d.ts +63 -0
- package/src/lib/api/snapshot.js +132 -0
- package/src/lib/api/snapshot.js.map +1 -0
- package/src/lib/api/validate-definition.d.ts +7 -0
- package/src/lib/api/validate-definition.js +79 -0
- package/src/lib/api/validate-definition.js.map +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @ethlete/cli
|
|
2
2
|
|
|
3
|
+
## 3.0.0-next.18
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add `et api ready --profile` to bring an API's data up to date from a snapshot or its seeds, plus `exec`, `doctor [--fix]`, `run --lock`, `snapshot save|restore` and `status`, with a machine-wide lock and state.
|
|
8
|
+
|
|
9
|
+
## 3.0.0-next.17
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- Add `et api seed` and `et api fixtures`, which copy `.ethlete/seeds/<api>/` into the API container and run the seeds its `seeds.json` names. A clone now gitignores only its own `/.ethlete/<api>/`.
|
|
14
|
+
|
|
3
15
|
## 3.0.0-next.16
|
|
4
16
|
|
|
5
17
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -104,10 +104,18 @@ yarn et api clone hub # clone the API into .ethlete/hub
|
|
|
104
104
|
yarn et api clear hub # remove that clone again
|
|
105
105
|
yarn et api clear --all # remove every managed clone
|
|
106
106
|
yarn et api setup hub # run the API's own setupCommand, which writes its .env
|
|
107
|
+
yarn et api seed hub # list the seeds in .ethlete/seeds/hub/seeds.json
|
|
108
|
+
yarn et api seed hub demo,shop # run two of them, in that order
|
|
109
|
+
yarn et api fixtures hub demo # load the fixtures, then run the demo seed
|
|
107
110
|
```
|
|
108
111
|
|
|
109
112
|
Every command takes a comma-separated list of names, and acts on each API in turn.
|
|
110
113
|
|
|
114
|
+
`seed` and `fixtures` read `.ethlete/seeds/<name>/seeds.json`, copy that folder into the API
|
|
115
|
+
container at `$SEED_DIR`, and run the shell lines of each seed you name there. The folder is
|
|
116
|
+
committed, so gitignore each managed checkout as `/.ethlete/<name>/`, never `.ethlete/` as a whole.
|
|
117
|
+
An `exec` entry named `seed` or `fixtures` runs instead.
|
|
118
|
+
|
|
111
119
|
`clone`, `checkout`, `pull`, `setup` and `clear` act on the checkout itself, so they work before the
|
|
112
120
|
API has an `.env` and need no container engine. `pull` refuses to run on a checkout with uncommitted
|
|
113
121
|
changes unless you pass `--force`. `--force` resets the branch to its remote and throws away local
|
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ApiDefinition } from './definition';
|
|
2
|
+
export declare const definedEntries: (record: Record<string, string | undefined>) => Record<string, string>;
|
|
3
|
+
/** The checkout and the machine-wide state directory of one API, or the checkout failure. */
|
|
4
|
+
export declare const stateDirectoryOf: (options: {
|
|
5
|
+
root: string;
|
|
6
|
+
name: string;
|
|
7
|
+
api: ApiDefinition;
|
|
8
|
+
needs?: "compose" | "env";
|
|
9
|
+
}) => ({
|
|
10
|
+
legacyConfigWarning?: string;
|
|
11
|
+
} & import("./resolve-checkout").ApiCheckoutFailure) | {
|
|
12
|
+
ok: true;
|
|
13
|
+
checkout: import("./resolve-checkout").ApiCheckout;
|
|
14
|
+
directory: string;
|
|
15
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stateDirectoryOf = exports.definedEntries = void 0;
|
|
4
|
+
const api_state_1 = require("./api-state");
|
|
5
|
+
const resolve_checkout_1 = require("./resolve-checkout");
|
|
6
|
+
const definedEntries = (record) => Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
|
|
7
|
+
exports.definedEntries = definedEntries;
|
|
8
|
+
/** The checkout and the machine-wide state directory of one API, or the checkout failure. */
|
|
9
|
+
const stateDirectoryOf = (options) => {
|
|
10
|
+
var _a, _b, _c;
|
|
11
|
+
const { api } = options;
|
|
12
|
+
const checkout = (0, resolve_checkout_1.resolveApiCheckout)(Object.assign(Object.assign({}, options), { needs: (_a = options.needs) !== null && _a !== void 0 ? _a : 'compose' }));
|
|
13
|
+
if (!checkout.ok)
|
|
14
|
+
return checkout;
|
|
15
|
+
const env = Object.assign(Object.assign({}, process.env), (0, exports.definedEntries)((_c = (_b = api.env) === null || _b === void 0 ? void 0 : _b.call(api)) !== null && _c !== void 0 ? _c : {}));
|
|
16
|
+
return {
|
|
17
|
+
ok: true,
|
|
18
|
+
checkout: checkout.checkout,
|
|
19
|
+
directory: (0, api_state_1.apiStateDirectory)({ project: (0, api_state_1.composeProjectName)({ composePath: checkout.checkout.composePath, env }) }),
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
exports.stateDirectoryOf = stateDirectoryOf;
|
|
23
|
+
//# sourceMappingURL=api-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-context.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/api-context.ts"],"names":[],"mappings":";;;AAAA,2CAAoE;AAEpE,yDAAwD;AAEjD,MAAM,cAAc,GAAG,CAAC,MAA0C,EAAE,EAAE,CAC3E,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAA2B,CAAC;AADrG,QAAA,cAAc,kBACuF;AAElH,6FAA6F;AACtF,MAAM,gBAAgB,GAAG,CAAC,OAKhC,EAAE,EAAE;;IACH,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IACxB,MAAM,QAAQ,GAAG,IAAA,qCAAkB,kCAAM,OAAO,KAAE,KAAK,EAAE,MAAA,OAAO,CAAC,KAAK,mCAAI,SAAS,IAAG,CAAC;IAEvF,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,OAAO,QAAQ,CAAC;IAElC,MAAM,GAAG,mCAAQ,OAAO,CAAC,GAAG,GAAK,IAAA,sBAAc,EAAC,MAAA,MAAA,GAAG,CAAC,GAAG,mDAAI,mCAAI,EAAE,CAAC,CAAE,CAAC;IAErE,OAAO;QACL,EAAE,EAAE,IAAa;QACjB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,SAAS,EAAE,IAAA,6BAAiB,EAAC,EAAE,OAAO,EAAE,IAAA,8BAAkB,EAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;KACnH,CAAC;AACJ,CAAC,CAAC;AAlBW,QAAA,gBAAgB,oBAkB3B"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** What `ready` last brought the API into. `dirty` means something changed the data since. */
|
|
2
|
+
export type ApiState = {
|
|
3
|
+
profile: string | null;
|
|
4
|
+
fingerprint: string | null;
|
|
5
|
+
dirty: boolean;
|
|
6
|
+
updatedAt: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The compose project name the container engine gives this compose directory, resolved the way compose
|
|
10
|
+
* does: `COMPOSE_PROJECT_NAME` from the environment or the directory's `.env`, then the top-level
|
|
11
|
+
* `name:` of the compose file, then the directory name.
|
|
12
|
+
*/
|
|
13
|
+
export declare const composeProjectName: (options: {
|
|
14
|
+
composePath: string;
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
16
|
+
}) => string;
|
|
17
|
+
/** Machine-wide directory of one compose project's `state.json` and `lock.json`. */
|
|
18
|
+
export declare const apiStateDirectory: (options: {
|
|
19
|
+
project: string;
|
|
20
|
+
env?: NodeJS.ProcessEnv;
|
|
21
|
+
}) => string;
|
|
22
|
+
/** The stored state, or `undefined` when there is none or it cannot be read. */
|
|
23
|
+
export declare const readApiState: (directory: string) => ApiState | undefined;
|
|
24
|
+
/** Replaces `state.json` in one rename, so a reader never sees half a file. */
|
|
25
|
+
export declare const writeApiState: (options: {
|
|
26
|
+
directory: string;
|
|
27
|
+
state: Omit<ApiState, "updatedAt">;
|
|
28
|
+
now?: Date;
|
|
29
|
+
}) => ApiState;
|
|
30
|
+
/** Keeps the stored profile and fingerprint, so `status` can still say what the data was before. */
|
|
31
|
+
export declare const markApiStateDirty: (directory: string, now?: Date) => ApiState;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.markApiStateDirty = exports.writeApiState = exports.readApiState = exports.apiStateDirectory = exports.composeProjectName = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const os_1 = require("os");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const COMPOSE_FILE_NAMES = ['compose.yaml', 'compose.yml', 'docker-compose.yaml', 'docker-compose.yml'];
|
|
9
|
+
const normalizeProjectName = (name) => name.toLowerCase().replace(/[^a-z0-9_-]/g, '');
|
|
10
|
+
const readText = (path) => ((0, fs_1.existsSync)(path) ? (0, fs_1.readFileSync)(path, 'utf8') : undefined);
|
|
11
|
+
const literal = (value) => (value === undefined || value.includes('$') ? undefined : value);
|
|
12
|
+
/**
|
|
13
|
+
* The compose project name the container engine gives this compose directory, resolved the way compose
|
|
14
|
+
* does: `COMPOSE_PROJECT_NAME` from the environment or the directory's `.env`, then the top-level
|
|
15
|
+
* `name:` of the compose file, then the directory name.
|
|
16
|
+
*/
|
|
17
|
+
const composeProjectName = (options) => {
|
|
18
|
+
var _a, _b, _c, _d;
|
|
19
|
+
const { composePath, env = process.env } = options;
|
|
20
|
+
const fromDotEnv = (_b = (_a = readText((0, path_1.join)(composePath, '.env'))) === null || _a === void 0 ? void 0 : _a.match(/^\s*COMPOSE_PROJECT_NAME\s*=\s*["']?([^"'\s#]+)/m)) === null || _b === void 0 ? void 0 : _b[1];
|
|
21
|
+
const composeFile = COMPOSE_FILE_NAMES.map((name) => (0, path_1.join)(composePath, name)).find((path) => (0, fs_1.existsSync)(path));
|
|
22
|
+
const fromComposeFile = composeFile ? (_d = (_c = readText(composeFile)) === null || _c === void 0 ? void 0 : _c.match(/^name:\s*["']?([^"'\s#]+)/m)) === null || _d === void 0 ? void 0 : _d[1] : undefined;
|
|
23
|
+
const name = [env['COMPOSE_PROJECT_NAME'], literal(fromDotEnv), literal(fromComposeFile)]
|
|
24
|
+
.map((candidate) => (candidate ? normalizeProjectName(candidate) : ''))
|
|
25
|
+
.find((candidate) => candidate !== '');
|
|
26
|
+
return name !== null && name !== void 0 ? name : normalizeProjectName((0, path_1.basename)(composePath));
|
|
27
|
+
};
|
|
28
|
+
exports.composeProjectName = composeProjectName;
|
|
29
|
+
/** Machine-wide directory of one compose project's `state.json` and `lock.json`. */
|
|
30
|
+
const apiStateDirectory = (options) => {
|
|
31
|
+
const { project, env = process.env } = options;
|
|
32
|
+
const stateHome = env['XDG_STATE_HOME'] || (0, path_1.join)((0, os_1.homedir)(), '.local/state');
|
|
33
|
+
return (0, path_1.join)(stateHome, 'ethlete', 'api', project);
|
|
34
|
+
};
|
|
35
|
+
exports.apiStateDirectory = apiStateDirectory;
|
|
36
|
+
const statePath = (directory) => (0, path_1.join)(directory, 'state.json');
|
|
37
|
+
/** The stored state, or `undefined` when there is none or it cannot be read. */
|
|
38
|
+
const readApiState = (directory) => {
|
|
39
|
+
try {
|
|
40
|
+
const value = JSON.parse((0, fs_1.readFileSync)(statePath(directory), 'utf8'));
|
|
41
|
+
return {
|
|
42
|
+
profile: typeof value.profile === 'string' ? value.profile : null,
|
|
43
|
+
fingerprint: typeof value.fingerprint === 'string' ? value.fingerprint : null,
|
|
44
|
+
dirty: value.dirty === true,
|
|
45
|
+
updatedAt: typeof value.updatedAt === 'string' ? value.updatedAt : '',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (_a) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
exports.readApiState = readApiState;
|
|
53
|
+
/** Replaces `state.json` in one rename, so a reader never sees half a file. */
|
|
54
|
+
const writeApiState = (options) => {
|
|
55
|
+
const { directory, state, now = new Date() } = options;
|
|
56
|
+
const written = Object.assign(Object.assign({}, state), { updatedAt: now.toISOString() });
|
|
57
|
+
const temporary = (0, path_1.join)(directory, `state.json.${(0, crypto_1.randomUUID)()}.tmp`);
|
|
58
|
+
(0, fs_1.mkdirSync)(directory, { recursive: true });
|
|
59
|
+
try {
|
|
60
|
+
(0, fs_1.writeFileSync)(temporary, `${JSON.stringify(written, null, 2)}\n`, 'utf8');
|
|
61
|
+
(0, fs_1.renameSync)(temporary, statePath(directory));
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
(0, fs_1.rmSync)(temporary, { force: true });
|
|
65
|
+
}
|
|
66
|
+
return written;
|
|
67
|
+
};
|
|
68
|
+
exports.writeApiState = writeApiState;
|
|
69
|
+
/** Keeps the stored profile and fingerprint, so `status` can still say what the data was before. */
|
|
70
|
+
const markApiStateDirty = (directory, now = new Date()) => {
|
|
71
|
+
var _a, _b;
|
|
72
|
+
const previous = (0, exports.readApiState)(directory);
|
|
73
|
+
return (0, exports.writeApiState)({
|
|
74
|
+
directory,
|
|
75
|
+
state: { profile: (_a = previous === null || previous === void 0 ? void 0 : previous.profile) !== null && _a !== void 0 ? _a : null, fingerprint: (_b = previous === null || previous === void 0 ? void 0 : previous.fingerprint) !== null && _b !== void 0 ? _b : null, dirty: true },
|
|
76
|
+
now,
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
exports.markApiStateDirty = markApiStateDirty;
|
|
80
|
+
//# sourceMappingURL=api-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-state.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/api-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,9 +24,45 @@ export type ApiDefinition = {
|
|
|
24
24
|
env?: () => Record<string, string | undefined>;
|
|
25
25
|
/** Named commands run in `execService`, for example `{ install: ['composer', 'install'] }`. */
|
|
26
26
|
exec?: Record<string, string[]>;
|
|
27
|
+
/** Ordered preconditions checked by `doctor`. A later check may rely on an earlier one. */
|
|
28
|
+
checks?: ApiCheck[];
|
|
29
|
+
/** Named states `ready` and `snapshot` work with. */
|
|
30
|
+
profiles?: Record<string, ApiProfile>;
|
|
31
|
+
/** Migrations folder relative to the API checkout root. Its contents are part of the state fingerprint. */
|
|
32
|
+
migrationsDir?: string;
|
|
33
|
+
};
|
|
34
|
+
/** One precondition of the API's local setup, run in order by `doctor`. */
|
|
35
|
+
export type ApiCheck = {
|
|
36
|
+
/** Unique label printed in the `doctor` report. */
|
|
37
|
+
name: string;
|
|
38
|
+
/** One shell line that exits 0 when the check passes. */
|
|
39
|
+
check: string;
|
|
40
|
+
/** One shell line that repairs a failed check, run by `doctor --fix`. */
|
|
41
|
+
fix?: string;
|
|
42
|
+
/** Service the lines run in. Defaults to `execService`. */
|
|
43
|
+
service?: string;
|
|
44
|
+
/** Run on the host in `composeDir` with the API's `env` instead of in a container. */
|
|
45
|
+
host?: boolean;
|
|
46
|
+
};
|
|
47
|
+
/** A named state the API can be brought into. */
|
|
48
|
+
export type ApiProfile = {
|
|
49
|
+
/** Seed names from `seeds.json` run in order, where `fixtures` stands for the fixtures list. */
|
|
50
|
+
seeds: string[];
|
|
51
|
+
/** Url that must answer with `expect` (default 200) before the profile counts as ready. */
|
|
52
|
+
health?: {
|
|
53
|
+
url: string;
|
|
54
|
+
expect?: number;
|
|
55
|
+
};
|
|
56
|
+
/** How to dump and restore the databases: `save` writes to stdout, `restore` reads stdin, both see `$DATABASES`. */
|
|
57
|
+
snapshot?: {
|
|
58
|
+
service: string;
|
|
59
|
+
databases: string[];
|
|
60
|
+
save: string;
|
|
61
|
+
restore: string;
|
|
62
|
+
};
|
|
27
63
|
};
|
|
28
64
|
export type ApiDefinitions = Record<string, ApiDefinition>;
|
|
29
|
-
export declare const BUILT_IN_API_COMMANDS: readonly ["up", "down", "logs", "shell", "clone", "clear", "checkout", "pull", "setup"];
|
|
65
|
+
export declare const BUILT_IN_API_COMMANDS: readonly ["up", "down", "logs", "shell", "clone", "clear", "checkout", "pull", "setup", "exec", "doctor", "run", "ready", "snapshot", "status"];
|
|
30
66
|
/** These act on the checkout itself, so they run before `setupCommand` and need no container engine. */
|
|
31
67
|
export declare const GIT_API_COMMANDS: string[];
|
|
32
68
|
/** Whether an exec entry downloads dependencies, which is the only failure the private-dependency hint explains. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.apiCommandNames = exports.dependencyInstallCommandName = exports.installsDependencies = exports.GIT_API_COMMANDS = exports.BUILT_IN_API_COMMANDS = void 0;
|
|
4
|
+
const seeds_1 = require("./seeds");
|
|
4
5
|
exports.BUILT_IN_API_COMMANDS = [
|
|
5
6
|
'up',
|
|
6
7
|
'down',
|
|
@@ -11,6 +12,12 @@ exports.BUILT_IN_API_COMMANDS = [
|
|
|
11
12
|
'checkout',
|
|
12
13
|
'pull',
|
|
13
14
|
'setup',
|
|
15
|
+
'exec',
|
|
16
|
+
'doctor',
|
|
17
|
+
'run',
|
|
18
|
+
'ready',
|
|
19
|
+
'snapshot',
|
|
20
|
+
'status',
|
|
14
21
|
];
|
|
15
22
|
/** These act on the checkout itself, so they run before `setupCommand` and need no container engine. */
|
|
16
23
|
exports.GIT_API_COMMANDS = ['clone', 'checkout', 'pull'];
|
|
@@ -25,8 +32,11 @@ exports.dependencyInstallCommandName = dependencyInstallCommandName;
|
|
|
25
32
|
const apiCommandNames = (api) => {
|
|
26
33
|
var _a;
|
|
27
34
|
return [
|
|
28
|
-
...
|
|
29
|
-
|
|
35
|
+
...new Set([
|
|
36
|
+
...exports.BUILT_IN_API_COMMANDS.filter((command) => command !== 'setup' || api.setupCommand),
|
|
37
|
+
...seeds_1.SEED_API_COMMANDS,
|
|
38
|
+
...Object.keys((_a = api.exec) !== null && _a !== void 0 ? _a : {}),
|
|
39
|
+
]),
|
|
30
40
|
];
|
|
31
41
|
};
|
|
32
42
|
exports.apiCommandNames = apiCommandNames;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/definition.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"definition.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/definition.ts"],"names":[],"mappings":";;;AAAA,mCAA4C;AA8D/B,QAAA,qBAAqB,GAAG;IACnC,IAAI;IACJ,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,UAAU;IACV,MAAM;IACN,OAAO;IACP,MAAM;IACN,QAAQ;IACR,KAAK;IACL,OAAO;IACP,UAAU;IACV,QAAQ;CACA,CAAC;AAEX,wGAAwG;AAC3F,QAAA,gBAAgB,GAAa,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;AAExE,MAAM,qBAAqB,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAElG,oHAAoH;AAC7G,MAAM,oBAAoB,GAAG,CAAC,WAA8B,EAAE,EAAE,WACrE,OAAA,qBAAqB,CAAC,QAAQ,CAAC,MAAA,WAAW,CAAC,CAAC,CAAC,mCAAI,EAAE,CAAC,CAAA,EAAA,CAAC;AAD1C,QAAA,oBAAoB,wBACsB;AAEvD,gGAAgG;AACzF,MAAM,4BAA4B,GAAG,CAAC,GAAkB,EAAE,EAAE,WACjE,OAAA,MAAM,CAAC,IAAI,CAAC,MAAA,GAAG,CAAC,IAAI,mCAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,eAAC,OAAA,IAAA,4BAAoB,EAAC,MAAA,MAAA,GAAG,CAAC,IAAI,0CAAG,IAAI,CAAC,mCAAI,EAAE,CAAC,CAAA,EAAA,CAAC,CAAA,EAAA,CAAC;AAD9E,QAAA,4BAA4B,gCACkD;AAE3F,+GAA+G;AACxG,MAAM,eAAe,GAAG,CAAC,GAAkB,EAAE,EAAE;;IAAC,OAAA;QACrD,GAAG,IAAI,GAAG,CAAC;YACT,GAAG,6BAAqB,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,OAAO,IAAI,GAAG,CAAC,YAAY,CAAC;YACrF,GAAG,yBAAiB;YACpB,GAAG,MAAM,CAAC,IAAI,CAAC,MAAA,GAAG,CAAC,IAAI,mCAAI,EAAE,CAAC;SAC/B,CAAC;KACH,CAAA;CAAA,CAAC;AANW,QAAA,eAAe,mBAM1B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ApiDefinition } from './definition';
|
|
2
|
+
import { ComposeTool } from './compose';
|
|
3
|
+
export type RunDoctorOptions = {
|
|
4
|
+
name: string;
|
|
5
|
+
api: ApiDefinition;
|
|
6
|
+
tool: ComposeTool;
|
|
7
|
+
/** The compose directory of the API checkout. */
|
|
8
|
+
cwd: string;
|
|
9
|
+
env: NodeJS.ProcessEnv;
|
|
10
|
+
invocation: string;
|
|
11
|
+
fix: boolean;
|
|
12
|
+
};
|
|
13
|
+
/** Runs the API's checks in order, repairing failures when `fix` is set. Stops at the first failure it cannot repair. */
|
|
14
|
+
export declare const runDoctor: ({ name, api, tool, cwd, env, invocation, fix }: RunDoctorOptions) => {
|
|
15
|
+
ok: boolean;
|
|
16
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runDoctor = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const STDERR_TAIL_LINES = 5;
|
|
6
|
+
const NOT_RUNNING = /is not running|not running|no such container|no container|can only create exec sessions/i;
|
|
7
|
+
/** Runs the API's checks in order, repairing failures when `fix` is set. Stops at the first failure it cannot repair. */
|
|
8
|
+
const runDoctor = ({ name, api, tool, cwd, env, invocation, fix }) => {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
const checks = (_a = api.checks) !== null && _a !== void 0 ? _a : [];
|
|
11
|
+
if (checks.length === 0) {
|
|
12
|
+
console.log(`The ${name} API declares no checks.`);
|
|
13
|
+
return { ok: true };
|
|
14
|
+
}
|
|
15
|
+
const [binary, ...composePrefix] = tool.compose;
|
|
16
|
+
const run = ({ check, line, stream }) => {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
const [command, args] = check.host
|
|
19
|
+
? ['sh', ['-c', line]]
|
|
20
|
+
: [binary, [...composePrefix, 'exec', '-T', (_a = check.service) !== null && _a !== void 0 ? _a : api.execService, 'sh', '-c', line]];
|
|
21
|
+
const result = (0, child_process_1.spawnSync)(command, args, Object.assign({ cwd,
|
|
22
|
+
env }, (stream ? { stdio: 'inherit' } : { encoding: 'utf8', maxBuffer: Infinity })));
|
|
23
|
+
const stderr = stream ? '' : `${(_b = result.stderr) !== null && _b !== void 0 ? _b : ''}`.trim();
|
|
24
|
+
return { ok: !result.error && result.status === 0, stderr: result.error ? result.error.message : stderr };
|
|
25
|
+
};
|
|
26
|
+
const printFailure = (stderr) => {
|
|
27
|
+
const tail = stderr
|
|
28
|
+
.split('\n')
|
|
29
|
+
.filter((line) => line !== '')
|
|
30
|
+
.slice(-STDERR_TAIL_LINES);
|
|
31
|
+
for (const line of tail)
|
|
32
|
+
console.log(` ${line}`);
|
|
33
|
+
};
|
|
34
|
+
let failed = false;
|
|
35
|
+
for (const check of checks) {
|
|
36
|
+
const first = run({ check, line: check.check, stream: false });
|
|
37
|
+
if (first.ok) {
|
|
38
|
+
console.log(`ok ${check.name}`);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (!check.host && NOT_RUNNING.test(first.stderr)) {
|
|
42
|
+
console.log(`FAIL ${check.name}`);
|
|
43
|
+
console.error(`\nThe ${(_b = check.service) !== null && _b !== void 0 ? _b : api.execService} service is not running. Start it with: ${invocation} up ${name}`);
|
|
44
|
+
return { ok: false };
|
|
45
|
+
}
|
|
46
|
+
if (!fix || check.fix === undefined) {
|
|
47
|
+
console.log(`FAIL ${check.name}`);
|
|
48
|
+
printFailure(first.stderr);
|
|
49
|
+
if (fix)
|
|
50
|
+
return { ok: false };
|
|
51
|
+
failed = true;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
console.log(`Fixing ${check.name}: ${check.fix}`);
|
|
55
|
+
const fixed = run({ check, line: check.fix, stream: true });
|
|
56
|
+
if (!fixed.ok) {
|
|
57
|
+
console.log(`fix failed ${check.name}`);
|
|
58
|
+
return { ok: false };
|
|
59
|
+
}
|
|
60
|
+
const again = run({ check, line: check.check, stream: false });
|
|
61
|
+
if (!again.ok) {
|
|
62
|
+
console.log(`FAIL ${check.name} (still failing after the fix)`);
|
|
63
|
+
printFailure(again.stderr);
|
|
64
|
+
return { ok: false };
|
|
65
|
+
}
|
|
66
|
+
console.log(`fixed ${check.name}`);
|
|
67
|
+
}
|
|
68
|
+
return { ok: !failed };
|
|
69
|
+
};
|
|
70
|
+
exports.runDoctor = runDoctor;
|
|
71
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const NO_GIT = "no-git";
|
|
2
|
+
/** The major version of this CLI, so a change to what `ready` does invalidates every snapshot. */
|
|
3
|
+
export declare const cliMajorVersion: () => string;
|
|
4
|
+
/**
|
|
5
|
+
* A 12 character hash of everything a profile's data is built from: the API checkout's commit, its
|
|
6
|
+
* migrations, the repo's seed files, the profile's seed list, `ethlete.apis.js` and the CLI major version.
|
|
7
|
+
*/
|
|
8
|
+
export declare const fingerprintApi: (options: {
|
|
9
|
+
/** The repo root that holds `ethlete.apis.js` and `.ethlete/seeds`. */
|
|
10
|
+
root: string;
|
|
11
|
+
name: string;
|
|
12
|
+
/** The API checkout root, not its compose directory. */
|
|
13
|
+
repoPath: string;
|
|
14
|
+
migrationsDir?: string;
|
|
15
|
+
seeds: readonly string[];
|
|
16
|
+
cliMajor?: string;
|
|
17
|
+
head?: (repoPath: string) => string | undefined;
|
|
18
|
+
}) => string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fingerprintApi = exports.cliMajorVersion = exports.NO_GIT = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const load_definitions_1 = require("./load-definitions");
|
|
8
|
+
const git_1 = require("./git");
|
|
9
|
+
const seeds_1 = require("./seeds");
|
|
10
|
+
exports.NO_GIT = 'no-git';
|
|
11
|
+
const FINGERPRINT_LENGTH = 12;
|
|
12
|
+
/** The major version of this CLI, so a change to what `ready` does invalidates every snapshot. */
|
|
13
|
+
const cliMajorVersion = () => {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
const manifest = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', '..', '..', 'package.json'), 'utf8'));
|
|
16
|
+
return (_b = (_a = manifest.version) === null || _a === void 0 ? void 0 : _a.split('.')[0]) !== null && _b !== void 0 ? _b : '0';
|
|
17
|
+
};
|
|
18
|
+
exports.cliMajorVersion = cliMajorVersion;
|
|
19
|
+
const filesUnder = (directory) => {
|
|
20
|
+
if (!(0, fs_1.existsSync)(directory))
|
|
21
|
+
return [];
|
|
22
|
+
const walk = (relative) => (0, fs_1.readdirSync)((0, path_1.join)(directory, relative))
|
|
23
|
+
.sort()
|
|
24
|
+
.flatMap((entry) => {
|
|
25
|
+
const name = relative === '' ? entry : `${relative}/${entry}`;
|
|
26
|
+
const stats = (0, fs_1.statSync)((0, path_1.join)(directory, name));
|
|
27
|
+
return stats.isDirectory() ? walk(name) : stats.isFile() ? [name] : [];
|
|
28
|
+
});
|
|
29
|
+
return walk('');
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* A 12 character hash of everything a profile's data is built from: the API checkout's commit, its
|
|
33
|
+
* migrations, the repo's seed files, the profile's seed list, `ethlete.apis.js` and the CLI major version.
|
|
34
|
+
*/
|
|
35
|
+
const fingerprintApi = (options) => {
|
|
36
|
+
var _a;
|
|
37
|
+
const { root, name, repoPath, migrationsDir, seeds, cliMajor = (0, exports.cliMajorVersion)(), head = git_1.headCommit } = options;
|
|
38
|
+
const hash = (0, crypto_1.createHash)('sha256');
|
|
39
|
+
const add = (label, value) => {
|
|
40
|
+
hash.update(`${label}\0${value.length}\0`);
|
|
41
|
+
hash.update(value);
|
|
42
|
+
hash.update('\0');
|
|
43
|
+
};
|
|
44
|
+
const addFiles = (label, directory) => {
|
|
45
|
+
for (const file of filesUnder(directory)) {
|
|
46
|
+
add(`${label}:name`, file);
|
|
47
|
+
add(`${label}:content`, (0, fs_1.readFileSync)((0, path_1.join)(directory, file)));
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
add('head', (_a = head(repoPath)) !== null && _a !== void 0 ? _a : exports.NO_GIT);
|
|
51
|
+
if (migrationsDir !== undefined)
|
|
52
|
+
addFiles('migrations', (0, path_1.join)(repoPath, migrationsDir));
|
|
53
|
+
addFiles('seeds', (0, seeds_1.seedDirectory)(root, name));
|
|
54
|
+
add('profile-seeds', JSON.stringify(seeds));
|
|
55
|
+
for (const fileName of load_definitions_1.API_DEFINITIONS_FILE_NAMES) {
|
|
56
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(root, fileName)))
|
|
57
|
+
add(`definitions:${fileName}`, (0, fs_1.readFileSync)((0, path_1.join)(root, fileName)));
|
|
58
|
+
}
|
|
59
|
+
add('cli', cliMajor);
|
|
60
|
+
return hash.digest('hex').slice(0, FINGERPRINT_LENGTH);
|
|
61
|
+
};
|
|
62
|
+
exports.fingerprintApi = fingerprintApi;
|
|
63
|
+
//# sourceMappingURL=fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/fingerprint.ts"],"names":[],"mappings":"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"}
|
package/src/lib/api/git.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type GitResult = {
|
|
|
4
4
|
stderr: string;
|
|
5
5
|
};
|
|
6
6
|
export declare const currentBranch: (cwd: string) => string | undefined;
|
|
7
|
+
/** The commit `HEAD` names, or `undefined` outside a git checkout. */
|
|
8
|
+
export declare const headCommit: (cwd: string) => string | undefined;
|
|
7
9
|
/** Modified tracked files and untracked files, as git's own porcelain lines, or `undefined` when git fails. */
|
|
8
10
|
export declare const uncommittedChanges: (cwd: string) => string[] | undefined;
|
|
9
11
|
/** Whether git ignores a repo-relative path, or `undefined` outside a git checkout. */
|
package/src/lib/api/git.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.pullApiBranch = exports.checkoutApiBranch = exports.stashEntries = exports.unpushedCommits = exports.hasUncommittedChanges = exports.ignoredByGit = exports.uncommittedChanges = exports.currentBranch = void 0;
|
|
3
|
+
exports.pullApiBranch = exports.checkoutApiBranch = exports.stashEntries = exports.unpushedCommits = exports.hasUncommittedChanges = exports.ignoredByGit = exports.uncommittedChanges = exports.headCommit = exports.currentBranch = void 0;
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
const git = (cwd, args) => {
|
|
6
6
|
var _a, _b, _c;
|
|
@@ -17,6 +17,12 @@ const currentBranch = (cwd) => {
|
|
|
17
17
|
return result.status === 0 ? result.stdout : undefined;
|
|
18
18
|
};
|
|
19
19
|
exports.currentBranch = currentBranch;
|
|
20
|
+
/** The commit `HEAD` names, or `undefined` outside a git checkout. */
|
|
21
|
+
const headCommit = (cwd) => {
|
|
22
|
+
const result = git(cwd, ['rev-parse', 'HEAD']);
|
|
23
|
+
return result.status === 0 && result.stdout !== '' ? result.stdout : undefined;
|
|
24
|
+
};
|
|
25
|
+
exports.headCommit = headCommit;
|
|
20
26
|
/** Modified tracked files and untracked files, as git's own porcelain lines, or `undefined` when git fails. */
|
|
21
27
|
const uncommittedChanges = (cwd) => {
|
|
22
28
|
const { status, stdout } = git(cwd, ['status', '--porcelain']);
|
package/src/lib/api/git.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/git.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/git.ts"],"names":[],"mappings":"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"}
|
package/src/lib/api/help.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.singleApiHelp = exports.apiHelp = void 0;
|
|
4
4
|
const definition_1 = require("./definition");
|
|
5
|
+
const seeds_1 = require("./seeds");
|
|
5
6
|
const BUILT_IN_DESCRIPTIONS = {
|
|
6
7
|
up: 'Start the containers of the API',
|
|
7
8
|
down: 'Stop them',
|
|
@@ -12,7 +13,18 @@ const BUILT_IN_DESCRIPTIONS = {
|
|
|
12
13
|
checkout: 'Switch the checkout to the branch apiRepoBranches names',
|
|
13
14
|
pull: 'Fetch and fast-forward the checked-out branch',
|
|
14
15
|
setup: "Run the API's own setupCommand in its compose directory",
|
|
16
|
+
exec: 'Run a command in a service without a TTY: exec <api> <service> -- <cmd...>',
|
|
17
|
+
doctor: 'Run the checks the API declares: doctor <api> [--fix]',
|
|
18
|
+
run: 'Run a host command under the API lock: run <api> --lock [--wait <s>] -- <cmd...>',
|
|
19
|
+
ready: 'Bring the data of a profile up to date and wait for health: ready <api> --profile <p>',
|
|
20
|
+
snapshot: 'Save or restore the databases of a profile: snapshot save|restore <api> <name> [--profile <p>]',
|
|
21
|
+
status: 'Print profile, fingerprints, dirty flag, snapshot and lock holder: status <api> [--profile <p>]',
|
|
15
22
|
};
|
|
23
|
+
const SEED_DESCRIPTIONS = {
|
|
24
|
+
seed: 'List the seeds in .ethlete/seeds/<name>/seeds.json, or run the ones you name',
|
|
25
|
+
fixtures: 'Run the fixtures of that manifest, then the seeds you name',
|
|
26
|
+
};
|
|
27
|
+
const isSeedCommand = (command) => seeds_1.SEED_API_COMMANDS.some((candidate) => candidate === command);
|
|
16
28
|
const pad = (text, width) => text.padEnd(width);
|
|
17
29
|
/** The help text for `et api`, listing the built-in commands and what each API adds to them. */
|
|
18
30
|
const apiHelp = (apis, invocation) => {
|
|
@@ -20,15 +32,25 @@ const apiHelp = (apis, invocation) => {
|
|
|
20
32
|
const width = Math.max(8, ...entries.map(([name]) => name.length));
|
|
21
33
|
const commandWidth = Math.max(8, ...definition_1.BUILT_IN_API_COMMANDS.map((command) => command.length), ...entries.flatMap(([, api]) => { var _a; return Object.keys((_a = api.exec) !== null && _a !== void 0 ? _a : {}).map((command) => command.length); }));
|
|
22
34
|
const apiLines = entries.map(([name, api]) => ` ${pad(name, width)} ${(0, definition_1.apiCommandNames)(api).join(', ')}`);
|
|
23
|
-
const execNames = [
|
|
35
|
+
const execNames = [
|
|
36
|
+
...new Set(entries.flatMap(([, api]) => { var _a; return Object.keys((_a = api.exec) !== null && _a !== void 0 ? _a : {}).filter((command) => !isSeedCommand(command)); })),
|
|
37
|
+
];
|
|
24
38
|
return [
|
|
25
|
-
`Usage: ${invocation} <command> <api>[,<api>] [--host]`,
|
|
39
|
+
`Usage: ${invocation} <command> <api>[,<api>] [<service> | <seed>[,<seed>]] [--host]`,
|
|
40
|
+
` ${invocation} exec <api> <service> -- <command> [<args>...]`,
|
|
41
|
+
` ${invocation} run <api> --lock [--wait <seconds>] -- <command> [<args>...]`,
|
|
42
|
+
` ${invocation} ready <api> --profile <profile> [--wait <seconds>]`,
|
|
43
|
+
` ${invocation} snapshot save|restore <api> <name> [--profile <profile>] [--wait <seconds>]`,
|
|
26
44
|
'',
|
|
27
45
|
'Commands',
|
|
28
46
|
...definition_1.BUILT_IN_API_COMMANDS.map((command) => ` ${pad(command, commandWidth)} ${BUILT_IN_DESCRIPTIONS[command]}`),
|
|
47
|
+
...seeds_1.SEED_API_COMMANDS.map((command) => ` ${pad(command, commandWidth)} ${SEED_DESCRIPTIONS[command]}`),
|
|
29
48
|
...execNames.map((command) => ` ${pad(command, commandWidth)} Declared by the API itself`),
|
|
30
49
|
` ${pad('help', commandWidth)} What one API accepts, and where its checkout is`,
|
|
31
50
|
'',
|
|
51
|
+
'Everything after -- goes to the command unchanged, and nothing else is written to stdout.',
|
|
52
|
+
`An exec entry named seed or fixtures in ethlete.apis.js runs instead of the built-in command.`,
|
|
53
|
+
'',
|
|
32
54
|
'APIs',
|
|
33
55
|
...(apiLines.length > 0 ? apiLines : [' none — declare them in ethlete.apis.js']),
|
|
34
56
|
'',
|
|
@@ -36,6 +58,8 @@ const apiHelp = (apis, invocation) => {
|
|
|
36
58
|
` ${pad('--host', commandWidth)} Also print the address another device on this network can use`,
|
|
37
59
|
` ${pad('--force', commandWidth)} With up: start even when a port is taken. With pull or clear: lose local work`,
|
|
38
60
|
` ${pad('--all', commandWidth)} With clear: every API at once`,
|
|
61
|
+
` ${pad('--profile', commandWidth)} With ready, snapshot and status: the profile to use`,
|
|
62
|
+
` ${pad('--wait', commandWidth)} With run, ready or snapshot restore: give up after this many seconds, with exit code 75`,
|
|
39
63
|
` ${pad('--clone', commandWidth)} Clone a missing checkout without asking first`,
|
|
40
64
|
` ${pad('--setup', commandWidth)} Run the setup command for a missing env file without asking first`,
|
|
41
65
|
` ${pad('--help', commandWidth)} Show this text`,
|
|
@@ -43,11 +67,14 @@ const apiHelp = (apis, invocation) => {
|
|
|
43
67
|
};
|
|
44
68
|
exports.apiHelp = apiHelp;
|
|
45
69
|
const commandDescription = (api, command) => {
|
|
46
|
-
var _a
|
|
70
|
+
var _a;
|
|
47
71
|
if (command === 'setup' && api.setupCommand)
|
|
48
72
|
return `Run "${api.setupCommand}" in ${api.composeDir}`;
|
|
73
|
+
const execCommand = (_a = api.exec) === null || _a === void 0 ? void 0 : _a[command];
|
|
74
|
+
if (isSeedCommand(command))
|
|
75
|
+
return execCommand ? execCommand.join(' ') : SEED_DESCRIPTIONS[command];
|
|
49
76
|
const builtIn = definition_1.BUILT_IN_API_COMMANDS.find((candidate) => candidate === command);
|
|
50
|
-
return builtIn ? BUILT_IN_DESCRIPTIONS[builtIn] : (
|
|
77
|
+
return builtIn ? BUILT_IN_DESCRIPTIONS[builtIn] : (execCommand !== null && execCommand !== void 0 ? execCommand : []).join(' ');
|
|
51
78
|
};
|
|
52
79
|
/** The help text for one API: every command it accepts, what each one runs, and where its files are. */
|
|
53
80
|
const singleApiHelp = (options) => {
|