@sap/cds-dk 6.4.1 → 6.5.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 +30 -0
- package/bin/bind.js +30 -34
- package/bin/cds.js +14 -3
- package/bin/deploy/index.js +6 -5
- package/bin/deploy/to-sqlite.js +2 -1
- package/bin/env.js +4 -4
- package/bin/migrate.js +25 -4
- package/bin/push.js +4 -0
- package/bin/watch.js +3 -3
- package/lib/bind/KubernetesApiAccessor.js +79 -0
- package/lib/bind/{BindingManager.js → bindingManager.js} +16 -15
- package/lib/bind/bindingResolver.js +41 -68
- package/lib/bind/bindingUtil.js +93 -104
- package/lib/bind/cfKeyProvider.js +85 -74
- package/lib/bind/kubernetesCredentialsProvider.js +34 -132
- package/lib/bind/userCdsrcJsonStorageProvider.js +12 -18
- package/lib/client/params.js +2 -2
- package/lib/client/push.js +11 -6
- package/lib/client/settings_manager.js +2 -1
- package/lib/client/subscription.js +4 -1
- package/lib/import/odata/v2parser.js +32 -8
- package/lib/import/odata/v4parser.js +5 -2
- package/lib/init/constants.js +1 -1
- package/lib/init/index.js +3 -11
- package/lib/init/template/approuter/files/approuter-configmap.yaml +4 -1
- package/lib/init/template/approuter/files/approuter-mtxs-configmap.yaml +5 -1
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/approuter/files/values.yaml.hbs +1 -1
- package/lib/init/template/approuter/files/xs-app.json.hbs +2 -2
- package/lib/init/template/approuter/index.js +4 -5
- package/lib/init/template/auditlog/index.js +1 -1
- package/lib/init/template/data/index.js +1 -1
- package/lib/init/template/destinations/index.js +1 -1
- package/lib/init/template/enterprise-messaging/index.js +1 -1
- package/lib/init/template/extensibility/index.js +6 -1
- package/lib/init/template/hana/files/chart.yaml +4 -0
- package/lib/init/template/hana/files/hana.yaml +1 -0
- package/lib/init/template/hana/files/java/db/package.json +1 -1
- package/lib/init/template/hana/files/values.yaml.hbs +6 -3
- package/lib/init/template/hana/index.js +73 -21
- package/lib/init/template/helm/chart/templates/_deployment_helpers.tpl +14 -6
- package/lib/init/template/helm/chart/values.root.schema.json +10 -0
- package/lib/init/template/helm/chart/values.schema.json +11 -110
- package/lib/init/template/helm/index.js +2 -2
- package/lib/init/template/helm/subcharts/content-deployment/Chart.yaml +5 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/_helpers.tpl +207 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/job.yaml +66 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/secret.yaml +10 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/service-account.yaml +4 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/service-binding.yaml +28 -0
- package/lib/init/template/helm/subcharts/content-deployment/values-lint.yaml +5 -0
- package/lib/init/template/helm/subcharts/content-deployment/values.md +1014 -0
- package/lib/init/template/helm/subcharts/content-deployment/values.schema.json +589 -0
- package/lib/init/template/helm/subcharts/content-deployment/values.yaml +54 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/Chart.yaml +0 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/_helpers.tpl +56 -50
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/api-rule.yaml +1 -1
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/deployment.yaml +15 -9
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/network-policy.yaml +0 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/pod-disruption-budget.yaml +2 -2
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/secret.yaml +0 -0
- package/lib/init/template/helm/subcharts/web-application/templates/service-account.yaml +6 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/service-binding.yaml +4 -3
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/service.yaml +0 -0
- package/lib/init/template/helm/subcharts/web-application/templating.md +44 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/values-lint.yaml +0 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/values.md +254 -200
- package/lib/init/template/helm/{subchart → subcharts/web-application}/values.schema.json +82 -28
- package/lib/init/template/helm/{subchart → subcharts/web-application}/values.yaml +15 -5
- package/lib/init/template/html5-repo/files/chart.yaml +4 -0
- package/lib/init/template/html5-repo/files/html5-apps-deployer-configmap.yaml +14 -0
- package/lib/init/template/html5-repo/index.js +39 -7
- package/lib/init/template/kibana-logging/index.js +1 -1
- package/lib/init/template/lint/index.js +1 -1
- package/lib/init/template/multitenancy/files/saas-registry.yaml +2 -2
- package/lib/init/template/multitenancy/files/service-manager.yaml +1 -0
- package/lib/init/template/multitenancy/files/values.yaml.hbs +10 -6
- package/lib/init/template/multitenancy/index.js +21 -3
- package/lib/init/util/commandUtil.js +5 -5
- package/lib/init/util/merge.js +27 -1
- package/lib/init/util/mvnArchetypeUtil.js +1 -1
- package/lib/init/util/projectReader.js +2 -2
- package/lib/util/exec.js +3 -3
- package/lib/util/term.js +7 -7
- package/lib/watch/livereload-connect.js +187 -0
- package/lib/watch/livereload-server.js +12 -12
- package/lib/watch/node-watch.js +1 -1
- package/npm-shrinkwrap.json +56 -308
- package/package.json +1 -4
- package/lib/init/template/hana/files/hana-deployer-job.yaml +0 -49
- package/lib/init/template/html5-repo/files/_html5_deployment_helpers.tpl +0 -16
- package/lib/init/template/html5-repo/files/html5-apps-deployer-job.yaml +0 -61
- package/lib/init/util/spinner.js +0 -80
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,34 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
9
9
|
|
|
10
|
+
## Version 6.5.1 - 2023-02-06
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `cds init` uses latest Maven Java archetype version 1.31.0 for creating Java projects.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- `cds deploy` no longer fails to write to a `package.json` file that has no `cds` section
|
|
19
|
+
|
|
20
|
+
## Version 6.5.0 - 2023-01-27
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- `cds run/serve/migrate --resolve-bindings` now pulls required service credentials if bound via `cds bind`. (beta)
|
|
25
|
+
- `cds add helm` now supports multitenancy.
|
|
26
|
+
- `cds bind` now supports binding of `user-provided service instances` from Cloud Foundry.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- `cds push` now runs a build of the extension project to update the pushed extension archive (unless custom archive given).
|
|
31
|
+
- `cds init` and `cds bind` no longer use a spinner when performing long running operations.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- `cds import` now generates flattened value for `@Common.FieldControl` annotation in the CSN for OData V4 files.
|
|
36
|
+
- `cds import` now treates `CollectionKind` property attribute in OData V2 similar to `Collection(<data_type>)` in OData V4.
|
|
37
|
+
|
|
10
38
|
## Version 6.4.1 - 2022-01-17
|
|
11
39
|
|
|
12
40
|
### Fixed
|
|
@@ -14,6 +42,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
|
14
42
|
- `cds deploy -2 sqlite` now preserves the `schema_evolution` setting in the `package.json`.
|
|
15
43
|
- `cds import` bug fix for OData V4 import crash.
|
|
16
44
|
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
17
47
|
## Version 6.4.0 - 2022-12-15
|
|
18
48
|
|
|
19
49
|
### Added
|
package/bin/bind.js
CHANGED
|
@@ -46,19 +46,14 @@ module.exports = Object.assign(cds_bind, {
|
|
|
46
46
|
`
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
// required for spinner
|
|
52
|
-
LOG.isDebug = LOG._debug;
|
|
53
|
-
LOG.isTTY = process.stdout.isTTY;
|
|
54
|
-
const resolveBinding = require('../lib/bind/bindingResolver').resolver(LOG);
|
|
49
|
+
|
|
50
|
+
const BindingResolver = require('../lib/bind/bindingResolver')
|
|
55
51
|
|
|
56
52
|
const { highlight, bold, info } = require('../lib/util/term');
|
|
57
53
|
|
|
58
|
-
const
|
|
59
|
-
const { determineKinds, getRequiresNameFromKind, execAndExit, checkIsJavaProject, throwError, platformText, bindingText } = require('../lib/bind/bindingUtil');
|
|
54
|
+
const { determineKinds, getRequiresNameFromKind, execAndExit, checkIsJavaProject, platformText, bindingText, logger } = require('../lib/bind/bindingUtil');
|
|
60
55
|
|
|
61
|
-
async function cds_bind(args, options
|
|
56
|
+
async function cds_bind(args, options) {
|
|
62
57
|
|
|
63
58
|
options.profile = parseProfile(options.profile);
|
|
64
59
|
setProfile(options.profile);
|
|
@@ -89,8 +84,6 @@ async function cds_bind(args, options, logger = LOG) {
|
|
|
89
84
|
throw new Error(`The option '--kind' cannot be specified together with multiple targets ('--to') services. Use one service per call or omit the '--kind' option.`);
|
|
90
85
|
}
|
|
91
86
|
|
|
92
|
-
const spinner = new Spinner();
|
|
93
|
-
|
|
94
87
|
let on;
|
|
95
88
|
if (options.on === 'k8s' || options.on === 'kubernetes') {
|
|
96
89
|
on = 'k8s';
|
|
@@ -101,9 +94,11 @@ async function cds_bind(args, options, logger = LOG) {
|
|
|
101
94
|
}
|
|
102
95
|
|
|
103
96
|
const onText = { 'cf': 'Cloud Foundry', 'k8s': 'Kubernetes' }[on];
|
|
104
|
-
|
|
105
|
-
|
|
97
|
+
logger.log(`Retrieving data from ${onText}...`);
|
|
98
|
+
let resolvedServices
|
|
106
99
|
|
|
100
|
+
try {
|
|
101
|
+
resolvedServices = await Promise.all(targets.map(async target => {
|
|
107
102
|
let binding;
|
|
108
103
|
if (on === 'k8s') {
|
|
109
104
|
binding = { type: on, name: target };
|
|
@@ -111,21 +106,28 @@ async function cds_bind(args, options, logger = LOG) {
|
|
|
111
106
|
const [instance, key] = target.split(/:/);
|
|
112
107
|
binding = { type: on, instance, key };
|
|
113
108
|
} else {
|
|
114
|
-
|
|
109
|
+
throw new Error('Internal Error');
|
|
115
110
|
}
|
|
116
|
-
|
|
117
|
-
const resolvedService = await resolveBinding(undefined, binding);
|
|
111
|
+
const resolvedService = await BindingResolver.resolveBinding(undefined, binding);
|
|
118
112
|
resolvedService._target = target;
|
|
119
113
|
delete resolvedService.credentials;
|
|
120
114
|
resolvedService.binding.resolved = false;
|
|
121
115
|
return resolvedService;
|
|
122
116
|
}));
|
|
123
|
-
})
|
|
117
|
+
} catch (error) {
|
|
118
|
+
if (error.name === 'AxiosError') {
|
|
119
|
+
const errors = error.response?.data?.errors ?? []
|
|
120
|
+
const responseInfo = errors.map(e => `${e.title}: ${e.detail} (${e.code})`).join(' \n')
|
|
121
|
+
const requestInfo = error.request?.path
|
|
122
|
+
throw new Error(`${error.toString()}\nResponse: ${responseInfo}\nRequest:${requestInfo}}`)
|
|
123
|
+
}
|
|
124
|
+
throw error
|
|
125
|
+
}
|
|
124
126
|
|
|
125
127
|
if (options.kind) {
|
|
126
128
|
resolvedServices.forEach(service => service.kind = options.kind);
|
|
127
129
|
} else {
|
|
128
|
-
determineKinds(resolvedServices
|
|
130
|
+
determineKinds(resolvedServices);
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
for (const resolvedService of resolvedServices) {
|
|
@@ -135,37 +137,31 @@ async function cds_bind(args, options, logger = LOG) {
|
|
|
135
137
|
resolvedService.name = getRequiresNameFromKind(resolvedService.binding.instance, resolvedService.kind);
|
|
136
138
|
}
|
|
137
139
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
let { kind, name, binding } = resolvedService;
|
|
141
|
+
name = name ?? `custom-service:${binding.instance || binding.secret}`
|
|
142
|
+
resolvedService.name = resolvedService.name ?? name
|
|
143
|
+
const kindText = kind ? ` with kind ${highlight(kind)}` : ''
|
|
144
|
+
const nameText = highlight(name)
|
|
141
145
|
|
|
142
|
-
logger.
|
|
143
|
-
|
|
144
|
-
if (!resolvedService.name) {
|
|
145
|
-
const { binding } = resolvedService;
|
|
146
|
-
// Generate a custom service entry for Java projects w/o the need to specify a name manually
|
|
147
|
-
resolvedService.name = `custom-service:${binding.instance || binding.secret}`
|
|
148
|
-
}
|
|
146
|
+
logger.log(`Binding ${nameText} to ${platformText(binding)} ${bindingText(binding, highlight)}${kindText}`);
|
|
149
147
|
}
|
|
150
148
|
|
|
151
149
|
// prepare for different providers
|
|
152
150
|
const userCdsrcJsonStorageProvider = require('../lib/bind/userCdsrcJsonStorageProvider');
|
|
153
151
|
|
|
154
152
|
await userCdsrcJsonStorageProvider.storeServices(resolvedServices, {
|
|
155
|
-
...options
|
|
156
|
-
logger
|
|
153
|
+
...options
|
|
157
154
|
});
|
|
158
155
|
|
|
159
|
-
logger.info();
|
|
160
|
-
logger.info(`${info('TIP:')} Run with cloud bindings: ${bold(runCmd(options, isJavaProject))}`);
|
|
156
|
+
logger.log(`${info('TIP:')} Run with cloud bindings: ${bold(runCmd(options, isJavaProject))}`);
|
|
161
157
|
}
|
|
162
158
|
|
|
163
159
|
async function cds_bind_exec(command) { // eslint-disable-lint
|
|
164
160
|
const cds = require('../lib/cds');
|
|
165
161
|
const env = cds.env.for('cds', process.cwd());
|
|
166
162
|
|
|
167
|
-
const BindingManager = require('../lib/bind/
|
|
168
|
-
const bindingManager = new BindingManager({ env
|
|
163
|
+
const BindingManager = require('../lib/bind/bindingManager')
|
|
164
|
+
const bindingManager = new BindingManager({ env })
|
|
169
165
|
const bindingEnv = await bindingManager.bindingEnv()
|
|
170
166
|
const processEnv = Object.assign(process.env, bindingEnv)
|
|
171
167
|
|
package/bin/cds.js
CHANGED
|
@@ -37,7 +37,7 @@ const cli = { //NOSONAR
|
|
|
37
37
|
|
|
38
38
|
const task = this.load (cmd, /*else*/ (f)=> argv.unshift(cmd) && _defaultCompile (argv,f))
|
|
39
39
|
if (task) {
|
|
40
|
-
// REVISIT: '--' handling for cds bind --exec. Should be moved to cds_cli
|
|
40
|
+
// REVISIT bind: '--' handling for cds bind --exec. Should be moved to cds_cli
|
|
41
41
|
const endOfOptions = argv.indexOf('--')
|
|
42
42
|
let appendArgs = []
|
|
43
43
|
if (endOfOptions>=0) {
|
|
@@ -46,7 +46,9 @@ const cli = { //NOSONAR
|
|
|
46
46
|
}
|
|
47
47
|
const args = cds_cli.args(task,argv)
|
|
48
48
|
args[0].push(...appendArgs)
|
|
49
|
-
|
|
49
|
+
const resolveBindings = cmd in { run: 1, serve: 1, migrate: 1 } && argv.includes('--resolve-bindings')
|
|
50
|
+
if (resolveBindings) return _resolveBindings().then(() => task.apply(this, args))
|
|
51
|
+
else return task.apply(this, args)
|
|
50
52
|
}
|
|
51
53
|
},
|
|
52
54
|
|
|
@@ -62,7 +64,16 @@ const cli = { //NOSONAR
|
|
|
62
64
|
help (cmd) { return this.exec ('help', cmd) }
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
const DEBUG = /\b(cli)\b/.test
|
|
67
|
+
const DEBUG = /\b(y|all|cli)\b/.test(process.env.DEBUG) && console.debug
|
|
68
|
+
|
|
69
|
+
async function _resolveBindings() {
|
|
70
|
+
const cds = require('../lib/cds')
|
|
71
|
+
const BindingManager = require('../lib/bind/bindingManager')
|
|
72
|
+
const bindingManager = new BindingManager()
|
|
73
|
+
const bindingEnv = await bindingManager.bindingEnv()
|
|
74
|
+
Object.assign(process.env, bindingEnv)
|
|
75
|
+
cds.env = cds.env.for('cds') // reload env
|
|
76
|
+
}
|
|
66
77
|
|
|
67
78
|
function _local (id, _else) {
|
|
68
79
|
try { return require.resolve (id, {paths:[process.cwd(), __dirname]}) }
|
package/bin/deploy/index.js
CHANGED
|
@@ -110,16 +110,17 @@ async function deploy (_model, options) { // NOSONAR
|
|
|
110
110
|
async function update_package_json (kind, model, database) {
|
|
111
111
|
const { fs, path, isfile } = cds.utils
|
|
112
112
|
const { readFile, writeFile } = fs.promises
|
|
113
|
-
const package_json = path.resolve ('package.json'), exists = isfile (package_json)
|
|
113
|
+
const package_json = path.resolve (cds.root, 'package.json'), exists = isfile (package_json)
|
|
114
114
|
const conf = exists ? JSON.parse (await readFile (package_json)) : {}
|
|
115
|
-
|
|
116
|
-
const
|
|
115
|
+
conf.cds?.requires || (conf.cds = {requires: {}})
|
|
116
|
+
const requires = conf.cds.requires
|
|
117
|
+
const { schema_evolution } = requires.db ?? {}
|
|
117
118
|
requires.db = cds.env.requires.db = { kind, model }
|
|
118
119
|
if (database) requires.db.credentials = { database }
|
|
119
120
|
else if (kind === 'sqlite') requires.db.credentials = { database:'db.sqlite' }
|
|
120
121
|
if (schema_evolution) requires.db.schema_evolution = schema_evolution
|
|
121
|
-
await writeFile (package_json, JSON.stringify(conf,null,
|
|
122
|
-
console.log (`/> ${ exists ? 'updated' : 'created' }
|
|
122
|
+
await writeFile (package_json, JSON.stringify(conf,null,2))
|
|
123
|
+
console.log (`/> ${ exists ? 'updated' : 'created' } .${path.sep}package_json`)
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
/* eslint no-console: off */
|
package/bin/deploy/to-sqlite.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
exports.deploy = function deploy_to_sqlite (_model, _db, options) {
|
|
2
2
|
|
|
3
|
-
if (options.dialect === 'postgres' && !options.dry) console.error('\nDeploying
|
|
3
|
+
if (options.dialect === 'postgres' && !options.dry) console.error('\nDeploying into a PostgreSQL database is not yet supported\n')
|
|
4
|
+
if (options.dialect === 'h2' && !options.dry) console.error('\nDeploying into a H2 database is not yet supported\n')
|
|
4
5
|
|
|
5
6
|
const cds = require('../../lib/cds')
|
|
6
7
|
const conf = cds.env.requires.db ?? {}
|
package/bin/env.js
CHANGED
|
@@ -53,8 +53,8 @@ async function env ([cmd, key, value], options={}) {
|
|
|
53
53
|
let env = options.for ? cds.env.for(options.for) : cds.env
|
|
54
54
|
|
|
55
55
|
if (options["resolve-bindings"]) {
|
|
56
|
-
const BindingManager = require('../lib/bind/
|
|
57
|
-
const bindingManager = new BindingManager({env,
|
|
56
|
+
const BindingManager = require('../lib/bind/bindingManager')
|
|
57
|
+
const bindingManager = new BindingManager({ env, silent: true })
|
|
58
58
|
const bindingEnv = await bindingManager.bindingEnv()
|
|
59
59
|
Object.assign(process.env, bindingEnv)
|
|
60
60
|
env = cds.env.for(options.for || 'cds') // reload env
|
|
@@ -97,14 +97,14 @@ const commands = {
|
|
|
97
97
|
if (!process.stdout.isTTY) return commands.json (conf, key, val)
|
|
98
98
|
// tty: display formatted object
|
|
99
99
|
const obj = (key ? conf.get(key) : conf)
|
|
100
|
-
console.log (inspect (obj, {depth:22,colors:true}).replace(/\s+use:.*\[Getter\]
|
|
100
|
+
console.log (inspect (obj, {depth:22,colors:true}).replace(/\s+use:.*\[Getter\][^,]+,?/g,''))
|
|
101
101
|
},
|
|
102
102
|
|
|
103
103
|
// eslint-disable-next-line no-unused-vars
|
|
104
104
|
json (conf, key, val) {
|
|
105
105
|
const obj = (key ? conf.get(key) : conf)
|
|
106
106
|
const str = JSON.stringify(obj, null, 2)
|
|
107
|
-
return console.log (str ? str.replace(/\s+use:.*\[Getter\]
|
|
107
|
+
return console.log (str ? str.replace(/\s+use:.*\[Getter\][^,]+,?/g,'') : str)
|
|
108
108
|
},
|
|
109
109
|
|
|
110
110
|
set () {
|
package/bin/migrate.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module.exports = Object.assign(migrate, {
|
|
2
|
-
options: ['--directory'],
|
|
2
|
+
options: ['--directory', '--tag', '--tagRule'],
|
|
3
3
|
shortcuts: ['-d'],
|
|
4
|
-
flags: ['--dry'],
|
|
4
|
+
flags: ['--dry', '--force', '--cleanup', '--resolve-bindings'],
|
|
5
5
|
help: `
|
|
6
6
|
# SYNOPSIS
|
|
7
7
|
|
|
8
|
-
*cds migrate* <tenant1|"*">[,<tenant2>] -d <directory> --dry
|
|
8
|
+
*cds migrate* <tenant1|"*">[,<tenant2>] [-d <directory>] [--tag <tag>] [--tagRule <tag rule>] [--dry] [--force]
|
|
9
9
|
|
|
10
10
|
Migrate extensions created with @sap/cds-mtx to extensions for @sap/cds-mtxs
|
|
11
11
|
|
|
@@ -17,10 +17,30 @@ module.exports = Object.assign(migrate, {
|
|
|
17
17
|
|
|
18
18
|
Specify the target directory of your migrated extension projects. By default, the migrated extension projects will not be stored.
|
|
19
19
|
|
|
20
|
+
*--tag* <tag>
|
|
21
|
+
|
|
22
|
+
Specify a default tag that is to be used to store the extension. If not specified "migrated" will be used.
|
|
23
|
+
|
|
24
|
+
*--tagRule* <tag rule>
|
|
25
|
+
|
|
26
|
+
Specify a regular expression that describes the mapping from file names to tags, e. g. "extension-(.*)\.cds" to map from "extension-123.cds" to tag "123". If the expression does not match, the default tag will be used.
|
|
27
|
+
|
|
28
|
+
*--force*
|
|
29
|
+
|
|
30
|
+
Force the re-migration of already migrated tenants.
|
|
31
|
+
|
|
20
32
|
*--dry*
|
|
21
33
|
|
|
22
34
|
Do a dry-run only. Only run a verification of the extension migration.
|
|
23
35
|
|
|
36
|
+
*--cleanup* (beta)
|
|
37
|
+
|
|
38
|
+
Removes all metadata containers created by @sap/cds-mtx.
|
|
39
|
+
|
|
40
|
+
*--resolve-bindings* (beta)
|
|
41
|
+
|
|
42
|
+
Resolve remote service bindings configured via *cds bind*.
|
|
43
|
+
|
|
24
44
|
# SEE ALSO
|
|
25
45
|
`})
|
|
26
46
|
|
|
@@ -30,4 +50,5 @@ async function migrate (param, options = {}) {
|
|
|
30
50
|
await require('@sap/cds-mtxs/bin/cds-mtx-migrate').run(param[0], options)
|
|
31
51
|
}
|
|
32
52
|
|
|
33
|
-
/* eslint no-console: off */
|
|
53
|
+
/* eslint no-console: off */
|
|
54
|
+
/* eslint no-useless-escape: off */
|
package/bin/push.js
CHANGED
|
@@ -14,6 +14,10 @@ module.exports = Object.assign(push, {
|
|
|
14
14
|
A download URL may contain Basic-Auth credentials as in 'https://user:pass@host'.
|
|
15
15
|
|
|
16
16
|
By default, the current working directory is used as project directory.
|
|
17
|
+
|
|
18
|
+
Unless a custom archive is given, the extension project will be automatically built
|
|
19
|
+
in order to update the generated extension archive. This ensures the most recent
|
|
20
|
+
extension model is pushed.
|
|
17
21
|
|
|
18
22
|
Any authentication data will not be saved.
|
|
19
23
|
|
package/bin/watch.js
CHANGED
|
@@ -43,7 +43,7 @@ module.exports = Object.assign ( watch, {
|
|
|
43
43
|
|
|
44
44
|
`})
|
|
45
45
|
|
|
46
|
-
const DEBUG = /\
|
|
46
|
+
const DEBUG = /\b(y|all|cli|watch)\b/.test(process.env.DEBUG) && console.debug
|
|
47
47
|
const {delimiter,dirname,relative,resolve,sep} = require ('path')
|
|
48
48
|
const fs = require ('fs')
|
|
49
49
|
|
|
@@ -91,7 +91,7 @@ async function watch ([cwd], {
|
|
|
91
91
|
ext += ',css,gif,html,jpg,png,svg'
|
|
92
92
|
includes = fioriIncludes
|
|
93
93
|
liveReload = new (require ('../lib/watch/livereload-server'))
|
|
94
|
-
env.CDS_LIVERELOAD_PATH = require.resolve ('connect
|
|
94
|
+
env.CDS_LIVERELOAD_PATH = require.resolve ('../lib/watch/livereload-connect')
|
|
95
95
|
env.CDS_LIVERELOAD_URL = await liveReload.start (options['livereload'])
|
|
96
96
|
.catch(err => { console.log(`Error starting live reload: ${err.message}`); liveReload = null })
|
|
97
97
|
} else {
|
|
@@ -113,7 +113,7 @@ async function watch ([cwd], {
|
|
|
113
113
|
DEBUG && log (`also watching: ${includes.source}`)
|
|
114
114
|
if (liveReload) log (`live reload enabled for browsers`)
|
|
115
115
|
|
|
116
|
-
const BindingManager = require('../lib/bind/
|
|
116
|
+
const BindingManager = require('../lib/bind/bindingManager')
|
|
117
117
|
const bindingManager = new BindingManager({cwd})
|
|
118
118
|
const bindingEnv = await bindingManager.bindingEnv()
|
|
119
119
|
if (bindingEnv) env = {...env, ...bindingEnv}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const yaml = require("@sap/cds-foss")("yaml");
|
|
2
|
+
const { exec } = require('../util/exec');
|
|
3
|
+
|
|
4
|
+
class KubernetesApiAccessor {
|
|
5
|
+
|
|
6
|
+
constructor() {
|
|
7
|
+
|
|
8
|
+
this.config = once( async() => {
|
|
9
|
+
const configString = await exec({result: 'stdout'}) `kubectl config view --raw`;
|
|
10
|
+
const config = yaml.parse(configString);
|
|
11
|
+
|
|
12
|
+
const currentContextName = config["current-context"];
|
|
13
|
+
if (!currentContextName) throw new Error(`No current context in kubectl config.`);
|
|
14
|
+
const currentContextEntry = config.contexts && config.contexts.find( entry => entry.name === currentContextName && entry.context && entry.context.cluster && entry.context.user );
|
|
15
|
+
if (!currentContextEntry) throw new Error(`Current context not found in kubectl config.`);
|
|
16
|
+
const currentContext = currentContextEntry.context;
|
|
17
|
+
const clusterEntry = config.clusters && config.clusters.find( entry => entry.name === currentContext.cluster && entry.cluster && entry.cluster.server );
|
|
18
|
+
if (!currentContextEntry) throw new Error(`Cluster ${currentContext.cluster} not found in kubectl config.`);
|
|
19
|
+
const { cluster } = clusterEntry;
|
|
20
|
+
|
|
21
|
+
const serverToContext = {};
|
|
22
|
+
for (const clusterEntry of config.clusters) {
|
|
23
|
+
const contextEntries = config.contexts.filter( contextEntry => contextEntry.context.cluster === clusterEntry.name );
|
|
24
|
+
// Collect only cluster servers that are used in exactly one context, to clearly identify the context to be used
|
|
25
|
+
if (contextEntries.length === 1) {
|
|
26
|
+
serverToContext[clusterEntry.cluster.server] = contextEntries[0];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
namespace: currentContext.namespace || 'default',
|
|
32
|
+
context: currentContextEntry,
|
|
33
|
+
cluster,
|
|
34
|
+
serverToContext
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async context({cluster, namespace}) {
|
|
40
|
+
const config = await this.config();
|
|
41
|
+
let contextEntry;
|
|
42
|
+
|
|
43
|
+
if (cluster && cluster !== config.cluster.server) {
|
|
44
|
+
contextEntry = config.serverToContext[cluster] || throwError(`Cluster ${cluster} not found in kubectl configuration`);
|
|
45
|
+
} else {
|
|
46
|
+
contextEntry = config.context;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
context: contextEntry.name,
|
|
51
|
+
cluster: cluster || config.cluster.server,
|
|
52
|
+
namespace: namespace || contextEntry.context.namespace || 'default'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async get(options) {
|
|
57
|
+
const {context, namespace, kind, name} = options;
|
|
58
|
+
|
|
59
|
+
const result = await exec({stdio: ['ignore', 'pipe', 'ignore'], acceptStatuses: [0, 1]}) `kubectl --output json --context ${context} --namespace ${namespace} get ${kind} ${name}`;
|
|
60
|
+
if (result.status === 0)
|
|
61
|
+
return JSON.parse(result.stdout);
|
|
62
|
+
else
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function once(func) {
|
|
68
|
+
let result;
|
|
69
|
+
return function(...args) {
|
|
70
|
+
if (!result) result = func(...args);
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function throwError(msg = 'Internal Error') {
|
|
76
|
+
throw new Error(msg);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = KubernetesApiAccessor;
|
|
@@ -1,32 +1,33 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
1
|
+
const bindingResolver = require('./bindingResolver')
|
|
2
|
+
const { logger } = require('./bindingUtil')
|
|
3
|
+
const DEBUG = /\b(all|cli)\b/.test(process.env.DEBUG)
|
|
4
4
|
|
|
5
5
|
class BindingManager {
|
|
6
|
-
constructor(options) {
|
|
6
|
+
constructor(options = {}) {
|
|
7
7
|
this.cache = {}
|
|
8
8
|
this.bindingsStr = ''
|
|
9
9
|
this.options = options
|
|
10
|
+
logger.log = DEBUG || !options.silent ? console.log : () => { }
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
getBindings() {
|
|
13
|
-
const bindings = getUnresolvedBindings(this.options)
|
|
14
|
+
const bindings = bindingResolver.getUnresolvedBindings(this.options)
|
|
14
15
|
return bindings
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
async resolve(bindings) {
|
|
18
19
|
if (!bindings) {
|
|
19
|
-
bindings = this.getBindings(
|
|
20
|
+
bindings = this.getBindings()
|
|
20
21
|
this.bindingsStr = JSON.stringify(bindings)
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
return await resolveBindings({...this.options, bindings, cache: this.cache})
|
|
24
|
+
return await bindingResolver.resolveBindings({ ...this.options, bindings, cache: this.cache })
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
async bindingEnv(bindings) {
|
|
27
28
|
if (!bindings) bindings = await this.resolve()
|
|
28
29
|
if (bindings) {
|
|
29
|
-
const VCAP_SERVICES = JSON.stringify(
|
|
30
|
+
const VCAP_SERVICES = JSON.stringify(BindingManager.toVcapServices(bindings))
|
|
30
31
|
return { VCAP_SERVICES }
|
|
31
32
|
} else {
|
|
32
33
|
return undefined
|
|
@@ -44,7 +45,7 @@ class BindingManager {
|
|
|
44
45
|
|
|
45
46
|
try {
|
|
46
47
|
if (this.pendingUpdate) await this.pendingUpdate
|
|
47
|
-
} catch(error) {
|
|
48
|
+
} catch (error) {
|
|
48
49
|
// ignore
|
|
49
50
|
}
|
|
50
51
|
this.pendingUpdate = undefined
|
|
@@ -55,18 +56,18 @@ class BindingManager {
|
|
|
55
56
|
try {
|
|
56
57
|
this.pendingUpdate = this.resolve(bindings)
|
|
57
58
|
resolvedBindings = await this.pendingUpdate
|
|
58
|
-
} catch(error) {
|
|
59
|
-
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error(error.message)
|
|
60
61
|
return
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
if (this.bindingsStr !== bindingsStr) return // Next update in progress
|
|
64
65
|
|
|
65
66
|
const env = Object.assign({ VCAP_SERVICES: '{}' }, await this.bindingEnv(resolvedBindings));
|
|
66
|
-
if (onAfterUpdate) onAfterUpdate({bindings: resolvedBindings, env})
|
|
67
|
+
if (onAfterUpdate) onAfterUpdate({ bindings: resolvedBindings, env })
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
toVcapServices(bindings) {
|
|
70
|
+
static toVcapServices(bindings) {
|
|
70
71
|
const services = {}
|
|
71
72
|
|
|
72
73
|
for (const name in bindings) {
|
|
@@ -77,11 +78,11 @@ class BindingManager {
|
|
|
77
78
|
|
|
78
79
|
// setting the 'name' property is important to make CAP match the CDS service to the VCAP service
|
|
79
80
|
// it is also added to the 'vcap' property by 'cds bind'
|
|
80
|
-
serviceEntries.push({ ...vcap, name, credentials: binding.credentials})
|
|
81
|
+
serviceEntries.push({ ...vcap, name, credentials: binding.credentials })
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
return services
|
|
84
|
-
|
|
85
|
+
}
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
module.exports = BindingManager
|
|
@@ -1,78 +1,51 @@
|
|
|
1
|
-
const cds = require('../cds')
|
|
2
|
-
const
|
|
3
|
-
const resolveBinding = resolver(LOG);
|
|
4
|
-
const { platformText, bindingText } = require('./bindingUtil');
|
|
1
|
+
const cds = require('../cds');
|
|
2
|
+
const { platformText, bindingText, logger } = require('./bindingUtil');
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const bindings = {}
|
|
11
|
-
const requires = env.requires || {}
|
|
12
|
-
for (const name in requires) {
|
|
13
|
-
const service = requires[name]
|
|
14
|
-
if (service && service.binding && !service.binding.resolved) {
|
|
15
|
-
bindings[name] = {...service.binding, kind: service.kind }
|
|
4
|
+
class BindingResolver {
|
|
5
|
+
getUnresolvedBindings({ cwd = process.cwd(), env } = {}) {
|
|
6
|
+
if (!env) {
|
|
7
|
+
env = cds.env.for('cds', cwd)
|
|
16
8
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (Object.keys(bindings).length===0) return undefined
|
|
25
|
-
LOG[output](`resolving cloud service bindings...`)
|
|
26
|
-
|
|
27
|
-
const resolvedBindings = {}
|
|
28
|
-
|
|
29
|
-
await Promise.all( Object.keys(bindings).map( async name => {
|
|
30
|
-
const binding = bindings[name]
|
|
31
|
-
const cacheKey = JSON.stringify(binding)
|
|
32
|
-
let resolvedBinding
|
|
33
|
-
if (!cache[cacheKey]) {
|
|
34
|
-
resolvedBinding = cache[cacheKey] = await resolveBinding(name, binding)
|
|
35
|
-
LOG[output](`bound ${name} to ${platformText(binding)} ${bindingText(binding)}`)
|
|
36
|
-
} else {
|
|
37
|
-
resolvedBinding = cache[cacheKey]
|
|
9
|
+
const bindings = {}
|
|
10
|
+
const requires = env.requires || {}
|
|
11
|
+
for (const name in requires) {
|
|
12
|
+
const service = requires[name]
|
|
13
|
+
if (service && service.binding && !service.binding.resolved) {
|
|
14
|
+
bindings[name] = { ...service.binding, kind: service.kind }
|
|
15
|
+
}
|
|
38
16
|
}
|
|
17
|
+
return bindings
|
|
18
|
+
}
|
|
39
19
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
20
|
+
async resolveBindings({ bindings, cwd = process.cwd(), env, cache = {} }) {
|
|
21
|
+
bindings = bindings || this.getUnresolvedBindings({ cwd, env })
|
|
22
|
+
if (Object.keys(bindings).length === 0) return undefined
|
|
23
|
+
logger.log(`resolving cloud service bindings...`)
|
|
24
|
+
|
|
25
|
+
const resolvedBindings = {}
|
|
26
|
+
|
|
27
|
+
await Promise.all(Object.keys(bindings).map(async name => {
|
|
28
|
+
const binding = bindings[name]
|
|
29
|
+
const cacheKey = JSON.stringify(binding)
|
|
30
|
+
let resolvedBinding
|
|
31
|
+
if (!cache[cacheKey]) {
|
|
32
|
+
resolvedBinding = cache[cacheKey] = await this.resolveBinding(name, binding)
|
|
33
|
+
logger.log(`bound ${name} to ${platformText(binding)} ${bindingText(binding)}`)
|
|
34
|
+
} else {
|
|
35
|
+
resolvedBinding = cache[cacheKey]
|
|
36
|
+
}
|
|
37
|
+
resolvedBindings[name] = resolvedBinding
|
|
38
|
+
}))
|
|
39
|
+
return Object.keys(resolvedBindings).length > 0 ? resolvedBindings : undefined
|
|
40
|
+
}
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
return function resolveBinding(name, binding) {
|
|
42
|
+
resolveBinding(name, binding) {
|
|
51
43
|
switch (binding.type) {
|
|
52
|
-
case 'cf':
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
cfKeyProvider.setLogger(log);
|
|
56
|
-
}
|
|
57
|
-
return cfKeyProvider.resolve(name, binding)
|
|
58
|
-
case 'k8s':
|
|
59
|
-
if (!kubernetesCredentialsProvider) {
|
|
60
|
-
kubernetesCredentialsProvider = require('./kubernetesCredentialsProvider')
|
|
61
|
-
kubernetesCredentialsProvider.setLogger(log)
|
|
62
|
-
}
|
|
63
|
-
return kubernetesCredentialsProvider.resolve(name, binding)
|
|
64
|
-
default:
|
|
65
|
-
throw new Error(`Unsupported binding type "${binding.type}" for service "${name}".`)
|
|
44
|
+
case 'cf': return require('./cfKeyProvider').resolve(name, binding)
|
|
45
|
+
case 'k8s': return require('./kubernetesCredentialsProvider').resolve(name, binding)
|
|
46
|
+
default: throw new Error(`Unsupported binding type "${binding.type}" for service "${name}".`)
|
|
66
47
|
}
|
|
67
48
|
}
|
|
68
49
|
}
|
|
69
50
|
|
|
70
|
-
|
|
71
|
-
return env.features && env.features.dk && env.features.dk.resolveBindingsForTesting
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
module.exports = {
|
|
75
|
-
resolver,
|
|
76
|
-
resolveBindings,
|
|
77
|
-
getUnresolvedBindings
|
|
78
|
-
}
|
|
51
|
+
module.exports = new BindingResolver()
|