@sap/cds-dk 6.2.3 → 6.3.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 (70) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/bin/bind.js +4 -4
  3. package/bin/deploy/to-h2.js +4 -0
  4. package/bin/deploy/to-sqlite.js +6 -4
  5. package/bin/help.js +1 -1
  6. package/bin/login.js +1 -0
  7. package/bin/push.js +29 -7
  8. package/lib/bind/userCdsrcJsonStorageProvider.js +4 -4
  9. package/lib/client/activate.js +1 -1
  10. package/lib/client/base_command.js +10 -10
  11. package/lib/client/helper/dependency_helper.js +10 -1
  12. package/lib/client/helper/logging.js +6 -2
  13. package/lib/client/pull.js +6 -6
  14. package/lib/client/push.js +33 -14
  15. package/lib/client/settings_manager.js +52 -21
  16. package/lib/compile/openapi/csdl2openapi.js +1 -1
  17. package/lib/compile/to-xsuaa.js +1 -1
  18. package/lib/import/odata/v2parser.js +37 -1
  19. package/lib/import/odata/v4parser.js +101 -23
  20. package/lib/init/constants.js +1 -1
  21. package/lib/init/index.js +23 -45
  22. package/lib/init/template/approuter/index.js +44 -48
  23. package/lib/init/template/auditlog/index.js +14 -10
  24. package/lib/init/template/cf-manifest/index.js +9 -11
  25. package/lib/init/template/connectivity/index.js +10 -10
  26. package/lib/init/template/data/index.js +20 -19
  27. package/lib/init/template/destinations/index.js +14 -9
  28. package/lib/init/template/enterprise-messaging/index.js +14 -9
  29. package/lib/init/template/extensibility/index.js +14 -9
  30. package/lib/init/template/hana/index.js +51 -57
  31. package/lib/init/template/helm/index.js +27 -59
  32. package/lib/init/template/helm/subchart/templates/_helpers.tpl +38 -0
  33. package/lib/init/template/helm/subchart/templates/deployment.yaml +12 -12
  34. package/lib/init/template/helm/subchart/values.md +565 -194
  35. package/lib/init/template/helm/subchart/values.schema.json +163 -8
  36. package/lib/init/template/helm/subchart/values.yaml +17 -1
  37. package/lib/init/template/html5-repo/index.js +15 -11
  38. package/lib/init/template/java/index.js +15 -11
  39. package/lib/init/template/kibana-logging/index.js +30 -31
  40. package/lib/init/template/lint/index.js +17 -18
  41. package/lib/init/template/mta/index.js +18 -40
  42. package/lib/init/template/mtx/index.js +2 -3
  43. package/lib/init/template/multitenancy/index.js +27 -20
  44. package/lib/init/template/nodejs/index.js +18 -20
  45. package/lib/init/template/notebook/index.js +5 -434
  46. package/lib/init/template/pipeline/index.js +10 -10
  47. package/lib/init/template/samples/index.js +7 -16
  48. package/lib/init/template/templateBase.js +17 -18
  49. package/lib/init/template/toggles/files/cdsrc.json +5 -0
  50. package/lib/init/template/toggles/files/cdsrc.json.hbs +7 -0
  51. package/lib/init/template/toggles/index.js +12 -6
  52. package/lib/init/template/xsuaa/index.js +44 -41
  53. package/lib/init/types.d.ts +0 -59
  54. package/lib/init/util/commandUtil.js +6 -7
  55. package/lib/init/util/fsUtil.js +23 -109
  56. package/lib/init/util/merge.js +319 -0
  57. package/lib/init/util/mvnArchetypeUtil.js +6 -5
  58. package/lib/init/util/projectReader.js +125 -300
  59. package/lib/init/util/spinner.js +10 -8
  60. package/lib/init/util/templateUtil.js +25 -368
  61. package/lib/lint/Linter.js +2 -3
  62. package/lib/lint/checks.js +0 -1
  63. package/lib/lint/io.js +18 -34
  64. package/npm-shrinkwrap.json +102 -239
  65. package/package.json +3 -3
  66. package/lib/init/template/notebook/cap_magic.py +0 -118
  67. package/lib/init/template/notebook/files/{{{name}}}.ipynb.hbs +0 -90
  68. package/lib/init/template/notebook/files/{{{name}}}.json +0 -102
  69. package/lib/init/template/notebook/notebook.js +0 -394
  70. package/lib/init/util/logger.js +0 -42
