@sap/cds-dk 6.3.1 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -5
- package/bin/cds.js +2 -0
- package/bin/compile/index.js +2 -1
- package/bin/deploy/index.js +2 -2
- package/bin/deploy/to-sqlite.js +17 -15
- package/bin/help.js +7 -4
- package/bin/init.js +1 -1
- package/bin/login.js +3 -4
- package/bin/migrate.js +33 -0
- package/bin/pull.js +4 -4
- package/bin/push.js +1 -1
- package/bin/subscribe.js +58 -66
- package/bin/unsubscribe.js +67 -0
- package/bin/watch.js +4 -3
- package/lib/bind/bindingUtil.js +2 -0
- package/lib/bind/cfKeyProvider.js +5 -1
- package/lib/client/activate.js +3 -3
- package/lib/client/auth_manager.js +2 -2
- package/lib/client/base_command.js +7 -6
- package/lib/client/extend.js +2 -2
- package/lib/client/helper/errors.js +8 -2
- package/lib/client/helper/logging.js +13 -11
- package/lib/client/params.js +3 -0
- package/lib/client/pull.js +1 -1
- package/lib/client/push.js +4 -4
- package/lib/client/settings_manager.js +13 -6
- package/lib/client/subscription.js +81 -0
- package/lib/compile/to-xsuaa.js +25 -19
- package/lib/import/odata/metadataconverter/MetadataConverter.js +3 -3
- package/lib/import/odata/v2parser.js +37 -24
- package/lib/import/odata/v4parser.js +106 -37
- package/lib/init/constants.js +1 -1
- package/lib/init/index.js +2 -2
- package/lib/init/template/_merging/registry-mta.js +0 -3
- package/lib/init/template/approuter/files/approuter-configmap.yaml +10 -0
- package/lib/init/template/approuter/files/approuter-mtxs-configmap.yaml +15 -0
- package/lib/init/template/approuter/files/chart.yaml +4 -0
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/approuter/files/values.yaml.hbs +31 -0
- package/lib/init/template/approuter/index.js +60 -12
- package/lib/init/template/auditlog/index.js +16 -8
- package/lib/init/template/cf-manifest/index.js +3 -3
- package/lib/init/template/connectivity/index.js +19 -10
- package/lib/init/template/destinations/index.js +23 -7
- package/lib/init/template/enterprise-messaging/files/cds.package.json +1 -2
- package/lib/init/template/enterprise-messaging/files/cds.profile.package.json.hbs +1 -2
- package/lib/init/template/enterprise-messaging/files/cdsrc.json +1 -2
- package/lib/init/template/enterprise-messaging/files/cdsrc.json.hbs +1 -2
- package/lib/init/template/enterprise-messaging/files/event-mesh.json.hbs +31 -0
- package/lib/init/template/enterprise-messaging/files/mta.yaml.hbs +1 -0
- package/lib/init/template/enterprise-messaging/index.js +26 -13
- package/lib/init/template/extensibility/index.js +19 -10
- package/lib/init/template/hana/files/mta.yaml.hbs +0 -4
- package/lib/init/template/hana/index.js +58 -22
- package/lib/init/template/helm/chart/templates/NOTES.txt +4 -3
- package/lib/init/template/helm/chart/templates/_deployment_helpers.tpl +25 -2
- package/lib/init/template/helm/chart/values.root.schema.json +5 -0
- package/lib/init/template/helm/chart/values.schema.json +27 -0
- package/lib/init/template/helm/files/values.yaml.hbs +1 -1
- package/lib/init/template/helm/index.js +25 -23
- package/lib/init/template/helm/subchart/templates/_helpers.tpl +29 -0
- package/lib/init/template/helm/subchart/templates/api-rule.yaml +5 -5
- package/lib/init/template/helm/subchart/templates/deployment.yaml +12 -9
- package/lib/init/template/helm/subchart/values.md +258 -88
- package/lib/init/template/helm/subchart/values.schema.json +96 -13
- package/lib/init/template/helm/subchart/values.yaml +6 -2
- package/lib/init/template/html5-repo/index.js +28 -11
- package/lib/init/template/java/index.js +5 -5
- package/lib/init/template/kibana-logging/index.js +5 -4
- package/lib/init/template/mta/index.js +2 -2
- package/lib/init/template/mtx/index.js +1 -1
- package/lib/init/template/multitenancy/files/chart.yaml +4 -0
- package/lib/init/template/multitenancy/files/java/mtxs-configmap.yaml +20 -0
- package/lib/init/template/multitenancy/files/java/package.json +6 -9
- package/lib/init/template/multitenancy/files/mtxs-configmap.yaml +15 -0
- package/lib/init/template/multitenancy/files/saas-registry.yaml +17 -19
- package/lib/init/template/multitenancy/files/values.yaml.hbs +47 -0
- package/lib/init/template/multitenancy/files/xs-security.json.hbs +0 -7
- package/lib/init/template/multitenancy/index.js +83 -37
- package/lib/init/template/nodejs/files/.eslintrc +26 -0
- package/lib/init/template/nodejs/files/package.json.hbs +0 -28
- package/lib/init/template/nodejs/index.js +7 -10
- package/lib/init/template/pipeline/index.js +4 -4
- package/lib/init/template/samples/index.js +5 -5
- package/lib/init/template/templateBase.js +1 -4
- package/lib/init/template/toggles/index.js +5 -5
- package/lib/init/template/xsuaa/files/values.yaml.hbs +21 -0
- package/lib/init/template/xsuaa/index.js +34 -24
- package/lib/init/util/md5Tracking.js +113 -0
- package/lib/init/util/merge.js +19 -2
- package/lib/init/util/projectReader.js +15 -12
- package/npm-shrinkwrap.json +70 -572
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,41 @@ 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.4.0 - 2022-12-15
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `cds add helm` now supports approuter.
|
|
15
|
+
- `cds subscribe --local` starts @sap/cds-mtxs locally instead of contacting a running instance via URL.
|
|
16
|
+
- `cds unsubscribe` removes the subscription of a tenant from a SaaS app.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- `cds add multitenancy` will not compile internal roles into the `xs-security.json` any more.
|
|
21
|
+
- `cds add hana` does not create a `hdi-service-name: ${service-name}` for the database resource properties any more.
|
|
22
|
+
- MTX-related commands now print usage help in case of known errors.
|
|
23
|
+
- `cds import` now adds the annotation `@open` for all the Entities and ComplexTypes with attribute `Abstract` or `OpenType` and adds the same for those referred by the attribute `BaseType`.
|
|
24
|
+
- `cds import` now adds default value in the CSN for the optional parameters in action/function for OData V4 files.
|
|
25
|
+
- `cds init` uses latest Maven Java archetype version 1.30.0 for creating Java projects.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- `cds init` no longer creates `engines` entry in package.json to avoid `unsupported engine` warnings.
|
|
30
|
+
- `cds subscribe` correctly exits the process after deploying to a HANA database.
|
|
31
|
+
- `cds add multitenancy` doesn't create a duplicate `saas-registry` resource if there's one with `service-plan: service` any more.
|
|
32
|
+
- `cds bind` now correctly maps the `hana-mt` and `sql-mt` shortcuts to the `cds.requires.db` entry.
|
|
33
|
+
- `cds add mtx` no longer fails if the `mtx/sidecar` folder doesn't exist.
|
|
34
|
+
- `cds compile --to xsuaa` now rejects expressions leading to invalid XSUAA attributes like `$user.foo-bar`, `$user.foo/bar`, `$user.foo.bar`
|
|
35
|
+
- `cds compile --to xsuaa -o <file>` now sets `.json` as file ending instead of `.xsuaa`
|
|
36
|
+
|
|
37
|
+
## Version 6.3.2 - 2022-11-28
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Include `@sap/cds` 6.3.2
|
|
42
|
+
- Include `@sap/cds-compiler` 3.4.4
|
|
43
|
+
- Include `@sap/cds-mtxs` 1.3.2
|
|
44
|
+
|
|
10
45
|
## Version 6.3.1 - 2022-11-04
|
|
11
46
|
|
|
12
47
|
### Changed
|
|
@@ -15,10 +50,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
|
15
50
|
- Use `@sap/cds` 6.3.1
|
|
16
51
|
- Use `@sap/cds-mtxs` 1.3.1
|
|
17
52
|
|
|
18
|
-
### Fixed
|
|
19
|
-
|
|
20
|
-
- MTX Client no longer reports 'Request failed with status code 401' when sending a passcode to old MTX server.
|
|
21
|
-
|
|
22
53
|
## Version 6.3.0 - 2022-11-02
|
|
23
54
|
|
|
24
55
|
### Added
|
|
@@ -37,7 +68,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
|
37
68
|
|
|
38
69
|
- MTX Client now ignores a username potentially saved for the current project, if a passcode is given
|
|
39
70
|
- MTX Client now treats keytar as optional unless explicitly running `cds login`
|
|
40
|
-
- `cds import` now
|
|
71
|
+
- `cds import` now captures the documentation properly for all the EntitySet referring to same EntityType.
|
|
41
72
|
- `cds deploy --to sql` now produces 'plain' SQL again, suitable for e.g. H2. In 6.2 it produced 'sqlite' dialect, erroneously.
|
|
42
73
|
- `cds compile --to openapi` now fixes the duplication of fields in `required` section.
|
|
43
74
|
- `cds lint` now recognizes ESLint configurations from _package.json_.
|
|
@@ -247,6 +278,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
|
247
278
|
|
|
248
279
|
### Fixed
|
|
249
280
|
|
|
281
|
+
- `cds add html5-repo` and `cds add destinations` throw an error if applied for MTA deployments, for which they are currently unsupported.
|
|
250
282
|
- `cds compile --to openapi` fixes annotations on bound action overloads.
|
|
251
283
|
- `cds add cf-manifest` now uses the correct `application` plan for the `xsuaa` service
|
|
252
284
|
- A combination of `cds add approuter`, `cds add mtx`, and `cds add mta` will now use a safer approach to determine the subscription URL.
|
package/bin/cds.js
CHANGED
|
@@ -94,7 +94,9 @@ function _dieForUnknownCommand(cmd) {
|
|
|
94
94
|
|
|
95
95
|
const excludeList = ['cds.js', 'cds-ts.js', 'fix-redirects.js'];
|
|
96
96
|
const { readdirSync } = require('fs');
|
|
97
|
+
const { resolve } = require('path');
|
|
97
98
|
const commands = readdirSync(__dirname, { withFileTypes: true })
|
|
99
|
+
.concat(readdirSync(resolve(_local('@sap/cds'), '..', '..', 'bin'), { withFileTypes: true }))
|
|
98
100
|
.filter((f) => f.isFile() && !excludeList.includes(f.name))
|
|
99
101
|
.map((f) => f.name.split('.')[0]).sort();
|
|
100
102
|
|
package/bin/compile/index.js
CHANGED
package/bin/deploy/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module.exports = Object.assign(deploy, {
|
|
2
2
|
options: ['--to', '--tunnel-address', '--vcap-file'],
|
|
3
|
-
flags: [ '--no-save', '--auto-undeploy', '--dry', '--with-mocks', '--store-credentials', '--bind' ],
|
|
3
|
+
flags: [ '--no-save', '--auto-undeploy', '--dry', '--xdry', '--with-mocks', '--store-credentials', '--bind' ],
|
|
4
4
|
shortcuts: ['-2'],
|
|
5
5
|
help: `
|
|
6
6
|
# SYNOPSIS
|
|
@@ -79,7 +79,7 @@ async function deploy (_model, options) { // NOSONAR
|
|
|
79
79
|
|
|
80
80
|
cds deploy --to sql
|
|
81
81
|
cds deploy --to sqlite
|
|
82
|
-
cds deploy --to sqlite:db/my.
|
|
82
|
+
cds deploy --to sqlite:db/my-db.sqlite
|
|
83
83
|
`)
|
|
84
84
|
|
|
85
85
|
const conf = cds.env.requires.db || {}
|
package/bin/deploy/to-sqlite.js
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
exports.deploy = function deploy_to_sqlite (_model, _db, options) {
|
|
2
|
-
const cds = require('../../lib/cds')
|
|
3
|
-
const {to:_dbrl} = options
|
|
4
|
-
const conf = cds.env.requires.db || {}
|
|
5
|
-
const fts = cds.env.features.folders
|
|
6
|
-
const model = _model || conf.model || cds.resolve(!fts ? '*' : ['*',fts], false)
|
|
7
|
-
const file = _database4 (_db, _dbrl, conf)
|
|
8
2
|
|
|
9
|
-
// current 'sqlite' default is bad, as we want to default to 'plain', so ignore it
|
|
10
|
-
const env_dialect = cds.env.sql.dialect !== 'sqlite' ? cds.env.sql.dialect : 'plain'
|
|
11
|
-
const to_dialect = _dbrl && _dbrl.match(/^(\w+)/) && RegExp.$1
|
|
12
|
-
if (to_dialect) options.dialect = (to_dialect === 'sql')
|
|
13
|
-
? conf.dialect || env_dialect
|
|
14
|
-
: to_dialect
|
|
15
3
|
if (options.dialect === 'postgres' && !options.dry) console.error('\nDeploying to PostgreSQL is not yet supported\n')
|
|
16
4
|
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
const cds = require('../../lib/cds')
|
|
6
|
+
const conf = cds.env.requires.db ?? {}
|
|
7
|
+
const fts = cds.env.features.folders
|
|
8
|
+
const model = _model || conf.model || cds.resolve(!fts ? '*' : ['*',fts], false)
|
|
9
|
+
let file = 'db'
|
|
10
|
+
if (options.to) {
|
|
11
|
+
file = 'sqlite:'+ _database4 (_db, options.to, conf)
|
|
12
|
+
// current 'sqlite' default is bad, as we want to default to 'plain', so ignore it
|
|
13
|
+
const env_dialect = cds.env.sql.dialect !== 'sqlite' ? cds.env.sql.dialect : 'plain'
|
|
14
|
+
const to_dialect = options.to && options.to.match(/^(\w+)/) && RegExp.$1
|
|
15
|
+
if (to_dialect) options.dialect = (to_dialect === 'sql')
|
|
16
|
+
? conf.dialect ?? env_dialect
|
|
17
|
+
: to_dialect
|
|
18
|
+
}
|
|
19
|
+
return cds.deploy(model) .to (file, options)
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
function _database4 (_db,_dbrl,conf) {
|
|
22
23
|
if (_db) return _db
|
|
24
|
+
if (_dbrl === 'sqlite') return 'db.sqlite'
|
|
23
25
|
if (conf.credentials?.database) return conf.credentials.database
|
|
24
26
|
if (conf.credentials?.url) return conf.credentials.url
|
|
25
|
-
if (_dbrl === 'sqlite') return 'db.sqlite'
|
|
26
27
|
if (_dbrl === 'sql') return ':memory:'
|
|
28
|
+
else return conf.credentials?.database ?? conf.credentials?.url
|
|
27
29
|
}
|
package/bin/help.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
module.exports = exports = Object.assign (help, {help:`
|
|
2
|
+
module.exports = exports = Object.assign (help, {formatHelp, help:`
|
|
3
3
|
# USAGE
|
|
4
4
|
|
|
5
5
|
*cds* <command> [<args>]
|
|
@@ -39,10 +39,13 @@ module.exports = exports = Object.assign (help, {help:`
|
|
|
39
39
|
function help (topic) {
|
|
40
40
|
if (Array.isArray(topic)) topic = topic[0]
|
|
41
41
|
const task = !topic ? help : this.load && this.load (this.Shortcuts[topic] || topic)
|
|
42
|
-
if (task && task.help) console.log (task.help
|
|
42
|
+
if (task && task.help) console.log (formatHelp (task.help))
|
|
43
|
+
else throw new Error(`Didn't find a help topic for '${ topic.name || topic }'.`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function formatHelp (text) {
|
|
47
|
+
return text
|
|
43
48
|
.replace(/\n# ([^\n]*)\n/g, `\n\x1b[1m$1\x1b[0m\n`)
|
|
44
49
|
.replace(/ \*([^*]+)\*/g, ` \x1b[1m$1\x1b[0m`)
|
|
45
50
|
.replace(/ _([^_]+)_/g, ` \x1b[4m$1\x1b[0m`)
|
|
46
|
-
)
|
|
47
|
-
else throw new Error(`Didn't find a help topic for '${ topic.name || topic }'.`)
|
|
48
51
|
}
|
package/bin/init.js
CHANGED
|
@@ -29,7 +29,7 @@ module.exports = Object.assign(init, {
|
|
|
29
29
|
This feature uses the 'Java Maven archetype' to create a project
|
|
30
30
|
using the *Java* programming language.
|
|
31
31
|
|
|
32
|
-
*mtx* - prepares a
|
|
32
|
+
*mtx* - prepares a multitenant project
|
|
33
33
|
|
|
34
34
|
This version only supports Node.js projects.
|
|
35
35
|
|
package/bin/login.js
CHANGED
|
@@ -74,8 +74,6 @@ module.exports = Object.assign(login, {
|
|
|
74
74
|
*-u* | *--user* <name>[:[<password>]]
|
|
75
75
|
|
|
76
76
|
Username and optionally password for authentication with Basic Auth in test scenarios.
|
|
77
|
-
See https://cap.cloud.sap/docs/guides/multitenancy/#send-subscribe-events for information
|
|
78
|
-
on suitable mock users.
|
|
79
77
|
|
|
80
78
|
When typing the colon but omitting <password>, the password is assumed empty.
|
|
81
79
|
When omitting both, password will be queried interactively.
|
|
@@ -117,8 +115,9 @@ module.exports = Object.assign(login, {
|
|
|
117
115
|
# SEE ALSO
|
|
118
116
|
|
|
119
117
|
*cds logout* to remove any authentication data
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
https://cap.cloud.sap/docs/guides/extensibility/customization?q=mock#mock-users for information on suitable mock users.
|
|
119
|
+
|
|
120
|
+
`}});
|
|
122
121
|
|
|
123
122
|
|
|
124
123
|
async function login ([url], options = {}) {
|
package/bin/migrate.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module.exports = Object.assign(migrate, {
|
|
2
|
+
options: ['--directory'],
|
|
3
|
+
shortcuts: ['-d'],
|
|
4
|
+
flags: ['--dry'],
|
|
5
|
+
help: `
|
|
6
|
+
# SYNOPSIS
|
|
7
|
+
|
|
8
|
+
*cds migrate* <tenant1|"*">[,<tenant2>] -d <directory> --dry
|
|
9
|
+
|
|
10
|
+
Migrate extensions created with @sap/cds-mtx to extensions for @sap/cds-mtxs
|
|
11
|
+
|
|
12
|
+
This command only runs on the root directory of an application.
|
|
13
|
+
|
|
14
|
+
# OPTIONS
|
|
15
|
+
|
|
16
|
+
*-d* | *--directory* <extension-projects-directory>
|
|
17
|
+
|
|
18
|
+
Specify the target directory of your migrated extension projects. By default, the migrated extension projects will not be stored.
|
|
19
|
+
|
|
20
|
+
*--dry*
|
|
21
|
+
|
|
22
|
+
Do a dry-run only. Only run a verification of the extension migration.
|
|
23
|
+
|
|
24
|
+
# SEE ALSO
|
|
25
|
+
`})
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async function migrate (param, options = {}) {
|
|
29
|
+
// eslint-disable-next-line cds-dk/no-missing-dependencies
|
|
30
|
+
await require('@sap/cds-mtxs/bin/cds-mtx-migrate').run(param[0], options)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* eslint no-console: off */
|
package/bin/pull.js
CHANGED
|
@@ -39,7 +39,7 @@ module.exports = Object.assign(pull, {
|
|
|
39
39
|
|
|
40
40
|
*cds push* to push an extension to the SaaS app.
|
|
41
41
|
*cds login* for more information on authentication options.
|
|
42
|
-
*cds login* to save authentication data, simplifying multiple runs of
|
|
42
|
+
*cds login* to save project settings and authentication data, simplifying multiple runs of this command.
|
|
43
43
|
|
|
44
44
|
`});
|
|
45
45
|
|
|
@@ -49,8 +49,8 @@ async function pull([url], options = {}) {
|
|
|
49
49
|
delete options.user;
|
|
50
50
|
const [clientid, clientsecret] = options.client?.split(':') ?? [];
|
|
51
51
|
delete options.client;
|
|
52
|
-
if (options.from) url = options.from
|
|
53
|
-
delete options.from
|
|
52
|
+
if (options.from) url = options.from;
|
|
53
|
+
delete options.from;
|
|
54
54
|
|
|
55
55
|
await require('../lib/client/pull').run({
|
|
56
56
|
...options,
|
|
@@ -59,5 +59,5 @@ async function pull([url], options = {}) {
|
|
|
59
59
|
password,
|
|
60
60
|
clientid,
|
|
61
61
|
clientsecret
|
|
62
|
-
})
|
|
62
|
+
});
|
|
63
63
|
}
|
package/bin/push.js
CHANGED
|
@@ -46,7 +46,7 @@ module.exports = Object.assign(push, {
|
|
|
46
46
|
|
|
47
47
|
*cds pull* to get the CDS model of the SaaS app.
|
|
48
48
|
*cds login* for more information on authentication options.
|
|
49
|
-
*cds login* to save authentication data, simplifying multiple runs of
|
|
49
|
+
*cds login* to save project settings and authentication data, simplifying multiple runs of this command.
|
|
50
50
|
|
|
51
51
|
`});
|
|
52
52
|
|
package/bin/subscribe.js
CHANGED
|
@@ -1,75 +1,67 @@
|
|
|
1
1
|
module.exports = Object.assign(subscribe, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
init: on => new (require('../lib/client/subscription'))(on),
|
|
3
|
+
options: ['--to', '--user'],
|
|
4
|
+
flags: ['--local'],
|
|
5
|
+
shortcuts: ['-2', '-u', '-l'],
|
|
6
|
+
help: `
|
|
6
7
|
# SYNOPSIS
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
*cds subscribe* <tenant>
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
Subscribe a tenant to a multitenant SaaS app.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
Running *cds subscribe* with a URL is intended for non-productive use only, including against
|
|
14
|
+
SaaS apps running on localhost with mock authentication.
|
|
14
15
|
|
|
15
16
|
# OPTIONS
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
async function subscribe([tenant], { to: url, user } = {}) {
|
|
34
|
-
|
|
35
|
-
const cds = require('../lib/cds')
|
|
36
|
-
|
|
37
|
-
// check for application environment
|
|
38
|
-
// fails for edge cases (ignored for now):
|
|
39
|
-
// @sap/cds-mtx application with missing modules (no npm install)
|
|
40
|
-
// dev scenario with both @sap/cds-mtx and @sap/cds-mtxs installed
|
|
41
|
-
function _hasMtEnv() {
|
|
42
|
-
return cds.requires.multitenancy && !cds.mtx
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (!tenant) {
|
|
47
|
-
console.error('Must provide a tenant')
|
|
48
|
-
return this.help('subscribe')
|
|
49
|
-
}
|
|
50
|
-
if (!url) {
|
|
51
|
-
// check whether we are in a mt(xs) environment
|
|
52
|
-
if (!_hasMtEnv()) throw new Error('Local cds subscribe operation can only be run inside a multitenant application environment using @sap/cds-mtxs. Please specify application url (--to <url>) if you want to subscribe from remote')
|
|
53
|
-
console.log ('\nSubscribing', {tenant})
|
|
54
|
-
const { 'cds.xt.DeploymentService':ds } = await cds.serve ([
|
|
55
|
-
'@sap/cds-mtxs/srv/deployment-service',
|
|
56
|
-
'@sap/cds-mtxs/srv/model-provider'
|
|
57
|
-
])
|
|
58
|
-
cds.emit('served')
|
|
59
|
-
// await cds.connect.to('db')
|
|
60
|
-
await ds.subscribe(tenant)
|
|
61
|
-
} else {
|
|
62
|
-
// Connecting to a deployment service in a subscribed application
|
|
63
|
-
if (typeof user !== 'string') throw new Error('Must provide a username')
|
|
64
|
-
const [username, password = ''] = user.split(':');
|
|
65
|
-
console.log ('\nSubscribing', {tenant}, 'to', {url})
|
|
66
|
-
await require('axios').post (url+'/-/cds/deployment/subscribe', {
|
|
67
|
-
tenant
|
|
68
|
-
}, {
|
|
69
|
-
auth: { username, password }
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
console.log('Subscription succeeded.\n')
|
|
73
|
-
}
|
|
18
|
+
*-2* | *--to* <url>
|
|
19
|
+
|
|
20
|
+
Specify the URL of the SaaS app. Determined from the current user's active CDS or
|
|
21
|
+
Cloud Foundry login by default.
|
|
22
|
+
|
|
23
|
+
*-u* | *--user* <name>[:[<password>]]
|
|
24
|
+
|
|
25
|
+
Username and optionally password for authentication with Basic Auth in test scenarios.
|
|
26
|
+
Required setting if URL is given. (Tokens saved with *cds login* are not used because they
|
|
27
|
+
are unsuitable for this command.)
|
|
28
|
+
|
|
29
|
+
*-l* | *--local*
|
|
30
|
+
|
|
31
|
+
Run a locally-installed @sap/cds-mtxs and connect to it instead of a URL. Ignore settings
|
|
32
|
+
saved with *cds login*.
|
|
33
|
+
|
|
74
34
|
|
|
75
|
-
|
|
35
|
+
# SEE ALSO
|
|
36
|
+
|
|
37
|
+
*cds login* for more information on authentication options.
|
|
38
|
+
*cds login* to save project settings, simplifying multiple runs of this command.
|
|
39
|
+
|
|
40
|
+
`});
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async function subscribe([tenant], options = {}) {
|
|
44
|
+
const { CliError } = require('../lib/client/helper/errors');
|
|
45
|
+
if (!tenant) {
|
|
46
|
+
throw new CliError('Tenant not given.', { command: 'subscribe' });
|
|
47
|
+
}
|
|
48
|
+
const libOptions = { tenant };
|
|
49
|
+
if (options.local) {
|
|
50
|
+
libOptions.local = true;
|
|
51
|
+
delete options.local;
|
|
52
|
+
if (options.user) {
|
|
53
|
+
throw new CliError('Username cannot be specified when running @sap/cds-mtxs locally.', { command: 'subscribe' });
|
|
54
|
+
}
|
|
55
|
+
if (options.to) {
|
|
56
|
+
throw new CliError('URL cannot be specified when running @sap/cds-mtxs locally.', { command: 'subscribe' });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const [username, password] = options.user?.split(':') ?? [];
|
|
60
|
+
delete options.user;
|
|
61
|
+
|
|
62
|
+
await subscribe.init(true).run({
|
|
63
|
+
...options,
|
|
64
|
+
username,
|
|
65
|
+
password
|
|
66
|
+
}, libOptions);
|
|
67
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module.exports = Object.assign(unsubscribe, {
|
|
2
|
+
init: on => new (require('../lib/client/subscription'))(on),
|
|
3
|
+
options: ['--from', '--user'],
|
|
4
|
+
flags: ['--local'],
|
|
5
|
+
shortcuts: ['-f', '-u', '-l'],
|
|
6
|
+
help: `
|
|
7
|
+
# SYNOPSIS
|
|
8
|
+
|
|
9
|
+
*cds unsubscribe* <tenant>
|
|
10
|
+
|
|
11
|
+
Unsubscribe a tenant from a multitenant SaaS app.
|
|
12
|
+
|
|
13
|
+
Running *cds unsubscribe* with a URL is intended for non-productive use only, including against
|
|
14
|
+
SaaS apps running on localhost with mock authentication.
|
|
15
|
+
|
|
16
|
+
# OPTIONS
|
|
17
|
+
|
|
18
|
+
*-f* | *--from* <url>
|
|
19
|
+
|
|
20
|
+
Specify the URL of the SaaS app. Determined from the current user's active CDS or
|
|
21
|
+
Cloud Foundry login by default.
|
|
22
|
+
|
|
23
|
+
*-u* | *--user* <name>[:[<password>]]
|
|
24
|
+
|
|
25
|
+
Username and optionally password for authentication with Basic Auth in test scenarios.
|
|
26
|
+
Required setting if URL is given. (Tokens saved with *cds login* are not used because they
|
|
27
|
+
are unsuitable for this command.)
|
|
28
|
+
|
|
29
|
+
*-l* | *--local*
|
|
30
|
+
|
|
31
|
+
Run a locally-installed @sap/cds-mtxs and connect to it instead of a URL. Ignore settings
|
|
32
|
+
saved with *cds login*.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# SEE ALSO
|
|
36
|
+
|
|
37
|
+
*cds login* for more information on authentication options.
|
|
38
|
+
*cds login* to save project settings, simplifying multiple runs of this command.
|
|
39
|
+
|
|
40
|
+
`});
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async function unsubscribe([tenant], options = {}) {
|
|
44
|
+
const { CliError } = require('../lib/client/helper/errors');
|
|
45
|
+
if (!tenant) {
|
|
46
|
+
throw new CliError('Tenant not given.', { command: 'unsubscribe' });
|
|
47
|
+
}
|
|
48
|
+
const libOptions = { tenant };
|
|
49
|
+
if (options.local) {
|
|
50
|
+
libOptions.local = true;
|
|
51
|
+
delete options.local;
|
|
52
|
+
if (options.user) {
|
|
53
|
+
throw new CliError('Username cannot be specified when running @sap/cds-mtxs locally.', { command: 'subscribe' });
|
|
54
|
+
}
|
|
55
|
+
if (options.from) {
|
|
56
|
+
throw new CliError('URL cannot be specified when running @sap/cds-mtxs locally.', { command: 'unsubscribe' });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const [username, password] = options.user?.split(':') ?? [];
|
|
60
|
+
delete options.user;
|
|
61
|
+
|
|
62
|
+
await unsubscribe.init(false).run({
|
|
63
|
+
...options,
|
|
64
|
+
username,
|
|
65
|
+
password
|
|
66
|
+
}, libOptions);
|
|
67
|
+
}
|
package/bin/watch.js
CHANGED
|
@@ -11,6 +11,9 @@ module.exports = Object.assign ( watch, {
|
|
|
11
11
|
project or the current work directory. Compiles and (re-)runs the server
|
|
12
12
|
on every change detected.
|
|
13
13
|
|
|
14
|
+
Actually, cds watch is just a convenient shortcut for:
|
|
15
|
+
*cds serve all --with-mocks --in-memory?*
|
|
16
|
+
|
|
14
17
|
# OPTIONS
|
|
15
18
|
|
|
16
19
|
*--port* <number>
|
|
@@ -36,9 +39,7 @@ module.exports = Object.assign ( watch, {
|
|
|
36
39
|
|
|
37
40
|
# SEE ALSO
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
*cds serve* all --with-mocks --in-memory? ...
|
|
41
|
-
Check out *cds serve ?* to learn more.
|
|
42
|
+
*cds serve --help* for the different start options
|
|
42
43
|
|
|
43
44
|
`})
|
|
44
45
|
|
package/lib/bind/bindingUtil.js
CHANGED
|
@@ -6,6 +6,7 @@ const util = require('util');
|
|
|
6
6
|
const axios = require('axios');
|
|
7
7
|
const { URL } = require('url');
|
|
8
8
|
const path = require('path');
|
|
9
|
+
const term = require('../util/term');
|
|
9
10
|
|
|
10
11
|
const execAsync = util.promisify(cp.exec);
|
|
11
12
|
const IS_WIN = os.platform() === 'win32';
|
|
@@ -150,7 +151,10 @@ class CFKeyProvider {
|
|
|
150
151
|
name = name || `${instance}:${key}`;
|
|
151
152
|
|
|
152
153
|
if (apiEndpoint && apiEndpoint !== target.apiEndpoint) {
|
|
153
|
-
|
|
154
|
+
let message = `Current Cloud Foundry API endpoint "${target.apiEndpoint}" differs from API endpoint "${apiEndpoint}" for service binding "${name}".\n`;
|
|
155
|
+
message += `Use ${term.bold(`cf login -a ${apiEndpoint}`)} to log in to the target API endpoint.`;
|
|
156
|
+
console.log(message);
|
|
157
|
+
process.exit(1);
|
|
154
158
|
}
|
|
155
159
|
|
|
156
160
|
let spaceGuid;
|
package/lib/client/activate.js
CHANGED
|
@@ -29,7 +29,7 @@ async function checkFinished(jobId, statusUrl, params, finisher) {
|
|
|
29
29
|
finisher.finished = true;
|
|
30
30
|
clearInterval(finisher.timer);
|
|
31
31
|
if (status === JOB_STATUS.FAILED) {
|
|
32
|
-
return finisher.reject(new CliError(`Job ${jobId} failed`, error));
|
|
32
|
+
return finisher.reject(new CliError(`Job ${jobId} failed`, { error }));
|
|
33
33
|
}
|
|
34
34
|
console.log('Extension active');
|
|
35
35
|
finisher.resolve();
|
|
@@ -66,7 +66,7 @@ module.exports = class Activate extends BaseCommand {
|
|
|
66
66
|
await this.runCustomFileUpload(params);
|
|
67
67
|
}
|
|
68
68
|
} catch (error) {
|
|
69
|
-
this.handleHttpError(error, params);
|
|
69
|
+
this.handleHttpError(error, params, { command: 'activate' });
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -132,7 +132,7 @@ module.exports = class Activate extends BaseCommand {
|
|
|
132
132
|
try {
|
|
133
133
|
pkgJson = await fs.readFile(path.join(absoluteFolder, 'package.json'), 'utf-8');
|
|
134
134
|
} catch (error) {
|
|
135
|
-
throw new CliError('No package.json file found', error);
|
|
135
|
+
throw new CliError('No package.json file found', { error });
|
|
136
136
|
}
|
|
137
137
|
allFiles.set('package.json', pkgJson);
|
|
138
138
|
|
|
@@ -60,7 +60,7 @@ async function retrieveTokenOrPasscodeUrl(params) {
|
|
|
60
60
|
try {
|
|
61
61
|
response = await axios.get(tokenUrl);
|
|
62
62
|
} catch (error) {
|
|
63
|
-
throw new CliError('Failed to get authentication token', error);
|
|
63
|
+
throw new CliError('Failed to get authentication token', { error });
|
|
64
64
|
}
|
|
65
65
|
authData = response.data;
|
|
66
66
|
|
|
@@ -83,7 +83,7 @@ module.exports = class AuthManager {
|
|
|
83
83
|
await SettingsManager.loadAndMergeSettings(params);
|
|
84
84
|
if (params.has('username')) {
|
|
85
85
|
params.set('reqAuth', { auth: { username: params.get('username'), password: params.get('password') } });
|
|
86
|
-
} else {
|
|
86
|
+
} else if (!params.get('skipToken')) {
|
|
87
87
|
await retrieveTokenOrPasscodeUrl(params);
|
|
88
88
|
if (!params.has('token')) {
|
|
89
89
|
if (params.get('saveData')) {
|
|
@@ -15,20 +15,21 @@ module.exports = class BaseCommand {
|
|
|
15
15
|
return exists;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
static handleHttpError(error, params, url) {
|
|
18
|
+
static handleHttpError(error, params, { url, command } = {}) {
|
|
19
19
|
url = url ?? params.get('appUrl');
|
|
20
20
|
const prefix = `Request to ${url} failed`;
|
|
21
21
|
switch (error.response?.status) {
|
|
22
22
|
case 401:
|
|
23
|
-
throw new CliError(prefix
|
|
24
|
-
params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : ''
|
|
23
|
+
throw new CliError(`${prefix}: invalid authentication. Retry with valid passcode${
|
|
24
|
+
params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : ''
|
|
25
|
+
}.`, { error, command });
|
|
25
26
|
case 403:
|
|
26
|
-
throw new CliError(prefix + ': insufficient authorization. Ensure client has all necessary roles', error);
|
|
27
|
+
throw new CliError(prefix + ': insufficient authorization. Ensure client has all necessary roles.', { error, command });
|
|
27
28
|
case 404:
|
|
28
|
-
throw new CliError(prefix + ': resource not found.');
|
|
29
|
+
throw new CliError(prefix + ': resource not found.', { command });
|
|
29
30
|
case 422:
|
|
30
31
|
// Compilation or native-extension error.
|
|
31
|
-
throw new CliError(prefix, error);
|
|
32
|
+
throw new CliError(prefix + '.', { error, command });
|
|
32
33
|
default:
|
|
33
34
|
// Unexpected error should be transparent to user.
|
|
34
35
|
throw error;
|
package/lib/client/extend.js
CHANGED
|
@@ -87,13 +87,13 @@ module.exports = class Extend extends BaseCommand {
|
|
|
87
87
|
|
|
88
88
|
const runOnExistingProject = await Extend.checkProject(params.get('projectFolder'));
|
|
89
89
|
if (runOnExistingProject && !(params.get('force') || params.get('templates'))) {
|
|
90
|
-
throw new CliError(folderExists(params.get('projectFolder')));
|
|
90
|
+
throw new CliError(folderExists(params.get('projectFolder')), { command: 'extend' });
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
try {
|
|
94
94
|
await Extend.runExtend(params);
|
|
95
95
|
} catch (error) {
|
|
96
|
-
await Extend.handleHttpError(error, params);
|
|
96
|
+
await Extend.handleHttpError(error, params, { command: 'extend' });
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
@@ -2,11 +2,17 @@ const { getMessage } = require('./logging');
|
|
|
2
2
|
|
|
3
3
|
class CliError extends Error {
|
|
4
4
|
// noinspection JSAnnotator
|
|
5
|
-
constructor(message, error) {
|
|
6
|
-
|
|
5
|
+
constructor(message, { error, command } = {}) {
|
|
6
|
+
const help = command && getCommandHelp(command);
|
|
7
|
+
throw getMessage(message, { error, help });
|
|
7
8
|
}
|
|
8
9
|
}
|
|
9
10
|
|
|
11
|
+
function getCommandHelp(command) {
|
|
12
|
+
const cli = require('../../../bin/cds');
|
|
13
|
+
return cli?.load(command, () => ({ help: '' }))?.help ?? '';
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
module.exports = {
|
|
11
17
|
CliError
|
|
12
18
|
};
|