@sap/cds-dk 6.1.5 → 6.2.1

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 (152) hide show
  1. package/CHANGELOG.md +36 -2
  2. package/bin/cds.js +7 -5
  3. package/bin/deploy/index.js +3 -2
  4. package/bin/deploy/to-sqlite.js +4 -3
  5. package/bin/help.js +4 -0
  6. package/bin/init.js +2 -1
  7. package/bin/login.js +23 -9
  8. package/bin/mock.js +1 -0
  9. package/bin/pull.js +24 -19
  10. package/bin/push.js +20 -9
  11. package/bin/subscribe.js +40 -10
  12. package/bin/watch.js +15 -10
  13. package/lib/bind/kubernetesCredentialsProvider.js +1 -0
  14. package/lib/client/activate.js +42 -51
  15. package/lib/client/auth_manager.js +7 -8
  16. package/lib/client/base_command.js +5 -2
  17. package/lib/client/extend.js +33 -38
  18. package/lib/client/helper/cf_helper.js +11 -11
  19. package/lib/client/helper/dependency_helper.js +2 -2
  20. package/lib/client/helper/errors.js +4 -3
  21. package/lib/client/helper/logging.js +17 -23
  22. package/lib/client/params.js +5 -5
  23. package/lib/client/pull.js +19 -21
  24. package/lib/client/push.js +16 -15
  25. package/lib/client/settings_manager.js +54 -55
  26. package/lib/compile/openapi/csdl2openapi.js +18 -12
  27. package/lib/import/message.js +1 -1
  28. package/lib/import/odata/metadataconverter/MetadataConverter.js +23 -17
  29. package/lib/import/odata/v2parser.js +43 -17
  30. package/lib/import/odata/v4parser.js +77 -22
  31. package/lib/init/constants.js +5 -2
  32. package/lib/init/index.js +16 -4
  33. package/lib/init/template/_merging/registry-mta.js +13 -0
  34. package/lib/init/template/approuter/index.js +9 -0
  35. package/lib/{k8s/connectivity/templates/connectivity.yaml → init/template/auditlog/files/auditlog.yaml} +0 -0
  36. package/lib/init/template/auditlog/index.js +46 -27
  37. package/lib/{k8s/connectivity/templates → init/template/connectivity/files}/connectivity-binding.yaml +0 -0
  38. package/lib/{k8s/connectivity/templates → init/template/connectivity/files}/connectivity-proxy-info.yaml +1 -1
  39. package/lib/init/template/connectivity/files/connectivity.yaml +1 -0
  40. package/lib/init/template/connectivity/files/values.yaml.hbs +26 -0
  41. package/lib/init/template/connectivity/index.js +41 -0
  42. package/lib/init/template/data/index.js +8 -8
  43. package/lib/init/template/destinations/files/destination.yaml +1 -0
  44. package/lib/init/template/destinations/index.js +44 -0
  45. package/lib/init/template/enterprise-messaging/files/cds.package.json +10 -0
  46. package/lib/init/template/enterprise-messaging/files/cds.profile.package.json.hbs +12 -0
  47. package/lib/init/template/enterprise-messaging/files/cdsrc.json +8 -0
  48. package/lib/init/template/enterprise-messaging/files/cdsrc.json.hbs +10 -0
  49. package/lib/init/template/enterprise-messaging/files/event-mesh.yaml +1 -0
  50. package/lib/init/template/enterprise-messaging/files/mta.yaml.hbs +13 -0
  51. package/lib/init/template/enterprise-messaging/files/values.yaml +8 -0
  52. package/lib/init/template/enterprise-messaging/index.js +56 -0
  53. package/lib/init/template/extensibility/files/cdsrc.json +5 -0
  54. package/lib/init/template/extensibility/files/cdsrc.json.hbs +7 -0
  55. package/lib/init/template/extensibility/index.js +18 -13
  56. package/lib/{k8s/hana-deployer/templates → init/template/hana/files}/hana-deployer-job.yaml +0 -0
  57. package/lib/init/template/hana/files/java/{cdsrc.json.hbs → cds.json.hbs} +0 -0
  58. package/lib/init/template/hana/files/java/{profile.cdsrc.json.hbs → cds.profile.json.hbs} +0 -0
  59. package/lib/init/template/hana/files/java/cds.shortcut.json.hbs +5 -0
  60. package/lib/init/template/hana/files/java/cds.shortcut.profile.json.hbs +8 -0
  61. package/lib/init/template/hana/files/java/db/package.json +2 -1
  62. package/lib/init/template/hana/files/mta.yaml.hbs +6 -0
  63. package/lib/init/template/hana/files/nodejs/{cds.package.json.hbs → cds.json.hbs} +0 -0
  64. package/lib/init/template/hana/files/nodejs/{cds.profile.package.json.hbs → cds.profile.json.hbs} +0 -0
  65. package/lib/init/template/hana/files/nodejs/cds.shortcut.json.hbs +7 -0
  66. package/lib/init/template/hana/files/nodejs/cds.shortcut.profile.json.hbs +10 -0
  67. package/lib/init/template/hana/files/values.yaml.hbs +19 -0
  68. package/lib/init/template/hana/index.js +29 -29
  69. package/lib/{k8s → init/template/helm}/Model.d.ts +0 -0
  70. package/lib/{k8s/resources → init/template}/helm/chart/templates/NOTES.txt +0 -0
  71. package/lib/{k8s/resources → init/template}/helm/chart/templates/_deployment_helpers.tpl +0 -0
  72. package/lib/{k8s/resources → init/template}/helm/chart/templates/_helpers.tpl +4 -5
  73. package/lib/{k8s/resources → init/template}/helm/chart/templates/_sapcp_helpers.tpl +0 -0
  74. package/lib/{k8s/resources/helm/chart/schemas → init/template/helm/chart}/values.root.schema.json +0 -0
  75. package/lib/{k8s/resources/helm/chart/schemas → init/template/helm/chart}/values.schema.json +0 -0
  76. package/lib/init/template/helm/files/Chart.yaml.hbs +13 -0
  77. package/lib/init/template/helm/files/values.yaml.hbs +26 -0
  78. package/lib/init/template/helm/index.js +74 -14
  79. package/lib/{k8s/deployment → init/template/helm}/subchart/Chart.yaml +0 -0
  80. package/lib/{k8s/deployment → init/template/helm}/subchart/templates/_helpers.tpl +0 -0
  81. package/lib/{k8s/deployment → init/template/helm}/subchart/templates/api-rule.yaml +0 -0
  82. package/lib/{k8s/deployment → init/template/helm}/subchart/templates/deployment.yaml +0 -0
  83. package/lib/{k8s/deployment → init/template/helm}/subchart/templates/network-policy.yaml +0 -0
  84. package/lib/{k8s/deployment → init/template/helm}/subchart/templates/pod-disruption-budget.yaml +0 -0
  85. package/lib/{k8s/deployment → init/template/helm}/subchart/templates/secret.yaml +0 -0
  86. package/lib/{k8s/deployment → init/template/helm}/subchart/templates/service-binding.yaml +0 -0
  87. package/lib/{k8s/deployment → init/template/helm}/subchart/templates/service.yaml +0 -0
  88. package/lib/{k8s/deployment → init/template/helm}/subchart/values-lint.yaml +0 -0
  89. package/lib/{k8s/deployment → init/template/helm}/subchart/values.md +0 -0
  90. package/lib/{k8s/deployment → init/template/helm}/subchart/values.schema.json +0 -0
  91. package/lib/{k8s/deployment → init/template/helm}/subchart/values.yaml +0 -0
  92. package/lib/{k8s/html5-apps-deployer/templates → init/template/html5-repo/files}/_html5_deployment_helpers.tpl +0 -0
  93. package/lib/{k8s/html5-apps-deployer/templates → init/template/html5-repo/files}/html5-apps-deployer-job.yaml +1 -1
  94. package/lib/{k8s/html5-apps-repo-host/templates → init/template/html5-repo/files}/html5-apps-repo-host.yaml +0 -0
  95. package/lib/init/template/html5-repo/index.js +59 -0
  96. package/lib/init/template/kibana-logging/index.js +8 -0
  97. package/lib/init/template/lint/index.js +1 -4
  98. package/lib/init/template/mta/files/mta.yaml.hbs +3 -2
  99. package/lib/init/template/mta/index.js +6 -1
  100. package/lib/init/template/multitenancy/files/java/.cdsrc.json +3 -0
  101. package/lib/init/template/multitenancy/files/java/package.json +2 -6
  102. package/lib/{k8s/multitenancy/templates → init/template/multitenancy/files}/saas-registry.yaml +3 -3
  103. package/lib/init/template/multitenancy/files/xsuaa.yaml +1 -0
  104. package/lib/init/template/multitenancy/index.js +53 -26
  105. package/lib/init/template/nodejs/files/.gitignore.hbs +1 -0
  106. package/lib/init/template/templateBase.js +1 -1
  107. package/lib/init/template/xsuaa/files/values.yaml.hbs +10 -0
  108. package/lib/init/template/xsuaa/files/xsuaa.yaml +1 -0
  109. package/lib/init/template/xsuaa/index.js +34 -22
  110. package/lib/init/util/fsUtil.js +11 -5
  111. package/lib/init/util/projectReader.js +24 -32
  112. package/lib/init/util/templateUtil.js +17 -5
  113. package/lib/lint/Linter.js +9 -17
  114. package/lib/lint/checks.js +0 -1
  115. package/lib/lint/generators.js +2 -192
  116. package/lib/lint/io.js +1 -3
  117. package/lib/watch/node-watch.js +2 -2
  118. package/npm-shrinkwrap.json +1666 -873
  119. package/package.json +5 -4
  120. package/lib/init/template/helm/update/index.js +0 -28
  121. package/lib/k8s/ChartAdder.js +0 -75
  122. package/lib/k8s/ChartBuilder.js +0 -192
  123. package/lib/k8s/Context.js +0 -71
  124. package/lib/k8s/ImageUtil.js +0 -21
  125. package/lib/k8s/auditlog/index.js +0 -29
  126. package/lib/k8s/auditlog/templates/auditlog.yaml +0 -1
  127. package/lib/k8s/buildModel.js +0 -68
  128. package/lib/k8s/connectivity/index.js +0 -80
  129. package/lib/k8s/deployment/index.js +0 -79
  130. package/lib/k8s/deployment/subchart-override/templates/_web_application_helpers.tpl +0 -81
  131. package/lib/k8s/destinations/index.js +0 -40
  132. package/lib/k8s/destinations/lib.js +0 -16
  133. package/lib/k8s/destinations/templates/destinations.yaml +0 -1
  134. package/lib/k8s/docker/push.js +0 -8
  135. package/lib/k8s/event-mesh/index.js +0 -53
  136. package/lib/k8s/event-mesh/lib.js +0 -9
  137. package/lib/k8s/event-mesh/templates/event-mesh.yaml +0 -1
  138. package/lib/k8s/hana-deployer/index.js +0 -48
  139. package/lib/k8s/helm/Release.js +0 -80
  140. package/lib/k8s/html5-apps-deployer/index.js +0 -53
  141. package/lib/k8s/html5-apps-repo-host/index.js +0 -26
  142. package/lib/k8s/html5-apps-repo-host/lib.js +0 -16
  143. package/lib/k8s/index.js +0 -153
  144. package/lib/k8s/modules.js +0 -36
  145. package/lib/k8s/multitenancy/index.js +0 -24
  146. package/lib/k8s/multitenancy/lib.js +0 -25
  147. package/lib/k8s/readProject.js +0 -14
  148. package/lib/k8s/util.js +0 -186
  149. package/lib/k8s/wrapFeature.js +0 -55
  150. package/lib/k8s/xsuaa/index.js +0 -64
  151. package/lib/k8s/xsuaa/lib.js +0 -17
  152. package/lib/k8s/xsuaa/templates/xsuaa.yaml +0 -1
