@sap/cds-dk 7.2.0 → 7.3.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/bin/activate.js +2 -2
- package/bin/add.js +1 -1
- package/bin/build.js +6 -3
- package/bin/compile/index.js +9 -5
- package/bin/env.js +0 -3
- package/bin/extend.js +29 -3
- package/bin/import.js +7 -3
- package/bin/init.js +31 -37
- package/bin/push.js +10 -6
- package/bin/repl.js +23 -43
- package/bin/watch.js +5 -9
- package/lib/bind/bindingResolver.js +2 -1
- package/lib/bind/index.js +1 -1
- package/lib/build/{buildTaskHandler.js → buildPlugin.js} +40 -27
- package/lib/build/buildTaskEngine.js +75 -74
- package/lib/build/buildTaskFactory.js +39 -32
- package/lib/build/buildTaskProvider.js +24 -19
- package/lib/build/buildTaskProviderFactory.js +125 -58
- package/lib/build/constants.js +6 -4
- package/lib/build/index.js +7 -3
- package/lib/build/plugins.js +35 -0
- package/lib/build/provider/{buildTaskHandlerEdmx.js → edmxBuildPlugin.js} +11 -7
- package/lib/build/provider/{buildTaskHandlerFeatureToggles.js → featureToggleBuildPlugin.js} +5 -5
- package/lib/build/provider/fiori/index.js +5 -6
- package/lib/build/provider/hana/index.js +54 -30
- package/lib/build/provider/{buildTaskHandlerInternal.js → internalBuildPlugin.js} +14 -10
- package/lib/build/provider/{buildTaskProviderInternal.js → internalBuildTaskProvider.js} +27 -28
- package/lib/build/provider/java/index.js +30 -24
- package/lib/build/provider/mtx/index.js +4 -4
- package/lib/build/provider/mtx/resourcesTarBuilder.js +8 -8
- package/lib/build/provider/mtx-extension/index.js +17 -9
- package/lib/build/provider/mtx-sidecar/index.js +17 -11
- package/lib/build/provider/nodejs/index.js +14 -13
- package/lib/build/util.js +5 -0
- package/lib/client/auth_manager.js +6 -12
- package/lib/client/base_command.js +1 -1
- package/lib/client/download_legacy.js +43 -0
- package/lib/client/params.js +6 -0
- package/lib/client/push.js +41 -1
- package/lib/client/settings_manager.js +28 -17
- package/lib/compile/openapi/csdl2openapi.js +1 -1
- package/lib/env/schema.js +36 -0
- package/lib/env/schemas/cds-rc.json +101 -0
- package/lib/import/common.js +23 -10
- package/lib/import/importapi.js +2 -2
- package/lib/import/message.js +3 -1
- package/lib/import/odata/v4parser.js +23 -7
- package/lib/index.js +11 -0
- package/lib/init/constants.js +5 -2
- package/lib/init/index.js +2 -3
- package/lib/init/template/_merging/registry-mta.js +33 -0
- package/lib/init/template/approuter/files/mta.yaml.hbs +1 -1
- package/lib/init/template/approuter/index.js +9 -9
- package/lib/init/template/connectivity/index.js +5 -4
- package/lib/init/template/destination/index.js +2 -5
- package/lib/init/template/helm/subcharts/content-deployment/Chart.yaml +4 -4
- package/lib/init/template/helm/subcharts/content-deployment/templates/_helpers.tpl +4 -2
- package/lib/init/template/helm/subcharts/content-deployment/templates/job.yaml +4 -3
- package/lib/init/template/helm/subcharts/content-deployment/values.schema.json +9 -83
- package/lib/init/template/helm/subcharts/content-deployment/values.yaml +54 -15
- package/lib/init/template/helm/subcharts/service-instance/Chart.yaml +4 -4
- package/lib/init/template/helm/subcharts/service-instance/templates/serviceinstance.yaml +1 -1
- package/lib/init/template/helm/subcharts/service-instance/values.schema.json +0 -17
- package/lib/init/template/helm/subcharts/service-instance/values.yaml +28 -0
- package/lib/init/template/helm/subcharts/web-application/Chart.yaml +5 -5
- package/lib/init/template/helm/subcharts/web-application/templates/_api.tpl +60 -0
- package/lib/init/template/helm/subcharts/web-application/templates/_helpers.tpl +34 -73
- package/lib/init/template/helm/subcharts/web-application/templates/api-rule.yaml +4 -4
- package/lib/init/template/helm/subcharts/web-application/templates/deployment.yaml +96 -17
- package/lib/init/template/helm/subcharts/web-application/templates/network-policy.yaml +19 -3
- package/lib/init/template/helm/subcharts/web-application/templates/pod-disruption-budget.yaml +3 -3
- package/lib/init/template/helm/subcharts/web-application/templates/rbac.yaml +26 -0
- package/lib/init/template/helm/subcharts/web-application/templates/secret.yaml +1 -1
- package/lib/init/template/helm/subcharts/web-application/templates/service-account.yaml +1 -1
- package/lib/init/template/helm/subcharts/web-application/templates/service-binding.yaml +1 -1
- package/lib/init/template/helm/subcharts/web-application/templates/service.yaml +21 -3
- package/lib/init/template/helm/subcharts/web-application/templates/virtual-service.yaml +36 -0
- package/lib/init/template/helm/subcharts/web-application/values.schema.json +535 -142
- package/lib/init/template/helm/subcharts/web-application/values.yaml +168 -44
- package/lib/init/template/html5-repo/index.js +27 -3
- package/lib/init/template/mta/index.js +9 -3
- package/lib/init/template/nodejs/files/.vscode/launch.json +0 -3
- package/lib/init/template/notifications/files/mta.yaml.hbs +17 -0
- package/lib/init/template/notifications/files/notificationtypes.json.hbs +16 -0
- package/lib/init/template/notifications/files/package.json.hbs +14 -0
- package/lib/init/template/notifications/index.js +52 -0
- package/lib/init/template/postgres/files/mta.yaml.hbs +27 -0
- package/lib/init/template/postgres/files/package.json.hbs +5 -0
- package/lib/init/template/postgres/index.js +52 -0
- package/lib/init/util/projectReader.js +0 -1
- package/lib/util/pruneAxiosErrors.js +25 -8
- package/lib/util/term.js +1 -2
- package/lib/watch/livereload-server.js +38 -2
- package/lib/watch/node-watch.js +3 -2
- package/npm-shrinkwrap.json +334 -335
- package/package.json +2 -2
- package/lib/init/template/helm/subcharts/content-deployment/templating.md +0 -37
- package/lib/init/template/helm/subcharts/content-deployment/values-lint.yaml +0 -5
- package/lib/init/template/helm/subcharts/content-deployment/values.md +0 -1011
- package/lib/init/template/helm/subcharts/service-instance/templating.md +0 -18
- package/lib/init/template/helm/subcharts/service-instance/values-lint.yaml +0 -2
- package/lib/init/template/helm/subcharts/service-instance/values.md +0 -186
- package/lib/init/template/helm/subcharts/web-application/templating.md +0 -51
- package/lib/init/template/helm/subcharts/web-application/values-lint.yaml +0 -8
- package/lib/init/template/helm/subcharts/web-application/values.md +0 -1363
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
2
|
const cds = require('../../../cds')
|
|
3
3
|
const fs = require('fs')
|
|
4
|
-
const { FOLDER_GEN, DEFAULT_CSN_FILE_NAME, MTX_SIDECAR_DB_VALIDATION } = require('../../constants')
|
|
5
|
-
const
|
|
4
|
+
const { FOLDER_GEN, DEFAULT_CSN_FILE_NAME, MTX_SIDECAR_DB_VALIDATION, CONTENT_EDMX, FLAVOR_LOCALIZED_EDMX } = require('../../constants')
|
|
5
|
+
const NodejsBuildPlugin = require('../nodejs')
|
|
6
6
|
const ResourcesTarProvider = require('../mtx/resourcesTarBuilder')
|
|
7
|
-
const { ERROR } =
|
|
7
|
+
const { ERROR } = NodejsBuildPlugin
|
|
8
8
|
const { relativePaths, BuildError, resolveRequiredSapModels, getI18nDefaultFolder } = require('../../util')
|
|
9
9
|
|
|
10
10
|
const DEFAULT_MAIN_FOLDER = "_main"
|
|
11
11
|
|
|
12
|
-
class
|
|
12
|
+
class MtxSidecarBuildPlugin extends NodejsBuildPlugin {
|
|
13
13
|
get priority() {
|
|
14
14
|
// should be scheduled after 'hana' build tasks are finished
|
|
15
|
-
return
|
|
15
|
+
return NodejsBuildPlugin.PRIORITY_MIN_VALUE
|
|
16
16
|
}
|
|
17
17
|
init() {
|
|
18
18
|
super.init()
|
|
@@ -47,7 +47,6 @@ class MtxSidecarModuleBuilder extends NodeCfModuleBuilder {
|
|
|
47
47
|
const destSidecarSrc = path.join(destSidecar, cds.env.folders.srv)
|
|
48
48
|
const model = this._compileSidecarSync(sidecarEnv)
|
|
49
49
|
await this.compileToJson(model, path.join(destSidecarSrc, DEFAULT_CSN_FILE_NAME))
|
|
50
|
-
|
|
51
50
|
await this.collectLanguageBundles(model, path.join(destSidecarSrc, getI18nDefaultFolder()))
|
|
52
51
|
await this.copySrvContent(this.task.src, destSidecar, destSidecar)
|
|
53
52
|
}
|
|
@@ -76,16 +75,23 @@ class MtxSidecarModuleBuilder extends NodeCfModuleBuilder {
|
|
|
76
75
|
const destRoot = this.task.dest
|
|
77
76
|
const destMain = path.join(destRoot, main)
|
|
78
77
|
const destMainSrv = path.join(destMain, cds.env.folders.srv)
|
|
79
|
-
const
|
|
80
|
-
if (!
|
|
78
|
+
const model = await this.model()
|
|
79
|
+
if (!model) {
|
|
81
80
|
return
|
|
82
81
|
}
|
|
83
|
-
const { dictionary, sources } = await this.compileAll(
|
|
82
|
+
const { dictionary, sources } = await this.compileAll(model, destMainSrv, destMain)
|
|
84
83
|
await this.collectAllLanguageBundles(dictionary, sources, destMainSrv, destMain)
|
|
85
84
|
|
|
85
|
+
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
86
|
+
//inferred model expected by cds.compile.to.edmx()
|
|
87
|
+
const compileOptions = { [FLAVOR_LOCALIZED_EDMX]: this.hasBuildOption(FLAVOR_LOCALIZED_EDMX, true) } // disabled by default
|
|
88
|
+
const baseModel = cds.compiler.compileSources({ 'base.json': dictionary.base }, { messages: this.messages })
|
|
89
|
+
await this.compileToEdmx(baseModel, path.join(destMainSrv, 'odata', cds.env.odata.version), compileOptions)
|
|
90
|
+
}
|
|
91
|
+
|
|
86
92
|
// create resources TAR
|
|
87
93
|
// resources are determined based on available database build task, SQLite as fallback
|
|
88
|
-
await new ResourcesTarProvider(this).createTar(destMain,
|
|
94
|
+
await new ResourcesTarProvider(this).createTar(destMain, model)
|
|
89
95
|
|
|
90
96
|
// copy package.json and .cdsrc.json from project root
|
|
91
97
|
await this._copyMainConfigFiles(cds.root, destMain)
|
|
@@ -139,4 +145,4 @@ class MtxSidecarModuleBuilder extends NodeCfModuleBuilder {
|
|
|
139
145
|
return promises
|
|
140
146
|
}
|
|
141
147
|
}
|
|
142
|
-
module.exports =
|
|
148
|
+
module.exports = MtxSidecarBuildPlugin
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const cds = require('../../../cds')
|
|
4
|
-
const
|
|
4
|
+
const EdmxBuildPlugin = require('../edmxBuildPlugin')
|
|
5
5
|
const { BuildError } = require('../../util')
|
|
6
|
-
const { OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM, ODATA_VERSION_V2, FOLDER_GEN, CONTENT_EDMX,
|
|
7
|
-
|
|
8
|
-
const { WARNING } =
|
|
6
|
+
const { OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM, ODATA_VERSION_V2, FOLDER_GEN, CONTENT_EDMX, CONTENT_PACKAGELOCK_JSON,
|
|
7
|
+
CONTENT_NPMRC, CONTENT_CDSRC_JSON, CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, FLAVOR_LOCALIZED_EDMX } = require('../../constants')
|
|
8
|
+
const { WARNING } = EdmxBuildPlugin
|
|
9
9
|
|
|
10
|
-
class
|
|
10
|
+
class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
11
11
|
init() {
|
|
12
12
|
super.init()
|
|
13
13
|
if (this.task.options.compileDest) {
|
|
@@ -28,8 +28,7 @@ class NodejsModuleBuilder extends BuildTaskHandlerEdmx {
|
|
|
28
28
|
async build() {
|
|
29
29
|
const destSrv = this.isStagingBuild() ? this.destSrv : path.resolve(this.destSrv, cds.env.folders.srv)
|
|
30
30
|
const destRoot = this.isStagingBuild() ? this.task.dest : this.destSrv
|
|
31
|
-
|
|
32
|
-
if (cds.env.odata?.version === ODATA_VERSION_V2) {
|
|
31
|
+
if (cds.env.odata.version === ODATA_VERSION_V2) {
|
|
33
32
|
// log warning as nodejs is only supporting odata version V4
|
|
34
33
|
this.pushMessage("OData v2 is not supported by node runtime. Make sure to define OData v2 in cds configuration.", WARNING)
|
|
35
34
|
}
|
|
@@ -44,15 +43,17 @@ class NodejsModuleBuilder extends BuildTaskHandlerEdmx {
|
|
|
44
43
|
// collect and write language bundles into single i18n.json file
|
|
45
44
|
await this.collectAllLanguageBundles(dictionary, sources, destSrv, destRoot)
|
|
46
45
|
|
|
47
|
-
if (this.hasBuildOption(CONTENT_EDMX,
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
47
|
+
//REVISIT: inferred model expected by cds.compile.to.edmx()
|
|
48
|
+
const compileOptions = { [FLAVOR_LOCALIZED_EDMX]: this.hasBuildOption(FLAVOR_LOCALIZED_EDMX, true) }
|
|
49
|
+
const baseModel = cds.compiler.compileSources({ 'base.json': dictionary.base }, { messages: this.messages })
|
|
50
|
+
await this.compileToEdmx(baseModel, path.join(this.destSrv, 'odata', cds.env.odata.version), compileOptions)
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
if (this.isStagingBuild() && this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM)) {
|
|
53
54
|
const srcSrv = this.task.src === cds.root ? path.resolve(this.task.src, cds.env.folders.srv) : this.task.src
|
|
54
55
|
await this._copyNativeContent(cds.root, srcSrv, destRoot, destSrv)
|
|
55
|
-
if (this.context.options.
|
|
56
|
+
if (this.context.options.ws) {
|
|
56
57
|
await this._addWorkspaceDependencies(destRoot)
|
|
57
58
|
}
|
|
58
59
|
}
|
|
@@ -91,7 +92,7 @@ class NodejsModuleBuilder extends BuildTaskHandlerEdmx {
|
|
|
91
92
|
if (!workspaceNames.has(folder) && folder.match(regex)) {
|
|
92
93
|
workspaceNames.add(folder)
|
|
93
94
|
const plugin = require(require.resolve(path.join(workspaceRoot, folder, 'package.json')))
|
|
94
|
-
const tarFile = `${plugin.name.replace(/\//g,'-').replace(/@/, '')}-${plugin.version}.tgz`
|
|
95
|
+
const tarFile = `${plugin.name.replace(/\//g, '-').replace(/@/, '')}-${plugin.version}.tgz`
|
|
95
96
|
if (dependencies[plugin.name] === '*') {
|
|
96
97
|
const tarFilePath = path.join(dest, tarFile)
|
|
97
98
|
dependencies[plugin.name] = `file:${tarFile}`
|
|
@@ -209,4 +210,4 @@ class NodejsModuleBuilder extends BuildTaskHandlerEdmx {
|
|
|
209
210
|
}
|
|
210
211
|
}
|
|
211
212
|
|
|
212
|
-
module.exports =
|
|
213
|
+
module.exports = NodejsBuildPlugin
|
package/lib/build/util.js
CHANGED
|
@@ -208,6 +208,10 @@ function _locationString(loc) {
|
|
|
208
208
|
: `${loc.file}:${loc.line}.${loc.col}-${loc.endLine}.${loc.endCol}`;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
async function pathExists(path) {
|
|
212
|
+
return fs.promises.access(path).then(() => true).catch(() => false);
|
|
213
|
+
}
|
|
214
|
+
|
|
211
215
|
/**
|
|
212
216
|
* Class for individual build message.
|
|
213
217
|
*
|
|
@@ -271,6 +275,7 @@ module.exports = {
|
|
|
271
275
|
getI18nDefaultFolder,
|
|
272
276
|
isClassicMtx,
|
|
273
277
|
normalizePath,
|
|
278
|
+
pathExists,
|
|
274
279
|
BuildMessage,
|
|
275
280
|
BuildError
|
|
276
281
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
2
|
|
|
3
|
+
require('../util/pruneAxiosErrors');
|
|
4
|
+
|
|
3
5
|
const cds = require('../cds');
|
|
4
6
|
const DEBUG = cds.debug('cli');
|
|
5
7
|
const { SettingsManager } = require('./settings_manager');
|
|
@@ -54,16 +56,7 @@ function* reqParams(params) {
|
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
async function retrieveTokenOrPasscodeUrl(params) {
|
|
57
|
-
if (params.has('token')) {
|
|
58
|
-
if (params.get('renewLogin') || params.get('tokenExpirationDate') <= Date.now()) {
|
|
59
|
-
DEBUG?.((params.get('renewLogin') ? 'Renewing' : 'Refreshing expired') + ' authentication token');
|
|
60
|
-
params.delete('token');
|
|
61
|
-
params.delete('tokenExpirationDate');
|
|
62
|
-
} else {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if (!params.has('passcode') && !params.has('refreshToken') && params.has('passcodeUrl')) {
|
|
59
|
+
if (params.has('token') || !params.has('refreshToken') && !params.has('passcode') && params.has('passcodeUrl')) {
|
|
67
60
|
return;
|
|
68
61
|
}
|
|
69
62
|
|
|
@@ -76,7 +69,7 @@ async function retrieveTokenOrPasscodeUrl(params) {
|
|
|
76
69
|
DEBUG?.(`Getting authentication token or passcode URL from ${method.toUpperCase()} ${(params.obfuscateQueryParams(url))}`);
|
|
77
70
|
response = await axios[method](url, data);
|
|
78
71
|
} catch (error) {
|
|
79
|
-
if (error.
|
|
72
|
+
if (error.status === 404) { // may represent 405 in case of wrong method
|
|
80
73
|
continue;
|
|
81
74
|
}
|
|
82
75
|
throw getMessage('Failed to get authentication token', { error });
|
|
@@ -95,7 +88,8 @@ async function retrieveTokenOrPasscodeUrl(params) {
|
|
|
95
88
|
|
|
96
89
|
if (authData.access_token) {
|
|
97
90
|
addTokenInfo(params, authData);
|
|
98
|
-
}
|
|
91
|
+
}
|
|
92
|
+
if (authData.passcode_url) {
|
|
99
93
|
addUrlInfo(params, authData);
|
|
100
94
|
}
|
|
101
95
|
}
|
|
@@ -20,7 +20,7 @@ module.exports = class BaseCommand {
|
|
|
20
20
|
static handleHttpError(error, params, { url, command } = {}) {
|
|
21
21
|
url = url ?? params.get('appUrl');
|
|
22
22
|
const prefix = `Request to ${url} failed`;
|
|
23
|
-
switch (error.
|
|
23
|
+
switch (error.status) {
|
|
24
24
|
case 401:
|
|
25
25
|
throw getMessage(`${prefix}: invalid authentication.\nRetry with valid passcode${
|
|
26
26
|
params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : ''
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const cds = require ('../cds')
|
|
2
|
+
const { tar } = cds.utils;
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { join } = require('path');
|
|
6
|
+
const axios = require('axios');
|
|
7
|
+
|
|
8
|
+
const { login } = require('./auth_manager');
|
|
9
|
+
const BaseCommand = require('./base_command');
|
|
10
|
+
|
|
11
|
+
const DOWNLOAD_FILE_NAME = 'migrated_projects.tgz'; // TODO try to add tenant later, if possible
|
|
12
|
+
|
|
13
|
+
module.exports = class Download extends BaseCommand {
|
|
14
|
+
|
|
15
|
+
static async run(paramValues) {
|
|
16
|
+
const params = await login(paramValues);
|
|
17
|
+
|
|
18
|
+
const projectFolder = params.get('projectFolder');
|
|
19
|
+
const downloadPath = join(projectFolder, DOWNLOAD_FILE_NAME);
|
|
20
|
+
|
|
21
|
+
if (fs.existsSync(downloadPath) && !(await require('./helper/question').askBooleanQuestion(`File ${DOWNLOAD_FILE_NAME} already exists. Continue (yN)? `, false, false))) {
|
|
22
|
+
console.log('Download cancelled');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(`Downloading migrated @sap/mtx extension project(s)`);
|
|
27
|
+
const downloadedTgz = await this.getTgz(params);
|
|
28
|
+
await fs.promises.writeFile(downloadPath, downloadedTgz);
|
|
29
|
+
|
|
30
|
+
console.log(`Finished.`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static async getTgz(params) {
|
|
34
|
+
const tagRule = params.get('tagRule');
|
|
35
|
+
const defaultTag = params.get('defaultTag');
|
|
36
|
+
const downloadUrl = `${(params.get('appUrl'))}/-/cds/extensibility/getMigratedProjects`;
|
|
37
|
+
const options = { ...params.get('reqAuth'), responseType: 'arraybuffer' };
|
|
38
|
+
|
|
39
|
+
return axios.post(downloadUrl, { tagRule, defaultTag }, options)
|
|
40
|
+
.then(response => Buffer.from(response.data))
|
|
41
|
+
.catch(error => this.handleHttpError(error, params, { url: downloadUrl }));
|
|
42
|
+
}
|
|
43
|
+
}
|
package/lib/client/params.js
CHANGED
|
@@ -162,6 +162,9 @@ class BasicParams {
|
|
|
162
162
|
this.projectFolder = new Param('projectFolder', '');
|
|
163
163
|
this.directory = this.projectFolder.newAlias('directory');
|
|
164
164
|
|
|
165
|
+
this.tagRule = new Param('tagRule', '');
|
|
166
|
+
this.defaultTag = new Param('defaultTag', '');
|
|
167
|
+
|
|
165
168
|
// - non-persisted, internal
|
|
166
169
|
this.reqAuth = new Param('reqAuth', null, { obfuscate: ObfuscationLevel.full, internal: true });
|
|
167
170
|
this.clearOtherTokenStorage = new Param('clearOtherTokenStorage', false, { internal: true });
|
|
@@ -222,6 +225,9 @@ class AllParams extends BasicParams {
|
|
|
222
225
|
this["delete-settings"] = this.deleteSettings.newAlias('delete-settings');
|
|
223
226
|
this.clearInvalid = new Param('clearInvalid', false);
|
|
224
227
|
this["clear-invalid"] = this.clearInvalid.newAlias('clear-invalid');
|
|
228
|
+
|
|
229
|
+
// download for mxts
|
|
230
|
+
this["download-migrated-projects"] = new Param('download-migrated-projects', false)
|
|
225
231
|
}
|
|
226
232
|
}
|
|
227
233
|
|
package/lib/client/push.js
CHANGED
|
@@ -9,6 +9,13 @@ const { getMessage } = require('./helper/logging');
|
|
|
9
9
|
const { schemaRegex } = require('./helper/url_helper');
|
|
10
10
|
const buildSystem = require('../build')
|
|
11
11
|
|
|
12
|
+
const JOB_STATUS = {
|
|
13
|
+
QUEUED: 'QUEUED',
|
|
14
|
+
RUNNING: 'RUNNING',
|
|
15
|
+
FINISHED: 'FINISHED',
|
|
16
|
+
FAILED: 'FAILED'
|
|
17
|
+
};
|
|
18
|
+
|
|
12
19
|
module.exports = class Push extends BaseCommand {
|
|
13
20
|
|
|
14
21
|
static async run(paramValues, pushOptions = {}) {
|
|
@@ -27,7 +34,11 @@ module.exports = class Push extends BaseCommand {
|
|
|
27
34
|
const target = Object.assign({ url }, subdomain && { subdomain });
|
|
28
35
|
|
|
29
36
|
console.log(`\nPushing extension '${extensionName}' from`, { src }, 'to', target);
|
|
30
|
-
await this.pushTgz(params, content, extensionName);
|
|
37
|
+
const push = await this.pushTgz(params, content, extensionName);
|
|
38
|
+
const async = !params.get('sync');
|
|
39
|
+
if (async) {
|
|
40
|
+
await this.pollUntilFinished(push.headers.location, params)
|
|
41
|
+
}
|
|
31
42
|
console.log ('Activation succeeded.\n')
|
|
32
43
|
}
|
|
33
44
|
|
|
@@ -61,6 +72,10 @@ module.exports = class Push extends BaseCommand {
|
|
|
61
72
|
static async pushTgz(params, tgz, extensionName) {
|
|
62
73
|
const pushUrl = `${params.get('appUrl')}/-/cds/extensibility/push`;
|
|
63
74
|
const options = { ...params.get('reqAuth') };
|
|
75
|
+
const async = !params.get('sync');
|
|
76
|
+
if (async) {
|
|
77
|
+
options.headers = { prefer: 'respond-async', ...options.headers }
|
|
78
|
+
}
|
|
64
79
|
|
|
65
80
|
return axios.post(pushUrl, {
|
|
66
81
|
extension: tgz,
|
|
@@ -68,4 +83,29 @@ module.exports = class Push extends BaseCommand {
|
|
|
68
83
|
}, options)
|
|
69
84
|
.catch(error => this.handleHttpError(error, params, { url: pushUrl }));
|
|
70
85
|
}
|
|
86
|
+
|
|
87
|
+
static async pollUntilFinished(jobUrl, params) {
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const options = { ...params.get('reqAuth') };
|
|
90
|
+
|
|
91
|
+
const timeout = setTimeout(() => {
|
|
92
|
+
clearInterval(interval);
|
|
93
|
+
reject(new Error('cds push timed out after 5 minutes'));
|
|
94
|
+
}, 5 * 60 * 1000);
|
|
95
|
+
|
|
96
|
+
const interval = setInterval(async () => {
|
|
97
|
+
const { status, error } = (await axios.get(jobUrl, options)).data;
|
|
98
|
+
if (status === JOB_STATUS.FINISHED || status === JOB_STATUS.FAILED) {
|
|
99
|
+
clearInterval(interval);
|
|
100
|
+
clearTimeout(timeout);
|
|
101
|
+
|
|
102
|
+
if (status === JOB_STATUS.FINISHED) {
|
|
103
|
+
resolve();
|
|
104
|
+
} else if (status === JOB_STATUS.FAILED) {
|
|
105
|
+
reject(new Error(error));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, 1000);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
71
111
|
}
|
|
@@ -112,7 +112,7 @@ async function getTokenBaseUrl(params, renewUrl) {
|
|
|
112
112
|
existingPath = path;
|
|
113
113
|
break;
|
|
114
114
|
} catch (error) {
|
|
115
|
-
if ([401, 404].includes(error.
|
|
115
|
+
if ([401, 404].includes(error.status)) {
|
|
116
116
|
continue;
|
|
117
117
|
}
|
|
118
118
|
throw error;
|
|
@@ -215,29 +215,31 @@ class SettingsManager {
|
|
|
215
215
|
|
|
216
216
|
static async updateUrls(params, logout, loadedAppUrl) {
|
|
217
217
|
async function addAppUrl() {
|
|
218
|
-
// Prefix URL schema
|
|
219
|
-
if (params.has('appUrl')) {
|
|
220
|
-
const appUrl = params.get('appUrl');
|
|
221
|
-
if (!schemaRegex.test(appUrl)) {
|
|
222
|
-
if (localhostRegex.test(appUrl)) {
|
|
223
|
-
params.set('appUrl', httpSchema + appUrl);
|
|
224
|
-
} else {
|
|
225
|
-
params.set('appUrl', httpsSchema + appUrl);
|
|
226
|
-
}
|
|
227
|
-
DEBUG?.(`Added schema to app URL: ${params.get('appUrl')}`);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
218
|
if (!logout && !params.has('appUrl')) {
|
|
232
219
|
// Get appUrl from CF
|
|
233
220
|
DEBUG?.('App URL not given');
|
|
234
221
|
await getAppUrlAndSubdomainFromSuggestions(params);
|
|
235
222
|
}
|
|
236
223
|
|
|
237
|
-
// Check required param: appUrl
|
|
238
224
|
if (!params.has('appUrl')) {
|
|
239
225
|
throw 'App URL not given. Please specify it or log in to Cloud Foundry and repeat this command.';
|
|
240
226
|
}
|
|
227
|
+
|
|
228
|
+
// Prefix URL schema
|
|
229
|
+
let appUrl = params.get('appUrl');
|
|
230
|
+
if (appUrl.endsWith('/')) {
|
|
231
|
+
appUrl = appUrl.replace(/\/+$/, '');
|
|
232
|
+
DEBUG?.(`Removed trailing slash from app URL: ${appUrl}`);
|
|
233
|
+
}
|
|
234
|
+
if (!schemaRegex.test(appUrl)) {
|
|
235
|
+
if (localhostRegex.test(appUrl)) {
|
|
236
|
+
appUrl = httpSchema + appUrl;
|
|
237
|
+
} else {
|
|
238
|
+
appUrl = httpsSchema + appUrl;
|
|
239
|
+
}
|
|
240
|
+
DEBUG?.(`Added schema to app URL: ${appUrl}`);
|
|
241
|
+
}
|
|
242
|
+
params.set('appUrl', appUrl);
|
|
241
243
|
}
|
|
242
244
|
async function renewTokenUrl() {
|
|
243
245
|
const renewUrl = params.get('appUrl') !== loadedAppUrl;
|
|
@@ -344,6 +346,13 @@ class SettingsManager {
|
|
|
344
346
|
params.merge(auth[storage]);
|
|
345
347
|
}
|
|
346
348
|
}
|
|
349
|
+
function removeObsoleteToken() {
|
|
350
|
+
if (params.get('renewLogin') || params.get('tokenExpirationDate') <= Date.now()) {
|
|
351
|
+
DEBUG?.((params.get('renewLogin') ? 'Renewing' : 'Refreshing expired') + ' authentication token');
|
|
352
|
+
params.delete('token');
|
|
353
|
+
params.delete('tokenExpirationDate');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
347
356
|
|
|
348
357
|
if (params.has('username')) {
|
|
349
358
|
if (!params.has('password') && !logout) {
|
|
@@ -381,8 +390,10 @@ class SettingsManager {
|
|
|
381
390
|
};
|
|
382
391
|
|
|
383
392
|
setRelevantAuth(auth);
|
|
384
|
-
|
|
385
|
-
|
|
393
|
+
if (params.has('token')) {
|
|
394
|
+
removeObsoleteToken();
|
|
395
|
+
}
|
|
396
|
+
if (!logout && !params.has('token') && !params.has('refreshToken') && !params.has('passcode') && !params.has('clientsecret') && !params.has('key')) {
|
|
386
397
|
await addPasscode();
|
|
387
398
|
}
|
|
388
399
|
}
|
|
@@ -64,7 +64,7 @@ module.exports.csdl2openapi = function (
|
|
|
64
64
|
csdl = JSON.parse(JSON.stringify(csdl))
|
|
65
65
|
csdl.$Version = odataVersion ? odataVersion : '4.01'
|
|
66
66
|
serviceRoot = serviceRoot || (scheme + '://' + host + basePath);
|
|
67
|
-
const queryOptionPrefix = csdl.$Version <= '4.
|
|
67
|
+
const queryOptionPrefix = csdl.$Version <= '4.01' ? '$' : '';
|
|
68
68
|
const typesToInline = {}; // filled in schema() and used in inlineTypes()
|
|
69
69
|
const boundOverloads = {};
|
|
70
70
|
const derivedTypes = {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const { join } = require('path')
|
|
2
|
+
const { mergeJSON } = require('../init/util/merge')
|
|
3
|
+
const { readJSON } = require('../util/fs')
|
|
4
|
+
|
|
5
|
+
module.exports = async function overlay4(schemaName, cwd = process.cwd()) {
|
|
6
|
+
|
|
7
|
+
// need to load @sap/cds from current cwd which might
|
|
8
|
+
// differ from initial cwd to get project specific cds version
|
|
9
|
+
const cds = require(require.resolve('@sap/cds', {
|
|
10
|
+
paths: [cwd, __dirname]
|
|
11
|
+
}))
|
|
12
|
+
|
|
13
|
+
// force cds.root to be project root
|
|
14
|
+
cds.root = cwd
|
|
15
|
+
|
|
16
|
+
// load defaults, throw err if schema not found
|
|
17
|
+
let result;
|
|
18
|
+
if (typeof cds.schema?.default4 === 'function') {
|
|
19
|
+
result = await cds.schema.default4(schemaName)
|
|
20
|
+
} else if (cds.env?.schemas?.[schemaName]) {
|
|
21
|
+
// backwards compatibility
|
|
22
|
+
result = await readJSON(cds.env.schemas[schemaName])
|
|
23
|
+
} else {
|
|
24
|
+
throw new Error(`cds ${cds.version} in ${cwd} does not support schema retrieval.`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// optional, don't throw if file not found
|
|
28
|
+
try {
|
|
29
|
+
await mergeJSON(result, join(__dirname, 'schemas', schemaName))
|
|
30
|
+
result.description = result.description + ' - overlaid'
|
|
31
|
+
} catch (err) {
|
|
32
|
+
if (err.code !== 'ENOENT') throw err
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return result
|
|
36
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "JSON schema for CDS-DK configuration",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"description": "This is a JSON schema representation for CDS project configuration",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": true,
|
|
7
|
+
"properties": {
|
|
8
|
+
"build": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"description": "Customize CDS build settings.",
|
|
11
|
+
"additionalProperties": true,
|
|
12
|
+
"properties": {
|
|
13
|
+
"target": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Specify the folder which contains generated build results. Defaults to './gen'.",
|
|
16
|
+
"format": "uri-reference"
|
|
17
|
+
},
|
|
18
|
+
"tasks": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"description": "Control which tasks 'cds build' will execute on your project modules. This is a typical task configuration: '\"tasks\": [{ \"for\": \"hana\"}];",
|
|
21
|
+
"uniqueItems": true,
|
|
22
|
+
"default": [
|
|
23
|
+
{}
|
|
24
|
+
],
|
|
25
|
+
"items": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"additionalProperties": true,
|
|
28
|
+
"properties": {
|
|
29
|
+
"dest": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "Optional: Define the destination folder for this build task, relative to build target folder. \nFor example: Destination defined as 'custom' results in an output written to 'gen/custom'.",
|
|
32
|
+
"format": "uri-reference"
|
|
33
|
+
},
|
|
34
|
+
"src": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"description": "Optional: Prefer defining 'cds.folders'. Use 'src' if you want it only to be valid for this specific build task, which excludes, for example, 'cds watch'.",
|
|
37
|
+
"format": "uri-reference"
|
|
38
|
+
},
|
|
39
|
+
"for": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"description": "Define the target technology for this build task.",
|
|
42
|
+
"minLength": 1,
|
|
43
|
+
"enum": [
|
|
44
|
+
"nodejs",
|
|
45
|
+
"java",
|
|
46
|
+
"hana",
|
|
47
|
+
"mtx-sidecar",
|
|
48
|
+
"mtx-extension",
|
|
49
|
+
"mtx",
|
|
50
|
+
"fiori",
|
|
51
|
+
"node-cf",
|
|
52
|
+
"java-cf"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"options": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"description": "Optional: Set target technology specific options for this build task.",
|
|
58
|
+
"additionalProperties": true,
|
|
59
|
+
"properties": {
|
|
60
|
+
"model": {
|
|
61
|
+
"$ref": "#/$defs/foldersStringArray"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"deploy": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"description": "Customize 'cds deploy' settings.",
|
|
73
|
+
"additionalProperties": true,
|
|
74
|
+
"properties": {
|
|
75
|
+
"no_save": {
|
|
76
|
+
"type": "boolean",
|
|
77
|
+
"description": "Do / don't update configuration in package.json.",
|
|
78
|
+
"default": true
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"$defs": {
|
|
84
|
+
"foldersStringArray": {
|
|
85
|
+
"oneOf": [
|
|
86
|
+
{
|
|
87
|
+
"type": "string",
|
|
88
|
+
"format": "uri-reference"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"type": "array",
|
|
92
|
+
"uniqueItems": true,
|
|
93
|
+
"items": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"format": "uri-reference"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
package/lib/import/common.js
CHANGED
|
@@ -17,7 +17,7 @@ let optionsMapping = {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
let apiOptions = ['includeNamespaces', 'keepNamespace'];
|
|
20
|
-
let commonOptions = ['no_copy', 'no_save', 'out', 'dry', 'as', 'from', 'force'];
|
|
20
|
+
let commonOptions = ['no_copy', 'no_save', 'out', 'dry', 'as', 'from', 'force', 'config'];
|
|
21
21
|
|
|
22
22
|
async function generateEDMX2JSON(edmx) {
|
|
23
23
|
let cjson = convert.xml2json(edmx, {
|
|
@@ -148,6 +148,18 @@ async function _copyToSrvExternal(file, dst, cwd) {
|
|
|
148
148
|
return file;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
async function isValidJsonObject(options){
|
|
152
|
+
let config;
|
|
153
|
+
try {
|
|
154
|
+
if (options.config) {
|
|
155
|
+
config = JSON.parse(options.config);
|
|
156
|
+
return config;
|
|
157
|
+
}
|
|
158
|
+
} catch (error) {
|
|
159
|
+
throw new Error(messages.SPECIFY_CONFIG);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
151
163
|
async function preProcess(file, options, cwd) {
|
|
152
164
|
let srcFilePath = await isValidInputFile(path.resolve(cwd, file));
|
|
153
165
|
if (options.as && !_supportedAsFormats().includes(options.as))
|
|
@@ -266,12 +278,12 @@ async function _generateChecksumValidate(dest, output, force) {
|
|
|
266
278
|
return "/* checksum : " + currentChecksum + " */\n" + output;
|
|
267
279
|
}
|
|
268
280
|
|
|
269
|
-
async function _getResult(output, as, dest, force,
|
|
281
|
+
async function _getResult(output, as, dest, force, kind) {
|
|
270
282
|
let extension = dest.substring(dest.lastIndexOf(".") + 1);
|
|
271
283
|
as = (as === "cds") ? "cdl" : as;
|
|
272
284
|
|
|
273
285
|
// output filepath should simply contain .csn as extension
|
|
274
|
-
if (
|
|
286
|
+
if (kind === 'rest' && ['swagger', 'openapi3'].includes(extension)) {
|
|
275
287
|
dest = dest.replace('.' + extension, '');
|
|
276
288
|
}
|
|
277
289
|
|
|
@@ -325,19 +337,19 @@ ${using}
|
|
|
325
337
|
console.log(message);
|
|
326
338
|
}
|
|
327
339
|
|
|
328
|
-
async function _updatePackageJson(dest, services,
|
|
340
|
+
async function _updatePackageJson(dest, services, kind, cwd, config) {
|
|
329
341
|
const package_json = path.resolve(cwd, 'package.json');
|
|
330
342
|
const conf = await exists(package_json) ? require(package_json) : {};
|
|
331
343
|
const requires = ['cds', 'requires'].reduce((p, n) => p[n] || (p[n] = {}), conf);
|
|
332
|
-
if (
|
|
333
|
-
|
|
344
|
+
if (kind !== 'rest') {
|
|
345
|
+
kind = (kind === "V2") ? 'odata-v2' : 'odata';
|
|
334
346
|
}
|
|
335
347
|
let package_json_updated = false;
|
|
336
348
|
for (let service of services) {
|
|
337
349
|
if (!requires[service]) {
|
|
338
350
|
const initial_model = path.relative(cwd, dest);
|
|
339
351
|
const model = isLinux() ? initial_model.replace(/\\/g, '/') : initial_model;
|
|
340
|
-
cds.env.requires[service] = requires[service] = { kind:
|
|
352
|
+
cds.env.requires[service] = requires[service] = { kind: kind, model, ...config };
|
|
341
353
|
await write(package_json, JSON.stringify(conf, null, ' '));
|
|
342
354
|
package_json_updated = true;
|
|
343
355
|
}
|
|
@@ -349,11 +361,12 @@ async function _updatePackageJson(dest, services, version, cwd) {
|
|
|
349
361
|
|
|
350
362
|
async function postProcess(filePath, options, csn, cwd) {
|
|
351
363
|
const services = _getServiceNames(csn);
|
|
364
|
+
let config = await isValidJsonObject(options);
|
|
352
365
|
if (options.out) options.out = _validateAndComputeOutputFilePath(options.out, options.as, filePath);
|
|
353
|
-
const
|
|
354
|
-
const result = await _getResult(csn, options.as, options.out || filePath.replace(/\.[^.]+$/, ''), options.force,
|
|
366
|
+
const kind = options.inputFileKind;
|
|
367
|
+
const result = await _getResult(csn, options.as, options.out || filePath.replace(/\.[^.]+$/, ''), options.force, kind);
|
|
355
368
|
const written = options.dry || await _write(result, services, cwd);
|
|
356
|
-
const registered = options.dry || options.no_save || await _updatePackageJson(result[1].replace(/\.[^.]+$/, ''), services,
|
|
369
|
+
const registered = options.dry || options.no_save || await _updatePackageJson(result[1].replace(/\.[^.]+$/, ''), services, kind, cwd, config);
|
|
357
370
|
if (options.dry) return console.log(result[0]);
|
|
358
371
|
return Promise.all([written, registered]);
|
|
359
372
|
}
|