@corva/create-app 0.27.0-rc.0 → 0.28.0-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 (128) hide show
  1. package/README.md +160 -17
  2. package/bin/create-corva-app.js +5 -0
  3. package/lib/app.js +9 -0
  4. package/lib/bump-version.option.js +29 -0
  5. package/{constants → lib/constants}/cli.js +1 -0
  6. package/{constants → lib/constants}/manifest.js +4 -12
  7. package/lib/constants/messages.js +21 -0
  8. package/{constants → lib/constants}/package.js +2 -2
  9. package/lib/flow.js +46 -0
  10. package/lib/flows/lib/create-zip-archive.js +77 -0
  11. package/lib/flows/lib/json.js +28 -0
  12. package/lib/flows/lib/manifest.js +31 -0
  13. package/lib/flows/lib/step-error.js +12 -0
  14. package/lib/flows/prepare.js +8 -0
  15. package/lib/flows/release.js +18 -0
  16. package/lib/flows/steps/prepare-load-app-files.js +18 -0
  17. package/lib/flows/steps/release-get-app-key.js +16 -0
  18. package/lib/flows/steps/release-get-config.js +30 -0
  19. package/lib/flows/steps/release-upload-zip-to-corva.js +34 -0
  20. package/lib/flows/steps/zip-cleanup.js +17 -0
  21. package/lib/flows/steps/zip-create-archive.js +15 -0
  22. package/lib/flows/steps/zip-file-list-resolve.js +185 -0
  23. package/lib/flows/steps/zip-prepare.js +21 -0
  24. package/lib/flows/steps/zip.js +15 -0
  25. package/lib/flows/zip-simple.js +8 -0
  26. package/lib/flows/zip.js +9 -0
  27. package/{helpers → lib/helpers}/manifest.js +11 -13
  28. package/{helpers → lib/helpers}/utils.js +0 -0
  29. package/{helpers → lib/helpers}/versioning.js +0 -0
  30. package/{index.js → lib/index.js} +165 -52
  31. package/{scripts → lib/scripts}/utils/version.js +49 -26
  32. package/package.json +13 -8
  33. package/{template → templates}/scheduler/node/README.md +0 -0
  34. package/{template → templates}/scheduler/node/__test__/processor.test.js +0 -0
  35. package/{template → templates}/scheduler/node/gitignore +0 -0
  36. package/{template → templates}/scheduler/node/index.js +0 -0
  37. package/{template → templates}/scheduler/node/package.json +1 -1
  38. package/{template → templates}/scheduler/node/src/processor.js +0 -0
  39. package/{template → templates}/scheduler/node-ts/README.md +0 -0
  40. package/{template → templates}/scheduler/node-ts/__test__/processor.spec.ts +0 -0
  41. package/{template → templates}/scheduler/node-ts/gitignore +0 -0
  42. package/{template → templates}/scheduler/node-ts/index.ts +0 -0
  43. package/templates/scheduler/node-ts/lib/processor.js +16 -0
  44. package/templates/scheduler/node-ts/lib/processor.js.map +1 -0
  45. package/{template → templates}/scheduler/node-ts/lib/processor.ts +0 -0
  46. package/{template → templates}/scheduler/node-ts/package.json +1 -1
  47. package/{template → templates}/scheduler/node-ts/tsconfig.build.json +0 -0
  48. package/{template → templates}/scheduler/node-ts/tsconfig.json +0 -0
  49. package/templates/scheduler/python/Makefile +15 -0
  50. package/templates/scheduler/python/README.md +31 -0
  51. package/{template → templates}/scheduler/python/lambda_function.py +0 -0
  52. package/{template → templates}/scheduler/python/requirements.txt +0 -0
  53. package/{template → templates}/scheduler/python/test/__init__.py +0 -0
  54. package/{template → templates}/scheduler/python/test/app_test.py +0 -0
  55. package/{template → templates}/stream/node/README.md +0 -0
  56. package/{template → templates}/stream/node/__test__/processor.test.js +0 -0
  57. package/{template → templates}/stream/node/gitignore +0 -0
  58. package/{template → templates}/stream/node/index.js +0 -0
  59. package/{template → templates}/stream/node/package.json +1 -1
  60. package/{template → templates}/stream/node/src/processor.js +0 -0
  61. package/{template → templates}/stream/node-ts/README.md +0 -0
  62. package/{template → templates}/stream/node-ts/__test__/processor.spec.ts +0 -0
  63. package/{template → templates}/stream/node-ts/gitignore +0 -0
  64. package/{template → templates}/stream/node-ts/index.ts +0 -0
  65. package/{template → templates}/stream/node-ts/lib/processor.ts +0 -0
  66. package/{template → templates}/stream/node-ts/package.json +1 -1
  67. package/{template → templates}/stream/node-ts/tsconfig.build.json +0 -0
  68. package/{template → templates}/stream/node-ts/tsconfig.json +0 -0
  69. package/templates/stream/python/Makefile +15 -0
  70. package/templates/stream/python/README.md +31 -0
  71. package/{template → templates}/stream/python/lambda_function.py +0 -0
  72. package/{template → templates}/stream/python/requirements.txt +0 -0
  73. package/{template → templates}/stream/python/test/__init__.py +0 -0
  74. package/{template → templates}/stream/python/test/app_test.py +0 -0
  75. package/{template → templates}/task/node/README.md +0 -0
  76. package/{template → templates}/task/node/__test__/processor.test.js +0 -0
  77. package/{template → templates}/task/node/gitignore +0 -0
  78. package/{template → templates}/task/node/index.js +0 -0
  79. package/{template → templates}/task/node/package.json +1 -1
  80. package/{template → templates}/task/node/src/processor.js +0 -0
  81. package/{template → templates}/task/node-ts/README.md +0 -0
  82. package/{template → templates}/task/node-ts/__test__/processor.spec.ts +0 -0
  83. package/{template → templates}/task/node-ts/gitignore +0 -0
  84. package/{template → templates}/task/node-ts/index.ts +0 -0
  85. package/{template → templates}/task/node-ts/package.json +1 -1
  86. package/{template → templates}/task/node-ts/src/processor.ts +0 -0
  87. package/{template → templates}/task/node-ts/tsconfig.build.json +0 -0
  88. package/{template → templates}/task/node-ts/tsconfig.json +0 -0
  89. package/templates/task/python/Makefile +15 -0
  90. package/templates/task/python/README.md +31 -0
  91. package/{template → templates}/task/python/lambda_function.py +0 -0
  92. package/{template → templates}/task/python/requirements.txt +0 -0
  93. package/{template → templates}/task/python/test/__init__.py +0 -0
  94. package/{template → templates}/task/python/test/app_test.py +0 -0
  95. package/{template → templates}/ui/js/.env +0 -0
  96. package/{template → templates}/ui/js/.env.sample +0 -0
  97. package/{template → templates}/ui/js/.eslintrc +0 -0
  98. package/{template → templates}/ui/js/.prettierrc +0 -0
  99. package/{template → templates}/ui/js/README.md +0 -0
  100. package/{template → templates}/ui/js/config-overrides.js +0 -0
  101. package/{template → templates}/ui/js/gitignore +0 -0
  102. package/{template → templates}/ui/js/src/App.css +0 -0
  103. package/{template → templates}/ui/js/src/App.js +0 -0
  104. package/{template → templates}/ui/js/src/AppSettings.js +0 -0
  105. package/{template → templates}/ui/js/src/assets/logo.svg +0 -0
  106. package/{template → templates}/ui/js/src/constants.js +0 -0
  107. package/{template → templates}/ui/js/src/index.js +0 -0
  108. package/{template → templates}/ui/ts/.env +0 -0
  109. package/{template → templates}/ui/ts/.env.sample +0 -0
  110. package/{template → templates}/ui/ts/.eslintrc +0 -0
  111. package/{template → templates}/ui/ts/.prettierrc +0 -0
  112. package/{template → templates}/ui/ts/README.md +0 -0
  113. package/{template → templates}/ui/ts/config-overrides.js +0 -0
  114. package/{template → templates}/ui/ts/gitignore +0 -0
  115. package/{template → templates}/ui/ts/src/App.css +0 -0
  116. package/{template → templates}/ui/ts/src/App.tsx +0 -0
  117. package/{template → templates}/ui/ts/src/AppSettings.tsx +0 -0
  118. package/{template → templates}/ui/ts/src/assets/logo.svg +0 -0
  119. package/{template → templates}/ui/ts/src/constants.ts +0 -0
  120. package/{template → templates}/ui/ts/src/custom.d.ts +0 -0
  121. package/{template → templates}/ui/ts/src/index.js +0 -0
  122. package/{template → templates}/ui/ts/tsconfig.json +0 -0
  123. package/scripts/ui/index.js +0 -7
  124. package/scripts/ui/releaseAppZip.js +0 -91
  125. package/scripts/ui/zipAppSource.js +0 -103
  126. package/template/scheduler/python/README.md +0 -19
  127. package/template/stream/python/README.md +0 -19
  128. package/template/task/python/README.md +0 -19
