@sap/cds-dk 7.4.0 → 7.5.0

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 (179) hide show
  1. package/bin/activate.js +1 -1
  2. package/bin/add.js +6 -4
  3. package/bin/build.js +10 -12
  4. package/bin/cds.js +4 -1
  5. package/bin/deploy/index.js +5 -2
  6. package/bin/eval.js +1 -1
  7. package/bin/extend.js +3 -3
  8. package/bin/login.js +2 -2
  9. package/bin/logout.js +1 -1
  10. package/bin/pull.js +1 -1
  11. package/bin/push.js +5 -5
  12. package/bin/subscribe.js +2 -2
  13. package/bin/unsubscribe.js +2 -2
  14. package/bin/upgrade.js +2 -2
  15. package/bin/version.js +2 -2
  16. package/bin/watch.js +1 -1
  17. package/lib/bind/bindingUtil.js +6 -3
  18. package/lib/bind/cfKeyProvider.js +1 -1
  19. package/lib/bind/userCdsrcJsonStorageProvider.js +1 -1
  20. package/lib/build/buildPlugin.js +6 -12
  21. package/lib/build/buildTaskEngine.js +24 -19
  22. package/lib/build/buildTaskFactory.js +27 -33
  23. package/lib/build/buildTaskProvider.js +1 -1
  24. package/lib/build/buildTaskProviderFactory.js +26 -41
  25. package/lib/build/constants.js +0 -1
  26. package/lib/build/index.js +3 -3
  27. package/lib/build/plugins.js +15 -15
  28. package/lib/build/provider/edmxBuildPlugin.js +6 -7
  29. package/lib/build/provider/fiori/index.js +8 -8
  30. package/lib/build/provider/hana/2migration.js +12 -16
  31. package/lib/build/provider/hana/index.js +5 -7
  32. package/lib/build/provider/hana/template/package.json +1 -1
  33. package/lib/build/provider/internalBuildPlugin.js +0 -8
  34. package/lib/build/provider/internalBuildTaskProvider.js +17 -21
  35. package/lib/build/provider/java/index.js +2 -1
  36. package/lib/build/provider/mtx-extension/index.js +8 -5
  37. package/lib/build/provider/mtx-sidecar/index.js +2 -1
  38. package/lib/build/provider/nodejs/index.js +64 -58
  39. package/lib/compile/openapi/csdl2openapi.js +29 -15
  40. package/lib/compile/openapi/index.js +6 -6
  41. package/lib/deploy/to-hana/hana.js +5 -3
  42. package/lib/env/schema.js +2 -3
  43. package/lib/index.js +68 -28
  44. package/lib/init/add.js +17 -0
  45. package/lib/init/constants.js +5 -3
  46. package/lib/init/index.js +39 -25
  47. package/lib/init/{util/merge.js → merge.js} +32 -20
  48. package/lib/init/{util/mvn.js → mvn.js} +5 -5
  49. package/lib/init/plugin.js +85 -0
  50. package/lib/init/projectReader.js +145 -0
  51. package/lib/init/registries/mta.js +151 -0
  52. package/lib/init/template/{kibana → application-logging}/files/mta.yaml.hbs +3 -3
  53. package/lib/init/template/application-logging/index.js +49 -0
  54. package/lib/init/template/approuter/files/mta.yaml.hbs +11 -11
  55. package/lib/init/template/approuter/files/xs-app.json.hbs +2 -2
  56. package/lib/init/template/approuter/index.js +36 -81
  57. package/lib/init/template/cf-manifest/files/manifest.yml.hbs +3 -3
  58. package/lib/init/template/cf-manifest/files/services-manifest.yml.hbs +4 -4
  59. package/lib/init/template/cf-manifest/index.js +4 -4
  60. package/lib/init/template/connectivity/index.js +22 -35
  61. package/lib/init/template/data/index.js +3 -2
  62. package/lib/init/template/destination/files/values.yaml +9 -0
  63. package/lib/init/template/destination/index.js +15 -47
  64. package/lib/init/template/enterprise-messaging/index.js +26 -58
  65. package/lib/init/template/enterprise-messaging-shared/index.js +23 -39
  66. package/lib/init/template/extensibility/index.js +16 -30
  67. package/lib/init/template/file-based-messaging/index.js +7 -8
  68. package/lib/init/template/h2/index.js +4 -4
  69. package/lib/init/template/hana/files/mta.yaml.hbs +8 -8
  70. package/lib/init/template/hana/index.js +29 -115
  71. package/lib/init/template/helm/files/chart/templates/NOTES.txt +12 -0
  72. package/lib/init/template/helm/files/chart/templates/_deployment_helpers.tpl +82 -0
  73. package/lib/init/template/helm/files/chart/templates/_helpers.tpl +28 -0
  74. package/lib/init/template/helm/files/chart/values.root.schema.json +61 -0
  75. package/lib/init/template/helm/files/chart/values.schema.json +366 -0
  76. package/lib/init/template/helm/{subcharts → files}/web-application/Chart.yaml +1 -1
  77. package/lib/init/template/helm/{subcharts → files}/web-application/templates/_api.tpl +1 -1
  78. package/lib/init/template/helm/{subcharts → files}/web-application/values.yaml +1 -1
  79. package/lib/init/template/helm/index.js +84 -85
  80. package/lib/init/template/helm-unified-runtime/files/Chart.yaml.hbs +10 -0
  81. package/lib/init/template/helm-unified-runtime/files/values.yaml.hbs +26 -0
  82. package/lib/init/template/helm-unified-runtime/index.js +91 -0
  83. package/lib/init/template/helm-unified-runtime/lib/build.js +0 -0
  84. package/lib/init/template/helm-unified-runtime/package.json +4 -0
  85. package/lib/init/template/html5-repo/files/values.yaml.hbs +28 -0
  86. package/lib/init/template/html5-repo/index.js +23 -97
  87. package/lib/init/template/java/index.js +3 -3
  88. package/lib/init/template/lint/index.js +2 -2
  89. package/lib/init/template/liquibase/index.js +16 -0
  90. package/lib/init/template/local-messaging/index.js +7 -8
  91. package/lib/init/template/mta/index.js +7 -19
  92. package/lib/init/template/mtx/index.js +2 -2
  93. package/lib/init/template/multitenancy/index.js +38 -89
  94. package/lib/init/template/nodejs/index.js +5 -4
  95. package/lib/init/template/notebook/index.js +1 -1
  96. package/lib/init/template/notifications/index.js +16 -19
  97. package/lib/init/template/pipeline/index.js +1 -1
  98. package/lib/init/template/postgres/index.js +25 -31
  99. package/lib/init/template/redis-messaging/index.js +23 -27
  100. package/lib/init/template/sample/index.js +4 -4
  101. package/lib/init/template/samples/index.js +2 -2
  102. package/lib/init/template/sqlite/files/{package.json.hbs → package.json} +0 -2
  103. package/lib/init/template/sqlite/index.js +6 -10
  104. package/lib/init/template/tiny-sample/index.js +6 -6
  105. package/lib/init/template/toggles/index.js +7 -8
  106. package/lib/init/template/typer/index.js +6 -6
  107. package/lib/init/template/xsuaa/files/mta.yaml.hbs +3 -3
  108. package/lib/init/template/xsuaa/files/values.yaml.hbs +3 -3
  109. package/lib/init/template/xsuaa/index.js +27 -52
  110. package/lib/init/{util/template.js → template.js} +1 -1
  111. package/lib/{client → mtx}/activate.js +15 -11
  112. package/lib/{client → mtx}/auth_manager.js +5 -4
  113. package/lib/{client → mtx}/download_legacy.js +6 -4
  114. package/lib/{client → mtx}/extend.js +14 -9
  115. package/lib/{client → mtx}/index.js +1 -1
  116. package/lib/{client → mtx}/params.js +4 -1
  117. package/lib/{client → mtx}/pull.js +6 -4
  118. package/lib/{client → mtx}/push.js +11 -10
  119. package/lib/{client → mtx}/settings_manager.js +8 -6
  120. package/lib/{client → mtx}/tenant_action.js +9 -8
  121. package/lib/{client/helper/cf_helper.js → mtx/util/cf.js} +4 -3
  122. package/lib/{client/helper/dependency_helper.js → mtx/util/dependencies.js} +1 -0
  123. package/lib/mtx/util/errors.js +27 -0
  124. package/lib/mtx/util/legacy_ext.js +16 -0
  125. package/lib/{client/helper/url_helper.js → mtx/util/urls.js} +12 -1
  126. package/lib/util/fs.js +5 -1
  127. package/lib/util/pruneAxiosErrors.js +35 -18
  128. package/lib/util/write.js +1 -1
  129. package/npm-shrinkwrap.json +27 -27
  130. package/package.json +10 -1
  131. package/lib/client/base_command.js +0 -54
  132. package/lib/init/template/_merging/registry-mta.js +0 -304
  133. package/lib/init/template/helm/Model.d.ts +0 -53
  134. package/lib/init/template/kibana/files/package.json.hbs +0 -17
  135. package/lib/init/template/kibana/index.js +0 -54
  136. package/lib/init/template/templateBase.js +0 -100
  137. package/lib/init/util/md5.js +0 -86
  138. package/lib/init/util/projectReader.js +0 -94
  139. /package/lib/init/{util/indent.js → indent.js} +0 -0
  140. /package/lib/init/template/helm/{subcharts → files}/content-deployment/Chart.yaml +0 -0
  141. /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/_helpers.tpl +0 -0
  142. /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/job.yaml +0 -0
  143. /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/secret.yaml +0 -0
  144. /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/service-account.yaml +0 -0
  145. /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/service-binding.yaml +0 -0
  146. /package/lib/init/template/helm/{subcharts → files}/content-deployment/values.schema.json +0 -0
  147. /package/lib/init/template/helm/{subcharts → files}/content-deployment/values.yaml +0 -0
  148. /package/lib/init/template/helm/{subcharts → files}/service-instance/Chart.yaml +0 -0
  149. /package/lib/init/template/helm/{subcharts → files}/service-instance/templates/_helpers.tpl +0 -0
  150. /package/lib/init/template/helm/{subcharts → files}/service-instance/templates/serviceinstance.yaml +0 -0
  151. /package/lib/init/template/helm/{subcharts → files}/service-instance/values.schema.json +0 -0
  152. /package/lib/init/template/helm/{subcharts → files}/service-instance/values.yaml +0 -0
  153. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/NOTES.txt +0 -0
  154. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/_helpers.tpl +0 -0
  155. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/api-rule.yaml +0 -0
  156. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/deployment.yaml +0 -0
  157. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/network-policy.yaml +0 -0
  158. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/pod-disruption-budget.yaml +0 -0
  159. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/rbac.yaml +0 -0
  160. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/secret.yaml +0 -0
  161. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/service-account.yaml +0 -0
  162. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/service-binding.yaml +0 -0
  163. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/service.yaml +0 -0
  164. /package/lib/init/template/helm/{subcharts → files}/web-application/templates/virtual-service.yaml +0 -0
  165. /package/lib/init/template/helm/{subcharts → files}/web-application/values.schema.json +0 -0
  166. /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/templates/NOTES.txt +0 -0
  167. /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/templates/_deployment_helpers.tpl +0 -0
  168. /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/templates/_helpers.tpl +0 -0
  169. /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/values.root.schema.json +0 -0
  170. /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/values.schema.json +0 -0
  171. /package/lib/init/template/postgres/files/{mta.yaml.hbs → mta.yml.hbs} +0 -0
  172. /package/lib/init/{util/xml.js → xml.js} +0 -0
  173. /package/lib/{client/helper/env_helper.js → mtx/util/env.js} +0 -0
  174. /package/lib/{client/helper/fs_helper.js → mtx/util/fs.js} +0 -0
  175. /package/lib/{client/helper → mtx/util}/logging.js +0 -0
  176. /package/lib/{client/helper → mtx/util}/question.js +0 -0
  177. /package/lib/{client/helper/string_helper.js → mtx/util/strings.js} +0 -0
  178. /package/lib/util/{cfUtil.js → cf.js} +0 -0
  179. /package/lib/util/{gitUtil.js → git.js} +0 -0
