@sap/cds-dk 9.7.2 → 9.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -2
- package/bin/bind.js +7 -2
- package/bin/build.js +14 -4
- package/bin/cds.js +2 -2
- package/bin/completion/completionFs.js +1 -1
- package/bin/completion/index.js +2 -2
- package/bin/data-products/get-csn-via-dp-cli.js +1 -1
- package/bin/debug.js +1 -1
- package/bin/deploy/index.js +3 -2
- package/bin/gen.js +1 -1
- package/bin/help.js +1 -1
- package/bin/import.js +3 -0
- package/bin/minify.js +1 -1
- package/bin/mock.js +1 -1
- package/bin/repl.js +212 -39
- package/bin/test.js +0 -2
- package/bin/up.js +27 -3
- package/bin/util/containerize.js +1 -3
- package/bin/version.js +30 -9
- package/bin/watch.js +20 -4
- package/lib/bind/cf.js +2 -2
- package/lib/bind/k8s.js +0 -1
- package/lib/bind/plugin.js +2 -0
- package/lib/bind/shared.js +6 -1
- package/lib/build/constants.js +0 -8
- package/lib/build/index.js +569 -25
- package/lib/build/{provider/edmxBuildPlugin.js → plugins/edmx.js} +6 -15
- package/lib/build/{provider/featureToggleBuildPlugin.js → plugins/featureToggles.js} +8 -27
- package/lib/build/{provider → plugins}/fiori/index.js +27 -40
- package/lib/build/{provider → plugins}/hana/index.js +67 -85
- package/lib/build/{provider → plugins}/hana/migrationtable.js +4 -3
- package/lib/build/plugins/helm/index.js +6 -6
- package/lib/build/{provider/internalBuildPlugin.js → plugins/internal.js} +7 -31
- package/lib/build/{provider → plugins}/java/index.js +18 -26
- package/lib/build/plugins/mtx/index.js +41 -0
- package/lib/build/plugins/mtx/resourcesTarBuilder.js +41 -0
- package/lib/build/{provider → plugins}/mtx-extension/extensionCompilation.js +1 -1
- package/lib/build/{provider → plugins}/mtx-extension/index.js +35 -44
- package/lib/build/{provider → plugins}/mtx-sidecar/index.js +17 -3
- package/lib/build/{provider → plugins}/nodejs/index.js +29 -28
- package/lib/build/{plugin.js → plugins/plugin.js} +57 -60
- package/lib/build/plugins.js +11 -8
- package/lib/build/util.js +0 -8
- package/lib/compile/to-xsuaa.js +2 -2
- package/lib/deploy/to-hana/hana.js +64 -56
- package/lib/import/common.js +1 -1
- package/lib/import/odata/metadataconverter/MetadataConverter.js +4 -3
- package/lib/import/odata/v2parser.js +28 -28
- package/lib/import/odata/v4parser.js +37 -2
- package/lib/import/openapi/index.js +1 -1
- package/lib/init/constants.js +1 -2
- package/lib/init/template/app-frontend/index.js +1 -1
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/completion/completionSetup.js +1 -1
- package/lib/init/template/data/as-csv.js +1 -1
- package/lib/init/template/github-actions/index.js +1 -1
- package/lib/init/template/handler/index.js +1 -1
- package/lib/init/template/helm/index.js +4 -4
- package/lib/init/template/kyma/index.js +3 -3
- package/lib/init/template/lint/index.js +7 -21
- package/lib/init/template/multitenancy/files/package.json.hbs +0 -5
- package/lib/init/template/postgres/files/containerize.yaml.hbs +15 -0
- package/lib/init/template/postgres/files/package.json.hbs +35 -0
- package/lib/init/template/postgres/files/values.yaml.hbs +23 -0
- package/lib/init/template/postgres/index.js +34 -9
- package/lib/init/template/test/files/package.json +1 -1
- package/lib/init/template/typescript/files/package.json +1 -1
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +1 -0
- package/lib/lint/eslintHelp.json +1 -1
- package/lib/lint/io.js +9 -13
- package/lib/mtx/pull.js +1 -1
- package/lib/mtx/settings_manager.js +11 -5
- package/lib/mtx/tenant_action.js +1 -1
- package/lib/mtx/util/fs.js +2 -2
- package/lib/util/fs.js +3 -3
- package/lib/util/git.js +1 -1
- package/lib/util/glob.js +1 -1
- package/lib/watch/hot-reload.js +202 -0
- package/lib/watch/livereload-server.js +6 -4
- package/lib/watch/node-watch.js +5 -1
- package/lib/watch/watched.js +7 -3
- package/lib/watch/watcher.js +41 -3
- package/npm-shrinkwrap.json +46 -31
- package/package.json +1 -1
- package/lib/build/buildTaskEngine.js +0 -377
- package/lib/build/buildTaskFactory.js +0 -198
- package/lib/build/buildTaskProvider.js +0 -38
- package/lib/build/buildTaskProviderFactory.js +0 -233
- package/lib/build/provider/internalBuildTaskProvider.js +0 -227
- package/lib/build/provider/java-cf/index.js +0 -1
- package/lib/build/provider/mtx/index.js +0 -36
- package/lib/build/provider/mtx/resourcesTarBuilder.js +0 -102
- package/lib/build/provider/node-cf/index.js +0 -1
- package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +0 -40
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/fixed/schema.cds +0 -4
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/invalid/schema.cds +0 -4
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +0 -15
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/valid/schema.cds +0 -6
- package/lib/init/types.d.ts +0 -23
- /package/lib/build/{provider → plugins}/hana/2migration.js +0 -0
- /package/lib/build/{provider → plugins}/hana/template/.hdiconfig-all +0 -0
- /package/lib/build/{provider → plugins}/hana/template/.hdiconfig-cloud +0 -0
- /package/lib/build/{provider → plugins}/hana/template/.hdinamespace +0 -0
- /package/lib/build/{provider → plugins}/hana/template/package.json +0 -0
- /package/lib/build/{provider → plugins}/hana/template/undeploy.json +0 -0
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
2
|
const cds = require('../../cds')
|
|
3
|
-
const { DEFAULT_CSN_FILE_NAME
|
|
4
|
-
const InternalBuildPlugin = require('./internalBuildPlugin')
|
|
3
|
+
const { DEFAULT_CSN_FILE_NAME } = require('../constants')
|
|
5
4
|
const { getI18nDefaultFolder, filterFeaturePaths } = require('../util')
|
|
6
5
|
|
|
7
|
-
class
|
|
8
|
-
init() {
|
|
9
|
-
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
10
|
-
this._result = {
|
|
11
|
-
dest: this.task.dest,
|
|
12
|
-
edmx: new Map(),
|
|
13
|
-
languages: new Set(),
|
|
14
|
-
services: new Set()
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
6
|
+
module.exports = class FeatureTogglesBuildPlugin extends require('./internal') {
|
|
18
7
|
|
|
19
8
|
async compileAll(csn, destBase, destFts) {
|
|
20
9
|
const sources = filterFeaturePaths(csn, this.task.options.model || this.task.src)
|
|
@@ -31,10 +20,6 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
|
|
|
31
20
|
const csnStr = await this.compileToJson(dictionary.base, path.join(destBase, DEFAULT_CSN_FILE_NAME))
|
|
32
21
|
const csnModel = JSON.parse(csnStr)
|
|
33
22
|
csnModel.meta = csn.meta
|
|
34
|
-
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
35
|
-
this._result.csn = csnModel
|
|
36
|
-
}
|
|
37
|
-
|
|
38
23
|
if (sources.features) {
|
|
39
24
|
dictionary.features = await this._compileFeatures(sources.features, destBase, destFts, dictionary.base)
|
|
40
25
|
}
|
|
@@ -45,18 +30,16 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
|
|
|
45
30
|
const i18nFolder = getI18nDefaultFolder()
|
|
46
31
|
const ftsName = path.dirname(cds.env.features.folders || 'fts/*')
|
|
47
32
|
// create language bundle for base model
|
|
48
|
-
|
|
49
|
-
if (i18n && this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
50
|
-
this._result.languageBundles = i18n.bundles
|
|
51
|
-
}
|
|
33
|
+
await this.collectLanguageBundles(dictionary.base, path.join(destBase, i18nFolder))
|
|
52
34
|
|
|
53
35
|
if (dictionary.features) {
|
|
54
36
|
// create language bundles for all features
|
|
55
|
-
|
|
37
|
+
const featureBundleTasks = Object.keys(dictionary.features).map(async ftName => {
|
|
56
38
|
// attach the sources information for i18n location reference
|
|
57
39
|
dictionary.features[ftName]['$sources'] = paths.features[ftName]
|
|
58
40
|
await this.collectLanguageBundles(dictionary.features[ftName], path.join(destFts, ftsName, ftName, i18nFolder))
|
|
59
|
-
}
|
|
41
|
+
})
|
|
42
|
+
await Promise.all(featureBundleTasks)
|
|
60
43
|
}
|
|
61
44
|
}
|
|
62
45
|
|
|
@@ -69,7 +52,7 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
|
|
|
69
52
|
const ftsName = path.dirname(cds.env.features.folders || 'fts/*')
|
|
70
53
|
|
|
71
54
|
// create feature models
|
|
72
|
-
|
|
55
|
+
await Promise.all(Object.keys(ftsPaths).map(async ftName => {
|
|
73
56
|
const ftCsn = await cds.load(ftsPaths[ftName], options)
|
|
74
57
|
const ftPath = path.join(destFts, ftsName, ftName)
|
|
75
58
|
|
|
@@ -80,7 +63,7 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
|
|
|
80
63
|
await this.compileToJson(ftCsn, path.join(ftPath, DEFAULT_CSN_FILE_NAME))
|
|
81
64
|
this._validateFeature(ftCsn, baseCsn)
|
|
82
65
|
features[ftName] = ftCsn
|
|
83
|
-
}
|
|
66
|
+
}))
|
|
84
67
|
return features
|
|
85
68
|
}
|
|
86
69
|
|
|
@@ -90,5 +73,3 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
|
|
|
90
73
|
cds.compiler.compileSources({ [ftCsn.requires[0]]: baseCsn, 'feature.csn': ftCsn }, { ...super.options(), ...cds.env.cdsc ?? {} })
|
|
91
74
|
}
|
|
92
75
|
}
|
|
93
|
-
|
|
94
|
-
module.exports = FeatureToggleBuildPlugin
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
const path = require('path')
|
|
1
|
+
const path = require('node:path')
|
|
2
2
|
const cds = require('../../../cds')
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const { OUTPUT_MODE, OUTPUT_MODE_RESULT, BUILD_TASK_FIORI, CDS_CONFIG_PATH_SEP, OUTPUT_MODE_FILESYSTEM } = require('../../constants')
|
|
3
|
+
const { relativePaths, normalizePath } = require('../../util')
|
|
4
|
+
const { BUILD_TASK_FIORI, CDS_CONFIG_PATH_SEP } = require('../../constants')
|
|
6
5
|
const DEBUG = cds.debug('cli|build')
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -10,25 +9,25 @@ const DEBUG = cds.debug('cli|build')
|
|
|
10
9
|
* For SAP Web IDE Full-Stack compatibility a corresponding metadata.xml is still generated.
|
|
11
10
|
* Though, 'fiori' build tasks can still be configured for UI5 mock server usage - see cap/issues#8673
|
|
12
11
|
*/
|
|
13
|
-
class FioriBuildPlugin extends
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
edmx: new Map(),
|
|
19
|
-
languages: new Set(),
|
|
20
|
-
services: new Set()
|
|
21
|
-
}
|
|
22
|
-
}
|
|
12
|
+
module.exports = class FioriBuildPlugin extends require('../edmx') {
|
|
13
|
+
|
|
14
|
+
_cachedEdmx = new Map()
|
|
15
|
+
|
|
16
|
+
static get taskDefaults() { return { src: normalizePath(cds.env.folders.app) } }
|
|
23
17
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
static hasTask() { return false } // never auto-pulled, only if configured in build tasks
|
|
19
|
+
|
|
20
|
+
async _ensureCachesInitialized() {
|
|
21
|
+
this.context.for ??= {}
|
|
22
|
+
this.context.for[BUILD_TASK_FIORI] ??= {}
|
|
27
23
|
|
|
28
24
|
// cache for later use across multiple FioriBuildPlugin instances
|
|
29
25
|
const fioriBuildOptions = this.context.for[BUILD_TASK_FIORI]
|
|
30
|
-
fioriBuildOptions.
|
|
31
|
-
|
|
26
|
+
if (fioriBuildOptions._initialized) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
fioriBuildOptions.appModel ??= new Map()
|
|
30
|
+
fioriBuildOptions.appEdmx ??= new Map()
|
|
32
31
|
|
|
33
32
|
// group tasks that have a common application root folder
|
|
34
33
|
const appTaskGroups = new Map()
|
|
@@ -51,10 +50,6 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
|
|
|
51
50
|
appModelGroups.set(appFolder, appModels)
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
// ensure edmx is cached as build result
|
|
55
|
-
const buildOption = this.context.options[OUTPUT_MODE]
|
|
56
|
-
this.context.options[OUTPUT_MODE] |= OUTPUT_MODE_RESULT
|
|
57
|
-
|
|
58
53
|
try {
|
|
59
54
|
for (let [appFolder, appModelGroup] of appModelGroups.entries()) {
|
|
60
55
|
DEBUG?.(`building module [${appFolder}] using [${this.constructor.name}]`)
|
|
@@ -64,20 +59,19 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
|
|
|
64
59
|
}
|
|
65
60
|
DEBUG?.(`model: ${relativePaths(cds.root, modelPaths).join(", ")}`)
|
|
66
61
|
|
|
67
|
-
//cache model per fiori app root folder
|
|
62
|
+
// cache model per fiori app root folder
|
|
68
63
|
const options = this.options()
|
|
69
64
|
const model = await cds.load(modelPaths, options)
|
|
70
65
|
fioriBuildOptions.appModel.set(appFolder, model)
|
|
71
66
|
|
|
72
|
-
await this.compileToEdmx(model)
|
|
73
|
-
|
|
74
67
|
// cache edmx per fiori app root folder
|
|
75
|
-
|
|
68
|
+
this._cachedEdmx = new Map()
|
|
69
|
+
await this.compileToEdmx(model)
|
|
70
|
+
fioriBuildOptions.appEdmx.set(appFolder, this._cachedEdmx)
|
|
76
71
|
}
|
|
77
72
|
} finally {
|
|
78
|
-
|
|
73
|
+
fioriBuildOptions._initialized = true
|
|
79
74
|
}
|
|
80
|
-
return false
|
|
81
75
|
}
|
|
82
76
|
|
|
83
77
|
/**
|
|
@@ -87,10 +81,7 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
|
|
|
87
81
|
* cannot be resolved based on the defined service URI
|
|
88
82
|
*/
|
|
89
83
|
async build() {
|
|
90
|
-
|
|
91
|
-
if (!model) {
|
|
92
|
-
return
|
|
93
|
-
}
|
|
84
|
+
await this._ensureCachesInitialized()
|
|
94
85
|
await this._writeEdmxToWebapp(this.task.src, this.task.dest)
|
|
95
86
|
}
|
|
96
87
|
|
|
@@ -100,7 +91,7 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
|
|
|
100
91
|
|
|
101
92
|
try {
|
|
102
93
|
manifest = require(manifestPath)
|
|
103
|
-
} catch
|
|
94
|
+
} catch {
|
|
104
95
|
console.log(`UI module does not contain a manifest.json [${relativePaths(cds.root, manifestPath)}], skipping build`)
|
|
105
96
|
return
|
|
106
97
|
}
|
|
@@ -133,10 +124,8 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
|
|
|
133
124
|
return
|
|
134
125
|
}
|
|
135
126
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return this.write(edmx).to(edmxPath)
|
|
139
|
-
}
|
|
127
|
+
const edmxPath = path.resolve(path.join(dest, 'webapp'), this._strippedUrlPath(localUri))
|
|
128
|
+
return this.write(edmx).to(edmxPath)
|
|
140
129
|
}
|
|
141
130
|
|
|
142
131
|
_getEdmxForUri(model, appFolder, uri) {
|
|
@@ -161,5 +150,3 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
|
|
|
161
150
|
return urlString.replace(/^(\/|\\)/, '').replace(/(\/|\\)$/, '') // strip leading and trailing slash or backslash
|
|
162
151
|
}
|
|
163
152
|
}
|
|
164
|
-
|
|
165
|
-
module.exports = FioriBuildPlugin
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
2
|
const cds = require('../../../cds')
|
|
3
|
+
const { exists, isdir, path } = cds.utils
|
|
4
4
|
const { compileToHdbMigration, getJournalEntities, getMigrationTableName } = require('./2migration')
|
|
5
|
-
const InternalBuildPlugin = require('../internalBuildPlugin')
|
|
6
5
|
const { find } = require('../../../util/fs')
|
|
7
|
-
const { BuildError, relativePaths, BuildMessage, hasOptionValue, getWorkspacePaths } = require('../../util')
|
|
8
|
-
const {
|
|
9
|
-
CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, CONTENT_NODE_MODULES, OUTPUT_MODE_RESULT, CONTINUE_UNRESOLVED_SCHEMA_CHANGES,
|
|
10
|
-
CSV_FILE_TARGET, OPTION_WS } = require('../../constants')
|
|
11
|
-
const { WARNING } = InternalBuildPlugin
|
|
6
|
+
const { BuildError, relativePaths, BuildMessage, hasOptionValue, getWorkspacePaths, normalizePath } = require('../../util')
|
|
7
|
+
const { CONTENT_PACKAGE_JSON, CONTENT_HDBTABLEDATA, CSV_FILE_DETECTION, CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, CONTENT_NODE_MODULES, CONTINUE_UNRESOLVED_SCHEMA_CHANGES, CSV_FILE_TARGET, OPTION_WS, SEVERITY_WARNING } = require('../../constants')
|
|
12
8
|
const DEFAULT_COMPILE_DEST_FOLDER = path.normalize("src/gen")
|
|
13
9
|
const FILE_EXT_CSV = ".csv"
|
|
14
10
|
const FILE_EXT_HDBTABLEDATA = ".hdbtabledata"
|
|
@@ -26,14 +22,19 @@ const DEBUG = cds.debug('cli|build')
|
|
|
26
22
|
// This list contains exceptions which will be ignored during the consistency check.
|
|
27
23
|
const PLUGINLESS_HDB_FILES = new Set([".hdbgrants", ".hdbrevokes"])
|
|
28
24
|
|
|
29
|
-
class HanaBuildPlugin extends
|
|
25
|
+
module.exports = class HanaBuildPlugin extends require('../internal') {
|
|
26
|
+
|
|
27
|
+
static get taskDefaults() { return { src: normalizePath(cds.env.folders.db) } }
|
|
28
|
+
|
|
29
|
+
static hasTask() {
|
|
30
|
+
if (cds.env.extends) return false
|
|
31
|
+
const src = path.join(cds.root, this.taskDefaults?.src ?? 'db')
|
|
32
|
+
if (!exists(src)) return false
|
|
33
|
+
const db = cds.env.requires.db
|
|
34
|
+
return db?.kind === 'hana' || db?.dialect === 'hana'
|
|
35
|
+
}
|
|
36
|
+
|
|
30
37
|
init() {
|
|
31
|
-
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
32
|
-
this._result = {
|
|
33
|
-
dest: this.task.dest,
|
|
34
|
-
hana: new Set()
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
38
|
this.task.options.compileDest = path.resolve(this.task.dest, this.task.options.compileDest || DEFAULT_COMPILE_DEST_FOLDER)
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -57,7 +58,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
57
58
|
// 1. compile
|
|
58
59
|
const hdiPlugins = await this._compileToHana(model, wsPaths)
|
|
59
60
|
|
|
60
|
-
if (!
|
|
61
|
+
if (!cds.cli.options.dry) {
|
|
61
62
|
// 2. copy resources
|
|
62
63
|
if (this.hasBuildOption(CSV_FILE_DETECTION, false)) {
|
|
63
64
|
await this._copyResources(src, dest)
|
|
@@ -83,13 +84,12 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
83
84
|
// common model artifacts that are not part of the current project
|
|
84
85
|
if (wsPaths.length || cds.cli.options?.[OPTION_WS] || hasOptionValue(this.task.options[OPTION_WS], true)) {
|
|
85
86
|
// first is winning, e.g. a .hdiconfig file might exist in multiple workspaces
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}, []);
|
|
87
|
+
const seen = new Set()
|
|
88
|
+
const wsFiles = (await this._getWorkspaceFiles(wsPaths)).filter(src => {
|
|
89
|
+
if (seen.has(src.filePath)) return false
|
|
90
|
+
seen.add(src.filePath)
|
|
91
|
+
return true
|
|
92
|
+
});
|
|
93
93
|
|
|
94
94
|
// copy artifacts to the src/gen folder in inplace mode
|
|
95
95
|
const dest = path.join(this.task.dest, this.isStagingBuild() ? 'src' : 'src/gen')
|
|
@@ -101,13 +101,12 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
101
101
|
)
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
-
return this._result
|
|
105
104
|
}
|
|
106
105
|
|
|
107
106
|
/**
|
|
108
107
|
* Deletes any content that has been created in folder '#this.task.dest/src/gen' by inplace mode.
|
|
109
108
|
* <br>
|
|
110
|
-
* Note: Content created in staging build will be deleted by
|
|
109
|
+
* Note: Content created in staging build will be deleted by default.
|
|
111
110
|
*/
|
|
112
111
|
async clean() {
|
|
113
112
|
if (this.isStagingBuild()) {
|
|
@@ -142,13 +141,17 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
142
141
|
csvFolder = !dbCSVs.length || dbCSVs.some(res => res && res.startsWith(csvPath)) ? "data" : "csv"
|
|
143
142
|
}
|
|
144
143
|
|
|
145
|
-
//
|
|
144
|
+
// preserve last-write-wins semantics for duplicate basenames while parallelizing distinct file copies
|
|
145
|
+
const csvResourcesByName = new Map()
|
|
146
146
|
for (const res of resources) {
|
|
147
147
|
// do not duplicate resources that are already contained in db/src/**
|
|
148
148
|
if (res && /\.csv$/.test(res) && !res.startsWith(dbSrc)) {
|
|
149
|
-
|
|
149
|
+
csvResourcesByName.set(path.basename(res), res)
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
+
await Promise.all(Array.from(csvResourcesByName.entries()).map(([fileName, res]) => {
|
|
153
|
+
return this.copy(res).to(path.join(this.task.options.compileDest, csvFolder, fileName))
|
|
154
|
+
}))
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
if (this.isStagingBuild()) {
|
|
@@ -162,7 +165,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
162
165
|
if (entry.startsWith(dbSrc)) {
|
|
163
166
|
return true
|
|
164
167
|
}
|
|
165
|
-
if (
|
|
168
|
+
if (isdir(entry)) {
|
|
166
169
|
return !/(\/|\\)node_modules(\/|\\)?$/.test(entry) ||
|
|
167
170
|
(/(\/|\\)node_modules(\/|\\)?$/.test(entry) && this.hasBuildOption(CONTENT_NODE_MODULES, true))
|
|
168
171
|
}
|
|
@@ -188,7 +191,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
188
191
|
const regex = RegExp('\\.cds$|\\.csv$|\\.hdbtabledata$')
|
|
189
192
|
|
|
190
193
|
await this.copyNativeContent(src, dest, (entry) => {
|
|
191
|
-
if (
|
|
194
|
+
if (isdir(entry)) {
|
|
192
195
|
return !/(\/|\\)node_modules(\/|\\)?$/.test(entry)
|
|
193
196
|
}
|
|
194
197
|
return (!regex.test(entry) && entry !== cds.env.build.outputfile) ||
|
|
@@ -200,7 +203,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
200
203
|
// subfolders are not supported
|
|
201
204
|
const allFiles = []
|
|
202
205
|
for (const csvDir of csvDirs) {
|
|
203
|
-
allFiles.push(...await find(csvDir, { filter: entry => regexData.test(entry) && !
|
|
206
|
+
allFiles.push(...await find(csvDir, { filter: entry => regexData.test(entry) && !isdir(entry) }))
|
|
204
207
|
}
|
|
205
208
|
|
|
206
209
|
return Promise.all(allFiles.map((file) => {
|
|
@@ -224,7 +227,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
224
227
|
const destSrcDir = path.join(this.task.dest, "src")
|
|
225
228
|
|
|
226
229
|
const allCsvFiles = await find(destSrcDir, { filter: (entry) => {
|
|
227
|
-
if (
|
|
230
|
+
if (isdir(entry)) {
|
|
228
231
|
return true
|
|
229
232
|
}
|
|
230
233
|
if (/\.hdbtabledata$/.test(entry)) {
|
|
@@ -257,9 +260,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
257
260
|
// otherwise create in 'src/gen'
|
|
258
261
|
let tableDataPath = csvFolder.startsWith(this.task.options.compileDest) ? csvFolder : this.task.options.compileDest
|
|
259
262
|
tableDataPath = path.join(tableDataPath, file)
|
|
260
|
-
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
261
|
-
this._result.hana.add(path.relative(this.task.dest, tableDataPath))
|
|
262
|
-
}
|
|
263
263
|
promises.push(this.write(tableData).to(tableDataPath))
|
|
264
264
|
}
|
|
265
265
|
await Promise.all(promises)
|
|
@@ -269,13 +269,11 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
269
269
|
async _stripCsvComments(csvFiles) {
|
|
270
270
|
// Note: modification of csv files is only allowed for files located in the compile destination folder,
|
|
271
271
|
// meaning having their origin location at db/data/* or db/csv/*
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
for (const file of csvFiles) {
|
|
272
|
+
await Promise.all(csvFiles.map(file => {
|
|
275
273
|
if (this.isStagingBuild() || file.startsWith(this.task.options.compileDest)) {
|
|
276
|
-
|
|
274
|
+
return cds.utils.csv?.stripComments(file, null, this.task.options.trimCsvWhitespaces)
|
|
277
275
|
}
|
|
278
|
-
}
|
|
276
|
+
}))
|
|
279
277
|
}
|
|
280
278
|
|
|
281
279
|
/**
|
|
@@ -300,7 +298,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
300
298
|
|
|
301
299
|
async _compileToHdb(model, format) {
|
|
302
300
|
const hdiPlugins = new Set()
|
|
303
|
-
const relDest = path.relative(this.task.dest, this.task.options.compileDest)
|
|
304
301
|
// enforces sqlNames option for compiler in tests
|
|
305
302
|
const options = { ...this.options(), sql_mapping: cds.env.sql.names }
|
|
306
303
|
const result = cds.compile.to[format](model, options)
|
|
@@ -311,9 +308,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
311
308
|
const file = key.file ? key.file : key.name + key.suffix
|
|
312
309
|
|
|
313
310
|
hdiPlugins.add(suffix)
|
|
314
|
-
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
315
|
-
this._result.hana.add(path.join(relDest, file))
|
|
316
|
-
}
|
|
317
311
|
promises.push(this.write(content).to(path.join(this.task.options.compileDest, file)))
|
|
318
312
|
if (suffix === FILE_EXT_HDBTABLE) {
|
|
319
313
|
const name = key.name || path.parse(key.file).name
|
|
@@ -332,7 +326,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
332
326
|
|
|
333
327
|
async _compileToHdbmigration(model, format, wsPaths) {
|
|
334
328
|
const hdiPlugins = new Set()
|
|
335
|
-
const relDestDir = path.relative(this.task.dest, this.task.options.compileDest)
|
|
336
329
|
const relDbDestDir = path.relative(cds.root, this.task.options.compileDest)
|
|
337
330
|
const dbSrcDir = path.join(this.task.src, "src")
|
|
338
331
|
const relDbSrcDir = path.relative(cds.root, dbSrcDir)
|
|
@@ -371,9 +364,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
371
364
|
if (!wsMigrationTables.has(name)) {
|
|
372
365
|
migrationTableFiles.push(path.join(relDbSrcDir, fileName))
|
|
373
366
|
if (changed) {
|
|
374
|
-
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
375
|
-
this._result.hana.add(path.join("src", fileName))
|
|
376
|
-
}
|
|
377
367
|
promises.push(this.write(content).to(path.join(dbSrcDir, fileName)))
|
|
378
368
|
} else {
|
|
379
369
|
DEBUG?.(`no change, keep existing ${fileName}`)
|
|
@@ -382,9 +372,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
382
372
|
DEBUG?.(`skip generation of migration table [${fileName}] as it originates from a different workspace`)
|
|
383
373
|
}
|
|
384
374
|
} else {
|
|
385
|
-
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
386
|
-
this._result.hana.add(path.join(relDestDir, fileName))
|
|
387
|
-
}
|
|
388
375
|
promises.push(this.write(content).to(path.join(this.task.options.compileDest, fileName)))
|
|
389
376
|
if (suffix === FILE_EXT_HDBTABLE) {
|
|
390
377
|
// issue an error in case a .hdbmigrationtable file already exists
|
|
@@ -407,12 +394,12 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
407
394
|
} finally {
|
|
408
395
|
// update last-dev CSN version
|
|
409
396
|
if (afterImage) {
|
|
410
|
-
if (!
|
|
397
|
+
if (!_toEqualIgnoreMeta(lastDev, afterImage)) {
|
|
411
398
|
await this.write(afterImage).to(lastDevCsnDir)
|
|
412
399
|
}
|
|
413
400
|
// add src/.hdiconfig if not existing
|
|
414
401
|
if (migrationTableFiles.length > 0 && !fs.existsSync(path.join(dbSrcDir, FILE_NAME_HDICONFIG))) {
|
|
415
|
-
const template = await
|
|
402
|
+
const template = await _readTemplateAsJson('.hdiconfig-cloud')
|
|
416
403
|
await this.write(template).to(path.join(dbSrcDir, FILE_NAME_HDICONFIG))
|
|
417
404
|
}
|
|
418
405
|
}
|
|
@@ -428,7 +415,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
428
415
|
DEBUG?.(`skip create [${relativePaths(cds.root, pkgJson)}], already existing`)
|
|
429
416
|
}
|
|
430
417
|
if (this.isStagingBuild() && !exists) {
|
|
431
|
-
const content = await
|
|
418
|
+
const content = await _readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
|
|
432
419
|
await this.write(content).to(path.join(this.task.dest, FILE_NAME_PACKAGE_JSON))
|
|
433
420
|
}
|
|
434
421
|
}
|
|
@@ -451,7 +438,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
451
438
|
// // without the need of creating a static .hdiconfig file in the 'db' folder
|
|
452
439
|
|
|
453
440
|
// // add all known plugins
|
|
454
|
-
// const defaultHdiConfig = await
|
|
441
|
+
// const defaultHdiConfig = await this._readTemplateAsJson('.hdiconfig-cloud')
|
|
455
442
|
// for (const plugin in defaultHdiConfig['file_suffixes']) {
|
|
456
443
|
// hdiPlugins.add('.' + plugin)
|
|
457
444
|
// }
|
|
@@ -463,7 +450,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
463
450
|
hdiConfigPath = path.join(this.task.options.compileDest, FILE_NAME_HDICONFIG)
|
|
464
451
|
// }
|
|
465
452
|
|
|
466
|
-
const template = await
|
|
453
|
+
const template = await _readTemplateAsJson('.hdiconfig-all')
|
|
467
454
|
let content = {
|
|
468
455
|
'file_suffixes': {}
|
|
469
456
|
}
|
|
@@ -490,7 +477,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
490
477
|
async _writeHdiNamespace() {
|
|
491
478
|
// see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
|
|
492
479
|
const hdiNamespace = path.join(this.task.options.compileDest, FILE_NAME_HDINAMESPACE)
|
|
493
|
-
const content = await
|
|
480
|
+
const content = await _readTemplateAsJson(FILE_NAME_HDINAMESPACE)
|
|
494
481
|
return await this.write(content).to(hdiNamespace)
|
|
495
482
|
}
|
|
496
483
|
|
|
@@ -502,7 +489,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
502
489
|
// see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
|
|
503
490
|
const undeployJsonDest = path.join(this.task.dest, FILE_NAME_UNDEPLOY_JSON)
|
|
504
491
|
const undeployJsonSrc = path.join(this.task.src, FILE_NAME_UNDEPLOY_JSON)
|
|
505
|
-
const templateEntries = await
|
|
492
|
+
const templateEntries = await _readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
|
|
506
493
|
let newEntries = []
|
|
507
494
|
if (fs.existsSync(undeployJsonSrc)) {
|
|
508
495
|
newEntries = await JSON.parse((await fs.promises.readFile(undeployJsonSrc, 'utf-8')).toString())
|
|
@@ -532,7 +519,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
532
519
|
if (fs.existsSync(file)) {
|
|
533
520
|
const undeployList = JSON.parse((await fs.promises.readFile(file)).toString(), 'utf-8')
|
|
534
521
|
if (Array.isArray(undeployList)) {
|
|
535
|
-
const hdiconfig = await
|
|
522
|
+
const hdiconfig = await _readTemplateAsJson('.hdiconfig-all')
|
|
536
523
|
const keys = new Set(Object.keys(hdiconfig['file_suffixes']).map(key => '.' + key))
|
|
537
524
|
undeployList.forEach(entry => {
|
|
538
525
|
const extName = path.extname(entry)
|
|
@@ -540,7 +527,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
540
527
|
if (keys.has(extName)) {
|
|
541
528
|
hdiPlugins.add(extName)
|
|
542
529
|
} else {
|
|
543
|
-
this.pushMessage(`Ignoring invalid entry '${entry}' in undeploy.json file`,
|
|
530
|
+
this.pushMessage(`Ignoring invalid entry '${entry}' in undeploy.json file`, SEVERITY_WARNING)
|
|
544
531
|
}
|
|
545
532
|
}
|
|
546
533
|
})
|
|
@@ -566,7 +553,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
566
553
|
resolutionMessages.push(new BuildMessage(`Manual resolution required for file ${path.relative(cds.root, file)}. Check migration version content for further details.`))
|
|
567
554
|
}
|
|
568
555
|
} catch (e) {
|
|
569
|
-
throw new Error(`${path.relative(cds.root, file)}: ${e.
|
|
556
|
+
throw new Error(`${path.relative(cds.root, file)}: ${e.message}`, { cause: e })
|
|
570
557
|
}
|
|
571
558
|
}))
|
|
572
559
|
if (resolutionMessages.length) {
|
|
@@ -618,35 +605,30 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
618
605
|
|
|
619
606
|
return workspaceFiles
|
|
620
607
|
}
|
|
608
|
+
}
|
|
621
609
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
610
|
+
async function _readTemplateAsJson(template) {
|
|
611
|
+
const content = await fs.promises.readFile(path.join(__dirname, 'template', template), 'utf-8')
|
|
612
|
+
return JSON.parse(content.toString())
|
|
613
|
+
}
|
|
625
614
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
return JSON.
|
|
615
|
+
function _toEqualIgnoreMeta(csn1, csn2) {
|
|
616
|
+
function toString(csn) {
|
|
617
|
+
return JSON.stringify(csn, (k, v) => {
|
|
618
|
+
if (v?.creator) {
|
|
619
|
+
// make sure it's the compiler meta tag
|
|
620
|
+
if (k === 'meta' && v.creator?.startsWith('CDS Compiler'))
|
|
621
|
+
return
|
|
622
|
+
}
|
|
623
|
+
return v
|
|
624
|
+
})
|
|
629
625
|
}
|
|
630
626
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
if (k === 'meta' && v.creator?.startsWith('CDS Compiler'))
|
|
637
|
-
return
|
|
638
|
-
}
|
|
639
|
-
return v
|
|
640
|
-
})
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
if (csn1 === csn2) {
|
|
644
|
-
return true
|
|
645
|
-
}
|
|
646
|
-
if (!csn1 || !csn2) {
|
|
647
|
-
return false
|
|
648
|
-
}
|
|
649
|
-
return toString(csn1) === toString(csn2)
|
|
627
|
+
if (csn1 === csn2) {
|
|
628
|
+
return true
|
|
629
|
+
}
|
|
630
|
+
if (!csn1 || !csn2) {
|
|
631
|
+
return false
|
|
650
632
|
}
|
|
633
|
+
return toString(csn1) === toString(csn2)
|
|
651
634
|
}
|
|
652
|
-
module.exports = HanaBuildPlugin
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const cds = require('../../../cds')
|
|
1
2
|
const fs = require('fs').promises
|
|
2
3
|
const {existsSync} = require('fs')
|
|
3
4
|
class MigrationTableParser {
|
|
@@ -306,7 +307,7 @@ class MigrationTableModel {
|
|
|
306
307
|
* Delete comments and return only those lines representing DDL statements.
|
|
307
308
|
*/
|
|
308
309
|
_compactLine(line) {
|
|
309
|
-
return line.
|
|
310
|
+
return line.replaceAll(' ', '')
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
313
|
|
|
@@ -354,7 +355,7 @@ class MigrationTable {
|
|
|
354
355
|
}
|
|
355
356
|
|
|
356
357
|
clone() {
|
|
357
|
-
return new MigrationTable(
|
|
358
|
+
return new MigrationTable(cds.clone(this.lines))
|
|
358
359
|
}
|
|
359
360
|
}
|
|
360
361
|
|
|
@@ -465,7 +466,7 @@ class Migration {
|
|
|
465
466
|
}
|
|
466
467
|
|
|
467
468
|
clone() {
|
|
468
|
-
return new Migration(
|
|
469
|
+
return new Migration(cds.clone(this.lines))
|
|
469
470
|
}
|
|
470
471
|
}
|
|
471
472
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const cds = require('../../../cds')
|
|
2
|
-
const { exists, path, readFileSync, yaml } = cds.utils
|
|
3
|
-
const {
|
|
4
|
-
const { join } = path
|
|
2
|
+
const { exists, path: { join }, readFileSync, yaml } = cds.utils
|
|
3
|
+
const { BuildError } = require('../../util')
|
|
5
4
|
const { readProject } = require('../../../init/projectReader')
|
|
5
|
+
const { SEVERITY_WARNING } = require('../../constants')
|
|
6
6
|
|
|
7
|
-
module.exports = class HelmBuildPlugin extends
|
|
8
|
-
static taskDefaults
|
|
7
|
+
module.exports = class HelmBuildPlugin extends require('../plugin') {
|
|
8
|
+
static get taskDefaults() { return { src: "." } }
|
|
9
9
|
|
|
10
10
|
static hasTask() {
|
|
11
11
|
if (exists('chart/Chart.yaml')) {
|
|
@@ -27,7 +27,7 @@ module.exports = class HelmBuildPlugin extends Plugin {
|
|
|
27
27
|
|
|
28
28
|
async build() {
|
|
29
29
|
if (!HelmBuildPlugin.hasTask()) {
|
|
30
|
-
this.pushMessage("Helm Chart not found. Execute `cds add kyma` to add the helm chart.",
|
|
30
|
+
this.pushMessage("Helm Chart not found. Execute `cds add kyma` to add the helm chart.", SEVERITY_WARNING)
|
|
31
31
|
return
|
|
32
32
|
}
|
|
33
33
|
|