@toa.io/cli 1.0.1-dev.0 → 1.0.2-alpha.56
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 +6 -6
- package/readme.md +50 -61
- package/src/commands/build.js +2 -6
- package/src/commands/compose.js +11 -1
- package/src/commands/export/deployment.js +2 -2
- package/src/commands/export/images.js +2 -2
- package/src/commands/push.js +19 -0
- package/src/commands/replay.js +11 -0
- package/src/commands/shell.js +22 -0
- package/src/handlers/build.js +2 -2
- package/src/handlers/compose.js +24 -0
- package/src/handlers/conceal.js +5 -1
- package/src/handlers/docker/build.js +67 -0
- package/src/handlers/docker/command.js +23 -0
- package/src/handlers/docker/index.js +9 -0
- package/src/handlers/docker/run.js +34 -0
- package/src/handlers/export/images.js +8 -0
- package/src/handlers/push.js +14 -0
- package/src/handlers/replay.js +23 -3
- package/src/handlers/reveal.js +4 -1
- package/src/handlers/shell.js +29 -0
- package/src/program.js +1 -1
- package/src/util/find.js +1 -1
- package/src/commands/configure.js +0 -43
- package/src/handlers/.configure/subcommands.js +0 -15
- package/src/handlers/configure.js +0 -46
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2-alpha.56+a80d81d4",
|
|
4
4
|
"description": "Toa CLI",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@toa.io/console": "0.6.0",
|
|
26
|
-
"@toa.io/generic": "0.10.
|
|
27
|
-
"@toa.io/kubernetes": "0.7.
|
|
28
|
-
"@toa.io/norm": "1.0.
|
|
29
|
-
"@toa.io/yaml": "0.7.
|
|
26
|
+
"@toa.io/generic": "0.10.1-alpha.56+a80d81d4",
|
|
27
|
+
"@toa.io/kubernetes": "0.7.5-alpha.56+a80d81d4",
|
|
28
|
+
"@toa.io/norm": "1.0.2-alpha.56+a80d81d4",
|
|
29
|
+
"@toa.io/yaml": "0.7.6-alpha.56+a80d81d4",
|
|
30
30
|
"find-up": "5.0.0",
|
|
31
31
|
"yargs": "17.6.2"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "a80d81d4d9da9fec07606154c959dd6512de4c76"
|
|
34
34
|
}
|
package/readme.md
CHANGED
|
@@ -2,43 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
## Development
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### compose
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
with `source /dev/stdin` to apply.
|
|
7
|
+
Run composition.
|
|
9
8
|
|
|
10
9
|
<dl>
|
|
11
|
-
<dt><code>toa
|
|
10
|
+
<dt><code>toa compose [paths]</code></dt>
|
|
12
11
|
<dd>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
<code>--
|
|
16
|
-
<code>--
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
<code>paths</code> glob patterns to look for components<br/>
|
|
13
|
+
<code>--kill</code> shutdown composition after it's started<br/>
|
|
14
|
+
<code>--dock</code> run in Docker using current <code>.env</code><br/>
|
|
15
|
+
<code>--bindnings</code> override bindings (obsolete)<br/>
|
|
16
|
+
</dd>
|
|
17
|
+
</dl>
|
|
19
18
|
|
|
20
|
-
>
|
|
19
|
+
> Note that your `localhost` it is accessible from the container as `host.docker.internal`.
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
# set new value
|
|
24
|
-
$ toa configure foo 'new value' | source /dev/stdin
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
```shell
|
|
28
|
-
# clear key
|
|
29
|
-
$ toa configure bar.baz --reset | source /dev/stdin
|
|
30
|
-
```
|
|
21
|
+
### env
|
|
31
22
|
|
|
32
|
-
|
|
33
|
-
<dt><code>toa configure reset</code></dt>
|
|
34
|
-
<dd>Remove Configuration Object.</dd>
|
|
35
|
-
<dt><code>toa configure print</code></dt>
|
|
36
|
-
<dd>Output Configuration Object as YAML.
|
|
23
|
+
Export environment to a `.env` file.
|
|
37
24
|
|
|
38
|
-
<
|
|
25
|
+
<dl>
|
|
26
|
+
<dt><code>toa env [environment]</code></dt>
|
|
27
|
+
<dd>
|
|
28
|
+
<code>environment</code> deployment environment name (default <code>local</code>).<br/>
|
|
29
|
+
<code>--path</code> path to context (default <code>.</code>)<br/>
|
|
39
30
|
</dd>
|
|
40
31
|
</dl>
|
|
41
32
|
|
|
33
|
+
Credentials specified in `.env` file are preserved.
|
|
34
|
+
|
|
35
|
+
> It is recommended to add `.env` to `.gitignore`.
|
|
36
|
+
|
|
42
37
|
### replay
|
|
43
38
|
|
|
44
39
|
[Replay](/extensions/sampling/docs/replay.md) samples. Reports in [TAP](https://testanything.org)
|
|
@@ -47,11 +42,12 @@ format.
|
|
|
47
42
|
<dl>
|
|
48
43
|
<dt><code>toa replay [paths...]</code></dt>
|
|
49
44
|
<dd>
|
|
50
|
-
<code>paths</code>
|
|
51
|
-
<code>--integration</code>
|
|
52
|
-
<code>--component <id></code>
|
|
53
|
-
<code>--operation <name></code>
|
|
54
|
-
<code>--title <regexp></code>
|
|
45
|
+
<code>paths</code> Path(s) to component(s) or a context (default <code>.</code>).<br/>
|
|
46
|
+
<code>--integration</code> Replay integration tests only.<br/>
|
|
47
|
+
<code>--component <id></code> Replay samples for a specified component <code>id</code>.<br/>
|
|
48
|
+
<code>--operation <name></code> Replay samples for specified operation.<br/>
|
|
49
|
+
<code>--title <regexp></code> Regexp to match sample titles.<br/>
|
|
50
|
+
<code>--dock</code> Run in Docker. Applicable only for component samples.
|
|
55
51
|
</dd>
|
|
56
52
|
</dl>
|
|
57
53
|
|
|
@@ -60,17 +56,15 @@ format.
|
|
|
60
56
|
```shell
|
|
61
57
|
$ toa replay
|
|
62
58
|
$ toa replay ./path/to/component
|
|
63
|
-
$ toa replay ./components/a ./components/b
|
|
59
|
+
$ toa replay ./components/a ./components/b --dock
|
|
64
60
|
$ toa replay ./components/*
|
|
65
61
|
$ toa replay ./path/to/context
|
|
66
62
|
$ toa replay --title "should add numbers"
|
|
67
63
|
```
|
|
68
64
|
|
|
69
|
-
If path is a context directory (containing `context.toa.yaml` file), samples for components within
|
|
65
|
+
If a path is a context directory (containing `context.toa.yaml` file), samples for components within
|
|
70
66
|
the context will be found and replayed sequentially.
|
|
71
67
|
|
|
72
|
-
## Exporting
|
|
73
|
-
|
|
74
68
|
### export manifest
|
|
75
69
|
|
|
76
70
|
<dl>
|
|
@@ -82,24 +76,9 @@ the context will be found and replayed sequentially.
|
|
|
82
76
|
</dd>
|
|
83
77
|
</dl>
|
|
84
78
|
|
|
85
|
-
|
|
79
|
+
## Operations
|
|
86
80
|
|
|
87
|
-
|
|
88
|
-
<dt><code>toa env [environment]</code></dt>
|
|
89
|
-
<dd>Select environment. Set local environment variables to <code>.env</code> file.
|
|
90
|
-
|
|
91
|
-
<code>environment</code> deployment environment name (default <code>local</code>).<br/>
|
|
92
|
-
<code>--path</code> path to context (default <code>.</code>)<br/>
|
|
93
|
-
</dd>
|
|
94
|
-
</dl>
|
|
95
|
-
|
|
96
|
-
> It is recommended to add `.env` to `.gitignore`.
|
|
97
|
-
|
|
98
|
-
> Credentials specified in a `.env` file are preserved during environment selection.
|
|
99
|
-
|
|
100
|
-
## Deployment
|
|
101
|
-
|
|
102
|
-
> Deployment commands use current `kubectl` context.
|
|
81
|
+
> Commands use current Kubernetes context.
|
|
103
82
|
|
|
104
83
|
### deploy
|
|
105
84
|
|
|
@@ -114,16 +93,8 @@ the context will be found and replayed sequentially.
|
|
|
114
93
|
### conceal
|
|
115
94
|
|
|
116
95
|
<dl>
|
|
117
|
-
<dt>
|
|
118
|
-
<code>toa conceal</code>
|
|
119
|
-
<img src="https://img.shields.io/badge/Not_Implemented-red" alt="Not Implemented"/>
|
|
120
|
-
</dt>
|
|
121
|
-
<dd>Deploy new declared secrets.
|
|
122
|
-
|
|
123
|
-
<code>--reset</code> don't skip already deployed</dd>
|
|
124
|
-
|
|
125
96
|
<dt><code>toa conceal <secret> <key> <value></code></dt>
|
|
126
|
-
<dd>Deploy a <code>key</code> with a <code>value</code> to a <code>secret</code>.</dd>
|
|
97
|
+
<dd>Deploy a <code>key</code> with a <code>value</code> to a secret named <code>toa-{secret}</code>.</dd>
|
|
127
98
|
</dl>
|
|
128
99
|
|
|
129
100
|
### reveal
|
|
@@ -134,3 +105,21 @@ the context will be found and replayed sequentially.
|
|
|
134
105
|
</dt>
|
|
135
106
|
<dd>Print keys and values of a secret.</dd>
|
|
136
107
|
</dl>
|
|
108
|
+
|
|
109
|
+
### shell
|
|
110
|
+
|
|
111
|
+
<dl>
|
|
112
|
+
<dt>
|
|
113
|
+
<code>toa shell [image]</code>
|
|
114
|
+
</dt>
|
|
115
|
+
<dd>Run interactive shell inside a disposable pod.
|
|
116
|
+
|
|
117
|
+
<code>image</code> Docker image<br/>
|
|
118
|
+
</dd>
|
|
119
|
+
</dl>
|
|
120
|
+
|
|
121
|
+
Extra arguments can be passed:
|
|
122
|
+
|
|
123
|
+
```shell
|
|
124
|
+
$ toa shell -- ping 1.1
|
|
125
|
+
```
|
package/src/commands/build.js
CHANGED
|
@@ -4,10 +4,6 @@ const { build } = require('../handlers/build')
|
|
|
4
4
|
|
|
5
5
|
const builder = (yargs) => {
|
|
6
6
|
yargs
|
|
7
|
-
.positional('environment', {
|
|
8
|
-
type: 'string',
|
|
9
|
-
desc: 'Deployment environment'
|
|
10
|
-
})
|
|
11
7
|
.option('path', {
|
|
12
8
|
alias: 'p',
|
|
13
9
|
group: 'Command options:',
|
|
@@ -17,7 +13,7 @@ const builder = (yargs) => {
|
|
|
17
13
|
})
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
exports.command = 'build
|
|
21
|
-
exports.desc = 'Build
|
|
16
|
+
exports.command = 'build'
|
|
17
|
+
exports.desc = 'Build Docker images'
|
|
22
18
|
exports.builder = builder
|
|
23
19
|
exports.handler = build
|
package/src/commands/compose.js
CHANGED
|
@@ -12,10 +12,20 @@ const builder = (yargs) => {
|
|
|
12
12
|
default: '.'
|
|
13
13
|
})
|
|
14
14
|
.array('paths')
|
|
15
|
+
.option('kill', {
|
|
16
|
+
group: 'Command options:',
|
|
17
|
+
type: 'boolean',
|
|
18
|
+
desc: 'Immediate shutdown'
|
|
19
|
+
})
|
|
20
|
+
.option('dock', {
|
|
21
|
+
group: 'Command options:',
|
|
22
|
+
type: 'boolean',
|
|
23
|
+
desc: 'Run in Docker'
|
|
24
|
+
})
|
|
15
25
|
.option('bindings', {
|
|
16
26
|
group: 'Command options:',
|
|
17
27
|
type: 'string',
|
|
18
|
-
desc: '
|
|
28
|
+
desc: 'OBSOLETE'
|
|
19
29
|
})
|
|
20
30
|
.array('bindings')
|
|
21
31
|
.example([
|
|
@@ -6,7 +6,7 @@ const builder = (yargs) => {
|
|
|
6
6
|
yargs
|
|
7
7
|
.positional('target', {
|
|
8
8
|
type: 'string',
|
|
9
|
-
desc: '
|
|
9
|
+
desc: 'Path to export to'
|
|
10
10
|
})
|
|
11
11
|
.positional('environment', {
|
|
12
12
|
type: 'string',
|
|
@@ -21,7 +21,7 @@ const builder = (yargs) => {
|
|
|
21
21
|
})
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
exports.command = ['deployment <target>
|
|
24
|
+
exports.command = ['deployment <environment> <target>', 'dep']
|
|
25
25
|
exports.desc = 'Export context deployment'
|
|
26
26
|
exports.builder = builder
|
|
27
27
|
exports.handler = dump
|
|
@@ -6,7 +6,7 @@ const builder = (yargs) => {
|
|
|
6
6
|
yargs
|
|
7
7
|
.positional('target', {
|
|
8
8
|
type: 'string',
|
|
9
|
-
desc: '
|
|
9
|
+
desc: 'Path to export to'
|
|
10
10
|
})
|
|
11
11
|
.option('path', {
|
|
12
12
|
alias: 'p',
|
|
@@ -17,7 +17,7 @@ const builder = (yargs) => {
|
|
|
17
17
|
})
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
exports.command = ['images
|
|
20
|
+
exports.command = ['images <target>', 'img']
|
|
21
21
|
exports.desc = 'Export docker image sources'
|
|
22
22
|
exports.builder = builder
|
|
23
23
|
exports.handler = prepare
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { push } = require('../handlers/push')
|
|
4
|
+
|
|
5
|
+
const builder = (yargs) => {
|
|
6
|
+
yargs
|
|
7
|
+
.option('path', {
|
|
8
|
+
alias: 'p',
|
|
9
|
+
group: 'Command options:',
|
|
10
|
+
type: 'string',
|
|
11
|
+
desc: 'Path to context',
|
|
12
|
+
default: '.'
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
exports.command = 'push'
|
|
17
|
+
exports.desc = 'Build and push Docker images'
|
|
18
|
+
exports.builder = builder
|
|
19
|
+
exports.handler = push
|
package/src/commands/replay.js
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
const { replay } = require('../handlers/replay')
|
|
6
6
|
|
|
7
|
+
/*
|
|
8
|
+
!!! OPTIONS MUST BE SYNCHRONIZED WITH ../handlers/.replay/args !!!
|
|
9
|
+
*/
|
|
10
|
+
|
|
7
11
|
const builder = (yargs) => {
|
|
8
12
|
yargs
|
|
9
13
|
.positional('paths', {
|
|
@@ -35,6 +39,13 @@ const builder = (yargs) => {
|
|
|
35
39
|
group: 'Command options:',
|
|
36
40
|
describe: 'Replay samples with titles matching given regexp'
|
|
37
41
|
})
|
|
42
|
+
.option('dock', {
|
|
43
|
+
alias: 'd',
|
|
44
|
+
type: 'boolean',
|
|
45
|
+
default: false,
|
|
46
|
+
group: 'Command options:',
|
|
47
|
+
describe: 'Replay inside Docker container'
|
|
48
|
+
})
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
exports.command = 'replay [paths...]'
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { shell } = require('../handlers/shell')
|
|
4
|
+
|
|
5
|
+
const builder = (yargs) => {
|
|
6
|
+
yargs
|
|
7
|
+
.positional('image', {
|
|
8
|
+
group: 'Command options:',
|
|
9
|
+
type: 'string',
|
|
10
|
+
desc: 'Docker image',
|
|
11
|
+
default: 'alpine'
|
|
12
|
+
})
|
|
13
|
+
.example([
|
|
14
|
+
['$0 shell'],
|
|
15
|
+
['$0 shell -- ping localhost']
|
|
16
|
+
])
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exports.command = 'shell [image]'
|
|
20
|
+
exports.desc = 'Run interactive shell from the current Kubernetes context'
|
|
21
|
+
exports.builder = builder
|
|
22
|
+
exports.handler = shell
|
package/src/handlers/build.js
CHANGED
|
@@ -6,9 +6,9 @@ const { context: find } = require('../util/find')
|
|
|
6
6
|
|
|
7
7
|
const build = async (argv) => {
|
|
8
8
|
const path = find(argv.path)
|
|
9
|
-
const
|
|
9
|
+
const registry = await boot.registry(path)
|
|
10
10
|
|
|
11
|
-
await
|
|
11
|
+
await registry.build()
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
exports.build = build
|
package/src/handlers/compose.js
CHANGED
|
@@ -1,14 +1,38 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { file: { dot } } = require('@toa.io/filesystem')
|
|
4
|
+
const { pick } = require('@toa.io/generic')
|
|
3
5
|
const boot = require('@toa.io/boot')
|
|
4
6
|
|
|
7
|
+
const docker = require('./docker')
|
|
5
8
|
const { components: find } = require('../util/find')
|
|
6
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @param {Record<string, string | boolean>} argv
|
|
12
|
+
* @return {Promise<void>}
|
|
13
|
+
*/
|
|
7
14
|
async function compose (argv) {
|
|
15
|
+
if (argv.dock === true) return dock(argv)
|
|
16
|
+
|
|
8
17
|
const paths = find(argv.paths)
|
|
9
18
|
const composition = await boot.composition(paths, argv)
|
|
10
19
|
|
|
11
20
|
await composition.connect()
|
|
21
|
+
|
|
22
|
+
if (argv.kill === true) await composition.disconnect()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {Record<string, string | string[] | boolean>} argv
|
|
27
|
+
* @return {Promise<void>}
|
|
28
|
+
*/
|
|
29
|
+
async function dock (argv) {
|
|
30
|
+
const envFile = await dot('env')
|
|
31
|
+
const repository = await docker.build(argv.paths)
|
|
32
|
+
const args = pick(argv, ['kill', 'bindings'])
|
|
33
|
+
const command = docker.command('toa compose *', args)
|
|
34
|
+
|
|
35
|
+
await docker.run(repository, command, ['--env-file', envFile])
|
|
12
36
|
}
|
|
13
37
|
|
|
14
38
|
exports.compose = compose
|
package/src/handlers/conceal.js
CHANGED
|
@@ -4,8 +4,12 @@ const { secrets } = require('@toa.io/kubernetes')
|
|
|
4
4
|
|
|
5
5
|
const conceal = async (argv) => {
|
|
6
6
|
const { secret, key, value } = argv
|
|
7
|
+
const prefixed = PREFIX + secret
|
|
7
8
|
|
|
8
|
-
await secrets.store(
|
|
9
|
+
await secrets.store(prefixed, { [key]: value })
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
const PREFIX = 'toa-'
|
|
13
|
+
|
|
11
14
|
exports.conceal = conceal
|
|
15
|
+
exports.PREFIX = PREFIX
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { newid } = require('@toa.io/generic')
|
|
4
|
+
const { component: load } = require('@toa.io/norm')
|
|
5
|
+
const { deployment: { Factory } } = require('@toa.io/operations')
|
|
6
|
+
const runtime = require('@toa.io/runtime')
|
|
7
|
+
|
|
8
|
+
const find = require('../../util/find')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string[]} paths
|
|
12
|
+
* @return {Promise<string>}
|
|
13
|
+
*/
|
|
14
|
+
async function build (paths) {
|
|
15
|
+
const context = await createContext(/** @type {string[]} */ paths)
|
|
16
|
+
const factory = new Factory(context)
|
|
17
|
+
const registry = factory.registry()
|
|
18
|
+
|
|
19
|
+
await registry.build()
|
|
20
|
+
|
|
21
|
+
const composition = context.compositions[0].name
|
|
22
|
+
|
|
23
|
+
return `${context.name}/composition-${composition}`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string[]} patterns
|
|
28
|
+
* @return {Promise<toa.norm.Context>}
|
|
29
|
+
*/
|
|
30
|
+
async function createContext (patterns) {
|
|
31
|
+
const paths = patterns.map((pattern) => find.components(pattern))
|
|
32
|
+
const components = await loadComponents(paths)
|
|
33
|
+
const rnd = newid().substring(0, 6)
|
|
34
|
+
const name = 'replay-' + rnd
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
name: 'toa-temp',
|
|
38
|
+
runtime: {
|
|
39
|
+
version: runtime.version
|
|
40
|
+
},
|
|
41
|
+
registry: {
|
|
42
|
+
platforms: null
|
|
43
|
+
},
|
|
44
|
+
compositions: [{
|
|
45
|
+
name,
|
|
46
|
+
components
|
|
47
|
+
}]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {string[]} paths
|
|
53
|
+
* @return {Promise<toa.norm.Component[]>}
|
|
54
|
+
*/
|
|
55
|
+
async function loadComponents (paths) {
|
|
56
|
+
const components = []
|
|
57
|
+
|
|
58
|
+
for (const path of paths) {
|
|
59
|
+
const component = await load(path)
|
|
60
|
+
|
|
61
|
+
components.push(component)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return components
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
exports.build = build
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {string} command
|
|
5
|
+
* @param {Record<string, any>} args
|
|
6
|
+
*/
|
|
7
|
+
const command = (command, args) => {
|
|
8
|
+
const options = []
|
|
9
|
+
|
|
10
|
+
for (const [name, value] of Object.entries(args)) {
|
|
11
|
+
if (value === undefined) continue
|
|
12
|
+
|
|
13
|
+
options.push('--' + name)
|
|
14
|
+
|
|
15
|
+
if (typeof value !== 'boolean') options.push(`"${value}"`)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const argumentLine = options.join(' ')
|
|
19
|
+
|
|
20
|
+
return command + ' ' + argumentLine
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
exports.command = command
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { spawn, exec } = require('node:child_process')
|
|
4
|
+
const { promisify } = require('node:util')
|
|
5
|
+
|
|
6
|
+
const { promex } = require('@toa.io/generic')
|
|
7
|
+
|
|
8
|
+
const execute = promisify(exec)
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} repository
|
|
12
|
+
* @param {string} command
|
|
13
|
+
* @param {string[]} runArguments
|
|
14
|
+
* @return {Promise<void>}
|
|
15
|
+
*/
|
|
16
|
+
async function run (repository, command, runArguments) {
|
|
17
|
+
const imagesResult =
|
|
18
|
+
/** @type {{ stdout: string }} */
|
|
19
|
+
await execute(`docker images -q ${repository} | head -n 1`)
|
|
20
|
+
|
|
21
|
+
const id = imagesResult.stdout.trim()
|
|
22
|
+
const args = ['run', '--rm', ...(runArguments ?? []), id, 'sh', '-c', command]
|
|
23
|
+
const done = promex()
|
|
24
|
+
|
|
25
|
+
const running = await spawn('docker', args, { stdio: 'inherit' })
|
|
26
|
+
|
|
27
|
+
running.on('exit', done.resolve)
|
|
28
|
+
|
|
29
|
+
await done
|
|
30
|
+
|
|
31
|
+
await execute(`docker rmi ${id}`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
exports.run = run
|
|
@@ -13,4 +13,12 @@ const prepare = async (argv) => {
|
|
|
13
13
|
console.log(path)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
// const prepare = async (argv) => {
|
|
17
|
+
// const context = find(argv.path)
|
|
18
|
+
// const registry = await boot.registry(context)
|
|
19
|
+
// const path = await registry.prepare(argv.target)
|
|
20
|
+
//
|
|
21
|
+
// console.log(path)
|
|
22
|
+
// }
|
|
23
|
+
|
|
16
24
|
exports.prepare = prepare
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const boot = require('@toa.io/boot')
|
|
4
|
+
|
|
5
|
+
const { context: find } = require('../util/find')
|
|
6
|
+
|
|
7
|
+
const push = async (argv) => {
|
|
8
|
+
const path = find(argv.path)
|
|
9
|
+
const registry = await boot.registry(path)
|
|
10
|
+
|
|
11
|
+
await registry.push()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
exports.push = push
|
package/src/handlers/replay.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { pick } = require('@toa.io/generic')
|
|
4
|
+
const { context, components } = require('@toa.io/userland/samples')
|
|
5
|
+
|
|
3
6
|
const find = require('../util/find')
|
|
7
|
+
const docker = require('./docker')
|
|
4
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @param {Record<string, string | boolean>} argv
|
|
11
|
+
* @return {Promise<void>}
|
|
12
|
+
*/
|
|
5
13
|
async function replay (argv) {
|
|
6
|
-
|
|
7
|
-
const { context, components } = require('@toa.io/userland/samples')
|
|
14
|
+
if (argv.dock) return dock(argv)
|
|
8
15
|
|
|
9
16
|
/** @type {boolean} */
|
|
10
17
|
let ok
|
|
@@ -16,7 +23,8 @@ async function replay (argv) {
|
|
|
16
23
|
component: argv.component,
|
|
17
24
|
integration: argv.integration,
|
|
18
25
|
operation: argv.operation,
|
|
19
|
-
title: argv.title
|
|
26
|
+
title: argv.title,
|
|
27
|
+
runner: { bail: true }
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
if (paths !== null) {
|
|
@@ -36,6 +44,18 @@ async function replay (argv) {
|
|
|
36
44
|
process.on('beforeExit', () => console.log(message))
|
|
37
45
|
}
|
|
38
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @param {Record<string, string | string[] | boolean>} argv
|
|
49
|
+
* @return {Promise<void>}
|
|
50
|
+
*/
|
|
51
|
+
async function dock (argv) {
|
|
52
|
+
const repository = await docker.build(argv.paths)
|
|
53
|
+
const args = pick(argv, ['component', 'operation', 'integration', 'title'])
|
|
54
|
+
const command = docker.command('toa replay *', args)
|
|
55
|
+
|
|
56
|
+
await docker.run(repository, command)
|
|
57
|
+
}
|
|
58
|
+
|
|
39
59
|
const GREEN = '\x1b[32m'
|
|
40
60
|
const RED = '\x1b[31m'
|
|
41
61
|
const RESET = '\x1b[0m'
|
package/src/handlers/reveal.js
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
const { secrets } = require('@toa.io/kubernetes')
|
|
4
4
|
const { remap, decode } = require('@toa.io/generic')
|
|
5
5
|
|
|
6
|
+
const { PREFIX } = require('./conceal')
|
|
7
|
+
|
|
6
8
|
const reveal = async (argv) => {
|
|
7
|
-
const
|
|
9
|
+
const prefixed = PREFIX + argv.secret
|
|
10
|
+
const secret = await secrets.get(prefixed)
|
|
8
11
|
const values = remap(secret.data, decode)
|
|
9
12
|
|
|
10
13
|
for (const [key, value] of Object.entries(values)) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('node:child_process')
|
|
4
|
+
const { newid } = require('@toa.io/generic')
|
|
5
|
+
|
|
6
|
+
const shell = async (argv) => {
|
|
7
|
+
const rnd = newid().substring(0, 6)
|
|
8
|
+
|
|
9
|
+
const args = [
|
|
10
|
+
'run',
|
|
11
|
+
'shell-' + rnd,
|
|
12
|
+
'--rm',
|
|
13
|
+
'-i',
|
|
14
|
+
'--tty',
|
|
15
|
+
'--image',
|
|
16
|
+
argv.image,
|
|
17
|
+
'--restart=Never',
|
|
18
|
+
'--'
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
const extra = argv._.splice(1)
|
|
22
|
+
|
|
23
|
+
if (extra.length > 0) args.push(...extra)
|
|
24
|
+
else args.push('sh')
|
|
25
|
+
|
|
26
|
+
await spawn('kubectl', args, { stdio: 'inherit' })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.shell = shell
|
package/src/program.js
CHANGED
|
@@ -19,7 +19,7 @@ yargs(process.argv.slice(2))
|
|
|
19
19
|
.fail((msg, err) => {
|
|
20
20
|
const actual = err || new Error(msg)
|
|
21
21
|
|
|
22
|
-
console.error(
|
|
22
|
+
console.error(actual)
|
|
23
23
|
|
|
24
24
|
process.exit(actual.exitCode > 0 ? actual.exitCode : 1)
|
|
25
25
|
})
|
package/src/util/find.js
CHANGED
|
@@ -17,7 +17,7 @@ const find = (from, filename, test) => {
|
|
|
17
17
|
|
|
18
18
|
if (found.size === 0) {
|
|
19
19
|
if (test === true) return null
|
|
20
|
-
else throw new Error(`File '${filename}' is found in ${from.join(', ')}`)
|
|
20
|
+
else throw new Error(`File '${filename}' is not found in ${from.join(', ')}`)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
return [...found]
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { configure } = require('../handlers/configure')
|
|
4
|
-
|
|
5
|
-
const builder = (yargs) => {
|
|
6
|
-
yargs
|
|
7
|
-
.positional('key', {
|
|
8
|
-
type: 'string',
|
|
9
|
-
desc: 'Configuration Object key'
|
|
10
|
-
})
|
|
11
|
-
.positional('value', {
|
|
12
|
-
type: 'string',
|
|
13
|
-
desc: 'Key value'
|
|
14
|
-
})
|
|
15
|
-
.option('path', {
|
|
16
|
-
alias: 'p',
|
|
17
|
-
group: 'Command options:',
|
|
18
|
-
describe: 'Path to component',
|
|
19
|
-
type: 'string',
|
|
20
|
-
default: '.'
|
|
21
|
-
})
|
|
22
|
-
.option('reset', {
|
|
23
|
-
group: 'Command options:',
|
|
24
|
-
type: 'boolean',
|
|
25
|
-
desc: 'Remove Configuration Object key'
|
|
26
|
-
})
|
|
27
|
-
.option('json', {
|
|
28
|
-
group: 'Command options:',
|
|
29
|
-
type: 'boolean',
|
|
30
|
-
desc: 'Print as JSON'
|
|
31
|
-
})
|
|
32
|
-
.example([
|
|
33
|
-
['$0 configure myKey \'new value\' | source /dev/stdin'],
|
|
34
|
-
['$0 configure myObject.myKey --reset | source /dev/stdin'],
|
|
35
|
-
['$0 configure reset | source /dev/stdin'],
|
|
36
|
-
['$0 configure print --json']
|
|
37
|
-
])
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
exports.command = 'configure [key] [value]'
|
|
41
|
-
exports.desc = 'Output shell command to update local environment Configuration Object'
|
|
42
|
-
exports.builder = builder
|
|
43
|
-
exports.handler = configure
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { dump } = require('@toa.io/yaml')
|
|
4
|
-
|
|
5
|
-
const reset = (provider) => console.log('unset ' + provider.key)
|
|
6
|
-
|
|
7
|
-
const print = async (provider, argv) => {
|
|
8
|
-
await provider.connect()
|
|
9
|
-
|
|
10
|
-
const formatter = argv.json ? JSON.stringify : dump
|
|
11
|
-
|
|
12
|
-
console.log(formatter(provider.object))
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
exports.subcommands = { print, reset }
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const boot = require('@toa.io/boot')
|
|
4
|
-
|
|
5
|
-
const { Factory } = require('@toa.io/extensions.configuration')
|
|
6
|
-
|
|
7
|
-
const { subcommands } = require('./.configure/subcommands')
|
|
8
|
-
const { components: find } = require('../util/find')
|
|
9
|
-
|
|
10
|
-
async function configure (argv) {
|
|
11
|
-
const path = find(argv.path)
|
|
12
|
-
const manifest = await boot.manifest(path)
|
|
13
|
-
const factory = new Factory()
|
|
14
|
-
const provider = factory.provider(manifest)
|
|
15
|
-
|
|
16
|
-
if (argv.value === undefined && subcommands[argv.key] !== undefined) {
|
|
17
|
-
await subcommands[argv.key](provider, argv)
|
|
18
|
-
|
|
19
|
-
return
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
await provider.connect()
|
|
23
|
-
|
|
24
|
-
let key = argv.key
|
|
25
|
-
let value = argv.value
|
|
26
|
-
|
|
27
|
-
// :(
|
|
28
|
-
if (key !== undefined) {
|
|
29
|
-
if (value === undefined && key.includes('=')) [key, value] = key.split('=')
|
|
30
|
-
|
|
31
|
-
if (value === undefined) {
|
|
32
|
-
if (argv.reset !== true) throw new Error('Key value expected')
|
|
33
|
-
else provider.unset(key)
|
|
34
|
-
} else provider.set(key, value)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let command
|
|
38
|
-
const exported = provider.export()
|
|
39
|
-
|
|
40
|
-
if (exported === undefined) command = `unset ${provider.key}`
|
|
41
|
-
else command = `export ${provider.key}=` + exported
|
|
42
|
-
|
|
43
|
-
console.log(command)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
exports.configure = configure
|