@@ -1,87 +1,62 @@
1
- const { join } = require('path')
2
1
  const cds = require('../../../cds')
3
2
  const { read } = cds.utils
4
- const { readProject } = require('../../util/projectReader')
5
- const { mergeJSON, mergeYAML } = require('../../util/merge')
6
- const { parseMd5File, writeMd5File } = require('../../util/md5')
7
- const { srvNode4, srvJava4, xsuaa, mtxSidecar4 } = require('../_merging/registry-mta')
3
+ const term = require('../../../util/term')
4
+ const { readProject } = require('../../projectReader')
5
+ const { merge } = require('../../merge')
6
+ const { srv4, xsuaa, mtxSidecar4 } = require('../../registries/mta')
8
7
 
9
- module.exports = class XsuaaTemplate extends require('../templateBase') {
8
+ module.exports = class XsuaaTemplate extends require('../../plugin') {
10
9
 
11
- static hasFacet(env) {
10
+ static hasInProduction(env) {
12
11
  return env.requires?.auth?.kind === 'xsuaa'
13
12
  }
14
13
 
15
- getRelatedFacets() {
16
- return ['multitenancy', 'extensibility', 'enterprise-messaging']
17
- }
18
-
19
14
  async run() {
20
- const project = await readProject()
15
+ const project = readProject()
21
16
  const { configFile } = project
22
17
  project.shortcut = !(await read(configFile)).cds?.requires?.auth?.kind
23
- await mergeJSON(configFile, join(__dirname, 'files', 'package.json.hbs'), project, { forceOverwrite: true })
18
+ await merge(__dirname, 'files/package.json.hbs').into(configFile, { project, forceOverwrite: true })
24
19
  }
25
20
 
26
- async runDependentMerging( context = {}) {
27
- const project = await readProject()
28
- const { isMultitenant, hasMta, hasHelm, isJava, srvPath } = project
21
+ async combine() {
22
+ const project = readProject()
23
+ const { hasMultitenancy, hasMta, hasHelm, hasHelmUnifiedRuntime, isJava, srvPath } = project
29
24
 
30
25
  const cds = require('../../../../lib')
31
26
  const xsSecurity = await (async () => { try {
32
27
  const models = await cds.load(cds.env.folders.srv)
33
28
  return cds.compile.to.xsuaa(models)
34
- } catch (error) { /* ignore */ }
35
- })() || { scopes: [], attributes: [], 'role-templates': [], 'authorities-inheritance': false }
36
- const mergingSemantics = { additions: xsSecurity.scopes.map(scope => ({
37
- in: 'scopes',
38
- where: [{
39
- property: 'name',
40
- isEqualTo: scope.name
41
- }],
42
- }))}
43
- await mergeJSON('xs-security.json', xsSecurity, project, mergingSemantics)
29
+ } catch (error) { /* ignore */ }})() ?? { scopes: [], attributes: [], 'role-templates': [], 'authorities-inheritance': false }
30
+
31
+ const additions = xsSecurity.scopes.map(scope => ({ in: 'scopes', where: { name: scope.name } }))
32
+ await merge(xsSecurity).into('xs-security.json', { project, additions })
44
33
 
45
34
  if (hasMta) {
46
- const srv = (isJava ? srvJava4 : srvNode4)(srvPath)
35
+ const srv = srv4(srvPath)
47
36
  const additions = [srv, xsuaa]
48
37
  const mtxSidecar = mtxSidecar4(isJava ? 'mtx/sidecar' : 'gen/mtx/sidecar')
49
- if (isMultitenant && isJava) additions.push(mtxSidecar)
38
+ if (hasMultitenancy && isJava) additions.push(mtxSidecar)
50
39
 
51
40
  const relationships = [{
52
41
  insert: [xsuaa, 'name'],
53
42
  into: [srv, 'requires', 'name']
54
43
  }]
55
- if (isMultitenant) relationships.push({
44
+ if (hasMultitenancy) relationships.push({
56
45
  insert: [xsuaa, 'name'],
57
46
  into: [mtxSidecar, 'requires', 'name']
58
47
  })
59
-
60
- await mergeYAML('mta.yaml', join(__dirname, 'files', 'mta.yaml.hbs'), project, { additions, relationships })
48
+ await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', { project, additions, relationships })
61
49
  }
62
50
 
63
- if (hasHelm) {
64
- //in case facet is being added to the already exisiting charts folder
65
- let isIndependentCommand = false;
66
- if(Object.keys(context).length == 0){
67
- isIndependentCommand = true;
68
- context.oldTrackingData = context.newTrackingData = await parseMd5File(join('chart', '.cds-add-helm-files.md5'));
69
- }
70
-
71
- // copy service-instance chart
72
- const HelmTemplate = require(`../helm`);
73
- const helmTemplate = new HelmTemplate(context.oldTrackingData, context.newTrackingData);
74
- isIndependentCommand = isIndependentCommand | await helmTemplate.addSubChart('service-instance');
75
-
76
- // add dependency entry in chart.yaml
77
- await helmTemplate.addDependency('service-instance', 'xsuaa');
51
+ if (hasHelm || hasHelmUnifiedRuntime) {
52
+ await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project })
53
+ }
54
+ }
78
55
 
79
- await mergeYAML(
80
- join('chart', 'values.yaml'),
81
- join(__dirname, 'files', 'values.yaml.hbs'),
82
- project
83
- )
84
- if(isIndependentCommand) await writeMd5File(join('chart', '.cds-add-helm-files.md5'), context.newTrackingData);
56
+ finalize() {
57
+ const { hasUI, hasApprouter } = readProject()
58
+ if (hasUI && !hasApprouter) {
59
+ console.log(`\nAlso run ${term.bold('cds add approuter --for production')} to route and authenticate the paths accessed via the UI.`)
85
60
  }
86
61
  }
87
62
  }
@@ -1,5 +1,5 @@
1
1
  const Mustache = require('mustache')
2
- const cds = require('../../cds')
2
+ const cds = require('../cds')
3
3
  const { copy, read, write, exists, readdir, path, isdir } = cds.utils
4
4
 
5
5
  async function renderAndCopy(from, into, replacements, overwrite = cds.cli.options.force) {
@@ -3,12 +3,16 @@ const path = require('path');
3
3
  const axios = require('axios');
4
4
 
5
5
  const cds = require('../cds');
6
- const DEBUG = cds.debug('cli');
7
- const { collectFileContent, collectFiles, toUnixPath } = require('./helper/fs_helper');
8
- const { getMessage } = require('./helper/logging');
9
-
10
6
  const AuthManager = require('./auth_manager');
11
- const BaseCommand = require('./base_command');
7
+
8
+ require('../util/pruneAxiosErrors');
9
+ const { collectFileContent, collectFiles, toUnixPath } = require('./util/fs');
10
+ const { getMessage } = require('./util/logging');
11
+ const { handleHttpError } = require('./util/errors');
12
+ const { concatUrls } = require('./util/urls');
13
+ const { checkProject, getMtxApiUrl } = require('./util/legacy_ext');
14
+
15
+ const DEBUG = cds.debug('cli');
12
16
 
13
17
  const COMMAND_URL_SUFFIX = 'asyncActivate';
14
18
  const COMMAND_URL_SUFFIX_SYNC = 'activate';
@@ -37,7 +41,7 @@ async function checkFinished(jobId, statusUrl, params, finisher) {
37
41
  }
38
42
  }
39
43
 
40
- module.exports = class Activate extends BaseCommand {
44
+ module.exports = class Activate {
41
45
 
42
46
  static get COMMAND_URL_SUFFIX() { return COMMAND_URL_SUFFIX; }
43
47
  static get COMMAND_URL_SUFFIX_SYNC() { return COMMAND_URL_SUFFIX_SYNC; }
@@ -57,7 +61,7 @@ module.exports = class Activate extends BaseCommand {
57
61
  console.log('Activating extension located at', params.get('projectFolder'), 'to URL', params.get('appUrl'));
58
62
  }
59
63
 
60
- if (!await this.checkProject(params.get('projectFolder'))) {
64
+ if (!await checkProject(params.get('projectFolder'))) {
61
65
  throw params.get('projectFolder') + ' is not a valid extension project';
62
66
  }
63
67
 
@@ -67,7 +71,7 @@ module.exports = class Activate extends BaseCommand {
67
71
  await this.runCustomFileUpload(params);
68
72
  }
69
73
  } catch (error) {
70
- this.handleHttpError(error, params, { command: 'activate' });
74
+ handleHttpError(error, params, { command: 'activate' });
71
75
  }
72
76
  }
73
77
 
@@ -163,7 +167,7 @@ module.exports = class Activate extends BaseCommand {
163
167
  console.log('Activating extension...');
164
168
 
165
169
  const urlSuffix = isSync ? this.COMMAND_URL_SUFFIX_SYNC : this.COMMAND_URL_SUFFIX;
166
- activationUrl = this.getMtxApiUrl(params.get('appUrl'), urlSuffix);
170
+ activationUrl = getMtxApiUrl(params.get('appUrl'), urlSuffix);
167
171
  const requestOptions = Object.assign({
168
172
  headers: {}
169
173
  }, params.get('reqAuth'));
@@ -192,7 +196,7 @@ module.exports = class Activate extends BaseCommand {
192
196
  DEBUG?.(`Job ID: ${jobId}`);
193
197
 
194
198
  return new Promise((resolve, reject) => {
195
- const statusUrl = this.concatUrls(params.get('appUrl'), statusPath);
199
+ const statusUrl = concatUrls(params.get('appUrl'), statusPath);
196
200
  const finisher = {
197
201
  resolve,
198
202
  reject,
@@ -218,7 +222,7 @@ module.exports = class Activate extends BaseCommand {
218
222
  });
219
223
  });
220
224
 
221
- const customFileUrl = this.getMtxApiUrl(params.get('appUrl'), this.UPDATE_CUSTOM_FILE_URL_SUFFIX);
225
+ const customFileUrl = getMtxApiUrl(params.get('appUrl'), this.UPDATE_CUSTOM_FILE_URL_SUFFIX);
222
226
  const requestOptions = Object.assign({
223
227
  headers: {},
224
228
  }, params.get('reqAuth'));
@@ -1,12 +1,13 @@
1
1
  const axios = require('axios');
2
2
 
3
- require('../util/pruneAxiosErrors');
4
-
5
3
  const cds = require('../cds');
6
- const DEBUG = cds.debug('cli');
7
4
  const { SettingsManager } = require('./settings_manager');
8
5
  const { ParamCollection } = require('./params');
9
- const { getMessage } = require('./helper/logging');
6
+
7
+ require('../util/pruneAxiosErrors');
8
+ const { getMessage } = require('./util/logging');
9
+
10
+ const DEBUG = cds.debug('cli');
10
11
 
11
12
  function addTokenInfo(params, authData) {
12
13
  params.set('token', authData.access_token);
@@ -3,11 +3,13 @@ const { join } = require('path');
3
3
  const axios = require('axios');
4
4
 
5
5
  const { login } = require('./auth_manager');
6
- const BaseCommand = require('./base_command');
6
+
7
+ require('../util/pruneAxiosErrors');
8
+ const { handleHttpError } = require('./util/errors');
7
9
 
8
10
  const DOWNLOAD_FILE_NAME = 'migrated_projects.tgz'; // TODO try to add tenant later, if possible
9
11
 
10
- module.exports = class Download extends BaseCommand {
12
+ module.exports = class Download {
11
13
 
12
14
  static async run(paramValues) {
13
15
  const params = await login(paramValues);
@@ -15,7 +17,7 @@ module.exports = class Download extends BaseCommand {
15
17
  const projectFolder = params.get('projectFolder');
16
18
  const downloadPath = join(projectFolder, DOWNLOAD_FILE_NAME);
17
19
 
18
- if (fs.existsSync(downloadPath) && !(await require('./helper/question').askBooleanQuestion(`File ${DOWNLOAD_FILE_NAME} already exists. Continue (yN)? `, false, false))) {
20
+ if (fs.existsSync(downloadPath) && !(await require('./util/question').askBooleanQuestion(`File ${DOWNLOAD_FILE_NAME} already exists. Continue (yN)? `, false, false))) {
19
21
  console.log('Download cancelled');
20
22
  return;
21
23
  }
@@ -35,6 +37,6 @@ module.exports = class Download extends BaseCommand {
35
37
 
36
38
  return axios.post(downloadUrl, { tagRule, defaultTag }, options)
37
39
  .then(response => Buffer.from(response.data))
38
- .catch(error => this.handleHttpError(error, params, { url: downloadUrl }));
40
+ .catch(error => handleHttpError(error, params, { url: downloadUrl }));
39
41
  }
40
42
  }
@@ -3,12 +3,16 @@ const path = require('path');
3
3
  const axios = require('axios');
4
4
 
5
5
  const AuthManager = require('./auth_manager');
6
- const BaseCommand = require('./base_command');
7
- const { normalizePath, isParent } = require('./helper/fs_helper');
8
- const Question = require('./helper/question');
9
- const { getMessage } = require('./helper/logging');
6
+
7
+ require('../util/pruneAxiosErrors');
8
+ const { normalizePath, isParent } = require('./util/fs');
9
+ const Question = require('./util/question');
10
+ const { getMessage } = require('./util/logging');
11
+ const { handleHttpError } = require('./util/errors');
12
+ const { checkProject, getMtxApiUrl } = require('./util/legacy_ext');
10
13
 
11
14
  const COMMAND_URL_SUFFIX = 'content';
15
+ const CUSTOM_FILE_URL_SUFFIX = 'customTenantContent';
12
16
  const CUSTOM_FILE_FOLDERS = ['wsdl'];
13
17
  const DB_FOLDER = 'db';
14
18
  const SRV_FOLDER = 'srv';
@@ -19,9 +23,10 @@ function folderExists(folder) {
19
23
  '\nWhen using --force, make sure you are using a version control system (like git) to avoid data loss';
20
24
  }
21
25
 
22
- module.exports = class Extend extends BaseCommand {
26
+ module.exports = class Extend {
23
27
 
24
28
  static get COMMAND_URL_SUFFIX() { return COMMAND_URL_SUFFIX; }
29
+ static get CUSTOM_FILE_URL_SUFFIX() { return CUSTOM_FILE_URL_SUFFIX; }
25
30
 
26
31
  static async storeFiles(content, targetDirectory, filter) {
27
32
  fs.mkdirSync(targetDirectory, { recursive: true });
@@ -85,7 +90,7 @@ module.exports = class Extend extends BaseCommand {
85
90
  console.log('\n\nCreating extension project for', params.get('appUrl'), 'subdomain', params.get('subdomain'), 'in folder', params.get('projectFolder'));
86
91
  }
87
92
 
88
- const runOnExistingProject = await Extend.checkProject(params.get('projectFolder'));
93
+ const runOnExistingProject = await checkProject(params.get('projectFolder'));
89
94
  if (runOnExistingProject && !(params.get('force') || params.get('templates'))) {
90
95
  throw getMessage(folderExists(params.get('projectFolder')), { command: 'extend' });
91
96
  }
@@ -93,12 +98,12 @@ module.exports = class Extend extends BaseCommand {
93
98
  try {
94
99
  await Extend.runExtend(params);
95
100
  } catch (error) {
96
- await Extend.handleHttpError(error, params, { command: 'extend' });
101
+ await handleHttpError(error, params, { command: 'extend' });
97
102
  }
98
103
  }
99
104
 
100
105
  static async runExtend(params) {
101
- const contentUrl = Extend.getMtxApiUrl(params.get('appUrl'), COMMAND_URL_SUFFIX);
106
+ const contentUrl = getMtxApiUrl(params.get('appUrl'), COMMAND_URL_SUFFIX);
102
107
  const requestOptions = Object.assign({ retry: 0 }, params.get('reqAuth'));
103
108
 
104
109
  console.log('Retrieving files...');
@@ -134,7 +139,7 @@ module.exports = class Extend extends BaseCommand {
134
139
 
135
140
  if (params.get('wsdl')) {
136
141
  console.log('Writing custom files');
137
- const customFileUrl = Extend.getMtxApiUrl(params.get('appUrl'), Extend.CUSTOM_FILE_URL_SUFFIX);
142
+ const customFileUrl = getMtxApiUrl(params.get('appUrl'), CUSTOM_FILE_URL_SUFFIX);
138
143
  const customFiles = (await axios.get(customFileUrl, requestOptions)).data;
139
144
  await Extend.storeCustomFiles(params.get('projectFolder'), customFiles);
140
145
  }
@@ -1,8 +1,8 @@
1
1
  const Activate = require('./activate');
2
2
  const AuthManager = require('./auth_manager');
3
3
  const Extend = require('./extend');
4
- const Question = require('./helper/question');
5
4
  const { SettingsManager } = require('./settings_manager');
5
+ const Question = require('./util/question');
6
6
 
7
7
  module.exports = {
8
8
  extend: Extend.run,
@@ -1,6 +1,8 @@
1
1
  const cds = require('../cds');
2
+
3
+ const { escapeRegex } = require('./util/strings');
4
+
2
5
  const DEBUG = cds.debug('cli');
3
- const { escapeRegex } = require('./helper/string_helper');
4
6
 
5
7
 
6
8
  // PARAM BASE TYPES
@@ -216,6 +218,7 @@ class AllParams extends BasicParams {
216
218
  this.undeploy = new Param('undeploy', false);
217
219
  this.wsdl = new Param('wsdl', false);
218
220
  this.sync = new Param('sync', false);
221
+ this.async = new Param('async', false);
219
222
 
220
223
  // `login` PARAMS
221
224
  this.skipToken = new Param('skipToken', false, { internal: true });
@@ -6,10 +6,12 @@ const { join } = require('path');
6
6
  const axios = require('axios');
7
7
 
8
8
  const { login } = require('./auth_manager');
9
- const BaseCommand = require('./base_command');
10
- const { getMessage } = require('./helper/logging');
11
9
 
12
- module.exports = class Pull extends BaseCommand {
10
+ require('../util/pruneAxiosErrors');
11
+ const { getMessage } = require('./util/logging');
12
+ const { handleHttpError } = require('./util/errors');
13
+
14
+ module.exports = class Pull {
13
15
 
14
16
  static async run(paramValues) {
15
17
  if (!tar) {
@@ -46,7 +48,7 @@ module.exports = class Pull extends BaseCommand {
46
48
 
47
49
  return axios.post(pullUrl, {}, options)
48
50
  .then(response => Buffer.from(response.data))
49
- .catch(error => this.handleHttpError(error, params, { url: pullUrl }));
51
+ .catch(error => handleHttpError(error, params, { url: pullUrl }));
50
52
  }
51
53
 
52
54
  static getPackageJsonIndentation(packageContents) {
@@ -4,11 +4,13 @@ const { readFileSync, existsSync } = require('fs');
4
4
  const axios = require('axios');
5
5
 
6
6
  const { login } = require('./auth_manager');
7
- const BaseCommand = require('./base_command');
8
- const { getMessage } = require('./helper/logging');
9
- const { schemaRegex } = require('./helper/url_helper');
10
7
  const buildSystem = require('../build')
11
8
 
9
+ require('../util/pruneAxiosErrors');
10
+ const { getMessage } = require('./util/logging');
11
+ const { schemaRegex } = require('./util/urls');
12
+ const { handleHttpError } = require('./util/errors');
13
+
12
14
  const JOB_STATUS = {
13
15
  QUEUED: 'QUEUED',
14
16
  RUNNING: 'RUNNING',
@@ -16,7 +18,7 @@ const JOB_STATUS = {
16
18
  FAILED: 'FAILED'
17
19
  };
18
20
 
19
- module.exports = class Push extends BaseCommand {
21
+ module.exports = class Push {
20
22
 
21
23
  static async run(paramValues, pushOptions = {}) {
22
24
  const params = await login(paramValues);
@@ -35,8 +37,7 @@ module.exports = class Push extends BaseCommand {
35
37
 
36
38
  console.log(`\nPushing extension '${extensionName}' from`, { src }, 'to', target);
37
39
  const push = await this.pushTgz(params, content, extensionName);
38
- const async = !params.get('sync');
39
- if (async) {
40
+ if (params.get('async')) {
40
41
  await this.pollUntilFinished(push.headers.location, params)
41
42
  }
42
43
  console.log ('Activation succeeded.\n')
@@ -55,7 +56,7 @@ module.exports = class Push extends BaseCommand {
55
56
  try {
56
57
  content = (await axios.get(src, { responseEncoding: 'base64' })).data;
57
58
  } catch (error) {
58
- this.handleHttpError(error, params, { url: src });
59
+ handleHttpError(error, params, { url: src });
59
60
  }
60
61
  }
61
62
  return { src, content };
@@ -72,7 +73,7 @@ module.exports = class Push extends BaseCommand {
72
73
  static async pushTgz(params, tgz, extensionName) {
73
74
  const pushUrl = `${params.get('appUrl')}/-/cds/extensibility/push`;
74
75
  const options = { ...params.get('reqAuth') };
75
- const async = !params.get('sync');
76
+ const async = params.get('async');
76
77
  if (async) {
77
78
  options.headers = { prefer: 'respond-async', ...options.headers }
78
79
  }
@@ -81,7 +82,7 @@ module.exports = class Push extends BaseCommand {
81
82
  extension: tgz,
82
83
  tag: extensionName
83
84
  }, options)
84
- .catch(error => this.handleHttpError(error, params, { url: pushUrl }));
85
+ .catch(error => handleHttpError(error, params, { url: pushUrl }));
85
86
  }
86
87
 
87
88
  static async pollUntilFinished(jobUrl, params) {
@@ -94,7 +95,7 @@ module.exports = class Push extends BaseCommand {
94
95
  }, 5 * 60 * 1000);
95
96
 
96
97
  const interval = setInterval(async () => {
97
- const { status, error } = (await axios.get(jobUrl, options)).data;
98
+ const { status, error = 'cds push failed' } = (await axios.get(jobUrl, options)).data;
98
99
  if (status === JOB_STATUS.FINISHED || status === JOB_STATUS.FAILED) {
99
100
  clearInterval(interval);
100
101
  clearTimeout(timeout);
@@ -4,13 +4,15 @@ const path = require('path');
4
4
  const axios = require('axios');
5
5
 
6
6
  const cds = require('../cds');
7
+
8
+ const { requireGlobal } = require('./util/dependencies');
9
+ const { getAppFromSuggestions, getSubdomain } = require('./util/cf');
10
+ const isBas = require('./util/env');
11
+ const Question = require('./util/question');
12
+ const { httpSchema, httpsSchema, schemaRegex, localhostRegex } = require('./util/urls');
13
+ const { capitalize } = require('./util/strings');
14
+
7
15
  const DEBUG = cds.debug('cli');
8
- const { requireGlobal } = require('./helper/dependency_helper');
9
- const { getAppFromSuggestions, getSubdomain } = require('./helper/cf_helper');
10
- const isBas = require('./helper/env_helper');
11
- const Question = require('./helper/question');
12
- const { httpSchema, httpsSchema, schemaRegex, localhostRegex } = require('./helper/url_helper');
13
- const { capitalize } = require('./helper/string_helper');
14
16
 
15
17
  const { ParamCollection, Persistence } = require('./params');
16
18
 
@@ -1,11 +1,13 @@
1
1
  const cds = require('../cds');
2
- const DEBUG = cds.debug('cli');
3
-
4
- const BaseCommand = require('./base_command');
5
- const { getMessage } = require('./helper/logging');
6
2
  const { ParamCollection } = require('./params');
7
3
  const AuthManager = require('./auth_manager');
8
- const { capitalize } = require('./helper/string_helper');
4
+
5
+ require('../util/pruneAxiosErrors');
6
+ const { getMessage } = require('./util/logging');
7
+ const { capitalize } = require('./util/strings');
8
+ const { handleHttpError } = require('./util/errors');
9
+
10
+ const DEBUG = cds.debug('cli');
9
11
 
10
12
  const COMMANDS = {
11
13
  subscribe: 'to',
@@ -13,7 +15,7 @@ const COMMANDS = {
13
15
  unsubscribe: 'from'
14
16
  };
15
17
 
16
- module.exports = class TenantAction extends BaseCommand {
18
+ module.exports = class TenantAction {
17
19
 
18
20
  // TODO JSDoc
19
21
  /**
@@ -23,7 +25,6 @@ module.exports = class TenantAction extends BaseCommand {
23
25
  if (!(command in COMMANDS)) {
24
26
  throw new Error(`invalid command: ${command}`);
25
27
  }
26
- super();
27
28
  this.command = command;
28
29
  this.gerund = command.replace(/e$/, 'ing');
29
30
  this.preposition = COMMANDS[command];
@@ -50,7 +51,7 @@ module.exports = class TenantAction extends BaseCommand {
50
51
  try {
51
52
  await require('axios').post(url, { tenant }, params.get('reqAuth'));
52
53
  } catch (error) {
53
- BaseCommand.handleHttpError(error, params, { url });
54
+ handleHttpError(error, params, { url });
54
55
  }
55
56
  }
56
57
 
@@ -2,10 +2,11 @@ const os = require('os');
2
2
  const { execFile } = require('child_process');
3
3
 
4
4
  const cds = require('../../cds');
5
- const DEBUG = cds.debug('cli');
6
5
  const Question = require('./question');
7
- const { formatObjectsFixedWidth } = require('./string_helper');
8
- const { schemaRegex } = require('./url_helper');
6
+ const { formatObjectsFixedWidth } = require('./strings');
7
+ const { schemaRegex } = require('./urls');
8
+
9
+ const DEBUG = cds.debug('cli');
9
10
 
10
11
  function runCf(args, callback) {
11
12
  const env = Object.assign({}, process.env, { LC_ALL: 'en_US.UTF-8' }); // enforce English headings
@@ -2,6 +2,7 @@ const os = require('os');
2
2
  const { execFileSync } = require('child_process');
3
3
 
4
4
  const cds = require('../../cds');
5
+
5
6
  const DEBUG = cds.debug('cli');
6
7
 
7
8
  let modulesDir;
@@ -0,0 +1,27 @@
1
+ const { getMessage } = require('./logging');
2
+
3
+ function handleHttpError(error, params, { url, command } = {}) {
4
+ url = url ?? params.get('appUrl');
5
+ const prefix = `Request to ${url} failed`;
6
+ switch (error.status) {
7
+ case 401:
8
+ throw getMessage(`${prefix}: invalid authentication.\nRetry with valid passcode${
9
+ params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : ''
10
+ } or username/password (required if SaaS app is configured with mocked-auth).`, { error, command });
11
+ case 403:
12
+ throw getMessage(prefix + ': insufficient authorization. Ensure client has all necessary roles.', { error, command });
13
+ case 404:
14
+ throw getMessage(prefix + ': resource not found.', { error, command });
15
+ case 422:
16
+ // Compilation or native-extension error.
17
+ throw getMessage(prefix + '.', { error, command });
18
+ default:
19
+ // Unexpected error should be transparent to user.
20
+ delete error.status; // Purge extra property already included in message.
21
+ throw error;
22
+ }
23
+ }
24
+
25
+ module.exports = {
26
+ handleHttpError
27
+ };
@@ -0,0 +1,16 @@
1
+ const path = require('path');
2
+ const fs = require('fs').promises;
3
+
4
+ const { concatUrls } = require('./urls');
5
+ require('../../util/pruneAxiosErrors');
6
+
7
+ const MTX_URL_PATH_PREFIX = 'mtx/v1/model/';
8
+
9
+ module.exports = {
10
+ async checkProject(folder) {
11
+ return await fs.access(path.join(folder, 'package.json')).then(() => true).catch(() => false);
12
+ },
13
+ getMtxApiUrl(url, action) {
14
+ return concatUrls(url, MTX_URL_PATH_PREFIX, action);
15
+ }
16
+ }
@@ -12,10 +12,21 @@ function extractSubdomain(url) {
12
12
  return hostname.split('.')[0];
13
13
  }
14
14
 
15
+ function concatUrls(...parts) {
16
+ return parts
17
+ .map((p, i) => i === 0
18
+ ? p.replace(/\/$/ /*end slash*/, '')
19
+ : i === parts.length - 1
20
+ ? p.replace(/^\// /*begin slash*/, '')
21
+ : p.replace(/^\/|\/$/g /*both*/, ''))
22
+ .join('/');
23
+ }
24
+
15
25
  module.exports = {
16
26
  schemaRegex,
17
27
  localhostRegex,
18
28
  httpSchema,
19
29
  httpsSchema,
20
- extractSubdomain
30
+ extractSubdomain,
31
+ concatUrls
21
32
  };
package/lib/util/fs.js CHANGED
@@ -44,7 +44,11 @@ module.exports = new class FsUtil {
44
44
  const renderedFile = Mustache.render(file, project)
45
45
  return JSON.parse(renderedFile)
46
46
  }
47
- return JSON.parse(file)
47
+ try {
48
+ return JSON.parse(file)
49
+ } catch (error) {
50
+ throw new Error(error.message + '\n' + file)
51
+ }
48
52
  }
49
53
 
50
54
  async readJSONC(src) {