clever-tools 3.12.0 → 3.13.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.
Files changed (42) hide show
  1. package/bin/clever.js +280 -6
  2. package/package.json +1 -1
  3. package/src/clever-client/auth-bridge.js +1 -1
  4. package/src/clever-client/operators.js +121 -0
  5. package/src/commands/addon.js +12 -7
  6. package/src/commands/cancel-deploy.js +3 -4
  7. package/src/commands/config.js +16 -20
  8. package/src/commands/console.js +4 -10
  9. package/src/commands/create.js +76 -9
  10. package/src/commands/delete.js +11 -10
  11. package/src/commands/deploy.js +35 -21
  12. package/src/commands/emails.js +174 -0
  13. package/src/commands/keycloak.js +138 -0
  14. package/src/commands/link.js +3 -1
  15. package/src/commands/makeDefault.js +2 -1
  16. package/src/commands/matomo.js +85 -0
  17. package/src/commands/metabase.js +112 -0
  18. package/src/commands/open.js +2 -5
  19. package/src/commands/otoroshi.js +138 -0
  20. package/src/commands/profile.js +2 -4
  21. package/src/commands/restart.js +1 -1
  22. package/src/commands/ssh-keys.js +159 -0
  23. package/src/commands/stop.js +1 -1
  24. package/src/commands/tcp-redirs.js +3 -3
  25. package/src/commands/tokens.js +16 -7
  26. package/src/commands/unlink.js +2 -1
  27. package/src/experimental-features.js +16 -15
  28. package/src/lib/operator-commands.js +281 -0
  29. package/src/lib/prompts.js +30 -0
  30. package/src/lib/slugify.js +10 -0
  31. package/src/models/addon.js +5 -2
  32. package/src/models/app_configuration.js +12 -9
  33. package/src/models/application.js +24 -12
  34. package/src/models/application_configuration.js +72 -72
  35. package/src/models/git.js +29 -1
  36. package/src/models/ids-resolver.js +37 -1
  37. package/src/models/interact.js +0 -24
  38. package/src/models/log-v4.js +13 -4
  39. package/src/models/operator.js +48 -0
  40. package/src/models/utils.js +21 -0
  41. package/src/parsers.js +14 -0
  42. package/src/prompt-password.js +0 -10
package/bin/clever.js CHANGED
@@ -36,24 +36,30 @@ import * as deploy from '../src/commands/deploy.js';
36
36
  import * as diag from '../src/commands/diag.js';
37
37
  import * as domain from '../src/commands/domain.js';
38
38
  import * as drain from '../src/commands/drain.js';
39
+ import * as emails from '../src/commands/emails.js';
39
40
  import * as env from '../src/commands/env.js';
40
41
  import * as features from '../src/commands/features.js';
42
+ import * as keycloak from '../src/commands/keycloak.js';
41
43
  import * as kv from '../src/commands/kv.js';
42
44
  import * as link from '../src/commands/link.js';
43
45
  import * as login from '../src/commands/login.js';
44
46
  import * as logout from '../src/commands/logout.js';
45
47
  import * as logs from '../src/commands/logs.js';
48
+ import * as matomo from '../src/commands/matomo.js';
49
+ import * as metabase from '../src/commands/metabase.js';
46
50
  import * as makeDefault from '../src/commands/makeDefault.js';
47
51
  import * as ng from '../src/commands/ng.js';
48
52
  import * as notifyEmail from '../src/commands/notify-email.js';
49
53
  import * as open from '../src/commands/open.js';
50
54
  import * as consoleModule from '../src/commands/console.js';
55
+ import * as otoroshi from '../src/commands/otoroshi.js';
51
56
  import * as profile from '../src/commands/profile.js';
52
57
  import * as publishedConfig from '../src/commands/published-config.js';
53
58
  import * as restart from '../src/commands/restart.js';
54
59
  import * as scale from '../src/commands/scale.js';
55
60
  import * as service from '../src/commands/service.js';
56
61
  import * as ssh from '../src/commands/ssh.js';
62
+ import * as sshKeys from '../src/commands/ssh-keys.js';
57
63
  import * as status from '../src/commands/status.js';
58
64
  import * as stop from '../src/commands/stop.js';
59
65
  import * as tcpRedirs from '../src/commands/tcp-redirs.js';
@@ -129,6 +135,12 @@ async function run () {
129
135
  metavar: 'public_key',
130
136
  description: 'Wireguard public key of the external peer to link to a Network Group',
131
137
  }),
