@toa.io/cli 0.20.0-dev.1 → 0.20.0-dev.10
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/package.json +8 -7
- package/readme.md +55 -20
- package/src/commands/compose.js +6 -0
- package/src/commands/env.js +7 -1
- package/src/commands/replay.js +12 -0
- package/src/handlers/compose.js +2 -4
- package/src/handlers/docker/build.js +17 -23
- package/src/handlers/docker/run.js +11 -6
- package/src/handlers/env.js +1 -1
- package/src/handlers/replay.js +4 -3
- package/src/program.js +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/cli",
|
|
3
|
-
"version": "0.20.0-dev.
|
|
3
|
+
"version": "0.20.0-dev.10",
|
|
4
4
|
"description": "Toa CLI",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -22,13 +22,14 @@
|
|
|
22
22
|
"@toa.io/runtime": "*"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@toa.io/console": "0.
|
|
26
|
-
"@toa.io/generic": "0.
|
|
27
|
-
"@toa.io/kubernetes": "0.20.0-dev.
|
|
28
|
-
"@toa.io/norm": "0.20.0-dev.
|
|
29
|
-
"@toa.io/yaml": "0.20.0-dev.
|
|
25
|
+
"@toa.io/console": "0.20.0-dev.11",
|
|
26
|
+
"@toa.io/generic": "0.20.0-dev.11",
|
|
27
|
+
"@toa.io/kubernetes": "0.20.0-dev.11",
|
|
28
|
+
"@toa.io/norm": "0.20.0-dev.11",
|
|
29
|
+
"@toa.io/yaml": "0.20.0-dev.11",
|
|
30
|
+
"dotenv": "16.1.1",
|
|
30
31
|
"find-up": "5.0.0",
|
|
31
32
|
"yargs": "17.6.2"
|
|
32
33
|
},
|
|
33
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "8ccc0289a7af2dfb7fabf615f0a71bc8adf41b1c"
|
|
34
35
|
}
|
package/readme.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Toa Command Line Interface
|
|
2
2
|
|
|
3
|
+
## Common Options
|
|
4
|
+
|
|
5
|
+
<dl>
|
|
6
|
+
<dt><code>--env</code></dt>
|
|
7
|
+
<dd>Path to the environment variables file (`.env` format)</dd>
|
|
8
|
+
</dl>
|
|
9
|
+
|
|
3
10
|
## Development
|
|
4
11
|
|
|
5
12
|
### compose
|
|
@@ -9,14 +16,15 @@ Run composition.
|
|
|
9
16
|
<dl>
|
|
10
17
|
<dt><code>toa compose [paths]</code></dt>
|
|
11
18
|
<dd>
|
|
12
|
-
<code>paths</code>
|
|
13
|
-
<code>--kill</code>
|
|
14
|
-
<code>--dock</code>
|
|
15
|
-
<code>--
|
|
19
|
+
<code>paths</code> Glob patterns to look for components.<br/>
|
|
20
|
+
<code>--kill</code> Shutdown composition after it's started<br/>
|
|
21
|
+
<code>--dock</code> Run in Docker using current <code>.env</code>.<br/>
|
|
22
|
+
<code>--context</code> Path to the Context root (default <code>.</code>).<br/>
|
|
23
|
+
<code>--bindnings</code> Override bindings (obsolete).
|
|
16
24
|
</dd>
|
|
17
25
|
</dl>
|
|
18
26
|
|
|
19
|
-
> Note that your `localhost` it is accessible from
|
|
27
|
+
> Note that your `localhost` it is accessible from a container as `host.docker.internal`.
|
|
20
28
|
|
|
21
29
|
### env
|
|
22
30
|
|
|
@@ -26,13 +34,14 @@ Export environment to a `.env` file.
|
|
|
26
34
|
<dt><code>toa env [environment]</code></dt>
|
|
27
35
|
<dd>
|
|
28
36
|
<code>environment</code> deployment environment name (default <code>local</code>).<br/>
|
|
29
|
-
<code>--path</code> path to
|
|
37
|
+
<code>--path</code> path to a Context (default <code>.</code>)<br/>
|
|
38
|
+
<code>--as</code> output file path (default <code>.env</code>)
|
|
30
39
|
</dd>
|
|
31
40
|
</dl>
|
|
32
41
|
|
|
33
|
-
Credentials specified in
|
|
42
|
+
Credentials specified in the output file are preserved.
|
|
34
43
|
|
|
35
|
-
> It is recommended to add `.env
|
|
44
|
+
> It is recommended to add `.env*` to `.gitignore`.
|
|
36
45
|
|
|
37
46
|
### replay
|
|
38
47
|
|
|
@@ -42,9 +51,10 @@ format.
|
|
|
42
51
|
<dl>
|
|
43
52
|
<dt><code>toa replay [paths...]</code></dt>
|
|
44
53
|
<dd>
|
|
45
|
-
<code>paths</code> Path(s) to
|
|
46
|
-
<code>--integration</code> Replay integration tests only.<br/>
|
|
54
|
+
<code>paths</code> Path(s) to Component(s) or a Context (default <code>.</code>).<br/>
|
|
47
55
|
<code>--component <id></code> Replay samples for a specified component <code>id</code>.<br/>
|
|
56
|
+
<code>--integration</code> Replay integration tests only.<br/>
|
|
57
|
+
<code>--autonomous</code> Replay autonomous tests only.<br/>
|
|
48
58
|
<code>--operation <name></code> Replay samples for specified operation.<br/>
|
|
49
59
|
<code>--title <regexp></code> Regexp to match sample titles.<br/>
|
|
50
60
|
<code>--dock</code> Run in Docker. Applicable only for component samples.
|
|
@@ -62,8 +72,8 @@ $ toa replay ./path/to/context
|
|
|
62
72
|
$ toa replay --title "should add numbers"
|
|
63
73
|
```
|
|
64
74
|
|
|
65
|
-
If
|
|
66
|
-
|
|
75
|
+
If the path is a Context root (containing `context.toa.yaml` file), samples for components within the Context will be
|
|
76
|
+
found and replayed sequentially.
|
|
67
77
|
|
|
68
78
|
### export manifest
|
|
69
79
|
|
|
@@ -72,48 +82,73 @@ the context will be found and replayed sequentially.
|
|
|
72
82
|
<dd>Print normalized manifest.
|
|
73
83
|
|
|
74
84
|
<code>--path</code> path to component (default <code>.</code>)<br/>
|
|
75
|
-
<code>--error</code> print errors only
|
|
85
|
+
<code>--error</code> print errors only
|
|
76
86
|
</dd>
|
|
77
87
|
</dl>
|
|
78
88
|
|
|
79
89
|
## Operations
|
|
80
90
|
|
|
81
|
-
>
|
|
91
|
+
> Some commands use current Kubernetes context.
|
|
92
|
+
|
|
93
|
+
### build
|
|
94
|
+
|
|
95
|
+
Build Docker images.
|
|
96
|
+
|
|
97
|
+
<dl>
|
|
98
|
+
<dt><code>toa build</code></dt>
|
|
99
|
+
<dd>
|
|
100
|
+
<code>--path</code> path to a Context (default <code>.</code>)
|
|
101
|
+
</dd>
|
|
102
|
+
</dl>
|
|
82
103
|
|
|
83
104
|
### deploy
|
|
84
105
|
|
|
106
|
+
Deploy a Context.
|
|
107
|
+
|
|
108
|
+
- Build Docker images.
|
|
109
|
+
- Push Docker images to the registry.
|
|
110
|
+
- Build a Helm chart.
|
|
111
|
+
- Apply the Helm chart to the current Kubernetes context.
|
|
112
|
+
|
|
85
113
|
<dl>
|
|
86
114
|
<dt><code>toa deploy [environment]</code></dt>
|
|
87
|
-
<dd>
|
|
88
|
-
|
|
115
|
+
<dd>
|
|
89
116
|
<code>environment</code> deployment environment name (default <code>default</code>).<br/>
|
|
117
|
+
<code>--path</code> path to a Context (default <code>.</code>)<br/>
|
|
118
|
+
<code>--namespace</code> Kubernetes namespace to apply the Helm chat to<br/>
|
|
119
|
+
<code>--wait</code> wait until all
|
|
120
|
+
Pods [are ready](https://helm.sh/docs/intro/using_helm/#helpful-options-for-installupgraderollback)<br/>
|
|
121
|
+
<code>--dry</code> do not apply the Helm chart
|
|
90
122
|
</dd>
|
|
91
123
|
</dl>
|
|
92
124
|
|
|
93
125
|
### conceal
|
|
94
126
|
|
|
127
|
+
Deploy a `key` with a `value` to a secret named `toa-{secret}`.
|
|
128
|
+
|
|
95
129
|
<dl>
|
|
96
130
|
<dt><code>toa conceal <secret> <key> <value></code></dt>
|
|
97
|
-
<dd>Deploy a <code>key</code> with a <code>value</code> to a secret named <code>toa-{secret}</code>.</dd>
|
|
98
131
|
</dl>
|
|
99
132
|
|
|
100
133
|
### reveal
|
|
101
134
|
|
|
135
|
+
Outputs keys and values of a secret.
|
|
136
|
+
|
|
102
137
|
<dl>
|
|
103
138
|
<dt>
|
|
104
139
|
<code>toa reveal <secret></code>
|
|
105
140
|
</dt>
|
|
106
|
-
<dd>Print keys and values of a secret.</dd>
|
|
107
141
|
</dl>
|
|
108
142
|
|
|
109
143
|
### shell
|
|
110
144
|
|
|
145
|
+
Run interactive shell inside a disposable pod inside a Kubernetes cluster.
|
|
146
|
+
|
|
111
147
|
<dl>
|
|
112
148
|
<dt>
|
|
113
149
|
<code>toa shell [image]</code>
|
|
114
150
|
</dt>
|
|
115
|
-
<dd>
|
|
116
|
-
|
|
151
|
+
<dd>
|
|
117
152
|
<code>image</code> Docker image<br/>
|
|
118
153
|
</dd>
|
|
119
154
|
</dl>
|
package/src/commands/compose.js
CHANGED
|
@@ -22,6 +22,12 @@ const builder = (yargs) => {
|
|
|
22
22
|
type: 'boolean',
|
|
23
23
|
desc: 'Run in Docker'
|
|
24
24
|
})
|
|
25
|
+
.option('context', {
|
|
26
|
+
group: 'Command options:',
|
|
27
|
+
type: 'string',
|
|
28
|
+
desc: 'Path to the Context (used with --dock)',
|
|
29
|
+
default: '.'
|
|
30
|
+
})
|
|
25
31
|
.option('bindings', {
|
|
26
32
|
group: 'Command options:',
|
|
27
33
|
type: 'string',
|
package/src/commands/env.js
CHANGED
|
@@ -12,10 +12,16 @@ const builder = (yargs) => {
|
|
|
12
12
|
.option('path', {
|
|
13
13
|
alias: 'p',
|
|
14
14
|
group: 'Command options:',
|
|
15
|
-
describe: 'Path to
|
|
15
|
+
describe: 'Path to a Context',
|
|
16
16
|
type: 'string',
|
|
17
17
|
default: '.'
|
|
18
18
|
})
|
|
19
|
+
.option('as', {
|
|
20
|
+
group: 'Command options:',
|
|
21
|
+
describe: 'Output file path',
|
|
22
|
+
type: 'string',
|
|
23
|
+
default: '.env'
|
|
24
|
+
})
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
exports.command = 'env [environment]'
|
package/src/commands/replay.js
CHANGED
|
@@ -21,6 +21,12 @@ const builder = (yargs) => {
|
|
|
21
21
|
group: 'Command options:',
|
|
22
22
|
describe: 'Replay samples for specified component'
|
|
23
23
|
})
|
|
24
|
+
.option('autonomous', {
|
|
25
|
+
alias: 'a',
|
|
26
|
+
type: 'boolean',
|
|
27
|
+
group: 'Command options:',
|
|
28
|
+
describe: 'Replay autonomous tests only'
|
|
29
|
+
})
|
|
24
30
|
.option('integration', {
|
|
25
31
|
alias: 'i',
|
|
26
32
|
type: 'boolean',
|
|
@@ -46,6 +52,12 @@ const builder = (yargs) => {
|
|
|
46
52
|
group: 'Command options:',
|
|
47
53
|
describe: 'Replay inside Docker container'
|
|
48
54
|
})
|
|
55
|
+
.option('context', {
|
|
56
|
+
group: 'Command options:',
|
|
57
|
+
type: 'string',
|
|
58
|
+
desc: 'Path to the Context (used with --dock)',
|
|
59
|
+
default: '.'
|
|
60
|
+
})
|
|
49
61
|
}
|
|
50
62
|
|
|
51
63
|
exports.command = 'replay [paths...]'
|
package/src/handlers/compose.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { file: { dot } } = require('@toa.io/filesystem')
|
|
4
3
|
const { pick } = require('@toa.io/generic')
|
|
5
4
|
const boot = require('@toa.io/boot')
|
|
6
5
|
|
|
@@ -27,12 +26,11 @@ async function compose (argv) {
|
|
|
27
26
|
* @return {Promise<void>}
|
|
28
27
|
*/
|
|
29
28
|
async function dock (argv) {
|
|
30
|
-
const
|
|
31
|
-
const repository = await docker.build(argv.paths)
|
|
29
|
+
const repository = await docker.build(argv.context, argv.paths)
|
|
32
30
|
const args = pick(argv, ['kill', 'bindings'])
|
|
33
31
|
const command = docker.command('toa compose *', args)
|
|
34
32
|
|
|
35
|
-
await docker.run(repository, command,
|
|
33
|
+
await docker.run(repository, command, argv.env)
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
exports.compose = compose
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { newid } = require('@toa.io/generic')
|
|
4
|
-
const
|
|
4
|
+
const norm = require('@toa.io/norm')
|
|
5
5
|
const { deployment: { Factory } } = require('@toa.io/operations')
|
|
6
|
-
const runtime = require('@toa.io/runtime')
|
|
7
6
|
|
|
8
7
|
const find = require('../../util/find')
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
|
-
* @param {string
|
|
10
|
+
* @param {string} contextPath
|
|
11
|
+
* @param {string[]} componentPatterns
|
|
12
12
|
* @return {Promise<string>}
|
|
13
13
|
*/
|
|
14
|
-
async function build (
|
|
15
|
-
const context = await createContext(
|
|
14
|
+
async function build (contextPath, componentPatterns) {
|
|
15
|
+
const context = await createContext(contextPath, componentPatterns)
|
|
16
16
|
const factory = new Factory(context)
|
|
17
17
|
const registry = factory.registry()
|
|
18
18
|
|
|
@@ -20,32 +20,26 @@ async function build (paths) {
|
|
|
20
20
|
|
|
21
21
|
const composition = context.compositions[0].name
|
|
22
22
|
|
|
23
|
-
return `${context.name}/composition-${composition}`
|
|
23
|
+
return `${context.registry.base === undefined ? '' : context.registry.base + '/'}${context.name}/composition-${composition}`
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* @param {string
|
|
27
|
+
* @param {string} contextPath
|
|
28
|
+
* @param {string[]} componentPatterns
|
|
28
29
|
* @return {Promise<toa.norm.Context>}
|
|
29
30
|
*/
|
|
30
|
-
async function createContext (
|
|
31
|
-
const
|
|
31
|
+
async function createContext (contextPath, componentPatterns) {
|
|
32
|
+
const contextRoot = find.context(contextPath)
|
|
33
|
+
const context = await norm.context(contextRoot)
|
|
34
|
+
const paths = componentPatterns.map((pattern) => find.components(pattern))
|
|
32
35
|
const components = await loadComponents(paths)
|
|
33
36
|
const rnd = newid().substring(0, 6)
|
|
34
37
|
const name = 'replay-' + rnd
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
registry: {
|
|
42
|
-
platforms: null
|
|
43
|
-
},
|
|
44
|
-
compositions: [{
|
|
45
|
-
name,
|
|
46
|
-
components
|
|
47
|
-
}]
|
|
48
|
-
}
|
|
39
|
+
context.name += '-' + rnd
|
|
40
|
+
context.compositions = [{ name, components }]
|
|
41
|
+
|
|
42
|
+
return context
|
|
49
43
|
}
|
|
50
44
|
|
|
51
45
|
/**
|
|
@@ -56,7 +50,7 @@ async function loadComponents (paths) {
|
|
|
56
50
|
const components = []
|
|
57
51
|
|
|
58
52
|
for (const path of paths) {
|
|
59
|
-
const component = await
|
|
53
|
+
const component = await norm.component(path)
|
|
60
54
|
|
|
61
55
|
components.push(component)
|
|
62
56
|
}
|
|
@@ -4,22 +4,27 @@ const { spawn, exec } = require('node:child_process')
|
|
|
4
4
|
const { promisify } = require('node:util')
|
|
5
5
|
|
|
6
6
|
const { promex } = require('@toa.io/generic')
|
|
7
|
+
const { file: { dot } } = require('@toa.io/filesystem')
|
|
7
8
|
|
|
8
9
|
const execute = promisify(exec)
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @param {string} repository
|
|
12
13
|
* @param {string} command
|
|
13
|
-
* @param {string[]
|
|
14
|
+
* @param {string} [envFile]
|
|
14
15
|
* @return {Promise<void>}
|
|
15
16
|
*/
|
|
16
|
-
async function run (repository, command,
|
|
17
|
-
|
|
17
|
+
async function run (repository, command, envFile) {
|
|
18
|
+
if (envFile === undefined) envFile = await dot('env')
|
|
19
|
+
|
|
20
|
+
const envArgs = envFile === undefined ? [] : ['--env-file', envFile]
|
|
21
|
+
|
|
22
|
+
const found =
|
|
18
23
|
/** @type {{ stdout: string }} */
|
|
19
24
|
await execute(`docker images -q ${repository} | head -n 1`)
|
|
20
25
|
|
|
21
|
-
const id =
|
|
22
|
-
const args = ['run', '--rm', ...
|
|
26
|
+
const id = found.stdout.trim()
|
|
27
|
+
const args = ['run', '--rm', ...envArgs, id, 'sh', '-c', command]
|
|
23
28
|
const done = promex()
|
|
24
29
|
|
|
25
30
|
const running = await spawn('docker', args, { stdio: 'inherit' })
|
|
@@ -28,7 +33,7 @@ async function run (repository, command, runArguments) {
|
|
|
28
33
|
|
|
29
34
|
await done
|
|
30
35
|
|
|
31
|
-
await execute(`docker rmi ${id}`)
|
|
36
|
+
await execute(`docker rmi --force ${id}`)
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
exports.run = run
|
package/src/handlers/env.js
CHANGED
|
@@ -8,7 +8,7 @@ const { context: find } = require('../util/find')
|
|
|
8
8
|
|
|
9
9
|
async function env (argv) {
|
|
10
10
|
const path = find(argv.path)
|
|
11
|
-
const filepath = join(path,
|
|
11
|
+
const filepath = join(path, argv.as)
|
|
12
12
|
const operator = await boot.deployment(path, argv.environment)
|
|
13
13
|
const variables = operator.variables()
|
|
14
14
|
const currentValues = await read(filepath)
|
package/src/handlers/replay.js
CHANGED
|
@@ -7,7 +7,7 @@ const find = require('../util/find')
|
|
|
7
7
|
const docker = require('./docker')
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* @param {Record<string, string | boolean>} argv
|
|
10
|
+
* @param {Record<string, string | string[] | boolean>} argv
|
|
11
11
|
* @return {Promise<void>}
|
|
12
12
|
*/
|
|
13
13
|
async function replay (argv) {
|
|
@@ -21,6 +21,7 @@ async function replay (argv) {
|
|
|
21
21
|
/** @type {toa.samples.suite.Options} */
|
|
22
22
|
const options = {
|
|
23
23
|
component: argv.component,
|
|
24
|
+
autonomous: argv.autonomous,
|
|
24
25
|
integration: argv.integration,
|
|
25
26
|
operation: argv.operation,
|
|
26
27
|
title: argv.title,
|
|
@@ -49,11 +50,11 @@ async function replay (argv) {
|
|
|
49
50
|
* @return {Promise<void>}
|
|
50
51
|
*/
|
|
51
52
|
async function dock (argv) {
|
|
52
|
-
const repository = await docker.build(argv.paths)
|
|
53
|
+
const repository = await docker.build(argv.context, argv.paths)
|
|
53
54
|
const args = pick(argv, ['component', 'operation', 'integration', 'title'])
|
|
54
55
|
const command = docker.command('toa replay *', args)
|
|
55
56
|
|
|
56
|
-
await docker.run(repository, command)
|
|
57
|
+
await docker.run(repository, command, argv.env)
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
const GREEN = '\x1b[32m'
|
package/src/program.js
CHANGED
|
@@ -16,6 +16,11 @@ yargs(process.argv.slice(2))
|
|
|
16
16
|
|
|
17
17
|
console.level(argv.log)
|
|
18
18
|
})
|
|
19
|
+
.middleware(async (argv) => {
|
|
20
|
+
if (argv.env === undefined) return
|
|
21
|
+
|
|
22
|
+
require('dotenv').config({ path: /** @type {string} */ argv.env })
|
|
23
|
+
})
|
|
19
24
|
.fail((msg, err) => {
|
|
20
25
|
const actual = err || new Error(msg)
|
|
21
26
|
|
|
@@ -26,6 +31,10 @@ yargs(process.argv.slice(2))
|
|
|
26
31
|
.option('log', {
|
|
27
32
|
describe: 'Log level'
|
|
28
33
|
})
|
|
34
|
+
.option('env', {
|
|
35
|
+
type: 'string',
|
|
36
|
+
describe: 'Path to environment variables file (.env format)'
|
|
37
|
+
})
|
|
29
38
|
.commandDir('./commands')
|
|
30
39
|
.demandCommand(1, 'A command is required. Pass --help to see all available commands and options.')
|
|
31
40
|
.strict()
|