@@ -2,12 +2,13 @@ const fs = require('fs').promises;
2
2
  const path = require('path');
3
3
  const axios = require('axios');
4
4
 
5
- const AuthManager = require('./auth_manager');
6
- const BaseCommand = require('./base_command');
5
+ const log = require('./helper/logging');
7
6
  const { collectFileContent, collectFiles, toUnixPath } = require('./helper/fs_helper');
8
- const Logger = require('./helper/logging');
9
7
  const { CliError } = require('./helper/errors');
10
8
 
9
+ const AuthManager = require('./auth_manager');
10
+ const BaseCommand = require('./base_command');
11
+
11
12
  const COMMAND_URL_SUFFIX = 'asyncActivate';
12
13
  const COMMAND_URL_SUFFIX_SYNC = 'activate';
13
14
  const UPDATE_CUSTOM_FILE_URL_SUFFIX = 'updateCustomTenantContent';
@@ -28,9 +29,9 @@ async function checkFinished(jobId, statusUrl, params, finisher) {
28
29
  finisher.finished = true;
29
30
  clearInterval(finisher.timer);
30
31
  if (status === JOB_STATUS.FAILED) {
31
- return finisher.reject(new CliError(`Job ${jobId} failed: ${error.message || JSON.stringify(error)}`));
32
+ return finisher.reject(new CliError(`Job ${jobId} failed`, error));
32
33
  }
33
- Logger.log('Extension active');
34
+ console.log('Extension active');
34
35
  finisher.resolve();
35
36
  }