package/README.md CHANGED
@@ -17,41 +17,184 @@ npm i -g @corva/create-app
17
17
  `corva-create-app` provides a user-friendly CLI wizard to create an app.
18
18
 
19
19
  ```sh
20
- Usage: corva-create-app <project-directory> [options]
20
+ Usage: create-corva-app [options] [command]
21
+
22
+ Options:
23
+ -h, --help display help for command
24
+
25
+ Commands:
26
+ create [options] [project-directory] Create a new app
27
+ zip [options] <project-directory> [patterns...] Bundle app
28
+ release [options] <project-directory> [patterns...] Release app
29
+ help [command] display help for command
30
+ ```
31
+
32
+ ## Create an app
33
+
34
+ To create a new app use `create` command.
35
+
36
+ ```sh
37
+ Usage: create-corva-app create <project-directory> [options]
38
+
39
+ Create a new app
21
40
 
22
41
  Arguments:
23
- project-directory project directory to work with
42
+ project-directory project directory to work with (default: "Current working dir")
24
43
 
25
44
  Options:
26
- -V, --version output the version number
27
- -z, --zip <type> zip app source
28
- -t, --useTypescript use typescript or javascript (default: false)
29
- -p, --packageManager <value> package manager to use (choices: "npm", "yarn", default: "yarn")
30
- --appType [value]
31
- --appKey [value]
32
- --appName [value]
33
- --category [value]
34
- --segments [value]
35
- --runtime [value]
36
- -h, --help display help for command
45
+ --developerName [string] Enter the Developer Name (default: "O&G Company")
46
+ --developerIdentifier [string] Enter the Developer Identifier (default: "oandgc")
47
+ --appType [string] Choose the App Type (choices: "ui", "scheduler", "stream", "task", default: "ui")
48
+ --schedulerType [number] Choose the scheduler type (choices: "1", "2", "4", default: 1)
49
+ --cronString [string] Provide CRON string for the scheduler (default: "*/5 * * * *")
50
+ --depthMilestone [number] Provide depth milestone for the scheduler (default: 1)
51
+ --appKey [string] Enter the App Key (default: "app.key-goes-here")
52
+ --appName [string] Enter the App Name
53
+ --description [string] Enter description (default: "This is the description of my app. You can do great things with it!")
54
+ --summary [string] Enter summary (default: "More information about this app goes here")
55
+ --category [string] Enter category (default: "")
56
+ --website [string] Enter website (default: "https://www.oandgexample.com/my-app/")
57
+ --segments [string] Choose segments (choices: "drilling", "completion")
58
+ --runtime [string] Choose runtime (choices: "ui", "nodejs12.x", "nodejs14.x", "python3.8")
59
+ -p, --packageManager [string] Please select the desired package manager (choices: "yarn", "npm", default: "yarn")
60
+ -t, --useTypescript [boolean] Would you like to use TypesScript? (default: false)
61
+ -V, --version output the version number
62
+ -z, --zip [string] DEPRECATED Use zip command instead
63
+ --release DEPRECATED Use release command instead
64
+ --bump-version <string> DEPRECATED Use with zip or release command instead (choices: "major", "minor", "patch", "skip")
65
+ -h, --help display help for command
37
66
  ```
