@sap/cds-dk 6.3.2 → 6.4.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 (93) hide show
  1. package/CHANGELOG.md +31 -7
  2. package/bin/cds.js +2 -0
  3. package/bin/compile/index.js +2 -1
  4. package/bin/deploy/index.js +2 -2
  5. package/bin/deploy/to-sqlite.js +17 -15
  6. package/bin/help.js +7 -4
  7. package/bin/init.js +1 -1
  8. package/bin/login.js +3 -4
  9. package/bin/migrate.js +33 -0
  10. package/bin/pull.js +4 -4
  11. package/bin/push.js +1 -1
  12. package/bin/subscribe.js +58 -66
  13. package/bin/unsubscribe.js +67 -0
  14. package/bin/watch.js +4 -3
  15. package/lib/bind/bindingUtil.js +2 -0
  16. package/lib/bind/cfKeyProvider.js +5 -1
  17. package/lib/client/activate.js +3 -3
  18. package/lib/client/auth_manager.js +2 -2
  19. package/lib/client/base_command.js +7 -6
  20. package/lib/client/extend.js +2 -2
  21. package/lib/client/helper/errors.js +8 -2
  22. package/lib/client/helper/logging.js +13 -11
  23. package/lib/client/params.js +3 -0
  24. package/lib/client/pull.js +1 -1
  25. package/lib/client/push.js +4 -4
  26. package/lib/client/settings_manager.js +13 -6
  27. package/lib/client/subscription.js +81 -0
  28. package/lib/compile/to-xsuaa.js +25 -19
  29. package/lib/import/odata/metadataconverter/MetadataConverter.js +3 -3
  30. package/lib/import/odata/v2parser.js +37 -24
  31. package/lib/import/odata/v4parser.js +106 -37
  32. package/lib/init/constants.js +1 -1
  33. package/lib/init/index.js +2 -2
  34. package/lib/init/template/_merging/registry-mta.js +0 -3
  35. package/lib/init/template/approuter/files/approuter-configmap.yaml +10 -0
  36. package/lib/init/template/approuter/files/approuter-mtxs-configmap.yaml +15 -0
  37. package/lib/init/template/approuter/files/chart.yaml +4 -0
  38. package/lib/init/template/approuter/files/package.json +1 -1
  39. package/lib/init/template/approuter/files/values.yaml.hbs +31 -0
  40. package/lib/init/template/approuter/index.js +60 -12
  41. package/lib/init/template/auditlog/index.js +16 -8
  42. package/lib/init/template/cf-manifest/index.js +3 -3
  43. package/lib/init/template/connectivity/index.js +19 -10
  44. package/lib/init/template/destinations/index.js +23 -7
  45. package/lib/init/template/enterprise-messaging/files/cds.package.json +1 -2
  46. package/lib/init/template/enterprise-messaging/files/cds.profile.package.json.hbs +1 -2
  47. package/lib/init/template/enterprise-messaging/files/cdsrc.json +1 -2
  48. package/lib/init/template/enterprise-messaging/files/cdsrc.json.hbs +1 -2
  49. package/lib/init/template/enterprise-messaging/files/event-mesh.json.hbs +31 -0
  50. package/lib/init/template/enterprise-messaging/files/mta.yaml.hbs +1 -0
  51. package/lib/init/template/enterprise-messaging/index.js +26 -13
  52. package/lib/init/template/extensibility/index.js +19 -10
  53. package/lib/init/template/hana/files/mta.yaml.hbs +0 -4
  54. package/lib/init/template/hana/index.js +58 -22
  55. package/lib/init/template/helm/chart/templates/NOTES.txt +4 -3
  56. package/lib/init/template/helm/chart/templates/_deployment_helpers.tpl +25 -2
  57. package/lib/init/template/helm/chart/values.root.schema.json +5 -0
  58. package/lib/init/template/helm/chart/values.schema.json +27 -0
  59. package/lib/init/template/helm/files/values.yaml.hbs +1 -1
  60. package/lib/init/template/helm/index.js +25 -23
  61. package/lib/init/template/helm/subchart/templates/_helpers.tpl +29 -0
  62. package/lib/init/template/helm/subchart/templates/api-rule.yaml +5 -5
  63. package/lib/init/template/helm/subchart/templates/deployment.yaml +12 -9
  64. package/lib/init/template/helm/subchart/values.md +258 -88
  65. package/lib/init/template/helm/subchart/values.schema.json +96 -13
  66. package/lib/init/template/helm/subchart/values.yaml +6 -2
  67. package/lib/init/template/html5-repo/index.js +28 -11
  68. package/lib/init/template/java/index.js +5 -5
  69. package/lib/init/template/kibana-logging/index.js +5 -4
  70. package/lib/init/template/mta/index.js +2 -2
  71. package/lib/init/template/mtx/index.js +1 -1
  72. package/lib/init/template/multitenancy/files/chart.yaml +4 -0
  73. package/lib/init/template/multitenancy/files/java/mtxs-configmap.yaml +20 -0
  74. package/lib/init/template/multitenancy/files/java/package.json +6 -9
  75. package/lib/init/template/multitenancy/files/mtxs-configmap.yaml +15 -0
  76. package/lib/init/template/multitenancy/files/saas-registry.yaml +17 -19
  77. package/lib/init/template/multitenancy/files/values.yaml.hbs +47 -0
  78. package/lib/init/template/multitenancy/files/xs-security.json.hbs +0 -7
  79. package/lib/init/template/multitenancy/index.js +83 -37
  80. package/lib/init/template/nodejs/files/.eslintrc +26 -0
  81. package/lib/init/template/nodejs/files/package.json.hbs +0 -28
  82. package/lib/init/template/nodejs/index.js +7 -10
  83. package/lib/init/template/pipeline/index.js +4 -4
  84. package/lib/init/template/samples/index.js +5 -5
  85. package/lib/init/template/templateBase.js +1 -4
  86. package/lib/init/template/toggles/index.js +5 -5
  87. package/lib/init/template/xsuaa/files/values.yaml.hbs +21 -0
  88. package/lib/init/template/xsuaa/index.js +34 -24
  89. package/lib/init/util/md5Tracking.js +113 -0
  90. package/lib/init/util/merge.js +19 -2
  91. package/lib/init/util/projectReader.js +15 -12
  92. package/npm-shrinkwrap.json +630 -1057
  93. package/package.json +3 -3
