@ethlete/cli 2.1.0-next.3 → 2.1.0-next.5
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 +22 -0
- package/README.md +103 -6
- package/package.json +1 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +31 -10
- package/src/index.js.map +1 -1
- package/src/lib/api/api-command.d.ts +4 -0
- package/src/lib/api/api-command.js +27 -0
- package/src/lib/api/api-command.js.map +1 -0
- package/src/lib/api/auth-hint.d.ts +9 -0
- package/src/lib/api/auth-hint.js +33 -0
- package/src/lib/api/auth-hint.js.map +1 -0
- package/src/lib/api/clone.d.ts +12 -0
- package/src/lib/api/clone.js +24 -0
- package/src/lib/api/clone.js.map +1 -0
- package/src/lib/api/compose.d.ts +17 -0
- package/src/lib/api/compose.js +58 -0
- package/src/lib/api/compose.js.map +1 -0
- package/src/lib/api/definition.d.ts +32 -0
- package/src/lib/api/definition.js +9 -0
- package/src/lib/api/definition.js.map +1 -0
- package/src/lib/api/git.d.ts +21 -0
- package/src/lib/api/git.js +59 -0
- package/src/lib/api/git.js.map +1 -0
- package/src/lib/api/help.d.ts +3 -0
- package/src/lib/api/help.js +39 -0
- package/src/lib/api/help.js.map +1 -0
- package/src/lib/api/index.d.ts +10 -0
- package/src/lib/api/index.js +14 -0
- package/src/lib/api/index.js.map +1 -0
- package/src/lib/api/load-definitions.d.ts +16 -0
- package/src/lib/api/load-definitions.js +22 -0
- package/src/lib/api/load-definitions.js.map +1 -0
- package/src/lib/api/resolve-checkout.d.ts +35 -0
- package/src/lib/api/resolve-checkout.js +78 -0
- package/src/lib/api/resolve-checkout.js.map +1 -0
- package/src/lib/api/run.d.ts +10 -0
- package/src/lib/api/run.js +149 -0
- package/src/lib/api/run.js.map +1 -0
- package/src/lib/config/diagnose.d.ts +7 -0
- package/src/lib/config/diagnose.js +103 -0
- package/src/lib/config/diagnose.js.map +1 -0
- package/src/lib/config/index.d.ts +2 -0
- package/src/lib/config/index.js +6 -0
- package/src/lib/config/index.js.map +1 -0
- package/src/lib/config/local-config.d.ts +44 -0
- package/src/lib/config/local-config.js +52 -0
- package/src/lib/config/local-config.js.map +1 -0
- package/src/lib/doctor/doctor-command.d.ts +4 -0
- package/src/lib/doctor/doctor-command.js +65 -0
- package/src/lib/doctor/doctor-command.js.map +1 -0
- package/src/lib/doctor/index.d.ts +1 -0
- package/src/lib/doctor/index.js +5 -0
- package/src/lib/doctor/index.js.map +1 -0
- package/src/lib/index.d.ts +3 -0
- package/src/lib/index.js +3 -0
- package/src/lib/index.js.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @ethlete/cli
|
|
2
2
|
|
|
3
|
+
## 2.1.0-next.5
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`612d735`](https://github.com/ethlete-io/ethdk/commit/612d73563e1689bbfcf948d26ebe7c59d2420781) Thanks [@TomTomB](https://github.com/TomTomB)! - `et api` now clones a missing API checkout from a `repoUrl` in `ethlete.apis.js`, making
|
|
8
|
+
`apiRepoPaths` optional. `runApiCommand` is async as a result.
|
|
9
|
+
|
|
10
|
+
- [#3072](https://github.com/ethlete-io/ethdk/pull/3072) [`4bbbb51`](https://github.com/ethlete-io/ethdk/commit/4bbbb5167989a1c3ef2ffeba09fcfd18ba953fba) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `et doctor` to check this machine's config, container engine and API checkouts, `et api
|
|
11
|
+
checkout` and `et api pull` (with `--force`) to move an API checkout to the branch it should be on,
|
|
12
|
+
and `et api --help`.
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- [#3072](https://github.com/ethlete-io/ethdk/pull/3072) [`0fd8ba3`](https://github.com/ethlete-io/ethdk/commit/0fd8ba3dd61cc78409c397c8180f0a675282642f) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et doctor` now says when a directory has neither config file rather than reporting no problems.
|
|
17
|
+
|
|
18
|
+
## 2.1.0-next.4
|
|
19
|
+
|
|
20
|
+
### Minor Changes
|
|
21
|
+
|
|
22
|
+
- [`b6fe4be`](https://github.com/ethlete-io/ethdk/commit/b6fe4beae010aaa2e0e367d636f6759442983395) Thanks [@TomTomB](https://github.com/TomTomB)! - Add `et api` to run an app's backend from a local checkout, declared in `ethlete.apis.js`. The new
|
|
23
|
+
`ethlete.config.local.json` says where the sibling checkouts on this machine live.
|
|
24
|
+
|
|
3
25
|
## 2.1.0-next.3
|
|
4
26
|
|
|
5
27
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,11 +1,108 @@
|
|
|
1
|
-
# cli
|
|
1
|
+
# @ethlete/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Repo tooling - installs the `et` binary.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
yarn add --dev @ethlete/cli
|
|
9
|
+
```
|
|
8
10
|
|
|
9
|
-
##
|
|
11
|
+
## `et release`
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
```bash
|
|
14
|
+
yarn et release
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Turns pending changesets into a tagged, pushed release commit (version → tag → commit → push).
|
|
18
|
+
|
|
19
|
+
## `et api`
|
|
20
|
+
|
|
21
|
+
Runs the API an app in this repo talks to, from a checkout on your own machine.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
yarn et api --help # the commands, the APIs and what each one accepts
|
|
25
|
+
yarn et api up hub # start the containers
|
|
26
|
+
yarn et api down hub # stop them
|
|
27
|
+
yarn et api logs hub # follow the API's log
|
|
28
|
+
yarn et api shell hub # a shell in the API container
|
|
29
|
+
yarn et api install hub # an entry from that API's own "exec" map
|
|
30
|
+
yarn et api up hub --host # also print the address other devices can reach
|
|
31
|
+
yarn et api checkout hub # switch the checkout to the branch apiRepoBranches names
|
|
32
|
+
yarn et api pull hub # fetch and fast-forward the checked-out branch
|
|
33
|
+
yarn et api pull hub --force # the same, discarding local commits and tracked changes
|
|
34
|
+
yarn et api clone hub # clone the API into .ethlete/hub
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`checkout` and `pull` act on the checkout itself, so they work before `make setup` has run and need
|
|
38
|
+
no container engine. `pull` refuses to run on a checkout with uncommitted changes unless you pass
|
|
39
|
+
`--force`. `--force` resets the branch to its remote and throws away local commits and tracked
|
|
40
|
+
changes; it never touches untracked or ignored files, so a `vendor/` directory or a `.env` survives.
|
|
41
|
+
|
|
42
|
+
The first container tool that answers is used, in this order: `docker compose`,
|
|
43
|
+
`container compose`, `podman-compose`, `podman compose`.
|
|
44
|
+
|
|
45
|
+
## `et doctor`
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
yarn et doctor
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Checks `ethlete.config.local.json`, reports the container engine it would use, and resolves every
|
|
52
|
+
API declared in `ethlete.apis.js`. It exits non-zero when it finds a problem, so CI can run it.
|
|
53
|
+
|
|
54
|
+
### Declaring the APIs
|
|
55
|
+
|
|
56
|
+
`ethlete.apis.js` at the repo root describes each API's compose setup. It is a module rather
|
|
57
|
+
than JSON because `env` is a function:
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
const { sshKeyPath } = require('@ethlete/cli');
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
hub: {
|
|
64
|
+
composeDir: 'development',
|
|
65
|
+
services: ['app', 'database', 'mailhog'],
|
|
66
|
+
execService: 'app',
|
|
67
|
+
port: 8040,
|
|
68
|
+
envFile: '.env',
|
|
69
|
+
setupCommand: 'make setup',
|
|
70
|
+
network: 'shared-fut',
|
|
71
|
+
envKey: 'hubApiEnv',
|
|
72
|
+
examplePath: '../fut-hub-backend',
|
|
73
|
+
env: () => ({ SSH_PRIVATE_KEY: sshKeyPath() }),
|
|
74
|
+
exec: {
|
|
75
|
+
install: ['composer', 'install'],
|
|
76
|
+
'reset-db': ['make', 'reset-db-with-dev-fixtures'],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Adding an API is an entry in this map. Nothing else changes.
|
|
83
|
+
|
|
84
|
+
### Where the checkouts live
|
|
85
|
+
|
|
86
|
+
Give an API a `repoUrl` and `et api` clones it into a gitignored `.ethlete/<name>` when you have no
|
|
87
|
+
checkout of your own, asking first (or use `--clone`). To point at a checkout you already have - which
|
|
88
|
+
you want whenever you work in the backend, since compose mounts it into the container - set
|
|
89
|
+
`apiRepoPaths` in a gitignored `ethlete.config.local.json` at the repo root. `@ethlete/agent-rules` reads the same file, so its skills and `et` agree on where a
|
|
90
|
+
checkout is:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"sdkSourcePath": "/absolute/path/to/ethlete-sdk",
|
|
95
|
+
"apiRepoPaths": { "hub": "../fut-hub-backend", "*": "../shared-backend" },
|
|
96
|
+
"apiRepoBranches": { "hub": "develop", "*": "main" }
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Matching is exact; `"*"` is an explicit shared fallback. A relative path resolves from the repo
|
|
101
|
+
root. These keys used to live in `ethlete-agents.config.local.json`, which is still read as a
|
|
102
|
+
fallback with a warning. Add `ethlete.config.local.json` to your `.gitignore`.
|
|
103
|
+
|
|
104
|
+
## Documentation
|
|
105
|
+
|
|
106
|
+
Full command reference on the docs site:
|
|
107
|
+
|
|
108
|
+
- [Overview & usage](https://ethlete-sdk-docs.web.app/cli/)
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './lib';
|
package/src/index.js
CHANGED
|
@@ -2,19 +2,40 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const lib_1 = require("./lib");
|
|
5
|
+
const USAGE = `et — Ethlete repo tooling
|
|
6
|
+
|
|
7
|
+
et release Turn pending changesets into a tagged, pushed release commit
|
|
8
|
+
et api <cmd> <api> Run an API from this repo's ethlete.apis.js locally
|
|
9
|
+
(up, down, logs, shell, plus that API's own exec entries)
|
|
10
|
+
et doctor Check this machine's ethlete.config.local.json, container engine
|
|
11
|
+
and every API checkout
|
|
12
|
+
`;
|
|
5
13
|
const cli = (args) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
6
|
-
|
|
7
|
-
switch (cliFunctionArg) {
|
|
14
|
+
switch (args[0]) {
|
|
8
15
|
case 'release':
|
|
9
|
-
|
|
10
|
-
|
|
16
|
+
// `release` reads its flags from a list that was split on "=" before this switch existed.
|
|
17
|
+
// Keep that shape here so its own parsing is untouched.
|
|
18
|
+
yield (0, lib_1.release)(args.join('=').split('='));
|
|
19
|
+
return 0;
|
|
20
|
+
case 'api':
|
|
21
|
+
return (0, lib_1.apiCommand)({ root: process.cwd(), argv: args.slice(1) });
|
|
22
|
+
case 'doctor':
|
|
23
|
+
return (0, lib_1.doctorCommand)({ root: process.cwd() });
|
|
11
24
|
default:
|
|
12
|
-
console.log(
|
|
13
|
-
|
|
25
|
+
console.log(USAGE);
|
|
26
|
+
return args[0] === undefined || args[0] === '--help' || args[0] === '-h' ? 0 : 1;
|
|
14
27
|
}
|
|
15
28
|
});
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
tslib_1.__exportStar(require("./lib"), exports);
|
|
30
|
+
// Guarded so the package can also be imported as a library without running the CLI.
|
|
31
|
+
if (require.main === module) {
|
|
32
|
+
cli(process.argv.slice(2))
|
|
33
|
+
.then((code) => {
|
|
34
|
+
process.exitCode = code;
|
|
35
|
+
})
|
|
36
|
+
.catch((error) => {
|
|
37
|
+
console.error(error instanceof Error ? error.message : error);
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
20
41
|
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/cli/src/index.ts"],"names":[],"mappings":";;;AAAA,+
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/cli/src/index.ts"],"names":[],"mappings":";;;AAAA,+BAA2D;AAE3D,MAAM,KAAK,GAAG;;;;;;;CAOb,CAAC;AAEF,MAAM,GAAG,GAAG,CAAO,IAAc,EAAmB,EAAE;IACpD,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAChB,KAAK,SAAS;YACZ,0FAA0F;YAC1F,wDAAwD;YACxD,MAAM,IAAA,aAAO,EAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAEzC,OAAO,CAAC,CAAC;QAEX,KAAK,KAAK;YACR,OAAO,IAAA,gBAAU,EAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAElE,KAAK,QAAQ;YACX,OAAO,IAAA,mBAAa,EAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAEhD;YACE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAEnB,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC;AACH,CAAC,CAAA,CAAC;AAEF,gDAAsB;AAEtB,oFAAoF;AACpF,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACvB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACb,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC1B,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACxB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC9D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.apiCommand = void 0;
|
|
4
|
+
const load_definitions_1 = require("./load-definitions");
|
|
5
|
+
const run_1 = require("./run");
|
|
6
|
+
const apiCommand = ({ root, argv }) => {
|
|
7
|
+
const { found, apis } = (0, load_definitions_1.loadApiDefinitions)(root);
|
|
8
|
+
if (!found) {
|
|
9
|
+
console.error(`No API definitions found. Create ${load_definitions_1.API_DEFINITIONS_FILE_NAMES[0]} in the repo root:\n\n` +
|
|
10
|
+
` const { sshKeyPath } = require('@ethlete/cli');\n\n` +
|
|
11
|
+
` module.exports = {\n` +
|
|
12
|
+
` hub: {\n` +
|
|
13
|
+
` composeDir: 'development',\n` +
|
|
14
|
+
` services: ['app', 'database'],\n` +
|
|
15
|
+
` execService: 'app',\n` +
|
|
16
|
+
` port: 8040,\n` +
|
|
17
|
+
` envFile: '.env',\n` +
|
|
18
|
+
` setupCommand: 'make setup',\n` +
|
|
19
|
+
` exec: { install: ['composer', 'install'] },\n` +
|
|
20
|
+
` },\n` +
|
|
21
|
+
` };`);
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
return (0, run_1.runApiCommand)({ apis, argv, root });
|
|
25
|
+
};
|
|
26
|
+
exports.apiCommand = apiCommand;
|
|
27
|
+
//# sourceMappingURL=api-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-command.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/api-command.ts"],"names":[],"mappings":";;;AAAA,yDAAoF;AACpF,+BAAsC;AAE/B,MAAM,UAAU,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAoC,EAAE,EAAE;IAC7E,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAA,qCAAkB,EAAC,IAAI,CAAC,CAAC;IAEjD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CACX,oCAAoC,6CAA0B,CAAC,CAAC,CAAC,wBAAwB;YACvF,uDAAuD;YACvD,wBAAwB;YACxB,cAAc;YACd,oCAAoC;YACpC,wCAAwC;YACxC,6BAA6B;YAC7B,qBAAqB;YACrB,0BAA0B;YAC1B,qCAAqC;YACrC,qDAAqD;YACrD,UAAU;YACV,MAAM,CACT,CAAC;QAEF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,IAAA,mBAAa,EAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC,CAAC;AAxBW,QAAA,UAAU,cAwBrB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A private dependency that will not download is the most common way these commands fail, and git
|
|
3
|
+
* and the package managers report it as a bare 403 or a public-key error. This says what to check.
|
|
4
|
+
*/
|
|
5
|
+
export declare const printPrivateDependencyHint: (options: {
|
|
6
|
+
repoHost?: string;
|
|
7
|
+
}) => void;
|
|
8
|
+
/** The host of a git url, for naming it in the hint. Undefined when the url has no host. */
|
|
9
|
+
export declare const gitUrlHost: (repoUrl: string) => string | undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gitUrlHost = exports.printPrivateDependencyHint = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A private dependency that will not download is the most common way these commands fail, and git
|
|
6
|
+
* and the package managers report it as a bare 403 or a public-key error. This says what to check.
|
|
7
|
+
*/
|
|
8
|
+
const printPrivateDependencyHint = (options) => {
|
|
9
|
+
var _a;
|
|
10
|
+
const host = (_a = options.repoHost) !== null && _a !== void 0 ? _a : 'your git host';
|
|
11
|
+
console.error(`\nThat command may have failed because a private dependency could not be downloaded.\n` +
|
|
12
|
+
`Three things are worth checking:\n\n` +
|
|
13
|
+
` 1. A personal access token for ${host} with permission to DOWNLOAD code.\n` +
|
|
14
|
+
` Read access is not enough for a clone, and the server reports the difference as 403.\n` +
|
|
15
|
+
` 2. An SSH key this machine offers to ${host}, when the dependency is fetched over SSH.\n` +
|
|
16
|
+
` 3. That the token is where the package manager looks for it, not only in your shell.\n` +
|
|
17
|
+
` Composer, for example, reads ~/.composer/auth.json rather than the environment.`);
|
|
18
|
+
};
|
|
19
|
+
exports.printPrivateDependencyHint = printPrivateDependencyHint;
|
|
20
|
+
/** The host of a git url, for naming it in the hint. Undefined when the url has no host. */
|
|
21
|
+
const gitUrlHost = (repoUrl) => {
|
|
22
|
+
const scpLike = /^[^/]+@([^:]+):/.exec(repoUrl);
|
|
23
|
+
if (scpLike)
|
|
24
|
+
return scpLike[1];
|
|
25
|
+
try {
|
|
26
|
+
return new URL(repoUrl).hostname || undefined;
|
|
27
|
+
}
|
|
28
|
+
catch (_a) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
exports.gitUrlHost = gitUrlHost;
|
|
33
|
+
//# sourceMappingURL=auth-hint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-hint.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/auth-hint.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACI,MAAM,0BAA0B,GAAG,CAAC,OAA8B,EAAE,EAAE;;IAC3E,MAAM,IAAI,GAAG,MAAA,OAAO,CAAC,QAAQ,mCAAI,eAAe,CAAC;IAEjD,OAAO,CAAC,KAAK,CACX,wFAAwF;QACtF,sCAAsC;QACtC,oCAAoC,IAAI,sCAAsC;QAC9E,6FAA6F;QAC7F,0CAA0C,IAAI,8CAA8C;QAC5F,0FAA0F;QAC1F,sFAAsF,CACzF,CAAC;AACJ,CAAC,CAAC;AAZW,QAAA,0BAA0B,8BAYrC;AAEF,4FAA4F;AACrF,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,EAAE;IAC5C,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IAE/B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAC;IAChD,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,CAAC;AAVW,QAAA,UAAU,cAUrB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const DEFAULT_CHECKOUT_DIR = ".ethlete";
|
|
2
|
+
/** True when git would ignore the path, so a cloned checkout cannot be committed by accident. */
|
|
3
|
+
export declare const isGitIgnored: (root: string, path: string) => boolean;
|
|
4
|
+
export type CloneRequest = {
|
|
5
|
+
repoUrl: string;
|
|
6
|
+
/** Absolute path to clone into. */
|
|
7
|
+
into: string;
|
|
8
|
+
/** Branch to check out, from `apiRepoBranches`. */
|
|
9
|
+
branch?: string;
|
|
10
|
+
};
|
|
11
|
+
/** Clones an API repo into its managed directory. Git's own output and failures are passed through. */
|
|
12
|
+
export declare const cloneApiRepo: ({ repoUrl, into, branch }: CloneRequest) => number;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cloneApiRepo = exports.isGitIgnored = exports.DEFAULT_CHECKOUT_DIR = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const fs_2 = require("fs");
|
|
8
|
+
exports.DEFAULT_CHECKOUT_DIR = '.ethlete';
|
|
9
|
+
/** True when git would ignore the path, so a cloned checkout cannot be committed by accident. */
|
|
10
|
+
const isGitIgnored = (root, path) => (0, child_process_1.spawnSync)('git', ['check-ignore', '-q', path], { cwd: root }).status === 0;
|
|
11
|
+
exports.isGitIgnored = isGitIgnored;
|
|
12
|
+
/** Clones an API repo into its managed directory. Git's own output and failures are passed through. */
|
|
13
|
+
const cloneApiRepo = ({ repoUrl, into, branch }) => {
|
|
14
|
+
var _a;
|
|
15
|
+
if ((0, fs_1.existsSync)(into)) {
|
|
16
|
+
console.error(`${into} already exists.`);
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
(0, fs_2.mkdirSync)((0, path_1.dirname)(into), { recursive: true });
|
|
20
|
+
const args = ['clone', ...(branch ? ['--branch', branch] : []), '--', repoUrl, into];
|
|
21
|
+
return (_a = (0, child_process_1.spawnSync)('git', args, { stdio: 'inherit' }).status) !== null && _a !== void 0 ? _a : 1;
|
|
22
|
+
};
|
|
23
|
+
exports.cloneApiRepo = cloneApiRepo;
|
|
24
|
+
//# sourceMappingURL=clone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/clone.ts"],"names":[],"mappings":";;;AAAA,iDAA0C;AAC1C,2BAAgC;AAChC,+BAA+B;AAC/B,2BAA+B;AAElB,QAAA,oBAAoB,GAAG,UAAU,CAAC;AAE/C,iGAAiG;AAC1F,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CACzD,IAAA,yBAAS,EAAC,KAAK,EAAE,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AADhE,QAAA,YAAY,gBACoD;AAU7E,uGAAuG;AAChG,MAAM,YAAY,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,EAAE,EAAE;;IACtE,IAAI,IAAA,eAAU,EAAC,IAAI,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,kBAAkB,CAAC,CAAC;QAEzC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAA,cAAS,EAAC,IAAA,cAAO,EAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9C,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAErF,OAAO,MAAA,IAAA,yBAAS,EAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,mCAAI,CAAC,CAAC;AAClE,CAAC,CAAC;AAZW,QAAA,YAAY,gBAYvB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ComposeTool = {
|
|
2
|
+
engine: string;
|
|
3
|
+
/** The binary and its fixed arguments. Non-empty, so the first entry is always the binary. */
|
|
4
|
+
compose: [string, ...string[]];
|
|
5
|
+
};
|
|
6
|
+
export declare const composeBinary: (compose: string[]) => string[];
|
|
7
|
+
/** Finds the first container tool on this machine that answers `<compose> version`. */
|
|
8
|
+
export declare const resolveComposeTool: (tools?: ComposeTool[]) => ComposeTool | undefined;
|
|
9
|
+
export declare const composeToolNames: (tools?: ComposeTool[]) => string[];
|
|
10
|
+
export declare const engineEnv: (engine: string) => {
|
|
11
|
+
CONTAINERS_REGISTRIES_CONF: string;
|
|
12
|
+
} | {
|
|
13
|
+
CONTAINERS_REGISTRIES_CONF?: undefined;
|
|
14
|
+
};
|
|
15
|
+
export declare const lanAddress: () => string | undefined;
|
|
16
|
+
/** Path of this machine's SSH key, for a compose file that mounts one into the API container. */
|
|
17
|
+
export declare const sshKeyPath: () => string | undefined;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sshKeyPath = exports.lanAddress = exports.engineEnv = exports.composeToolNames = exports.resolveComposeTool = exports.composeBinary = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const os_1 = require("os");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
/**
|
|
9
|
+
* SELinux denies a container read access to a bind mount that carries the host's own label, and API
|
|
10
|
+
* repos mount their checkout without the `:z` that would relabel it. Disabling the label from here
|
|
11
|
+
* keeps those checkouts untouched.
|
|
12
|
+
*/
|
|
13
|
+
const PODMAN_COMPOSE_ARGS = ['--podman-run-args=--security-opt label=disable'];
|
|
14
|
+
const COMPOSE_TOOLS = [
|
|
15
|
+
{ engine: 'docker', compose: ['docker', 'compose'] },
|
|
16
|
+
{ engine: 'container', compose: ['container', 'compose'] },
|
|
17
|
+
{ engine: 'podman', compose: ['podman-compose', ...PODMAN_COMPOSE_ARGS] },
|
|
18
|
+
{ engine: 'podman', compose: ['podman', 'compose', ...PODMAN_COMPOSE_ARGS] },
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Podman refuses to resolve a short image name such as `mysql:8.0` without a TTY prompt when several
|
|
22
|
+
* unqualified search registries are configured. API compose files use short names, so point podman
|
|
23
|
+
* at one registry and turn the prompt off.
|
|
24
|
+
*/
|
|
25
|
+
const PODMAN_REGISTRIES_CONF = `unqualified-search-registries = ["docker.io"]\nshort-name-mode = "disabled"\n`;
|
|
26
|
+
let podmanRegistriesConfPath;
|
|
27
|
+
const writePodmanRegistriesConf = () => {
|
|
28
|
+
podmanRegistriesConfPath !== null && podmanRegistriesConfPath !== void 0 ? podmanRegistriesConfPath : (podmanRegistriesConfPath = (0, path_1.join)((0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'ethlete-api-')), 'registries.conf'));
|
|
29
|
+
(0, fs_1.writeFileSync)(podmanRegistriesConfPath, PODMAN_REGISTRIES_CONF, 'utf8');
|
|
30
|
+
return podmanRegistriesConfPath;
|
|
31
|
+
};
|
|
32
|
+
const composeBinary = (compose) => compose.filter((part) => !part.startsWith('--'));
|
|
33
|
+
exports.composeBinary = composeBinary;
|
|
34
|
+
const canRun = (command, args) => {
|
|
35
|
+
const result = (0, child_process_1.spawnSync)(command, args, { stdio: 'ignore' });
|
|
36
|
+
return result.error === undefined && result.status === 0;
|
|
37
|
+
};
|
|
38
|
+
/** Finds the first container tool on this machine that answers `<compose> version`. */
|
|
39
|
+
const resolveComposeTool = (tools = COMPOSE_TOOLS) => tools.find(({ compose }) => {
|
|
40
|
+
const [binary, ...rest] = (0, exports.composeBinary)(compose);
|
|
41
|
+
return binary !== undefined && canRun(binary, [...rest, 'version']);
|
|
42
|
+
});
|
|
43
|
+
exports.resolveComposeTool = resolveComposeTool;
|
|
44
|
+
const composeToolNames = (tools = COMPOSE_TOOLS) => tools.map(({ compose }) => (0, exports.composeBinary)(compose).join(' '));
|
|
45
|
+
exports.composeToolNames = composeToolNames;
|
|
46
|
+
const engineEnv = (engine) => engine === 'podman' ? { CONTAINERS_REGISTRIES_CONF: writePodmanRegistriesConf() } : {};
|
|
47
|
+
exports.engineEnv = engineEnv;
|
|
48
|
+
const lanAddress = () => {
|
|
49
|
+
var _a;
|
|
50
|
+
return (_a = Object.values((0, os_1.networkInterfaces)())
|
|
51
|
+
.flat()
|
|
52
|
+
.find((networkInterface) => (networkInterface === null || networkInterface === void 0 ? void 0 : networkInterface.family) === 'IPv4' && !networkInterface.internal)) === null || _a === void 0 ? void 0 : _a.address;
|
|
53
|
+
};
|
|
54
|
+
exports.lanAddress = lanAddress;
|
|
55
|
+
/** Path of this machine's SSH key, for a compose file that mounts one into the API container. */
|
|
56
|
+
const sshKeyPath = () => [(0, path_1.join)((0, os_1.homedir)(), '.ssh/id_ed25519'), (0, path_1.join)((0, os_1.homedir)(), '.ssh/id_rsa')].find((path) => (0, fs_1.existsSync)(path));
|
|
57
|
+
exports.sshKeyPath = sshKeyPath;
|
|
58
|
+
//# sourceMappingURL=compose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/compose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** One API this repo can run locally. Everything here describes the API's own compose setup. */
|
|
2
|
+
export type ApiDefinition = {
|
|
3
|
+
/** Directory inside the API checkout that holds the compose file, for example `development`. */
|
|
4
|
+
composeDir: string;
|
|
5
|
+
/** Compose services to start. Leave out a service the app does not need, such as a bundled frontend. */
|
|
6
|
+
services: string[];
|
|
7
|
+
/** Service that `shell`, `logs` and every `exec` entry run in. */
|
|
8
|
+
execService: string;
|
|
9
|
+
/** Published host port, not the port inside the container. Used for the printed url. */
|
|
10
|
+
port: number;
|
|
11
|
+
/** File that must exist in `composeDir` before the API can start, for example `.env`. */
|
|
12
|
+
envFile?: string;
|
|
13
|
+
/** Command that creates `envFile`. Named in the error when the file is missing. */
|
|
14
|
+
setupCommand?: string;
|
|
15
|
+
/** External container network to create before the first `up`. */
|
|
16
|
+
network?: string;
|
|
17
|
+
/** Example path shown in the error that asks the developer to configure this API's checkout. */
|
|
18
|
+
examplePath?: string;
|
|
19
|
+
/** Where to clone this API from when the developer has no checkout of their own. */
|
|
20
|
+
repoUrl?: string;
|
|
21
|
+
/** localStorage key the app reads to pick its API. Printed by `--host`. */
|
|
22
|
+
envKey?: string;
|
|
23
|
+
/** Extra environment for every compose call. An undefined value is dropped rather than passed as "undefined". */
|
|
24
|
+
env?: () => Record<string, string | undefined>;
|
|
25
|
+
/** Named commands run in `execService`, for example `{ install: ['composer', 'install'] }`. */
|
|
26
|
+
exec?: Record<string, string[]>;
|
|
27
|
+
};
|
|
28
|
+
export type ApiDefinitions = Record<string, ApiDefinition>;
|
|
29
|
+
export declare const BUILT_IN_API_COMMANDS: readonly ["up", "down", "logs", "shell", "clone", "checkout", "pull"];
|
|
30
|
+
/** These act on the checkout itself, so they run before `make setup` and need no container engine. */
|
|
31
|
+
export declare const GIT_API_COMMANDS: string[];
|
|
32
|
+
export declare const apiCommandNames: (api: ApiDefinition) => string[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.apiCommandNames = exports.GIT_API_COMMANDS = exports.BUILT_IN_API_COMMANDS = void 0;
|
|
4
|
+
exports.BUILT_IN_API_COMMANDS = ['up', 'down', 'logs', 'shell', 'clone', 'checkout', 'pull'];
|
|
5
|
+
/** These act on the checkout itself, so they run before `make setup` and need no container engine. */
|
|
6
|
+
exports.GIT_API_COMMANDS = ['clone', 'checkout', 'pull'];
|
|
7
|
+
const apiCommandNames = (api) => { var _a; return [...exports.BUILT_IN_API_COMMANDS, ...Object.keys((_a = api.exec) !== null && _a !== void 0 ? _a : {})]; };
|
|
8
|
+
exports.apiCommandNames = apiCommandNames;
|
|
9
|
+
//# sourceMappingURL=definition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definition.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/definition.ts"],"names":[],"mappings":";;;AA8Ba,QAAA,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAU,CAAC;AAE3G,sGAAsG;AACzF,QAAA,gBAAgB,GAAa,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;AAEjE,MAAM,eAAe,GAAG,CAAC,GAAkB,EAAE,EAAE,WAAC,OAAA,CAAC,GAAG,6BAAqB,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,MAAA,GAAG,CAAC,IAAI,mCAAI,EAAE,CAAC,CAAC,CAAA,EAAA,CAAC;AAArG,QAAA,eAAe,mBAAsF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type GitResult = {
|
|
2
|
+
status: number;
|
|
3
|
+
stdout: string;
|
|
4
|
+
stderr: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const currentBranch: (cwd: string) => string | undefined;
|
|
7
|
+
export declare const hasUncommittedChanges: (cwd: string) => boolean;
|
|
8
|
+
/** Switches the API checkout to the branch configured for it. Git's own refusal is passed through. */
|
|
9
|
+
export declare const checkoutApiBranch: (options: {
|
|
10
|
+
repoPath: string;
|
|
11
|
+
branch: string;
|
|
12
|
+
}) => number;
|
|
13
|
+
/**
|
|
14
|
+
* Fast-forwards the checked-out branch. `force` throws away local commits and uncommitted tracked
|
|
15
|
+
* changes on it; untracked files such as `vendor/` and `.env` are never touched.
|
|
16
|
+
*/
|
|
17
|
+
export declare const pullApiBranch: (options: {
|
|
18
|
+
repoPath: string;
|
|
19
|
+
expectedBranch?: string;
|
|
20
|
+
force: boolean;
|
|
21
|
+
}) => number;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pullApiBranch = exports.checkoutApiBranch = exports.hasUncommittedChanges = exports.currentBranch = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const git = (cwd, args) => {
|
|
6
|
+
var _a, _b, _c;
|
|
7
|
+
const result = (0, child_process_1.spawnSync)('git', args, { cwd, encoding: 'utf8' });
|
|
8
|
+
return {
|
|
9
|
+
status: (_a = result.status) !== null && _a !== void 0 ? _a : 1,
|
|
10
|
+
stdout: ((_b = result.stdout) !== null && _b !== void 0 ? _b : '').trim(),
|
|
11
|
+
stderr: ((_c = result.stderr) !== null && _c !== void 0 ? _c : '').trim(),
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
const gitInherit = (cwd, args) => { var _a; return (_a = (0, child_process_1.spawnSync)('git', args, { cwd, stdio: 'inherit' }).status) !== null && _a !== void 0 ? _a : 1; };
|
|
15
|
+
const currentBranch = (cwd) => {
|
|
16
|
+
const result = git(cwd, ['rev-parse', '--abbrev-ref', 'HEAD']);
|
|
17
|
+
return result.status === 0 ? result.stdout : undefined;
|
|
18
|
+
};
|
|
19
|
+
exports.currentBranch = currentBranch;
|
|
20
|
+
const hasUncommittedChanges = (cwd) => git(cwd, ['status', '--porcelain']).stdout.length > 0;
|
|
21
|
+
exports.hasUncommittedChanges = hasUncommittedChanges;
|
|
22
|
+
/** Switches the API checkout to the branch configured for it. Git's own refusal is passed through. */
|
|
23
|
+
const checkoutApiBranch = (options) => {
|
|
24
|
+
const { repoPath, branch } = options;
|
|
25
|
+
if ((0, exports.currentBranch)(repoPath) === branch) {
|
|
26
|
+
console.log(`Already on ${branch}.`);
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
return gitInherit(repoPath, ['checkout', branch]);
|
|
30
|
+
};
|
|
31
|
+
exports.checkoutApiBranch = checkoutApiBranch;
|
|
32
|
+
/**
|
|
33
|
+
* Fast-forwards the checked-out branch. `force` throws away local commits and uncommitted tracked
|
|
34
|
+
* changes on it; untracked files such as `vendor/` and `.env` are never touched.
|
|
35
|
+
*/
|
|
36
|
+
const pullApiBranch = (options) => {
|
|
37
|
+
const { repoPath, expectedBranch, force } = options;
|
|
38
|
+
const branch = (0, exports.currentBranch)(repoPath);
|
|
39
|
+
if (!branch) {
|
|
40
|
+
console.error(`${repoPath} is not a git checkout.`);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
if (expectedBranch && branch !== expectedBranch) {
|
|
44
|
+
console.warn(`On ${branch}, but apiRepoBranches expects ${expectedBranch}. Pulling ${branch}.\n`);
|
|
45
|
+
}
|
|
46
|
+
if (!force && (0, exports.hasUncommittedChanges)(repoPath)) {
|
|
47
|
+
console.error(`${repoPath} has uncommitted changes. Commit or stash them, or pass --force to discard them.`);
|
|
48
|
+
return 1;
|
|
49
|
+
}
|
|
50
|
+
const fetched = gitInherit(repoPath, ['fetch', 'origin', branch]);
|
|
51
|
+
if (fetched !== 0)
|
|
52
|
+
return fetched;
|
|
53
|
+
if (!force)
|
|
54
|
+
return gitInherit(repoPath, ['merge', '--ff-only', `origin/${branch}`]);
|
|
55
|
+
console.log(`Discarding local commits and tracked changes on ${branch}.`);
|
|
56
|
+
return gitInherit(repoPath, ['reset', '--hard', `origin/${branch}`]);
|
|
57
|
+
};
|
|
58
|
+
exports.pullApiBranch = pullApiBranch;
|
|
59
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.apiHelp = void 0;
|
|
4
|
+
const definition_1 = require("./definition");
|
|
5
|
+
const BUILT_IN_DESCRIPTIONS = {
|
|
6
|
+
up: 'Start the containers of the API',
|
|
7
|
+
down: 'Stop them',
|
|
8
|
+
logs: 'Follow the log of the API container',
|
|
9
|
+
shell: 'Open a shell in the API container',
|
|
10
|
+
clone: 'Clone the API into .ethlete/<name> from its repoUrl',
|
|
11
|
+
checkout: 'Switch the checkout to the branch apiRepoBranches names',
|
|
12
|
+
pull: 'Fetch and fast-forward the checked-out branch',
|
|
13
|
+
};
|
|
14
|
+
const pad = (text, width) => text.padEnd(width);
|
|
15
|
+
/** The help text for `et api`, listing the built-in commands and what each API adds to them. */
|
|
16
|
+
const apiHelp = (apis, invocation) => {
|
|
17
|
+
const entries = Object.entries(apis);
|
|
18
|
+
const width = Math.max(8, ...entries.map(([name]) => name.length));
|
|
19
|
+
const apiLines = entries.map(([name, api]) => ` ${pad(name, width)} ${(0, definition_1.apiCommandNames)(api).join(', ')}`);
|
|
20
|
+
const execNames = [...new Set(entries.flatMap(([, api]) => { var _a; return Object.keys((_a = api.exec) !== null && _a !== void 0 ? _a : {}); }))];
|
|
21
|
+
return [
|
|
22
|
+
`Usage: ${invocation} <command> <api> [--host]`,
|
|
23
|
+
'',
|
|
24
|
+
'Commands',
|
|
25
|
+
...definition_1.BUILT_IN_API_COMMANDS.map((command) => ` ${pad(command, 8)} ${BUILT_IN_DESCRIPTIONS[command]}`),
|
|
26
|
+
...execNames.map((command) => ` ${pad(command, 8)} Declared by the API itself`),
|
|
27
|
+
'',
|
|
28
|
+
'APIs',
|
|
29
|
+
...(apiLines.length > 0 ? apiLines : [' none — declare them in ethlete.apis.js']),
|
|
30
|
+
'',
|
|
31
|
+
'Options',
|
|
32
|
+
` ${pad('--host', 8)} Also print the address another device on this network can use`,
|
|
33
|
+
` ${pad('--force', 8)} With pull: discard local commits and tracked changes on the branch`,
|
|
34
|
+
` ${pad('--clone', 8)} Clone a missing checkout without asking first`,
|
|
35
|
+
` ${pad('--help', 8)} Show this text`,
|
|
36
|
+
].join('\n');
|
|
37
|
+
};
|
|
38
|
+
exports.apiHelp = apiHelp;
|
|
39
|
+
//# sourceMappingURL=help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/lib/api/help.ts"],"names":[],"mappings":";;;AAAA,6CAAsF;AAEtF,MAAM,qBAAqB,GAA2D;IACpF,EAAE,EAAE,iCAAiC;IACrC,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,qCAAqC;IAC3C,KAAK,EAAE,mCAAmC;IAC1C,KAAK,EAAE,qDAAqD;IAC5D,QAAQ,EAAE,yDAAyD;IACnE,IAAI,EAAE,+CAA+C;CACtD,CAAC;AAEF,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAEhE,gGAAgG;AACzF,MAAM,OAAO,GAAG,CAAC,IAAoB,EAAE,UAAkB,EAAE,EAAE;IAClE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAEnE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,IAAA,4BAAe,EAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAE3G,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,WAAC,OAAA,MAAM,CAAC,IAAI,CAAC,MAAA,GAAG,CAAC,IAAI,mCAAI,EAAE,CAAC,CAAA,EAAA,CAAC,CAAC,CAAC,CAAC;IAE1F,OAAO;QACL,UAAU,UAAU,2BAA2B;QAC/C,EAAE;QACF,UAAU;QACV,GAAG,kCAAqB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,8BAA8B,CAAC;QACjF,EAAE;QACF,MAAM;QACN,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,0CAA0C,CAAC,CAAC;QAClF,EAAE;QACF,SAAS;QACT,KAAK,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,iEAAiE;QACtF,KAAK,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,sEAAsE;QAC5F,KAAK,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,iDAAiD;QACvE,KAAK,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,kBAAkB;KACxC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC,CAAC;AAxBW,QAAA,OAAO,WAwBlB"}
|