38
67
 
39
- ## Examples
68
+ ### Examples
40
69
 
41
- ### Create a UI application
70
+ #### Create a UI application
42
71
 
43
72
  ```sh
44
73
  create-corva-app test --appName "Test" --segments "drilling" --category "wellDesign" --appKey "some-company.test.ui" --appType "ui" --runtime "ui"
45
74
  ```
46
75
 
47
- ### Create a NodeJs TypeScript application
76
+ #### Create a NodeJs TypeScript application
48
77
 
49
78
  ```sh
50
79
  create-corva-app test --appName "Test" --segments "drilling" --category "wellDesign" --appKey "some-company.test.scheduler" --appType "scheduler" --runtime "nodejs12.x" -t
51
80
  ```
52
81
 
53
- ### Create a Python application
82
+ #### Create a Python application
54
83
 
55
84
  ```sh
56
85
  create-corva-app test --appName "Test" --segments "drilling" --category "analytics" --appKey "some-company.test.stream" --appType "stream" --runtime "python3.8"
57
86
  ```
87
+
88
+ ## Zip
89
+
90
+ To create a zip that contains app ready to be deployed to Corva use `zip` command.
91
+
92
+ ```sh
93
+ Usage: create-corva-app zip [options] <project-directory> [patterns...]
94
+
95
+ Bundle app
96
+
97
+ Arguments:
98
+ project-directory Project directory to work with
99
+ patterns Additional patterns to zip (default: [])
100
+
101
+ Options:
102
+ --bump-version <string> bump version (choices: "major", "minor", "patch", "skip")
103
+ -h, --help display help for command
104
+ ```
105
+
106
+ ### What is getting zipped?
107
+
108
+ By default next files will be included.
109
+
110
+ For `frontend` apps:
111
+
112
+ - `manifest.json`
113
+ - `package.json`
114
+ - `yarn.lock`
115
+ - `.npmrc`
116
+ - `config-overrides.js`
117
+ - all files under `src`
118
+ - `tsconfig.json`
119
+
120
+ For apps that written in `node`:
121
+
122
+ - `manifest.json`
123
+ - `package.json`
124
+ - either `package-lock.json` or `yarn.lock`
125
+ - all files under `config` folder
126
+ - all `*.js` files under `src` and `lib` folders (if `typescript` is not used)
127
+ - `tsconfig.json`, `tsconfig.build.json` (if `typescript` is used)
128
+ - all `*.ts` files under `src` and `lib` folders (if `typescript` is used)
129
+
130
+ For apps that written in `python`:
131
+
132
+ - `manifest.json`
133
+ - `requirements.txt`
134
+ - all `*.py` files
135
+
136
+ If you want to zip some files that are not included pass that as `patterns` arguments.
137
+
138
+ ### Examples
139
+
140
+ #### Create a zip file from the content of `test-app` folder & put zip file in it.
141
+
142
+ ```sh
143
+ create-corva-app zip test-app
144
+ ```
145
+
146
+ #### Create a zip file & automatically bump version
147
+
148
+ ```sh
149
+ create-corva-app zip test-app --bump-version=patch
150
+ ```
151
+
152
+ #### Create a zip file from the content of `test-app` folder with custom content ([globs](<https://en.wikipedia.org/wiki/Glob_(programming)>) are supported)
153
+
154
+ ```sh
155
+ create-corva-app zip test-app some/missing/file1 some/other/missing/file2 all/files/*.glob
156
+ ```
157
+
158
+ ## Release
159
+
160
+ To push app to Corva use `release` command.
161
+
162
+ ```sh
163
+ Usage: create-corva-app release [options] <project-directory> [patterns...]
164
+
165
+ Release app
166
+
167
+ Arguments:
168
+ project-directory Project directory to work with
169
+ patterns Additional patterns to zip (default: [])
170
+
171
+ Options:
172
+ --bump-version <string> bump version (choices: "major", "minor", "patch", "skip")
173
+ -h, --help display help for command
174
+ ```
175
+
176
+ ### Examples
177
+
178
+ #### Make a release with ask for version
179
+
180
+ ```sh
181
+ create-corva-app release test-app
182
+ ```
183
+
184
+ #### Make a release without version increase
185
+
186
+ ```sh
187
+ create-corva-app release test-app --bump-version=skip
188
+ ```
189
+
190
+ #### Make a release with increased version
191
+
192
+ ```sh
193
+ create-corva-app release test-app --bump-version=patch
194
+ ```
195
+
196
+ #### Make a release with custom version
197
+
198
+ ```sh
199
+ create-corva-app release test-app --bump-version=4.2.0
200
+ ```
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { run } = require('../lib/app');
4
+
5
+ run();
package/lib/app.js ADDED
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const run = () => {
4
+ require('./');
5
+ };
6
+
7
+ module.exports = {
8
+ run,
9
+ };
@@ -0,0 +1,29 @@
1
+ const { Option, InvalidArgumentError } = require('commander');
2
+ const chalk = require('chalk');
3
+
4
+ const flags = '--bump-version <string>';
5
+ const description = 'Bump version';
6
+ const choices = ['major', 'minor', 'patch', 'skip'];
7
+
8
+ function argParser(value, previous) {
9
+ if (this.argChoices.includes(value) || semver.valid(value)) {
10
+ return value;
11
+ }
12
+
13
+ throw new InvalidArgumentError(
14
+ `Allowed choices are ${this.argChoices
15
+ .map((choice) => `"${choice}"`)
16
+ .join(', ')} or a valid semver version.`
17
+ );
18
+ }
19
+ const bumpVersionOption = new Option(flags, description).choices(choices).argParser(argParser);
20
+
21
+ const bumpVersionOptionDeprecated = new Option(
22
+ flags,
23
+ chalk.bgYellow`DEPRECATED` +
24
+ ` Use with ${chalk.cyan`zip`} or ${chalk.cyan`release`} command instead`
25
+ )
26
+ .choices(choices)
27
+ .argParser(argParser);
28
+
29
+ module.exports = { bumpVersionOption, bumpVersionOptionDeprecated };
@@ -1,6 +1,7 @@
1
1
  const APP_RUNTIMES = {
2
2
  UI: 'ui',
3
3
  NODE12: 'nodejs12.x',
4
+ NODE14: 'nodejs14.x',
4
5
  PYTHON3: 'python3.8',
5
6
  };