36
37
  }
@@ -42,34 +43,30 @@ module.exports = class Activate extends BaseCommand {
42
43
  static get UPDATE_CUSTOM_FILE_URL_SUFFIX() { return UPDATE_CUSTOM_FILE_URL_SUFFIX; }
43
44
 
44
45
  static async run(injection, paramValues) {
45
- try {
46
- const params = await AuthManager.login(paramValues);
47
-
48
- if (process.env.DEBUG) {
49
- Logger.log('Activating extension with parameters ' + JSON.stringify({
50
- appUrl: params.get('appUrl'),
51
- projectFolder: params.get('projectFolder'),
52
- undeploy: params.get('undeploy'),
53
- sync: params.get('sync')
54
- }));
55
- } else {
56
- Logger.log(`Activating extension located at ${params.get('projectFolder')} to URL ${params.get('appUrl')}`);
57
- }
46
+ const params = await AuthManager.login(paramValues);
47
+
48
+ if (process.env.DEBUG) {
49
+ console.log('Activating extension with parameters', JSON.stringify({
50
+ appUrl: params.get('appUrl'),
51
+ projectFolder: params.get('projectFolder'),
52
+ undeploy: params.get('undeploy'),
53
+ sync: params.get('sync')
54
+ }));
55
+ } else {
56
+ console.log('Activating extension located at', params.get('projectFolder'), 'to URL', params.get('appUrl'));
57
+ }
58
58
 
59
- if (!await this.checkProject(params.get('projectFolder'))) {
60
- throw new CliError(params.get('projectFolder') + ' is not a valid extension project');
61
- }
59
+ if (!await this.checkProject(params.get('projectFolder'))) {
60
+ throw new CliError(params.get('projectFolder') + ' is not a valid extension project');
61
+ }
62
62
 
63
- try {
64
- await this.runActivate(injection.cds, params);
65
- if (params.get('wsdl')) {
66
- await this.runCustomFileUpload(params);
67
- }
68
- } catch (error) {
69
- await this.handleHttpError(error, params);
63
+ try {
64
+ await this.runActivate(injection.cds, params);
65
+ if (params.get('wsdl')) {
66
+ await this.runCustomFileUpload(params);
70
67
  }
71
68
  } catch (error) {
72
- Logger.error(undefined, error);
69
+ await this.handleHttpError(error, params);
73
70
  }
74
71
  }
75
72
 
@@ -94,7 +91,7 @@ module.exports = class Activate extends BaseCommand {
94
91
  let allFiles = new Map();
95
92
 
96
93
  if (resolvedPaths.length < 1) {
97
- Logger.log('No extension files found');
94
+ console.warn('No extension files found');
98
95
  return allFiles;
99
96
  }
100
97
 
@@ -105,7 +102,7 @@ module.exports = class Activate extends BaseCommand {
105
102
  if (! entry.startsWith(projectFolder)) {
106
103
  /* Current file might be below the base model's node_modules, in which case compilation on server should succeed.
107
104
  Otherwise, compilation will probably fail, with this message giving a hint. */
108
- Logger.debug(`Source file outside project folder will not be uploaded: ${entry}`);
105
+ log.debug(`Source file outside project folder will not be uploaded: ${entry}`);
109
106
  return false;
110
107
  }
111
108
  const unixFilename = toUnixPath(entry);
@@ -123,8 +120,7 @@ module.exports = class Activate extends BaseCommand {
123
120
  return !(/.*node_modules\/_base\/.*/.test(unixFilename));
124
121
  });
125
122
 
126
- // FIXME remove async
127
- i18nFolders.forEach(async(folder) => {
123
+ i18nFolders.forEach(folder => {
128
124
  const i18nFiles = collectFiles(projectFolder, folder, entry => {
129
125
  const ext = path.extname(entry);
130
126
  return I18N_WHITELIST.includes(ext);
@@ -132,13 +128,13 @@ module.exports = class Activate extends BaseCommand {
132
128
  allFiles = new Map([...allFiles, ...i18nFiles]);
133
129
  });
134
130
 
131
+ let pkgJson;
135
132
  try {
136
- const pkgJson = await fs.readFile(path.join(absoluteFolder, 'package.json'), 'utf-8');
137
- allFiles.set('package.json', pkgJson);
138
- } catch(e) {
139
- Logger.log('No package.json file found');
140
- Logger.error('No package.json file found', e);
133
+ pkgJson = await fs.readFile(path.join(absoluteFolder, 'package.json'), 'utf-8');
134
+ } catch (error) {
135
+ throw new CliError('No package.json file found', error);
141
136
  }
137
+ allFiles.set('package.json', pkgJson);
142
138
 
143
139
  return allFiles;
144
140
  }
@@ -146,16 +142,11 @@ module.exports = class Activate extends BaseCommand {
146
142
  static collectCustomFiles(projectFolder) {
147
143
  const wsdlFolder = path.join(projectFolder, 'wsdl');
148
144
 
149
- try {
150
- const wsdlFiles = collectFiles(projectFolder, wsdlFolder);
151
- if (wsdlFiles.size === 0) {
152
- Logger.log('No custom files found');
153
- }
154
- return wsdlFiles;
155
- } catch (error) {
156
- Logger.error(undefined, error);
157
- throw new CliError('No custom files found');
145
+ const wsdlFiles = collectFiles(projectFolder, wsdlFolder);
146
+ if (wsdlFiles.size === 0) {
147
+ console.log('No custom files found');
158
148
  }
149
+ return wsdlFiles;
159
150
  }
160
151
 
161
152
  static async runActivate(cds, params) {
@@ -168,7 +159,7 @@ module.exports = class Activate extends BaseCommand {
168
159
  return null;
169
160
  }
170
161
 
171
- Logger.log('Activating extension...');
162
+ console.log('Activating extension...');
172
163
 
173
164
  const urlSuffix = isSync ? this.COMMAND_URL_SUFFIX_SYNC : this.COMMAND_URL_SUFFIX;
174
165
  activationUrl = this.getMtxApiUrl(params.get('appUrl'), urlSuffix);
@@ -197,7 +188,7 @@ module.exports = class Activate extends BaseCommand {
197
188
  throw new CliError(`Job ${jobId} failed: did not receive job-status path`);
198
189
  }
199
190
 
200
- Logger.debug(`Job ID: ${jobId}`);
191
+ log.debug(`Job ID: ${jobId}`);
201
192
 
202
193
  return new Promise((resolve, reject) => {
203
194
  const statusUrl = this.concatUrls(params.get('appUrl'), statusPath);
@@ -213,7 +204,7 @@ module.exports = class Activate extends BaseCommand {
213
204
  }
214
205
 
215
206
  static async runCustomFileUpload(params) {
216
- Logger.log(`Uploading custom files to ${params.get('appUrl')}...`);
207
+ console.log('Uploading custom files to', params.get('appUrl'), '...');
217
208
 
218
209
  const customFiles = this.collectCustomFiles(params.get('projectFolder'));
219
210
 
@@ -236,7 +227,7 @@ module.exports = class Activate extends BaseCommand {
236
227
  content: customFilesSerialized
237
228
  }, requestOptions);
238
229
 
239
- Logger.log('Custom file upload finished');
230
+ console.log('Custom file upload finished');
240
231
  }
241
232
 
242
233
  }
@@ -1,7 +1,6 @@
1
- const util = require('util');
2
1
  const axios = require('axios');
3
2
 
4
- const Logger = require('./helper/logging');
3
+ const log = require('./helper/logging');
5
4
  const { SettingsManager } = require('./settings_manager');
6
5
  const { ParamCollection } = require('./params');
7
6
  const { CliError } = require('./helper/errors');
@@ -40,7 +39,7 @@ function getTokenUrl(params) {
40
39
  async function retrieveTokenOrPasscodeUrl(params) {
41
40
  if (params.has('token')) {
42
41
  if (params.get('renewLogin') || params.get('tokenExpirationDate') <= Date.now()) {
43
- Logger.debug((params.get('renewLogin') ? 'Renewing' : 'Refreshing expired') + ' authentication token');
42
+ log.debug((params.get('renewLogin') ? 'Renewing' : 'Refreshing expired') + ' authentication token');
44
43
  params.delete('token');
45
44
  params.delete('tokenExpirationDate');
46
45
  } else {
@@ -55,13 +54,13 @@ async function retrieveTokenOrPasscodeUrl(params) {
55
54
  let authData;
56
55
  do {
57
56
  const tokenUrl = getTokenUrl(params);
58
- Logger.debug(`Getting authentication token or passcode URL from ${(params.obfuscateQueryParams(tokenUrl))}`);
57
+ log.debug(`Getting authentication token or passcode URL from ${(params.obfuscateQueryParams(tokenUrl))}`);
59
58
 
60
59
  let response;
61
60
  try {
62
61
  response = await axios.get(tokenUrl);
63
62
  } catch (error) {
64
- throw new CliError(`Failed to get authentication token: ${error}.\nResponse body: ${util.inspect(error.response && error.response.data)}`);
63
+ throw new CliError('Failed to get authentication token', error);
65
64
  }
66
65
  authData = response.data;
67
66
 
@@ -90,9 +89,9 @@ module.exports = class AuthManager {
90
89
  if (params.get('saveData')) {
91
90
  await SettingsManager.saveSettings(params);
92
91
  }
93
- throw new CliError('Failed to login: no valid token or passcode provided. ' +
94
- 'Get a passcode' + (params.get('passcodeUrl') ? ' from ' + params.get('passcodeUrl') : '') +
95
- ' and supply the code when re-running the command');
92
+ throw new CliError(`Failed to login: no valid token or passcode provided. Get a passcode${
93
+ params.get('passcodeUrl') ? ' from ' + params.get('passcodeUrl') : ''
94
+ } and supply the code when re-running the command`);
96
95
  }
97
96
  params.set('reqAuth', { headers: { Authorization: 'Bearer ' + params.get('token') } });
98
97
  }
@@ -26,9 +26,12 @@ module.exports = class BaseCommand {
26
26
  (params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : ''), error);
27
27
  case 404:
28
28
  throw new CliError(`Request failed. Please check application URL ${params.get('appUrl')}`, error);
29
- default:
30
- // Including 422 (compilation or native-extension error).
29
+ case 422:
30
+ // Compilation or native-extension error.
31
31
  throw new CliError(undefined, error);
32
+ default:
33
+ // Unexpected error should be transparent to user.
34
+ throw error;
32
35
  }
33
36
  }
34
37
 
@@ -5,7 +5,6 @@ const axios = require('axios');
5
5
  const AuthManager = require('./auth_manager');
6
6
  const BaseCommand = require('./base_command');
7
7
  const { normalizePath, isParent } = require('./helper/fs_helper');
8
- const Logger = require('./helper/logging');
9
8
  const Question = require('./helper/question');
10
9
  const { CliError } = require('./helper/errors');
11
10
 
@@ -63,7 +62,7 @@ module.exports = class Extend extends BaseCommand {
63
62
  await Extend.storeFiles(templates, directory, async filepath => {
64
63
  const normalizedPath = normalizePath(filepath);
65
64
  if (!isParent(path.join(directory, DB_FOLDER), normalizedPath) && !isParent(path.join(directory, SRV_FOLDER), normalizedPath)) {
66
- Logger.log(`Ignoring template ${normalizedPath}: not in ${DB_FOLDER} or ${SRV_FOLDER}`);
65
+ console.log('Ignoring template', normalizedPath, ': not in', DB_FOLDER, 'or', SRV_FOLDER);
67
66
  return false;
68
67
  }
69
68
  return true;
@@ -71,34 +70,30 @@ module.exports = class Extend extends BaseCommand {
71
70
  }
72
71
 
73
72
  static async run(paramValues) {
74
- try {
75
- const params = await AuthManager.login(paramValues);
76
-
77
- if (process.env.DEBUG) {
78
- Logger.log(`\n\nCreating extension project with parameters ${JSON.stringify({
79
- appUrl: params.get('appUrl'),
80
- projectFolder: params.get('projectFolder'),
81
- subdomain: params.get('subdomain'),
82
- passcode: params.get('passcode'),
83
- username: params.get('username'),
84
- password: params.get('password') ? '***' : 'undefined'
85
- })}`);
86
- } else {
87
- Logger.log(`\n\nCreating extension project for ${params.get('appUrl')}, subdomain '${params.get('subdomain')}', in folder '${params.get('projectFolder')}'`);
88
- }
73
+ const params = await AuthManager.login(paramValues);
74
+
75
+ if (process.env.DEBUG) {
76
+ console.log('\n\nCreating extension project with parameters', JSON.stringify({
77
+ appUrl: params.get('appUrl'),
78
+ projectFolder: params.get('projectFolder'),
79
+ subdomain: params.get('subdomain'),
80
+ passcode: params.get('passcode'),
81
+ username: params.get('username'),
82
+ password: params.get('password') ? '***' : 'undefined'
83
+ }));
84
+ } else {
85
+ console.log('\n\nCreating extension project for', params.get('appUrl'), 'subdomain', params.get('subdomain'), 'in folder', params.get('projectFolder'));
86
+ }
89
87
 
90
- const runOnExistingProject = await Extend.checkProject(params.get('projectFolder'));
91
- if (runOnExistingProject && !(params.get('force') || params.get('templates'))) {
92
- throw new CliError(folderExists(params.get('projectFolder')));
93
- }
88
+ const runOnExistingProject = await Extend.checkProject(params.get('projectFolder'));
89
+ if (runOnExistingProject && !(params.get('force') || params.get('templates'))) {
90
+ throw new CliError(folderExists(params.get('projectFolder')));
91
+ }
94
92
 
95
- try {
96
- await Extend.runExtend(params);
97
- } catch (error) {
98
- await Extend.handleHttpError(error, params);
99
- }
100
- } catch (mainError) {
101
- Logger.error(undefined, mainError);
93
+ try {
94
+ await Extend.runExtend(params);
95
+ } catch (error) {
96
+ await Extend.handleHttpError(error, params);
102
97
  }
103
98
  }
104
99
 
@@ -106,11 +101,11 @@ module.exports = class Extend extends BaseCommand {
106
101
  const contentUrl = Extend.getMtxApiUrl(params.get('appUrl'), COMMAND_URL_SUFFIX);
107
102
  const requestOptions = Object.assign({ retry: 0 }, params.get('reqAuth'));
108
103
 
109
- Logger.log('Retrieving files...');
104
+ console.log('Retrieving files...');
110
105
 
111
106
  const [ response ] = (await axios.get(contentUrl, requestOptions)).data;
112
107
 
113
- Logger.log('\nWriting files to: ' + params.get('projectFolder'));
108
+ console.log('\nWriting files to', params.get('projectFolder'));
114
109
 
115
110
  if (params.get('templates')) {
116
111
  await Extend.storeTemplateFilesToTpl(response.templates, params.get('projectFolder'));
@@ -124,21 +119,21 @@ module.exports = class Extend extends BaseCommand {
124
119
  await fs.promises.mkdir(path.join(params.get('projectFolder'), DB_FOLDER), { recursive: true });
125
120
  await fs.promises.mkdir(path.join(params.get('projectFolder'), SRV_FOLDER), { recursive: true });
126
121
 
127
- Logger.log(`\nPut database extension models into ${DB_FOLDER} folder.`);
128
- Logger.log(`Put service extension models into ${SRV_FOLDER} folder.`);
122
+ console.log('\nPut database extension models into', DB_FOLDER, 'folder.');
123
+ console.log('Put service extension models into', SRV_FOLDER, 'folder.');
129
124
 
130
125
  if (response.templates && response.templates.length > 0) {
131
126
  // only write templates if there are no extensions so far
132
127
  if (response.extension && response.extension.length === 0) {
133
- Logger.log(`Writing template files to ${DB_FOLDER} and ${SRV_FOLDER} folder`);
128
+ console.log('Writing template files to', DB_FOLDER, 'and', SRV_FOLDER, 'folder');
134
129
  await Extend.storeTemplateFiles(response.templates, params.get('projectFolder'));
135
130
  } else {
136
- Logger.log('Ignoring templates because extension is already active.');
131
+ console.log('Ignoring templates because extension is already active.');
137
132
  }
138
133
  }
139
134
 
140
135
  if (params.get('wsdl')) {
141
- Logger.log('Writing custom files');
136
+ console.log('Writing custom files');
142
137
  const customFileUrl = Extend.getMtxApiUrl(params.get('appUrl'), Extend.CUSTOM_FILE_URL_SUFFIX);
143
138
  const customFiles = (await axios.get(customFileUrl, requestOptions)).data;
144
139
  await Extend.storeCustomFiles(params.get('projectFolder'), customFiles);
@@ -153,12 +148,12 @@ module.exports = class Extend extends BaseCommand {
153
148
  if (targetExists) {
154
149
  await fs.promises.rm(targetDirectory, { force: true, recursive: true });
155
150
  }
156
- Logger.log(`Writing template files to ${TEMPLATE_FOLDER} folder`);
151
+ console.log('Writing template files to', TEMPLATE_FOLDER, 'folder');
157
152
  await Extend.storeTemplateFiles(templates, targetDirectory);
158
153
  }
159
154
 
160
155
  } else {
161
- Logger.log('No templates available');
156
+ console.log('No templates available');
162
157
  }
163
158
  }
164
159
 
@@ -167,7 +162,7 @@ module.exports = class Extend extends BaseCommand {
167
162
  }
168
163
 
169
164
  static _logWrittenFile(file) {
170
- Logger.log('CREATE: ' + file);
165
+ console.log('CREATE:', file);
171
166
  }
172
167
 
173
168
  }
@@ -1,7 +1,7 @@
1
1
  const os = require('os');
2
2
  const { execFile } = require('child_process');
3
3
 
4
- const Logger = require('./logging');
4
+ const log = require('./logging');
5
5
  const Question = require('./question');
6
6
  const { formatObjectsFixedWidth } = require('./string_helper');
7
7
  const { schemaRegex } = require('./url_helper');
@@ -20,7 +20,7 @@ function getErrorMessage(error, stdout) {
20
20
  async function getAppFromSuggestions() {
21
21
  const apps = await getApps();
22
22
  if (apps.length === 0) {
23
- Logger.debug('Failed to obtain list of apps from CF');
23
+ log.debug('Failed to obtain list of apps from CF');
24
24
  return undefined;
25
25
  }
26
26
 
@@ -36,7 +36,7 @@ Your choice: `);
36
36
  console.log();
37
37
 
38
38
  if (!choice) {
39
- Logger.debug('No app URL selected');
39
+ log.debug('No app URL selected');
40
40
  return undefined;
41
41
  }
42
42
  choiceNr = Number(choice);
@@ -46,7 +46,7 @@ Your choice: `);
46
46
  }
47
47
 
48
48
  async function getApps(nameRegex = /(?<!-db)$/) {
49
- Logger.debug('Getting running apps from CF');
49
+ log.debug('Getting running apps from CF');
50
50
 
51
51
  return new Promise(resolve => {
52
52
  runCf(['apps'], function(error, stdout) {
@@ -120,13 +120,13 @@ async function getApps(nameRegex = /(?<!-db)$/) {
120
120
  }
121
121
 
122
122
  function errorResult(message) {
123
- Logger.debug(`Failed to get apps: ${message}`);
123
+ log.debug(`Failed to get apps: ${message}`);
124
124
  return [];
125
125
  }
126
126
  }
127
127
 
128
128
  async function getSubdomain(appName) {
129
- Logger.debug('Getting subdomain from CF env');
129
+ log.debug('Getting subdomain from CF env');
130
130
 
131
131
  return new Promise(resolve => {
132
132
  runCf(['env', appName], function(error, stdout) {
@@ -155,13 +155,13 @@ async function getSubdomain(appName) {
155
155
  }
156
156
  }
157
157
 
158
- Logger.debug(`Subdomain determined from CF app environment: ${value}`);
158
+ log.debug(`Subdomain determined from CF app environment: ${value}`);
159
159
  return resolve(value);
160
160
  });
161
161
  });
162
162
 
163
163
  function errorResult(message) {
164
- Logger.debug(`Failed to get subdomain: ${message}`);
164
+ log.debug(`Failed to get subdomain: ${message}`);
165
165
  return undefined;
166
166
  }
167
167
  }
@@ -171,14 +171,14 @@ async function getAppName(appUrl) {
171
171
  return url1.replace(schemaRegex, '') === url2.replace(schemaRegex, '');
172
172
  }
173
173
 
174
- Logger.debug('Getting app name from CF apps');
174
+ log.debug('Getting app name from CF apps');
175
175
  const apps = await getApps();
176
176
  const app = apps.find(app => equalIgnoringTls(app.url, appUrl));
177
177
  if (!app) {
178
- Logger.debug(`Failed to find app with URL ${appUrl}. Running apps: ${apps.map(app => app.name)}`);
178
+ log.debug(`Failed to find app with URL ${appUrl}. Running apps: ${apps.map(app => app.name)}`);
179
179
  return;
180
180
  }
181
- Logger.debug(`App name determined from CF: ${app.name}`);
181
+ log.debug(`App name determined from CF: ${app.name}`);
182
182
  return app.name;
183
183
  }
184
184
 
@@ -1,7 +1,7 @@
1
1
  const os = require('os');
2
2
  const { execFileSync } = require('child_process');
3
3
 
4
- const Logger = require('./logging');
4
+ const log = require('./logging');
5
5
 
6
6
  let cachedDir;
7
7
 
@@ -21,6 +21,6 @@ module.exports = function requireGlobal(packageId) {
21
21
  return require(packagePath);
22
22
  } catch (error) {
23
23
  // Ignore error.
24
- Logger.debug(`Failed to find module '${packageId}' in ${globalModulesDir()}: ${error}`);
24
+ log.debug(`Failed to find module '${packageId}' in ${globalModulesDir()}`, error);
25
25
  }
26
26
  }
@@ -1,8 +1,9 @@
1
- const Logger = require('./logging');
1
+ const { getMessage } = require('./logging');
2
+
2
3
  class CliError extends Error {
3
- stack = '';
4
+ // noinspection JSAnnotator
4
5
  constructor(message, error) {
5
- super(Logger.getMessage(message, error));
6
+ throw getMessage(message, error);
6
7
  }
7
8
  }
8
9
 
@@ -1,30 +1,24 @@
1
1
  /* eslint-disable no-console */
2
2
 
3
- module.exports = class Logger {
4
-
5
- static log(logText) {
6
- console.log(logText);
7
- }
8
-
9
- static error(errorText, error) {
10
- console.error(this.getMessage(errorText, error));
11
- }
12
-
13
- static debug(debugText, error) {
14
- if (process.env.DEBUG) {
15
- console.error(this.getMessage(debugText, error));
16
- }
3
+ function debug(debugText, error) {
4
+ if (process.env.DEBUG) {
5
+ console.error(getMessage(debugText, error));
17
6
  }
7
+ }
18
8
 
19
- static getMessage(errorText, error) {
20
- let message = errorText ? errorText + '\n' : '';
21
- if (!error) {
22
- return message;
23
- }
24
- message += error.response?.data?.error?.message || error.message;
25
- if (process.env.DEBUG && error.stack) {
26
- message += '\n' + error.stack;
27
- }
9
+ function getMessage(errorText, error) {
10
+ let message = errorText ? errorText : '';
11
+ if (!error) {
28
12
  return message;
29
13
  }
14
+ message += '\n' + (error.response?.data?.error?.message || error.message);
15
+ if (process.env.DEBUG && error.stack) {
16
+ message += '\n' + error.stack;
17
+ }
18
+ return message;
30
19
  }
20
+
21
+ module.exports = {
22
+ debug,
23
+ getMessage
24
+ };
@@ -1,4 +1,4 @@
1
- const Logger = require('./helper/logging');
1
+ const log = require('./helper/logging');
2
2
  const { escapeRegex } = require('./helper/string_helper');
3
3
  const { CliError } = require('./helper/errors');
4
4
 
@@ -178,7 +178,7 @@ class BasicParams {
178
178
  this.appUrl = new Param('appUrl', '', { persist: Persistence.setting });
179
179
  this.to = this.appUrl.newAlias('to');
180
180
  this.url = this.appUrl.newAlias('url');
181
- this.subdomain = new Param('subdomain', '', { persist: Persistence.setting });
181
+ this.subdomain = new Param('subdomain', '', { persist: Persistence.setting }); // only needed to fetch token
182
182
  this.passcodeUrl = new Param('passcodeUrl', '', { persist: Persistence.setting, abbreviate: true });
183
183
  this.passcode_url = this.passcodeUrl.newAlias('passcode_url');
184
184
  this.tokenUrl = new Param('tokenUrl', '', { persist: Persistence.setting, abbreviate: true })
@@ -247,7 +247,7 @@ class ParamCollection {
247
247
  */
248
248
  checkFrozen() {
249
249
  if (this.isFrozen) {
250
- throw new CliError('cannot modify read-only parameter collection');
250
+ throw new Error('cannot modify read-only parameter collection');
251
251
  }
252
252
  }
253
253
 
@@ -268,7 +268,7 @@ class ParamCollection {
268
268
  static mainName(name) {
269
269
  const paramDef = ParamDefs[name];
270
270
  if (!paramDef) {
271
- throw new CliError(`Unknown parameter: '${name}'`);
271
+ throw new Error(`Unknown parameter: '${name}'`);
272
272
  }
273
273
  return paramDef.mainName;
274
274
  }
@@ -312,7 +312,7 @@ class ParamCollection {
312
312
  this.params[mainName] = ParamDefs[mainName].clone(val);
313
313
  }
314
314
  if (mainName !== name) {
315
- Logger.debug(`Migrated setting '${name}' to new key '${mainName}'`);
315
+ log.debug(`Migrated setting '${name}' to new key '${mainName}'`);
316
316
  }
317
317
  }
318
318
 
@@ -1,40 +1,38 @@
1
+ const cds = require ('../cds')
2
+ const { local, tar } = cds.utils;
3
+
1
4
  const fs = require('fs');
2
5
  const { join } = require('path');
3
6
  const axios = require('axios');
4
7
 
5
- const { unpackTarArchive } = require('@sap/cds/lib/utils/resources');
6
-
7
8
  const { login } = require('./auth_manager');
8
9
  const BaseCommand = require('./base_command');
9
- const Logger = require('./helper/logging');
10
- const { CliError } = require('./helper/errors');
11
10
 
12
11
  module.exports = class Pull extends BaseCommand {
13
12
 
14
13
  static async run(paramValues) {
15
- try {
16
- const params = await login(paramValues);
17
- Logger.log(`Pulling base model from ${params.get('appUrl')}, for subdomain '${params.get('subdomain')}', to project folder '${params.get('projectFolder')}'`);
14
+ if (!tar) {
15
+ console.error(`cds pull requires @sap/cds version >= 6.2. Current version is ${cds.version}\n`);
16
+ return process.exitCode = 1;
17
+ }
18
18
 
19
- const projectFolder = params.get('projectFolder');
20
- const targetDir = join(projectFolder, 'node_modules', this.getAppPackageName(projectFolder));
21
- fs.rmSync(targetDir, { force: true, recursive: true });
22
- fs.mkdirSync(targetDir, { recursive: true });
19
+ const params = await login(paramValues);
20
+ const url = params.get('appUrl')
21
+ const home = params.get('projectFolder');
22
+ const target = join(home, 'node_modules', this.getAppPackageName(home));
23
+ const subdomain = params.get('subdomain') // REVISIT: Why are subdomains not transparently encoded in URLs?
24
+ console.log(`Pulling app base model`, Object.assign({ from: url, to: local(target) }, subdomain && {subdomain}))
23
25
 
24
- const tgzBuffer = Buffer.from(await this.getTgz(params));
25
- return unpackTarArchive(tgzBuffer, targetDir, false);
26
+ fs.rmSync(target, { force: true, recursive: true });
27
+ fs.mkdirSync(target, { recursive: true });
26
28
 
27
- } catch (error) {
28
- throw new CliError(undefined, error);
29
- }
29
+ const tgzBuffer = Buffer.from(await this.getTgz(params));
30
+ return tar.xz(tgzBuffer).to(target);
30
31
  }
31
32
 
32
33
  static getAppPackageName(projectFolder) {
33
- try {
34
- return require(join(projectFolder, 'package.json')).cds.extends;
35
- } catch (error) {
36
- return '_base';
37
- }
34
+ const env = cds.env.for('cds', projectFolder);
35
+ return env.extends || '_base';
38
36
  }
39
37
 
40
38
  static async getTgz(params) {