@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,41 @@
1
+ import {command, flag, help, namespace, option, param} from 'oo-cli';
2
+ import {die} from '../../lib/die';
3
+ import {formatError} from '../../lib/formatError';
4
+ import {Rivendell} from '../../lib/Rivendell';
5
+ import {applicableShards} from '../../lib/Shards';
6
+
7
+ @namespace('app')
8
+ export class RegisterCommand {
9
+ @param
10
+ @help('The app id to reserve')
11
+ public id!: string;
12
+
13
+ @param
14
+ @help('The display name of the app')
15
+ public name!: string;
16
+
17
+ @flag
18
+ @help(
19
+ 'Do not share this app with other developers in your organization. ' +
20
+ 'If not set, the app will be shared with all developers in your organization'
21
+ )
22
+ public personal: boolean = false;
23
+
24
+ @option('a')
25
+ @help('The availability zone that will be targeted (default: us)')
26
+ private availability: string = '';
27
+
28
+ @command
29
+ @help('Register an app version')
30
+ public async register() {
31
+ try {
32
+ const shards = await applicableShards(this.availability);
33
+ for (const shard of shards) {
34
+ const app = await Rivendell.registerApp(this.id, this.name, this.personal, shard);
35
+ console.log(`Registered app ${app.id} with name "${app.name} in ${shard}`);
36
+ }
37
+ } catch (e) {
38
+ die(formatError(e));
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,13 @@
1
+ import chalk from 'chalk';
2
+ import {command, help, namespace} from 'oo-cli';
3
+ import {BaseBuildCommand} from './BaseBuildCommand';
4
+
5
+ @namespace('app')
6
+ export class ValidateCommand extends BaseBuildCommand {
7
+ @command
8
+ @help('Validate an app locally')
9
+ public async validate() {
10
+ await this.run(false, false, false);
11
+ console.log(chalk.gray(`\nUse ${chalk.white('ocp app prepare')} to upload and build your app\n`));
12
+ }
13
+ }
@@ -0,0 +1,37 @@
1
+ import {command, help, namespace} from 'oo-cli';
2
+ import {die} from '../../lib/die';
3
+ import {formatError} from '../../lib/formatError';
4
+ import {Rivendell} from '../../lib/Rivendell';
5
+ import Shard = Rivendell.Shard;
6
+ import chalk from 'chalk';
7
+ import * as table from 'text-table';
8
+ import {styledStringLength} from '../../lib/StringUtils';
9
+
10
+ @namespace('availability')
11
+ export class ListCommand {
12
+ @command
13
+ @help('List all availability zones')
14
+ public async list() {
15
+ try {
16
+ this.render(await Rivendell.shards());
17
+ } catch (e) {
18
+ die(formatError(e));
19
+ }
20
+ }
21
+
22
+ private render(accounts: Shard[]) {
23
+ const header = ['Name', 'Description'].map((item) => chalk.grey(item));
24
+ const rows = accounts.map((shard) => [shard.id, shard.description]);
25
+ const t = table(
26
+ [
27
+ header,
28
+ ...rows
29
+ ],
30
+ {
31
+ hsep: ' '.repeat(8),
32
+ stringLength: styledStringLength
33
+ }
34
+ );
35
+ console.log(`\n${t}\n`);
36
+ }
37
+ }
@@ -0,0 +1,83 @@
1
+ import chalk from 'chalk';
2
+ import {command, help, namespace, option, param} from 'oo-cli';
3
+ import {die} from '../../lib/die';
4
+ import {formatVersionState} from '../../lib/formatVersionState';
5
+ import {formatReviewStatus} from '../../lib/formatReviewStatus';
6
+ import {formatError} from '../../lib/formatError';
7
+ import {Rivendell} from '../../lib/Rivendell';
8
+ import * as table from 'text-table';
9
+ import {styledStringLength} from '../../lib/StringUtils';
10
+ import SortDirection = Rivendell.SortDirection;
11
+ import AppVersion = Rivendell.AppVersion;
12
+ import AppVersionState = Rivendell.AppVersionState;
13
+ import App = Rivendell.App;
14
+ import ReviewStatus = Rivendell.ReviewStatus;
15
+
16
+ @namespace('directory')
17
+ export class InfoCommand {
18
+ @param
19
+ @help('The App ID to look up')
20
+ public appId!: string;
21
+
22
+ @option('a')
23
+ @help('The availability zone that will be targeted (default: us)')
24
+ private availability: string = '';
25
+
26
+ @command
27
+ @help('Get information about an app')
28
+ public async info() {
29
+ try {
30
+ await this.render(await Rivendell.fetchApp(this.appId, this.availability));
31
+ } catch (e) {
32
+ die(formatError(e));
33
+ }
34
+ }
35
+
36
+ private async render(app: App): Promise<void> {
37
+ console.log('');
38
+ console.log(` ${chalk.bold.underline('General')}\n`);
39
+ console.log(` ${chalk.cyanBright('id')}\t\t${app.id}`);
40
+ console.log(` ${chalk.cyanBright('name')}\t${app.name}`);
41
+ console.log(` ${chalk.cyanBright('created')}\t${app.createdAt}`);
42
+ console.log('');
43
+
44
+ // Versions
45
+ console.log(` ${chalk.bold.underline('Versions')}\n`);
46
+ const versions = await this.fetchAppVersions();
47
+ if (!versions) {
48
+ console.log(` ${chalk.italic('None')}`);
49
+ } else {
50
+ const rows = versions.map((appVersion) => {
51
+ const r = [
52
+ '',
53
+ appVersion.id.version,
54
+ formatVersionState(appVersion.state as AppVersionState)
55
+ ];
56
+ if (appVersion.reviewStatus) {
57
+ r.push(formatReviewStatus(appVersion.reviewStatus as ReviewStatus, appVersion.state as AppVersionState));
58
+ }
59
+ return r;
60
+ });
61
+ const t = table(rows, {
62
+ hsep: ' '.repeat(4),
63
+ stringLength: styledStringLength
64
+ }
65
+ );
66
+ console.log(`\n${t}\n`);
67
+ }
68
+ }
69
+
70
+ private async fetchAppVersions(): Promise<AppVersion[]> {
71
+ return await Rivendell.searchAppVersions(
72
+ {
73
+ appId: this.appId,
74
+ sorts: [
75
+ {
76
+ field: 'createdAt',
77
+ direction: SortDirection.DESC
78
+ }
79
+ ]
80
+ }, this.availability
81
+ );
82
+ }
83
+ }
@@ -0,0 +1,37 @@
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 InstallCommand {
9
+ @param
10
+ @help('The App ID and version (e.g. my_app@1.0.0)')
11
+ public appVersion!: 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('Install a specific app version into an account')
23
+ public async install() {
24
+ if (!/[\w-]+@\d+\.\d+\.\d+(?:-\w+\.\d+)?/.test(this.appVersion)) {
25
+ return die('appVersion is required in the format of app@1.0.0');
26
+ }
27
+
28
+ const [appId, version] = this.appVersion.split('@');
29
+ try {
30
+ const install = await Rivendell.install(appId, version, this.trackerId, this.availability);
31
+ console.log(chalk.green(`Installed ${appId}@${version} for ${this.trackerId} ` +
32
+ `with install id ${install.id} in ${this.availability || 'us'}`));
33
+ } catch (e) {
34
+ die(formatError(e));
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,96 @@
1
+ import chalk from 'chalk';
2
+ import {command, flag, help, namespace, option, optional, param} from 'oo-cli';
3
+ import * as semver from 'semver';
4
+ import * as table from 'text-table';
5
+ import {die} from '../../lib/die';
6
+ import {formatVersionState} from '../../lib/formatVersionState';
7
+ import {styledStringLength} from '../../lib/StringUtils';
8
+ import {Rivendell} from '../../lib/Rivendell';
9
+ import {formatError} from '../../lib/formatError';
10
+ import AppVersion = Rivendell.AppVersion;
11
+ import AppVersionState = Rivendell.AppVersionState;
12
+ import DeploymentStage = Rivendell.DeploymentStage;
13
+ import AppVersionSearchCriteria = Rivendell.AppVersionSearchCriteria;
14
+ import ReviewStatus = Rivendell.ReviewStatus;
15
+
16
+ @namespace('directory')
17
+ export class ListCommand {
18
+ @param
19
+ @optional
20
+ @help('A specific App ID to filter down to (lists all apps by default)')
21
+ private appId!: string;
22
+
23
+ @flag
24
+ @help('Include all statuses. STOPPED is filtered by default')
25
+ private allStatuses: boolean = false;
26
+
27
+ @option('a')
28
+ @help('The availability zone that will be targeted (default: us)')
29
+ private availability: string = '';
30
+
31
+ @command
32
+ @help('List registered app versions')
33
+ public async list(): Promise<void> {
34
+ try {
35
+ const criteria: AppVersionSearchCriteria = {
36
+ stages: [DeploymentStage.TEST, DeploymentStage.PRODUCTION]
37
+ };
38
+
39
+ if (this.appId) {
40
+ criteria.appId = this.appId;
41
+ }
42
+ this.render(await Rivendell.searchAppVersions(criteria, this.availability));
43
+ } catch (e) {
44
+ die(formatError(e));
45
+ }
46
+ }
47
+
48
+ private render(appVersions: AppVersion[]) {
49
+ const header = ['App ID', 'Version', 'State', 'Created At', 'Updated At'].map(
50
+ (item) => chalk.grey(item)
51
+ );
52
+ const rows = appVersions
53
+ .filter((appVersion) =>
54
+ this.allStatuses || appVersion.state as AppVersionState !== AppVersionState.STOPPED
55
+ )
56
+ .sort((lhs, rhs) => {
57
+ let result = lhs.id.appId.localeCompare(rhs.id.appId);
58
+ if (result === 0) {
59
+ const lhsVersion = lhs.id.version;
60
+ const rhsVersion = rhs.id.version;
61
+ if (lhsVersion !== rhsVersion) {
62
+ result = semver.gt(lhsVersion, rhsVersion) ? -1 : 1;
63
+ }
64
+ }
65
+ return result;
66
+ })
67
+ .map((appVersion) => [
68
+ appVersion.id.appId,
69
+ appVersion.id.version,
70
+ this.renderState(appVersion),
71
+ appVersion.createdAt,
72
+ appVersion.updatedAt
73
+ ]);
74
+
75
+ const t = table(
76
+ [
77
+ header,
78
+ ...rows
79
+ ],
80
+ {
81
+ hsep: ' '.repeat(8),
82
+ stringLength: styledStringLength
83
+ }
84
+ );
85
+ console.log(`\n${t}\n`);
86
+ }
87
+
88
+ private renderState(appVersion: AppVersion): string {
89
+ const state = appVersion.state as AppVersionState;
90
+ const reviewStatus = appVersion.reviewStatus as Rivendell.ReviewStatus;
91
+ const includeReviewStatus = reviewStatus === ReviewStatus.APPROVED || reviewStatus === ReviewStatus.IN_REVIEW;
92
+ return state === AppVersionState.PUBLISHED && includeReviewStatus
93
+ ? `${formatVersionState(state)} (${chalk.yellow(reviewStatus)})`
94
+ : formatVersionState(state);
95
+ }
96
+ }
@@ -0,0 +1,60 @@
1
+ import chalk from 'chalk';
2
+ import {command, help, namespace, option, param} from 'oo-cli';
3
+ import {die} from '../../lib/die';
4
+ import {formatError} from '../../lib/formatError';
5
+ import {Rivendell} from '../../lib/Rivendell';
6
+ import Webhook = Rivendell.Webhook;
7
+
8
+ @namespace('directory')
9
+ export class ListFunctionsCommand {
10
+ @param
11
+ @help('The App ID (e.g. my_app)')
12
+ public appId!: string;
13
+
14
+ @param
15
+ @help('The Tracker ID of the installed account')
16
+ public trackerId!: string;
17
+
18
+ @option('a')
19
+ @help('The availability zone that will be targeted (default: us)')
20
+ private availability: string = '';
21
+
22
+ @command('list-functions')
23
+ @help('List the functions exposed by an app installation')
24
+ public async listFunctions() {
25
+ try {
26
+ const appInstallation = await Rivendell.fetchAppInstallation(this.appId, this.trackerId, this.availability);
27
+ const webhooks = await Rivendell.searchWebhooks({
28
+ appInstallId: appInstallation.id,
29
+ includeInternal: true,
30
+ includeDisabled: true
31
+ }, this.availability);
32
+
33
+ this.render(webhooks);
34
+ } catch (e) {
35
+ die(formatError(e));
36
+ }
37
+ }
38
+
39
+ private render(webhooks: Webhook[]) {
40
+ if (webhooks.length === 0) {
41
+ console.log(chalk.yellow(`${this.appId} install for ${this.trackerId} does not have functions.`));
42
+ } else {
43
+ webhooks.forEach((webhook) => {
44
+ const attrs = webhook.attributes!;
45
+ const caveats = [];
46
+ if (attrs.internal) {
47
+ caveats.push('internal');
48
+ }
49
+ if (!attrs.enabled) {
50
+ caveats.push('disabled');
51
+ }
52
+ if (caveats.length === 0) {
53
+ console.log(webhook.url);
54
+ } else {
55
+ console.log(chalk.yellow(`${webhook.url} (${caveats.join(', ')})`));
56
+ }
57
+ });
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,54 @@
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
+ import Webhook = Rivendell.Webhook;
7
+
8
+ @namespace('directory')
9
+ export class ListGlobalFunctionsCommand {
10
+ @param
11
+ @help('The App ID (e.g. my_app)')
12
+ public appId!: string;
13
+
14
+ @option('a')
15
+ @help('The availability zone that will be targeted (default: us)')
16
+ private availability: string = '';
17
+
18
+ @command('list-global-functions')
19
+ @help('List the global functions exposed by an app')
20
+ public async listGlobalFunctions() {
21
+ try {
22
+ this.render(await Rivendell.searchWebhooks({
23
+ appId: this.appId,
24
+ appInstallId: 0,
25
+ includeInternal: true,
26
+ includeDisabled: true
27
+ }, this.availability));
28
+ } catch (e) {
29
+ die(formatError(e));
30
+ }
31
+ }
32
+
33
+ private render(webhooks: Webhook[]) {
34
+ if (webhooks.length === 0) {
35
+ console.log(chalk.yellow(`${this.appId} does not contain global functions.`));
36
+ } else {
37
+ webhooks.forEach((webhook) => {
38
+ const attrs = webhook.attributes;
39
+ const caveats = [];
40
+ if (attrs.internal) {
41
+ caveats.push('internal');
42
+ }
43
+ if (!attrs.enabled) {
44
+ caveats.push('disabled');
45
+ }
46
+ if (caveats.length === 0) {
47
+ console.log(webhook.url);
48
+ } else {
49
+ console.log(chalk.yellow(`${webhook.url} (${caveats.join(', ')})`));
50
+ }
51
+ });
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,73 @@
1
+ import chalk from 'chalk';
2
+ import {command, help, namespace, option, param} from 'oo-cli';
3
+ import * as table from 'text-table';
4
+ import {die} from '../../lib/die';
5
+ import {styledStringLength} from '../../lib/StringUtils';
6
+ import {Rivendell} from '../../lib/Rivendell';
7
+ import {formatError} from '../../lib/formatError';
8
+ import SortDirection = Rivendell.SortDirection;
9
+ import AppInstallation = Rivendell.AppInstallation;
10
+
11
+ @namespace('directory')
12
+ export class ListInstallsCommand {
13
+ @param
14
+ @help('The App ID and optional version (e.g. my_app or my_app@1.0.0)')
15
+ public appVersion!: string;
16
+
17
+ @option('a')
18
+ @help('The availability zone that will be targeted (default: us)')
19
+ private availability: string = '';
20
+
21
+ @command('list-installs')
22
+ @help('List installations of a specific app version')
23
+ public async listInstalls() {
24
+ const [appId, version] = this.appVersion.split('@');
25
+ try {
26
+ const appInstallations = await Rivendell.searchAppInstallations({
27
+ appId,
28
+ version,
29
+ sorts: [{
30
+ field: 'trackerId', direction: SortDirection.DESC
31
+ }]
32
+ },
33
+ this.availability
34
+ );
35
+
36
+ this.render(version, appInstallations);
37
+ } catch (e) {
38
+ die(formatError(e));
39
+ }
40
+ }
41
+
42
+ private render(version: string, appInstallations: AppInstallation[]) {
43
+ const header = this.getHeaders(version).map((item) => chalk.grey(item));
44
+ const rows = appInstallations.map((install) => this.getRow(install, version));
45
+ const t = table(
46
+ [
47
+ header,
48
+ ...rows
49
+ ],
50
+ {
51
+ hsep: ' '.repeat(8),
52
+ stringLength: styledStringLength
53
+ }
54
+ );
55
+ console.log(`\n${t}\n`);
56
+ }
57
+
58
+ private getHeaders(version: string): string[] {
59
+ const headers = ['Tracker', 'Created At', 'Updated At'];
60
+ if (!version) {
61
+ headers.splice(1, 0, 'Version');
62
+ }
63
+ return headers;
64
+ }
65
+
66
+ private getRow(install: AppInstallation, version: string): Array<{}> {
67
+ const row = [install.trackerId, install.createdAt, install.updatedAt];
68
+ if (!version) {
69
+ row.splice(1, 0, install.version);
70
+ }
71
+ return row;
72
+ }
73
+ }
@@ -0,0 +1,179 @@
1
+ import chalk from 'chalk';
2
+ import {command, flag, help, namespace, 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 {formatError} from '../../lib/formatError';
11
+ import AppVersionState = Rivendell.AppVersionState;
12
+ import {applicableShards} from '../../lib/Shards';
13
+ import { AppManifest } from '@zaiusinc/app-sdk';
14
+ import { prerelease, rcompare } from 'semver';
15
+ import { UnpublishCommand } from './Unpublish';
16
+ import { TerminalConfirm } from '../../lib/TerminalConfirm';
17
+
18
+ const STOPPED_STATES = [AppVersionState.START_FAILED, AppVersionState.STOPPED, AppVersionState.STOP_FAILED];
19
+ const UNPUBLISHABLE_STATES = [AppVersionState.RUNNING, AppVersionState.START_FAILED, AppVersionState.STOP_FAILED];
20
+ const PUBLISHABLE_STATES = [
21
+ AppVersionState.NEW,
22
+ AppVersionState.PUBLISHED,
23
+ AppVersionState.START_FAILED,
24
+ AppVersionState.STOPPED
25
+ ];
26
+
27
+ @namespace('directory')
28
+ export class PublishCommand {
29
+ @flag('no-progress')
30
+ public noProgress!: boolean;
31
+
32
+ @param
33
+ @help('The App ID and version (e.g. my_app@1.0.0)')
34
+ public appVersion!: string;
35
+
36
+ @command
37
+ @help('Publish (make available) a specific app version that has been reviewed and approved')
38
+ public async publish() {
39
+ handleInterrupt();
40
+
41
+ if (!/[\w-]+@\d+\.\d+\.\d+(?:-\w+\.\d+)?/.test(this.appVersion)) {
42
+ return die('appVersion is required in the format of app@1.0.0');
43
+ }
44
+
45
+ const [appId, version] = this.appVersion.split('@');
46
+ console.log(chalk.gray(`Publishing ${this.appVersion} to the directory...`));
47
+
48
+ try {
49
+ const appVersion = await Rivendell.fetchAppVersion({appId, version}, 'us');
50
+
51
+ if (!PUBLISHABLE_STATES.includes(appVersion.state as AppVersionState)) {
52
+ throw new Error(`AppVersion must be in a publishable state. ` +
53
+ `Currently: ${formatVersionState(appVersion.state as AppVersionState)}`);
54
+ }
55
+
56
+ const manifest = JSON.parse(appVersion.manifestJson) as AppManifest;
57
+ const shards = await applicableShards('', manifest);
58
+ const errors: string[] = [];
59
+
60
+ for (const shard of shards) {
61
+ try {
62
+ await Rivendell.publish(appId, version, shard);
63
+ console.log(chalk.green(`Success. ${this.appVersion} is being published to ${shard}.`));
64
+ const context = {appId, version};
65
+ await this.watchForPublishCompletion(context, await this.isStopped(context, shard), shard);
66
+ // since we are handling the interrupt, disable the handler so we can exit
67
+ terminal.removeAllListeners('key');
68
+ } catch (error) {
69
+ errors.push(`${formatError(error)} (${shard})`);
70
+ }
71
+ }
72
+ if (errors.length) {
73
+ console.error(chalk.red(errors.join('\n')));
74
+ }
75
+
76
+ const pre = prerelease(version);
77
+ if (pre && pre[0] !== 'dev') {
78
+ await this.checkOrphanedDeploys(appId, shards);
79
+ }
80
+ } catch (e) {
81
+ die(formatError(e));
82
+ }
83
+ }
84
+
85
+ private async checkOrphanedDeploys(appId: string, currentShards: string[]) {
86
+ const criteria: Rivendell.AppVersionSearchCriteria = {
87
+ appId,
88
+ states: UNPUBLISHABLE_STATES,
89
+ };
90
+ const versions: Rivendell.AppVersion[] = await Rivendell.searchAppVersions(criteria, 'us');
91
+
92
+ if (versions.length) {
93
+ versions.sort((x, y) => {
94
+ return rcompare(x.id.version, y.id.version);
95
+ });
96
+
97
+ const undeployVersions: {[key: string]: Rivendell.AppVersion[]} = {};
98
+ for (const version of versions) {
99
+ const appVersion = await Rivendell.fetchAppVersion({appId, version: version.id.version}, 'us');
100
+ const shards = await applicableShards('', JSON.parse(appVersion.manifestJson) as AppManifest);
101
+ const check = shards.filter((x: string) => !currentShards.includes(x));
102
+ for (const s of check) {
103
+ undeployVersions[s] = await Rivendell.searchAppVersions(criteria, s);
104
+ }
105
+ }
106
+
107
+ if (Object.keys(undeployVersions).length) {
108
+ console.log(`You are no longer targeting the availability: ${Object.keys(undeployVersions)}, ` +
109
+ `do you want to unpublish the following apps:`);
110
+ console.log(Object.entries(undeployVersions)
111
+ .map((x) => x[1].map((y) => `* ${y.id.appId}@${y.id.version} in ${x[0]}`).join('\n')).join('\n'));
112
+ if (await TerminalConfirm.ask(chalk.red('Do you want to unpublish the listed AppVersions now?'))) {
113
+ for (const [shard, toUndeploy] of Object.entries(undeployVersions)) {
114
+ for (const version of toUndeploy) {
115
+ const unpublish = new UnpublishCommand();
116
+ unpublish.appVersion = `${version.id.appId}@${version.id.version}`;
117
+ unpublish.availability = shard;
118
+ await unpublish.unpublish();
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ private async isStopped(context: AppContext, shard: string) {
127
+ const appVersion = await Rivendell.fetchAppVersion(context, shard);
128
+ return STOPPED_STATES.includes(appVersion.state as AppVersionState);
129
+ }
130
+
131
+ private watchForPublishCompletion(context: AppContext, wasStopped: boolean, shard: string) {
132
+ console.log(chalk.gray(`Watching for publish (${shard}) to complete... CTRL+C to stop checking.`));
133
+ return new Promise((resolve, reject) => {
134
+ const spinner = this.noProgress ? null : new TerminalSpinner().start('');
135
+ let attempts = 0;
136
+ let ignoreStopped = wasStopped;
137
+ const checkStatus = () => {
138
+ attempts++;
139
+ Rivendell.fetchAppVersion(context, shard)
140
+ .then((appVersion) => {
141
+ const state = appVersion.state as AppVersionState;
142
+ if (ignoreStopped && !STOPPED_STATES.includes(state)) {
143
+ ignoreStopped = false;
144
+ }
145
+ if (state === AppVersionState.RUNNING || (!ignoreStopped && STOPPED_STATES.includes(state))) {
146
+ if (spinner) {
147
+ spinner.stop();
148
+ }
149
+ clearInterval(interval);
150
+ if (state === AppVersionState.RUNNING) {
151
+ console.log(chalk.green(`${context.appId}@${context.version} has been published to ${shard}.`));
152
+ } else {
153
+ die(`Publish to ${shard} failed. ${context.appId}@${context.version} ` +
154
+ `in ${formatVersionState(state)} state.`);
155
+ }
156
+ resolve();
157
+ } else {
158
+ if (attempts > 300) {
159
+ die('Timed out waiting for completion');
160
+ }
161
+ if (spinner) {
162
+ spinner.update(`Status: ${formatVersionState(state)}`);
163
+ }
164
+ }
165
+ })
166
+ .catch((e) => {
167
+ clearInterval(interval);
168
+ if (spinner) {
169
+ spinner.stop();
170
+ }
171
+ reject(e);
172
+ });
173
+ };
174
+
175
+ const interval = setInterval(checkStatus, 2000);
176
+ checkStatus();
177
+ });
178
+ }
179
+ }