138
+ email: cliparse.argument('email', {
139
+ description: 'Email address',
140
+ parser: Parsers.email,
141
+ }),
142
+ sshKeyName: cliparse.argument('ssh-key-name', { description: 'SSH key name' }),
143
+ sshKeyPath: cliparse.argument('ssh-key-path', { description: 'SSH public key path (.pub)' }),
132
144
  addonIdOrName: cliparse.argument('addon-id', {
133
145
  description: 'Add-on ID (or name, if unambiguous)',
134
146
  parser: Parsers.addonIdOrName,
@@ -172,7 +184,7 @@ async function run () {
172
184
  parser: Parsers.integer,
173
185
  }),
174
186
  configurationName: cliparse.argument('configuration-name', {
175
- description: 'The name of the configuration to manage',
187
+ description: `Configuration to manage: ${ApplicationConfiguration.listAvailableIds(true)}`,
176
188
  complete () {
177
189
  return cliparse.autocomplete.words(ApplicationConfiguration.listAvailableIds());
178
190
  },
@@ -182,6 +194,10 @@ async function run () {
182
194
 
183
195
  // OPTIONS
184
196
  const opts = {
197
+ targetVersion: cliparse.option('target', {
198
+ metavar: 'version',
199
+ description: 'Target version to upgrade to (e.g.: 24, 2.4, 2.4.1)',
200
+ }),
185
201
  apiTokenExpiration: cliparse.option('expiration', {
186
202
  aliases: ['e'],
187
203
  metavar: 'expiration',
@@ -508,10 +524,18 @@ async function run () {
508
524
  aliases: ['y'],
509
525
  description: 'Skip confirmation and delete the application directly',
510
526
  }),
527
+ confirmSshKeyClean: cliparse.flag('yes', {
528
+ aliases: ['y'],
529
+ description: 'Skip confirmation and remove all SSH keys directly',
530
+ }),
511
531
  confirmTcpRedirCreation: cliparse.flag('yes', {
512
532
  aliases: ['y'],
513
533
  description: 'Skip confirmation even if the TCP redirection is not free',
514
534
  }),
535
+ yes: cliparse.flag('yes', {
536
+ aliases: ['y'],
537
+ description: 'Skip confirmation',
538
+ }),
515
539
  jsonFormat: cliparse.flag('json', { aliases: ['j'], description: 'Show result in JSON format' }),
516
540
  humanJsonOutputFormat: getOutputFormatOption(),
517
541
  tag: cliparse.option('tag', {
@@ -632,7 +656,7 @@ async function run () {
632
656
  description: 'Display or edit the configuration of your application',
633
657
  options: [opts.alias, opts.appIdOrName],
634
658
  commands: [configGetCommand, configSetCommand, configUpdateCommand],
635
- }, config.get);
659
+ }, config.list);
636
660
 
637
661
  // CREATE COMMAND
638
662
  const appCreateCommand = cliparse.command('create', {
@@ -728,6 +752,32 @@ async function run () {
728
752
  commands: [drainCreateCommand, drainRemoveCommand, drainEnableCommand, drainDisableCommand],
729
753
  }, drain.list);
730
754
 
755
+ // EMAILS COMMANDS
756
+ const emailsAddCommand = cliparse.command('add', {
757
+ description: 'Add a new secondary email address to the current user',
758
+ args: [args.email],
759
+ }, emails.addSecondary);
760
+ const emailsPrimaryCommand = cliparse.command('primary', {
761
+ description: 'Set the primary email address of the current user',
762
+ args: [args.email],
763
+ }, emails.setPrimary);
764
+ const emailsRemoveCommand = cliparse.command('remove', {
765
+ description: 'Remove a secondary email address from the current user',
766
+ args: [args.email],
767
+ }, emails.removeSecondary);
768
+ const emailsClearCommand = cliparse.command('remove-all', {
769
+ description: 'Remove all secondary email addresses from the current user',
770
+ options: [opts.yes],
771
+ }, emails.removeAllSecondary);
772
+ const emailsOpenConsoleCommand = cliparse.command('open', {
773
+ description: 'Open the email addresses management page in the Console',
774
+ }, emails.openConsole);
775
+ const emailsCommands = cliparse.command('emails', {
776
+ description: 'Manage email addresses of the current user',
777
+ privateOptions: [opts.humanJsonOutputFormat],
778
+ commands: [emailsAddCommand, emailsPrimaryCommand, emailsRemoveCommand, emailsClearCommand, emailsOpenConsoleCommand],
779
+ }, emails.list);
780
+
731
781
  // ENV COMMANDS
732
782
  const envSetCommand = cliparse.command('set', {
733
783
  description: 'Add or update an environment variable named <variable-name> with the value <variable-value>',
@@ -774,6 +824,63 @@ async function run () {
774
824
  commands: [enableFeatureCommand, disableFeatureCommand, listFeaturesCommand, infoFeaturesCommand],
775
825
  }, features.list);
776
826
 
827
+ // KEYCLOAK COMMAND
828
+ const keycloakGetCommand = cliparse.command('get', {
829
+ description: 'Get information about a deployed Keycloak',
830
+ args: [args.addonIdOrName],
831
+ options: [opts.humanJsonOutputFormat],
832
+ }, keycloak.get);
833
+ const keycloakEnableNgCommand = cliparse.command('enable-ng', {
834
+ description: 'Link Keycloak to a Network Group, used for multi-instances secure communication',
835
+ args: [args.addonIdOrName],
836
+ }, keycloak.ngEnable);
837
+ const keycloakDisableNgCommand = cliparse.command('disable-ng', {
838
+ description: 'Unlink Keycloak from its Network Group',
839
+ args: [args.addonIdOrName],
840
+ }, keycloak.ngDisable);
841
+ const keycloakOpenLogsCommand = cliparse.command('logs', {
842
+ description: 'Open the Keycloak application logs in Clever Cloud Console',
843
+ args: [args.addonIdOrName],
844
+ }, keycloak.openLogs);
845
+ const keycloakOpenWebUiCommand = cliparse.command('webui', {
846
+ description: 'Open the Keycloak admin console in your browser',
847
+ args: [args.addonIdOrName],
848
+ }, keycloak.openWebUi);
849
+ const keycloakOpenCommand = cliparse.command('open', {
850
+ description: 'Open the Keycloak dashboard in Clever Cloud Console',
851
+ args: [args.addonIdOrName],
852
+ commands: [keycloakOpenLogsCommand, keycloakOpenWebUiCommand],
853
+ }, keycloak.open);
854
+ const keycloakRestartCommand = cliparse.command('restart', {
855
+ description: 'Restart Keycloak',
856
+ args: [args.addonIdOrName],
857
+ }, keycloak.reboot);
858
+ const keycloakRebuildCommand = cliparse.command('rebuild', {
859
+ description: 'Rebuild Keycloak',
860
+ args: [args.addonIdOrName],
861
+ }, keycloak.rebuild);
862
+ const keycloakVersionCheckCommand = cliparse.command('check', {
863
+ description: 'Check Keycloak deployed version',
864
+ args: [args.addonIdOrName],
865
+ options: [opts.humanJsonOutputFormat],
866
+ }, keycloak.checkVersion);
867
+ const keycloakVersionUpdateCommand = cliparse.command('update', {
868
+ description: 'Update Keycloak deployed version',
869
+ args: [args.addonIdOrName],
870
+ options: [opts.targetVersion],
871
+ }, keycloak.updateVersion);
872
+ const keycloakVersionsCommands = cliparse.command('version', {
873
+ description: 'Check Keycloak deployed version',
874
+ args: [args.addonIdOrName],
875
+ options: [opts.humanJsonOutputFormat],
876
+ commands: [keycloakVersionCheckCommand, keycloakVersionUpdateCommand],
877
+ }, keycloak.checkVersion);
878
+ const keycloakCommand = cliparse.command('keycloak', {
879
+ description: 'Manage Clever Cloud Keycloak services',
880
+ privateOptions: [opts.humanJsonOutputFormat],
881
+ commands: [keycloakGetCommand, keycloakEnableNgCommand, keycloakDisableNgCommand, keycloakOpenCommand, keycloakRestartCommand, keycloakRebuildCommand, keycloakVersionsCommands],
882
+ }, keycloak.list);
883
+
777
884
  // KV COMMAND
778
885
  const kvRawCommand = cliparse.command('kv', {
779
886
  description: 'Send a raw command to a Materia KV or Redis® add-on',
@@ -811,6 +918,88 @@ async function run () {
811
918
  args: [args.alias],
812
919
  }, makeDefault.makeDefault);
813
920
 
921
+ // MATOMO COMMAND
922
+ const matomoGetCommand = cliparse.command('get', {
923
+ description: 'Get information about a deployed Matomo',
924
+ args: [args.addonIdOrName],
925
+ options: [opts.humanJsonOutputFormat],
926
+ }, matomo.get);
927
+ const matomoOpenLogsCommand = cliparse.command('logs', {
928
+ description: 'Open the Matomo application logs in Clever Cloud Console',
929
+ args: [args.addonIdOrName],
930
+ }, matomo.openLogs);
931
+ const matomoOpenWebUiCommand = cliparse.command('webui', {
932
+ description: 'Open the Matomo admin console in your browser',
933
+ args: [args.addonIdOrName],
934
+ }, matomo.openWebUi);
935
+ const matomoOpenCommand = cliparse.command('open', {
936
+ description: 'Open the Matomo dashboard in Clever Cloud Console',
937
+ args: [args.addonIdOrName],
938
+ commands: [matomoOpenLogsCommand, matomoOpenWebUiCommand],
939
+ }, matomo.open);
940
+ const matomoRestartCommand = cliparse.command('restart', {
941
+ description: 'Restart Matomo',
942
+ args: [args.addonIdOrName],
943
+ }, matomo.reboot);
944
+ const matomoRebuildCommand = cliparse.command('rebuild', {
945
+ description: 'Rebuild Matomo',
946
+ args: [args.addonIdOrName],
947
+ }, matomo.rebuild);
948
+ const matomoCommand = cliparse.command('matomo', {
949
+ description: 'Manage Clever Cloud Matomo services',
950
+ privateOptions: [opts.humanJsonOutputFormat],
951
+ commands: [matomoGetCommand, matomoOpenCommand, matomoRestartCommand, matomoRebuildCommand],
952
+ }, matomo.list);
953
+
954
+ // METABASE COMMAND
955
+ const metabaseGetCommand = cliparse.command('get', {
956
+ description: 'Get information about a deployed Metabase',
957
+ args: [args.addonIdOrName],
958
+ options: [opts.humanJsonOutputFormat],
959
+ }, metabase.get);
960
+ const metabaseOpenLogsCommand = cliparse.command('logs', {
961
+ description: 'Open the Metabase application logs in Clever Cloud Console',
962
+ args: [args.addonIdOrName],
963
+ }, metabase.openLogs);
964
+ const metabaseOpenWebUiCommand = cliparse.command('webui', {
965
+ description: 'Open the Metabase admin console in your browser',
966
+ args: [args.addonIdOrName],
967
+ }, metabase.openWebUi);
968
+ const metabaseOpenCommand = cliparse.command('open', {
969
+ description: 'Open the Metabase dashboard in Clever Cloud Console',
970
+ args: [args.addonIdOrName],
971
+ commands: [metabaseOpenLogsCommand, metabaseOpenWebUiCommand],
972
+ }, metabase.open);
973
+ const metabaseRestartCommand = cliparse.command('restart', {
974
+ description: 'Restart Metabase',
975
+ args: [args.addonIdOrName],
976
+ }, metabase.reboot);
977
+ const metabaseRebuildCommand = cliparse.command('rebuild', {
978
+ description: 'Rebuild Metabase',
979
+ args: [args.addonIdOrName],
980
+ }, metabase.rebuild);
981
+ const metabaseVersionCheckCommand = cliparse.command('check', {
982
+ description: 'Check Metabase deployed version',
983
+ args: [args.addonIdOrName],
984
+ options: [opts.humanJsonOutputFormat],
985
+ }, metabase.checkVersion);
986
+ const metabaseVersionUpdateCommand = cliparse.command('update', {
987
+ description: 'Update Metabase deployed version',
988
+ args: [args.addonIdOrName],
989
+ options: [opts.targetVersion],
990
+ }, metabase.updateVersion);
991
+ const metabaseVersionsCommands = cliparse.command('version', {
992
+ description: 'Manage Metabase deployed version',
993
+ args: [args.addonIdOrName],
994
+ options: [opts.humanJsonOutputFormat],
995
+ commands: [metabaseVersionCheckCommand, metabaseVersionUpdateCommand],
996
+ }, metabase.checkVersion);
997
+ const metabaseCommand = cliparse.command('metabase', {
998
+ description: 'Manage Clever Cloud Metabase services',
999
+ privateOptions: [opts.humanJsonOutputFormat],
1000
+ commands: [metabaseGetCommand, metabaseOpenCommand, metabaseRestartCommand, metabaseRebuildCommand, metabaseVersionsCommands],
1001
+ }, metabase.list);
1002
+
814
1003
  // NETWORK GROUP COMMANDS
815
1004
  const ngCreateExternalPeerCommand = cliparse.command('external', {
816
1005
  description: 'Create an external peer in a Network Group',
@@ -884,6 +1073,63 @@ async function run () {
884
1073
  options: [opts.alias, opts.appIdOrName],
885
1074
  }, open.open);
886
1075
 
1076
+ // OTOROSHI COMMAND
1077
+ const otoroshiGetCommand = cliparse.command('get', {
1078
+ description: 'Get information about a deployed Otoroshi',
1079
+ args: [args.addonIdOrName],
1080
+ options: [opts.humanJsonOutputFormat],
1081
+ }, otoroshi.get);
1082
+ const otoroshiEnableNgCommand = cliparse.command('enable-ng', {
1083
+ description: 'Link Otoroshi to a Network Group',
1084
+ args: [args.addonIdOrName],
1085
+ }, otoroshi.ngEnable);
1086
+ const otoroshiDisableNgCommand = cliparse.command('disable-ng', {
1087
+ description: 'Unlink Otoroshi from its Network Group',
1088
+ args: [args.addonIdOrName],
1089
+ }, otoroshi.ngDisable);
1090
+ const otoroshiOpenLogsCommand = cliparse.command('logs', {
1091
+ description: 'Open the Otoroshi application logs in Clever Cloud Console',
1092
+ args: [args.addonIdOrName],
1093
+ }, otoroshi.openLogs);
1094
+ const otoroshiOpenWebUiCommand = cliparse.command('webui', {
1095
+ description: 'Open the Otoroshi admin console in your browser',
1096
+ args: [args.addonIdOrName],
1097
+ }, otoroshi.openWebUi);
1098
+ const otoroshiOpenCommand = cliparse.command('open', {
1099
+ description: 'Open the Otoroshi dashboard in Clever Cloud Console',
1100
+ args: [args.addonIdOrName],
1101
+ commands: [otoroshiOpenLogsCommand, otoroshiOpenWebUiCommand],
1102
+ }, otoroshi.open);
1103
+ const otoroshiRestartCommand = cliparse.command('restart', {
1104
+ description: 'Restart Otoroshi',
1105
+ args: [args.addonIdOrName],
1106
+ }, otoroshi.reboot);
1107
+ const otoroshiRebuildCommand = cliparse.command('rebuild', {
1108
+ description: 'Rebuild Otoroshi',
1109
+ args: [args.addonIdOrName],
1110
+ }, otoroshi.rebuild);
1111
+ const otoroshiVersionCheckCommand = cliparse.command('check', {
1112
+ description: 'Check Otoroshi deployed version',
1113
+ args: [args.addonIdOrName],
1114
+ options: [opts.humanJsonOutputFormat],
1115
+ }, otoroshi.checkVersion);
1116
+ const otoroshiVersionUpdateCommand = cliparse.command('update', {
1117
+ description: 'Update Otoroshi deployed version',
1118
+ args: [args.addonIdOrName],
1119
+ options: [opts.targetVersion],
1120
+ }, otoroshi.updateVersion);
1121
+ const otoroshiVersionsCommands = cliparse.command('version', {
1122
+ description: 'Manage Otoroshi deployed version',
1123
+ args: [args.addonIdOrName],
1124
+ options: [opts.humanJsonOutputFormat],
1125
+ commands: [otoroshiVersionCheckCommand, otoroshiVersionUpdateCommand],
1126
+ }, otoroshi.checkVersion);
1127
+ const otoroshiCommand = cliparse.command('otoroshi', {
1128
+ description: 'Manage Clever Cloud Otoroshi services',
1129
+ privateOptions: [opts.humanJsonOutputFormat],
1130
+ commands: [otoroshiGetCommand, otoroshiEnableNgCommand, otoroshiDisableNgCommand, otoroshiOpenCommand, otoroshiRestartCommand, otoroshiRebuildCommand, otoroshiVersionsCommands],
1131
+ }, otoroshi.list);
1132
+
887
1133
  // CONSOLE COMMAND
888
1134
  const consoleCommand = cliparse.command('console', {
889
1135
  description: 'Open an application in the Console',
@@ -962,6 +1208,28 @@ async function run () {
962
1208
  options: [opts.alias, opts.appIdOrName, opts.sshIdentityFile],
963
1209
  }, ssh.ssh);
964
1210
 
1211
+ // SSH KEYS COMMANDS
1212
+ const sshKeysAddCommand = cliparse.command('add', {
1213
+ description: 'Add a new SSH key to the current user',
1214
+ args: [args.sshKeyName, args.sshKeyPath],
1215
+ }, sshKeys.add);
1216
+ const sshKeysRemoveCommand = cliparse.command('remove', {
1217
+ description: 'Remove a SSH key from the current user',
1218
+ args: [args.sshKeyName],
1219
+ }, sshKeys.remove);
1220
+ const sshKeysRemoveAllCommand = cliparse.command('remove-all', {
1221
+ description: 'Remove all SSH keys from the current user',
1222
+ options: [opts.confirmSshKeyClean],
1223
+ }, sshKeys.removeAll);
1224
+ const sshKeysOpenConsoleCommand = cliparse.command('open', {
1225
+ description: 'Open the SSH keys management page in the Console',
1226
+ }, sshKeys.openConsole);
1227
+ const sshKeysCommands = cliparse.command('ssh-keys', {
1228
+ description: 'Manage SSH keys of the current user',
1229
+ privateOptions: [opts.humanJsonOutputFormat],
1230
+ commands: [sshKeysAddCommand, sshKeysRemoveCommand, sshKeysRemoveAllCommand, sshKeysOpenConsoleCommand],
1231
+ }, sshKeys.list);
1232
+
965
1233
  // STATUS COMMAND
966
1234
  const statusCommand = cliparse.command('status', {
967
1235
  description: 'See the status of an application',
@@ -1084,6 +1352,7 @@ async function run () {
1084
1352
  domainCommands,
1085
1353
  drainCommands,
1086
1354
  emailNotificationsCommand,
1355
+ emailsCommands,
1087
1356
  envCommands,
1088
1357
  featuresCommands,
1089
1358
  cliparseCommands.helpCommand,
@@ -1099,9 +1368,11 @@ async function run () {
1099
1368
  scaleCommand,
1100
1369
  serviceCommands,
1101
1370
  sshCommand,
1371
+ sshKeysCommands,
1102
1372
  statusCommand,
1103
1373
  stopCommand,
1104
1374
  tcpRedirsCommands,
1375
+ tokensCommands,
1105
1376
  versionCommand,
1106
1377
  webhooksCommand,
1107
1378
  ];
@@ -1109,12 +1380,15 @@ async function run () {
1109
1380
  // Add experimental features only if they are enabled through the configuration file
1110
1381
  const featuresFromConf = await getFeatures();
1111
1382
 
1112
- if (featuresFromConf.kv) {
1113
- commands.push(colorizeExperimentalCommand(kvRawCommand, 'kv'));
1383
+ if (featuresFromConf.operators) {
1384
+ commands.push(colorizeExperimentalCommand(keycloakCommand, 'operators'));
1385
+ commands.push(colorizeExperimentalCommand(matomoCommand, 'operators'));
1386
+ commands.push(colorizeExperimentalCommand(metabaseCommand, 'operators'));
1387
+ commands.push(colorizeExperimentalCommand(otoroshiCommand, 'operators'));
1114
1388
  }
1115
1389
 
1116
- if (featuresFromConf.tokens) {
1117
- commands.push(colorizeExperimentalCommand(tokensCommands, 'tokens'));
1390
+ if (featuresFromConf.kv) {
1391
+ commands.push(colorizeExperimentalCommand(kvRawCommand, 'kv'));
1118
1392
  }
1119
1393
 
1120
1394
  if (featuresFromConf.ng) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clever-tools",
3
- "version": "3.12.0",
3
+ "version": "3.13.0",
4
4
  "description": "Command Line Interface for Clever Cloud.",
5
5
  "main": "bin/clever.js",
6
6
  "type": "module",
@@ -1,4 +1,4 @@
1
- export function createApiToken ({ email, password, mfaCode, name, description, expirationDate }) {
1
+ export function createApiToken ({ email, password, mfaCode, name, description = '', expirationDate }) {
2
2
  return Promise.resolve({
3
3
  method: 'post',
4
4
  url: '/api-tokens',
@@ -0,0 +1,121 @@
1
+ // TODO: Move this to the Clever Cloud JS Client
2
+
3
+ /**
4
+ * GET /v4/addon-providers/addon-{provider}/addons/{realId}
5
+ * @param {Object} params
6
+ * @param {String} params.provider
7
+ * @param {String} params.realId
8
+ */
9
+ export function getOperator (params) {
10
+ // no multipath for /self or /organisations/{id}
11
+ return Promise.resolve({
12
+ method: 'get',
13
+ url: `/v4/addon-providers/addon-${params.provider}/addons/${params.realId}`,
14
+ headers: { Accept: 'application/json' },
15
+ // no queryParams
16
+ // no body
17
+ });
18
+ }
19
+
20
+ /**
21
+ * POST /v4/addon-providers/addon-{provider}/addons/{realId}/reboot
22
+ * @param {Object} params
23
+ * @param {String} params.provider
24
+ * @param {String} params.realId
25
+ */
26
+ export function rebootOperator (params) {
27
+ // no multipath for /self or /organisations/{id}
28
+ return Promise.resolve({
29
+ method: 'post',
30
+ url: `/v4/addon-providers/addon-${params.provider}/addons/${params.realId}/reboot`,
31
+ headers: { Accept: 'application/json' },
32
+ // no queryParams
33
+ // no body
34
+ });
35
+ }
36
+
37
+ /**
38
+ * POST /v4/addon-providers/addon-{provider}/addons/{realId}/rebuild
39
+ * @param {Object} params
40
+ * @param {String} params.provider
41
+ * @param {String} params.realId
42
+ */
43
+ export function rebuildOperator (params) {
44
+ // no multipath for /self or /organisations/{id}
45
+ return Promise.resolve({
46
+ method: 'post',
47
+ url: `/v4/addon-providers/addon-${params.provider}/addons/${params.realId}/rebuild`,
48
+ headers: { Accept: 'application/json' },
49
+ // no queryParams
50
+ // no body
51
+ });
52
+ }
53
+
54
+ /**
55
+ * POST /v4/addon-providers/addon-{provider}/addons/{realId}/networkgroup
56
+ * @param {Object} params
57
+ * @param {String} params.provider
58
+ * @param {String} params.realId
59
+ */
60
+ export function ngEnableOperator (params) {
61
+ // no multipath for /self or /organisations/{id}
62
+ return Promise.resolve({
63
+ method: 'post',
64
+ url: `/v4/addon-providers/addon-${params.provider}/addons/${params.realId}/networkgroup`,
65
+ headers: { Accept: 'application/json' },
66
+ // no queryParams
67
+ // no body
68
+ });
69
+ }
70
+
71
+ /**
72
+ * POST /v4/addon-providers/addon-{provider}/addons/{realId}/networkgroup
73
+ * @param {Object} params
74
+ * @param {String} params.provider
75
+ * @param {String} params.realId
76
+ */
77
+ export function ngDisableOperator (params) {
78
+ // no multipath for /self or /organisations/{id}
79
+ return Promise.resolve({
80
+ method: 'delete',
81
+ url: `/v4/addon-providers/addon-${params.provider}/addons/${params.realId}/networkgroup`,
82
+ headers: { Accept: 'application/json' },
83
+ // no queryParams
84
+ // no body
85
+ });
86
+ }
87
+
88
+ /**
89
+ * GET /v4/addon-providers/addon-{provider}/addons/{realId}/version/check
90
+ * @param {Object} params
91
+ * @param {String} params.provider
92
+ * @param {String} params.realId
93
+ */
94
+ export function versionCheck (params) {
95
+ // no multipath for /self or /organisations/{id}
96
+ return Promise.resolve({
97
+ method: 'get',
98
+ url: `/v4/addon-providers/addon-${params.provider}/addons/${params.realId}/version/check`,
99
+ headers: { Accept: 'application/json' },
100
+ // no queryParams
101
+ // no body
102
+ });
103
+ }
104
+
105
+ /**
106
+ * POST /v4/addon-providers/addon-{provider}/addons/{realId}/version/update
107
+ * @param {Object} params
108
+ * @param {String} params.provider
109
+ * @param {String} params.realId
110
+ * @param {Object} body
111
+ */
112
+ export function versionUpdate (params, body) {
113
+ // no multipath for /self or /organisations/{id}
114
+ return Promise.resolve({
115
+ method: 'post',
116
+ url: `/v4/addon-providers/addon-${params.provider}/addons/${params.realId}/version/update`,
117
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
118
+ // no queryParams
119
+ body,
120
+ });
121
+ }
@@ -124,7 +124,7 @@ function displayAddon (format, addon, providerName, message) {
124
124
 
125
125
  const WIP_PROVIDERS = {
126
126
  keycloak: {
127
- status: 'beta',
127
+ status: '',
128
128
  postCreateInstructions: dedent`
129
129
  Learn more about Keycloak on Clever Cloud: ${conf.DOC_URL}/addons/keycloak/,
130
130
  `,
@@ -139,19 +139,19 @@ function displayAddon (format, addon, providerName, message) {
139
139
  `,
140
140
  },
141
141
  'addon-matomo': {
142
- status: 'beta',
142
+ status: '',
143
143
  postCreateInstructions: dedent`
144
144
  Learn more about Matomo on Clever Cloud: ${conf.DOC_URL}/addons/matomo/
145
145
  `,
146
146
  },
147
147
  metabase: {
148
- status: 'beta',
148
+ status: '',
149
149
  postCreateInstructions: dedent`
150
150
  Learn more about Metabase on Clever Cloud: ${conf.DOC_URL}/addons/metabase/
151
151
  `,
152
152
  },
153
153
  otoroshi: {
154
- status: 'beta',
154
+ status: '',
155
155
  postCreateInstructions: dedent`
156
156
  Learn more about Otoroshi with LLM on Clever Cloud: ${conf.DOC_URL}/addons/otoroshi/
157
157
  `,
@@ -166,7 +166,7 @@ function displayAddon (format, addon, providerName, message) {
166
166
 
167
167
  let providerNameToShow = '';
168
168
  let statusMessage = '';
169
- if (providerName in WIP_PROVIDERS) {
169
+ if (providerName in WIP_PROVIDERS && WIP_PROVIDERS[providerName].status !== '') {
170
170
 
171
171
  providerNameToShow = providerName === 'kv'
172
172
  ? 'Materia KV'
@@ -207,11 +207,12 @@ function displayAddon (format, addon, providerName, message) {
207
207
  const provider = PROVIDERS_WITH_URL[providerName];
208
208
  const urlEnv = addon.env.find((entry) => entry.name === provider.urlEnv);
209
209
  const urlToShow = urlEnv.value;
210
+ const urlToShowWithHttps = urlToShow.startsWith('http') ? urlToShow : `https://${urlToShow}`;
210
211
 
211
212
  if (urlEnv) {
212
213
  Logger.println();
213
214
  Logger.println(`Your ${provider.name} is starting:`);
214
- Logger.println(` - Access it: ${urlToShow.startsWith('http') ? urlToShow : `https://${urlToShow}`}`);
215
+ Logger.println(` - Access it: ${urlToShowWithHttps}`);
215
216
  Logger.println(` - Manage it: ${conf.GOTO_URL}/${addon.id}`);
216
217
  }
217
218
 
@@ -233,7 +234,11 @@ function displayAddon (format, addon, providerName, message) {
233
234
  if (providerName in WIP_PROVIDERS) {
234
235
 
235
236
  Logger.println();
236
- Logger.println(colors.yellow(`/!\\ ${statusMessage}`));
237
+
238
+ if (statusMessage !== '') {
239
+ Logger.println(colors.yellow(`/!\\ ${statusMessage}`));
240
+ }
241
+
237
242
  Logger.println(WIP_PROVIDERS[providerName].postCreateInstructions);
238
243
  }
239
244
  }
@@ -2,6 +2,7 @@ import * as Application from '../models/application.js';
2
2
  import { Logger } from '../logger.js';
3
3
  import { getAllDeployments, cancelDeployment } from '@clevercloud/client/esm/api/v2/application.js';
4
4
  import { sendToApi } from '../models/send-to-api.js';
5
+ import colors from 'colors/safe.js';
5
6
 
6
7
  export async function cancelDeploy (params) {
7
8
  const { alias, app: appIdOrName } = params.options;
@@ -13,8 +14,6 @@ export async function cancelDeploy (params) {
13
14
  throw new Error('There is no ongoing deployment for this application');
14
15
  }
15
16
 
16
- const deploymentId = deployments[0].id;
17
- await cancelDeployment({ id: ownerId, appId, deploymentId }).then(sendToApi);
18
-
19
- Logger.println('Deployment cancelled!');
17
+ await cancelDeployment({ id: ownerId, appId, deploymentId: deployments[0].id }).then(sendToApi);
18
+ Logger.printSuccess(`Deployment ${colors.bold.green(deployments[0].uuid)} successfully cancelled!`);
20
19
  };