@optimizely/ocp-cli 1.0.0-beta.2
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/LICENSE +201 -0
- package/README.md +18 -0
- package/bin/opti.js +3 -0
- package/dist/commands/accounts/Whoami.d.ts +3 -0
- package/dist/commands/accounts/Whoami.js +34 -0
- package/dist/commands/accounts/Whoami.js.map +1 -0
- package/dist/commands/accounts/Whois.d.ts +6 -0
- package/dist/commands/accounts/Whois.js +65 -0
- package/dist/commands/accounts/Whois.js.map +1 -0
- package/dist/commands/app/BaseBuildCommand.d.ts +23 -0
- package/dist/commands/app/BaseBuildCommand.js +227 -0
- package/dist/commands/app/BaseBuildCommand.js.map +1 -0
- package/dist/commands/app/Init.d.ts +20 -0
- package/dist/commands/app/Init.js +285 -0
- package/dist/commands/app/Init.js.map +1 -0
- package/dist/commands/app/Logs.d.ts +19 -0
- package/dist/commands/app/Logs.js +230 -0
- package/dist/commands/app/Logs.js.map +1 -0
- package/dist/commands/app/Package.d.ts +4 -0
- package/dist/commands/app/Package.js +51 -0
- package/dist/commands/app/Package.js.map +1 -0
- package/dist/commands/app/Prepare.d.ts +8 -0
- package/dist/commands/app/Prepare.js +112 -0
- package/dist/commands/app/Prepare.js.map +1 -0
- package/dist/commands/app/Register.d.ts +7 -0
- package/dist/commands/app/Register.js +58 -0
- package/dist/commands/app/Register.js.map +1 -0
- package/dist/commands/app/Validate.d.ts +4 -0
- package/dist/commands/app/Validate.js +27 -0
- package/dist/commands/app/Validate.js.map +1 -0
- package/dist/commands/availability/List.d.ts +4 -0
- package/dist/commands/availability/List.js +47 -0
- package/dist/commands/availability/List.js.map +1 -0
- package/dist/commands/directory/Info.d.ts +7 -0
- package/dist/commands/directory/Info.js +92 -0
- package/dist/commands/directory/Info.js.map +1 -0
- package/dist/commands/directory/Install.d.ts +6 -0
- package/dist/commands/directory/Install.js +54 -0
- package/dist/commands/directory/Install.js.map +1 -0
- package/dist/commands/directory/List.d.ts +8 -0
- package/dist/commands/directory/List.js +102 -0
- package/dist/commands/directory/List.js.map +1 -0
- package/dist/commands/directory/ListFunctions.d.ts +7 -0
- package/dist/commands/directory/ListFunctions.js +77 -0
- package/dist/commands/directory/ListFunctions.js.map +1 -0
- package/dist/commands/directory/ListGlobalFunctions.d.ts +6 -0
- package/dist/commands/directory/ListGlobalFunctions.js +72 -0
- package/dist/commands/directory/ListGlobalFunctions.js.map +1 -0
- package/dist/commands/directory/ListInstalls.d.ts +8 -0
- package/dist/commands/directory/ListInstalls.js +81 -0
- package/dist/commands/directory/ListInstalls.js.map +1 -0
- package/dist/commands/directory/Publish.d.ts +8 -0
- package/dist/commands/directory/Publish.js +180 -0
- package/dist/commands/directory/Publish.js.map +1 -0
- package/dist/commands/directory/Status.d.ts +5 -0
- package/dist/commands/directory/Status.js +60 -0
- package/dist/commands/directory/Status.js.map +1 -0
- package/dist/commands/directory/Uninstall.d.ts +6 -0
- package/dist/commands/directory/Uninstall.js +50 -0
- package/dist/commands/directory/Uninstall.js.map +1 -0
- package/dist/commands/directory/Unpublish.d.ts +10 -0
- package/dist/commands/directory/Unpublish.js +181 -0
- package/dist/commands/directory/Unpublish.js.map +1 -0
- package/dist/commands/directory/Uprade.d.ts +8 -0
- package/dist/commands/directory/Uprade.js +100 -0
- package/dist/commands/directory/Uprade.js.map +1 -0
- package/dist/commands/env/GetEnvironment.d.ts +3 -0
- package/dist/commands/env/GetEnvironment.js +28 -0
- package/dist/commands/env/GetEnvironment.js.map +1 -0
- package/dist/commands/env/SetEnvironment.d.ts +4 -0
- package/dist/commands/env/SetEnvironment.js +63 -0
- package/dist/commands/env/SetEnvironment.js.map +1 -0
- package/dist/commands/jobs/List.d.ts +21 -0
- package/dist/commands/jobs/List.js +268 -0
- package/dist/commands/jobs/List.js.map +1 -0
- package/dist/commands/jobs/RuntimeStatus.d.ts +5 -0
- package/dist/commands/jobs/RuntimeStatus.js +65 -0
- package/dist/commands/jobs/RuntimeStatus.js.map +1 -0
- package/dist/commands/jobs/Terminate.d.ts +5 -0
- package/dist/commands/jobs/Terminate.js +45 -0
- package/dist/commands/jobs/Terminate.js.map +1 -0
- package/dist/commands/jobs/Trigger.d.ts +8 -0
- package/dist/commands/jobs/Trigger.js +58 -0
- package/dist/commands/jobs/Trigger.js.map +1 -0
- package/dist/commands/review/List.d.ts +5 -0
- package/dist/commands/review/List.js +81 -0
- package/dist/commands/review/List.js.map +1 -0
- package/dist/commands/review/Open.d.ts +4 -0
- package/dist/commands/review/Open.js +42 -0
- package/dist/commands/review/Open.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/AppContext.d.ts +9 -0
- package/dist/lib/AppContext.js +43 -0
- package/dist/lib/AppContext.js.map +1 -0
- package/dist/lib/AppPackager.d.ts +8 -0
- package/dist/lib/AppPackager.js +40 -0
- package/dist/lib/AppPackager.js.map +1 -0
- package/dist/lib/AppUpdater.d.ts +9 -0
- package/dist/lib/AppUpdater.js +155 -0
- package/dist/lib/AppUpdater.js.map +1 -0
- package/dist/lib/AppUploader.d.ts +8 -0
- package/dist/lib/AppUploader.js +36 -0
- package/dist/lib/AppUploader.js.map +1 -0
- package/dist/lib/Config.d.ts +15 -0
- package/dist/lib/Config.js +47 -0
- package/dist/lib/Config.js.map +1 -0
- package/dist/lib/EnvironmentalOutput.d.ts +1 -0
- package/dist/lib/EnvironmentalOutput.js +21 -0
- package/dist/lib/EnvironmentalOutput.js.map +1 -0
- package/dist/lib/Moria.d.ts +51 -0
- package/dist/lib/Moria.js +30 -0
- package/dist/lib/Moria.js.map +1 -0
- package/dist/lib/MoriaApi.d.ts +22 -0
- package/dist/lib/MoriaApi.js +75 -0
- package/dist/lib/MoriaApi.js.map +1 -0
- package/dist/lib/Rivendell.d.ts +351 -0
- package/dist/lib/Rivendell.js +328 -0
- package/dist/lib/Rivendell.js.map +1 -0
- package/dist/lib/RivendellApi.d.ts +22 -0
- package/dist/lib/RivendellApi.js +90 -0
- package/dist/lib/RivendellApi.js.map +1 -0
- package/dist/lib/Shards.d.ts +3 -0
- package/dist/lib/Shards.js +34 -0
- package/dist/lib/Shards.js.map +1 -0
- package/dist/lib/StringUtils.d.ts +1 -0
- package/dist/lib/StringUtils.js +9 -0
- package/dist/lib/StringUtils.js.map +1 -0
- package/dist/lib/TeminalPassthru.d.ts +5 -0
- package/dist/lib/TeminalPassthru.js +12 -0
- package/dist/lib/TeminalPassthru.js.map +1 -0
- package/dist/lib/TerminalConfirm.d.ts +3 -0
- package/dist/lib/TerminalConfirm.js +26 -0
- package/dist/lib/TerminalConfirm.js.map +1 -0
- package/dist/lib/TerminalInput.d.ts +32 -0
- package/dist/lib/TerminalInput.js +207 -0
- package/dist/lib/TerminalInput.js.map +1 -0
- package/dist/lib/TerminalMenu.d.ts +34 -0
- package/dist/lib/TerminalMenu.js +186 -0
- package/dist/lib/TerminalMenu.js.map +1 -0
- package/dist/lib/TerminalOutput.d.ts +5 -0
- package/dist/lib/TerminalOutput.js +12 -0
- package/dist/lib/TerminalOutput.js.map +1 -0
- package/dist/lib/TerminalSpinner.d.ts +15 -0
- package/dist/lib/TerminalSpinner.js +71 -0
- package/dist/lib/TerminalSpinner.js.map +1 -0
- package/dist/lib/build.d.ts +5 -0
- package/dist/lib/build.js +35 -0
- package/dist/lib/build.js.map +1 -0
- package/dist/lib/checkForUpdate.d.ts +2 -0
- package/dist/lib/checkForUpdate.js +58 -0
- package/dist/lib/checkForUpdate.js.map +1 -0
- package/dist/lib/dev/app.d.ts +8 -0
- package/dist/lib/dev/app.js +53 -0
- package/dist/lib/dev/app.js.map +1 -0
- package/dist/lib/dev/index.d.ts +1 -0
- package/dist/lib/dev/index.js +14 -0
- package/dist/lib/dev/index.js.map +1 -0
- package/dist/lib/dev/logger.d.ts +15 -0
- package/dist/lib/dev/logger.js +58 -0
- package/dist/lib/dev/logger.js.map +1 -0
- package/dist/lib/die.d.ts +5 -0
- package/dist/lib/die.js +14 -0
- package/dist/lib/die.js.map +1 -0
- package/dist/lib/directoryExists.d.ts +1 -0
- package/dist/lib/directoryExists.js +9 -0
- package/dist/lib/directoryExists.js.map +1 -0
- package/dist/lib/formatBuildState.d.ts +2 -0
- package/dist/lib/formatBuildState.js +23 -0
- package/dist/lib/formatBuildState.js.map +1 -0
- package/dist/lib/formatError.d.ts +1 -0
- package/dist/lib/formatError.js +45 -0
- package/dist/lib/formatError.js.map +1 -0
- package/dist/lib/formatJobStatus.d.ts +3 -0
- package/dist/lib/formatJobStatus.js +28 -0
- package/dist/lib/formatJobStatus.js.map +1 -0
- package/dist/lib/formatReviewStatus.d.ts +4 -0
- package/dist/lib/formatReviewStatus.js +28 -0
- package/dist/lib/formatReviewStatus.js.map +1 -0
- package/dist/lib/formatTimstamp.d.ts +1 -0
- package/dist/lib/formatTimstamp.js +25 -0
- package/dist/lib/formatTimstamp.js.map +1 -0
- package/dist/lib/formatVersionState.d.ts +2 -0
- package/dist/lib/formatVersionState.js +35 -0
- package/dist/lib/formatVersionState.js.map +1 -0
- package/dist/lib/gatherAppEnv.d.ts +3 -0
- package/dist/lib/gatherAppEnv.js +71 -0
- package/dist/lib/gatherAppEnv.js.map +1 -0
- package/dist/lib/handleInterrupt.d.ts +1 -0
- package/dist/lib/handleInterrupt.js +17 -0
- package/dist/lib/handleInterrupt.js.map +1 -0
- package/dist/lib/jobRuntime.d.ts +3 -0
- package/dist/lib/jobRuntime.js +16 -0
- package/dist/lib/jobRuntime.js.map +1 -0
- package/dist/lib/parseDate.d.ts +2 -0
- package/dist/lib/parseDate.js +26 -0
- package/dist/lib/parseDate.js.map +1 -0
- package/dist/lib/templating/TemplateRenderer.d.ts +13 -0
- package/dist/lib/templating/TemplateRenderer.js +62 -0
- package/dist/lib/templating/TemplateRenderer.js.map +1 -0
- package/dist/lib/templating/fetchTemplatesManifest.d.ts +1 -0
- package/dist/lib/templating/fetchTemplatesManifest.js +10 -0
- package/dist/lib/templating/fetchTemplatesManifest.js.map +1 -0
- package/dist/lib/templating/types.d.ts +27 -0
- package/dist/lib/templating/types.js +3 -0
- package/dist/lib/templating/types.js.map +1 -0
- package/dist/oo-cli.manifest.json +1142 -0
- package/dist/test/setup.d.ts +0 -0
- package/dist/test/setup.js +4 -0
- package/dist/test/setup.js.map +1 -0
- package/package.json +94 -0
- package/src/commands/accounts/Whoami.ts +19 -0
- package/src/commands/accounts/Whois.ts +51 -0
- package/src/commands/app/BaseBuildCommand.ts +266 -0
- package/src/commands/app/Init.ts +303 -0
- package/src/commands/app/Logs.ts +241 -0
- package/src/commands/app/Package.ts +39 -0
- package/src/commands/app/Prepare.ts +108 -0
- package/src/commands/app/Register.ts +41 -0
- package/src/commands/app/Validate.ts +13 -0
- package/src/commands/availability/List.ts +37 -0
- package/src/commands/directory/Info.ts +83 -0
- package/src/commands/directory/Install.ts +37 -0
- package/src/commands/directory/List.ts +96 -0
- package/src/commands/directory/ListFunctions.ts +60 -0
- package/src/commands/directory/ListGlobalFunctions.ts +54 -0
- package/src/commands/directory/ListInstalls.ts +73 -0
- package/src/commands/directory/Publish.ts +179 -0
- package/src/commands/directory/Status.ts +45 -0
- package/src/commands/directory/Uninstall.ts +32 -0
- package/src/commands/directory/Unpublish.ts +173 -0
- package/src/commands/directory/Uprade.ts +85 -0
- package/src/commands/env/GetEnvironment.ts +14 -0
- package/src/commands/env/SetEnvironment.ts +52 -0
- package/src/commands/jobs/List.ts +278 -0
- package/src/commands/jobs/RuntimeStatus.ts +49 -0
- package/src/commands/jobs/Terminate.ts +29 -0
- package/src/commands/jobs/Trigger.ts +41 -0
- package/src/commands/review/List.ts +76 -0
- package/src/commands/review/Open.ts +28 -0
- package/src/index.ts +15 -0
- package/src/lib/AppContext.ts +47 -0
- package/src/lib/AppPackager.ts +47 -0
- package/src/lib/AppUpdater.ts +177 -0
- package/src/lib/AppUploader.ts +39 -0
- package/src/lib/Config.ts +60 -0
- package/src/lib/EnvironmentalOutput.ts +18 -0
- package/src/lib/Moria.ts +66 -0
- package/src/lib/MoriaApi.ts +86 -0
- package/src/lib/Rivendell.ts +572 -0
- package/src/lib/RivendellApi.ts +99 -0
- package/src/lib/Shards.ts +37 -0
- package/src/lib/StringUtils.ts +4 -0
- package/src/lib/TeminalPassthru.ts +7 -0
- package/src/lib/TerminalConfirm.ts +27 -0
- package/src/lib/TerminalInput.ts +236 -0
- package/src/lib/TerminalMenu.ts +221 -0
- package/src/lib/TerminalOutput.ts +7 -0
- package/src/lib/TerminalSpinner.ts +76 -0
- package/src/lib/build.ts +36 -0
- package/src/lib/checkForUpdate.ts +63 -0
- package/src/lib/dev/app.ts +58 -0
- package/src/lib/dev/index.ts +1 -0
- package/src/lib/dev/logger.ts +77 -0
- package/src/lib/die.ts +10 -0
- package/src/lib/directoryExists.ts +5 -0
- package/src/lib/formatBuildState.ts +20 -0
- package/src/lib/formatError.ts +39 -0
- package/src/lib/formatJobStatus.ts +24 -0
- package/src/lib/formatReviewStatus.ts +27 -0
- package/src/lib/formatTimstamp.ts +21 -0
- package/src/lib/formatVersionState.ts +31 -0
- package/src/lib/gatherAppEnv.ts +75 -0
- package/src/lib/handleInterrupt.ts +13 -0
- package/src/lib/jobRuntime.ts +12 -0
- package/src/lib/parseDate.ts +21 -0
- package/src/lib/templating/TemplateRenderer.ts +65 -0
- package/src/lib/templating/fetchTemplatesManifest.ts +6 -0
- package/src/lib/templating/types.ts +30 -0
- package/src/test/setup.ts +2 -0
- package/src/types/columnify.d.ts +27 -0
- package/src/types/gitignore-parser.d.ts +11 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {command, help, namespace, option, optional, param} from 'oo-cli';
|
|
2
|
+
import {appContext} from '../../lib/AppContext';
|
|
3
|
+
import {die} from '../../lib/die';
|
|
4
|
+
import {formatReviewStatus} from '../../lib/formatReviewStatus';
|
|
5
|
+
import {formatVersionState} from '../../lib/formatVersionState';
|
|
6
|
+
import {formatError} from '../../lib/formatError';
|
|
7
|
+
import {Rivendell} from '../../lib/Rivendell';
|
|
8
|
+
import AppVersionState = Rivendell.AppVersionState;
|
|
9
|
+
import ReviewStatus = Rivendell.ReviewStatus;
|
|
10
|
+
|
|
11
|
+
@namespace('directory')
|
|
12
|
+
export class StatusCommand {
|
|
13
|
+
@param
|
|
14
|
+
@optional
|
|
15
|
+
@help('The App ID and version to look up')
|
|
16
|
+
public appId!: string;
|
|
17
|
+
|
|
18
|
+
@option('a')
|
|
19
|
+
@help('The availability zone that will be targeted (default: us)')
|
|
20
|
+
private availability: string = '';
|
|
21
|
+
|
|
22
|
+
@command
|
|
23
|
+
@help('Get the status of a particular app version')
|
|
24
|
+
public async status() {
|
|
25
|
+
const context = appContext(this.appId);
|
|
26
|
+
if (!context.appId || !context.version) {
|
|
27
|
+
return die('App ID and version are required');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const appVersion = await Rivendell.fetchAppVersion(context, this.availability);
|
|
32
|
+
console.log(`Version state: ${formatVersionState(appVersion.state as AppVersionState)}`);
|
|
33
|
+
|
|
34
|
+
if (appVersion.reviewStatus) {
|
|
35
|
+
const reviewStatus = appVersion.reviewStatus as ReviewStatus;
|
|
36
|
+
const appVersionState = appVersion.state as AppVersionState;
|
|
37
|
+
if (appVersionState === AppVersionState.PUBLISHED) {
|
|
38
|
+
console.log(`Review status: ${formatReviewStatus(reviewStatus, appVersionState)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} catch (e) {
|
|
42
|
+
die(formatError(e));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import {command, help, namespace, option, param} from 'oo-cli';
|
|
3
|
+
import {die} from '../../lib/die';
|
|
4
|
+
import {Rivendell} from '../../lib/Rivendell';
|
|
5
|
+
import {formatError} from '../../lib/formatError';
|
|
6
|
+
|
|
7
|
+
@namespace('directory')
|
|
8
|
+
export class UninstallCommand {
|
|
9
|
+
@param
|
|
10
|
+
@help('The App ID')
|
|
11
|
+
public appId!: string;
|
|
12
|
+
|
|
13
|
+
@param
|
|
14
|
+
@help('The Tracker ID of the account to install into')
|
|
15
|
+
public trackerId!: string;
|
|
16
|
+
|
|
17
|
+
@option('a')
|
|
18
|
+
@help('The availability zone that will be targeted (default: us)')
|
|
19
|
+
private availability: string = '';
|
|
20
|
+
|
|
21
|
+
@command
|
|
22
|
+
@help('Uninstall an app from an account')
|
|
23
|
+
public async uninstall() {
|
|
24
|
+
try {
|
|
25
|
+
const install = await Rivendell.fetchAppInstallation(this.appId, this.trackerId, this.availability);
|
|
26
|
+
await Rivendell.uninstall(install.id, this.availability);
|
|
27
|
+
console.log(chalk.green(`Uninstalled ${install.appId} from ${install.trackerId} (${this.availability || 'us'})`));
|
|
28
|
+
} catch (e) {
|
|
29
|
+
die(formatError(e));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import {command, flag, help, namespace, option, param} from 'oo-cli';
|
|
3
|
+
import {terminal} from 'terminal-kit';
|
|
4
|
+
import {AppContext} from '../../lib/AppContext';
|
|
5
|
+
import {die} from '../../lib/die';
|
|
6
|
+
import {formatVersionState} from '../../lib/formatVersionState';
|
|
7
|
+
import {handleInterrupt} from '../../lib/handleInterrupt';
|
|
8
|
+
import {TerminalSpinner} from '../../lib/TerminalSpinner';
|
|
9
|
+
import {Rivendell} from '../../lib/Rivendell';
|
|
10
|
+
import AppVersionState = Rivendell.AppVersionState;
|
|
11
|
+
import SortDirection = Rivendell.SortDirection;
|
|
12
|
+
import AppInstallation = Rivendell.AppInstallation;
|
|
13
|
+
import {formatError} from '../../lib/formatError';
|
|
14
|
+
import {applicableShards} from '../../lib/Shards';
|
|
15
|
+
import { AppManifest } from '@zaiusinc/app-sdk';
|
|
16
|
+
|
|
17
|
+
const UNPUBLISHABLE_STATES = [AppVersionState.RUNNING, AppVersionState.START_FAILED, AppVersionState.STOP_FAILED];
|
|
18
|
+
|
|
19
|
+
@namespace('directory')
|
|
20
|
+
export class UnpublishCommand {
|
|
21
|
+
@flag('f')
|
|
22
|
+
public force!: boolean;
|
|
23
|
+
|
|
24
|
+
@flag('no-progress')
|
|
25
|
+
public noProgress!: boolean;
|
|
26
|
+
|
|
27
|
+
@param
|
|
28
|
+
@help('The App ID and version (e.g. my_app@1.0.0)')
|
|
29
|
+
public appVersion!: string;
|
|
30
|
+
|
|
31
|
+
@option('a')
|
|
32
|
+
@help('The availability zone that will be targeted (default: us)')
|
|
33
|
+
public availability: string = '';
|
|
34
|
+
|
|
35
|
+
@command
|
|
36
|
+
@help('Unpublish an app version (uninstall everywhere and undeploy)')
|
|
37
|
+
public async unpublish() {
|
|
38
|
+
handleInterrupt();
|
|
39
|
+
|
|
40
|
+
if (!/[\w-]+@\d+\.\d+\.\d+(?:-\w+\.\d+)?/.test(this.appVersion)) {
|
|
41
|
+
die('appVersion is required in the format of app@1.0.0');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const [appId, version] = this.appVersion.split('@');
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const appVersion = await Rivendell.fetchAppVersion({appId, version}, 'us');
|
|
48
|
+
|
|
49
|
+
if (!UNPUBLISHABLE_STATES.includes(appVersion.state as AppVersionState)) {
|
|
50
|
+
throw new Error(`AppVersion must be in an unpublishable state. ` +
|
|
51
|
+
`Currently: ${formatVersionState(appVersion.state as AppVersionState)}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const manifest = JSON.parse(appVersion.manifestJson) as AppManifest;
|
|
55
|
+
const shards = await applicableShards(this.availability, manifest);
|
|
56
|
+
const errors: string[] = [];
|
|
57
|
+
|
|
58
|
+
for (const shard of shards) {
|
|
59
|
+
if (!(await this.uninstallEverywhere(appId, version, shard))) {
|
|
60
|
+
process.exit();
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
await Rivendell.unpublish(appId, version, shard);
|
|
64
|
+
console.log(chalk.green(`${this.appVersion} is being unpublished in ${shard}.`));
|
|
65
|
+
await this.watchForCompletion({appId, version}, shard);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
errors.push(`${formatError(error)} (${shard})`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (errors.length) {
|
|
72
|
+
console.log(chalk.red(errors.join('\n')));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
} catch (e) {
|
|
76
|
+
die(formatError(e));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private async uninstallEverywhere(appId: string, version: string, shard: string): Promise<boolean> {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
const criteria = {
|
|
83
|
+
appId,
|
|
84
|
+
version,
|
|
85
|
+
sorts: [{
|
|
86
|
+
field: 'trackerId', direction: SortDirection.DESC
|
|
87
|
+
}]
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
Rivendell.searchAppInstallations(criteria, shard)
|
|
91
|
+
.then(async (installations) => {
|
|
92
|
+
if (!installations.length) {
|
|
93
|
+
resolve(true);
|
|
94
|
+
} else {
|
|
95
|
+
const doIt = async () => {
|
|
96
|
+
try {
|
|
97
|
+
for (const appInstallation of installations) {
|
|
98
|
+
await this.uninstall(appInstallation, shard);
|
|
99
|
+
}
|
|
100
|
+
resolve(true);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
reject(e);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (this.force) {
|
|
107
|
+
await doIt();
|
|
108
|
+
} else {
|
|
109
|
+
const trackers = installations.map((installation) => installation.trackerId);
|
|
110
|
+
console.log(`${this.appVersion} is currently installed in ${trackers.length} account(s) in ${shard}:`);
|
|
111
|
+
console.log(` (${trackers.join(', ')})\n`);
|
|
112
|
+
console.log(chalk.red('Are you sure you want to uninstall from all these accounts? [y/n]'));
|
|
113
|
+
terminal.yesOrNo({yes: ['y', 'yes'], no: ['n', 'no']}, async (err, yes) => {
|
|
114
|
+
if (err) {
|
|
115
|
+
reject(err);
|
|
116
|
+
} else if (yes) {
|
|
117
|
+
await doIt();
|
|
118
|
+
} else {
|
|
119
|
+
console.log(`Aborted. No changes made to ${this.appVersion}.`);
|
|
120
|
+
resolve(false);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
.catch((e) => reject(e));
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private async uninstall(appInstallation: AppInstallation, shard: string) {
|
|
131
|
+
await Rivendell.uninstall(appInstallation.id, shard);
|
|
132
|
+
console.log(chalk.gray(`Uninstalled ${appInstallation.appId} from ${appInstallation.trackerId} in ${shard}`));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private async watchForCompletion(context: AppContext, shard: string) {
|
|
136
|
+
console.log(chalk.gray(`Watching for unpublish to complete in ${shard}... CTRL+C to stop checking.`));
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
const spinner = this.noProgress ? null : new TerminalSpinner().start('');
|
|
139
|
+
let attempts = 0;
|
|
140
|
+
const checkStatus = () => {
|
|
141
|
+
attempts++;
|
|
142
|
+
Rivendell.fetchAppVersion(context, shard)
|
|
143
|
+
.then((appVersion) => {
|
|
144
|
+
const state = appVersion.state as AppVersionState;
|
|
145
|
+
if (state === AppVersionState.STOPPED) {
|
|
146
|
+
if (spinner) {
|
|
147
|
+
spinner.stop();
|
|
148
|
+
}
|
|
149
|
+
clearInterval(interval);
|
|
150
|
+
console.log(chalk.green(`${context.appId}@${context.version} has been unpublished in ${shard}.`));
|
|
151
|
+
resolve();
|
|
152
|
+
} else {
|
|
153
|
+
if (attempts > 300) {
|
|
154
|
+
die('Timed out waiting for completion');
|
|
155
|
+
}
|
|
156
|
+
if (spinner) {
|
|
157
|
+
spinner.update(`Status: ${formatVersionState(state)}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
.catch((e) => {
|
|
162
|
+
clearInterval(interval);
|
|
163
|
+
if (spinner) {
|
|
164
|
+
spinner.stop();
|
|
165
|
+
}
|
|
166
|
+
reject(e);
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
const interval = setInterval(checkStatus, 2000);
|
|
170
|
+
checkStatus();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import {command, help, namespace, option, param, required} from 'oo-cli';
|
|
3
|
+
import {die} from '../../lib/die';
|
|
4
|
+
import {formatError} from '../../lib/formatError';
|
|
5
|
+
import {handleInterrupt} from '../../lib/handleInterrupt';
|
|
6
|
+
import {TerminalSpinner} from '../../lib/TerminalSpinner';
|
|
7
|
+
import {terminal} from 'terminal-kit';
|
|
8
|
+
import {Rivendell} from '../../lib/Rivendell';
|
|
9
|
+
|
|
10
|
+
@namespace('directory')
|
|
11
|
+
export class UpgradeCommand {
|
|
12
|
+
@param
|
|
13
|
+
@help('The App ID of the app to upgrade (e.g. my_app)')
|
|
14
|
+
public appId!: string;
|
|
15
|
+
|
|
16
|
+
@param
|
|
17
|
+
@help('The Tracker ID of the account to install into')
|
|
18
|
+
public trackerId!: string;
|
|
19
|
+
|
|
20
|
+
@option('v')
|
|
21
|
+
@required
|
|
22
|
+
@help('The desired version (i.e. 1.0.0)')
|
|
23
|
+
public toVersion!: string;
|
|
24
|
+
|
|
25
|
+
@option('a')
|
|
26
|
+
@help('The availability zone that will be targeted (default: us)')
|
|
27
|
+
private availability: string = '';
|
|
28
|
+
|
|
29
|
+
@command
|
|
30
|
+
@help('Upgrade the Install to a specific app version')
|
|
31
|
+
public async upgrade() {
|
|
32
|
+
handleInterrupt();
|
|
33
|
+
try {
|
|
34
|
+
const shard = this.availability || 'us';
|
|
35
|
+
const install = await Rivendell.fetchAppInstallation(this.appId, this.trackerId, shard);
|
|
36
|
+
if (install.version === this.toVersion) {
|
|
37
|
+
console.log(
|
|
38
|
+
chalk.yellow(`${this.trackerId} is currently at ${this.appId}@${install.version} in ${shard}.`)
|
|
39
|
+
);
|
|
40
|
+
} else {
|
|
41
|
+
await Rivendell.upgrade(install.id, this.appId, this.toVersion, shard);
|
|
42
|
+
console.log(`Upgrading ${this.appId} for ${this.trackerId} to ${this.toVersion} in ${shard}`);
|
|
43
|
+
await this.watchForCompletion(shard);
|
|
44
|
+
console.log(
|
|
45
|
+
chalk.green(`Upgraded ${this.trackerId} to ${this.appId}@${this.toVersion} in ${shard}.`));
|
|
46
|
+
terminal.removeAllListeners('key');
|
|
47
|
+
}
|
|
48
|
+
} catch (e) {
|
|
49
|
+
die(formatError(e));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private watchForCompletion(shard: string) {
|
|
54
|
+
console.log(chalk.gray(`Upgrade was scheduled in ${shard}, watching for completion... CTRL+C to stop checking.`));
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
let attempts = 0;
|
|
57
|
+
const spinner = new TerminalSpinner().start('');
|
|
58
|
+
const checkUpgrade = () => {
|
|
59
|
+
attempts++;
|
|
60
|
+
Rivendell.fetchAppInstallation(this.appId, this.trackerId, shard)
|
|
61
|
+
.then((install) => {
|
|
62
|
+
if (install.version === this.toVersion) {
|
|
63
|
+
clearInterval(interval);
|
|
64
|
+
spinner.stop();
|
|
65
|
+
resolve();
|
|
66
|
+
} else {
|
|
67
|
+
if (attempts > 300) {
|
|
68
|
+
clearInterval(interval);
|
|
69
|
+
spinner.stop();
|
|
70
|
+
die('Timed out waiting for completion');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
.catch((e) => {
|
|
75
|
+
clearInterval(interval);
|
|
76
|
+
spinner.stop();
|
|
77
|
+
reject(e);
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const interval = setInterval(checkUpgrade, 2000);
|
|
82
|
+
checkUpgrade();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import {command, help, namespace} from 'oo-cli';
|
|
3
|
+
import {getEnv, runtimeConfig} from '../../lib/Config';
|
|
4
|
+
|
|
5
|
+
@namespace('env')
|
|
6
|
+
export class GetEnvironmentCommand {
|
|
7
|
+
@command
|
|
8
|
+
@help('Get the current environment of the CLI')
|
|
9
|
+
public get() {
|
|
10
|
+
console.log(`Using ${chalk.yellow(getEnv())} environment\n`);
|
|
11
|
+
console.log('Configuration:');
|
|
12
|
+
console.log(chalk.gray(require('js-yaml').dump(runtimeConfig())));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import {command, help, namespace, param} from 'oo-cli';
|
|
6
|
+
import { getEnv } from '../../lib/Config';
|
|
7
|
+
|
|
8
|
+
const STAGING_ENV = {
|
|
9
|
+
'OCP_ENV': 'staging',
|
|
10
|
+
'RIVENDELL': 'https://rivendell.staging.zaius.com',
|
|
11
|
+
'AWS_REGION': 'us-east-1',
|
|
12
|
+
'UPLOAD_BUCKET': 'zaius-apps-staging'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const ENV_WHITELIST = ['staging', 'production'];
|
|
16
|
+
|
|
17
|
+
@namespace('env')
|
|
18
|
+
export class SetEnvironmentCommand {
|
|
19
|
+
@param
|
|
20
|
+
@help('The environment name')
|
|
21
|
+
public env!: string;
|
|
22
|
+
|
|
23
|
+
@command
|
|
24
|
+
@help('Set the current environment for the CLI')
|
|
25
|
+
public set() {
|
|
26
|
+
if (ENV_WHITELIST.includes(this.env)) {
|
|
27
|
+
const envPath = path.join(os.homedir(), '.ocp');
|
|
28
|
+
const envFile = path.join(envPath, `.env`);
|
|
29
|
+
const setEnvFile = `${envFile}.${this.env}`;
|
|
30
|
+
|
|
31
|
+
if (fs.existsSync(envFile)) {
|
|
32
|
+
fs.renameSync(envFile, `${envFile}.${getEnv()}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (fs.existsSync(setEnvFile)) {
|
|
36
|
+
fs.renameSync(setEnvFile, envFile);
|
|
37
|
+
} else if (this.env === 'staging') {
|
|
38
|
+
try {
|
|
39
|
+
fs.statSync(envPath);
|
|
40
|
+
} catch {
|
|
41
|
+
fs.mkdirSync(envPath);
|
|
42
|
+
}
|
|
43
|
+
fs.writeFileSync(envFile, Object.entries(STAGING_ENV).map((x) => x.join('=')).join('\n'));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(chalk.yellow(`using ${this.env} environment`));
|
|
47
|
+
} else {
|
|
48
|
+
console.log(chalk.red(
|
|
49
|
+
`Could not switch to environment ${this.env}. Permitted environments are ${ENV_WHITELIST}`));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import {command, help, multiple, namespace, option, param} from 'oo-cli';
|
|
3
|
+
import * as table from 'text-table';
|
|
4
|
+
import {isValidDateOrEpochOrDurationString, parseDate} from '../../lib/parseDate';
|
|
5
|
+
import {die} from '../../lib/die';
|
|
6
|
+
import {styledStringLength} from '../../lib/StringUtils';
|
|
7
|
+
import {Rivendell} from '../../lib/Rivendell';
|
|
8
|
+
import {formatError} from '../../lib/formatError';
|
|
9
|
+
import {default as parseDuration} from 'parse-duration';
|
|
10
|
+
import Job = Rivendell.Job;
|
|
11
|
+
import JobDefinition = Rivendell.JobDefinition;
|
|
12
|
+
import Sort = Rivendell.Sort;
|
|
13
|
+
import SortDirection = Rivendell.SortDirection;
|
|
14
|
+
import JobStatus = Rivendell.JobStatus;
|
|
15
|
+
import JobSearchCriteria = Rivendell.JobSearchCriteria;
|
|
16
|
+
import { formatJobStatus } from '../../lib/formatJobStatus';
|
|
17
|
+
import { jobRuntime } from '../../lib/jobRuntime';
|
|
18
|
+
|
|
19
|
+
interface Column {
|
|
20
|
+
long: string;
|
|
21
|
+
header: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface DisplayJob extends Job {
|
|
25
|
+
runtime?: number;
|
|
26
|
+
duration?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const COLUMN_DEFINITIONS: Column[] = [
|
|
30
|
+
{long: 'id', header: 'Job ID'},
|
|
31
|
+
{long: 'version', header: 'Version'},
|
|
32
|
+
{long: 'function', header: 'Job Function'},
|
|
33
|
+
{long: 'trackerId', header: 'Tracker ID'},
|
|
34
|
+
{long: 'trigger', header: 'Trigger'},
|
|
35
|
+
{long: 'status', header: 'Status'},
|
|
36
|
+
{long: 'error', header: 'Error'},
|
|
37
|
+
{long: 'createdAt', header: 'Created At'},
|
|
38
|
+
{long: 'triggeredAt', header: 'Triggered At'},
|
|
39
|
+
{long: 'scheduledAt', header: 'Scheduled At'},
|
|
40
|
+
{long: 'terminatedAt', header: 'Terminated At'},
|
|
41
|
+
{long: 'updatedAt', header: 'Updated At'},
|
|
42
|
+
{long: 'duration', header: 'Duration'}
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const SORT_COLUMNS: Column[] = COLUMN_DEFINITIONS
|
|
46
|
+
.filter((c) => !['appId', 'trigger', 'version'].includes(c.long));
|
|
47
|
+
|
|
48
|
+
const DEFAULT_DISPLAY_COLUMNS = COLUMN_DEFINITIONS
|
|
49
|
+
.filter(
|
|
50
|
+
(c) => ['id', 'version', 'function', 'trackerId', 'status', 'createdAt', 'updatedAt', 'duration'].includes(c.long)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
function columnLongString(columns: Column[]) {
|
|
54
|
+
return columns.map((x) => x.long).join(', ');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@namespace('jobs')
|
|
58
|
+
export class ListCommand {
|
|
59
|
+
|
|
60
|
+
@param
|
|
61
|
+
@help('Specific App ID to filter by')
|
|
62
|
+
private appId!: string;
|
|
63
|
+
|
|
64
|
+
@option
|
|
65
|
+
@help('Specific Versions to filter by')
|
|
66
|
+
@multiple
|
|
67
|
+
private version?: string[];
|
|
68
|
+
|
|
69
|
+
@option
|
|
70
|
+
@help('Specific Tracker IDs to filter by')
|
|
71
|
+
@multiple
|
|
72
|
+
private trackerId?: string[];
|
|
73
|
+
|
|
74
|
+
@option
|
|
75
|
+
@help('Specific Job Function to filter by')
|
|
76
|
+
@multiple
|
|
77
|
+
private function?: string[];
|
|
78
|
+
|
|
79
|
+
@option
|
|
80
|
+
@help(`Specific JobStatus to filter by. Possible values: ${Object.values(JobStatus).join(', ')}`)
|
|
81
|
+
@multiple
|
|
82
|
+
private status?: JobStatus[];
|
|
83
|
+
|
|
84
|
+
@option
|
|
85
|
+
@help('Show jobs that have been running longer than the given duration. (e.g. 5m = 5 minutes)')
|
|
86
|
+
private minDuration?: string;
|
|
87
|
+
|
|
88
|
+
@option
|
|
89
|
+
@help(`Column to sort the jobs by. Possible values: ${columnLongString(SORT_COLUMNS)}; Default: updatedAt`)
|
|
90
|
+
private sortBy: string = 'updatedAt';
|
|
91
|
+
|
|
92
|
+
@option
|
|
93
|
+
@help('Sort resulting jobs in ascending or descending order. Possible values: asc|desc. Default: desc')
|
|
94
|
+
private sortDirection: string = 'desc';
|
|
95
|
+
|
|
96
|
+
@option
|
|
97
|
+
@help('Number of jobs to list. Default: 50')
|
|
98
|
+
private limit?: number = 50;
|
|
99
|
+
|
|
100
|
+
@option
|
|
101
|
+
@help(`Columns to display. Possible values: ${columnLongString(COLUMN_DEFINITIONS)}. Default: ${columnLongString(DEFAULT_DISPLAY_COLUMNS)}`)
|
|
102
|
+
private columns: string = DEFAULT_DISPLAY_COLUMNS.map((c) => c.long).join(',');
|
|
103
|
+
|
|
104
|
+
@option
|
|
105
|
+
@help('A start time as an ISO string, an epoch timestamp, or relative string (i.e. "5m" for 5 minutes.) Default: 7d')
|
|
106
|
+
private from: string = '7d';
|
|
107
|
+
|
|
108
|
+
@option
|
|
109
|
+
@help('A end time as an ISO string, an epoch timestamp, or relative string (i.e. "5m" for 5 minutes)')
|
|
110
|
+
private to?: string;
|
|
111
|
+
|
|
112
|
+
@option('a')
|
|
113
|
+
@help('The availability zone that will be targeted (default: us)')
|
|
114
|
+
private availability: string = '';
|
|
115
|
+
|
|
116
|
+
@command
|
|
117
|
+
@help('List jobs')
|
|
118
|
+
public async list(): Promise<void> {
|
|
119
|
+
try {
|
|
120
|
+
const criteria: JobSearchCriteria = {
|
|
121
|
+
appId: this.appId,
|
|
122
|
+
};
|
|
123
|
+
if (this.version) {
|
|
124
|
+
criteria.versions = this.version;
|
|
125
|
+
}
|
|
126
|
+
if (this.trackerId) {
|
|
127
|
+
criteria.trackerIds = this.trackerId;
|
|
128
|
+
}
|
|
129
|
+
if (this.status) {
|
|
130
|
+
criteria.states = this.getJobStatus(this.status);
|
|
131
|
+
}
|
|
132
|
+
if (this.function) {
|
|
133
|
+
criteria.functions = this.function;
|
|
134
|
+
}
|
|
135
|
+
if (this.minDuration) {
|
|
136
|
+
const parsedDurationInMillis = parseDuration(this.minDuration, 'ms');
|
|
137
|
+
if (!parsedDurationInMillis) {
|
|
138
|
+
die(chalk.red('Invalid "--minDuration" input, should be a relative string (i.e. "5m" for 5 minutes.'));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
criteria.minDurationMillis = parsedDurationInMillis;
|
|
142
|
+
}
|
|
143
|
+
if (this.limit) {
|
|
144
|
+
criteria.limit = this.limit;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
criteria.sort = [this.getSort(this.sortBy, this.sortDirection)];
|
|
148
|
+
|
|
149
|
+
if (!isValidDateOrEpochOrDurationString(this.from)) {
|
|
150
|
+
die(chalk.red('Invalid "--from" input, should be an ISO string,' +
|
|
151
|
+
'an epoch timestamp, or relative string (i.e. "5m" for 5 minutes.'));
|
|
152
|
+
}
|
|
153
|
+
criteria.start = parseDate(this.from)?.valueOf();
|
|
154
|
+
|
|
155
|
+
if (this.to) {
|
|
156
|
+
if (!isValidDateOrEpochOrDurationString(this.to)) {
|
|
157
|
+
die(chalk.red('Invalid "--to" input, should be an ISO string,' +
|
|
158
|
+
'an epoch timestamp, or relative string (i.e. "5m" for 5 minutes.'));
|
|
159
|
+
}
|
|
160
|
+
criteria.end = parseDate(this.to)?.valueOf();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const jobs = await Rivendell.searchJobs(criteria, this.availability);
|
|
164
|
+
if (jobs.length === 0) {
|
|
165
|
+
die(chalk.yellow(`No jobs found since ${this.from} ago for given criteria. Try to change the criteria or extend the time range.`));
|
|
166
|
+
} else {
|
|
167
|
+
this.render(this.amendWithDuration(jobs));
|
|
168
|
+
}
|
|
169
|
+
} catch (e) {
|
|
170
|
+
die(formatError(e));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private getJobStatus(status: string[]): JobStatus[] {
|
|
175
|
+
return status.map((s) => {
|
|
176
|
+
const key = s.toUpperCase();
|
|
177
|
+
if (!JobStatus[key as JobStatus]) {
|
|
178
|
+
die(`${s} is not a valid JobStatus`);
|
|
179
|
+
}
|
|
180
|
+
return JobStatus[key as JobStatus];
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private getSort(sortBy: string, sortDirection: string | undefined) {
|
|
185
|
+
const sortColumn = SORT_COLUMNS.find((c) => c.long === sortBy);
|
|
186
|
+
if (!sortColumn) {
|
|
187
|
+
die(`"${sortBy}" not an available column for sorting`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const sort: Sort = {
|
|
191
|
+
field: sortColumn!.long
|
|
192
|
+
};
|
|
193
|
+
if (sortDirection) {
|
|
194
|
+
if (sortDirection.toUpperCase() === SortDirection.ASC) {
|
|
195
|
+
sort.direction = SortDirection.ASC;
|
|
196
|
+
} else if (sortDirection.toUpperCase() === SortDirection.DESC) {
|
|
197
|
+
sort.direction = SortDirection.DESC;
|
|
198
|
+
} else {
|
|
199
|
+
die(`"${sortDirection}" not valid for sorting`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return sort;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private amendWithDuration(jobs: Job[]) {
|
|
206
|
+
const jobsWithRuntime: DisplayJob[] = jobs.map((job) => {
|
|
207
|
+
const runtime = jobRuntime(job);
|
|
208
|
+
return {...job, runtime, duration: this.timeToDurationString(runtime)};
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return jobsWithRuntime;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private timeToDurationString(ms: number | undefined) {
|
|
215
|
+
if (!ms || ms <= 0) {
|
|
216
|
+
return '-';
|
|
217
|
+
}
|
|
218
|
+
const duration = ms / 1000;
|
|
219
|
+
const hours = Math.floor(duration / 3600);
|
|
220
|
+
const minutes = Math.floor((duration - (hours * 3600)) / 60);
|
|
221
|
+
const seconds = duration - (hours * 3600) - (minutes * 60);
|
|
222
|
+
const out = [];
|
|
223
|
+
if (hours > 0) {
|
|
224
|
+
out.push(`${hours}h`);
|
|
225
|
+
}
|
|
226
|
+
if (minutes > 0) {
|
|
227
|
+
out.push(`${minutes}m`);
|
|
228
|
+
}
|
|
229
|
+
if (seconds > 0) {
|
|
230
|
+
out.push(`${seconds}s`);
|
|
231
|
+
}
|
|
232
|
+
return out.join(' ');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private render(jobs: DisplayJob[]) {
|
|
236
|
+
const columns: Column[] = this.columns.split(',')
|
|
237
|
+
.map((c) => {
|
|
238
|
+
const col = COLUMN_DEFINITIONS.find((d) => d.long === c);
|
|
239
|
+
if (!col) {
|
|
240
|
+
die(`"${c}" is not a valid column name`);
|
|
241
|
+
}
|
|
242
|
+
return col!;
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const header = columns.map((item) => chalk.grey(item.header));
|
|
246
|
+
|
|
247
|
+
const rows = jobs.map((job: DisplayJob) => {
|
|
248
|
+
return columns.map((col) => {
|
|
249
|
+
if (job[col.long as keyof Job]) {
|
|
250
|
+
if (col.long === 'status') {
|
|
251
|
+
return formatJobStatus(job[col.long as keyof Job] as JobStatus);
|
|
252
|
+
}
|
|
253
|
+
return job[col.long as keyof Job];
|
|
254
|
+
} else if (job.definition[col.long as keyof JobDefinition]) {
|
|
255
|
+
return job.definition[col.long as keyof JobDefinition];
|
|
256
|
+
} else {
|
|
257
|
+
return '';
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const t = table(
|
|
263
|
+
[
|
|
264
|
+
header,
|
|
265
|
+
...rows
|
|
266
|
+
],
|
|
267
|
+
{
|
|
268
|
+
hsep: ' '.repeat(8),
|
|
269
|
+
stringLength: styledStringLength
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
console.log(`\n${t}\n`);
|
|
273
|
+
|
|
274
|
+
if (Number(this.limit) === jobs.length) {
|
|
275
|
+
console.log(chalk.yellow(`Showing first ${this.limit} results. Use --limit paramter to see more.\n`));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|