@@ -351,16 +351,171 @@
351
351
  "env": {
352
352
  "$id": "#/properties/env",
353
353
  "description": "Key-value map of environment variables, which should be added to the Pod spec.",
354
- "type": "object",
355
- "patternProperties": {
356
- "^[-._a-zA-Z][-._a-zA-Z0-9]*$": {
357
- "$comment": "regex above copied from https://github.com/kubernetes/kubernetes/blob/ea0764452222146c47ec826977f49d7001b0ea8c/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go#L402",
358
- "not": {
359
- "type": ["null", "object", "array"]
354
+ "anyOf": [
355
+ {
356
+ "type": "object",
357
+ "patternProperties": {
358
+ "^[-._a-zA-Z][-._a-zA-Z0-9]*$": {
359
+ "$comment": "regex above copied from https://github.com/kubernetes/kubernetes/blob/ea0764452222146c47ec826977f49d7001b0ea8c/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go#L402",
360
+ "anyOf": [
361
+ {
362
+ "description": "Plain value of an environment variable.",
363
+ "type": [
364
+ "integer",
365
+ "string"
366
+ ]
367
+ },
368
+ {
369
+ "description": "`valueFrom` configuration for the environment variable https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/",
370
+ "type": "object",
371
+ "additionalProperties": false,
372
+ "maxProperties": 1,
373
+ "properties": {
374
+ "configMapKeyRef": {
375
+ "description": "Selects a key of a ConfigMap.",
376
+ "type": "object",
377
+ "additionalProperties": false,
378
+ "properties": {
379
+ "name": {
380
+ "description": "Name of a ConfigMap.",
381
+ "$ref": "#/definitions/KubernetesName"
382
+ },
383
+ "key": {
384
+ "description": "Key in that ConfigMap, which value will be used.",
385
+ "type": "string"
386
+ }
387
+ }
388
+ },
389
+ "secretKeyRef": {
390
+ "description": "Selects a key of a Secret.",
391
+ "type": "object",
392
+ "additionalProperties": false,
393
+ "properties": {
394
+ "name": {
395
+ "description": "Name of a Secret.",
396
+ "$ref": "#/definitions/KubernetesName"
397
+ },
398
+ "key": {
399
+ "description": "Key in that Secret, which value will be used.",
400
+ "type": "string"
401
+ }
402
+ }
403
+ },
404
+ "resourceFieldRef": {
405
+ "description": "Selects a resource of the container.",
406
+ "type": "object",
407
+ "additionalProperties": false,
408
+ "properties": {
409
+ "containerName": {
410
+ "description": "Name of a Container.",
411
+ "$ref": "#/definitions/KubernetesName"
412
+ },
413
+ "resource": {
414
+ "description": "Only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.",
415
+ "type": "string"
416
+ }
417
+ }
418
+ },
419
+ "fieldRef": {
420
+ "description": "Selects a field of the pod.",
421
+ "type": "object",
422
+ "additionalProperties": false,
423
+ "properties": {
424
+ "fieldPath": {
425
+ "type": "string",
426
+ "description": "Supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs."
427
+ }
428
+ }
429
+ }
430
+ }
431
+ }
432
+ ]
433
+ }
434
+ },
435
+ "additionalProperties": false,
436
+ "default": {}
437
+ },
438
+ {
439
+ "type": "array",
440
+ "uniqueItems": true,
441
+ "items": {
442
+ "type": "object",
443
+ "additionalProperties": false,
444
+ "maxProperties": 2,
445
+ "required": [
446
+ "name"
447
+ ],
448
+ "properties": {
449
+ "name": {
450
+ "type": "string",
451
+ "pattern": "^[-._a-zA-Z][-._a-zA-Z0-9]*$"
452
+ },
453
+ "value": {
454
+ "type": [
455
+ "string",
456
+ "integer"
457
+ ]
458
+ },
459
+ "configMapKeyRef": {
460
+ "description": "Selects a key of a ConfigMap.",
461
+ "type": "object",
462
+ "additionalProperties": false,
463
+ "properties": {
464
+ "name": {
465
+ "description": "Name of a ConfigMap.",
466
+ "$ref": "#/definitions/KubernetesName"
467
+ },
468
+ "key": {
469
+ "description": "Key in that ConfigMap, which value will be used.",
470
+ "type": "string"
471
+ }
472
+ }
473
+ },
474
+ "secretKeyRef": {
475
+ "description": "Selects a key of a Secret.",
476
+ "type": "object",
477
+ "additionalProperties": false,
478
+ "properties": {
479
+ "name": {
480
+ "description": "Name of a Secret.",
481
+ "$ref": "#/definitions/KubernetesName"
482
+ },
483
+ "key": {
484
+ "description": "Key in that Secret, which value will be used.",
485
+ "type": "string"
486
+ }
487
+ }
488
+ },
489
+ "resourceFieldRef": {
490
+ "description": "Selects a resource of the container.",
491
+ "type": "object",
492
+ "additionalProperties": false,
493
+ "properties": {
494
+ "containerName": {
495
+ "description": "Name of a Container.",
496
+ "$ref": "#/definitions/KubernetesName"
497
+ },
498
+ "resource": {
499
+ "description": "Only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.",
500
+ "type": "string"
501
+ }
502
+ }
503
+ },
504
+ "fieldRef": {
505
+ "description": "Selects a field of the pod.",
506
+ "type": "object",
507
+ "additionalProperties": false,
508
+ "properties": {
509
+ "fieldPath": {
510
+ "type": "string",
511
+ "description": "Supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs."
512
+ }
513
+ }
514
+ }
515
+ }
360
516
  }
361
517
  }
362
- },
363
- "additionalProperties": false,
518
+ ],
364
519
  "default": {}
365
520
  },
366
521
  "envSecretNames": {
@@ -55,7 +55,23 @@ envSecretNames: []
55
55
 
56
56
  env: {}
57
57
  # env:
58
- # key: value
58
+ # key1: value
59
+ # key2:
60
+ # secretKeyRef:
61
+ # name: my-secret
62
+ # key: my-key
63
+ # key3:
64
+ # configMapKeyRef:
65
+ # name: my-configmap
66
+ # key: my-key
67
+ # Also can be specified as a list
68
+ # env:
69
+ # - name: key1
70
+ # value: value1
71
+ # - name: key2
72
+ # configMapKeyRef:
73
+ # name: my-configmap
74
+ # key: my-key
59
75
 
60
76
  expose:
61
77
  enabled: true
@@ -1,30 +1,34 @@
1
1
  const path = require('path')
2
- const TemplateBase = require('../templateBase')
2
+ const { exists, copy } = require('../../../cds').utils
3
3
  const ProjectReader = require('../../util/projectReader')
4
- const { srvNode, srvJava, auditlog } = require('../_merging/registry-mta')
4
+ const { mergeYAML } = require('../../util/merge')
5
5
  const { OPTION_DESTINATIONS } = require('../../constants')
6
- const cds = require('../../../cds'), { fs } = cds.utils
7
6
 
8
- module.exports = class Html5RepoTemplate extends TemplateBase {
7
+ module.exports = class Html5RepoTemplate extends require('../templateBase') {
9
8
  constructor(projectPath, generator) {
10
9
  super(projectPath, generator, __dirname)
11
- this.projectReader = new ProjectReader(this)
10
+ this.projectReader = new ProjectReader(projectPath)
12
11
  }
13
12
 
14
13
  async getDependencies() {
15
14
  return [OPTION_DESTINATIONS]
16
15
  }
17
16
 
17
+ static hasFacet(_, projectPath) {
18
+ // REVISIT: Should be detectable without helm charts
19
+ return exists(path.join(projectPath, 'chart', 'templates', 'html5-apps-repo-host.yaml'))
20
+ }
21
+
18
22
  async run() {
19
23
  await this.runDependentMerging()
20
24
  }
21
25
 
22
26
  async runDependentMerging() {
23
27
  const projectDescriptor = await this.projectReader.read(this.options)
24
- const { appName, hasHelmDeployment } = projectDescriptor.cap
28
+ const { appName, hasHelm } = projectDescriptor.cap
25
29
 
26
- if (hasHelmDeployment) {
27
- await this.templateUtil.mergeYAML(
30
+ if (hasHelm) {
31
+ await mergeYAML(
28
32
  path.join(this.projectPath, 'chart', 'values.yaml'),
29
33
  {
30
34
  html5_apps_repo_host: {
@@ -51,9 +55,9 @@ module.exports = class Html5RepoTemplate extends TemplateBase {
51
55
  },
52
56
  null, { forceOverwrite: true }
53
57
  )
54
- await fs.copy(path.join(__dirname, 'files', '_html5_deployment_helpers.tpl'), path.join(this.projectPath, 'chart', 'templates', '_html5_deployment_helpers.tpl'))
55
- await fs.copy(path.join(__dirname, 'files', 'html5-apps-deployer-job.yaml'), path.join(this.projectPath, 'chart', 'templates', 'html5-apps-deployer-job.yaml'))
56
- await fs.copy(path.join(__dirname, 'files', 'html5-apps-repo-host.yaml'), path.join(this.projectPath, 'chart', 'templates', 'html5-apps-repo-host.yaml'))
58
+ await copy(path.join(__dirname, 'files', '_html5_deployment_helpers.tpl'), path.join(this.projectPath, 'chart', 'templates', '_html5_deployment_helpers.tpl'))
59
+ await copy(path.join(__dirname, 'files', 'html5-apps-deployer-job.yaml'), path.join(this.projectPath, 'chart', 'templates', 'html5-apps-deployer-job.yaml'))
60
+ await copy(path.join(__dirname, 'files', 'html5-apps-repo-host.yaml'), path.join(this.projectPath, 'chart', 'templates', 'html5-apps-repo-host.yaml'))
57
61
  }
58
62
  }
59
63
  }
@@ -5,18 +5,22 @@ const path = require('path');
5
5
  const commandUtil = require('../../util/commandUtil');
6
6
  const mvnArchetypeUtil = require('../../util/mvnArchetypeUtil');
7
7
  const term = require('../../../util/term');
8
+ const cds = require('../../../cds')
9
+ const { exists, copy } = cds.utils
10
+ const LOG = console
8
11
 
9
- const TemplateBase = require('../templateBase');
10
12
  const { COMMAND_ADD, URLS, OPTION_JAVA, OPTION_NODEJS } = require('../../constants');
11
- const { nullLogger } = require('../../util/logger');
12
13
 
13
-
14
- module.exports = class JavaTemplate extends TemplateBase {
14
+ module.exports = class JavaTemplate extends require('../templateBase') {
15
15
  constructor(projectPath, generator) {
16
16
  super(projectPath, generator, __dirname);
17
17
  }
18
18
 
19
- async checkEnabled() {
19
+ static hasFacet(_, projectPath) {
20
+ return exists(path.join(projectPath, 'pom.xml'))
21
+ }
22
+
23
+ async canRun() {
20
24
  if (this.options._cmd === COMMAND_ADD) {
21
25
  throw new Error(`You can't change the type of an existing project.`);
22
26
  }
@@ -29,18 +33,18 @@ module.exports = class JavaTemplate extends TemplateBase {
29
33
  }
30
34
 
31
35
  async run() {
32
- const mvnCmdArgs = mvnArchetypeUtil.getGenerateCmdArgs(this.projectName, this.options, this.logger);
36
+ const mvnCmdArgs = mvnArchetypeUtil.getGenerateCmdArgs(this.projectName, this.options);
33
37
  const { cmdLine, artifactId, archetypeVersion } = mvnCmdArgs
34
38
 
35
- this.logger.log(`Using Maven archetype version ${archetypeVersion}`);
39
+ LOG.info(`Using Maven archetype version ${archetypeVersion}`);
36
40
 
37
41
  const tempFolder = await fs.mkdtemp(path.join(os.tmpdir(), `${this.projectName}_`));
38
42
  try {
39
43
  await commandUtil.spawnCommand('mvn', cmdLine, {
40
44
  cwd: tempFolder
41
- }, (this.logger.isDebug ? this.logger : nullLogger));
45
+ });
42
46
 
43
- await this.fsUtil.copy(path.join(tempFolder, artifactId), this.projectPath);
47
+ await copy(path.join(tempFolder, artifactId), this.projectPath);
44
48
  } catch (err) {
45
49
  if (err.code === 'ENOENT' && err.path === 'mvn') {
46
50
  throw new Error(`Maven executable 'mvn' not found, follow ${term.info(URLS.MAVEN_INSTALL_HELP)} and install Maven on your machine.`);
@@ -54,9 +58,9 @@ module.exports = class JavaTemplate extends TemplateBase {
54
58
  async finalize() {
55
59
  const relativeProjectPath = path.relative(this.cwd, this.projectPath);
56
60
  if (relativeProjectPath && relativeProjectPath !== '.') {
57
- this.logger.log(`Continue with 'cd ${relativeProjectPath}'`);
61
+ LOG.info(`Continue with 'cd ${relativeProjectPath}'`);
58
62
  }
59
63
 
60
- this.logger.log(`Learn about next steps at ${URLS.CAPIRE}`);
64
+ LOG.info(`Learn about next steps at ${URLS.CAPIRE}`);
61
65
  }
62
66
  }
@@ -1,34 +1,53 @@
1
- const cds = require('../../../cds')
2
1
  const path = require('path')
3
-
2
+ const cds = require('../../../cds')
4
3
  const ProjectReader = require('../../util/projectReader')
5
- const TemplateBase = require('../templateBase')
4
+ const { mergeJSON, mergeYAML } = require('../../util/merge')
6
5
  const { PROJECT_TYPE, } = require('../../constants')
7
6
  const { srvNode, srvJava, kibanaLogging } = require('../_merging/registry-mta')
8
7
 
9
- module.exports = class KibanaTemplate extends TemplateBase {
8
+ module.exports = class KibanaTemplate extends require('../templateBase') {
10
9
  constructor(projectPath, generator) {
11
10
  super(projectPath, generator, __dirname)
12
- this.projectReader = new ProjectReader(this)
11
+ this.projectReader = new ProjectReader(projectPath)
13
12
  }
14
13
 
15
- async checkEnabled() {
14
+ async canRun() {
16
15
  const projectDescriptor = await this.projectReader.read(this.options)
17
- const { hasMtaDeployment, hasHelmDeployment } = projectDescriptor.cap
18
- if (hasHelmDeployment && !hasMtaDeployment) {
16
+ const { hasMta, hasHelm } = projectDescriptor.cap
17
+ if (hasHelm && !hasMta) {
19
18
  throw `'cds add kibana-logging' is not available for Kyma yet`
20
19
  }
21
20
  }
22
21
 
22
+ async run() {
23
+ const projectType = await this.getProjectType()
24
+
25
+ switch (projectType) {
26
+ case PROJECT_TYPE.java:
27
+ default:
28
+ cds.error(`kibana-logging is not implemented for project type '${projectType}' yet`)
29
+ // TODO: implement
30
+ break
31
+ case PROJECT_TYPE.nodejs: {
32
+ const projectDescriptor = await this.projectReader.read(this.options);
33
+ const { for: forProfile } = projectDescriptor.cap
34
+ const cdsTemplateFile = forProfile ? 'cds.profile.package.json.hbs' : 'cds.package.json'
35
+ const cdsTemplatePath = path.join(__dirname, 'files', cdsTemplateFile)
36
+ await mergeJSON(path.join(this.projectPath, 'package.json'), cdsTemplatePath, projectDescriptor)
37
+ }
38
+ }
39
+ await this.runDependentMerging()
40
+ }
41
+
23
42
  async runDependentMerging() {
24
43
  const projectDescriptor = await this.projectReader.read(this.options)
25
- const { hasMtaDeployment, isNodejs } = projectDescriptor.cap
44
+ const { hasMta, isNodejs } = projectDescriptor.cap
26
45
 
27
- if (hasMtaDeployment) {
46
+ if (hasMta) {
28
47
  const srv = isNodejs ? srvNode : srvJava
29
48
 
30
49
  const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml')
31
- await this.templateUtil.mergeYAML(
50
+ await mergeYAML(
32
51
  mtaYAMLPath,
33
52
  `${__dirname}/files/mta.yaml.hbs`,
34
53
  projectDescriptor,
@@ -42,24 +61,4 @@ module.exports = class KibanaTemplate extends TemplateBase {
42
61
  )
43
62
  }
44
63
  }
45
-
46
- async run() {
47
- const projectType = await this.getProjectType()
48
-
49
- switch (projectType) {
50
- case PROJECT_TYPE.java:
51
- default:
52
- cds.error(`kibana-logging is not implemented for project type '${projectType}' yet`)
53
- // TODO: implement
54
- break
55
- case PROJECT_TYPE.nodejs: {
56
- const projectDescriptor = await this.projectReader.read(this.options);
57
- const { for: forProfile } = projectDescriptor.cap
58
- const cdsTemplateFile = forProfile ? 'cds.profile.package.json.hbs' : 'cds.package.json'
59
- const cdsTemplatePath = path.join(__dirname, 'files', cdsTemplateFile)
60
- await this.templateUtil.mergeJSON(path.join(this.projectPath, 'package.json'), cdsTemplatePath, projectDescriptor)
61
- }
62
- }
63
- await this.runDependentMerging()
64
- }
65
64
  }
@@ -1,15 +1,16 @@
1
1
  const os = require("os");
2
2
  const path = require("path");
3
3
  const cp = require("child_process");
4
- const TemplateBase = require("../templateBase");
5
4
  const term = require("../../../util/term");
6
5
  const checks = require("../../../lint/checks");
7
6
  const io = require("../../../lint/io");
8
7
  const readline = require("readline");
9
-
8
+ const { copyFiles } = require('../../util/templateUtil')
10
9
  const { OPTION_LINT_DEV, OPTION_LINT_GLOBAL } = require("../../constants");
11
- const { mkdirp, fs } = require("../../../cds").utils;
12
10
  const { getConfigPath, getFileExtensions } = require("@sap/eslint-plugin-cds/lib/api");
11
+ const cds = require("../../../cds");
12
+ const { mkdirp, exists } = cds.utils;
13
+ const LOG = console;
13
14
 
14
15
  const IS_WIN = os.platform() === "win32";
15
16
  const ALLOWED_FILE_EXTENSIONS = getFileExtensions();
@@ -17,7 +18,7 @@ const VSCODE_FILE_ASSOCIATIONS = {
17
18
  "csv": [ "csv", "csv (semicolon)", "tsv", "tab" ]
18
19
  }
19
20
 
20
- module.exports = class LintTemplate extends TemplateBase {
21
+ module.exports = class LintTemplate extends require('../templateBase') {
21
22
  constructor(projectPath, generator) {
22
23
  super(projectPath, generator, __dirname);
23
24
  this.projectPath = projectPath;
@@ -31,7 +32,7 @@ module.exports = class LintTemplate extends TemplateBase {
31
32
  this.isTest = false;
32
33
  }
33
34
 
34
- async checkEnabled() {
35
+ async canRun() {
35
36
  if (this.options.lint) {
36
37
  // If custom rule example is requested, also trigger
37
38
  // "custom" rule type of setup
@@ -61,10 +62,10 @@ module.exports = class LintTemplate extends TemplateBase {
61
62
  // Generate custom lint rules dirs
62
63
  await this._generateEslintDirs();
63
64
 
64
- if (!fs.existsSync(".eslint/rules/no-entity-moo.js")) {
65
+ if (!exists(".eslint/rules/no-entity-moo.js")) {
65
66
  await this._copyFromTemplate(".eslint/rules", this.rulesPath);
66
67
  }
67
- if (!fs.existsSync(".eslint/tests/no-entity-moo.test.js")) {
68
+ if (!exists(".eslint/tests/no-entity-moo.test.js")) {
68
69
  await this._copyFromTemplate(".eslint/tests", this.testsPath);
69
70
  }
70
71
  }
@@ -99,20 +100,20 @@ module.exports = class LintTemplate extends TemplateBase {
99
100
  ].join(" ")}`;
100
101
 
101
102
  if (this.options.force) {
102
- this.logger.log(
103
+ LOG.info(
103
104
  `\n\nAlmost done - installing ${this.missingNpmDependencies["names"].length} npm dependencies:\n${task}`
104
105
  );
105
106
  this._runTask(task);
106
107
  } else {
107
- this.logger.log(
108
+ LOG.info(
108
109
  `\n\nAlmost done - ${term.warn(
109
110
  `you are missing ${this.missingNpmDependencies["names"].length} npm dependencies`
110
111
  )}:\n`
111
112
  );
112
113
  this.missingNpmDependencies["msgs"].forEach((msg, i) => {
113
- this.logger.log(`(${i + 1}) ${msg}`);
114
+ LOG.info(`(${i + 1}) ${msg}`);
114
115
  if (i === this.missingNpmDependencies["msgs"].length - 1) {
115
- this.logger.log("\n");
116
+ LOG.info("\n");
116
117
  }
117
118
  });
118
119
  await this._promptInstallDependencies(task);
@@ -148,20 +149,18 @@ module.exports = class LintTemplate extends TemplateBase {
148
149
  await mkdirp(this.docsPath);
149
150
  await mkdirp(this.rulesPath);
150
151
  await mkdirp(this.testsPath);
151
- return;
152
152
  }
153
153
 
154
154
  async _copyFromTemplate(source, dest) {
155
- await this.templateUtil.copyFiles(source, dest, {}, true);
156
- return;
155
+ await copyFiles(source, dest, {}, true);
157
156
  }
158
157
 
159
158
  async _addEslintPluginConfig() {
160
- let configPath = getConfigPath(this.projectPath, this.logger);
159
+ let configPath = getConfigPath(this.projectPath);
161
160
  if (!configPath) {
162
161
  configPath = path.join(this.projectPath, ".eslintrc");
163
162
  }
164
- await io.sanitizeEslintConfig(configPath, this.customRuleExample, this.logger);
163
+ await io.sanitizeEslintConfig(configPath, this.customRuleExample);
165
164
  return;
166
165
  }
167
166
 
@@ -178,7 +177,7 @@ module.exports = class LintTemplate extends TemplateBase {
178
177
  const timerID = setTimeout(() => {
179
178
  rl.write("no" + os.EOL);
180
179
  }, 10000);
181
- // Ask user whether dependences should be installed
180
+ // Ask user whether dependencies should be installed
182
181
  const question = `${term.warn("Install dependencies now")} ? [y/n] `;
183
182
  let todos = `${term.error(
184
183
  "Aborted!\nPlease install the following components manually:"
@@ -193,7 +192,7 @@ module.exports = class LintTemplate extends TemplateBase {
193
192
  resolve(this._runTask(task));
194
193
  // If use declines or question timeout is reached, print todos
195
194
  } else if (["n", "no"].includes(received.toLowerCase())) {
196
- this.logger.log(todos);
195
+ LOG.info(todos);
197
196
  resolve();
198
197
  } else {
199
198
  // Close and restart question (with new timeout)
@@ -1,53 +1,31 @@
1
- const { existsSync } = require('fs');
2
1
  const { join } = require('path');
3
- const TemplateBase = require('../templateBase');
2
+ const { exists, path } = require('../../../cds').utils
3
+ const { copyFiles } = require('../../util/templateUtil')
4
4
  const ProjectReader = require('../../util/projectReader');
5
5
 
6
- module.exports = class MtaTemplate extends TemplateBase {
6
+ module.exports = class MtaTemplate extends require('../templateBase') {
7
7
  constructor(projectPath, generator) {
8
8
  super(projectPath, generator, __dirname);
9
- this.projectReader = new ProjectReader(this);
9
+ this.projectReader = new ProjectReader(projectPath);
10
+ }
11
+
12
+ static hasFacet(_, projectPath, options) {
13
+ if (!options?.add.has('mta') && options?.add.has('helm')) return false
14
+ return exists(join(projectPath, 'mta.yaml'))
10
15
  }
11
16
 
12
17
  async run() {
13
- const projectDescriptor = await this.projectReader.read();
14
- const { hasApprouter, hasHana, hasXsuaa, isMultitenant, isExtensible, hasMessaging } = projectDescriptor.cap;
15
- if (!existsSync(join(this.projectPath, 'mta.yaml'))) {
16
- await this.templateUtil.copyFiles('.', this.projectPath, projectDescriptor);
18
+ const projectDescriptor = await this.projectReader.read()
19
+ if (!exists(join(this.projectPath, 'mta.yaml'))) {
20
+ await copyFiles(path.join(__dirname, 'files'), this.projectPath, projectDescriptor);
17
21
  }
18
22
 
19
- // Re-applying the merging part of `cds add xsuaa`, `cds add hana`, and `cds add mtx`, if necessary.
20
- // TODO: Find a generic solution for situation like these. Probably involves some restructuring in the
21
- // project reader, so that there's a logical mapping from hasX to XTemplate.
22
- if (hasApprouter) {
23
- const ApprouterTemplate = require(`../approuter`)
24
- const template = new ApprouterTemplate(this.projectPath, this.generator)
25
- await template.runDependentMerging()
26
- }
27
- if (hasHana) {
28
- const HanaTemplate = require(`../hana`)
29
- const template = new HanaTemplate(this.projectPath, this.generator)
30
- await template.runDependentMerging()
31
- }
32
- if (hasXsuaa) {
33
- const XsuaaTemplate = require(`../xsuaa`)
34
- const template = new XsuaaTemplate(this.projectPath, this.generator)
35
- await template.runDependentMerging()
36
- }
37
- if (isMultitenant) {
38
- const MultitenancyTemplate = require(`../multitenancy`)
39
- const template = new MultitenancyTemplate(this.projectPath, this.generator)
40
- await template.runDependentMerging()
41
- }
42
- if (isExtensible) {
43
- const ExtensibilityTemplate = require(`../extensibility`)
44
- const template = new ExtensibilityTemplate(this.projectPath, this.generator)
45
- await template.runDependentMerging()
46
- }
47
- if (hasMessaging) {
48
- const EnterpriseMessagingTemplate = require(`../enterprise-messaging`)
49
- const template = new EnterpriseMessagingTemplate(this.projectPath, this.generator)
50
- await template.runDependentMerging()
23
+ // Re-applying the dependent merging part of other facets if necessary.
24
+ const dependentFacets = ['approuter', 'hana', 'xsuaa', 'multitenancy', 'extensibility', 'enterprise-messaging']
25
+ for (const facet of dependentFacets) {
26
+ const Template = require('../'+facet)
27
+ const template = new Template(this.projectPath, this.generator)
28
+ if (Template.hasFacet(await this.getEnv(), this.projectPath, this.options)) await template.runDependentMerging()
51
29
  }
52
30
  }
53
31
  }
@@ -1,11 +1,10 @@
1
- const TemplateBase = require('../templateBase')
2
1
  const ProjectReader = require('../../util/projectReader')
3
2
  const { OPTION_MULTITENANCY, OPTION_TOGGLES, OPTION_EXTENSIBILITY } = require('../../constants')
4
3
 
5
- module.exports = class MtxTemplate extends TemplateBase {
4
+ module.exports = class MtxTemplate extends require('../templateBase') {
6
5
  constructor(projectPath, generator) {
7
6
  super(projectPath, generator, __dirname)
8
- this.projectReader = new ProjectReader(this)
7
+ this.projectReader = new ProjectReader(projectPath)
9
8
  }
10
9
 
11
10
  async getDependencies() {