clever-tools 3.7.0 → 3.8.1

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 (41) hide show
  1. package/README.md +2 -2
  2. package/bin/clever.js +103 -51
  3. package/package.json +47 -47
  4. package/src/command-options.js +19 -0
  5. package/src/commands/accesslogs.js +114 -34
  6. package/src/commands/activity.js +64 -12
  7. package/src/commands/addon.js +152 -57
  8. package/src/commands/applications.js +83 -1
  9. package/src/commands/cancel-deploy.js +3 -3
  10. package/src/commands/config.js +6 -7
  11. package/src/commands/console.js +16 -4
  12. package/src/commands/delete.js +16 -6
  13. package/src/commands/deploy.js +9 -6
  14. package/src/commands/diag.js +68 -28
  15. package/src/commands/domain.js +13 -13
  16. package/src/commands/drain.js +42 -27
  17. package/src/commands/env.js +53 -24
  18. package/src/commands/logs.js +3 -3
  19. package/src/commands/notify-email.js +33 -18
  20. package/src/commands/open.js +3 -3
  21. package/src/commands/profile.js +29 -9
  22. package/src/commands/published-config.js +26 -15
  23. package/src/commands/restart.js +12 -5
  24. package/src/commands/scale.js +2 -3
  25. package/src/commands/service.js +42 -15
  26. package/src/commands/ssh.js +3 -3
  27. package/src/commands/status.js +72 -46
  28. package/src/commands/stop.js +3 -3
  29. package/src/commands/tcp-redirs.js +54 -18
  30. package/src/commands/webhooks.js +28 -13
  31. package/src/logger.js +9 -6
  32. package/src/models/app_configuration.js +11 -3
  33. package/src/models/application.js +106 -7
  34. package/src/models/exit-strategy-option.js +24 -0
  35. package/src/models/json-array.js +28 -0
  36. package/src/models/log-v4.js +9 -29
  37. package/src/models/log.js +9 -2
  38. package/src/models/namespaces.js +20 -0
  39. package/src/models/organisation.js +0 -20
  40. package/src/models/utils.js +8 -1
  41. package/src/models/accesslogs.js +0 -54