@@ -1,7 +1,9 @@
1
+ const { join } = require('path')
1
2
  const cds = require('../../../cds')
2
- const { path, copy, exists } = cds.utils
3
+ const { copy, exists } = cds.utils
3
4
  const ProjectReader = require('../../util/projectReader')
4
5
  const { mergeJSON, mergeYAML, sortDependencies } = require('../../util/merge')
6
+ const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking')
5
7
  const {
6
8
  srvNode, srvJava, // Server
7
9
  mtxSidecar, // Additional Modules
@@ -19,27 +21,27 @@ module.exports = class MultitenancyTemplate extends require('../templateBase') {
19
21
  // REVISIT: Check if this can be simplified
20
22
  return options?.add?.has('mtx') || options?.add?.has('multitenancy') ||
21
23
  !!env.requires?.multitenancy || !!env.requires?.db?.multiTenant ||
22
- this.isJava && exists(path.join(projectPath, 'mtx', 'sidecar')) || false
24
+ this.isJava && exists(join(projectPath, 'mtx', 'sidecar')) || false
23
25
  }
24
26
 
25
27
  async run() {
26
28
  const projectDescriptor = await this.projectReader.read(this.options)
27
29
  const { for: forProfile, isNodejs, isJava } = projectDescriptor.cap
28
30
  if (isNodejs) {
29
- const packageJSONPath = path.join(this.projectPath, 'package.json')
31
+ const packageJSONPath = join(this.projectPath, 'package.json')
30
32
  const cdsTemplateFile = forProfile ? 'cds.package.json.hbs' : 'cds.package.json'
31
- await mergeJSON(packageJSONPath, path.join(__dirname, 'files', cdsTemplateFile), projectDescriptor)
32
- await mergeJSON(packageJSONPath, path.join(__dirname, 'files', 'dependencies.package.json'))
33
+ await mergeJSON(packageJSONPath, join(__dirname, 'files', cdsTemplateFile), projectDescriptor)
34
+ await mergeJSON(packageJSONPath, join(__dirname, 'files', 'dependencies.package.json'))
33
35
  await sortDependencies(packageJSONPath)
34
36
  } else if (isJava) {
35
- const cdsrcJSONPath = path.join(this.projectPath, '.cdsrc.json')
36
- await mergeJSON(cdsrcJSONPath, path.join(__dirname, 'files', 'java', '.cdsrc.json'))
37
- await copy(path.join(__dirname, 'files', 'java', 'package.json'), path.join(this.projectPath, 'mtx', 'sidecar', 'package.json'))
37
+ const cdsrcJSONPath = join(this.projectPath, '.cdsrc.json')
38
+ await mergeJSON(cdsrcJSONPath, join(__dirname, 'files', 'java', '.cdsrc.json'))
39
+ await copy(join(__dirname, 'files', 'java', 'package.json'), join(this.projectPath, 'mtx', 'sidecar', 'package.json'))
38
40
  }
39
41
  await this.runDependentMerging()
40
42
  }
41
43
 
42
- async runDependentMerging() {
44
+ async runDependentMerging(context = {}) {
43
45
  const projectDescriptor = await this.projectReader.read()
44
46
  const { isNodejs, isJava, hasMta, hasHelm, hasApprouter, hasXsuaa, hasHana } = projectDescriptor.cap
45
47
 
@@ -66,67 +68,109 @@ module.exports = class MultitenancyTemplate extends require('../templateBase') {
66
68
  }
67
69
  if (hasHana) {
68
70
  relationships.push({
69
- insert: [serviceManager, 'name'],
70
- into: [mtxSidecar, 'requires', 'name'],
71
+ insert: [serviceManager, 'name'],
72
+ into: [mtxSidecar, 'requires', 'name'],
71
73
  })
72
74
  }
73
75
  }
74
76
 
75
- const templateMtaPath = path.join(__dirname, `files`, `mta.yaml.hbs`)
76
- const mtaPath = path.join(this.projectPath, 'mta.yaml')
77
+ const templateMtaPath = join(__dirname, `files`, `mta.yaml.hbs`)
78
+ const mtaPath = join(this.projectPath, 'mta.yaml')
77
79
  const mergingRules = { additions, overwrites, relationships }
78
80
  await mergeYAML(mtaPath, templateMtaPath, projectDescriptor, mergingRules)
79
81
  }
80
82
 
83
+ let isIndependentCommand = false
81
84
  if (hasHelm) {
85
+ //in case facet is being added to the already exisiting charts folder
86
+ if (Object.keys(context).length == 0) {
87
+ isIndependentCommand = true
88
+ context.projectPath = this.projectPath
89
+ context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'))
90
+ }
91
+
82
92
  await mergeYAML(
83
- path.join(this.projectPath, 'chart', 'values.yaml'),
93
+ join(this.projectPath, 'chart', 'values.yaml'),
94
+ join(__dirname, 'files', 'values.yaml.hbs'),
95
+ projectDescriptor
96
+ )
97
+
98
+ await mergeYAML(
99
+ join(this.projectPath, 'chart', 'values.yaml'),
84
100
  {
85
- xsuaa: {
86
- serviceOfferingName: 'saas-registry',
87
- servicePlanName: 'application'
101
+ srv: {
102
+ envFrom: [
103
+ {
104
+ configMapRef: {
105
+ name: "{{ .Release.Name }}-mtxs-configmap",
106
+ tpl: true
107
+ }
108
+ }
109
+ ]
88
110
  }
89
111
  },
90
- null, { forceOverwrite: true }
112
+ projectDescriptor
91
113
  )
92
- //if (hasXsuaa) { // REVISIT: Can we get rid of this dependency?
93
- await copy(
94
- path.join(__dirname, 'files', 'xsuaa.yaml'),
95
- path.join(this.projectPath, 'chart', 'templates', 'xsuaa.yaml')
114
+
115
+ if (isJava) {
116
+ await mergeYAML(
117
+ join(this.projectPath, 'chart', 'Chart.yaml'),
118
+ join(__dirname, 'files', 'chart.yaml'),
119
+ projectDescriptor,
120
+ {
121
+ additions: [{
122
+ ref: `web-application-sidecar`,
123
+ in: `dependencies`,
124
+ where: [{
125
+ property: 'alias',
126
+ isEqualTo: 'sidecar'
127
+ }]
128
+ }]
129
+ }
96
130
  )
97
- //}
98
- await copy(
99
- path.join(__dirname, 'files', 'saas-registry.yaml'),
100
- path.join(this.projectPath, 'chart', 'templates', 'saas-registry.yaml')
131
+ }
132
+
133
+ const mtxsConfigmapPath = isNodejs
134
+ ? join(__dirname, 'files', 'mtxs-configmap.yaml')
135
+ : join(__dirname, 'files', 'java', 'mtxs-configmap.yaml');
136
+
137
+ // add mtxs configmap
138
+ await copyAndTrack(
139
+ mtxsConfigmapPath,
140
+ join(this.projectPath, 'chart', 'templates', 'mtxs-configmap.yaml'),
141
+ context
101
142
  )
143
+
144
+ await copyAndTrack(
145
+ join(__dirname, 'files', 'saas-registry.yaml'),
146
+ join(this.projectPath, 'chart', 'templates', 'saas-registry.yaml'),
147
+ context
148
+ )
149
+ if (isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData)
102
150
  }
103
151
 
104
152
  if (hasApprouter) {
105
153
  const ApprouterTemplate = require(`../approuter`)
106
154
  const template = new ApprouterTemplate(this.projectPath, this.generator)
107
- await template.runDependentMerging()
155
+ await template.runDependentMerging(context)
108
156
  }
109
157
 
110
158
  if (hasHana) {
111
159
  const HanaTemplate = require(`../hana`)
112
160
  const template = new HanaTemplate(this.projectPath, this.generator)
113
- await template.runDependentMerging()
161
+ await template.runDependentMerging(context)
114
162
  }
115
163
 
116
164
  if (hasXsuaa) {
117
165
  await mergeJSON(
118
- path.join(this.projectPath, 'xs-security.json'),
119
- path.join(__dirname, 'files', 'xs-security.json.hbs'),
166
+ join(this.projectPath, 'xs-security.json'),
167
+ join(__dirname, 'files', 'xs-security.json.hbs'),
120
168
  projectDescriptor,
121
169
  {
122
170
  additions: [{
123
171
  ref: 'scope-mtcallback',
124
172
  in: 'scopes',
125
173
  where: [{ property: 'name', isEqualTo: '$XSAPPNAME.mtcallback' }],
126
- }, {
127
- ref: 'scope-subscriber',
128
- in: 'scopes',
129
- where: [{ property: 'name', isEqualTo: '$XSAPPNAME.cds.Subscriber' }],
130
174
  }]
131
175
  }
132
176
  )
@@ -134,10 +178,12 @@ module.exports = class MultitenancyTemplate extends require('../templateBase') {
134
178
 
135
179
  if (hasXsuaa && hasHelm) {
136
180
  // REVISIT: Shared xs-security.json location for Helm and MTA?
137
- await copy(
138
- path.join(this.projectPath, 'xs-security.json'),
139
- path.join(this.projectPath, 'chart', 'xs-security.json')
181
+ await copyAndTrack(
182
+ join(this.projectPath, 'xs-security.json'),
183
+ join(this.projectPath, 'chart', 'xs-security.json'),
184
+ context
140
185
  )
186
+ if (isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData)
141
187
  }
142
188
  }
143
189
  }
@@ -0,0 +1,26 @@
1
+ {
2
+ "extends": "eslint:recommended",
3
+ "env": {
4
+ "es2022": true,
5
+ "node": true,
6
+ "jest": true,
7
+ "mocha": true
8
+ },
9
+ "globals": {
10
+ "SELECT": true,
11
+ "INSERT": true,
12
+ "UPSERT": true,
13
+ "UPDATE": true,
14
+ "DELETE": true,
15
+ "CREATE": true,
16
+ "DROP": true,
17
+ "CDL": true,
18
+ "CQL": true,
19
+ "CXL": true,
20
+ "cds": true
21
+ },
22
+ "rules": {
23
+ "no-console": "off",
24
+ "require-atomic-updates": "off"
25
+ }
26
+ }
@@ -14,33 +14,5 @@
14
14
  },
15
15
  "scripts": {
16
16
  "start": "cds run"
17
- },
18
- "engines": {
19
- "node": "^16.15"
20
- },
21
- "eslintConfig": {
22
- "extends": "eslint:recommended",
23
- "env": {
24
- "es2020": true,
25
- "node": true,
26
- "jest": true,
27
- "mocha": true
28
- },
29
- "globals": {
30
- "SELECT": true,
31
- "INSERT": true,
32
- "UPDATE": true,
33
- "DELETE": true,
34
- "CREATE": true,
35
- "DROP": true,
36
- "CDL": true,
37
- "CQL": true,
38
- "CXL": true,
39
- "cds": true
40
- },
41
- "rules": {
42
- "no-console": "off",
43
- "require-atomic-updates": "off"
44
- }
45
17
  }
46
18
  }
@@ -1,4 +1,4 @@
1
- const path = require('path');
1
+ const { join, relative } = require('path');
2
2
  const { mkdirp } = require('../../../cds').utils
3
3
  const { COMMAND_ADD, OPTION_JAVA, OPTION_NODEJS, URLS } = require('../../constants')
4
4
  const { copyFiles } = require('../../util/templateUtil')
@@ -28,19 +28,16 @@ module.exports = class NodeJSTemplate extends require('../templateBase') {
28
28
 
29
29
  async run() {
30
30
  const env = await this.getEnv();
31
+ const { projectPath, projectName } = this
32
+ await copyFiles(join(__dirname, 'files'), projectPath, { projectName }, this.options.force)
31
33
 
32
- const values = {
33
- projectName: this.projectName
34
- }
35
- await copyFiles(path.join(__dirname, 'files'), this.projectPath, values, this.options.force)
36
-
37
- await mkdirp(this.projectPath, env.folders.db);
38
- await mkdirp(this.projectPath, env.folders.srv);
39
- await mkdirp(this.projectPath, env.folders.app);
34
+ await mkdirp(projectPath, env.folders.db);
35
+ await mkdirp(projectPath, env.folders.srv);
36
+ await mkdirp(projectPath, env.folders.app);
40
37
  }
41
38
 
42
39
  async finalize() {
43
- const relativeProjectPath = path.relative(this.cwd, this.projectPath);
40
+ const relativeProjectPath = relative(this.cwd, this.projectPath);
44
41
  if (relativeProjectPath && relativeProjectPath !== '.') {
45
42
  LOG.info(`Continue with 'cd ${relativeProjectPath}'`);
46
43
  }
@@ -1,4 +1,4 @@
1
- const path = require('path');
1
+ const { join } = require('path');
2
2
  const { exists } = require('../../../cds').utils
3
3
  const { copyFiles } = require('../../util/templateUtil')
4
4
  const { URLS } = require('../../constants')
@@ -14,8 +14,8 @@ module.exports = class PipelineTemplate extends require('../templateBase') {
14
14
  return true;
15
15
  }
16
16
 
17
- if (exists(path.join(this.projectPath, 'Jenkinsfile')) ||
18
- exists(path.join(this.projectPath, '.pipeline/config.yml'))) {
17
+ if (exists(join(this.projectPath, 'Jenkinsfile')) ||
18
+ exists(join(this.projectPath, '.pipeline/config.yml'))) {
19
19
  throw new Error(`Pipeline support file exists. Use --force to overwrite.`);
20
20
  }
21
21
 
@@ -23,7 +23,7 @@ module.exports = class PipelineTemplate extends require('../templateBase') {
23
23
  }
24
24
 
25
25
  async run() {
26
- await copyFiles(path.join(__dirname, 'files'), this.projectPath, {}, this.options.force);
26
+ await copyFiles(join(__dirname, 'files'), this.projectPath, {}, this.options.force);
27
27
  }
28
28
 
29
29
  async finalize() {
@@ -1,4 +1,4 @@
1
- const path = require('path');
1
+ const { join } = require('path');
2
2
  const { copyFiles } = require('../../util/templateUtil')
3
3
  const commandUtil = require('../../util/commandUtil');
4
4
  const mvnArchetypes = require('../../util/mvnArchetypeUtil');
@@ -50,11 +50,11 @@ module.exports = class SamplesTemplate extends require('../templateBase') {
50
50
 
51
51
  async _addNodejsSamples() {
52
52
  const folders = (await this.getEnv()).folders;
53
- const dbFolder = path.join(this.projectPath, folders.db);
54
- await copyFiles(path.join(__dirname, 'files', 'nodejs', 'db'), dbFolder, {}, this.options.force);
53
+ const dbFolder = join(this.projectPath, folders.db);
54
+ await copyFiles(join(__dirname, 'files', 'nodejs', 'db'), dbFolder, {}, this.options.force);
55
55
 
56
- const srvFolder = path.join(this.projectPath, folders.srv);
57
- await copyFiles(path.join(__dirname, 'files', 'nodejs', 'srv'), srvFolder, {
56
+ const srvFolder = join(this.projectPath, folders.srv);
57
+ await copyFiles(join(__dirname, 'files', 'nodejs', 'srv'), srvFolder, {
58
58
  dbFolder: folders.db.replace(/[\\/]+$/, '')
59
59
  }, this.options.force);
60
60
  }
@@ -1,8 +1,6 @@
1
1
  const cds = require('../../cds');
2
2
  const path = require('path');
3
3
 
4
- const TemplateUtil = require('../util/templateUtil');
5
-
6
4
  const { PROJECT_TYPE } = require('../constants');
7
5
  const { exists } = require('../../cds').utils;
8
6
 
@@ -27,10 +25,9 @@ module.exports = class TemplateBase {
27
25
 
28
26
  /**
29
27
  * Returns an array of required templates. These templates will also be added if not already included.
30
- * Declared async to allow complex calculation of the dependencies.
31
28
  * @returns an array with depending templates, might be empty or null
32
29
  */
33
- async getDependencies() {
30
+ getDependencies() {
34
31
  }
35
32
 
36
33
  /**
@@ -1,4 +1,4 @@
1
- const cds = require('../../../cds'), { path } = cds.utils
1
+ const { join } = require('path')
2
2
  const ProjectReader = require('../../util/projectReader')
3
3
  const { mergeJSON, sortDependencies } = require('../../util/merge')
4
4
 
@@ -16,13 +16,13 @@ module.exports = class TogglesTemplate extends require('../templateBase') {
16
16
  const projectDescriptor = await this.projectReader.read(this.options)
17
17
  const { for: forProfile, isNodejs, isJava } = projectDescriptor.cap
18
18
  if (isNodejs) {
19
- const packageJSONPath = path.join(this.projectPath, 'package.json')
19
+ const packageJSONPath = join(this.projectPath, 'package.json')
20
20
  const cdsTemplateFile = forProfile ? 'cds.package.json.hbs' : 'cds.package.json'
21
- await mergeJSON(packageJSONPath, path.join(__dirname, 'files', cdsTemplateFile), projectDescriptor)
21
+ await mergeJSON(packageJSONPath, join(__dirname, 'files', cdsTemplateFile), projectDescriptor)
22
22
  await sortDependencies(packageJSONPath)
23
23
  } else if (isJava) {
24
- const cdsrcPath = path.join(this.projectPath, '.cdsrc.json')
25
- const cdsTemplateFile = path.join(__dirname, 'files', forProfile ? 'cdsrc.json.hbs' : 'cdsrc.json')
24
+ const cdsrcPath = join(this.projectPath, '.cdsrc.json')
25
+ const cdsTemplateFile = join(__dirname, 'files', forProfile ? 'cdsrc.json.hbs' : 'cdsrc.json')
26
26
  await mergeJSON(cdsrcPath, cdsTemplateFile, projectDescriptor)
27
27
  }
28
28
  await this.runDependentMerging()
@@ -1,3 +1,18 @@
1
+ ---
2
+ {{#cap.isJava}}
3
+ {{#cap.isMultitenant}}
4
+ sidecar:
5
+ bindings:
6
+ auth:
7
+ serviceInstanceName: xsuaa
8
+ {{/cap.isMultitenant}}
9
+ {{/cap.isJava}}
10
+ {{#cap.hasApprouter}}
11
+ approuter:
12
+ bindings:
13
+ auth:
14
+ serviceInstanceName: xsuaa
15
+ {{/cap.hasApprouter}}
1
16
  srv:
2
17
  bindings:
3
18
  auth:
@@ -7,4 +22,10 @@ xsuaa:
7
22
  servicePlanName: application
8
23
  parameters:
9
24
  xsappname: {{cap.appName}}
25
+ tenant-mode: {{#cap.isMultitenant}}shared{{/cap.isMultitenant}}{{^cap.isMultitenant}}dedicated{{/cap.isMultitenant}}
26
+ {{#cap.hasApprouter}}
27
+ oauth2-configuration:
28
+ redirect-uris:
29
+ - https://*.<your-cluster-domain>/**
30
+ {{/cap.hasApprouter}}
10
31
  config: xs-security.json
@@ -1,8 +1,7 @@
1
- const path = require('path')
2
- const cds = require('../../../cds')
3
- const { copy } = cds.utils
1
+ const { join } = require('path')
4
2
  const ProjectReader = require('../../util/projectReader')
5
3
  const { mergeJSON, mergeYAML } = require('../../util/merge')
4
+ const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking')
6
5
  const { srvNode, srvJava, xsuaa, mtxSidecar } = require('../_merging/registry-mta')
7
6
  const { PROJECT_TYPE } = require('../../constants')
8
7
 
@@ -18,35 +17,35 @@ module.exports = class XsuaaTemplate extends require('../templateBase') {
18
17
 
19
18
  async run() {
20
19
  const { projectPath } = this
21
- const templatePath = path.join(__dirname, 'files')
20
+ const templatePath = join(__dirname, 'files')
22
21
  const projectDescriptor = await this.projectReader.read(this.options)
23
22
  const projectType = await this.getProjectType();
24
23
  const { for: forProfile } = projectDescriptor.cap
25
24
 
26
25
  if (projectType === PROJECT_TYPE.java) {
27
- const cdsrcJSONPath = path.join(projectPath, '.cdsrc.json')
26
+ const cdsrcJSONPath = join(projectPath, '.cdsrc.json')
28
27
  const cdsTemplateFile = forProfile ? 'cds.cdsrc.json.hbs' : 'cds.cdsrc.json'
29
- const cdsTemplatePath = path.join(templatePath, cdsTemplateFile)
28
+ const cdsTemplatePath = join(templatePath, cdsTemplateFile)
30
29
  await mergeJSON(cdsrcJSONPath, cdsTemplatePath, projectDescriptor)
31
30
  } else if (projectType === PROJECT_TYPE.nodejs) {
32
- const packageJSONPath = path.join(projectPath, 'package.json')
31
+ const packageJSONPath = join(projectPath, 'package.json')
33
32
  const cdsTemplateFile = forProfile ? 'cds.package.json.hbs' : 'cds.package.json'
34
- const cdsTemplatePath = path.join(templatePath, cdsTemplateFile)
33
+ const cdsTemplatePath = join(templatePath, cdsTemplateFile)
35
34
  await mergeJSON(packageJSONPath, cdsTemplatePath, projectDescriptor)
36
- const dependenciesTemplatePath = path.join(templatePath, 'dependencies.package.json')
35
+ const dependenciesTemplatePath = join(templatePath, 'dependencies.package.json')
37
36
  await mergeJSON(packageJSONPath, dependenciesTemplatePath)
38
37
  }
39
38
 
40
39
  await this.runDependentMerging()
41
40
  }
42
41
 
43
- async runDependentMerging() {
42
+ async runDependentMerging( context = {}) {
44
43
  const projectDescriptor = await this.projectReader.read(this.options)
45
44
  const { isMultitenant, isExtensible, hasMta, hasHelm, isNodejs, isJava } = projectDescriptor.cap
46
45
 
47
46
  const cds = require('../../../../lib/compile')
48
47
  const xsSecurity = await (async () => { try {
49
- const models = await cds.load(path.join(this.projectPath, cds.env.folders.srv))
48
+ const models = await cds.load(join(this.projectPath, cds.env.folders.srv))
50
49
  return cds.compile.to.xsuaa(models)
51
50
  } catch (error) { /* ignore */ }
52
51
  })() || { scopes: [], attributes: [], 'role-templates': [], 'authorities-inheritance': false }
@@ -58,7 +57,7 @@ module.exports = class XsuaaTemplate extends require('../templateBase') {
58
57
  isEqualTo: scope.name
59
58
  }],
60
59
  }))}
61
- const xsSecurityPath = path.join(this.projectPath, 'xs-security.json')
60
+ const xsSecurityPath = join(this.projectPath, 'xs-security.json')
62
61
  await mergeJSON(xsSecurityPath, xsSecurity, projectDescriptor, mergingSemantics)
63
62
 
64
63
  if (hasMta) {
@@ -66,7 +65,7 @@ module.exports = class XsuaaTemplate extends require('../templateBase') {
66
65
  const additions = [srv, xsuaa]
67
66
  if (isMultitenant && isJava) additions.push(mtxSidecar)
68
67
 
69
- const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml')
68
+ const mtaYAMLPath = join(this.projectPath, 'mta.yaml')
70
69
  const relationships = [{
71
70
  insert: [xsuaa, 'name'],
72
71
  into: [srv, 'requires', 'name']
@@ -88,20 +87,30 @@ module.exports = class XsuaaTemplate extends require('../templateBase') {
88
87
  }
89
88
 
90
89
  if (hasHelm) {
91
- await copy(
92
- path.join(__dirname, 'files', 'xsuaa.yaml'),
93
- path.join(this.projectPath, 'chart', 'templates', 'xsuaa.yaml')
90
+ //in case facet is being added to the already exisiting charts folder
91
+ let isIndependentCommand = false;
92
+ if(Object.keys(context).length == 0){
93
+ isIndependentCommand = true;
94
+ context.projectPath = this.projectPath;
95
+ context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'));
96
+ }
97
+ await copyAndTrack(
98
+ join(__dirname, 'files', 'xsuaa.yaml'),
99
+ join(this.projectPath, 'chart', 'templates', 'xsuaa.yaml'),
100
+ context
94
101
  )
95
102
  await mergeYAML(
96
- path.join(this.projectPath, 'chart', 'values.yaml'),
97
- path.join(__dirname, 'files', 'values.yaml.hbs'),
98
- projectDescriptor, { forceOverwrite: true }
103
+ join(this.projectPath, 'chart', 'values.yaml'),
104
+ join(__dirname, 'files', 'values.yaml.hbs'),
105
+ projectDescriptor
99
106
  )
100
107
  // REVISIT: Shared xs-security.json location for Helm and MTA?
101
- await copy(
102
- path.join(this.projectPath, 'xs-security.json'),
103
- path.join(this.projectPath, 'chart', 'xs-security.json')
108
+ await copyAndTrack(
109
+ join(this.projectPath, 'xs-security.json'),
110
+ join(this.projectPath, 'chart', 'xs-security.json'),
111
+ context
104
112
  )
113
+ if(isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData);
105
114
  }
106
115
 
107
116
  // Re-applying the merging part of `cds add mtx` because cds.compile.to.xsuaa
@@ -110,12 +119,13 @@ module.exports = class XsuaaTemplate extends require('../templateBase') {
110
119
  if (isMultitenant) {
111
120
  const MultitenancyTemplate = require(`../multitenancy`)
112
121
  const multitenancyTemplate = new MultitenancyTemplate(this.projectPath, this.generator)
113
- await multitenancyTemplate.runDependentMerging()
122
+ await multitenancyTemplate.runDependentMerging(context)
114
123
  }
124
+
115
125
  if (isExtensible) {
116
126
  const ExtensibilityTemplate = require(`../extensibility`)
117
127
  const extensibilityTemplate = new ExtensibilityTemplate(this.projectPath, this.generator)
118
- await extensibilityTemplate.runDependentMerging()
128
+ await extensibilityTemplate.runDependentMerging(context)
119
129
  }
120
130
  }
121
131
  }
@@ -0,0 +1,113 @@
1
+ const path = require('path'), { dirname, resolve } = path;
2
+ const { mkdirp, isdir } = require('../../cds').utils;
3
+ const cds = require('../../cds');
4
+
5
+ const fs = require('fs');
6
+ const crypto = require('crypto');
7
+ const LOG = cds.log('k8s');
8
+ const os = require('os');
9
+
10
+ async function copyAndTrack(source, dest, context = {}, force = false) {
11
+ const sourcePath = resolve(cds.root, source);
12
+ const destPath = resolve(cds.root, dest);
13
+ //if (fs.promises.cp) return fs.promises.cp(src, dst, { recursive: true });
14
+ await mkdirp(dirname(destPath));
15
+ if (isdir(sourcePath)) {
16
+ const entries = await fs.promises.readdir(sourcePath);
17
+ return Promise.all(entries.map(async each => {
18
+ const subSourcePath = path.join(sourcePath, each);
19
+ const subDestPath = path.join(destPath, each);
20
+ return copyAndTrack(subSourcePath, subDestPath, context);
21
+ }))
22
+ } else {
23
+ let data = await _readFileIfExists(sourcePath, 'utf-8');
24
+ if (!force && await _isChartFileModified(destPath, context)) {
25
+ LOG.warn("Chart file " + destPath + " has been modified and will not be updated.");
26
+ } else {
27
+ _track(destPath, data, context);
28
+ return fs.promises.copyFile(sourcePath, destPath);
29
+ }
30
+ }
31
+ }
32
+
33
+
34
+ /**
35
+ * Takes path of md5 file as an argument and returns a JSON object containing hashes of files stored in MD5 file.
36
+ * @param {String} path
37
+ * @returns {Promise<JSON>}
38
+ */
39
+ async function parseMd5File(path) {
40
+ let md5Hashes = {};
41
+ const md5FileContent = await _readFileIfExists(path);
42
+ if (md5FileContent == undefined) return md5Hashes;
43
+ let md5Checksums = md5FileContent.toString().split(os.EOL)
44
+ md5Checksums.forEach((checksum) => {
45
+ checksum = checksum.split(" ")
46
+ md5Hashes[checksum[1]] = checksum[0];
47
+ })
48
+ return md5Hashes;
49
+ }
50
+
51
+ /**
52
+ * Takes json object containing key as filename and value as MD5 hash and generates a md5sum format file.
53
+ * @param {String} path
54
+ * @param {Promise<JSON>} data
55
+ */
56
+ async function writeMd5File(path, data) {
57
+ let md5_output;
58
+ Object.keys(data).forEach(key => {
59
+ var currMd5 = `${data[key]} ${key}`;
60
+ if (md5_output === undefined)
61
+ md5_output = currMd5;
62
+ else
63
+ md5_output += os.EOL + currMd5;
64
+ })
65
+ await fs.promises.writeFile(path, md5_output);
66
+ }
67
+
68
+ async function _readFileIfExists(path, encoding) {
69
+ try {
70
+ return await fs.promises.readFile(path, encoding);
71
+ } catch (error) {
72
+ if (error.code === 'ENOENT' || error.code === 'EISDIR') return undefined;
73
+ else throw error;
74
+ }
75
+ }
76
+
77
+ async function _isChartFileModified(filePath, context = {}) {
78
+ const data = await _readFileIfExists(filePath, 'utf-8');
79
+ if (data == undefined) {
80
+ return false;
81
+ }
82
+
83
+ const key = _pathKey(path.join(context.projectPath, 'chart'), filePath);
84
+ const currentHash = _hash(data);
85
+ return context.oldTrackingData != undefined && context.oldTrackingData[key] != undefined && context.oldTrackingData[key] != currentHash;
86
+ }
87
+
88
+ function _hash(data) {
89
+ return crypto.createHash('md5').update(data).digest('base64');
90
+ }
91
+
92
+ function _pathKey(basePath, cPath) {
93
+ return path.posix.normalize(_toPosix(path.relative(basePath, cPath)))
94
+ }
95
+
96
+ function _toPosix(path) {
97
+ return path.replace(/\\/g, '/');
98
+ }
99
+
100
+ async function _track(filePath, data, context = {}) {
101
+ const key = _pathKey(path.join(context.projectPath, 'chart'), filePath);
102
+ const hashedContent = _hash(data);
103
+ if (context.oldTrackingData != undefined && context.oldTrackingData[key] != undefined) {
104
+ context.oldTrackingData[key] = hashedContent;
105
+ }
106
+ context.newTrackingData[key] = hashedContent;
107
+ }
108
+
109
+ module.exports = {
110
+ copyAndTrack,
111
+ parseMd5File,
112
+ writeMd5File
113
+ }