6
7
 
@@ -69,14 +69,6 @@ const defaultDataAppPythonManifest = {
69
69
  },
70
70
  };
71
71
 
72
- const defaultTimeSchedulerSettings = {
73
- cron_string: '*/5 * * * *',
74
- };
75
-
76
- const defaultDepthSchedulerSettings = {
77
- depth_milestone: 1,
78
- };
79
-
80
72
  const getManifestMandatoryKeys = (opts) => {
81
73
  const keys = manifestOptions(opts.projectName).reduce((acc, option) => {
82
74
  if (option.required) {
@@ -134,14 +126,15 @@ const manifestOptions = (projectName) => [
134
126
  name: 'cronString',
135
127
  message: 'Provide CRON string for the scheduler',
136
128
  default: '*/5 * * * *',
137
- when: (answers) => answers.schedulerType && answers.schedulerType !== SCHEDULER_TYPE_DEPTH.value,
129
+ when: (answers) =>
130
+ answers.schedulerType && answers.schedulerType !== SCHEDULER_TYPE_DEPTH.value,
138
131
  },
139
132
  {
140
133
  name: 'depthMilestone',
141
134
  message: 'Provide depth milestone for the scheduler',
142
135
  default: 1,
143
136
  when: (answers) => answers.schedulerType === SCHEDULER_TYPE_DEPTH.value,
144
- filter: (value) => (isNaN(value) ? value : Number(value))
137
+ filter: (value) => (isNaN(value) ? value : Number(value)),
145
138
  },
146
139
  {
147
140
  name: 'appKey',
@@ -196,6 +189,7 @@ const manifestOptions = (projectName) => [
196
189
  type: 'rawlist',
197
190
  name: 'packageManager',
198
191
  message: 'Please select the desired package manager',
192
+ alias: 'p',
199
193
  default: 'yarn',
200
194
  choices: ['yarn', 'npm'],
201
195
  when: (answers) => !answers.runtime || !answers.runtime.startsWith(TEMPLATE_TYPES.PYTHON),
@@ -217,8 +211,6 @@ module.exports = {
217
211
  defaultUIAppManifest,
218
212
  defaultDataAppNodeManifest,
219
213
  defaultDataAppPythonManifest,
220
- defaultTimeSchedulerSettings,
221
- defaultDepthSchedulerSettings,
222
214
  manifestOptions,
223
215
  getManifestMandatoryKeys,
224
216
  SCHEDULER_TYPE_NATURAL_TIME,
@@ -0,0 +1,21 @@
1
+ const chalk = require('chalk');
2
+
3
+ const SUCCESS_ICON = ' ✅ \n';
4
+ const ERROR_ICON = ' ❌ \n';
5
+
6
+ const RELEASE = {
7
+ createZip: 'Creating zip archive...\n',
8
+ createZipError: 'Could not create zip archive.',
9
+ createZipSuccess: `Zip archive has been created ${SUCCESS_ICON}`,
10
+ getAuthToken: 'Reading auth token...',
11
+ getAuthTokenError: `Could not find auth token. For UI app please run ${chalk.cyan`yarn start`} and login to Corva to fetch it.`,
12
+ getAppKey: 'Reading app key...',
13
+ getAppKeyError: "Could not find app key. Please make sure it's defined in manifest.json",
14
+ uploadApp: 'Uploading app...',
15
+ };
16
+
17
+ module.exports = {
18
+ RELEASE,
19
+ SUCCESS_ICON,
20
+ ERROR_ICON,
21
+ };
@@ -38,9 +38,9 @@ const tsDependencies = {
38
38
  const scripts = {
39
39
  build: 'webpack --config=./config-overrides.js --mode production',
40
40
  start: 'webpack-dev-server --config=./config-overrides.js --open --mode development',
41
- zip: 'create-corva-app --zip ui',
41
+ zip: 'create-corva-app zip .',
42
42
  lint: 'eslint --cache ./src/',
43
- release: 'create-corva-app --release',
43
+ release: 'create-corva-app release .',
44
44
  };
45
45
 
46
46
  module.exports = {
package/lib/flow.js ADDED
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ const chalk = require('chalk');
4
+ const { SUCCESS_ICON } = require('./constants/messages');
5
+ const { resolve, sep } = require('path');
6
+
7
+ const debug = require('debug')('cca:flow');
8
+
9
+ const runFlow = async (flow, context, indent = '') => {
10
+ process.stdout.write(
11
+ `${indent}Running ${chalk.cyan(flow.name)} in ${chalk.cyan(resolve(context.dirName).split(sep).pop())}\n`
12
+ );
13
+
14
+ const result = await runSteps(flow.steps, context, indent + ' ');
15
+
16
+ process.stdout.write(`${indent}Done!` + SUCCESS_ICON);
17
+
18
+ return result;
19
+ };
20
+
21
+ const runSteps = async (steps = [], context = {}, indent = '') => {
22
+ for (const step of steps) {
23
+ if (step.name) {
24
+ const result = await runFlow(step, context, indent);
25
+
26
+ Object.assign(context, result);
27
+
28
+ continue;
29
+ }
30
+
31
+ const message = indent + step.message;
32
+
33
+ process.stdout.write(message);
34
+ debug('Context: %o', context);
35
+
36
+ const result = await step.fn(context);
37
+
38
+ Object.assign(context, result);
39
+
40
+ process.stdout.write(SUCCESS_ICON);
41
+ }
42
+
43
+ return context;
44
+ };
45
+
46
+ module.exports = { runFlow };
@@ -0,0 +1,77 @@
1
+ const archiver = require('archiver');
2
+ const debug = require('debug')('cca:zip');
3
+ const { promises: fs, createWriteStream } = require('fs');
4
+ const path = require('path');
5
+
6
+ const createZipArchive = async (dirName, zipName, itemsToZip = []) => {
7
+ const filePath = path.resolve(dirName, zipName);
8
+ const archive = archiver.create('zip', {});
9
+ const output = createWriteStream(filePath);
10
+ // pipe archive data to the file
11
+ archive.pipe(output);
12
+
13
+ await new Promise(async (resolve, reject) => {
14
+ output.once('close', resolve).once('end', function () {
15
+ debug('Data has been drained');
16
+ });
17
+
18
+ archive.on('warning', function (err) {
19
+ if (err.code === 'ENOENT') {
20
+ console.warn(err.message);
21
+
22
+ return;
23
+ }
24
+
25
+ throw err;
26
+ });
27
+
28
+ archive.once('error', reject);
29
+
30
+ const dataToZip = await getDataToZip(itemsToZip, dirName);
31
+
32
+ for (const item of dataToZip) {
33
+ if (item.isDir) {
34
+ debug(`Adding directory %s -> %s`, item.path, item.name);
35
+ archive.directory(item.path, item.name);
36
+
37
+ continue;
38
+ }
39
+
40
+ debug(`Adding file %s -> %s`, item.path, item.name);
41
+ archive.file(item.path, { name: item.name });
42
+ }
43
+
44
+ archive.finalize();
45
+ });
46
+
47
+ return archive.pointer();
48
+ };
49
+
50
+ const getDataToZip = async (itemsToZip, dirName) => {
51
+ const promises = itemsToZip.map(async (name) => {
52
+ const nameWasProvided = typeof name === 'string';
53
+ const filePath = nameWasProvided ? path.resolve(dirName, name) : name.path;
54
+ const fileName = nameWasProvided ? name : name.name;
55
+
56
+ const { exists, isDir } = await fs
57
+ .lstat(filePath)
58
+ .then((stat) => ({ exists: true, isDir: stat.isDirectory() }))
59
+ .catch(() => {
60
+ debug(`%s location not exist, filtering it out`, filePath);
61
+
62
+ return { exists: false, isDir: false };
63
+ });
64
+
65
+ return {
66
+ name: fileName,
67
+ path: filePath,
68
+ exists,
69
+ isDir,
70
+ };
71
+ });
72
+ const allData = await Promise.all(promises);
73
+
74
+ return allData.filter((f) => f.exists);
75
+ };
76
+
77
+ module.exports = { createZipArchive };
@@ -0,0 +1,28 @@
1
+ const { resolve } = require('path');
2
+ const { promises: fs } = require('fs');
3
+ const os = require('os');
4
+
5
+ const debug = require('debug')('cca:json');
6
+
7
+ const loadJson = async (dirName, fileName) => {
8
+ const fullPath = resolve(dirName, fileName);
9
+
10
+ try {
11
+ debug('Loading file %s', fullPath);
12
+ const manifest = await fs.readFile(fullPath, 'utf8');
13
+
14
+ return JSON.parse(manifest);
15
+ } catch (e) {
16
+ if (e.code === 'ENOENT') {
17
+ throw new Error(`${fileName} was not found in ${resolve(dirName)}`);
18
+ }
19
+
20
+ throw e;
21
+ }
22
+ };
23
+
24
+ const saveJson = async (dirName, fileName, data) => {
25
+ return fs.writeFile(resolve(dirName, fileName), JSON.stringify(data, null, 2) + os.EOL);
26
+ };
27
+
28
+ module.exports = { loadJson, saveJson };
@@ -0,0 +1,31 @@
1
+ const { APP_TYPES, APP_RUNTIMES } = require('../../constants/cli');
2
+
3
+ const NODE_RUNTIMES = [APP_RUNTIMES.NODE12, APP_RUNTIMES.NODE14];
4
+
5
+ class Manifest {
6
+ constructor(manifest) {
7
+ this.manifest = manifest;
8
+ }
9
+
10
+ get runtime() {
11
+ return this.manifest.settings.runtime;
12
+ }
13
+
14
+ isNode() {
15
+ return NODE_RUNTIMES.includes(this.manifest.settings.runtime);
16
+ }
17
+
18
+ isUi() {
19
+ return this.manifest.application.type === APP_TYPES.UI;
20
+ }
21
+
22
+ isJs() {
23
+ return this.isUi() || this.isNode();
24
+ }
25
+
26
+ isPython() {
27
+ return this.manifest.settings.runtime === APP_RUNTIMES.PYTHON3;
28
+ }
29
+ }
30
+
31
+ module.exports = { Manifest };
@@ -0,0 +1,12 @@
1
+ class StepError extends Error {
2
+ cause;
3
+ name;
4
+
5
+ constructor(message, { cause } = {}) {
6
+ super(message);
7
+ this.name = 'StepError';
8
+ this.cause = cause;
9
+ }
10
+ }
11
+
12
+ module.exports = { StepError };
@@ -0,0 +1,8 @@
1
+ const { LOAD_APP_FILES_STEP } = require('./steps/prepare-load-app-files');
2
+
3
+ const PREPARE_FLOW = {
4
+ name: 'prepare',
5
+ steps: [LOAD_APP_FILES_STEP],
6
+ };
7
+
8
+ module.exports = { PREPARE_FLOW };
@@ -0,0 +1,18 @@
1
+ const { PREPARE_FLOW } = require('./prepare');
2
+ const { GET_APP_KEY_STEP } = require('./steps/release-get-app-key');
3
+ const { GET_RELEASE_CONFIG_STEP } = require('./steps/release-get-config');
4
+ const { UPLOAD_ZIP_TO_CORVA_STEP } = require('./steps/release-upload-zip-to-corva');
5
+ const { ZIP_SIMPLE_FLOW } = require('./zip-simple');
6
+
7
+ const RELEASE_FLOW = {
8
+ name: 'release',
9
+ steps: [
10
+ PREPARE_FLOW,
11
+ GET_RELEASE_CONFIG_STEP,
12
+ GET_APP_KEY_STEP,
13
+ ZIP_SIMPLE_FLOW,
14
+ UPLOAD_ZIP_TO_CORVA_STEP,
15
+ ],
16
+ };
17
+
18
+ module.exports = { RELEASE_FLOW };
@@ -0,0 +1,18 @@
1
+ const { loadJson } = require('../lib/json');
2
+ const { Manifest } = require('../lib/manifest');
3
+
4
+ const LOAD_APP_FILES_STEP = {
5
+ message: "Loading Corva app's files...",
6
+ async fn(context) {
7
+ const manifest =
8
+ context.manifest || new Manifest(await loadJson(context.dirName, 'manifest.json'));
9
+ const pkg =
10
+ context.package || (manifest.isJs() && (await loadJson(context.dirName, 'package.json')));
11
+
12
+ return { pkg, manifest };
13
+ },
14
+ };
15
+
16
+ module.exports = {
17
+ LOAD_APP_FILES_STEP,
18
+ };
@@ -0,0 +1,16 @@
1
+ const { RELEASE } = require('../../constants/messages');
2
+
3
+ const GET_APP_KEY_STEP = {
4
+ message: RELEASE.getAppKey,
5
+ fn: ({ manifest }) => {
6
+ const appKey = manifest.manifest.application.key;
7
+
8
+ if (!appKey) {
9
+ throw new Error(RELEASE.getAppKeyError);
10
+ }
11
+
12
+ return { appKey };
13
+ },
14
+ };
15
+
16
+ module.exports = { GET_APP_KEY_STEP };
@@ -0,0 +1,30 @@
1
+ const { RELEASE } = require('../../constants/messages');
2
+ const { promises: fs } = require('fs');
3
+ const dotenv = require('dotenv');
4
+ const { resolve } = require('path');
5
+ const { StepError } = require('../lib/step-error');
6
+
7
+ const GET_RELEASE_CONFIG_STEP = {
8
+ message: RELEASE.getAuthToken,
9
+ fn: async ({ dirName }) => {
10
+ const env = await fs.readFile(resolve(dirName, '.env')).catch((e) => {
11
+ if (e.code === 'ENOENT') {
12
+ throw new StepError('Mising .env file', { cause: e });
13
+ }
14
+
15
+ throw e;
16
+ });
17
+ const { CORVA_API_ENV, AUTH_TOKEN } = dotenv.parse(env);
18
+
19
+ if (!AUTH_TOKEN) {
20
+ throw new StepError(RELEASE.getAuthTokenError);
21
+ }
22
+
23
+ return {
24
+ CORVA_API_ENV: CORVA_API_ENV || 'production',
25
+ AUTH_TOKEN,
26
+ };
27
+ },
28
+ };
29
+
30
+ module.exports = { GET_RELEASE_CONFIG_STEP };
@@ -0,0 +1,34 @@
1
+ const { RELEASE } = require('../../constants/messages');
2
+ const axios = require('axios');
3
+ const FormData = require('form-data');
4
+ const { resolve } = require('path');
5
+ const { createReadStream } = require('fs');
6
+ const { StepError } = require('../lib/step-error');
7
+ const { get } = require('lodash/fp');
8
+
9
+ const UPLOAD_ZIP_TO_CORVA_STEP = {
10
+ message: RELEASE.uploadApp,
11
+ fn: async ({ zipFileName, appKey, CORVA_API_ENV, AUTH_TOKEN, dirName }) => {
12
+ const form = new FormData();
13
+
14
+ form.append('package', createReadStream(resolve(dirName, zipFileName)), 'archive.zip');
15
+
16
+ const baseURL = `https://api${
17
+ CORVA_API_ENV === 'production' ? '' : `.${CORVA_API_ENV}`
18
+ }.corva.ai`;
19
+ const uploadURL = `${baseURL}/v2/apps/${appKey}/packages/upload`;
20
+
21
+ await axios
22
+ .post(uploadURL, form, {
23
+ headers: { ...form.getHeaders(), Authorization: `Bearer ${AUTH_TOKEN}` },
24
+ })
25
+ .catch((e) => {
26
+ throw new StepError(
27
+ `${get('response.data.message', e) || ''} \nPOST: ${uploadURL} failed.`,
28
+ { cause: e }
29
+ );
30
+ });
31
+ },
32
+ };
33
+
34
+ module.exports = { UPLOAD_ZIP_TO_CORVA_STEP };