@@ -8,34 +8,49 @@ const { getOwnerAndApp, getOrgaIdOrUserId } = require('../models/notification.js
8
8
  const { getEmailhooks, createEmailhook, deleteEmailhook } = require('@clevercloud/client/cjs/api/v2/notification.js');
9
9
  const { sendToApi } = require('../models/send-to-api.js');
10
10
 
11
- function displayEmailhook (hook) {
12
- Logger.println((hook.name && colors.bold(hook.name)) || hook.id);
13
- Logger.println(` id: ${hook.id}`);
14
- Logger.println(` services: ${(hook.scope && hook.scope.join(', ')) || hook.ownerId}`);
15
- Logger.println(` events: ${(hook.events && hook.events.join(', ')) || colors.bold('ALL')}`);
16
- if (hook.notified) {
17
- Logger.println(' to:');
18
- hook.notified.forEach((target) => Logger.println(` ${target.target || 'whole team'}`));
19
- }
20
- else {
21
- Logger.println(' to: whole team');
22
- }
23
- Logger.println();
24
- }
25
-
26
11
  async function list (params) {
27
- const { org, 'list-all': listAll } = params.options;
12
+ const { org, 'list-all': listAll, format } = params.options;
28
13
 
29
14
  // TODO: fix alias option
30
15
  const { ownerId, appId } = await getOwnerAndApp(null, org, !listAll);
31
16
  const hooks = await getEmailhooks({ ownerId }).then(sendToApi);
32
17
 
33
- hooks
18
+ const formattedHooks = hooks
34
19
  .filter((hook) => {
35
20
  const emptyScope = !hook.scope || hook.scope.length === 0;
36
21
  return !appId || emptyScope || hook.scope.includes(appId);
37
22
  })
38
- .forEach((hook) => displayEmailhook(hook));
23
+ .map((hook) => ({
24
+ id: hook.id,
25
+ name: hook.name,
26
+ ownerId: hook.ownerId,
27
+ services: hook.scope ?? [hook.ownerId],
28
+ events: hook.events ?? ['ALL'],
29
+ notified: hook.notified ? hook.notified.map(({ target }) => target ?? 'whole team') : ['whole team'],
30
+ }));
31
+
32
+ switch (format) {
33
+ case 'json': {
34
+ Logger.printJson(formattedHooks);
35
+ break;
36
+ }
37
+ case 'human':
38
+ default: {
39
+ formattedHooks.forEach((hook, i) => {
40
+ Logger.println(colors.bold(hook.name ?? hook.id));
41
+ Logger.println(` id: ${hook.id}`);
42
+ Logger.println(` services: ${hook.services.join(', ')}`);
43
+ Logger.println(` events: ${hook.events.join(', ')}`);
44
+ if (hook.notified.length > 1) {
45
+ Logger.println(' to:');
46
+ hook.notified.forEach((target) => Logger.println(` ${target}`));
47
+ }
48
+ else {
49
+ Logger.println(` to: ${hook.notified[0]}`);
50
+ }
51
+ });
52
+ }
53
+ }
39
54
  }
40
55
 
41
56
  function getEmailNotificationTargets (notifTargets) {
@@ -2,13 +2,13 @@
2
2
 
3
3
  const openPage = require('open');
4
4
 
5
- const AppConfig = require('../models/app_configuration.js');
5
+ const Application = require('../models/application.js');
6
6
  const Domain = require('../models/domain.js');
7
7
  const Logger = require('../logger.js');
8
8
 
9
9
  async function open (params) {
10
- const { alias } = params.options;
11
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
10
+ const { alias, app: appIdOrName } = params.options;
11
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
12
12
 
13
13
  const vhost = await Domain.getBest(appId, ownerId);
14
14
  const url = 'https://' + vhost.fqdn;
@@ -5,15 +5,35 @@ const colors = require('colors/safe');
5
5
  const Logger = require('../logger.js');
6
6
  const User = require('../models/user.js');
7
7
 
8
- async function profile () {
9
- const { id, name, email, preferredMFA } = await User.getCurrent();
10
- const has2FA = (preferredMFA != null && preferredMFA !== 'NONE') ? 'yes' : 'no';
11
- const formattedName = name || colors.red.bold('[not specified]');
12
- Logger.println('You\'re currently logged in as:');
13
- Logger.println('User id ' + id);
14
- Logger.println('Name ' + formattedName);
15
- Logger.println('Email ' + email);
16
- Logger.println('Two factor auth ' + has2FA);
8
+ async function profile (params) {
9
+ const { format } = params.options;
10
+
11
+ const user = await User.getCurrent();
12
+
13
+ const formattedUser = {
14
+ id: user.id,
15
+ email: user.email,
16
+ name: user.name,
17
+ avatar: user.avatar,
18
+ creationDate: new Date(user.creationDate),
19
+ lang: user.lang,
20
+ has2FA: (user.preferredMFA != null && user.preferredMFA !== 'NONE'),
21
+ };
22
+
23
+ switch (format) {
24
+ case 'json': {
25
+ Logger.printJson(formattedUser);
26
+ break;
27
+ }
28
+ case 'human':
29
+ default: {
30
+ Logger.println('You\'re currently logged in as:');
31
+ Logger.println(`User id ${formattedUser.id}`);
32
+ Logger.println(`Name ${formattedUser.name ?? colors.red.bold('[not specified]')}`);
33
+ Logger.println(`Email ${formattedUser.email}`);
34
+ Logger.println(`Two factor auth ${formattedUser.has2FA ? 'yes' : 'no'}`);
35
+ }
36
+ }
17
37
  };
18
38
 
19
39
  module.exports = { profile };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const AppConfig = require('../models/app_configuration.js');
3
+ const Application = require('../models/application.js');
4
4
  const Logger = require('../logger.js');
5
5
  const variables = require('../models/variables.js');
6
6
  const { sendToApi } = require('../models/send-to-api.js');
@@ -8,27 +8,38 @@ const { toNameEqualsValueString, validateName } = require('@clevercloud/client/c
8
8
  const application = require('@clevercloud/client/cjs/api/v2/application.js');
9
9
 
10
10
  async function list (params) {
11
- const { alias } = params.options;
12
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
11
+ const { alias, app: appIdOrName, format } = params.options;
12
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
13
13
 
14
14
  const publishedConfigs = await application.getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
15
- const pairs = Object.entries(publishedConfigs)
16
- .map(([name, value]) => ({ name, value }));
17
-
18
- Logger.println('# Published configs');
19
- Logger.println(toNameEqualsValueString(pairs));
20
- };
15
+ const pairs = Object.entries(publishedConfigs).map(([name, value]) => ({ name, value }));
16
+
17
+ switch (format) {
18
+ case 'json': {
19
+ Logger.printJson(pairs);
20
+ break;
21
+ }
22
+ case 'shell':
23
+ Logger.println(toNameEqualsValueString(pairs, { addExports: true }));
24
+ break;
25
+ case 'human':
26
+ default: {
27
+ Logger.println('# Published configs');
28
+ Logger.println(toNameEqualsValueString(pairs, { addExports: false }));
29
+ }
30
+ }
31
+ }
21
32
 
22
33
  async function set (params) {
23
34
  const [varName, varValue] = params.args;
24
- const { alias } = params.options;
35
+ const { alias, app: appIdOrName } = params.options;
25
36
 
26
37
  const nameIsValid = validateName(varName);
27
38
  if (!nameIsValid) {
28
39
  throw new Error(`Published config name ${varName} is invalid`);
29
40
  }
30
41
 
31
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
42
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
32
43
 
33
44
  const publishedConfigs = await application.getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
34
45
  publishedConfigs[varName] = varValue;
@@ -39,8 +50,8 @@ async function set (params) {
39
50
 
40
51
  async function rm (params) {
41
52
  const [varName] = params.args;
42
- const { alias } = params.options;
43
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
53
+ const { alias, app: appIdOrName } = params.options;
54
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
44
55
 
45
56
  const publishedConfigs = await application.getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
46
57
  delete publishedConfigs[varName];
@@ -50,9 +61,9 @@ async function rm (params) {
50
61
  };
51
62
 
52
63
  async function importEnv (params) {
53
- const { alias, json } = params.options;
64
+ const { alias, app: appIdOrName, json } = params.options;
54
65
  const format = json ? 'json' : 'name-equals-value';
55
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
66
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
56
67
 
57
68
  const publishedConfigs = await variables.readVariablesFromStdin(format);
58
69
  await application.updateAllExposedEnvVars({ id: ownerId, appId }, publishedConfigs).then(sendToApi);
@@ -2,26 +2,33 @@
2
2
 
3
3
  const colors = require('colors/safe');
4
4
 
5
- const AppConfig = require('../models/app_configuration.js');
6
5
  const Application = require('../models/application.js');
7
6
  const git = require('../models/git.js');
8
7
  const Log = require('../models/log-v4.js');
9
8
  const Logger = require('../logger.js');
9
+ const ExitStrategy = require('../models/exit-strategy-option.js');
10
10
 
11
11
  // Once the API call to redeploy() has been triggerred successfully,
12
12
  // the rest (waiting for deployment state to evolve and displaying logs) is done with auto retry (resilient to network pb)
13
13
  async function restart (params) {
14
- const { alias, quiet, commit, 'without-cache': withoutCache, follow } = params.options;
14
+ const { alias, app: appIdOrName, quiet, commit, 'without-cache': withoutCache, follow, 'exit-on': exitOnDeploy } = params.options;
15
15
 
16
- const { ownerId, appId, name: appName } = await AppConfig.getAppDetails({ alias });
16
+ const exitStrategy = ExitStrategy.get(follow, exitOnDeploy);
17
+
18
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
17
19
  const fullCommitId = await git.resolveFullCommitId(commit);
18
20
  const app = await Application.get(ownerId, appId);
21
+
22
+ if (app == null) {
23
+ throw new Error('The application doesn\'t exist');
24
+ }
25
+
19
26
  const remoteCommitId = app.commitId;
20
27
 
21
28
  const commitId = fullCommitId || remoteCommitId;
22
29
  if (commitId != null) {
23
30
  const cacheSuffix = withoutCache ? ' without using cache' : '';
24
- Logger.println(`Restarting ${appName} on commit ${colors.green(commitId)}${cacheSuffix}`);
31
+ Logger.println(`Restarting ${app.name} on commit ${colors.green(commitId)}${cacheSuffix}`);
25
32
  }
26
33
 
27
34
  // This should be handled by the API when a deployment ID is set but we'll do this for now
@@ -34,8 +41,8 @@ async function restart (params) {
34
41
  appId,
35
42
  deploymentId: redeploy.deploymentId,
36
43
  quiet,
37
- follow,
38
44
  redeployDate,
45
+ exitStrategy,
39
46
  });
40
47
  }
41
48
 
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const AppConfig = require('../models/app_configuration.js');
4
3
  const Application = require('../models/application.js');
5
4
  const Logger = require('../logger.js');
6
5
 
@@ -45,9 +44,9 @@ function validateOptions (options) {
45
44
  }
46
45
 
47
46
  async function scale (params) {
48
- const { alias } = params.options;
47
+ const { alias, app: appIdOrName } = params.options;
49
48
  const { minFlavor, maxFlavor, minInstances, maxInstances, buildFlavor } = validateOptions(params.options);
50
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
49
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
51
50
 
52
51
  await Application.setScalability(appId, ownerId, {
53
52
  minFlavor,
@@ -1,62 +1,89 @@
1
1
  'use strict';
2
2
 
3
3
  const Addon = require('../models/addon.js');
4
- const AppConfig = require('../models/app_configuration.js');
5
4
  const Application = require('../models/application.js');
6
5
  const Logger = require('../logger.js');
7
6
 
8
7
  async function list (params) {
9
- const { alias, 'show-all': showAll, 'only-apps': onlyApps, 'only-addons': onlyAddons } = params.options;
8
+ const { alias, app: appIdOrName, 'show-all': showAll, 'only-apps': onlyApps, 'only-addons': onlyAddons, format } = params.options;
10
9
  if (onlyApps && onlyAddons) {
11
10
  throw new Error('--only-apps and --only-addons are mutually exclusive');
12
11
  }
13
12
 
14
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
13
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
14
+
15
+ const formattedServices = {};
15
16
 
16
17
  if (!onlyAddons) {
17
18
  const apps = await Application.listDependencies(ownerId, appId, showAll);
18
- Logger.println('Applications:');
19
- apps.forEach(({ isLinked, name }) => Logger.println(`${isLinked ? '*' : ' '} ${name}`));
19
+ formattedServices.applications = apps.map((app) => ({
20
+ id: app.id,
21
+ name: app.name,
22
+ isLinked: app.isLinked,
23
+ }));
20
24
  }
21
25
 
22
26
  if (!onlyApps) {
23
27
  const addons = await Addon.list(ownerId, appId, showAll);
24
- Logger.println('Addons:');
25
- addons.forEach(({ isLinked, name, realId }) => Logger.println(`${isLinked ? '*' : ' '} ${name} (${realId})`));
28
+ formattedServices.addons = addons.map((addon) => ({
29
+ id: addon.id,
30
+ realId: addon.realId,
31
+ name: addon.name,
32
+ isLinked: addon.isLinked,
33
+ }));
34
+ }
35
+
36
+ switch (format) {
37
+ case 'json': {
38
+ Logger.printJson(formattedServices);
39
+ break;
40
+ }
41
+ case 'human':
42
+ default: {
43
+ if (formattedServices.applications) {
44
+ Logger.println('Applications:');
45
+ formattedServices.applications.forEach(({ isLinked, name }) => Logger.println(`${isLinked ? '*' : ' '} ${name}`));
46
+ }
47
+
48
+ if (formattedServices.addons) {
49
+ Logger.println('Addons:');
50
+ formattedServices.addons.forEach(({ isLinked, name, realId }) => Logger.println(`${isLinked ? '*' : ' '} ${name} (${realId})`));
51
+ }
52
+ }
26
53
  }
27
54
  }
28
55
 
29
56
  async function linkApp (params) {
30
- const { alias } = params.options;
57
+ const { alias, app: appIdOrName } = params.options;
31
58
  const [dependency] = params.args;
32
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
59
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
33
60
 
34
61
  await Application.link(ownerId, appId, dependency);
35
62
  Logger.println(`App ${dependency.app_id || dependency.app_name} successfully linked`);
36
63
  }
37
64
 
38
65
  async function unlinkApp (params) {
39
- const { alias } = params.options;
66
+ const { alias, app: appIdOrName } = params.options;
40
67
  const [dependency] = params.args;
41
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
68
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
42
69
 
43
70
  await Application.unlink(ownerId, appId, dependency);
44
71
  Logger.println(`App ${dependency.app_id || dependency.app_name} successfully unlinked`);
45
72
  }
46
73
 
47
74
  async function linkAddon (params) {
48
- const { alias } = params.options;
75
+ const { alias, app: appIdOrName } = params.options;
49
76
  const [addon] = params.args;
50
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
77
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
51
78
 
52
79
  await Addon.link(ownerId, appId, addon);
53
80
  Logger.println(`Addon ${addon.addon_id || addon.addon_name} successfully linked`);
54
81
  }
55
82
 
56
83
  async function unlinkAddon (params) {
57
- const { alias } = params.options;
84
+ const { alias, app: appIdOrName } = params.options;
58
85
  const [addon] = params.args;
59
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
86
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
60
87
 
61
88
  await Addon.unlink(ownerId, appId, addon);
62
89
  Logger.println(`Addon ${addon.addon_id || addon.addon_name} successfully unlinked`);
@@ -2,13 +2,13 @@
2
2
 
3
3
  const { spawn } = require('child_process');
4
4
 
5
- const AppConfig = require('../models/app_configuration.js');
5
+ const Application = require('../models/application.js');
6
6
  const { conf } = require('../models/configuration.js');
7
7
 
8
8
  async function ssh (params) {
9
- const { alias, 'identity-file': identityFile } = params.options;
9
+ const { alias, app: appIdOrName, 'identity-file': identityFile } = params.options;
10
10
 
11
- const { appId } = await AppConfig.getAppDetails({ alias });
11
+ const { appId } = await Application.resolveId(appIdOrName, alias);
12
12
  const sshParams = ['-t', conf.SSH_GATEWAY, appId];
13
13
  if (identityFile != null) {
14
14
  sshParams.push('-i', identityFile);
@@ -3,22 +3,49 @@
3
3
  const _ = require('lodash');
4
4
  const colors = require('colors/safe');
5
5
 
6
- const AppConfig = require('../models/app_configuration.js');
6
+ const Application = require('../models/application.js');
7
7
  const Logger = require('../logger.js');
8
8
 
9
9
  const { get: getApplication, getAllInstances } = require('@clevercloud/client/cjs/api/v2/application.js');
10
10
  const { sendToApi } = require('../models/send-to-api.js');
11
11
 
12
- function displayGroupInfo (instances, commit) {
13
- return `(${displayFlavors(instances)}, Commit: ${commit || 'N/A'})`;
12
+ async function status (params) {
13
+ const { alias, app: appIdOrName, format } = params.options;
14
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
15
+
16
+ const instances = await getAllInstances({ id: ownerId, appId }).then(sendToApi);
17
+ const app = await getApplication({ id: ownerId, appId }).then(sendToApi);
18
+
19
+ const status = computeStatus(instances, app);
20
+
21
+ switch (format) {
22
+ case 'json': {
23
+ Logger.printJson(status);
24
+ break;
25
+ }
26
+ case 'human':
27
+ default: {
28
+ const statusMessage = status.status === 'running'
29
+ ? `${colors.bold.green('running')} ${displayInstances(status.instances, status.commit)}`
30
+ : colors.bold.red('stopped');
31
+
32
+ Logger.println(`${status.name}: ${statusMessage}`);
33
+ Logger.println(`Executed as: ${colors.bold(status.lifetime)}`);
34
+ if (status.deploymentInProgress) {
35
+ Logger.println(`Deployment in progress ${displayInstances(status.deploymentInProgress.instances, status.deploymentInProgress.commit)}`);
36
+ }
37
+ Logger.println();
38
+ Logger.println('Scalability:');
39
+ Logger.println(` Auto scalability: ${status.scalability.enabled ? colors.green('enabled') : colors.red('disabled')}`);
40
+ Logger.println(` Scalers: ${colors.bold(formatScalability(status.scalability.horizontal))}`);
41
+ Logger.println(` Sizes: ${colors.bold(formatScalability(status.scalability.vertical))}`);
42
+ Logger.println(` Dedicated build: ${status.separateBuild ? colors.bold(status.buildFlavor) : colors.red('disabled')}`);
43
+ }
44
+ }
14
45
  }
15
46
 
16
- function displayFlavors (instances) {
17
- return _(instances)
18
- .groupBy((i) => i.flavor.name)
19
- .map((instances, flavorName) => `${instances.length}*${flavorName}`)
20
- .value()
21
- .join(', ');
47
+ function displayInstances (instances, commit) {
48
+ return `(${instances.map((instance) => `${instance.count}*${instance.flavor}`)}, Commit: ${commit || 'N/A'})`;
22
49
  }
23
50
 
24
51
  function computeStatus (instances, app) {
@@ -30,50 +57,49 @@ function computeStatus (instances, app) {
30
57
  const isDeploying = !_.isEmpty(deployingInstances);
31
58
  const deployingCommit = _(deployingInstances).map('commit').head();
32
59
 
33
- const statusMessage = isUp
34
- ? `${colors.bold.green('running')} ${displayGroupInfo(upInstances, upCommit)}`
35
- : colors.bold.red('stopped');
36
-
37
- const statusLine = `${app.name}: ${statusMessage}`;
38
- const taskLine = `Executed as: ${colors.bold(app.instance.lifetime)}`;
39
- const deploymentLine = isDeploying
40
- ? `Deployment in progress ${displayGroupInfo(deployingInstances, deployingCommit)}`
41
- : '';
42
-
43
- return [statusLine, taskLine, deploymentLine].join('\n');
44
- }
45
-
46
- function displayScalability (app) {
47
-
48
60
  const { minFlavor, maxFlavor, minInstances, maxInstances } = app.instance;
49
61
 
50
- const vertical = (minFlavor.name === maxFlavor.name)
51
- ? minFlavor.name
52
- : `${minFlavor.name} to ${maxFlavor.name}`;
53
-
54
- const horizontal = (minInstances === maxInstances)
55
- ? minInstances
56
- : `${minInstances} to ${maxInstances}`;
57
-
58
- const enabled = (minFlavor.name !== maxFlavor.name)
62
+ const scalabilityEnabled = (minFlavor.name !== maxFlavor.name)
59
63
  || (minInstances !== maxInstances);
60
64
 
61
- return `Scalability:
62
- Auto scalability: ${enabled ? colors.green('enabled') : colors.red('disabled')}
63
- Scalers: ${colors.bold(horizontal)}
64
- Sizes: ${colors.bold(vertical)}
65
- Dedicated build: ${app.separateBuild ? colors.bold(app.buildFlavor.name) : colors.red('disabled')}`;
65
+ const status = {
66
+ id: app.id,
67
+ name: app.name,
68
+ lifetime: app.instance.lifetime,
69
+ status: isUp ? 'running' : 'stopped',
70
+ commit: upCommit,
71
+ instances: groupInstances(upInstances),
72
+ scalability: {
73
+ enabled: scalabilityEnabled,
74
+ vertical: { min: minFlavor.name, max: maxFlavor.name },
75
+ horizontal: { min: minInstances, max: maxInstances },
76
+ },
77
+ separateBuild: app.separateBuild,
78
+ buildFlavor: app.buildFlavor.name,
79
+ };
80
+
81
+ if (isDeploying) {
82
+ status.deploymentInProgress = {
83
+ commit: deployingCommit,
84
+ instances: groupInstances(deployingInstances),
85
+ };
86
+ }
87
+
88
+ return status;
66
89
  }
67
90
 
68
- async function status (params) {
69
- const { alias } = params.options;
70
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
71
-
72
- const instances = await getAllInstances({ id: ownerId, appId }).then(sendToApi);
73
- const app = await getApplication({ id: ownerId, appId }).then(sendToApi);
91
+ function formatScalability ({ min, max }) {
92
+ return (min === max) ? min : `${min} to ${max}`;
93
+ }
74
94
 
75
- Logger.println(computeStatus(instances, app));
76
- Logger.println(displayScalability(app));
95
+ function groupInstances (instances) {
96
+ return _(instances)
97
+ .groupBy((i) => i.flavor.name)
98
+ .map((instances, flavorName) => ({
99
+ flavor: flavorName,
100
+ count: instances.length,
101
+ }))
102
+ .value();
77
103
  }
78
104
 
79
105
  module.exports = { status };
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- const AppConfig = require('../models/app_configuration.js');
3
+ const Application = require('../models/application.js');
4
4
  const application = require('@clevercloud/client/cjs/api/v2/application.js');
5
5
  const Logger = require('../logger.js');
6
6
  const { sendToApi } = require('../models/send-to-api.js');
7
7
 
8
8
  async function stop (params) {
9
- const { alias } = params.options;
10
- const { ownerId, appId } = await AppConfig.getAppDetails({ alias });
9
+ const { alias, app: appIdOrName } = params.options;
10
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
11
11
 
12
12
  await application.undeploy({ id: ownerId, appId }).then(sendToApi);
13
13
  Logger.println('App successfully stopped!');