clever-tools 2.10.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -12
- package/README.md +7 -4
- package/bin/clever.js +61 -54
- package/package.json +6 -7
- package/src/commands/addon.js +46 -2
- package/src/commands/create.js +13 -2
- package/src/commands/curl.js +1 -1
- package/src/commands/database.js +10 -42
- package/src/commands/deploy.js +1 -1
- package/src/commands/diag.js +24 -6
- package/src/commands/logs.js +15 -4
- package/src/commands/restart.js +12 -2
- package/src/get-output-format-option.js +23 -0
- package/src/models/accesslogs.js +3 -5
- package/src/models/addon.js +23 -15
- package/src/models/configuration.js +47 -42
- package/src/models/format-ng-table.js +9 -9
- package/src/models/ids-resolver.js +110 -0
- package/src/models/log-v4.js +136 -0
- package/src/models/send-to-api.js +2 -2
- package/src/parsers.js +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
# clever-tools changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Unreleased (????-??-??)
|
|
4
|
+
|
|
5
|
+
...
|
|
6
|
+
|
|
7
|
+
## 3.0.0 (2023-10-19)
|
|
8
|
+
|
|
9
|
+
### ⚠ BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* Move from Node.js v12.22.8 to v18.5.0
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* add config file and auth source to `clever diag`
|
|
16
|
+
* add shell to `clever diag`
|
|
17
|
+
* improve `clever diag`, display (color and details) for oAuth token and user ID
|
|
18
|
+
* `clever deploy`: use new logs API (faster, longer, order)
|
|
19
|
+
* `clever restart`: use new logs API (faster, longer, order)
|
|
20
|
+
* `clever logs`: use new logs API (faster, longer, order), only for applications for now
|
|
21
|
+
|
|
22
|
+
## 2.11.0 (2023-07-25)
|
|
23
|
+
|
|
24
|
+
* skip preorder step on addon creation
|
|
25
|
+
* add `clever addon env` command
|
|
26
|
+
* improve implicit ID params (owner and add-on ID / real ID) for `clever database`
|
|
4
27
|
|
|
5
28
|
## 2.10.1 (2023-02-20)
|
|
6
29
|
|
|
7
30
|
* `clever database` command
|
|
8
|
-
* Improve output when trying
|
|
31
|
+
* Improve output when trying
|
|
9
32
|
* `clever database backups` command
|
|
10
33
|
* Improve output when there are no backups yet
|
|
11
34
|
* Fix command with personal orga
|
|
@@ -13,8 +36,8 @@
|
|
|
13
36
|
|
|
14
37
|
## 2.10.0 (2023-02-16)
|
|
15
38
|
|
|
16
|
-
* add `clever database backups DATABASE-ID` command to list backups of a database
|
|
17
|
-
* add `clever database backups download DATABASE-ID BACKUP-IP` command to download a backup
|
|
39
|
+
* add `clever database backups DATABASE-ID` command to list backups of a database
|
|
40
|
+
* add `clever database backups download DATABASE-ID BACKUP-IP` command to download a backup
|
|
18
41
|
* add `clever curl` so we can prefix any `curl` command with `clever` and benefit from the local oAuth v1 auth
|
|
19
42
|
|
|
20
43
|
## 2.10.0-beta.2 (2022-09-13)
|
|
@@ -55,7 +78,7 @@
|
|
|
55
78
|
|
|
56
79
|
* Fix linux-release-info usage in `clever diag`
|
|
57
80
|
|
|
58
|
-
## 2.7.0 (2020-08-20)
|
|
81
|
+
## 2.7.0 (2020-08-20)
|
|
59
82
|
|
|
60
83
|
* Improve `clever deploy` perfs in several cases (partial push, force push...)
|
|
61
84
|
* NOTE: Pushing a brand new repo is still slow in some situations
|
|
@@ -64,8 +87,8 @@
|
|
|
64
87
|
* `clever domain favourite` just displays the favourite domain (no prefix)
|
|
65
88
|
* `clever domain favourite set example.com` sets the favourite domain to `example.com`
|
|
66
89
|
* `clever domain favourite unset` unsets the favourite domain for this app
|
|
67
|
-
* Add a message while waiting for deploy to start `clever deploy` and `clever restart`
|
|
68
|
-
* Add shallow detection with appropriate error message for `clever deploy`
|
|
90
|
+
* Add a message while waiting for deploy to start `clever deploy` and `clever restart`
|
|
91
|
+
* Add shallow detection with appropriate error message for `clever deploy`
|
|
69
92
|
* Fix `clever status` typo in output (Clément Delafargue)
|
|
70
93
|
* Fix `clever env` error message when JSON input is incorrect (Jean Baptiste Noblot)
|
|
71
94
|
* Update dependencies
|
|
@@ -86,7 +109,7 @@ This is the one with the latest isomorphic-git!!!
|
|
|
86
109
|
* Add `clever config` command to configure application options
|
|
87
110
|
* Existing supported options: `name`, `description`, `zero-downtime`, `sticky-sessions` and `cancel-on-push`
|
|
88
111
|
* New supported option: `force-https`
|
|
89
|
-
* Add `--follow` to `clever deploy` and `clever restart` so you can continue to follow logs after the deployment is finished
|
|
112
|
+
* Add `--follow` to `clever deploy` and `clever restart` so you can continue to follow logs after the deployment is finished
|
|
90
113
|
* Fix #318 where `clever deploy` and `clever restart` would sometimes never exit
|
|
91
114
|
* We changed the way we detect when a deployment is finished
|
|
92
115
|
* Fix #304 where `clever logs` would run endlessly even when using `--before/--until`
|
|
@@ -94,7 +117,7 @@ This is the one with the latest isomorphic-git!!!
|
|
|
94
117
|
### Internals
|
|
95
118
|
|
|
96
119
|
* We completely removed our dependency to Bacon.js, goodbye old friend 😘
|
|
97
|
-
* `@clevercloud/client` was updated to `6.0.0` so we can use the new event based API for logs and events
|
|
120
|
+
* `@clevercloud/client` was updated to `6.0.0` so we can use the new event based API for logs and events
|
|
98
121
|
|
|
99
122
|
## 2.4.0 (2020-04-16)
|
|
100
123
|
|
|
@@ -249,7 +272,7 @@ These release were only created for some tests on our CI pipeline.
|
|
|
249
272
|
|
|
250
273
|
- Log error trace in --verbose mode
|
|
251
274
|
- Update deps (rename opn => open)
|
|
252
|
-
- Fix logs with `clever deploy` (update @clevercloud/client to 2.0.0-beta.1)
|
|
275
|
+
- Fix logs with `clever deploy` (update @clevercloud/client to 2.0.0-beta.1)
|
|
253
276
|
- Fix typo "connexion" => "connection" in logs and README
|
|
254
277
|
|
|
255
278
|
## 1.5.0-beta.5 (2019-08-01)
|
|
@@ -279,7 +302,7 @@ These release were only created for some tests on our CI pipeline.
|
|
|
279
302
|
- Ease testing for preprod with comments in config
|
|
280
303
|
- Update @clevercloud/client to 2.0.0-beta.0
|
|
281
304
|
|
|
282
|
-
## 1.5.0-beta.4 (2019-07-25)
|
|
305
|
+
## 1.5.0-beta.4 (2019-07-25)
|
|
283
306
|
|
|
284
307
|
- Fix --add-export option for `clever env`
|
|
285
308
|
|
|
@@ -381,7 +404,7 @@ These release were only created for some tests on our CI pipeline.
|
|
|
381
404
|
|
|
382
405
|
- Replace [nodegit](https://github.com/nodegit/nodegit) with [isomorphic-git](https://github.com/isomorphic-git/isomorphic-git)
|
|
383
406
|
- Add ESLint config with a big refactoring to go along
|
|
384
|
-
- Always use the npm `colors` package in safe mode: no global `String` pollution
|
|
407
|
+
- Always use the npm `colors` package in safe mode: no global `String` pollution
|
|
385
408
|
- Build, package and publish with a multibranch pipeline project on Jenkins
|
|
386
409
|
|
|
387
410
|
### Packaging & distribution
|
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ If you are using a GNU/Linux distribution that uses `.deb` packages like Debian
|
|
|
39
39
|
|
|
40
40
|
```sh
|
|
41
41
|
curl -fsSL https://clever-tools.clever-cloud.com/gpg/cc-nexus-deb.public.gpg.key | gpg --dearmor -o /usr/share/keyrings/cc-nexus-deb.gpg
|
|
42
|
-
echo "deb [signed-by=/usr/share/keyrings/cc-nexus-deb.gpg] https://nexus.clever-cloud.com/repository/deb stable main" | tee -a /etc/apt/sources.list
|
|
42
|
+
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/cc-nexus-deb.gpg] https://nexus.clever-cloud.com/repository/deb stable main" | tee -a /etc/apt/sources.list
|
|
43
43
|
apt-get update
|
|
44
44
|
apt-get install clever-tools
|
|
45
45
|
```
|
|
@@ -51,7 +51,7 @@ NOTES:
|
|
|
51
51
|
* If you want access to the beta channel, you can use this in your `sources.list`:
|
|
52
52
|
|
|
53
53
|
```sh
|
|
54
|
-
echo "deb [signed-by=/usr/share/keyrings/cc-nexus-deb.gpg] https://nexus.clever-cloud.com/repository/deb-beta beta main" | tee -a /etc/apt/sources.list
|
|
54
|
+
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/cc-nexus-deb.gpg] https://nexus.clever-cloud.com/repository/deb-beta beta main" | tee -a /etc/apt/sources.list
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
#### CentOS/Fedora (.rpm)
|
|
@@ -252,7 +252,7 @@ Where `type` is one of:
|
|
|
252
252
|
- `php`: for PHP applications
|
|
253
253
|
- `play1`: for Play1 applications
|
|
254
254
|
- `play2`: for Play2 applications
|
|
255
|
-
- `python`: for python27 applications
|
|
255
|
+
- `python`: for python27 and python3 applications
|
|
256
256
|
- `ruby`: for ruby applications
|
|
257
257
|
- `rust`: for rust applications
|
|
258
258
|
- `sbt`: for applications launched with SBT
|
|
@@ -334,9 +334,12 @@ ElasticSearch drains use the Elastic bulk API. To match this endpoint, specify `
|
|
|
334
334
|
|
|
335
335
|
Datadog has two zones, EU and COM. An account on one zone is not available on the other, make sure to target the good EU or COM intake endpoint.
|
|
336
336
|
|
|
337
|
-
To create a [Datadog](https://docs.datadoghq.com/api/?lang=python#send-logs-over-http) drain, you just need to use:
|
|
337
|
+
To create a [Datadog](https://docs.datadoghq.com/api/?lang=python#send-logs-over-http) drain, you just need to use one of the following command depending on your zone:
|
|
338
338
|
|
|
339
339
|
```sh
|
|
340
|
+
# EU
|
|
341
|
+
clever drain create DatadogHTTP "https://http-intake.logs.datadoghq.eu/v1/input/<API_KEY>?ddsource=clevercloud&service=<SERVICE>&host=<HOST>"
|
|
342
|
+
# US
|
|
340
343
|
clever drain create DatadogHTTP "https://http-intake.logs.datadoghq.com/v1/input/<API_KEY>?ddsource=clevercloud&service=<SERVICE>&host=<HOST>"
|
|
341
344
|
```
|
|
342
345
|
|
package/bin/clever.js
CHANGED
|
@@ -13,12 +13,15 @@ if (process.argv.includes('--autocomplete-index')) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const cliparse = require('cliparse');
|
|
16
|
+
const cliparseCommands = require('cliparse/src/command.js');
|
|
16
17
|
const updateNotifier = require('update-notifier');
|
|
18
|
+
const _sortBy = require('lodash/sortBy.js');
|
|
17
19
|
|
|
18
20
|
const git = require('../src/models/git.js');
|
|
19
21
|
const Parsers = require('../src/parsers.js');
|
|
20
22
|
const handleCommandPromise = require('../src/command-promise-handler.js');
|
|
21
23
|
const Formatter = require('../src/models/format-string.js');
|
|
24
|
+
const { getOutputFormatOption } = require('../src/get-output-format-option.js');
|
|
22
25
|
|
|
23
26
|
// Exit cleanly if the program we pipe to exits abruptly
|
|
24
27
|
process.stdout.on('error', (error) => {
|
|
@@ -63,7 +66,6 @@ function lazyRequire (modulePath) {
|
|
|
63
66
|
};
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
const AccessLogs = lazyRequire('../src/models/accesslogs.js');
|
|
67
69
|
const Addon = lazyRequire('../src/models/addon.js');
|
|
68
70
|
const Application = lazyRequire('../src/models/application.js');
|
|
69
71
|
const ApplicationConfiguration = lazyRequire('../src/models/application_configuration.js');
|
|
@@ -89,7 +91,7 @@ function run () {
|
|
|
89
91
|
}),
|
|
90
92
|
appNameCreation: cliparse.argument('app-name', { description: 'Application name' }),
|
|
91
93
|
backupId: cliparse.argument('backup-id', { description: 'A Database backup ID (format: UUID)' }),
|
|
92
|
-
databaseId: cliparse.argument('database-id', { description: '
|
|
94
|
+
databaseId: cliparse.argument('database-id', { description: 'Any database ID (format: addon_UUID, postgresql_UUID, mysql_UUID, ...)' }),
|
|
93
95
|
drainId: cliparse.argument('drain-id', { description: 'Drain ID' }),
|
|
94
96
|
drainType: cliparse.argument('drain-type', {
|
|
95
97
|
description: 'Drain type',
|
|
@@ -127,16 +129,8 @@ function run () {
|
|
|
127
129
|
// OPTIONS
|
|
128
130
|
const opts = {
|
|
129
131
|
sourceableEnvVarsList: cliparse.flag('add-export', { description: 'Display sourceable env variables setting' }),
|
|
130
|
-
accesslogsFormat:
|
|
131
|
-
|
|
132
|
-
metavar: 'format',
|
|
133
|
-
parser: Parsers.accessLogsFormat,
|
|
134
|
-
default: 'simple',
|
|
135
|
-
description: 'Output format (one of simple, extended, clf or json)',
|
|
136
|
-
complete () {
|
|
137
|
-
return cliparse.autocomplete.words(AccessLogs('listAvailableFormats')());
|
|
138
|
-
},
|
|
139
|
-
}),
|
|
132
|
+
accesslogsFormat: getOutputFormatOption(['simple', 'extended', 'clf']),
|
|
133
|
+
addonEnvFormat: getOutputFormatOption(['shell']),
|
|
140
134
|
accesslogsFollow: cliparse.flag('follow', {
|
|
141
135
|
aliases: ['f'],
|
|
142
136
|
description: 'Display access logs continuously (ignores before/until, after/since)',
|
|
@@ -512,6 +506,7 @@ function run () {
|
|
|
512
506
|
description: 'A WireGuard® private key',
|
|
513
507
|
}),
|
|
514
508
|
jsonFormat: cliparse.flag('json', { aliases: ['j'], description: 'Show result in JSON format' }),
|
|
509
|
+
humanJsonOutputFormat: getOutputFormatOption(),
|
|
515
510
|
tag: cliparse.option('tag', {
|
|
516
511
|
required: true,
|
|
517
512
|
metavar: 'tag',
|
|
@@ -581,10 +576,16 @@ function run () {
|
|
|
581
576
|
description: 'List available addon providers',
|
|
582
577
|
commands: [addonShowProviderCommand],
|
|
583
578
|
}, addon('listProviders'));
|
|
579
|
+
const addonEnvCommand = cliparse.command('env', {
|
|
580
|
+
description: 'List the environment variables for an add-on',
|
|
581
|
+
options: [opts.addonEnvFormat],
|
|
582
|
+
args: [opts.addonId],
|
|
583
|
+
}, addon('env'));
|
|
584
|
+
|
|
584
585
|
const addonCommands = cliparse.command('addon', {
|
|
585
586
|
description: 'Manage addons',
|
|
586
587
|
options: [opts.orgaIdOrName],
|
|
587
|
-
commands: [addonCreateCommand, addonDeleteCommand, addonRenameCommand, addonProvidersCommand],
|
|
588
|
+
commands: [addonCreateCommand, addonDeleteCommand, addonRenameCommand, addonProvidersCommand, addonEnvCommand],
|
|
588
589
|
}, addon('list'));
|
|
589
590
|
|
|
590
591
|
// APPLICATIONS COMMAND
|
|
@@ -626,7 +627,7 @@ function run () {
|
|
|
626
627
|
const appCreateCommand = cliparse.command('create', {
|
|
627
628
|
description: 'Create a Clever Cloud application',
|
|
628
629
|
args: [args.appNameCreation],
|
|
629
|
-
options: [opts.instanceType, opts.orgaIdOrName, opts.aliasCreation, opts.region, opts.github],
|
|
630
|
+
options: [opts.instanceType, opts.orgaIdOrName, opts.aliasCreation, opts.region, opts.github, opts.humanJsonOutputFormat],
|
|
630
631
|
}, create('create'));
|
|
631
632
|
|
|
632
633
|
// DELETE COMMAND
|
|
@@ -828,11 +829,13 @@ function run () {
|
|
|
828
829
|
});
|
|
829
830
|
// peer category - end
|
|
830
831
|
|
|
832
|
+
// eslint-disable-next-line no-unused-vars
|
|
831
833
|
const networkGroupsCommand = cliparse.command('networkgroups', {
|
|
832
834
|
description: 'List Network Group commands',
|
|
833
835
|
options: [opts.orgaIdOrName, opts.alias],
|
|
834
836
|
commands: [networkGroupsListCommand, networkGroupsCreateCommand, networkGroupsDeleteCommand, networkGroupsMembersCategoryCommand, networkGroupsPeersCategoryCommand],
|
|
835
837
|
});
|
|
838
|
+
// eslint-disable-next-line no-unused-vars
|
|
836
839
|
const ngCommand = cliparse.command('ng', {
|
|
837
840
|
description: `Alias for ${Formatter.formatCommand('clever networkgroups')}`,
|
|
838
841
|
options: [opts.orgaIdOrName, opts.alias],
|
|
@@ -1011,7 +1014,7 @@ function run () {
|
|
|
1011
1014
|
const downloadBackupCommand = cliparse.command('download', {
|
|
1012
1015
|
description: 'Download a database backup',
|
|
1013
1016
|
args: [args.databaseId, args.backupId],
|
|
1014
|
-
options: [opts.
|
|
1017
|
+
options: [opts.output],
|
|
1015
1018
|
}, database('downloadBackups'));
|
|
1016
1019
|
const backupsCommand = cliparse.command('backups', {
|
|
1017
1020
|
description: 'List available database backups',
|
|
@@ -1030,51 +1033,55 @@ function run () {
|
|
|
1030
1033
|
console.info('clever database backups download');
|
|
1031
1034
|
});
|
|
1032
1035
|
|
|
1036
|
+
const commands = _sortBy([
|
|
1037
|
+
accesslogsCommand,
|
|
1038
|
+
activityCommand,
|
|
1039
|
+
addonCommands,
|
|
1040
|
+
appCreateCommand,
|
|
1041
|
+
applicationsCommand,
|
|
1042
|
+
appLinkCommand,
|
|
1043
|
+
appUnlinkCommand,
|
|
1044
|
+
cancelDeployCommand,
|
|
1045
|
+
configCommands,
|
|
1046
|
+
databaseCommand,
|
|
1047
|
+
deleteCommand,
|
|
1048
|
+
deployCommand,
|
|
1049
|
+
diagCommand,
|
|
1050
|
+
domainCommands,
|
|
1051
|
+
drainCommands,
|
|
1052
|
+
emailNotificationsCommand,
|
|
1053
|
+
envCommands,
|
|
1054
|
+
cliparseCommands.helpCommand,
|
|
1055
|
+
loginCommand,
|
|
1056
|
+
logoutCommand,
|
|
1057
|
+
logsCommand,
|
|
1058
|
+
makeDefaultCommand,
|
|
1059
|
+
// Not ready for stable release yet
|
|
1060
|
+
// networkGroupsCommand,
|
|
1061
|
+
// ngCommand,
|
|
1062
|
+
openCommand,
|
|
1063
|
+
consoleCommand,
|
|
1064
|
+
profileCommand,
|
|
1065
|
+
publishedConfigCommands,
|
|
1066
|
+
restartCommand,
|
|
1067
|
+
scaleCommand,
|
|
1068
|
+
serviceCommands,
|
|
1069
|
+
sshCommand,
|
|
1070
|
+
statusCommand,
|
|
1071
|
+
stopCommand,
|
|
1072
|
+
tcpRedirsCommands,
|
|
1073
|
+
versionCommand,
|
|
1074
|
+
webhooksCommand,
|
|
1075
|
+
], 'name');
|
|
1076
|
+
|
|
1033
1077
|
// CLI PARSER
|
|
1034
1078
|
const cliParser = cliparse.cli({
|
|
1035
1079
|
name: 'clever',
|
|
1036
1080
|
description: 'CLI tool to manage Clever Cloud data and products',
|
|
1037
1081
|
version: pkg.version,
|
|
1038
1082
|
options: [opts.verbose, opts.noUpdateNotifier],
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
activityCommand,
|
|
1042
|
-
addonCommands,
|
|
1043
|
-
appCreateCommand,
|
|
1044
|
-
applicationsCommand,
|
|
1045
|
-
appLinkCommand,
|
|
1046
|
-
appUnlinkCommand,
|
|
1047
|
-
cancelDeployCommand,
|
|
1048
|
-
configCommands,
|
|
1049
|
-
databaseCommand,
|
|
1050
|
-
deleteCommand,
|
|
1051
|
-
deployCommand,
|
|
1052
|
-
diagCommand,
|
|
1053
|
-
domainCommands,
|
|
1054
|
-
drainCommands,
|
|
1055
|
-
emailNotificationsCommand,
|
|
1056
|
-
envCommands,
|
|
1057
|
-
loginCommand,
|
|
1058
|
-
logoutCommand,
|
|
1059
|
-
logsCommand,
|
|
1060
|
-
makeDefaultCommand,
|
|
1061
|
-
// Not ready for stable release yet
|
|
1062
|
-
// networkGroupsCommand,
|
|
1063
|
-
// ngCommand,
|
|
1064
|
-
openCommand,
|
|
1065
|
-
consoleCommand,
|
|
1066
|
-
profileCommand,
|
|
1067
|
-
publishedConfigCommands,
|
|
1068
|
-
restartCommand,
|
|
1069
|
-
scaleCommand,
|
|
1070
|
-
serviceCommands,
|
|
1071
|
-
sshCommand,
|
|
1072
|
-
statusCommand,
|
|
1073
|
-
stopCommand,
|
|
1074
|
-
tcpRedirsCommands,
|
|
1075
|
-
versionCommand,
|
|
1076
|
-
webhooksCommand,
|
|
1077
|
-
],
|
|
1083
|
+
helpCommand: false,
|
|
1084
|
+
commands,
|
|
1078
1085
|
});
|
|
1079
1086
|
|
|
1080
1087
|
// Make sure argv[0] is always "node"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clever-tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Command Line Interface for Clever Cloud.",
|
|
5
5
|
"main": "bin/clever.js",
|
|
6
6
|
"keywords": [
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"clever cloud"
|
|
10
10
|
],
|
|
11
11
|
"engines": {
|
|
12
|
-
"node": ">=
|
|
12
|
+
"node": ">=18"
|
|
13
13
|
},
|
|
14
|
-
"pkg-node-version": "
|
|
14
|
+
"pkg-node-version": "18",
|
|
15
15
|
"author": "Clever Cloud <ci@clever-cloud.com>",
|
|
16
16
|
"license": "Apache-2.0",
|
|
17
17
|
"bin": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"scripts/*.sh"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@clevercloud/client": "
|
|
28
|
+
"@clevercloud/client": "^8.0.1",
|
|
29
29
|
"clf-date": "^0.2.0",
|
|
30
30
|
"cliparse": "^0.3.3",
|
|
31
31
|
"colors": "1.4.0",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"grunt-http": "^2.3.3",
|
|
65
65
|
"grunt-mocha-test": "^0.13.3",
|
|
66
66
|
"mocha": "^8.4.0",
|
|
67
|
-
"pkg": "^5.
|
|
67
|
+
"pkg": "^5.8.1",
|
|
68
68
|
"semver": "^7.3.5"
|
|
69
69
|
},
|
|
70
70
|
"scripts": {
|
|
@@ -87,7 +87,6 @@
|
|
|
87
87
|
]
|
|
88
88
|
},
|
|
89
89
|
"volta": {
|
|
90
|
-
"node": "
|
|
91
|
-
"npm": "6.14.15"
|
|
90
|
+
"node": "18.5.0"
|
|
92
91
|
}
|
|
93
92
|
}
|
package/src/commands/addon.js
CHANGED
|
@@ -9,7 +9,11 @@ const formatTable = require('../format-table')();
|
|
|
9
9
|
const Logger = require('../logger.js');
|
|
10
10
|
const Organisation = require('../models/organisation.js');
|
|
11
11
|
const User = require('../models/user.js');
|
|
12
|
-
const { parseAddonOptions } = require('../models/addon.js');
|
|
12
|
+
const { parseAddonOptions, findOwnerId } = require('../models/addon.js');
|
|
13
|
+
const { getAllEnvVars } = require('@clevercloud/client/cjs/api/v2/addon.js');
|
|
14
|
+
const { sendToApi } = require('../models/send-to-api.js');
|
|
15
|
+
const { toNameEqualsValueString } = require('@clevercloud/client/cjs/utils/env-vars.js');
|
|
16
|
+
const { resolveAddonId } = require('../models/ids-resolver.js');
|
|
13
17
|
|
|
14
18
|
async function list (params) {
|
|
15
19
|
const { org: orgaIdOrName } = params.options;
|
|
@@ -57,7 +61,16 @@ async function create (params) {
|
|
|
57
61
|
Logger.println(`Addon ${name} (id: ${newAddon.id}) successfully created and linked to the application`);
|
|
58
62
|
}
|
|
59
63
|
else {
|
|
60
|
-
const newAddon = await Addon.create({
|
|
64
|
+
const newAddon = await Addon.create({
|
|
65
|
+
ownerId,
|
|
66
|
+
name,
|
|
67
|
+
providerName,
|
|
68
|
+
planName,
|
|
69
|
+
region,
|
|
70
|
+
skipConfirmation,
|
|
71
|
+
version,
|
|
72
|
+
addonOptions,
|
|
73
|
+
});
|
|
61
74
|
Logger.println(`Addon ${name} (id: ${newAddon.id}) successfully created`);
|
|
62
75
|
}
|
|
63
76
|
}
|
|
@@ -142,6 +155,36 @@ async function showProvider (params) {
|
|
|
142
155
|
});
|
|
143
156
|
}
|
|
144
157
|
|
|
158
|
+
async function env (params) {
|
|
159
|
+
|
|
160
|
+
const { org, format } = params.options;
|
|
161
|
+
const [addonIdOrRealId] = params.args;
|
|
162
|
+
|
|
163
|
+
const addonId = await resolveAddonId(addonIdOrRealId);
|
|
164
|
+
const ownerId = await findOwnerId(org, addonId);
|
|
165
|
+
|
|
166
|
+
const envFromAddon = await getAllEnvVars({ id: ownerId, addonId }).then(sendToApi);
|
|
167
|
+
|
|
168
|
+
switch (format) {
|
|
169
|
+
|
|
170
|
+
case 'json': {
|
|
171
|
+
const envFromAddonJson = Object.fromEntries(
|
|
172
|
+
envFromAddon.map(({ name, value }) => [name, value]),
|
|
173
|
+
);
|
|
174
|
+
Logger.println(JSON.stringify(envFromAddonJson, null, 2));
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
case 'shell':
|
|
179
|
+
Logger.println(toNameEqualsValueString(envFromAddon, { addExports: true }));
|
|
180
|
+
break;
|
|
181
|
+
|
|
182
|
+
case 'human':
|
|
183
|
+
default:
|
|
184
|
+
Logger.println(toNameEqualsValueString(envFromAddon, { addExports: false }));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
145
188
|
module.exports = {
|
|
146
189
|
list,
|
|
147
190
|
create,
|
|
@@ -149,4 +192,5 @@ module.exports = {
|
|
|
149
192
|
rename,
|
|
150
193
|
listProviders,
|
|
151
194
|
showProvider,
|
|
195
|
+
env,
|
|
152
196
|
};
|
package/src/commands/create.js
CHANGED
|
@@ -3,17 +3,28 @@
|
|
|
3
3
|
const Application = require('../models/application.js');
|
|
4
4
|
const AppConfig = require('../models/app_configuration.js');
|
|
5
5
|
const Logger = require('../logger.js');
|
|
6
|
+
const { toNameEqualsValueString } = require('@clevercloud/client/cjs/utils/env-vars.js');
|
|
6
7
|
|
|
7
8
|
async function create (params) {
|
|
8
9
|
const { type: typeName } = params.options;
|
|
9
10
|
const [name] = params.args;
|
|
10
|
-
const { org: orgaIdOrName, alias, region, github: githubOwnerRepo } = params.options;
|
|
11
|
+
const { org: orgaIdOrName, alias, region, github: githubOwnerRepo, format } = params.options;
|
|
11
12
|
const github = getGithubDetails(githubOwnerRepo);
|
|
12
13
|
|
|
13
14
|
const app = await Application.create(name, typeName, region, orgaIdOrName, github);
|
|
14
15
|
await AppConfig.addLinkedApplication(app, alias);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
switch (format) {
|
|
18
|
+
|
|
19
|
+
case 'json': {
|
|
20
|
+
console.log(JSON.stringify(app, null, 2));
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
case 'human':
|
|
25
|
+
default:
|
|
26
|
+
Logger.println('Your application has been successfully created!');
|
|
27
|
+
}
|
|
17
28
|
};
|
|
18
29
|
|
|
19
30
|
function getGithubDetails (githubOwnerRepo) {
|
package/src/commands/curl.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { parseCurlCommand } = require('curlconverter/util.js');
|
|
4
4
|
const { spawn } = require('child_process');
|
|
5
5
|
const { loadOAuthConf, conf } = require('../models/configuration.js');
|
|
6
|
-
const { addOauthHeader } = require('@clevercloud/client/cjs/oauth.
|
|
6
|
+
const { addOauthHeader } = require('@clevercloud/client/cjs/oauth.js');
|
|
7
7
|
|
|
8
8
|
async function loadTokens () {
|
|
9
9
|
const tokens = await loadOAuthConf();
|
package/src/commands/database.js
CHANGED
|
@@ -5,20 +5,19 @@ const { getBackups } = require('@clevercloud/client/cjs/api/v2/backups.js');
|
|
|
5
5
|
const { println } = require('../logger.js');
|
|
6
6
|
const formatTable = require('../format-table')();
|
|
7
7
|
const superagent = require('superagent');
|
|
8
|
-
const { getSummary } = require('@clevercloud/client/cjs/api/v2/user.js');
|
|
9
8
|
const fs = require('fs');
|
|
9
|
+
const { findOwnerId } = require('../models/addon.js');
|
|
10
|
+
const { resolveRealId } = require('../models/ids-resolver.js');
|
|
10
11
|
|
|
11
12
|
async function listBackups (params) {
|
|
12
13
|
|
|
13
|
-
const [databaseId] = params.args;
|
|
14
14
|
const { org } = params.options;
|
|
15
|
+
const [addonIdOrRealId] = params.args;
|
|
15
16
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
throw new Error('organisation ID is mandatory');
|
|
19
|
-
}
|
|
17
|
+
const addonId = await resolveRealId(addonIdOrRealId);
|
|
18
|
+
const ownerId = await findOwnerId(org, addonId);
|
|
20
19
|
|
|
21
|
-
const backups = await getBackups({ ownerId, ref:
|
|
20
|
+
const backups = await getBackups({ ownerId, ref: addonId }).then(sendToApi);
|
|
22
21
|
|
|
23
22
|
if (backups.length === 0) {
|
|
24
23
|
println('There are no backups yet');
|
|
@@ -47,15 +46,13 @@ async function listBackups (params) {
|
|
|
47
46
|
|
|
48
47
|
async function downloadBackups (params) {
|
|
49
48
|
|
|
50
|
-
const [databaseId, backupId] = params.args;
|
|
51
49
|
const { org, output } = params.options;
|
|
50
|
+
const [addonIdOrRealId, backupId] = params.args;
|
|
52
51
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
throw new Error('organisation ID is mandatory');
|
|
56
|
-
}
|
|
52
|
+
const addonId = await resolveRealId(addonIdOrRealId);
|
|
53
|
+
const ownerId = await findOwnerId(org, addonId);
|
|
57
54
|
|
|
58
|
-
const backups = await getBackups({ ownerId, ref:
|
|
55
|
+
const backups = await getBackups({ ownerId, ref: addonId }).then(sendToApi);
|
|
59
56
|
const backup = backups.find((backup) => backup.backup_id === backupId);
|
|
60
57
|
|
|
61
58
|
if (backup == null) {
|
|
@@ -74,33 +71,4 @@ async function downloadBackups (params) {
|
|
|
74
71
|
process.stdout.write(res.body);
|
|
75
72
|
}
|
|
76
73
|
|
|
77
|
-
/**
|
|
78
|
-
* Try to get an ownerId from the API
|
|
79
|
-
* @param {*} org cliparse param's option for orga
|
|
80
|
-
* @param {String} databaseId the resource which belong to the owner we are looking for
|
|
81
|
-
* @returns the owner ID (or null if cannot be found)
|
|
82
|
-
*/
|
|
83
|
-
async function resolveOwnerId (org, databaseId) {
|
|
84
|
-
|
|
85
|
-
if (org != null && org.orga_name != null) {
|
|
86
|
-
return org.orga_name;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const summary = await getSummary().then(sendToApi);
|
|
90
|
-
|
|
91
|
-
const userHasAddon = summary.user.addons.some((addon) => addon.realId === databaseId);
|
|
92
|
-
if (userHasAddon) {
|
|
93
|
-
return summary.user.id;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
for (const orga of summary.organisations) {
|
|
97
|
-
const orgaHasAddon = orga.addons.some((addon) => addon.realId === databaseId);
|
|
98
|
-
if (orgaHasAddon) {
|
|
99
|
-
return orga.id;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
74
|
module.exports = { listBackups, downloadBackups };
|
package/src/commands/deploy.js
CHANGED
|
@@ -5,7 +5,7 @@ const colors = require('colors/safe');
|
|
|
5
5
|
const AppConfig = require('../models/app_configuration.js');
|
|
6
6
|
const Application = require('../models/application.js');
|
|
7
7
|
const git = require('../models/git.js');
|
|
8
|
-
const Log = require('../models/log.js');
|
|
8
|
+
const Log = require('../models/log-v4.js');
|
|
9
9
|
const Logger = require('../logger.js');
|
|
10
10
|
const { getAllDeployments } = require('@clevercloud/client/cjs/api/v2/application.js');
|
|
11
11
|
const { sendToApi } = require('../models/send-to-api.js');
|
package/src/commands/diag.js
CHANGED
|
@@ -8,12 +8,12 @@ const colors = require('colors/safe');
|
|
|
8
8
|
const Logger = require('../logger.js');
|
|
9
9
|
const pkg = require('../../package.json');
|
|
10
10
|
const User = require('../models/user.js');
|
|
11
|
-
const { loadOAuthConf } = require('../models/configuration.js');
|
|
11
|
+
const { conf, loadOAuthConf } = require('../models/configuration.js');
|
|
12
12
|
|
|
13
13
|
async function diag () {
|
|
14
14
|
|
|
15
|
-
const userId = await User.getCurrentId().catch(() =>
|
|
16
|
-
const
|
|
15
|
+
const userId = await User.getCurrentId().catch(() => null);
|
|
16
|
+
const authDetails = await loadOAuthConf();
|
|
17
17
|
|
|
18
18
|
Logger.println('clever-tools ' + colors.green(pkg.version));
|
|
19
19
|
Logger.println('Node.js ' + colors.green(process.version));
|
|
@@ -28,12 +28,30 @@ async function diag () {
|
|
|
28
28
|
Logger.println('Linux ' + colors.green(linuxInfos));
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
Logger.println('Shell ' + colors.green(process.env.SHELL));
|
|
32
|
+
|
|
31
33
|
const isPackaged = (process.pkg != null);
|
|
32
34
|
Logger.println('Packaged ' + colors.green(isPackaged));
|
|
33
35
|
Logger.println('Exec path ' + colors.green(process.execPath));
|
|
34
|
-
|
|
35
|
-
Logger.println('
|
|
36
|
-
|
|
36
|
+
Logger.println('Config file ' + colors.green(conf.CONFIGURATION_FILE));
|
|
37
|
+
Logger.println('Auth source ' + colors.green(authDetails.source));
|
|
38
|
+
|
|
39
|
+
const oauthToken = (authDetails.token != null)
|
|
40
|
+
? colors.green(authDetails.token)
|
|
41
|
+
: colors.red('(none)');
|
|
42
|
+
Logger.println('oAuth token ' + oauthToken);
|
|
43
|
+
|
|
44
|
+
if (authDetails.token != null) {
|
|
45
|
+
if (userId != null) {
|
|
46
|
+
Logger.println('User ID ' + colors.green(userId));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
Logger.println('User ID ' + colors.red('Authentication failed'));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
Logger.println('User ID ' + colors.red('Not connected'));
|
|
54
|
+
}
|
|
37
55
|
}
|
|
38
56
|
|
|
39
57
|
module.exports = { diag };
|
package/src/commands/logs.js
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const AppConfig = require('../models/app_configuration.js');
|
|
4
|
-
const
|
|
4
|
+
const LogV2 = require('../models/log.js');
|
|
5
|
+
const Log = require('../models/log-v4.js');
|
|
5
6
|
const Logger = require('../logger.js');
|
|
7
|
+
const { Deferred } = require('../models/utils.js');
|
|
6
8
|
|
|
7
9
|
async function appLogs (params) {
|
|
8
10
|
const { alias, after: since, before: until, search, 'deployment-id': deploymentId } = params.options;
|
|
9
|
-
const { addon: addonId } = params.options;
|
|
10
11
|
|
|
11
12
|
// ignore --search ""
|
|
12
13
|
const filter = (search !== '') ? search : null;
|
|
13
|
-
|
|
14
|
+
|
|
15
|
+
const { appId, ownerId } = await AppConfig.getAppDetails({ alias });
|
|
14
16
|
|
|
15
17
|
Logger.println('Waiting for application logs…');
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
// TODO: drop when addons are migrated to the v4 API
|
|
20
|
+
if (params.addon) {
|
|
21
|
+
const { addon: addonId } = params.options;
|
|
22
|
+
const appAddonId = addonId || await AppConfig.getAppDetails({ alias }).then(({ appId }) => appId);
|
|
23
|
+
return LogV2.displayLogs({ appAddonId, since, until, filter, deploymentId });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const deferred = new Deferred();
|
|
27
|
+
await Log.displayLogs({ ownerId, appId, since, until, filter, deploymentId, deferred });
|
|
28
|
+
return deferred.promise;
|
|
18
29
|
}
|
|
19
30
|
|
|
20
31
|
module.exports = { appLogs };
|
package/src/commands/restart.js
CHANGED
|
@@ -5,7 +5,7 @@ const colors = require('colors/safe');
|
|
|
5
5
|
const AppConfig = require('../models/app_configuration.js');
|
|
6
6
|
const Application = require('../models/application.js');
|
|
7
7
|
const git = require('../models/git.js');
|
|
8
|
-
const Log = require('../models/log.js');
|
|
8
|
+
const Log = require('../models/log-v4.js');
|
|
9
9
|
const Logger = require('../logger.js');
|
|
10
10
|
|
|
11
11
|
// Once the API call to redeploy() has been triggerred successfully,
|
|
@@ -24,9 +24,19 @@ async function restart (params) {
|
|
|
24
24
|
Logger.println(`Restarting ${appName} on commit ${colors.green(commitId)}${cacheSuffix}`);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// This should be handled by the API when a deployment ID is set but we'll do this for now
|
|
28
|
+
const redeployDate = new Date();
|
|
29
|
+
|
|
27
30
|
const redeploy = await Application.redeploy(ownerId, appId, fullCommitId, withoutCache);
|
|
28
31
|
|
|
29
|
-
return Log.watchDeploymentAndDisplayLogs({
|
|
32
|
+
return Log.watchDeploymentAndDisplayLogs({
|
|
33
|
+
ownerId,
|
|
34
|
+
appId,
|
|
35
|
+
deploymentId: redeploy.deploymentId,
|
|
36
|
+
quiet,
|
|
37
|
+
follow,
|
|
38
|
+
redeployDate,
|
|
39
|
+
});
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
module.exports = { restart };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const cliparse = require('cliparse');
|
|
2
|
+
|
|
3
|
+
function getOutputFormatOption (formats = []) {
|
|
4
|
+
const availableFormats = ['human', 'json', ...formats];
|
|
5
|
+
return cliparse.option('format', {
|
|
6
|
+
aliases: ['F'],
|
|
7
|
+
metavar: 'format',
|
|
8
|
+
parser: (format) => {
|
|
9
|
+
return availableFormats.includes(format)
|
|
10
|
+
? cliparse.parsers.success(format)
|
|
11
|
+
: cliparse.parsers.error('The output format must be one of ' + availableFormats.join(', '));
|
|
12
|
+
},
|
|
13
|
+
default: 'human',
|
|
14
|
+
description: `Output format (${availableFormats.join(', ')})`,
|
|
15
|
+
complete () {
|
|
16
|
+
return cliparse.autocomplete.words(availableFormats);
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
getOutputFormatOption,
|
|
23
|
+
};
|
package/src/models/accesslogs.js
CHANGED
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const clfDate = require('clf-date');
|
|
4
4
|
|
|
5
|
-
function listAvailableFormats () {
|
|
6
|
-
return ['simple', 'extended', 'clf', 'json'];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
5
|
function getFormatter (format, isAddon) {
|
|
10
6
|
switch (format.toLowerCase()) {
|
|
7
|
+
// "simple" is the legacy default, "human" is the new one
|
|
8
|
+
case 'human':
|
|
11
9
|
case 'simple':
|
|
12
10
|
return isAddon ? formatSimpleAddon : formatSimple;
|
|
13
11
|
case 'extended':
|
|
@@ -53,4 +51,4 @@ function formatCLFAddon (l) {
|
|
|
53
51
|
return `${l.ipS} - - [${clfDate(new Date(l.t))}] "- - -" - ${l.bOut}`;
|
|
54
52
|
}
|
|
55
53
|
|
|
56
|
-
module.exports = {
|
|
54
|
+
module.exports = { getFormatter };
|
package/src/models/addon.js
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const application = require('@clevercloud/client/cjs/api/v2/application.js');
|
|
4
4
|
const autocomplete = require('cliparse').autocomplete;
|
|
5
|
-
const
|
|
6
|
-
|
|
5
|
+
const {
|
|
6
|
+
get: getAddon,
|
|
7
|
+
getAll: getAllAddons,
|
|
8
|
+
remove: removeAddon,
|
|
9
|
+
create: createAddon,
|
|
10
|
+
update: updateAddon,
|
|
11
|
+
} = require('@clevercloud/client/cjs/api/v2/addon.js');
|
|
7
12
|
const { getAllAddonProviders } = require('@clevercloud/client/cjs/api/v2/product.js');
|
|
8
13
|
const { getSummary } = require('@clevercloud/client/cjs/api/v2/user.js');
|
|
9
14
|
const { getAddonProvider } = require('@clevercloud/client/cjs/api/v4/addon-providers.js');
|
|
@@ -11,6 +16,7 @@ const { getAddonProvider } = require('@clevercloud/client/cjs/api/v4/addon-provi
|
|
|
11
16
|
const Interact = require('./interact.js');
|
|
12
17
|
const Logger = require('../logger.js');
|
|
13
18
|
const { sendToApi } = require('../models/send-to-api.js');
|
|
19
|
+
const { resolveOwnerId } = require('./ids-resolver.js');
|
|
14
20
|
|
|
15
21
|
function listProviders () {
|
|
16
22
|
return getAllAddonProviders({}).then(sendToApi);
|
|
@@ -167,19 +173,6 @@ async function create ({ ownerId, name, providerName, planName, region, skipConf
|
|
|
167
173
|
options: createOptions,
|
|
168
174
|
};
|
|
169
175
|
|
|
170
|
-
const result = await preorderAddon({ id: ownerId }, addonToCreate).then(sendToApi);
|
|
171
|
-
|
|
172
|
-
if (result.totalTTC > 0 && !skipConfirmation) {
|
|
173
|
-
result.lines.forEach(({ description, VAT, price }) => Logger.println(`${description}\tVAT: ${VAT}%\tPrice: ${price}€`));
|
|
174
|
-
Logger.println(`Total (without taxes): ${result.totalHT}€`);
|
|
175
|
-
Logger.println(colors.bold(`Total (with taxes): ${result.totalTTC}€`));
|
|
176
|
-
|
|
177
|
-
await Interact.confirm(
|
|
178
|
-
`You're about to pay ${result.totalTTC}€, confirm? (yes or no) `,
|
|
179
|
-
'No confirmation, aborting addon creation',
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
176
|
return createAddon({ id: ownerId }, addonToCreate).then(sendToApi);
|
|
184
177
|
}
|
|
185
178
|
|
|
@@ -255,6 +248,20 @@ async function findById (addonId) {
|
|
|
255
248
|
throw new Error(`Could not find add-on with ID: ${addonId}`);
|
|
256
249
|
}
|
|
257
250
|
|
|
251
|
+
async function findOwnerId (org, addonId) {
|
|
252
|
+
|
|
253
|
+
if (org != null && org.orga_id != null) {
|
|
254
|
+
return org.orga_id;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const ownerId = await resolveOwnerId(addonId);
|
|
258
|
+
if (ownerId != null) {
|
|
259
|
+
return ownerId;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
throw new Error(`Add-on ${addonId} does not exist`);
|
|
263
|
+
}
|
|
264
|
+
|
|
258
265
|
function parseAddonOptions (options) {
|
|
259
266
|
if (options == null) {
|
|
260
267
|
return {};
|
|
@@ -288,6 +295,7 @@ module.exports = {
|
|
|
288
295
|
create,
|
|
289
296
|
delete: deleteAddon,
|
|
290
297
|
findById,
|
|
298
|
+
findOwnerId,
|
|
291
299
|
getProvider,
|
|
292
300
|
getProviderInfos,
|
|
293
301
|
link,
|
|
@@ -10,63 +10,42 @@ const xdg = require('xdg');
|
|
|
10
10
|
const Logger = require('../logger.js');
|
|
11
11
|
const env = commonEnv(Logger);
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
else {
|
|
18
|
-
return xdg.basedir.configPath('clever-cloud');
|
|
19
|
-
}
|
|
20
|
-
}
|
|
13
|
+
const CONFIG_FILES = {
|
|
14
|
+
MAIN: 'clever-tools.json',
|
|
15
|
+
IDS_CACHE: 'ids-cache.json',
|
|
16
|
+
};
|
|
21
17
|
|
|
22
|
-
function getConfigPath () {
|
|
23
|
-
const configDir =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
async function isFile (path) {
|
|
28
|
-
try {
|
|
29
|
-
const pathStat = await fs.stat(path);
|
|
30
|
-
return pathStat.isFile();
|
|
31
|
-
}
|
|
32
|
-
catch (e) {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async function maybeMigrateFromLegacyConfigurationPath () {
|
|
38
|
-
// This used to be a file
|
|
39
|
-
const configDir = getConfigDir();
|
|
40
|
-
const legacyConfig = await isFile(configDir);
|
|
41
|
-
// If it is still a file, we replace it with a dir and move it inside
|
|
42
|
-
if (legacyConfig) {
|
|
43
|
-
const tmpConfigFile = `${configDir}.tmp`;
|
|
44
|
-
const configFile = getConfigPath();
|
|
45
|
-
|
|
46
|
-
// Rename so that we can create the directory
|
|
47
|
-
await fs.rename(configDir, tmpConfigFile);
|
|
48
|
-
await mkdirp(configDir, { mode: 0o700 });
|
|
49
|
-
await fs.rename(tmpConfigFile, configFile);
|
|
50
|
-
}
|
|
18
|
+
function getConfigPath (configFile) {
|
|
19
|
+
const configDir = (process.platform === 'win32')
|
|
20
|
+
? path.resolve(process.env.APPDATA, 'clever-cloud')
|
|
21
|
+
: xdg.basedir.configPath('clever-cloud');
|
|
22
|
+
return path.resolve(configDir, configFile);
|
|
51
23
|
}
|
|
52
24
|
|
|
53
25
|
async function loadOAuthConf () {
|
|
54
26
|
Logger.debug('Load configuration from environment variables');
|
|
55
27
|
if (process.env.CLEVER_TOKEN != null && process.env.CLEVER_SECRET != null) {
|
|
56
28
|
return {
|
|
29
|
+
source: 'environment variables',
|
|
57
30
|
token: process.env.CLEVER_TOKEN,
|
|
58
31
|
secret: process.env.CLEVER_SECRET,
|
|
59
32
|
};
|
|
60
33
|
}
|
|
61
34
|
Logger.debug('Load configuration from ' + conf.CONFIGURATION_FILE);
|
|
62
|
-
await maybeMigrateFromLegacyConfigurationPath();
|
|
63
35
|
try {
|
|
64
36
|
const rawFile = await fs.readFile(conf.CONFIGURATION_FILE);
|
|
65
|
-
|
|
37
|
+
const { token, secret } = JSON.parse(rawFile);
|
|
38
|
+
return {
|
|
39
|
+
source: 'configuration file',
|
|
40
|
+
token,
|
|
41
|
+
secret,
|
|
42
|
+
};
|
|
66
43
|
}
|
|
67
44
|
catch (error) {
|
|
68
45
|
Logger.info(`Cannot load configuration from ${conf.CONFIGURATION_FILE}\n${error.message}`);
|
|
69
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
source: 'none',
|
|
48
|
+
};
|
|
70
49
|
}
|
|
71
50
|
}
|
|
72
51
|
|
|
@@ -82,6 +61,32 @@ async function writeOAuthConf (oauthData) {
|
|
|
82
61
|
}
|
|
83
62
|
}
|
|
84
63
|
|
|
64
|
+
async function loadIdsCache () {
|
|
65
|
+
const cachePath = getConfigPath(CONFIG_FILES.IDS_CACHE);
|
|
66
|
+
try {
|
|
67
|
+
const rawFile = await fs.readFile(cachePath);
|
|
68
|
+
return JSON.parse(rawFile);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
Logger.info(`Cannot load IDs cache from ${cachePath}\n${error.message}`);
|
|
72
|
+
return {
|
|
73
|
+
owners: {},
|
|
74
|
+
addons: {},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function writeIdsCache (ids) {
|
|
80
|
+
const cachePath = getConfigPath(CONFIG_FILES.IDS_CACHE);
|
|
81
|
+
const idsJson = JSON.stringify(ids);
|
|
82
|
+
try {
|
|
83
|
+
await fs.writeFile(cachePath, idsJson);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
throw new Error(`Cannot write IDs cache to ${cachePath}\n${error.message}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
85
90
|
const conf = env.getOrElseAll({
|
|
86
91
|
API_HOST: 'https://api.clever-cloud.com',
|
|
87
92
|
// API_HOST: 'https://ccapi-preprod.cleverapps.io',
|
|
@@ -94,7 +99,7 @@ const conf = env.getOrElseAll({
|
|
|
94
99
|
OAUTH_CONSUMER_SECRET: 'MgVMqTr6fWlf2M0tkC2MXOnhfqBWDT',
|
|
95
100
|
SSH_GATEWAY: 'ssh@sshgateway-clevercloud-customers.services.clever-cloud.com',
|
|
96
101
|
|
|
97
|
-
CONFIGURATION_FILE: getConfigPath(),
|
|
102
|
+
CONFIGURATION_FILE: getConfigPath(CONFIG_FILES.MAIN),
|
|
98
103
|
CONSOLE_TOKEN_URL: 'https://console.clever-cloud.com/cli-oauth',
|
|
99
104
|
// CONSOLE_TOKEN_URL: 'https://next-console.cleverapps.io/cli-oauth',
|
|
100
105
|
|
|
@@ -102,4 +107,4 @@ const conf = env.getOrElseAll({
|
|
|
102
107
|
APP_CONFIGURATION_FILE: path.resolve('.', '.clever.json'),
|
|
103
108
|
});
|
|
104
109
|
|
|
105
|
-
module.exports = { conf, loadOAuthConf, writeOAuthConf };
|
|
110
|
+
module.exports = { conf, loadOAuthConf, writeOAuthConf, loadIdsCache, writeIdsCache };
|
|
@@ -42,7 +42,7 @@ const membersTableColumnLengths = [
|
|
|
42
42
|
48, /* id length */
|
|
43
43
|
12, /* type length */
|
|
44
44
|
48, /* label length */
|
|
45
|
-
|
|
45
|
+
110, /* domain-name length */
|
|
46
46
|
];
|
|
47
47
|
const formatMembersTable = formatNgTable(membersTableColumnLengths);
|
|
48
48
|
async function formatMembersLine (member, showAliases = false) {
|
|
@@ -71,23 +71,23 @@ async function printMembersTableHeader (naturalName = false) {
|
|
|
71
71
|
|
|
72
72
|
const peersTableColumnLengths = [
|
|
73
73
|
45, /* id length */
|
|
74
|
+
15, /* ip */
|
|
75
|
+
36, /* hostname */
|
|
74
76
|
12, /* type length */
|
|
75
77
|
14, /* endpoint type length */
|
|
76
|
-
|
|
77
|
-
24, /* hostname */
|
|
78
|
-
15, /* ip */
|
|
78
|
+
36, /* label length */
|
|
79
79
|
];
|
|
80
80
|
const formatPeersTable = formatNgTable(peersTableColumnLengths);
|
|
81
81
|
function formatPeersLine (peer) {
|
|
82
|
-
const ip = (peer.endpoint.type === 'ServerEndpoint') ? peer.endpoint.ng_term.
|
|
82
|
+
const ip = (peer.endpoint.type === 'ServerEndpoint') ? peer.endpoint.ng_term.host : peer.endpoint.ng_ip;
|
|
83
83
|
return formatPeersTable([
|
|
84
84
|
[
|
|
85
85
|
Formatter.formatId(peer.id),
|
|
86
|
+
Formatter.formatIp(ip),
|
|
87
|
+
Formatter.formatString(peer.hostname, false),
|
|
86
88
|
Formatter.formatString(peer.type, false),
|
|
87
89
|
Formatter.formatString(peer.endpoint.type, false),
|
|
88
90
|
Formatter.formatString(peer.label, false),
|
|
89
|
-
Formatter.formatString(peer.hostname, false),
|
|
90
|
-
Formatter.formatIp(ip),
|
|
91
91
|
],
|
|
92
92
|
]);
|
|
93
93
|
};
|
|
@@ -95,11 +95,11 @@ function printPeersTableHeader () {
|
|
|
95
95
|
Logger.println(colors.bold(formatPeersTable([
|
|
96
96
|
[
|
|
97
97
|
'Peer ID',
|
|
98
|
+
'IP Address',
|
|
99
|
+
'Hostname',
|
|
98
100
|
'Peer Type',
|
|
99
101
|
'Endpoint Type',
|
|
100
102
|
'Label',
|
|
101
|
-
'Hostname',
|
|
102
|
-
'IP Address',
|
|
103
103
|
],
|
|
104
104
|
])));
|
|
105
105
|
printSeparator(peersTableColumnLengths);
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const { getSummary } = require('@clevercloud/client/cjs/api/v2/user.js');
|
|
2
|
+
const { sendToApi } = require('./send-to-api.js');
|
|
3
|
+
const { loadIdsCache, writeIdsCache } = require('./configuration.js');
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
This system uses a simplified representation of the summary to expose IDs links:
|
|
7
|
+
|
|
8
|
+
* app ID => owner ID
|
|
9
|
+
* add-on ID => owner ID
|
|
10
|
+
* real add-on ID => owner ID
|
|
11
|
+
* add-on ID => real add-on ID
|
|
12
|
+
* real add-on ID => add-on ID
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
owners: {
|
|
16
|
+
[appid]: [ownerId],
|
|
17
|
+
[addonId]: [ownerId],
|
|
18
|
+
[realId]: [ownerId],
|
|
19
|
+
},
|
|
20
|
+
addons: {
|
|
21
|
+
[addonId]: { realId: [realId], addonId: [addonId] },
|
|
22
|
+
[realId]: { realId: [realId], addonId: [addonId] },
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
async function resolveOwnerId (id) {
|
|
28
|
+
return getIdFromCacheOrSummary((ids) => ids.owners[id]);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function resolveAddonId (id) {
|
|
32
|
+
|
|
33
|
+
const addonId = await getIdFromCacheOrSummary((ids) => {
|
|
34
|
+
return (ids.addons[id] != null) ? ids.addons[id].addonId : null;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (addonId != null) {
|
|
38
|
+
return addonId;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
throw new Error(`Add-on ${id} does not exist`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function resolveRealId (id) {
|
|
45
|
+
|
|
46
|
+
const realId = await getIdFromCacheOrSummary((ids) => {
|
|
47
|
+
return (ids.addons[id] != null) ? ids.addons[id].realId : null;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (realId != null) {
|
|
51
|
+
return realId;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
throw new Error(`Add-on ${id} does not exist foo`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function getIdFromCacheOrSummary (callback) {
|
|
58
|
+
|
|
59
|
+
const idsFromCache = await loadIdsCache();
|
|
60
|
+
const idFromCache = callback(idsFromCache);
|
|
61
|
+
if (idFromCache != null) {
|
|
62
|
+
return idFromCache;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const idsFromSummary = await getIdsFromSummary();
|
|
66
|
+
await writeIdsCache(idsFromSummary);
|
|
67
|
+
|
|
68
|
+
const idFromSummary = callback(idsFromSummary);
|
|
69
|
+
if (idFromSummary != null) {
|
|
70
|
+
return idFromSummary;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function getIdsFromSummary () {
|
|
77
|
+
|
|
78
|
+
const ids = {
|
|
79
|
+
owners: {},
|
|
80
|
+
addons: {},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const summary = await getSummary().then(sendToApi);
|
|
84
|
+
|
|
85
|
+
const owners = [
|
|
86
|
+
summary.user,
|
|
87
|
+
...summary.organisations,
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
for (const owner of owners) {
|
|
91
|
+
for (const app of owner.applications) {
|
|
92
|
+
ids.owners[app.id] = owner.id;
|
|
93
|
+
}
|
|
94
|
+
for (const addon of owner.addons) {
|
|
95
|
+
ids.owners[addon.id] = owner.id;
|
|
96
|
+
ids.owners[addon.realId] = owner.id;
|
|
97
|
+
const addonIds = { addonId: addon.id, realId: addon.realId };
|
|
98
|
+
ids.addons[addon.id] = addonIds;
|
|
99
|
+
ids.addons[addon.realId] = addonIds;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return ids;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = {
|
|
107
|
+
resolveOwnerId,
|
|
108
|
+
resolveAddonId,
|
|
109
|
+
resolveRealId,
|
|
110
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
const { getHostAndTokens } = require('./send-to-api.js');
|
|
2
|
+
const colors = require('colors/safe');
|
|
3
|
+
const { Deferred } = require('./utils.js');
|
|
4
|
+
const Logger = require('../logger.js');
|
|
5
|
+
const { waitForDeploymentEnd, waitForDeploymentStart } = require('./deployments.js');
|
|
6
|
+
const { ApplicationLogStream } = require('@clevercloud/client/cjs/streams/application-logs.js');
|
|
7
|
+
|
|
8
|
+
// 2000 logs per 100ms maximum
|
|
9
|
+
const THROTTLE_ELEMENTS = 2000;
|
|
10
|
+
const THROTTLE_PER_IN_MILLISECONDS = 100;
|
|
11
|
+
|
|
12
|
+
async function displayLogs (params) {
|
|
13
|
+
|
|
14
|
+
const deferred = params.deferred || new Deferred();
|
|
15
|
+
const { apiHost, tokens } = await getHostAndTokens();
|
|
16
|
+
const { ownerId, appId, filter, since, until, deploymentId } = params;
|
|
17
|
+
|
|
18
|
+
const logStream = new ApplicationLogStream({
|
|
19
|
+
apiHost,
|
|
20
|
+
tokens,
|
|
21
|
+
ownerId,
|
|
22
|
+
appId,
|
|
23
|
+
since,
|
|
24
|
+
until,
|
|
25
|
+
deploymentId,
|
|
26
|
+
filter,
|
|
27
|
+
throttleElements: THROTTLE_ELEMENTS,
|
|
28
|
+
throttlePerInMilliseconds: THROTTLE_PER_IN_MILLISECONDS,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Properly close the stream
|
|
32
|
+
process.once('SIGINT', (signal) => logStream.close(signal));
|
|
33
|
+
|
|
34
|
+
logStream
|
|
35
|
+
.on('open', (event) => {
|
|
36
|
+
Logger.debug(`stream opened! ${JSON.stringify({ appId, filter, deploymentId })}`);
|
|
37
|
+
})
|
|
38
|
+
.on('error', (event) => {
|
|
39
|
+
Logger.error(`an error occured: ${event.detail}`);
|
|
40
|
+
})
|
|
41
|
+
.onLog((log) => {
|
|
42
|
+
Logger.println(formatLogLine(log));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// start() is blocking until end of stream
|
|
46
|
+
logStream.start()
|
|
47
|
+
.then((reason) => deferred.resolve())
|
|
48
|
+
.catch((error) => deferred.reject(error));
|
|
49
|
+
|
|
50
|
+
return logStream;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function watchDeploymentAndDisplayLogs (options) {
|
|
54
|
+
|
|
55
|
+
const {
|
|
56
|
+
ownerId,
|
|
57
|
+
appId,
|
|
58
|
+
deploymentId,
|
|
59
|
+
commitId,
|
|
60
|
+
knownDeployments,
|
|
61
|
+
quiet,
|
|
62
|
+
follow,
|
|
63
|
+
redeployDate,
|
|
64
|
+
} = options;
|
|
65
|
+
|
|
66
|
+
Logger.println('Waiting for deployment to start…');
|
|
67
|
+
const deployment = await waitForDeploymentStart({ ownerId, appId, deploymentId, commitId, knownDeployments });
|
|
68
|
+
Logger.println(colors.bold.blue(`Deployment started (${deployment.uuid})`));
|
|
69
|
+
|
|
70
|
+
const deferred = new Deferred();
|
|
71
|
+
let logsStream;
|
|
72
|
+
|
|
73
|
+
if (!quiet) {
|
|
74
|
+
// About the deferred…
|
|
75
|
+
// If displayLogs() throws an error,
|
|
76
|
+
// the async function we're in (watchDeploymentAndDisplayLogs) will stop here and the error will be passed to the parent.
|
|
77
|
+
// displayLogs() defines callback listeners so if it catches error in those callbacks,
|
|
78
|
+
// it has no proper way to bubble up the error here.
|
|
79
|
+
// Using the deferred enables this.
|
|
80
|
+
logsStream = await displayLogs({ ownerId, appId, deploymentId: deployment.uuid, since: redeployDate, deferred });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Logger.println('Waiting for application logs…');
|
|
84
|
+
|
|
85
|
+
// Wait for deployment end (or an error thrown by logs with the deferred)
|
|
86
|
+
const deploymentEnded = await Promise.race([
|
|
87
|
+
waitForDeploymentEnd({ ownerId, appId, deploymentId: deployment.uuid }),
|
|
88
|
+
deferred.promise,
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
if (!quiet && !follow) {
|
|
92
|
+
logsStream.close(quiet ? 'quiet' : 'follow');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (deploymentEnded.state === 'OK') {
|
|
96
|
+
Logger.println(colors.bold.green('Deployment successful'));
|
|
97
|
+
}
|
|
98
|
+
else if (deploymentEnded.state === 'CANCELLED') {
|
|
99
|
+
throw new Error('Deployment was cancelled. Please check the activity');
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
throw new Error('Deployment failed. Please check the logs');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function formatLogLine (log) {
|
|
107
|
+
const { date, message } = log;
|
|
108
|
+
if (isDeploymentSuccessMessage(log)) {
|
|
109
|
+
return `${date.toISOString()}: ${colors.bold.green(message)}`;
|
|
110
|
+
}
|
|
111
|
+
else if (isDeploymentFailedMessage(log)) {
|
|
112
|
+
return `${date.toISOString()}: ${colors.bold.red(message)}`;
|
|
113
|
+
}
|
|
114
|
+
else if (isBuildSucessMessage(log)) {
|
|
115
|
+
return `${date.toISOString()}: ${colors.bold.blue(message)}`;
|
|
116
|
+
}
|
|
117
|
+
return `${date.toISOString()}: ${message}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function isCleverMessage (log) {
|
|
121
|
+
return log.service !== 'bas-deploy.service';
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
function isDeploymentSuccessMessage (log) {
|
|
125
|
+
return isCleverMessage(log) && log.message.toLowerCase().startsWith('successfully deployed in');
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
function isDeploymentFailedMessage (log) {
|
|
129
|
+
return isCleverMessage(log) && log.message.toLowerCase().startsWith('deploy failed in');
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
function isBuildSucessMessage (log) {
|
|
133
|
+
return isCleverMessage(log) && log.message.toLowerCase().startsWith('build succeeded in');
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
module.exports = { displayLogs, watchDeploymentAndDisplayLogs };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const Logger = require('../logger.js');
|
|
4
|
-
const { addOauthHeader } = require('@clevercloud/client/cjs/oauth.
|
|
4
|
+
const { addOauthHeader } = require('@clevercloud/client/cjs/oauth.js');
|
|
5
5
|
const { conf, loadOAuthConf } = require('../models/configuration.js');
|
|
6
6
|
const { execWarpscript } = require('@clevercloud/client/cjs/request-warp10.superagent.js');
|
|
7
7
|
const { prefixUrl } = require('@clevercloud/client/cjs/prefix-url.js');
|
|
8
|
-
const { request } = require('@clevercloud/client/cjs/request.
|
|
8
|
+
const { request } = require('@clevercloud/client/cjs/request.fetch.js');
|
|
9
9
|
|
|
10
10
|
async function loadTokens () {
|
|
11
11
|
const tokens = await loadOAuthConf();
|
package/src/parsers.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const cliparse = require('cliparse');
|
|
4
4
|
|
|
5
|
-
const AccessLogs = require('./models/accesslogs.js');
|
|
6
5
|
const Application = require('./models/application.js');
|
|
7
6
|
|
|
8
7
|
function flavor (flavor) {
|
|
@@ -79,14 +78,6 @@ function commaSeparated (string) {
|
|
|
79
78
|
return cliparse.parsers.success(string.split(','));
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
function accessLogsFormat (format) {
|
|
83
|
-
const availableFormats = AccessLogs.listAvailableFormats();
|
|
84
|
-
if (availableFormats.includes(format)) {
|
|
85
|
-
return cliparse.parsers.success(format);
|
|
86
|
-
}
|
|
87
|
-
return cliparse.parsers.error('The format must be one of ' + availableFormats.join(', '));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
81
|
function integer (string) {
|
|
91
82
|
const integer = parseInt(string);
|
|
92
83
|
if (isNaN(integer)) {
|
|
@@ -162,7 +153,6 @@ module.exports = {
|
|
|
162
153
|
addonIdOrName,
|
|
163
154
|
ngIdOrLabel,
|
|
164
155
|
commaSeparated,
|
|
165
|
-
accessLogsFormat,
|
|
166
156
|
integer,
|
|
167
157
|
tag,
|
|
168
158
|
tags,
|