@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.
Files changed (283) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +18 -0
  3. package/bin/opti.js +3 -0
  4. package/dist/commands/accounts/Whoami.d.ts +3 -0
  5. package/dist/commands/accounts/Whoami.js +34 -0
  6. package/dist/commands/accounts/Whoami.js.map +1 -0
  7. package/dist/commands/accounts/Whois.d.ts +6 -0
  8. package/dist/commands/accounts/Whois.js +65 -0
  9. package/dist/commands/accounts/Whois.js.map +1 -0
  10. package/dist/commands/app/BaseBuildCommand.d.ts +23 -0
  11. package/dist/commands/app/BaseBuildCommand.js +227 -0
  12. package/dist/commands/app/BaseBuildCommand.js.map +1 -0
  13. package/dist/commands/app/Init.d.ts +20 -0
  14. package/dist/commands/app/Init.js +285 -0
  15. package/dist/commands/app/Init.js.map +1 -0
  16. package/dist/commands/app/Logs.d.ts +19 -0
  17. package/dist/commands/app/Logs.js +230 -0
  18. package/dist/commands/app/Logs.js.map +1 -0
  19. package/dist/commands/app/Package.d.ts +4 -0
  20. package/dist/commands/app/Package.js +51 -0
  21. package/dist/commands/app/Package.js.map +1 -0
  22. package/dist/commands/app/Prepare.d.ts +8 -0
  23. package/dist/commands/app/Prepare.js +112 -0
  24. package/dist/commands/app/Prepare.js.map +1 -0
  25. package/dist/commands/app/Register.d.ts +7 -0
  26. package/dist/commands/app/Register.js +58 -0
  27. package/dist/commands/app/Register.js.map +1 -0
  28. package/dist/commands/app/Validate.d.ts +4 -0
  29. package/dist/commands/app/Validate.js +27 -0
  30. package/dist/commands/app/Validate.js.map +1 -0
  31. package/dist/commands/availability/List.d.ts +4 -0
  32. package/dist/commands/availability/List.js +47 -0
  33. package/dist/commands/availability/List.js.map +1 -0
  34. package/dist/commands/directory/Info.d.ts +7 -0
  35. package/dist/commands/directory/Info.js +92 -0
  36. package/dist/commands/directory/Info.js.map +1 -0
  37. package/dist/commands/directory/Install.d.ts +6 -0
  38. package/dist/commands/directory/Install.js +54 -0
  39. package/dist/commands/directory/Install.js.map +1 -0
  40. package/dist/commands/directory/List.d.ts +8 -0
  41. package/dist/commands/directory/List.js +102 -0
  42. package/dist/commands/directory/List.js.map +1 -0
  43. package/dist/commands/directory/ListFunctions.d.ts +7 -0
  44. package/dist/commands/directory/ListFunctions.js +77 -0
  45. package/dist/commands/directory/ListFunctions.js.map +1 -0
  46. package/dist/commands/directory/ListGlobalFunctions.d.ts +6 -0
  47. package/dist/commands/directory/ListGlobalFunctions.js +72 -0
  48. package/dist/commands/directory/ListGlobalFunctions.js.map +1 -0
  49. package/dist/commands/directory/ListInstalls.d.ts +8 -0
  50. package/dist/commands/directory/ListInstalls.js +81 -0
  51. package/dist/commands/directory/ListInstalls.js.map +1 -0
  52. package/dist/commands/directory/Publish.d.ts +8 -0
  53. package/dist/commands/directory/Publish.js +180 -0
  54. package/dist/commands/directory/Publish.js.map +1 -0
  55. package/dist/commands/directory/Status.d.ts +5 -0
  56. package/dist/commands/directory/Status.js +60 -0
  57. package/dist/commands/directory/Status.js.map +1 -0
  58. package/dist/commands/directory/Uninstall.d.ts +6 -0
  59. package/dist/commands/directory/Uninstall.js +50 -0
  60. package/dist/commands/directory/Uninstall.js.map +1 -0
  61. package/dist/commands/directory/Unpublish.d.ts +10 -0
  62. package/dist/commands/directory/Unpublish.js +181 -0
  63. package/dist/commands/directory/Unpublish.js.map +1 -0
  64. package/dist/commands/directory/Uprade.d.ts +8 -0
  65. package/dist/commands/directory/Uprade.js +100 -0
  66. package/dist/commands/directory/Uprade.js.map +1 -0
  67. package/dist/commands/env/GetEnvironment.d.ts +3 -0
  68. package/dist/commands/env/GetEnvironment.js +28 -0
  69. package/dist/commands/env/GetEnvironment.js.map +1 -0
  70. package/dist/commands/env/SetEnvironment.d.ts +4 -0
  71. package/dist/commands/env/SetEnvironment.js +63 -0
  72. package/dist/commands/env/SetEnvironment.js.map +1 -0
  73. package/dist/commands/jobs/List.d.ts +21 -0
  74. package/dist/commands/jobs/List.js +268 -0
  75. package/dist/commands/jobs/List.js.map +1 -0
  76. package/dist/commands/jobs/RuntimeStatus.d.ts +5 -0
  77. package/dist/commands/jobs/RuntimeStatus.js +65 -0
  78. package/dist/commands/jobs/RuntimeStatus.js.map +1 -0
  79. package/dist/commands/jobs/Terminate.d.ts +5 -0
  80. package/dist/commands/jobs/Terminate.js +45 -0
  81. package/dist/commands/jobs/Terminate.js.map +1 -0
  82. package/dist/commands/jobs/Trigger.d.ts +8 -0
  83. package/dist/commands/jobs/Trigger.js +58 -0
  84. package/dist/commands/jobs/Trigger.js.map +1 -0
  85. package/dist/commands/review/List.d.ts +5 -0
  86. package/dist/commands/review/List.js +81 -0
  87. package/dist/commands/review/List.js.map +1 -0
  88. package/dist/commands/review/Open.d.ts +4 -0
  89. package/dist/commands/review/Open.js +42 -0
  90. package/dist/commands/review/Open.js.map +1 -0
  91. package/dist/index.d.ts +1 -0
  92. package/dist/index.js +15 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/lib/AppContext.d.ts +9 -0
  95. package/dist/lib/AppContext.js +43 -0
  96. package/dist/lib/AppContext.js.map +1 -0
  97. package/dist/lib/AppPackager.d.ts +8 -0
  98. package/dist/lib/AppPackager.js +40 -0
  99. package/dist/lib/AppPackager.js.map +1 -0
  100. package/dist/lib/AppUpdater.d.ts +9 -0
  101. package/dist/lib/AppUpdater.js +155 -0
  102. package/dist/lib/AppUpdater.js.map +1 -0
  103. package/dist/lib/AppUploader.d.ts +8 -0
  104. package/dist/lib/AppUploader.js +36 -0
  105. package/dist/lib/AppUploader.js.map +1 -0
  106. package/dist/lib/Config.d.ts +15 -0
  107. package/dist/lib/Config.js +47 -0
  108. package/dist/lib/Config.js.map +1 -0
  109. package/dist/lib/EnvironmentalOutput.d.ts +1 -0
  110. package/dist/lib/EnvironmentalOutput.js +21 -0
  111. package/dist/lib/EnvironmentalOutput.js.map +1 -0
  112. package/dist/lib/Moria.d.ts +51 -0
  113. package/dist/lib/Moria.js +30 -0
  114. package/dist/lib/Moria.js.map +1 -0
  115. package/dist/lib/MoriaApi.d.ts +22 -0
  116. package/dist/lib/MoriaApi.js +75 -0
  117. package/dist/lib/MoriaApi.js.map +1 -0
  118. package/dist/lib/Rivendell.d.ts +351 -0
  119. package/dist/lib/Rivendell.js +328 -0
  120. package/dist/lib/Rivendell.js.map +1 -0
  121. package/dist/lib/RivendellApi.d.ts +22 -0
  122. package/dist/lib/RivendellApi.js +90 -0
  123. package/dist/lib/RivendellApi.js.map +1 -0
  124. package/dist/lib/Shards.d.ts +3 -0
  125. package/dist/lib/Shards.js +34 -0
  126. package/dist/lib/Shards.js.map +1 -0
  127. package/dist/lib/StringUtils.d.ts +1 -0
  128. package/dist/lib/StringUtils.js +9 -0
  129. package/dist/lib/StringUtils.js.map +1 -0
  130. package/dist/lib/TeminalPassthru.d.ts +5 -0
  131. package/dist/lib/TeminalPassthru.js +12 -0
  132. package/dist/lib/TeminalPassthru.js.map +1 -0
  133. package/dist/lib/TerminalConfirm.d.ts +3 -0
  134. package/dist/lib/TerminalConfirm.js +26 -0
  135. package/dist/lib/TerminalConfirm.js.map +1 -0
  136. package/dist/lib/TerminalInput.d.ts +32 -0
  137. package/dist/lib/TerminalInput.js +207 -0
  138. package/dist/lib/TerminalInput.js.map +1 -0
  139. package/dist/lib/TerminalMenu.d.ts +34 -0
  140. package/dist/lib/TerminalMenu.js +186 -0
  141. package/dist/lib/TerminalMenu.js.map +1 -0
  142. package/dist/lib/TerminalOutput.d.ts +5 -0
  143. package/dist/lib/TerminalOutput.js +12 -0
  144. package/dist/lib/TerminalOutput.js.map +1 -0
  145. package/dist/lib/TerminalSpinner.d.ts +15 -0
  146. package/dist/lib/TerminalSpinner.js +71 -0
  147. package/dist/lib/TerminalSpinner.js.map +1 -0
  148. package/dist/lib/build.d.ts +5 -0
  149. package/dist/lib/build.js +35 -0
  150. package/dist/lib/build.js.map +1 -0
  151. package/dist/lib/checkForUpdate.d.ts +2 -0
  152. package/dist/lib/checkForUpdate.js +58 -0
  153. package/dist/lib/checkForUpdate.js.map +1 -0
  154. package/dist/lib/dev/app.d.ts +8 -0
  155. package/dist/lib/dev/app.js +53 -0
  156. package/dist/lib/dev/app.js.map +1 -0
  157. package/dist/lib/dev/index.d.ts +1 -0
  158. package/dist/lib/dev/index.js +14 -0
  159. package/dist/lib/dev/index.js.map +1 -0
  160. package/dist/lib/dev/logger.d.ts +15 -0
  161. package/dist/lib/dev/logger.js +58 -0
  162. package/dist/lib/dev/logger.js.map +1 -0
  163. package/dist/lib/die.d.ts +5 -0
  164. package/dist/lib/die.js +14 -0
  165. package/dist/lib/die.js.map +1 -0
  166. package/dist/lib/directoryExists.d.ts +1 -0
  167. package/dist/lib/directoryExists.js +9 -0
  168. package/dist/lib/directoryExists.js.map +1 -0
  169. package/dist/lib/formatBuildState.d.ts +2 -0
  170. package/dist/lib/formatBuildState.js +23 -0
  171. package/dist/lib/formatBuildState.js.map +1 -0
  172. package/dist/lib/formatError.d.ts +1 -0
  173. package/dist/lib/formatError.js +45 -0
  174. package/dist/lib/formatError.js.map +1 -0
  175. package/dist/lib/formatJobStatus.d.ts +3 -0
  176. package/dist/lib/formatJobStatus.js +28 -0
  177. package/dist/lib/formatJobStatus.js.map +1 -0
  178. package/dist/lib/formatReviewStatus.d.ts +4 -0
  179. package/dist/lib/formatReviewStatus.js +28 -0
  180. package/dist/lib/formatReviewStatus.js.map +1 -0
  181. package/dist/lib/formatTimstamp.d.ts +1 -0
  182. package/dist/lib/formatTimstamp.js +25 -0
  183. package/dist/lib/formatTimstamp.js.map +1 -0
  184. package/dist/lib/formatVersionState.d.ts +2 -0
  185. package/dist/lib/formatVersionState.js +35 -0
  186. package/dist/lib/formatVersionState.js.map +1 -0
  187. package/dist/lib/gatherAppEnv.d.ts +3 -0
  188. package/dist/lib/gatherAppEnv.js +71 -0
  189. package/dist/lib/gatherAppEnv.js.map +1 -0
  190. package/dist/lib/handleInterrupt.d.ts +1 -0
  191. package/dist/lib/handleInterrupt.js +17 -0
  192. package/dist/lib/handleInterrupt.js.map +1 -0
  193. package/dist/lib/jobRuntime.d.ts +3 -0
  194. package/dist/lib/jobRuntime.js +16 -0
  195. package/dist/lib/jobRuntime.js.map +1 -0
  196. package/dist/lib/parseDate.d.ts +2 -0
  197. package/dist/lib/parseDate.js +26 -0
  198. package/dist/lib/parseDate.js.map +1 -0
  199. package/dist/lib/templating/TemplateRenderer.d.ts +13 -0
  200. package/dist/lib/templating/TemplateRenderer.js +62 -0
  201. package/dist/lib/templating/TemplateRenderer.js.map +1 -0
  202. package/dist/lib/templating/fetchTemplatesManifest.d.ts +1 -0
  203. package/dist/lib/templating/fetchTemplatesManifest.js +10 -0
  204. package/dist/lib/templating/fetchTemplatesManifest.js.map +1 -0
  205. package/dist/lib/templating/types.d.ts +27 -0
  206. package/dist/lib/templating/types.js +3 -0
  207. package/dist/lib/templating/types.js.map +1 -0
  208. package/dist/oo-cli.manifest.json +1142 -0
  209. package/dist/test/setup.d.ts +0 -0
  210. package/dist/test/setup.js +4 -0
  211. package/dist/test/setup.js.map +1 -0
  212. package/package.json +94 -0
  213. package/src/commands/accounts/Whoami.ts +19 -0
  214. package/src/commands/accounts/Whois.ts +51 -0
  215. package/src/commands/app/BaseBuildCommand.ts +266 -0
  216. package/src/commands/app/Init.ts +303 -0
  217. package/src/commands/app/Logs.ts +241 -0
  218. package/src/commands/app/Package.ts +39 -0
  219. package/src/commands/app/Prepare.ts +108 -0
  220. package/src/commands/app/Register.ts +41 -0
  221. package/src/commands/app/Validate.ts +13 -0
  222. package/src/commands/availability/List.ts +37 -0
  223. package/src/commands/directory/Info.ts +83 -0
  224. package/src/commands/directory/Install.ts +37 -0
  225. package/src/commands/directory/List.ts +96 -0
  226. package/src/commands/directory/ListFunctions.ts +60 -0
  227. package/src/commands/directory/ListGlobalFunctions.ts +54 -0
  228. package/src/commands/directory/ListInstalls.ts +73 -0
  229. package/src/commands/directory/Publish.ts +179 -0
  230. package/src/commands/directory/Status.ts +45 -0
  231. package/src/commands/directory/Uninstall.ts +32 -0
  232. package/src/commands/directory/Unpublish.ts +173 -0
  233. package/src/commands/directory/Uprade.ts +85 -0
  234. package/src/commands/env/GetEnvironment.ts +14 -0
  235. package/src/commands/env/SetEnvironment.ts +52 -0
  236. package/src/commands/jobs/List.ts +278 -0
  237. package/src/commands/jobs/RuntimeStatus.ts +49 -0
  238. package/src/commands/jobs/Terminate.ts +29 -0
  239. package/src/commands/jobs/Trigger.ts +41 -0
  240. package/src/commands/review/List.ts +76 -0
  241. package/src/commands/review/Open.ts +28 -0
  242. package/src/index.ts +15 -0
  243. package/src/lib/AppContext.ts +47 -0
  244. package/src/lib/AppPackager.ts +47 -0
  245. package/src/lib/AppUpdater.ts +177 -0
  246. package/src/lib/AppUploader.ts +39 -0
  247. package/src/lib/Config.ts +60 -0
  248. package/src/lib/EnvironmentalOutput.ts +18 -0
  249. package/src/lib/Moria.ts +66 -0
  250. package/src/lib/MoriaApi.ts +86 -0
  251. package/src/lib/Rivendell.ts +572 -0
  252. package/src/lib/RivendellApi.ts +99 -0
  253. package/src/lib/Shards.ts +37 -0
  254. package/src/lib/StringUtils.ts +4 -0
  255. package/src/lib/TeminalPassthru.ts +7 -0
  256. package/src/lib/TerminalConfirm.ts +27 -0
  257. package/src/lib/TerminalInput.ts +236 -0
  258. package/src/lib/TerminalMenu.ts +221 -0
  259. package/src/lib/TerminalOutput.ts +7 -0
  260. package/src/lib/TerminalSpinner.ts +76 -0
  261. package/src/lib/build.ts +36 -0
  262. package/src/lib/checkForUpdate.ts +63 -0
  263. package/src/lib/dev/app.ts +58 -0
  264. package/src/lib/dev/index.ts +1 -0
  265. package/src/lib/dev/logger.ts +77 -0
  266. package/src/lib/die.ts +10 -0
  267. package/src/lib/directoryExists.ts +5 -0
  268. package/src/lib/formatBuildState.ts +20 -0
  269. package/src/lib/formatError.ts +39 -0
  270. package/src/lib/formatJobStatus.ts +24 -0
  271. package/src/lib/formatReviewStatus.ts +27 -0
  272. package/src/lib/formatTimstamp.ts +21 -0
  273. package/src/lib/formatVersionState.ts +31 -0
  274. package/src/lib/gatherAppEnv.ts +75 -0
  275. package/src/lib/handleInterrupt.ts +13 -0
  276. package/src/lib/jobRuntime.ts +12 -0
  277. package/src/lib/parseDate.ts +21 -0
  278. package/src/lib/templating/TemplateRenderer.ts +65 -0
  279. package/src/lib/templating/fetchTemplatesManifest.ts +6 -0
  280. package/src/lib/templating/types.ts +30 -0
  281. package/src/test/setup.ts +2 -0
  282. package/src/types/columnify.d.ts +27 -0
  283. 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
+ }