@sap/cds-dk 6.0.4 → 6.1.3
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.
- package/CHANGELOG.md +60 -1
- package/bin/add.js +29 -16
- package/bin/compile/index.js +7 -2
- package/bin/fix-redirects.js +4 -2
- package/bin/init.js +5 -0
- package/bin/login.js +20 -4
- package/bin/pull.js +58 -0
- package/bin/push.js +52 -0
- package/bin/subscribe.js +45 -0
- package/lib/bind/bindingUtil.js +1 -2
- package/lib/cds.js +2 -3
- package/lib/client/activate.js +17 -16
- package/lib/client/auth_manager.js +10 -5
- package/lib/client/base_command.js +4 -6
- package/lib/client/extend.js +3 -2
- package/lib/client/helper/cf_helper.js +1 -0
- package/lib/client/helper/errors.js +11 -0
- package/lib/client/helper/logging.js +3 -10
- package/lib/client/helper/url_helper.js +7 -3
- package/lib/client/index.js +1 -1
- package/lib/client/params.js +9 -6
- package/lib/client/pull.js +48 -0
- package/lib/client/push.js +45 -0
- package/lib/client/settings_manager.js +81 -27
- package/lib/compile/openapi/csdl2openapi.js +135 -163
- package/lib/compile/openapi/index.js +0 -1
- package/lib/import/common.js +9 -1
- package/lib/import/odata/metadataconverter/MetadataConverter.js +17 -4
- package/lib/import/odata/v2parser.js +50 -26
- package/lib/import/odata/v4parser.js +110 -29
- package/lib/import/openapi/importOpenAPI.js +3 -3
- package/lib/init/constants.js +9 -3
- package/lib/init/template/_merging/registry-mta.js +284 -0
- package/lib/init/template/approuter/files/xs-app.json.hbs +7 -7
- package/lib/init/template/approuter/index.js +22 -32
- package/lib/init/template/auditlog/index.js +7 -9
- package/lib/init/template/data/index.js +2 -4
- package/lib/init/template/extensibility/files/cds.package.json +7 -0
- package/lib/init/template/extensibility/files/cds.package.json.hbs +9 -0
- package/lib/init/template/extensibility/files/xs-security.json.hbs +26 -0
- package/lib/init/template/extensibility/index.js +48 -0
- package/lib/init/template/hana/files/java/cdsrc.json.hbs +1 -1
- package/lib/init/template/hana/files/java/profile.cdsrc.json.hbs +2 -2
- package/lib/init/template/hana/files/mta.yaml.hbs +10 -0
- package/lib/init/template/hana/files/nodejs/cds.package.json.hbs +1 -1
- package/lib/init/template/hana/files/nodejs/cds.profile.package.json.hbs +2 -2
- package/lib/init/template/hana/index.js +74 -61
- package/lib/init/template/kibana-logging/index.js +31 -37
- package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +14 -14
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
- package/lib/init/template/mta/index.js +13 -7
- package/lib/init/template/mtx/index.js +2 -142
- package/lib/init/template/multitenancy/files/cds.package.json +7 -0
- package/lib/init/template/multitenancy/files/cds.package.json.hbs +9 -0
- package/lib/init/template/{mtx → multitenancy}/files/dependencies.package.json +1 -1
- package/lib/init/template/multitenancy/files/java/.cdsrc.json +19 -0
- package/lib/init/template/multitenancy/files/java/package.json +31 -0
- package/lib/init/template/{mtx → multitenancy}/files/mta.yaml.hbs +13 -6
- package/lib/init/template/multitenancy/files/xs-security.json.hbs +18 -0
- package/lib/init/template/multitenancy/index.js +109 -0
- package/lib/init/template/nodejs/files/package.json.hbs +4 -1
- package/lib/init/template/templateBase.js +2 -1
- package/lib/init/template/toggles/files/cds.package.json +7 -0
- package/lib/init/template/toggles/files/cds.package.json.hbs +9 -0
- package/lib/init/template/toggles/index.js +24 -0
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +10 -0
- package/lib/init/template/xsuaa/index.js +44 -33
- package/lib/init/util/projectReader.js +12 -7
- package/lib/init/util/templateUtil.js +113 -111
- package/lib/k8s/ChartAdder.js +13 -3
- package/lib/k8s/ChartBuilder.js +6 -0
- package/lib/k8s/buildModel.js +1 -3
- package/lib/k8s/connectivity/index.js +5 -5
- package/lib/k8s/deployment/index.js +2 -4
- package/lib/k8s/deployment/subchart/Chart.yaml +1 -1
- package/lib/k8s/deployment/subchart/templates/_helpers.tpl +22 -11
- package/lib/k8s/deployment/subchart/templates/deployment.yaml +12 -5
- package/lib/k8s/deployment/subchart/templates/network-policy.yaml +3 -1
- package/lib/k8s/deployment/subchart/templates/pod-disruption-budget.yaml +1 -1
- package/lib/k8s/deployment/subchart/values.md +812 -0
- package/lib/k8s/deployment/subchart/values.schema.json +125 -30
- package/lib/k8s/deployment/subchart/values.yaml +7 -3
- package/lib/k8s/hana-deployer/index.js +10 -0
- package/lib/k8s/hana-deployer/templates/hana-deployer-job.yaml +8 -0
- package/lib/k8s/html5-apps-deployer/index.js +10 -0
- package/lib/k8s/html5-apps-deployer/templates/html5-apps-deployer-job.yaml +8 -0
- package/lib/k8s/index.js +2 -2
- package/lib/k8s/resources/helm/chart/schemas/values.root.schema.json +11 -0
- package/lib/k8s/resources/helm/chart/schemas/values.schema.json +479 -0
- package/lib/k8s/resources/helm/chart/templates/_deployment_helpers.tpl +1 -159
- package/lib/k8s/resources/helm/chart/templates/_helpers.tpl +0 -33
- package/lib/k8s/resources/helm/chart/templates/_sapcp_helpers.tpl +1 -1
- package/lib/lint/Linter.js +155 -158
- package/lib/lint/io.js +12 -5
- package/npm-shrinkwrap.json +214 -74
- package/package.json +5 -4
- package/lib/init/template/_merging/existences.js +0 -297
- package/lib/init/template/mtx/files/cds.package.json +0 -12
- package/lib/init/template/mtx/files/cds.package.json.hbs +0 -14
- package/lib/init/template/mtx/files/java/.cdsrc.json +0 -17
- package/lib/init/template/mtx/files/java/package.json +0 -43
- package/lib/init/template/mtx/files/java/server.js +0 -30
- package/lib/init/template/mtx/files/xs-security.json.hbs +0 -48
- package/lib/lint/.eslintrc.js +0 -3
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
1
|
const path = require('path')
|
|
3
2
|
const TemplateBase = require('../templateBase')
|
|
4
3
|
const ProjectReader = require('../../util/projectReader')
|
|
5
|
-
const { srvNode, srvJava, xsuaa } = require('../_merging/
|
|
6
|
-
const { PROJECT_TYPE, OPTION_HELM_UPDATE } = require('../../constants')
|
|
4
|
+
const { srvNode, srvJava, xsuaa, mtxSidecar } = require('../_merging/registry-mta')
|
|
5
|
+
const { PROJECT_TYPE, OPTION_HELM_UPDATE } = require('../../constants')
|
|
7
6
|
|
|
8
7
|
module.exports = class XsuaaTemplate extends TemplateBase {
|
|
9
8
|
constructor(projectPath, generator) {
|
|
@@ -13,35 +12,46 @@ module.exports = class XsuaaTemplate extends TemplateBase {
|
|
|
13
12
|
|
|
14
13
|
async runDependentMerging() {
|
|
15
14
|
const projectDescriptor = await this.projectReader.read(this.options)
|
|
16
|
-
const {
|
|
15
|
+
const { isMultitenant, isExtensible, hasMtaDeployment, isNodejs, isJava } = projectDescriptor.cap
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
if (hasMtaDeployment) {
|
|
18
|
+
const srv = isNodejs ? srvNode : srvJava
|
|
19
|
+
const additions = [srv, xsuaa]
|
|
20
|
+
if (isMultitenant && isJava) additions.push(mtxSidecar)
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
{
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml')
|
|
23
|
+
const relationships = [{
|
|
24
|
+
insert: [xsuaa, 'name'],
|
|
25
|
+
into: [srv, 'requires', 'name']
|
|
26
|
+
}]
|
|
27
|
+
relationships.push({
|
|
28
|
+
insert: [xsuaa, 'name'],
|
|
29
|
+
into: [mtxSidecar, 'requires', 'name']
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
await this.templateUtil.mergeYAML(
|
|
33
|
+
mtaYAMLPath,
|
|
34
|
+
`${__dirname}/files/mta.yaml.hbs`,
|
|
35
|
+
projectDescriptor,
|
|
36
|
+
{
|
|
37
|
+
additions,
|
|
38
|
+
relationships
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
}
|
|
37
42
|
|
|
38
43
|
// Re-applying the merging part of `cds add mtx` because cds.compile.to.xsuaa
|
|
39
44
|
// has overwritten the existing `xs-security.json`.
|
|
40
45
|
// TODO: Find a generic solution for situation like these.
|
|
41
|
-
if (
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
await
|
|
46
|
+
if (isMultitenant) {
|
|
47
|
+
const MultitenancyTemplate = require(`../multitenancy`)
|
|
48
|
+
const multitenancyTemplate = new MultitenancyTemplate(this.projectPath, this.generator)
|
|
49
|
+
await multitenancyTemplate.runDependentMerging()
|
|
50
|
+
}
|
|
51
|
+
if (isExtensible) {
|
|
52
|
+
const ExtensibilityTemplate = require(`../extensibility`)
|
|
53
|
+
const extensibilityTemplate = new ExtensibilityTemplate(this.projectPath, this.generator)
|
|
54
|
+
await extensibilityTemplate.runDependentMerging()
|
|
45
55
|
}
|
|
46
56
|
}
|
|
47
57
|
|
|
@@ -49,19 +59,20 @@ module.exports = class XsuaaTemplate extends TemplateBase {
|
|
|
49
59
|
const { projectPath } = this
|
|
50
60
|
const templatePath = path.join(__dirname, 'files')
|
|
51
61
|
const projectDescriptor = await this.projectReader.read(this.options)
|
|
62
|
+
const { for: forProfile } = projectDescriptor.cap
|
|
52
63
|
|
|
53
64
|
const projectType = await this.getProjectType();
|
|
54
65
|
switch (projectType) {
|
|
55
66
|
case PROJECT_TYPE.java: {
|
|
56
67
|
const cdsrcJSONPath = path.join(projectPath, '.cdsrc.json')
|
|
57
|
-
const cdsTemplateFile =
|
|
68
|
+
const cdsTemplateFile = forProfile ? 'cds.cdsrc.json.hbs' : 'cds.cdsrc.json'
|
|
58
69
|
const cdsTemplatePath = path.join(templatePath, cdsTemplateFile)
|
|
59
70
|
await this.templateUtil.mergeJSON(cdsrcJSONPath, cdsTemplatePath, projectDescriptor)
|
|
60
71
|
break
|
|
61
72
|
}
|
|
62
73
|
case PROJECT_TYPE.nodejs: {
|
|
63
74
|
const packageJSONPath = path.join(projectPath, 'package.json')
|
|
64
|
-
const cdsTemplateFile =
|
|
75
|
+
const cdsTemplateFile = forProfile ? 'cds.package.json.hbs' : 'cds.package.json'
|
|
65
76
|
const cdsTemplatePath = path.join(templatePath, cdsTemplateFile)
|
|
66
77
|
await this.templateUtil.mergeJSON(packageJSONPath, cdsTemplatePath, projectDescriptor)
|
|
67
78
|
const dependenciesTemplatePath = path.join(templatePath, 'dependencies.package.json')
|
|
@@ -76,12 +87,12 @@ module.exports = class XsuaaTemplate extends TemplateBase {
|
|
|
76
87
|
} catch (error) { /* ignore */ }
|
|
77
88
|
})() || { scopes: [], attributes: [], 'role-templates': [], 'authorities-inheritance': false }
|
|
78
89
|
|
|
79
|
-
const mergingSemantics = {
|
|
90
|
+
const mergingSemantics = { additions: xsuaa.scopes.map(scope => ({
|
|
80
91
|
ref: scope.name,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
92
|
+
in: 'scopes',
|
|
93
|
+
where: [{
|
|
94
|
+
property: 'name',
|
|
95
|
+
isEqualTo: scope.name
|
|
85
96
|
}],
|
|
86
97
|
}))}
|
|
87
98
|
const xsSecurityPath = path.join(projectPath, 'xs-security.json')
|
|
@@ -63,6 +63,7 @@ module.exports = class ProjectReader {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
async _getCapDescriptor(env, options) {
|
|
66
|
+
const projectPath = this.projectPath
|
|
66
67
|
let capDescriptor = {
|
|
67
68
|
for: options && options.for,
|
|
68
69
|
pLanguage: DEFAULT_P_LANGUAGE,
|
|
@@ -70,12 +71,17 @@ module.exports = class ProjectReader {
|
|
|
70
71
|
db: [],
|
|
71
72
|
requires: [],
|
|
72
73
|
get isMultitenant() {
|
|
73
|
-
return options
|
|
74
|
+
return options?.add?.has('mtx') || options?.add?.has('multitenancy') ||
|
|
74
75
|
env.requires.multitenancy ||
|
|
75
|
-
env.requires.db
|
|
76
|
-
this.isJava && fs.existsSync('mtx
|
|
76
|
+
env.requires.db?.multiTenant ||
|
|
77
|
+
this.isJava && fs.existsSync(path.join('mtx', 'sidecar')) ||
|
|
77
78
|
false
|
|
78
79
|
},
|
|
80
|
+
get isExtensible() {
|
|
81
|
+
const sidecarPackage = path.join('mtx', 'sidecar', 'package.json')
|
|
82
|
+
return options?.add?.has('mtx') || options?.add?.has('extensibility') || env.requires.extensibility ||
|
|
83
|
+
fs.existsSync(sidecarPackage) && JSON.parse(fs.readFileSync(sidecarPackage, 'utf8')).cds.requires.extensibility === true
|
|
84
|
+
},
|
|
79
85
|
get isNodejs() {
|
|
80
86
|
return this.pLanguage === P_LANGUAGE_NODEJS
|
|
81
87
|
},
|
|
@@ -99,6 +105,9 @@ module.exports = class ProjectReader {
|
|
|
99
105
|
},
|
|
100
106
|
get hasApprouter() {
|
|
101
107
|
return !!env.requires.approuter
|
|
108
|
+
},
|
|
109
|
+
get hasMtaDeployment() {
|
|
110
|
+
return fs.existsSync(path.join(projectPath, 'mta.yaml'))
|
|
102
111
|
}
|
|
103
112
|
}
|
|
104
113
|
|
|
@@ -392,7 +401,6 @@ module.exports = class ProjectReader {
|
|
|
392
401
|
// use different service name to avoid conflicts when switching from single tenant to multitenant
|
|
393
402
|
// otherwise we would enforce that users have to delete the db container first
|
|
394
403
|
if (resource.isMultitenant) {
|
|
395
|
-
//resource.name += '-mt'
|
|
396
404
|
resource.service = 'service-manager'
|
|
397
405
|
resource.vcap.plan = 'container'
|
|
398
406
|
} else {
|
|
@@ -402,9 +410,6 @@ module.exports = class ProjectReader {
|
|
|
402
410
|
break
|
|
403
411
|
|
|
404
412
|
case 'xsuaa':
|
|
405
|
-
// if (capDescriptor.isMultitenant) {
|
|
406
|
-
// resource.name += '-mt'
|
|
407
|
-
// }
|
|
408
413
|
resource.service = reqEntry.kind
|
|
409
414
|
resource.vcap.plan = 'application'
|
|
410
415
|
break
|
|
@@ -68,31 +68,29 @@ module.exports = class TemplateUtil {
|
|
|
68
68
|
just maps where you can do a key-value replacement.
|
|
69
69
|
*/
|
|
70
70
|
_deepMerge(target, source) {
|
|
71
|
+
const unique = array => [...new Set(array.map(JSON.stringify))].map(JSON.parse)
|
|
71
72
|
if (this._isObject(target) && this._isObject(source)) {
|
|
72
73
|
for (const key in source) {
|
|
73
74
|
if (this._isObject(source[key])) {
|
|
74
|
-
if (!target[key]) Object.assign(target, { [key]: source[key] })
|
|
75
|
-
|
|
76
|
-
else this._deepMerge(target[key], source[key]);
|
|
75
|
+
if (!target[key]) Object.assign(target, { [key]: source[key] })
|
|
76
|
+
else this._deepMerge(target[key], source[key])
|
|
77
77
|
} else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
|
|
78
|
-
const unique = array => [...new Set(array.map(JSON.stringify))].map(JSON.parse);
|
|
79
78
|
target[key] = unique([...source[key], ...target[key]])
|
|
80
79
|
} else {
|
|
81
|
-
Object.assign(target, { [key]: target[key] || source[key] })
|
|
80
|
+
Object.assign(target, { [key]: target[key] || source[key] })
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
} else if (Array.isArray(target) && Array.isArray(source)) {
|
|
85
|
-
const unique = array => [...new Set(array.map(JSON.stringify))].map(JSON.parse);
|
|
86
84
|
target = unique([...source, ...target])
|
|
87
85
|
}
|
|
88
|
-
return target || source
|
|
86
|
+
return target || source
|
|
89
87
|
}
|
|
90
88
|
|
|
91
89
|
async mergeJSON(targetPath, from, projectDescriptor, semantics) {
|
|
92
90
|
const source = typeof from === 'string' ? await this.fsUtil.readJSON(from, projectDescriptor) : from
|
|
93
91
|
|
|
94
92
|
if (! await this.fsUtil.pathExists(targetPath)) {
|
|
95
|
-
await this.fsUtil.writeJSON(targetPath, source)
|
|
93
|
+
await this.fsUtil.writeJSON(targetPath, source)
|
|
96
94
|
} else if (semantics) {
|
|
97
95
|
const target = await this.fsUtil.readJSON(targetPath)
|
|
98
96
|
|
|
@@ -104,11 +102,11 @@ module.exports = class TemplateUtil {
|
|
|
104
102
|
const result = YAML.parse(YAML.stringify(resultYAML))
|
|
105
103
|
await this.fsUtil.writeJSON(targetPath, result)
|
|
106
104
|
} else {
|
|
107
|
-
const target = await this.fsUtil.readJSON(targetPath)
|
|
108
|
-
const sourceFile = await this._processTemplateFile(from, projectDescriptor)
|
|
109
|
-
const source = JSON.parse(sourceFile)
|
|
110
|
-
const result = target && source ? this._deepMerge(target, source) : target || source
|
|
111
|
-
await this.fsUtil.writeJSON(targetPath, result)
|
|
105
|
+
const target = await this.fsUtil.readJSON(targetPath)
|
|
106
|
+
const sourceFile = await this._processTemplateFile(from, projectDescriptor)
|
|
107
|
+
const source = JSON.parse(sourceFile)
|
|
108
|
+
const result = target && source ? this._deepMerge(target, source) : target || source
|
|
109
|
+
await this.fsUtil.writeJSON(targetPath, result)
|
|
112
110
|
}
|
|
113
111
|
}
|
|
114
112
|
|
|
@@ -121,98 +119,95 @@ module.exports = class TemplateUtil {
|
|
|
121
119
|
const existenceMap = new Map()
|
|
122
120
|
const templateExistenceMap = new Map()
|
|
123
121
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
existences && existences.forEach(existence => {
|
|
122
|
+
const { additions, overwrites, deletions, relationships } = semantics
|
|
123
|
+
additions?.forEach(existence => {
|
|
127
124
|
existenceMap.set(existence.ref, undefined)
|
|
128
125
|
templateExistenceMap.set(existence.ref, undefined)
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
const { deletions } = semantics
|
|
132
|
-
deletions && deletions.forEach(deletion => {
|
|
133
|
-
existenceMap.set(deletion.existence.ref, undefined)
|
|
134
126
|
})
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
127
|
+
deletions?.forEach(deletion => {
|
|
128
|
+
existenceMap.set(deletion.item.ref, undefined)
|
|
129
|
+
})
|
|
130
|
+
relationships?.forEach(relationship => {
|
|
131
|
+
const [existence] = relationship.into
|
|
132
|
+
const [insertExistence] = relationship.insert
|
|
133
|
+
const ref = insertExistence.ref + ' -> ' + existence.ref
|
|
134
|
+
existenceMap.set(ref, undefined)
|
|
135
|
+
})
|
|
142
136
|
|
|
143
137
|
let collectionStack = [target.contents]
|
|
144
138
|
|
|
145
|
-
const _getProperty = (object, keyPath) => keyPath.reduce((p,
|
|
146
|
-
const _getYAMLProperty = (object, keyPath) => keyPath.reduce((p,
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
const _addToMap = existences => existences
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
139
|
+
const _getProperty = (object, keyPath) => keyPath.split('.').reduce((p, k) => p && p[k], object)
|
|
140
|
+
const _getYAMLProperty = (object, keyPath) => keyPath.split('.').reduce((p, k) => p && p.get(k), object)
|
|
141
|
+
|
|
142
|
+
const _validateWhere = (node, dict, index) => {
|
|
143
|
+
const _addToMap = existences => existences?.filter(existence => {
|
|
144
|
+
let where = existence.in
|
|
145
|
+
if (typeof where === 'string') return true // just a key path on the document root
|
|
146
|
+
else where = where[0] // a more complex list of constraints, a sequence/array is involved
|
|
147
|
+
const neededParent = dict.get(where.ref)?.node
|
|
148
|
+
return collectionStack.includes(neededParent) // lookbehind in parent collection stack
|
|
149
|
+
// REVISIT: Only look behind until sequence is reached?
|
|
150
|
+
}).forEach(({ where, ref }) => {
|
|
151
|
+
const json = JSON.parse(String(node))
|
|
152
|
+
const whereFulfilled = where.every(constraint =>
|
|
153
|
+
constraint.isEqualTo === _getProperty(json, constraint.property)
|
|
154
|
+
)
|
|
155
|
+
if (whereFulfilled) {
|
|
156
|
+
const [collection] = collectionStack
|
|
157
|
+
dict.set(ref, { json, node, index, collection })
|
|
158
|
+
}
|
|
164
159
|
})
|
|
165
|
-
_addToMap(
|
|
166
|
-
deletions
|
|
160
|
+
if (additions) _addToMap(additions)
|
|
161
|
+
if (deletions) _addToMap(deletions.map(deletion => deletion.item))
|
|
162
|
+
if (relationships) _addToMap(relationships?.map(({into: [existence]}) => existence).filter(e => e))
|
|
167
163
|
}
|
|
168
164
|
|
|
169
165
|
function _traverseYAMLNode(node, index, actions, templateNode) {
|
|
170
166
|
let shifted = false
|
|
171
167
|
if (YAML.isMap(node)) {
|
|
172
|
-
actions
|
|
168
|
+
actions?.visitMap && actions.visitMap(node, index)
|
|
173
169
|
const [collection] = collectionStack
|
|
174
170
|
if (YAML.isSeq(collection)) {
|
|
175
171
|
collectionStack.unshift(node)
|
|
176
172
|
shifted = true
|
|
177
173
|
}
|
|
178
|
-
} else if (YAML.isPair(node) && node.value
|
|
174
|
+
} else if (YAML.isPair(node) && node.value?.items) {
|
|
179
175
|
collectionStack.unshift(node.value)
|
|
180
176
|
} else if (YAML.isScalar(node) && semantics.forceOverwrite && templateNode) {
|
|
181
|
-
node.value = templateNode.value
|
|
177
|
+
node.value = templateNode.value ?? templateNode.items?.[0]?.value?.value
|
|
182
178
|
}
|
|
183
179
|
|
|
184
180
|
if (node.items) {
|
|
185
|
-
if (YAML.isSeq(node) && templateNode
|
|
186
|
-
actions
|
|
181
|
+
if (YAML.isSeq(node) && templateNode?.items) {
|
|
182
|
+
actions?.mergeCollection && actions.mergeCollection(node, templateNode)
|
|
187
183
|
_traverseYAMLCollection(node, actions, templateNode)
|
|
188
184
|
} else {
|
|
189
185
|
_traverseYAMLCollection(node, actions, templateNode)
|
|
190
186
|
}
|
|
191
|
-
} else if (node.value
|
|
187
|
+
} else if (node.value?.items || node.value && semantics.forceOverwrite) {
|
|
192
188
|
_traverseYAMLNode(node.value, index, actions, templateNode && templateNode.value)
|
|
193
189
|
}
|
|
194
190
|
|
|
195
|
-
if (node.value
|
|
191
|
+
if (node.value?.items || shifted) {
|
|
196
192
|
collectionStack.shift()
|
|
197
193
|
}
|
|
198
194
|
}
|
|
199
195
|
_traverseYAMLNode.bind(this)
|
|
200
196
|
|
|
201
|
-
|
|
197
|
+
function _traverseYAMLCollection (collection, actions, templateCollection) {
|
|
202
198
|
if (!collection) return
|
|
203
199
|
|
|
204
|
-
const
|
|
205
|
-
const templateIndexMap = new Map()
|
|
200
|
+
const keyToIndex = new Map, templateIndexToIndex = new Map
|
|
206
201
|
|
|
207
202
|
// Map collection items to their semantic counterpart(s)
|
|
208
203
|
collection.items.forEach((node, i) => {
|
|
209
|
-
if (node.key)
|
|
210
|
-
const existence = [...existenceMap.entries()].find(([,value]) => value
|
|
204
|
+
if (node.key) keyToIndex.set(node.key.value, i)
|
|
205
|
+
const existence = [...existenceMap.entries()].find(([,value]) => value?.node === node)
|
|
211
206
|
if (existence) {
|
|
212
207
|
const [existenceKey] = existence
|
|
213
208
|
const templateExistence = existenceKey && templateExistenceMap.get(existenceKey)
|
|
214
|
-
const templateIndex = templateExistence
|
|
215
|
-
if (templateIndex !== undefined)
|
|
209
|
+
const templateIndex = templateExistence?.index
|
|
210
|
+
if (templateIndex !== undefined) templateIndexToIndex.set(templateIndex, i)
|
|
216
211
|
}
|
|
217
212
|
if (!templateCollection) _traverseYAMLNode(node, i, actions)
|
|
218
213
|
})
|
|
@@ -220,8 +215,12 @@ module.exports = class TemplateUtil {
|
|
|
220
215
|
if (!templateCollection) return
|
|
221
216
|
|
|
222
217
|
templateCollection.items.forEach((templateNode, templateIndex) => {
|
|
223
|
-
if (YAML.
|
|
224
|
-
|
|
218
|
+
if (YAML.isScalar(templateNode)) {
|
|
219
|
+
if (!collection.items.map(item => item.value).includes(templateNode.value)) {
|
|
220
|
+
collection.add(templateNode)
|
|
221
|
+
}
|
|
222
|
+
} else if (YAML.isPair(templateNode)) {
|
|
223
|
+
const i = keyToIndex.get(templateNode.key.value)
|
|
225
224
|
const [collection] = collectionStack
|
|
226
225
|
const targetNode = collection.items && collection.items[i]
|
|
227
226
|
if (targetNode) {
|
|
@@ -230,10 +229,10 @@ module.exports = class TemplateUtil {
|
|
|
230
229
|
actions.mergePair(collection, templateNode)
|
|
231
230
|
}
|
|
232
231
|
} else if (YAML.isMap(templateNode)) {
|
|
233
|
-
const targetNode = collection.items[
|
|
232
|
+
const targetNode = collection.items[templateIndexToIndex.get(templateIndex)]
|
|
234
233
|
if (actions.mergeCollection) actions.mergeCollection(targetNode, templateNode)
|
|
235
234
|
if (targetNode) {
|
|
236
|
-
_traverseYAMLNode(targetNode, templateIndex, actions, templateNode)
|
|
235
|
+
_traverseYAMLNode(targetNode, templateIndex, actions, templateNode)
|
|
237
236
|
}
|
|
238
237
|
}
|
|
239
238
|
})
|
|
@@ -243,42 +242,43 @@ module.exports = class TemplateUtil {
|
|
|
243
242
|
// 1. Validate the existences in the template
|
|
244
243
|
_traverseYAMLNode(source.contents, null, {
|
|
245
244
|
visitMap: (node, index) => {
|
|
246
|
-
|
|
245
|
+
_validateWhere(node, templateExistenceMap, index)
|
|
247
246
|
}
|
|
248
247
|
})
|
|
249
248
|
|
|
250
249
|
// 2. Validate the existences in the project
|
|
251
250
|
_traverseYAMLNode(target.contents, null, {
|
|
252
251
|
visitMap: (node, index) => {
|
|
253
|
-
|
|
252
|
+
_validateWhere(node, existenceMap, index)
|
|
254
253
|
}
|
|
255
254
|
})
|
|
256
255
|
|
|
257
256
|
// 3. Apply overwrites to already found existences
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
257
|
+
overwrites?.forEach(({ item, withValue }) => {
|
|
258
|
+
const keyPath = Array.isArray(item) && typeof item[0] === 'string' ? item[0] : typeof item === 'string' ? item : item[1]
|
|
259
|
+
const inExistence = Array.isArray(item) && typeof item[0] === 'object' ? item[0] : typeof item === 'object' ? item : item[1]
|
|
260
|
+
const node = inExistence && existenceMap.get(inExistence.ref) ? existenceMap.get(inExistence.ref).node : collectionStack[collectionStack.length - 1]
|
|
261
|
+
const keys = keyPath.split('.')
|
|
262
|
+
if (!node.getIn(keys)) return
|
|
263
|
+
_getYAMLProperty(node, keys.slice(0, keys.length - 1).join('.'))
|
|
264
|
+
.set(keys[keys.length - 1], withValue)
|
|
264
265
|
})
|
|
265
266
|
|
|
266
267
|
// 4. Delete existences from the project (e.g. separate deployer module when adding mtx)
|
|
267
|
-
|
|
268
|
+
deletions?.forEach(({ item: { ref }, relationships }) => {
|
|
268
269
|
const existence = existenceMap.get(ref)
|
|
269
270
|
if (!existence) return
|
|
270
271
|
existence.collection.delete(existence.index)
|
|
271
272
|
|
|
272
|
-
relationships
|
|
273
|
-
const
|
|
273
|
+
relationships?.forEach(relationship => {
|
|
274
|
+
const [allWithinKeyPath, inKeyPath, into] = relationship.allWithin
|
|
275
|
+
const parent = _getYAMLProperty(target, allWithinKeyPath)
|
|
274
276
|
for (const child of parent.items) {
|
|
275
|
-
const
|
|
276
|
-
const i =
|
|
277
|
-
node.get(
|
|
278
|
-
)
|
|
279
|
-
if (i > -1)
|
|
280
|
-
c.delete(i)
|
|
281
|
-
}
|
|
277
|
+
const grandchild = _getYAMLProperty(child, inKeyPath)
|
|
278
|
+
const i = grandchild?.items?.findIndex(node =>
|
|
279
|
+
node.get(into) === _getProperty(existence.json, relationship.removeProperty)
|
|
280
|
+
) ?? - 1
|
|
281
|
+
if (i > -1) grandchild.delete(i)
|
|
282
282
|
}
|
|
283
283
|
})
|
|
284
284
|
})
|
|
@@ -286,33 +286,32 @@ module.exports = class TemplateUtil {
|
|
|
286
286
|
// 5. Create missing existences and pairs
|
|
287
287
|
_traverseYAMLNode(target.contents, null, {
|
|
288
288
|
mergePair: (collection, templateNode) => {
|
|
289
|
-
|
|
290
|
-
if (YAML.isMap(collection) && !childIsArray) {
|
|
289
|
+
if (YAML.isMap(collection)) {
|
|
291
290
|
collection.add(templateNode)
|
|
292
291
|
}
|
|
293
292
|
},
|
|
294
293
|
mergeCollection: (targetNode, templateNode) => {
|
|
295
294
|
if (YAML.isSeq(templateNode)) {
|
|
296
295
|
let [,parent] = collectionStack
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
existenceMap.get(existence.in.ref) &&
|
|
302
|
-
existenceMap.get(existence.in.ref).node
|
|
303
|
-
return !existence.in || requiredParent === parent
|
|
304
|
-
|
|
296
|
+
additions?.filter(addition => {
|
|
297
|
+
if (typeof addition.in === 'string' || Array.isArray(addition.in) && typeof addition.in[0] === 'string') return true
|
|
298
|
+
const inExistence = Array.isArray(addition.in) ? existenceMap.get(addition.in[0].ref) : existenceMap.get(addition.in.ref)
|
|
299
|
+
return inExistence?.node === parent
|
|
305
300
|
})
|
|
306
|
-
.filter(
|
|
307
|
-
|
|
308
|
-
|
|
301
|
+
.filter(addition => {
|
|
302
|
+
const keyPath = typeof addition.in === 'string' ? addition.in : Array.isArray(addition.in) && typeof addition.in[0] === 'string' ? addition.in[0] : addition.in[1]
|
|
303
|
+
const keys = keyPath.split('.')
|
|
304
|
+
if (keys.length > collectionStack.length + 1) return
|
|
305
|
+
if (keys.length > 1) parent = collectionStack[keys.length]
|
|
309
306
|
return _getYAMLProperty(parent, keyPath) === targetNode
|
|
310
307
|
})
|
|
311
|
-
.filter(({ref}) =>
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
308
|
+
.filter(({ ref }) => {
|
|
309
|
+
return !existenceMap.get(ref)
|
|
310
|
+
})
|
|
311
|
+
.forEach(({ ref, at }) => {
|
|
312
|
+
const templateNode = templateExistenceMap.get(ref).node
|
|
313
|
+
at !== undefined ? targetNode.items.splice(at, 0, templateNode) : targetNode.add(templateNode)
|
|
314
|
+
})
|
|
316
315
|
}
|
|
317
316
|
},
|
|
318
317
|
}, source.contents)
|
|
@@ -320,7 +319,7 @@ module.exports = class TemplateUtil {
|
|
|
320
319
|
// 6. Re-validate the existences in the project
|
|
321
320
|
_traverseYAMLNode(target.contents, null, {
|
|
322
321
|
visitMap: (node, index) => {
|
|
323
|
-
|
|
322
|
+
_validateWhere(node, existenceMap, index)
|
|
324
323
|
}
|
|
325
324
|
})
|
|
326
325
|
|
|
@@ -329,23 +328,26 @@ module.exports = class TemplateUtil {
|
|
|
329
328
|
mergeCollection: (targetNode, templateNode) => {
|
|
330
329
|
if (YAML.isSeq(templateNode)) {
|
|
331
330
|
const targetJSON = YAML.parse(String(targetNode))
|
|
332
|
-
const relationship = semantics.relationships
|
|
333
|
-
.filter(r => r)
|
|
331
|
+
const relationship = semantics.relationships?.filter(r => r)
|
|
334
332
|
.find(relationship => {
|
|
335
|
-
const
|
|
333
|
+
const [existence, keyPath] = relationship.into
|
|
334
|
+
if (!existenceMap.get(existence.ref)) return false
|
|
335
|
+
const existingNode = _getYAMLProperty(existenceMap.get(existence.ref).node, keyPath)
|
|
336
336
|
return targetNode === existingNode
|
|
337
337
|
})
|
|
338
338
|
if (!relationship) return
|
|
339
339
|
|
|
340
|
-
const
|
|
340
|
+
const intoKey = relationship.into[relationship.into.length - 1]
|
|
341
|
+
const [existence, existenceKeyPath] = relationship.insert
|
|
342
|
+
const missingPairs = [existence]
|
|
341
343
|
.filter(({ref}) =>
|
|
342
344
|
!targetJSON.some(item =>
|
|
343
|
-
_getProperty(existenceMap.get(ref).json,
|
|
345
|
+
_getProperty(existenceMap.get(ref).json, existenceKeyPath) === item[intoKey]
|
|
344
346
|
)
|
|
345
347
|
)
|
|
346
|
-
.map(({ref}) => existenceMap.get(ref).node.get(
|
|
348
|
+
.map(({ref}) => existenceMap.get(ref).node.get(intoKey))
|
|
347
349
|
missingPairs.forEach(pair => {
|
|
348
|
-
targetNode.add({ [
|
|
350
|
+
targetNode.add({ [intoKey]: pair })
|
|
349
351
|
})
|
|
350
352
|
}
|
|
351
353
|
}
|
package/lib/k8s/ChartAdder.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
const { yaml } = require('./modules');
|
|
4
|
+
const path = require('path');
|
|
4
5
|
const fs = require('fs').promises;
|
|
5
6
|
const FsUtil = require('../../lib/init/util/fsUtil')
|
|
6
7
|
const TemplateUtil = require('../../lib/init/util/templateUtil')
|
|
@@ -10,9 +11,9 @@ class ChartAdder {
|
|
|
10
11
|
*
|
|
11
12
|
* @param {{ builder: import('./ChartBuilder') }} param0
|
|
12
13
|
*/
|
|
13
|
-
constructor({ builder,
|
|
14
|
+
constructor({ builder, resources, chartValues, chartDependencies, app, mergeSemantics }) {
|
|
14
15
|
this.builder = builder;
|
|
15
|
-
this.
|
|
16
|
+
this.resources = resources;
|
|
16
17
|
this.chartValues = chartValues;
|
|
17
18
|
this.app = app;
|
|
18
19
|
this.mergeSemantics = mergeSemantics;
|
|
@@ -22,12 +23,21 @@ class ChartAdder {
|
|
|
22
23
|
|
|
23
24
|
async execute() {
|
|
24
25
|
await this.copyTemplates();
|
|
26
|
+
await this.copySchema();
|
|
25
27
|
await this.addChartValues();
|
|
26
28
|
await this.addChartFile();
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
async copyTemplates() {
|
|
30
|
-
await this.builder.addAllTemplates(this.
|
|
32
|
+
await this.builder.addAllTemplates(this.resources);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async copySchema() {
|
|
36
|
+
let valuesSchema = JSON.parse(await fs.readFile(path.join(this.resources, 'schemas', 'values.schema.json'), { encoding: 'utf8' }))
|
|
37
|
+
let valuesRootSchema = JSON.parse(await fs.readFile(path.join(this.resources, 'schemas', 'values.root.schema.json'), { encoding: 'utf8' }))
|
|
38
|
+
|
|
39
|
+
await this.builder.writeChartFile('values.schema.json', JSON.stringify(valuesSchema, null, 4));
|
|
40
|
+
await this.builder.writeChartFile('values.root.schema.json', JSON.stringify(valuesRootSchema, null, 4));
|
|
31
41
|
}
|
|
32
42
|
|
|
33
43
|
async addChartValues() {
|
package/lib/k8s/ChartBuilder.js
CHANGED
|
@@ -51,6 +51,12 @@ class ChartBuilder {
|
|
|
51
51
|
|
|
52
52
|
await this.templateUtil.mergeYAML(filePath, newYamlContent, null, mergeSemantics);
|
|
53
53
|
} else {
|
|
54
|
+
|
|
55
|
+
const header = `
|
|
56
|
+
# yaml-language-server: $schema=./values.root.schema.json
|
|
57
|
+
|
|
58
|
+
`
|
|
59
|
+
data = header + data;
|
|
54
60
|
await this.writeChartFile(fileName, data);
|
|
55
61
|
}
|
|
56
62
|
|