@sap/cds-dk
Advanced tools
Comparing version 6.3.2 to 6.4.0
@@ -97,3 +97,5 @@ #!/usr/bin/env node | ||
const { readdirSync } = require('fs'); | ||
const { resolve } = require('path'); | ||
const commands = readdirSync(__dirname, { withFileTypes: true }) | ||
.concat(readdirSync(resolve(_local('@sap/cds'), '..', '..', 'bin'), { withFileTypes: true })) | ||
.filter((f) => f.isFile() && !excludeList.includes(f.name)) | ||
@@ -100,0 +102,0 @@ .map((f) => f.name.split('.')[0]).sort(); |
@@ -276,3 +276,4 @@ module.exports = Object.assign ( compile, { | ||
sql: '.sql', | ||
edm: '.json' | ||
edm: '.json', | ||
xsuaa: '.json' | ||
}[x] || '.'+x) } | ||
@@ -279,0 +280,0 @@ |
module.exports = Object.assign(deploy, { | ||
options: ['--to', '--tunnel-address', '--vcap-file'], | ||
flags: [ '--no-save', '--auto-undeploy', '--dry', '--with-mocks', '--store-credentials', '--bind' ], | ||
flags: [ '--no-save', '--auto-undeploy', '--dry', '--xdry', '--with-mocks', '--store-credentials', '--bind' ], | ||
shortcuts: ['-2'], | ||
@@ -82,3 +82,3 @@ help: ` | ||
cds deploy --to sqlite | ||
cds deploy --to sqlite:db/my.db | ||
cds deploy --to sqlite:db/my-db.sqlite | ||
`) | ||
@@ -85,0 +85,0 @@ |
exports.deploy = function deploy_to_sqlite (_model, _db, options) { | ||
if (options.dialect === 'postgres' && !options.dry) console.error('\nDeploying to PostgreSQL is not yet supported\n') | ||
const cds = require('../../lib/cds') | ||
const {to:_dbrl} = options | ||
const conf = cds.env.requires.db || {} | ||
const conf = cds.env.requires.db ?? {} | ||
const fts = cds.env.features.folders | ||
const model = _model || conf.model || cds.resolve(!fts ? '*' : ['*',fts], false) | ||
const file = _database4 (_db, _dbrl, conf) | ||
// current 'sqlite' default is bad, as we want to default to 'plain', so ignore it | ||
const env_dialect = cds.env.sql.dialect !== 'sqlite' ? cds.env.sql.dialect : 'plain' | ||
const to_dialect = _dbrl && _dbrl.match(/^(\w+)/) && RegExp.$1 | ||
if (to_dialect) options.dialect = (to_dialect === 'sql') | ||
? conf.dialect || env_dialect | ||
: to_dialect | ||
if (options.dialect === 'postgres' && !options.dry) console.error('\nDeploying to PostgreSQL is not yet supported\n') | ||
return cds.deploy(model) .to ('sqlite:'+file, options) | ||
.then (db => db && db.disconnect()) // REVISIT: we should NOT require to disconnect explicitly | ||
let file = 'db' | ||
if (options.to) { | ||
file = 'sqlite:'+ _database4 (_db, options.to, conf) | ||
// current 'sqlite' default is bad, as we want to default to 'plain', so ignore it | ||
const env_dialect = cds.env.sql.dialect !== 'sqlite' ? cds.env.sql.dialect : 'plain' | ||
const to_dialect = options.to && options.to.match(/^(\w+)/) && RegExp.$1 | ||
if (to_dialect) options.dialect = (to_dialect === 'sql') | ||
? conf.dialect ?? env_dialect | ||
: to_dialect | ||
} | ||
return cds.deploy(model) .to (file, options) | ||
} | ||
@@ -23,6 +24,7 @@ | ||
if (_db) return _db | ||
if (_dbrl === 'sqlite') return 'db.sqlite' | ||
if (conf.credentials?.database) return conf.credentials.database | ||
if (conf.credentials?.url) return conf.credentials.url | ||
if (_dbrl === 'sqlite') return 'db.sqlite' | ||
if (_dbrl === 'sql') return ':memory:' | ||
else return conf.credentials?.database ?? conf.credentials?.url | ||
} |
/* eslint-disable no-console */ | ||
module.exports = exports = Object.assign (help, {help:` | ||
module.exports = exports = Object.assign (help, {formatHelp, help:` | ||
# USAGE | ||
@@ -42,8 +42,11 @@ | ||
const task = !topic ? help : this.load && this.load (this.Shortcuts[topic] || topic) | ||
if (task && task.help) console.log (task.help | ||
if (task && task.help) console.log (formatHelp (task.help)) | ||
else throw new Error(`Didn't find a help topic for '${ topic.name || topic }'.`) | ||
} | ||
function formatHelp (text) { | ||
return text | ||
.replace(/\n# ([^\n]*)\n/g, `\n\x1b[1m$1\x1b[0m\n`) | ||
.replace(/ \*([^*]+)\*/g, ` \x1b[1m$1\x1b[0m`) | ||
.replace(/ _([^_]+)_/g, ` \x1b[4m$1\x1b[0m`) | ||
) | ||
else throw new Error(`Didn't find a help topic for '${ topic.name || topic }'.`) | ||
} |
@@ -32,3 +32,3 @@ const { URLS } = require('../lib/init/constants') | ||
*mtx* - prepares a multi-tenant project | ||
*mtx* - prepares a multitenant project | ||
@@ -35,0 +35,0 @@ This version only supports Node.js projects. |
@@ -77,4 +77,2 @@ const { bold } = require('../lib/util/term'); | ||
Username and optionally password for authentication with Basic Auth in test scenarios. | ||
See https://cap.cloud.sap/docs/guides/multitenancy/#send-subscribe-events for information | ||
on suitable mock users. | ||
@@ -121,6 +119,7 @@ When typing the colon but omitting <password>, the password is assumed empty. | ||
*cds logout* to remove any authentication data | ||
` | ||
}}); | ||
https://cap.cloud.sap/docs/guides/extensibility/customization?q=mock#mock-users for information on suitable mock users. | ||
`}}); | ||
async function login ([url], options = {}) { | ||
@@ -127,0 +126,0 @@ const [username, password] = options.user?.split(':') ?? []; |
@@ -42,3 +42,3 @@ module.exports = Object.assign(pull, { | ||
*cds login* for more information on authentication options. | ||
*cds login* to save authentication data, simplifying multiple runs of *cds pull* and *cds push* against the same app. | ||
*cds login* to save project settings and authentication data, simplifying multiple runs of this command. | ||
@@ -53,4 +53,4 @@ `}); | ||
delete options.client; | ||
if (options.from) url = options.from | ||
delete options.from | ||
if (options.from) url = options.from; | ||
delete options.from; | ||
@@ -64,3 +64,3 @@ await require('../lib/client/pull').run({ | ||
clientsecret | ||
}) | ||
}); | ||
} |
@@ -49,3 +49,3 @@ module.exports = Object.assign(push, { | ||
*cds login* for more information on authentication options. | ||
*cds login* to save authentication data, simplifying multiple runs of *cds pull* and *cds push* against the same app. | ||
*cds login* to save project settings and authentication data, simplifying multiple runs of this command. | ||
@@ -52,0 +52,0 @@ `}); |
module.exports = Object.assign(subscribe, { | ||
options: ['--to', '--user'], | ||
flags: [], | ||
shortcuts: ['-2', '-u'], | ||
help: ` | ||
init: on => new (require('../lib/client/subscription'))(on), | ||
options: ['--to', '--user'], | ||
flags: ['--local'], | ||
shortcuts: ['-2', '-u', '-l'], | ||
help: ` | ||
# SYNOPSIS | ||
*cds subscribe* <tenant> | ||
*cds subscribe* <tenant> | ||
Subscribe a tenant to a multi-tenant SaaS app. | ||
Subscribe a tenant to a multitenant SaaS app. | ||
*cds subscribe* only supports Basic Authentication and is intended for non-productive use, | ||
including SaaS apps running on localhost with mock authentication. | ||
Running *cds subscribe* with a URL is intended for non-productive use only, including against | ||
SaaS apps running on localhost with mock authentication. | ||
# OPTIONS | ||
*-2* | *--to* <url> | ||
*-2* | *--to* <url> | ||
Specify the URL of the extensible SaaS app. Required setting. | ||
Specify the URL of the SaaS app. Determined from the current user's active CDS or | ||
Cloud Foundry login by default. | ||
*-u* | *--user* <name>[:<password>] | ||
*-u* | *--user* <name>[:[<password>]] | ||
Username and optionally password for authentication. Required setting. | ||
See https://cap.cloud.sap/docs/guides/multitenancy/#send-subscribe-events for information on suitable mock users. | ||
Username and optionally password for authentication with Basic Auth in test scenarios. | ||
Required setting if URL is given. (Tokens saved with *cds login* are not used because they | ||
are unsuitable for this command.) | ||
If password is omitted, it is assumed empty. | ||
Note: productive passwords should not be specified on the command line. | ||
*-l* | *--local* | ||
`}) | ||
Run a locally-installed @sap/cds-mtxs and connect to it instead of a URL. Ignore settings | ||
saved with *cds login*. | ||
# SEE ALSO | ||
async function subscribe([tenant], { to: url, user } = {}) { | ||
*cds login* for more information on authentication options. | ||
*cds login* to save project settings, simplifying multiple runs of this command. | ||
const cds = require('../lib/cds') | ||
`}); | ||
// check for application environment | ||
// fails for edge cases (ignored for now): | ||
// @sap/cds-mtx application with missing modules (no npm install) | ||
// dev scenario with both @sap/cds-mtx and @sap/cds-mtxs installed | ||
function _hasMtEnv() { | ||
return cds.requires.multitenancy && !cds.mtx | ||
} | ||
async function subscribe([tenant], options = {}) { | ||
const { CliError } = require('../lib/client/helper/errors'); | ||
if (!tenant) { | ||
throw new CliError('Tenant not given.', { command: 'subscribe' }); | ||
} | ||
const libOptions = { tenant }; | ||
if (options.local) { | ||
libOptions.local = true; | ||
delete options.local; | ||
if (options.user) { | ||
throw new CliError('Username cannot be specified when running @sap/cds-mtxs locally.', { command: 'subscribe' }); | ||
} | ||
if (options.to) { | ||
throw new CliError('URL cannot be specified when running @sap/cds-mtxs locally.', { command: 'subscribe' }); | ||
} | ||
} | ||
const [username, password] = options.user?.split(':') ?? []; | ||
delete options.user; | ||
if (!tenant) { | ||
console.error('Must provide a tenant') | ||
return this.help('subscribe') | ||
} | ||
if (!url) { | ||
// check whether we are in a mt(xs) environment | ||
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') | ||
console.log ('\nSubscribing', {tenant}) | ||
const { 'cds.xt.DeploymentService':ds } = await cds.serve ([ | ||
'@sap/cds-mtxs/srv/deployment-service', | ||
'@sap/cds-mtxs/srv/model-provider' | ||
]) | ||
cds.emit('served') | ||
// await cds.connect.to('db') | ||
await ds.subscribe(tenant) | ||
} else { | ||
// Connecting to a deployment service in a subscribed application | ||
if (typeof user !== 'string') throw new Error('Must provide a username') | ||
const [username, password = ''] = user.split(':'); | ||
console.log ('\nSubscribing', {tenant}, 'to', {url}) | ||
await require('axios').post (url+'/-/cds/deployment/subscribe', { | ||
tenant | ||
}, { | ||
auth: { username, password } | ||
}); | ||
} | ||
console.log('Subscription succeeded.\n') | ||
await subscribe.init(true).run({ | ||
...options, | ||
username, | ||
password | ||
}, libOptions); | ||
} | ||
// cds subscribe t1 --to http://localhost:4004 -u yves |
@@ -14,2 +14,5 @@ const watchOnlyOptions = ['--ext', '--livereload', '--open'] | ||
Actually, cds watch is just a convenient shortcut for: | ||
*cds serve all --with-mocks --in-memory?* | ||
# OPTIONS | ||
@@ -40,5 +43,3 @@ | ||
Actually, *cds watch* is just a convenient shortcut for: | ||
*cds serve* all --with-mocks --in-memory? ... | ||
Check out *cds serve ?* to learn more. | ||
*cds serve --help* for the different start options | ||
@@ -45,0 +46,0 @@ `}) |
@@ -10,2 +10,29 @@ | ||
## Version 6.4.0 - 2022-12-15 | ||
### Added | ||
- `cds add helm` now supports approuter. | ||
- `cds subscribe --local` starts @sap/cds-mtxs locally instead of contacting a running instance via URL. | ||
- `cds unsubscribe` removes the subscription of a tenant from a SaaS app. | ||
### Changed | ||
- `cds add multitenancy` will not compile internal roles into the `xs-security.json` any more. | ||
- `cds add hana` does not create a `hdi-service-name: ${service-name}` for the database resource properties any more. | ||
- MTX-related commands now print usage help in case of known errors. | ||
- `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`. | ||
- `cds import` now adds default value in the CSN for the optional parameters in action/function for OData V4 files. | ||
- `cds init` uses latest Maven Java archetype version 1.30.0 for creating Java projects. | ||
### Fixed | ||
- `cds init` no longer creates `engines` entry in package.json to avoid `unsupported engine` warnings. | ||
- `cds subscribe` correctly exits the process after deploying to a HANA database. | ||
- `cds add multitenancy` doesn't create a duplicate `saas-registry` resource if there's one with `service-plan: service` any more. | ||
- `cds bind` now correctly maps the `hana-mt` and `sql-mt` shortcuts to the `cds.requires.db` entry. | ||
- `cds add mtx` no longer fails if the `mtx/sidecar` folder doesn't exist. | ||
- `cds compile --to xsuaa` now rejects expressions leading to invalid XSUAA attributes like `$user.foo-bar`, `$user.foo/bar`, `$user.foo.bar` | ||
- `cds compile --to xsuaa -o <file>` now sets `.json` as file ending instead of `.xsuaa` | ||
## Version 6.3.2 - 2022-11-28 | ||
@@ -24,9 +51,5 @@ | ||
- `cds init` uses latest Maven Java archetype version 1.29.0 for creating Java projects. | ||
- Include `@sap/cds` 6.3.1 | ||
- Include `@sap/cds-mtxs` 1.3.1 | ||
- Use `@sap/cds` 6.3.1 | ||
- Use `@sap/cds-mtxs` 1.3.1 | ||
### Fixed | ||
- MTX Client no longer reports 'Request failed with status code 401' when sending a passcode to old MTX server. | ||
## Version 6.3.0 - 2022-11-02 | ||
@@ -50,3 +73,3 @@ | ||
- MTX Client now treats keytar as optional unless explicitly running `cds login` | ||
- `cds import` now caputres the documentation properly for all the EntitySet referring to same EntityType. | ||
- `cds import` now captures the documentation properly for all the EntitySet referring to same EntityType. | ||
- `cds deploy --to sql` now produces 'plain' SQL again, suitable for e.g. H2. In 6.2 it produced 'sqlite' dialect, erroneously. | ||
@@ -261,2 +284,3 @@ - `cds compile --to openapi` now fixes the duplication of fields in `required` section. | ||
- `cds add html5-repo` and `cds add destinations` throw an error if applied for MTA deployments, for which they are currently unsupported. | ||
- `cds compile --to openapi` fixes annotations on bound action overloads. | ||
@@ -263,0 +287,0 @@ - `cds add cf-manifest` now uses the correct `application` plan for the `xsuaa` service |
@@ -9,2 +9,4 @@ | ||
hana: 'db', | ||
'hana-mt': 'db', | ||
'sql-mt': 'db', | ||
destinations: 'destinations', | ||
@@ -11,0 +13,0 @@ connectivity: 'connectivity', |
@@ -9,2 +9,3 @@ const cp = require('child_process'); | ||
const path = require('path'); | ||
const term = require('../util/term'); | ||
@@ -154,3 +155,6 @@ const execAsync = util.promisify(cp.exec); | ||
if (apiEndpoint && apiEndpoint !== target.apiEndpoint) { | ||
throw new Error(`Current Cloud Foundry api endpoint "${target.apiEndpoint}" different than api endpoint "${apiEndpoint}" for service binding "${name}".`); | ||
let message = `Current Cloud Foundry API endpoint "${target.apiEndpoint}" differs from API endpoint "${apiEndpoint}" for service binding "${name}".\n`; | ||
message += `Use ${term.bold(`cf login -a ${apiEndpoint}`)} to log in to the target API endpoint.`; | ||
console.log(message); | ||
process.exit(1); | ||
} | ||
@@ -157,0 +161,0 @@ |
@@ -32,3 +32,3 @@ const fs = require('fs').promises; | ||
if (status === JOB_STATUS.FAILED) { | ||
return finisher.reject(new CliError(`Job ${jobId} failed`, error)); | ||
return finisher.reject(new CliError(`Job ${jobId} failed`, { error })); | ||
} | ||
@@ -70,3 +70,3 @@ console.log('Extension active'); | ||
} catch (error) { | ||
this.handleHttpError(error, params); | ||
this.handleHttpError(error, params, { command: 'activate' }); | ||
} | ||
@@ -137,3 +137,3 @@ } | ||
} catch (error) { | ||
throw new CliError('No package.json file found', error); | ||
throw new CliError('No package.json file found', { error }); | ||
} | ||
@@ -140,0 +140,0 @@ allFiles.set('package.json', pkgJson); |
@@ -63,3 +63,3 @@ const axios = require('axios'); | ||
} catch (error) { | ||
throw new CliError('Failed to get authentication token', error); | ||
throw new CliError('Failed to get authentication token', { error }); | ||
} | ||
@@ -87,3 +87,3 @@ authData = response.data; | ||
params.set('reqAuth', { auth: { username: params.get('username'), password: params.get('password') } }); | ||
} else { | ||
} else if (!params.get('skipToken')) { | ||
await retrieveTokenOrPasscodeUrl(params); | ||
@@ -90,0 +90,0 @@ if (!params.has('token')) { |
@@ -18,3 +18,3 @@ const path = require('path'); | ||
static handleHttpError(error, params, url) { | ||
static handleHttpError(error, params, { url, command } = {}) { | ||
url = url ?? params.get('appUrl'); | ||
@@ -24,11 +24,12 @@ const prefix = `Request to ${url} failed`; | ||
case 401: | ||
throw new CliError(prefix + ': invalid authentication. Retry with valid passcode' + | ||
params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : '', error); | ||
throw new CliError(`${prefix}: invalid authentication. Retry with valid passcode${ | ||
params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : '' | ||
}.`, { error, command }); | ||
case 403: | ||
throw new CliError(prefix + ': insufficient authorization. Ensure client has all necessary roles', error); | ||
throw new CliError(prefix + ': insufficient authorization. Ensure client has all necessary roles.', { error, command }); | ||
case 404: | ||
throw new CliError(prefix + ': resource not found.'); | ||
throw new CliError(prefix + ': resource not found.', { command }); | ||
case 422: | ||
// Compilation or native-extension error. | ||
throw new CliError(prefix, error); | ||
throw new CliError(prefix + '.', { error, command }); | ||
default: | ||
@@ -35,0 +36,0 @@ // Unexpected error should be transparent to user. |
@@ -90,3 +90,3 @@ const fs = require('fs'); | ||
if (runOnExistingProject && !(params.get('force') || params.get('templates'))) { | ||
throw new CliError(folderExists(params.get('projectFolder'))); | ||
throw new CliError(folderExists(params.get('projectFolder')), { command: 'extend' }); | ||
} | ||
@@ -97,3 +97,3 @@ | ||
} catch (error) { | ||
await Extend.handleHttpError(error, params); | ||
await Extend.handleHttpError(error, params, { command: 'extend' }); | ||
} | ||
@@ -100,0 +100,0 @@ } |
@@ -5,9 +5,15 @@ const { getMessage } = require('./logging'); | ||
// noinspection JSAnnotator | ||
constructor(message, error) { | ||
throw getMessage(message, error); | ||
constructor(message, { error, command } = {}) { | ||
const help = command && getCommandHelp(command); | ||
throw getMessage(message, { error, help }); | ||
} | ||
} | ||
function getCommandHelp(command) { | ||
const cli = require('../../../bin/cds'); | ||
return cli?.load(command, () => ({ help: '' }))?.help ?? ''; | ||
} | ||
module.exports = { | ||
CliError | ||
}; |
@@ -5,18 +5,20 @@ /* eslint-disable no-console */ | ||
if (process.env.DEBUG) { | ||
console.log(getMessage(debugText, error)); | ||
console.log(getMessage(debugText, { error })); | ||
} | ||
} | ||
function getMessage(errorText, error) { | ||
function getMessage(errorText, { error, help } = {}) { | ||
let message = errorText ? errorText : ''; | ||
if (!error) { | ||
return message; | ||
if (error) { | ||
message += '\n' + ( | ||
error.response?.data?.message // response body == error | ||
|| error.response?.data?.error?.message // response body == { error } | ||
|| error.message // no response attached | ||
); | ||
if (process.env.DEBUG && error.stack) { | ||
message += '\n' + error.stack; | ||
} | ||
} | ||
message += '\n' + ( | ||
error.response?.data?.message // response body == error | ||
|| error.response?.data?.error?.message // response body == { error } | ||
|| error.message // no response attached | ||
); | ||
if (process.env.DEBUG && error.stack) { | ||
message += '\n' + error.stack; | ||
if (typeof help === 'string') { | ||
message += require('../../../bin/help').formatHelp(help); | ||
} | ||
@@ -23,0 +25,0 @@ return message; |
@@ -213,2 +213,5 @@ const log = require('./helper/logging'); | ||
// `login` PARAMS | ||
this.skipToken = new Param('skipToken', false); | ||
// `logout` PARAMS | ||
@@ -215,0 +218,0 @@ this.deleteSettings = new Param('deleteSettings', false); |
@@ -44,4 +44,4 @@ const cds = require ('../cds') | ||
.then(response => Buffer.from(response.data)) | ||
.catch(error => this.handleHttpError(error, params, pullUrl)); | ||
.catch(error => this.handleHttpError(error, params, { url: pullUrl })); | ||
} | ||
} |
@@ -36,3 +36,3 @@ const cds = require ('../cds'), { local } = cds.utils | ||
if (!schemaRegex.test(src)) { | ||
throw new CliError(`Nonexistent path: ${src}`); | ||
throw new CliError(`Nonexistent path: ${src}`, { command: 'push' }); | ||
} | ||
@@ -42,3 +42,3 @@ try { | ||
} catch (error) { | ||
this.handleHttpError(error, params, src); | ||
this.handleHttpError(error, params, { url: src }); | ||
} | ||
@@ -53,3 +53,3 @@ } | ||
} catch (error) { | ||
throw new CliError(`Extension project at ${projectFolder} is missing package.json file`, error); | ||
throw new CliError(`Extension project at ${projectFolder} is missing package.json file`, { error, command: 'push' }); | ||
} | ||
@@ -66,4 +66,4 @@ } | ||
}, options) | ||
.catch(error => this.handleHttpError(error, params, pushUrl)); | ||
.catch(error => this.handleHttpError(error, params, { url: pushUrl })); | ||
} | ||
} |
@@ -174,3 +174,3 @@ const fs = require('fs'); | ||
if (!params.has('token')) { | ||
if (params.get('skipToken') || !params.has('token')) { | ||
return; | ||
@@ -210,2 +210,5 @@ } | ||
if (params.has('username')) { | ||
params.set('skipToken', true); | ||
} | ||
await this.updateUrls(params, logout, loadedAppUrl); | ||
@@ -221,3 +224,3 @@ await this.checkKeytar(params, logout); | ||
// Subdomain needed for token retrieval. | ||
return params.has('appUrl') && !localhostRegex.test(params.get('appUrl')) && !params.has('username'); | ||
return params.has('appUrl') && !localhostRegex.test(params.get('appUrl')) && !params.get('skipToken'); | ||
} | ||
@@ -279,3 +282,3 @@ | ||
if (!logout) { | ||
if (!logout && !params.get('skipToken')) { | ||
await renewTokenUrl(); | ||
@@ -286,2 +289,5 @@ } | ||
static async checkKeytar(params, logout) { | ||
if (params.get('skipToken')) { | ||
return; | ||
} | ||
if (isBas()) { | ||
@@ -294,5 +300,2 @@ if (params.get('tokenStorage') === 'keyring') { | ||
} | ||
if (params.get('username')) { | ||
return; | ||
} | ||
keytar = requireGlobal('keytar'); | ||
@@ -387,2 +390,6 @@ if (keytar) { | ||
if (params.get('skipToken')) { | ||
return; | ||
} | ||
if (params.get('clientid') && !params.get('clientsecret') && !logout) { | ||
@@ -389,0 +396,0 @@ await addClientSecret(); |
@@ -17,27 +17,33 @@ const cds = require('../cds') | ||
const findUserAttrInExpression = (expr, attributes = []) => { | ||
if (Array.isArray(expr)) { // descend arrays | ||
expr.forEach(e => findUserAttrInExpression(e, attributes)) | ||
} | ||
else if (typeof expr === 'object' && expr.ref) { | ||
const userIdx = expr.ref.indexOf('$user') | ||
if (userIdx >= 0 && userIdx < expr.ref.length - 1) { | ||
const attr = expr.ref[userIdx + 1] | ||
if (!hardcoded.Attributes.includes(attr)) attributes.push(attr) | ||
} | ||
} | ||
return attributes | ||
} | ||
const parseAttributes = (condition) => { // e.g. 'foo = $user.bar or baz = $user.boo' | ||
if (!condition) return [] | ||
// first validate basic syntax of expression by parsing it | ||
let expr | ||
try { | ||
// {"xpr":[{"ref":["foo"]},"=",{"ref":["$user","bar"]},"or",{"ref":["baz"]},"=",{"ref":["$user","boo"]}]} | ||
const expr = cds.parse.expr(condition) | ||
// find paths value following $user, i.e. 'bar' and 'boo' | ||
return findUserAttrInExpression(expr.xpr) | ||
expr = cds.parse.expr(condition).xpr | ||
} catch (err) { | ||
throw new Error(`${err.message} in '${condition}'`) | ||
throw new Error(`Invalid expression': ${err.message}`) | ||
} | ||
// Reject expressions like `$user.foo.bar`, as xsuaa attributes are primitive, not structured | ||
expr.forEach(expr => { | ||
const userIdx = expr.ref?.indexOf('$user') | ||
if (userIdx >= 0 && expr.ref.length > userIdx+2) { | ||
throw new Error (`Structured attributes like '${expr.ref.join('.')}' are not supported`) | ||
} | ||
}) | ||
// Reject expressions like `$user.foo-bar` | ||
// Impl. note: use the expression string rather than the parsed expression as the above example would be | ||
// `[ { ref: [ '$user', 'foo' ] }, '-', { ref: [ 'bar' ] } ]` | ||
// making it ambiguous to tell if it was `$user.foo-bar` or `$user.foo - bar` | ||
return Array.from(condition.matchAll(/\$user\s*\.\s*(\S*)/g)) | ||
.map(m => m[1]) | ||
.filter(m => !hardcoded.Attributes.includes(m)) | ||
.map(m => { | ||
// see https://help.sap.com/docs/CP_AUTHORIZ_TRUST_MNG/ae8e8427ecdf407790d96dad93b5f723/517895a9612241259d6941dbf9ad81cb.html#attributes | ||
if (!/^[a-zA-Z0-9_]*$/.test(m)) throw new Error(`Illegal attribute name '${m}' in '${condition}'. Only characters a-z, A-Z, 0-9, _ are allowed.`) | ||
return m | ||
}) | ||
} | ||
@@ -44,0 +50,0 @@ |
@@ -57,2 +57,3 @@ /** | ||
parserContext.allInheritedComplexTypes = {}; | ||
parserContext.allInheritedEntityTypes = {}; | ||
parserContext.allowedNamespaces = []; | ||
@@ -343,2 +344,5 @@ parserContext.allowAllNamespaces = false; | ||
baseType = complexType[key].BaseType; | ||
if (complexType[key].Abstract || complexType[key].OpenType) { | ||
complexType.open = true; | ||
} | ||
} else if (key === "Property") { | ||
@@ -350,3 +354,3 @@ properties = complexType.Property; | ||
}); | ||
parserContext.allComplexTypes[complexTypeKey] = properties; | ||
parserContext.allComplexTypes[complexTypeKey] = complexType; | ||
if (complexTypeKey && baseType) { | ||
@@ -387,3 +391,3 @@ parserContext.allInheritedComplexTypes[complexTypeKey] = baseType; | ||
//preprocessing of datatype in case it is a collection | ||
if (dataType.substring(0, 10) === 'Collection') { | ||
if (dataType && dataType.substring(0, 10) === 'Collection') { | ||
dataType = dataType.substring(11, dataType.length - 1); | ||
@@ -490,11 +494,7 @@ isCollection = 1; | ||
} | ||
if (nullable == "false") { | ||
if (nullable === "false") | ||
propertyJson = propertyJson + ',\n"notNull": true'; | ||
} | ||
else if(nullable=="true" || !nullable){ | ||
propertyJson = propertyJson + ',\n"notNull": false'; | ||
} | ||
propertyJson = propertyJson + '\n}' | ||
} | ||
else{ | ||
else { | ||
propertyJson = propertyJson + '"type":"' + cdsDataType + '"'; | ||
@@ -536,9 +536,4 @@ //if annotations to be added | ||
if(isCollection == -1) { | ||
if (nullable === "false") { | ||
propertyJson = propertyJson + ',\n"notNull": true'; | ||
} | ||
else if(nullable=="true" || !nullable){ | ||
propertyJson = propertyJson + ',\n"notNull": false'; | ||
} | ||
if (isCollection === -1 && nullable === "false") { | ||
propertyJson = propertyJson + ',\n"notNull": true'; | ||
} | ||
@@ -551,7 +546,10 @@ | ||
function _getServiceComplexType(complexTypeKey, complexType, parserContext) { | ||
function _getServiceComplexType(complexTypeKey, complexType, parserContext, isOpenType) { | ||
let complexTypeCSN = '"' + complexTypeKey + '": {\n'; | ||
let complexTypeProperty; | ||
let i; | ||
complexTypeCSN = complexTypeCSN + '"kind": "type",\n'; | ||
// checking if the ComplexType is marked open or acts as a BaseType | ||
if (isOpenType === true || Object.values(parserContext.allInheritedComplexTypes).indexOf(complexTypeKey) > -1) { | ||
complexTypeCSN = complexTypeCSN + '"@open": true,\n'; | ||
} | ||
complexTypeCSN = complexTypeCSN + '"@cds.external": true,\n'; | ||
@@ -567,3 +565,3 @@ if (parserContext.allComplexTypeNamespaces[complexTypeKey]) { | ||
// More than one complex types | ||
for (i = 0; i < complexType.length; i++) { | ||
for (let i = 0; i < complexType.length; i++) { | ||
complexTypeProperty = complexType[i]._attributes; | ||
@@ -575,3 +573,3 @@ if (complexType[i].Documentation) | ||
let complexProperty = | ||
let complexProperty = | ||
_getServiceEntityProperty( | ||
@@ -629,3 +627,3 @@ complexTypeProperty.Name, | ||
complexTypeCSN = complexTypeCSN + ",\n"; | ||
complexTypeCSN = complexTypeCSN + | ||
complexTypeCSN = complexTypeCSN + | ||
'"includes": ["' + parserContext.allInheritedComplexTypes[complexTypeKey] + '"]\n'; | ||
@@ -642,6 +640,8 @@ } | ||
let complexType; | ||
let isOpenType; | ||
for (let i = 0; i < complexTypesKeys.length; i++) { | ||
complexTypeKey = complexTypesKeys[i]; | ||
complexType = parserContext.allComplexTypes[complexTypesKeys[i]]; | ||
complexTypeCSN = complexTypeCSN + _getServiceComplexType(complexTypeKey, complexType, parserContext); | ||
complexType = parserContext.allComplexTypes[complexTypeKey].Property; | ||
isOpenType = parserContext.allComplexTypes[complexTypeKey].open; | ||
complexTypeCSN = complexTypeCSN + _getServiceComplexType(complexTypeKey, complexType, parserContext, isOpenType); | ||
if (i !== complexTypesKeys.length - 1) { | ||
@@ -801,2 +801,3 @@ complexTypeCSN = complexTypeCSN + ",\n"; | ||
entityAttributes.Abstract = attributes.Abstract; | ||
entityAttributes.OpenType = attributes.OpenType; | ||
entityAttributes.allowedNamespaceAttributes = namespaceAttributeFilter(attributes, parserContext); | ||
@@ -1319,2 +1320,7 @@ | ||
csn = csn + `"@cds.ambiguous": "missing on condition?",\n`; | ||
//Code for notNull working but change is not reflecting when we use: cds compile {file-path} -2 edmx > {newFileName} | ||
/*if (navPropAttributes.Nullable === "false") | ||
csn = csn + '"notNull": true,\n';*/ | ||
// if documentation exists for navigation property | ||
@@ -1412,4 +1418,4 @@ if (navPropDoc) | ||
if (entityAttributes.Abstract && entityAttributes.Abstract.toUpperCase() === "TRUE") { | ||
csnEntity = csnEntity + '"abstract": true,\n'; | ||
if ((entityAttributes.Abstract && entityAttributes.Abstract.toUpperCase() === "TRUE") || (entityAttributes.OpenType && entityAttributes.OpenType.toUpperCase() === "TRUE")) { | ||
csnEntity = csnEntity + '"@open": true,\n' | ||
} | ||
@@ -1542,2 +1548,3 @@ | ||
parserContext.allEntities.push(_extractEntityFromNamespace(entityAttributes.BaseType)); | ||
parserContext.allInheritedEntityTypes[_extractEntityFromNamespace(entityAttributes.BaseType)] = entity["_attributes"].Name; | ||
} | ||
@@ -1632,2 +1639,8 @@ // adding blob element if entity has m:HasStream as true | ||
ignorePersistenceSkip, mockServerUc, parserContext); | ||
// adding @open annotation to BaseTypes | ||
for (let j = 0; j < parsedEntities[i].length; j++) { | ||
if (parserContext.allInheritedEntityTypes[_extractEntityFromNamespace(parserContext.allEntitySetMap[entitiesWithNames[i][j].name])] != undefined || parserContext.allInheritedEntityTypes[entitiesWithNames[i][j].name]) { | ||
parsedEntities[i][j] = parsedEntities[i][j].replace(/}$/, ',"@open": true' + '}'); | ||
} | ||
} | ||
} | ||
@@ -1634,0 +1647,0 @@ } |
@@ -7,3 +7,2 @@ /* eslint-disable no-prototype-builtins */ | ||
"use strict"; | ||
let messages = require("../message").getMessages(); | ||
@@ -75,2 +74,4 @@ let common = require("../common"); | ||
parserContext.entityTypes = []; | ||
parserContext.entityTypeOpenEntries = []; | ||
parserContext.complexTypeOpenEntries = []; | ||
parserContext.namespace = ""; | ||
@@ -105,7 +106,3 @@ parserContext.complexTypes = {}; | ||
function _isValidJSON(jsonObj, parserContext) { | ||
let tempNamespace = jsonObj.$EntityContainer; | ||
parserContext.namespace = tempNamespace.substring(0, tempNamespace.lastIndexOf('.')); | ||
parserContext.jsonEntityContainerName = tempNamespace.substring(tempNamespace.lastIndexOf('.') + 1); | ||
if (jsonObj.$Version && jsonObj.$EntityContainer && jsonObj[parserContext.namespace]) { | ||
if (jsonObj.$Version && _hasEntityContainer(jsonObj, parserContext) && jsonObj[parserContext.namespace]) { | ||
return true; | ||
@@ -119,7 +116,11 @@ } | ||
function _hasEntityContainer(jsonObj, parserContext) { | ||
if (jsonObj[parserContext.namespace][parserContext.jsonEntityContainerName] && | ||
jsonObj[parserContext.namespace][parserContext.jsonEntityContainerName] instanceof Object | ||
) { | ||
return true; | ||
} else { | ||
let jsonObjEntityContainer = jsonObj.$EntityContainer; | ||
try { | ||
if (jsonObjEntityContainer) [parserContext.namespace, parserContext.jsonEntityContainerName] = jsonObjEntityContainer.split('.'); | ||
if (jsonObj[parserContext.namespace][parserContext.jsonEntityContainerName] && | ||
jsonObj[parserContext.namespace][parserContext.jsonEntityContainerName] instanceof Object | ||
) { | ||
return true; | ||
} | ||
} catch (err) { | ||
throw new Error(messages.MISSING_ENTITY_CONTAINER); | ||
@@ -129,9 +130,2 @@ } | ||
function _validateJSON(jsonObj, parserContext) { | ||
return ( | ||
_isValidJSON(jsonObj, parserContext) && | ||
_hasEntityContainer(jsonObj, parserContext) | ||
); | ||
} | ||
function _includeExternalNamespaceAnnotation(source, target) { | ||
@@ -145,2 +139,7 @@ Object.entries(source).forEach(element => { | ||
function _addNotNull(property, isCollection) { | ||
if (isCollection) property.items["notNull"] = true; | ||
else property["notNull"] = true; | ||
} | ||
function _typeWithCollections(property, type, isCollection) { | ||
@@ -175,3 +174,5 @@ if (isCollection === true) { | ||
else { | ||
typeProperties["notNull"] = propertyType.$Nullable ? false : true; | ||
if ((propertyType.$Nullable !== true) && (propertyType.$Kind !== 'TypeDefinition')) { | ||
typeProperties["notNull"] = true; | ||
} | ||
} | ||
@@ -235,2 +236,3 @@ _includeExternalNamespaceAnnotation(propertyType, property); | ||
_typeWithCollections(property, type, propertyType.$Collection); | ||
if (!propertyType.$Nullable) _addNotNull(property, propertyType.$Collection); | ||
@@ -242,6 +244,7 @@ return property; | ||
let property = {}; | ||
let type = { type: propertyType.$Type } | ||
let type = { type: propertyType.$Type }; | ||
_includeExternalNamespaceAnnotation(propertyType, property); | ||
_typeWithCollections(property, type, propertyType.$Collection); | ||
if (!propertyType.$Nullable) _addNotNull(property, propertyType.$Collection); | ||
@@ -263,2 +266,7 @@ return property; | ||
// associationProperty.target = associationNode.$Type; | ||
//Code for NavigationProperty for notNull | ||
/*if(associationProperty.$Nullable != true){ | ||
associationProperty["notNull"] = true; | ||
}*/ | ||
if (mockServerUc && parserContext.entitySetToEntityTypeMap && parserContext.entitySetToEntityTypeMap.get(associationNode.$Type)) { | ||
@@ -346,2 +354,3 @@ if (parserContext.entitySetToEntityTypeMap.get(associationNode.$Type).length > 1) { | ||
let isAbstract = element[key].$Abstract; | ||
let isOpenType = element[key].$OpenType; | ||
if (key) { | ||
@@ -369,5 +378,6 @@ entityCsn[key] = {}; | ||
entityCsn[key].includes.push(baseType); | ||
if (!parserContext.entityTypeOpenEntries.includes(baseType)) parserContext.entityTypeOpenEntries.push(baseType); | ||
} | ||
if (isAbstract) { | ||
entityCsn[key].abstract = isAbstract; | ||
if ((isAbstract || isOpenType) && !parserContext.entityTypeOpenEntries.includes(key)) { | ||
parserContext.entityTypeOpenEntries.push(key); | ||
} | ||
@@ -423,2 +433,8 @@ entityCsn[key].elements = {}; | ||
}); | ||
// add @open annotations | ||
parserContext.entityTypeOpenEntries.forEach(key => { | ||
if (entityCsn[key]) entityCsn[key]['@open'] = true; | ||
}); | ||
return entityCsn; | ||
@@ -595,2 +611,22 @@ } | ||
function _captureOptionalParameter(annotation, path) { | ||
let param = annotation[0].split('/'); | ||
let defaultvalue = annotation[1]["@Core.OptionalParameter"]["DefaultValue"]; | ||
if (path.params === undefined) { | ||
_addDefaultValueObject(path, defaultvalue); | ||
} | ||
else { | ||
_addDefaultValueObject(path.params[param[1]], defaultvalue); | ||
} | ||
return path; | ||
} | ||
function _addDefaultValueObject(path, defaultvalue) { | ||
// for collection, default value isin't expected | ||
if (path.items === undefined) { | ||
path.default = {}; | ||
path.default.val = (defaultvalue) ? defaultvalue : null; | ||
} | ||
} | ||
function _collectBounded(schemaDataList, flag, parserContext) { | ||
@@ -694,10 +730,12 @@ let schemaData; | ||
csnDefs[boundedEntityName].actions[name].params[paramName].items = paramType; | ||
csnDefs[boundedEntityName].actions[name].params[paramName].items["notNull"] = paramObj?.$Nullable ? false : true; | ||
if(paramObj.$Nullable != true){ | ||
csnDefs[boundedEntityName].actions[name].params[paramName].items["notNull"] = true; | ||
} | ||
} else { | ||
csnDefs[boundedEntityName].actions[name].params[paramName] = paramType; | ||
if (!paramType.items) { | ||
csnDefs[boundedEntityName].actions[name].params[paramName].notNull = paramObj?.$Nullable ? false : true; | ||
if(paramObj.$Nullable != true){ | ||
csnDefs[boundedEntityName].actions[name].params[paramName].notNull = true; | ||
} | ||
} | ||
} | ||
} | ||
@@ -736,3 +774,5 @@ } | ||
csnDefs[boundedEntityName].actions[name].returns.items = returnType; | ||
csnDefs[boundedEntityName].actions[name].returns.items["notNull"] = obj[j].$ReturnType?.$Nullable ? false : true | ||
if(obj[j].$ReturnType.$Nullable != true){ | ||
csnDefs[boundedEntityName].actions[name].returns.items["notNull"] = true; | ||
} | ||
} | ||
@@ -742,3 +782,5 @@ else { | ||
if (!returnType.items) { | ||
csnDefs[boundedEntityName].actions[name].returns["notNull"] = obj[j].$ReturnType?.$Nullable ? false : true | ||
if(obj[j].$ReturnType.$Nullable != true){ | ||
csnDefs[boundedEntityName].actions[name].returns["notNull"] = true; | ||
} | ||
} | ||
@@ -756,2 +798,3 @@ } | ||
} | ||
} | ||
}); | ||
@@ -789,3 +832,3 @@ } | ||
let propertyType; | ||
let baseType; | ||
let baseType, isAbstract, isOpenType; | ||
let enumType; | ||
@@ -800,6 +843,12 @@ cTypes = _collectComplexType(schemaData, parserContext); | ||
baseType = cTypes[element].$BaseType; | ||
isAbstract = cTypes[element].$Abstract; | ||
isOpenType = cTypes[element].$OpenType; | ||
if (baseType) { | ||
complexCsn[element].includes = []; | ||
complexCsn[element].includes.push(baseType); | ||
if (!parserContext.complexTypeOpenEntries.includes(baseType)) parserContext.complexTypeOpenEntries.push(baseType); | ||
} | ||
if ((isAbstract || isOpenType) && !parserContext.complexTypeOpenEntries.includes(element)) { | ||
parserContext.complexTypeOpenEntries.push(element); | ||
} | ||
Object.keys(cTypes[element]).forEach(property => { // cTypes[element][property].$Type.startsWith('Edm.') | ||
@@ -816,2 +865,5 @@ if (cTypes[element][property] instanceof Object) { | ||
complexCsn[element].elements[property] = _generateComplexTypePropertyCsn(propertyType); | ||
} else if (parserContext.typeDefinitions[cTypes[element][property].$Type]) { | ||
propertyType = cTypes[element][property]; | ||
complexCsn[element].elements[property] = _generateTypeDefinitionPropertyCsn(propertyType); | ||
} else if (parserContext.enumTypes[cTypes[element][property].$Type]) { | ||
@@ -829,2 +881,8 @@ enumType = cTypes[element][property]; | ||
}); | ||
// add @open annotations | ||
parserContext.complexTypeOpenEntries.forEach(key => { | ||
if (complexCsn[key]) complexCsn[key]['@open'] = true; | ||
}); | ||
return complexCsn; | ||
@@ -895,7 +953,11 @@ } | ||
obj[objType].params[objData.$Parameter[i].$Name].items = paramType; | ||
obj[objType].params[objData.$Parameter[i].$Name].items["notNull"] = objData.$Parameter[i]?.$Nullable ? false : true; | ||
if(objData.$Parameter[i].$Nullable != true){ | ||
obj[objType].params[objData.$Parameter[i].$Name].items["notNull"] = true; | ||
} | ||
} else { | ||
obj[objType].params[objData.$Parameter[i].$Name] = paramType; | ||
if (!paramType.items) { | ||
obj[objType].params[objData.$Parameter[i].$Name]["notNull"] = objData.$Parameter[i]?.$Nullable ? false : true; | ||
if(objData.$Parameter[i].$Nullable != true){ | ||
obj[objType].params[objData.$Parameter[i].$Name]["notNull"] = true; | ||
} | ||
} | ||
@@ -935,8 +997,12 @@ } | ||
obj[objType].returns.items = returnValue; | ||
obj[objType].returns.items["notNull"] = objData.$ReturnType?.$Nullable ? false : true; | ||
if(objData.$ReturnType.$Nullable != true){ | ||
obj[objType].returns.items["notNull"] = true; | ||
} | ||
} else { | ||
obj[objType].returns = returnValue; | ||
if (!returnValue.items) { | ||
obj[objType].returns["notNull"] = objData.$ReturnType?.$Nullable ? false : true; | ||
if(objData.$ReturnType.$Nullable != true){ | ||
obj[objType].returns["notNull"] = true; | ||
} | ||
} | ||
} | ||
@@ -1048,5 +1114,8 @@ } | ||
} | ||
else if (vocab) { | ||
else if (targetString === "@Core.OptionalParameter" && annotation[1]["@Core.OptionalParameter"]) { | ||
_captureOptionalParameter(annotation, path); | ||
} | ||
else if (vocab) { | ||
if (vocab.includes(targetString.substring(targetString.indexOf('@') + 1, targetString.lastIndexOf('.')))) { | ||
path[targetString] = annotation[1][targetString]; | ||
path[targetString] = annotation[1][targetString] === null ? true : annotation[1][targetString]; | ||
} | ||
@@ -1222,3 +1291,3 @@ } | ||
} | ||
if (_validateJSON(json, parserContext)) { | ||
if (_isValidJSON(json, parserContext)) { | ||
resolve(json); | ||
@@ -1250,3 +1319,3 @@ } | ||
edmjConverted = JSON.parse(edmx); | ||
if (_validateJSON(edmjConverted, parserContext)) { | ||
if (_isValidJSON(edmjConverted, parserContext)) { | ||
csn = _generateCSN(edmjConverted, ignorePersistenceSkip, mockServerUc, parserContext); | ||
@@ -1253,0 +1322,0 @@ if (csn) resolve(csn); |
const os = require('os'); | ||
const MAVEN_ARCHETYPE_VERSION = '1.29.0'; | ||
const MAVEN_ARCHETYPE_VERSION = '1.30.0'; | ||
@@ -5,0 +5,0 @@ const constants = { |
@@ -270,4 +270,4 @@ const path = require('path'); | ||
this.templateList = Array.from(templates.entries()).sort((a, b) => { | ||
return OPTIONS_PRIORITY.indexOf(a[0]) - OPTIONS_PRIORITY.indexOf(b[0]); | ||
this.templateList = Array.from(templates.entries()).sort(([a], [b]) => { | ||
return OPTIONS_PRIORITY.indexOf(a) - OPTIONS_PRIORITY.indexOf(b); | ||
}).map((entry) => entry[1]); | ||
@@ -274,0 +274,0 @@ |
@@ -126,5 +126,2 @@ // Registry of sequence matchers in mta.yaml files | ||
isEqualTo: 'saas-registry', | ||
}, { | ||
property: 'parameters.service-plan', | ||
isEqualTo: 'application' | ||
}] | ||
@@ -131,0 +128,0 @@ } |
{ | ||
"name": "approuter", | ||
"dependencies": { | ||
"@sap/approuter": "^11.0.0" | ||
"@sap/approuter": "^12.0.0" | ||
}, | ||
@@ -6,0 +6,0 @@ "engines": { |
@@ -12,2 +12,3 @@ const { join } = require('path') | ||
} = require('../_merging/registry-mta') | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
@@ -25,12 +26,3 @@ module.exports = class ApprouterTemplate extends require('../templateBase') { | ||
async canRun() { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
const { hasMta, hasHelm } = projectDescriptor.cap | ||
if (hasHelm && !hasMta) { | ||
throw `'cds add approuter' is not available for Kyma yet` | ||
} | ||
return true | ||
} | ||
async getDependencies() { | ||
getDependencies() { | ||
return [OPTION_XSUAA] | ||
@@ -71,5 +63,5 @@ } | ||
async runDependentMerging() { | ||
async runDependentMerging(context = {}) { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
const { isNodejs, isJava, isExtensible, isMultitenant, hasMta } = projectDescriptor.cap | ||
const { isNodejs, isJava, isExtensible, isMultitenant, hasMta, hasHelm } = projectDescriptor.cap | ||
@@ -95,2 +87,58 @@ if (hasMta) { | ||
if (hasHelm) { | ||
let isIndependentCommand = false; | ||
if (Object.keys(context).length == 0) { | ||
isIndependentCommand = true; | ||
context.projectPath = this.projectPath; | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')); | ||
} | ||
await mergeYAML( | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
join(__dirname, 'files', 'values.yaml.hbs'), | ||
projectDescriptor | ||
) | ||
await mergeYAML( | ||
join(this.projectPath, 'chart', 'Chart.yaml'), | ||
join(__dirname, 'files', 'chart.yaml'), | ||
projectDescriptor, | ||
{ additions: [{ | ||
ref: `web-application-approuter`, | ||
in: `dependencies`, | ||
where: [{ | ||
property: 'alias', | ||
isEqualTo: 'approuter' | ||
}] | ||
}]} | ||
) | ||
await mergeYAML( | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
{ | ||
approuter: { | ||
envFrom: [ | ||
{ | ||
configMapRef: { | ||
name: "{{ .Release.Name }}-approuter-configmap", | ||
tpl: true | ||
} | ||
} | ||
] | ||
} | ||
}, | ||
projectDescriptor | ||
) | ||
const fileName = isMultitenant ? 'approuter-mtxs-configmap.yaml' : 'approuter-configmap.yaml'; | ||
await copyAndTrack( | ||
join(__dirname, 'files', fileName), | ||
join(this.projectPath, 'chart', 'templates', 'approuter-configmap.yaml'), | ||
context, | ||
true | ||
) | ||
if (isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData); | ||
} | ||
const appPath = join(this.projectPath, projectDescriptor.ui.appPath || 'app') | ||
@@ -97,0 +145,0 @@ const additions = isExtensible && isJava ? [{ ...approuterExtensibilityJava, at: 0 }] : |
@@ -1,5 +0,5 @@ | ||
const path = require('path') | ||
const { copy } = require('../../../cds').utils | ||
const { join } = require('path') | ||
const ProjectReader = require('../../util/projectReader') | ||
const { mergeYAML } = require('../../util/merge') | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
const { srvNode, srvJava, auditlog } = require('../_merging/registry-mta') | ||
@@ -21,3 +21,3 @@ | ||
async runDependentMerging() { | ||
async runDependentMerging(context = {}) { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
@@ -27,3 +27,3 @@ const { isNodejs, hasMta, hasHelm } = projectDescriptor.cap | ||
if (hasMta) { | ||
const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml') | ||
const mtaYAMLPath = join(this.projectPath, 'mta.yaml') | ||
const srv = isNodejs ? srvNode : srvJava | ||
@@ -45,4 +45,12 @@ await mergeYAML( | ||
if (hasHelm) { | ||
//in case facet is being added to the already exisiting charts folder | ||
let isIndependentCommand = false | ||
if(Object.keys(context).length == 0){ | ||
isIndependentCommand = true | ||
context.projectPath = this.projectPath | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')) | ||
} | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'values.yaml'), | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
{ | ||
@@ -56,8 +64,8 @@ srv: { bindings: { | ||
} | ||
}, | ||
null, { forceOverwrite: true } | ||
} | ||
) | ||
await copy(path.join(__dirname, 'files', 'auditlog.yaml'), path.join(this.projectPath, 'chart', 'templates', 'auditlog.yaml')) | ||
await copyAndTrack(join(__dirname, 'files', 'auditlog.yaml'), join(this.projectPath, 'chart', 'templates', 'auditlog.yaml'), context) | ||
if(isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData) | ||
} | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
const path = require('path') | ||
const { join } = require('path') | ||
const { exists } = require('../../../cds').utils | ||
@@ -24,3 +24,3 @@ const ProjectReader = require('../../util/projectReader'); | ||
if (exists(path.join(this.projectPath, MANIFEST_FILE)) || exists(path.join(this.projectPath, SERVICES_MANIFEST_FILE))) { | ||
if (exists(join(this.projectPath, MANIFEST_FILE)) || exists(join(this.projectPath, SERVICES_MANIFEST_FILE))) { | ||
throw new Error(`File ${MANIFEST_FILE} or ${SERVICES_MANIFEST_FILE} already exist in current folder. Use --force to overwrite.`); | ||
@@ -33,4 +33,4 @@ } | ||
const projectDescriptor = await this.projectReader.read() | ||
await copyFiles(path.join(__dirname, 'files'), this.projectPath, projectDescriptor, this.options.force); | ||
await copyFiles(join(__dirname, 'files'), this.projectPath, projectDescriptor, this.options.force); | ||
} | ||
} |
@@ -1,5 +0,5 @@ | ||
const path = require('path') | ||
const { join } = require('path') | ||
const ProjectReader = require('../../util/projectReader') | ||
const { mergeYAML } = require('../../util/merge') | ||
const cds = require('../../../cds'), { copy } = cds.utils | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
@@ -16,3 +16,3 @@ module.exports = class ConnectivityTemplate extends require('../templateBase') { | ||
async runDependentMerging() { | ||
async runDependentMerging(context = {}) { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
@@ -22,5 +22,13 @@ const { hasHelm } = projectDescriptor.cap | ||
if (hasHelm) { | ||
//in case facet is being added to the already exisiting charts folder | ||
let isIndependentCommand = false | ||
if(Object.keys(context).length == 0){ | ||
isIndependentCommand = true | ||
context.projectPath = this.projectPath | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')) | ||
} | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'values.yaml'), | ||
path.join(__dirname, 'files', 'values.yaml.hbs'), | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
join(__dirname, 'files', 'values.yaml.hbs'), | ||
projectDescriptor, | ||
@@ -36,9 +44,10 @@ { additions: [{ | ||
) | ||
const filesPath = path.join(__dirname, 'files') | ||
const templatesPath = path.join(this.projectPath, 'chart', 'templates') | ||
await copy(path.join(filesPath, 'connectivity-binding.yaml'), path.join(templatesPath, 'connectivity-binding.yaml')) | ||
await copy(path.join(filesPath, 'connectivity-proxy-info.yaml'), path.join(templatesPath, 'connectivity-proxy-info.yaml')) | ||
await copy(path.join(filesPath, 'connectivity.yaml'), path.join(templatesPath, 'connectivity.yaml')) | ||
const filesPath = join(__dirname, 'files') | ||
const templatesPath = join(this.projectPath, 'chart', 'templates') | ||
await copyAndTrack(join(filesPath, 'connectivity-binding.yaml'), join(templatesPath, 'connectivity-binding.yaml'), context) | ||
await copyAndTrack(join(filesPath, 'connectivity-proxy-info.yaml'), join(templatesPath, 'connectivity-proxy-info.yaml'), context) | ||
await copyAndTrack(join(filesPath, 'connectivity.yaml'), join(templatesPath, 'connectivity.yaml'), context) | ||
if(isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData) | ||
} | ||
} | ||
} |
@@ -1,5 +0,5 @@ | ||
const path = require('path') | ||
const { join } = require('path') | ||
const ProjectReader = require('../../util/projectReader') | ||
const { mergeYAML } = require('../../util/merge') | ||
const { copy } = require('../../../cds').utils | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
@@ -12,2 +12,11 @@ module.exports = class DestinationsTemplate extends require('../templateBase') { | ||
async canRun() { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
const { hasMta, hasHelm } = projectDescriptor.cap | ||
if (!hasHelm && hasMta) { | ||
throw `'cds add destinations' is not available for Cloud Foundry yet` | ||
} | ||
return true | ||
} | ||
static hasFacet(env) { | ||
@@ -22,3 +31,3 @@ const kinds = { odata: 1, 'odata-v2': 1, 'odata-v4': 1, rest: 1 } | ||
async runDependentMerging() { | ||
async runDependentMerging(context = {}) { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
@@ -32,4 +41,11 @@ const { hasHelm, hasDestination, hasHtml5Repo } = projectDescriptor.cap | ||
//in case facet is being added to the already exisiting charts folder | ||
let isIndependentCommand = false | ||
if(Object.keys(context).length == 0){ | ||
isIndependentCommand = true | ||
context.projectPath = this.projectPath | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')) | ||
} | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'values.yaml'), | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
{ | ||
@@ -46,8 +62,8 @@ ...binding, | ||
} | ||
}, | ||
null, { forceOverwrite: true } | ||
} | ||
) | ||
await copy(path.join(__dirname, 'files', 'destination.yaml'), path.join(this.projectPath, 'chart', 'templates', 'destination.yaml')) | ||
await copyAndTrack(join(__dirname, 'files', 'destination.yaml'), join(this.projectPath, 'chart', 'templates', 'destination.yaml'), context) | ||
if(isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData) | ||
} | ||
} | ||
} |
@@ -5,4 +5,3 @@ { | ||
"messaging": { | ||
"kind": "enterprise-messaging", | ||
"format": "cloudevents" | ||
"kind": "enterprise-messaging" | ||
} | ||
@@ -9,0 +8,0 @@ } |
{ | ||
"requires": { | ||
"messaging": { | ||
"kind": "enterprise-messaging", | ||
"format": "cloudevents" | ||
"kind": "enterprise-messaging" | ||
} | ||
} | ||
} |
@@ -1,5 +0,5 @@ | ||
const path = require('path') | ||
const { copy } = require('../../../cds').utils | ||
const { join } = require('path') | ||
const ProjectReader = require('../../util/projectReader') | ||
const { mergeJSON, mergeYAML } = require('../../util/merge') | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
const { srvNode, srvJava, enterpriseMessaging } = require('../_merging/registry-mta') | ||
@@ -20,6 +20,6 @@ | ||
const { for: forProfile, isNodejs } = projectDescriptor.cap | ||
const templatePath = path.join(__dirname, 'files') | ||
const templatePath = join(__dirname, 'files') | ||
const cdsTemplateFile = (isNodejs ? 'cds.package.json' : 'cdsrc.json') + (forProfile ? '.hbs' : '') | ||
const cdsTemplatePath = path.join(templatePath, cdsTemplateFile) | ||
const configPath = path.join(this.projectPath, isNodejs ? 'package.json' : '.cdsrc.json') | ||
const cdsTemplatePath = join(templatePath, cdsTemplateFile) | ||
const configPath = join(this.projectPath, isNodejs ? 'package.json' : '.cdsrc.json') | ||
await mergeJSON(configPath, cdsTemplatePath, projectDescriptor) | ||
@@ -29,3 +29,3 @@ await this.runDependentMerging() | ||
async runDependentMerging() { | ||
async runDependentMerging(context = {}) { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
@@ -35,3 +35,3 @@ const { hasHelm, hasMta, isNodejs } = projectDescriptor.cap | ||
if (hasMta) { | ||
const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml') | ||
const mtaYAMLPath = join(this.projectPath, 'mta.yaml') | ||
const srv = isNodejs ? srvNode : srvJava | ||
@@ -50,16 +50,29 @@ await mergeYAML( | ||
) | ||
await mergeJSON( | ||
join(this.projectPath, 'event-mesh.json'), | ||
join(__dirname, 'files', 'event-mesh.json.hbs'), | ||
projectDescriptor | ||
) | ||
} | ||
if (hasHelm) { | ||
//in case facet is being added to the already exisiting charts folder | ||
let isIndependentCommand = false | ||
if(Object.keys(context).length == 0){ | ||
isIndependentCommand = true | ||
context.projectPath = this.projectPath | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')) | ||
} | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'values.yaml'), | ||
path.join(__dirname, 'files', 'values.yaml'), | ||
null, { forceOverwrite: true } | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
join(__dirname, 'files', 'values.yaml') | ||
) | ||
await copy( | ||
path.join(__dirname, 'files', 'event-mesh.yaml'), | ||
path.join(this.projectPath, 'chart', 'templates', 'event-mesh.yaml') | ||
await copyAndTrack( | ||
join(__dirname, 'files', 'event-mesh.yaml'), | ||
join(this.projectPath, 'chart', 'templates', 'event-mesh.yaml'), | ||
context | ||
) | ||
if(isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData) | ||
} | ||
} | ||
} |
@@ -1,5 +0,5 @@ | ||
const cds = require('../../../cds') | ||
const { copy, path } = cds.utils | ||
const { join } = require('path') | ||
const ProjectReader = require('../../util/projectReader') | ||
const { mergeJSON } = require('../../util/merge') | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
@@ -19,9 +19,9 @@ module.exports = class ExtensibilityTemplate extends require('../templateBase') { | ||
const { for: forProfile, isJava } = projectDescriptor.cap | ||
const cdsConfigPath = path.join(this.projectPath, isJava ? '.cdsrc.json' : 'package.json') | ||
const cdsConfigPath = join(this.projectPath, isJava ? '.cdsrc.json' : 'package.json') | ||
const cdsTemplateFile = forProfile ? (isJava ? 'cdsrc.json.hbs' : 'cds.package.json.hbs') : (isJava ? 'cdsrc.json' : 'cds.package.json') | ||
await mergeJSON(cdsConfigPath, path.join(__dirname, 'files', cdsTemplateFile), projectDescriptor) | ||
await mergeJSON(cdsConfigPath, join(__dirname, 'files', cdsTemplateFile), projectDescriptor) | ||
await this.runDependentMerging() | ||
} | ||
async runDependentMerging() { | ||
async runDependentMerging(context = {}) { | ||
const projectDescriptor = await this.projectReader.read() | ||
@@ -31,4 +31,4 @@ const { hasXsuaa, hasHelm } = projectDescriptor.cap | ||
await mergeJSON( | ||
path.join(this.projectPath, 'xs-security.json'), | ||
path.join(__dirname, 'files', 'xs-security.json.hbs'), | ||
join(this.projectPath, 'xs-security.json'), | ||
join(__dirname, 'files', 'xs-security.json.hbs'), | ||
projectDescriptor, | ||
@@ -53,9 +53,18 @@ { | ||
if (hasXsuaa && hasHelm) { | ||
//in case facet is being added to the already exisiting charts folder | ||
let isIndependentCommand = false | ||
if(Object.keys(context).length == 0){ | ||
isIndependentCommand = true | ||
context.projectPath = this.projectPath | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')) | ||
} | ||
// REVISIT: Shared xs-security.json location for Helm and MTA? | ||
await copy( | ||
path.join(this.projectPath, 'xs-security.json'), | ||
path.join(this.projectPath, 'chart', 'xs-security.json') | ||
await copyAndTrack( | ||
join(this.projectPath, 'xs-security.json'), | ||
join(this.projectPath, 'chart', 'xs-security.json'), | ||
context | ||
) | ||
if(isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData) | ||
} | ||
} | ||
} |
@@ -1,8 +0,9 @@ | ||
const path = require('path'); | ||
const { join } = require('path'); | ||
const cds = require('../../../cds') | ||
const { fs, read, write } = cds.utils | ||
const { read, write, exists, rm } = cds.utils | ||
const commandUtil = require('../../util/commandUtil'); | ||
const mvnArchetypes = require('../../util/mvnArchetypeUtil'); | ||
const term = require('../../../util/term'); | ||
const { mergeJSON, mergeYAML } = require('../../util/merge') | ||
const { mergeJSON, mergeYAML, removeFromYAML } = require('../../util/merge') | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
const { copyFiles } = require('../../util/templateUtil') | ||
@@ -37,8 +38,8 @@ const ProjectReader = require('../../util/projectReader'); | ||
const hdiConfigPath = path.join(this.projectPath, env.folders.db, 'src', '.hdiconfig'); | ||
const hdiConfigTemplatePath = path.join(__dirname, 'files', 'common', 'src', '.hdiconfig'); | ||
const hdiConfigPath = join(this.projectPath, env.folders.db, 'src', '.hdiconfig'); | ||
const hdiConfigTemplatePath = join(__dirname, 'files', 'common', 'src', '.hdiconfig'); | ||
await mergeJSON(hdiConfigPath, hdiConfigTemplatePath); | ||
const undeployJSONPath = path.join(this.projectPath, env.folders.db, 'undeploy.json'); | ||
const undeployJSONTemplatePath = path.join(__dirname, 'files', 'common', 'undeploy.json'); | ||
const undeployJSONPath = join(this.projectPath, env.folders.db, 'undeploy.json'); | ||
const undeployJSONTemplatePath = join(__dirname, 'files', 'common', 'undeploy.json'); | ||
await mergeJSON(undeployJSONPath, undeployJSONTemplatePath); | ||
@@ -49,3 +50,3 @@ | ||
case PROJECT_TYPE.java: { | ||
await copyFiles(path.join(__dirname, 'files', 'java', 'db'), path.join(this.projectPath, env.folders.db), {}, this.options.force); | ||
await copyFiles(join(__dirname, 'files', 'java', 'db'), join(this.projectPath, env.folders.db), {}, this.options.force); | ||
await this._updatePomXml(); | ||
@@ -65,3 +66,3 @@ await this._updateCdsConfiguration(); | ||
async runDependentMerging() { | ||
async runDependentMerging(context = {}) { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
@@ -91,3 +92,3 @@ const { hasMta, hasHelm, isNodejs, isJava, isMultitenant } = projectDescriptor.cap | ||
const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml') | ||
const mtaYAMLPath = join(this.projectPath, 'mta.yaml') | ||
@@ -124,10 +125,45 @@ const relationships = [{ | ||
if (hasHelm) { | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'values.yaml'), | ||
path.join(__dirname, 'files', 'values.yaml.hbs'), | ||
projectDescriptor, { forceOverwrite: true }) | ||
await fs.copy( | ||
path.join(__dirname, 'files', 'hana-deployer-job.yaml'), | ||
path.join(this.projectPath, 'chart', 'templates', 'hana-deployer-job.yaml') | ||
) | ||
//in case facet is being added to the already exisiting charts folder | ||
let shouldUpdateTrackingFile = false; | ||
if(Object.keys(context).length == 0){ | ||
shouldUpdateTrackingFile = true; | ||
context.projectPath = this.projectPath; | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')); | ||
} | ||
if(isMultitenant){ | ||
shouldUpdateTrackingFile = true; | ||
const key = "templates/hana-deployer-job.yaml"; | ||
// remove entry from oldTrackingData | ||
if(context.oldTrackingData !== undefined && context.oldTrackingData[key] !== undefined) { | ||
delete context.oldTrackingData[key]; | ||
} | ||
// remove entry from newTrackingData | ||
if(context.newTrackingData !== undefined && context.newTrackingData[key] !== undefined) { | ||
delete context.newTrackingData[key]; | ||
} | ||
// remove hana entries from values.yaml | ||
await removeFromYAML(join(this.projectPath, 'chart', 'values.yaml'), ['hana_deployer', 'srv.bindings.db']); | ||
const hanaDeployerPath = join(this.projectPath, 'chart', 'templates', 'hana-deployer-job.yaml'); | ||
if(exists(hanaDeployerPath)) { | ||
await rm(hanaDeployerPath, { force: true }); | ||
} | ||
} | ||
else{ | ||
await mergeYAML( | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
join(__dirname, 'files', 'values.yaml.hbs'), | ||
projectDescriptor | ||
) | ||
await copyAndTrack( | ||
join(__dirname, 'files', 'hana-deployer-job.yaml'), | ||
join(this.projectPath, 'chart', 'templates', 'hana-deployer-job.yaml'), | ||
context | ||
) | ||
} | ||
if(shouldUpdateTrackingFile) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData); | ||
} | ||
@@ -154,4 +190,4 @@ } | ||
async _updatePackageJson() { | ||
const packageJsonPath = path.join(this.projectPath, 'package.json') | ||
const dependenciesTemplatePath = path.join(__dirname, 'files', 'nodejs', 'dependencies.package.json'); | ||
const packageJsonPath = join(this.projectPath, 'package.json') | ||
const dependenciesTemplatePath = join(__dirname, 'files', 'nodejs', 'dependencies.package.json'); | ||
await mergeJSON(packageJsonPath, dependenciesTemplatePath); | ||
@@ -171,3 +207,3 @@ | ||
const configFile = projectType === PROJECT_TYPE.nodejs ? 'package.json' : '.cdsrc.json'; | ||
configPath = configPath ?? path.join(this.projectPath, configFile) | ||
configPath = configPath ?? join(this.projectPath, configFile) | ||
const projectDescriptor = await this.projectReader.read(this.options); | ||
@@ -181,5 +217,5 @@ const { for: forProfile } = projectDescriptor.cap; | ||
const { pLanguage } = projectDescriptor.cap; | ||
const cdsTemplatePath = path.join(__dirname, 'files', pLanguage, cdsTemplateFile); | ||
const cdsTemplatePath = join(__dirname, 'files', pLanguage, cdsTemplateFile); | ||
await mergeJSON(configPath, cdsTemplatePath, projectDescriptor, { forceOverwrite: true }) | ||
} | ||
} |
@@ -1,4 +0,4 @@ | ||
Thank you for installing {{ .Chart.Name }} version {{ .Chart.Version }}. | ||
{{- printf "Thank you for installing %s version %s." .Chart.Name .Chart.Version }} | ||
The release "{{ .Release.Name }}" is installed in namespace "{{ .Release.Namespace }}". | ||
{{ printf "The release %s is installed in namespace %s." .Release.Name .Release.Namespace }} | ||
@@ -10,3 +10,4 @@ Your services are available at: | ||
{{- $ := merge (dict "name" $name "deployment" $deployment) $root }} | ||
- https://{{ include "cap.deploymentHostFull" $ }} | ||
{{- $url := include "cap.deploymentHostFull" $ }} | ||
{{ printf "%s - https://%s" $name $url }} | ||
{{- end }} |
@@ -9,4 +9,9 @@ { | ||
"$ref": "./charts/web-application/values.schema.json" | ||
}, | ||
"approuter": { | ||
"$id": "#/properties/approuter", | ||
"description": "Deployment", | ||
"$ref": "./charts/web-application/values.schema.json" | ||
} | ||
} | ||
} |
@@ -45,2 +45,29 @@ { | ||
}, | ||
"approuter": { | ||
"$id": "#/properties/approuter", | ||
"description": "Deployment" | ||
}, | ||
"approuterDestinations": { | ||
"$id": "#/properties/approuterDestinations", | ||
"title": "Backend Destinations for Approuter", | ||
"type": "object", | ||
"patternProperties": { | ||
"^[-._a-zA-Z][-._a-zA-Z0-9]*$": { | ||
"description": "Name of the backend Destination", | ||
"required": [ | ||
"service" | ||
], | ||
"properties": { | ||
"service": { | ||
"type": "string", | ||
"description": "Target Kubernetes service" | ||
}, | ||
"path": { | ||
"type": "string", | ||
"description": "This path will be appended to the URL" | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"auditlog": { | ||
@@ -47,0 +74,0 @@ "$id": "#/properties/auditlog", |
@@ -1,5 +0,6 @@ | ||
const path = require('path'); | ||
const { exists, read, copy, rimraf } = require('../../../cds').utils; | ||
const { join } = require('path'); | ||
const { exists, read, rimraf } = require('../../../cds').utils; | ||
const ProjectReader = require('../../util/projectReader'); | ||
const { mergeYAML } = require('../../util/merge') | ||
const { parseMd5File, writeMd5File, copyAndTrack } = require('../../util/md5Tracking') | ||
//const { yaml } = require('@sap/cds-foss') | ||
@@ -11,2 +12,4 @@ | ||
this.projectReader = new ProjectReader(projectPath); | ||
this.oldTrackingData = undefined; | ||
this.newTrackingData = {}; | ||
} | ||
@@ -17,3 +20,3 @@ | ||
if (options?.add.has('mta') && !options?.add.has('helm')) return false | ||
return exists(path.join(projectPath, 'chart', 'values.yaml')) | ||
return exists(join(projectPath, 'chart', 'values.yaml')) | ||
} | ||
@@ -23,3 +26,3 @@ | ||
if (this.options.force) { | ||
await rimraf(path.join(this.projectPath, 'chart')) | ||
await rimraf(join(this.projectPath, 'chart')) | ||
return true; | ||
@@ -32,29 +35,28 @@ } | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
this.oldTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')); | ||
await copy( | ||
path.join(__dirname, 'subchart'), | ||
path.join(this.projectPath, 'chart', 'charts', 'web-application'), | ||
await copyAndTrack( | ||
join(__dirname, 'subchart'), | ||
join(this.projectPath, 'chart', 'charts', 'web-application'), | ||
this | ||
) | ||
await copy( | ||
path.join(__dirname, 'chart'), | ||
path.join(this.projectPath, 'chart') | ||
await copyAndTrack( | ||
join(__dirname, 'chart'), | ||
join(this.projectPath, 'chart'), | ||
this | ||
) | ||
const webApplicationChartPath = process.env.WEB_APPLICATION_CHART ?? path.join(__dirname, 'subchart') | ||
const chartFilePath = path.join(webApplicationChartPath, 'Chart.yaml') | ||
const chartFile = await read(chartFilePath) | ||
//const { version } = yaml.parse(chartFile) | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'Chart.yaml'), | ||
path.join(__dirname, 'files', 'Chart.yaml.hbs'), | ||
projectDescriptor, { forceOverwrite: true } | ||
join(this.projectPath, 'chart', 'Chart.yaml'), | ||
join(__dirname, 'files', 'Chart.yaml.hbs'), | ||
projectDescriptor | ||
) | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'values.yaml'), | ||
path.join(__dirname, 'files', 'values.yaml.hbs'), | ||
projectDescriptor, { forceOverwrite: true } | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
join(__dirname, 'files', 'values.yaml.hbs'), | ||
projectDescriptor | ||
) | ||
await this.runDependentMerging(); | ||
await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), this.newTrackingData); | ||
} | ||
@@ -64,9 +66,9 @@ | ||
// Re-applying the dependent merging part of other facets if necessary. | ||
const dependentFacets = ['hana', 'xsuaa', 'auditlog', 'enterprise-messaging', 'destinations' , 'multitenancy', 'extensibility'] | ||
const dependentFacets = ['hana', 'xsuaa', 'auditlog', 'enterprise-messaging', 'destinations' , 'multitenancy', 'extensibility', 'approuter'] | ||
for (const facet of dependentFacets) { | ||
const Template = require('../'+facet) | ||
const template = new Template(this.projectPath, this.generator) | ||
if (Template.hasFacet(await this.getEnv(), this.projectPath, this.options)) await template.runDependentMerging() | ||
if (Template.hasFacet(await this.getEnv(), this.projectPath, this.options)) await template.runDependentMerging(this) | ||
} | ||
} | ||
}; |
@@ -313,2 +313,3 @@ { | ||
"title": "Health-check configuration", | ||
"description": "[Deprecated] Use health instead", | ||
"type": "object", | ||
@@ -325,4 +326,3 @@ "additionalProperties": false, | ||
"description": "HTTP path used by Kubernetes, to perform health-check calls.", | ||
"type": "string", | ||
"default": "/healthz" | ||
"type": "string" | ||
} | ||
@@ -339,2 +339,22 @@ } | ||
"description": "HTTP path used by Kubernetes, to perform health-check calls.", | ||
"type": "string" | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"health": { | ||
"$id": "#/properties/health", | ||
"title": "Health-check configuration", | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"liveness": { | ||
"$id": "#/properties/health/properties/liveness", | ||
"description": "Liveness-probe configuration.", | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"path": { | ||
"description": "HTTP path used by Kubernetes, to perform liveness-probe calls.", | ||
"type": "string", | ||
@@ -344,2 +364,15 @@ "default": "/healthz" | ||
} | ||
}, | ||
"readiness": { | ||
"$id": "#/properties/health/properties/readiness", | ||
"description": "Readiness-probe configuration.", | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"path": { | ||
"description": "HTTP path used by Kubernetes, to perform readiness-probe calls.", | ||
"type": "string", | ||
"default": "/healthz" | ||
} | ||
} | ||
} | ||
@@ -367,6 +400,3 @@ } | ||
"description": "Plain value of an environment variable.", | ||
"type": [ | ||
"integer", | ||
"string" | ||
] | ||
"type": ["integer", "string"] | ||
}, | ||
@@ -459,6 +489,3 @@ { | ||
"value": { | ||
"type": [ | ||
"string", | ||
"integer" | ||
] | ||
"type": ["string", "integer"] | ||
}, | ||
@@ -529,3 +556,3 @@ "configMapKeyRef": { | ||
"$id": "#/properties/envSecretNames", | ||
"description": "List of Kubernetes Secret names, used as sources for the Pod's environment variables.", | ||
"description": "[Deprecated] Use `envFrom` instead", | ||
"type": "array", | ||
@@ -535,5 +562,61 @@ "uniqueItems": true, | ||
"$ref": "#/definitions/KubernetesName" | ||
}, | ||
"default": [] | ||
} | ||
}, | ||
"envFrom": { | ||
"$id": "#/properties/envFrom", | ||
"description": "List of sources to populate environment variables in the pod.", | ||
"type": "array", | ||
"default": [], | ||
"items": { | ||
"type": "object", | ||
"oneOf": [ | ||
{ | ||
"additionalProperties": false, | ||
"properties": { | ||
"configMapRef": { | ||
"description": "The contents of the target ConfigMap's Data field will represent the key-value pairs as environment variables.", | ||
"properties": { | ||
"name": { | ||
"description": "Name of a ConfigMap.", | ||
"type": "string" | ||
}, | ||
"tpl": { | ||
"description": "Flag which tells whether the name is a template string or not.", | ||
"type": "boolean", | ||
"default": false | ||
} | ||
}, | ||
"required": [ "name" ], | ||
"additionalProperties": false, | ||
"type": "object" | ||
} | ||
}, | ||
"required": [ "configMapRef" ] | ||
}, | ||
{ | ||
"additionalProperties": false, | ||
"properties": { | ||
"secretRef": { | ||
"description": "The contents of the target Secret's Data field will represent the key-value pairs as environment variables.", | ||
"properties": { | ||
"name": { | ||
"description": "Name of a Secret.", | ||
"type": "string" | ||
}, | ||
"tpl": { | ||
"description": "Flag which tells whether the name is a template string or not.", | ||
"type": "boolean", | ||
"default": false | ||
} | ||
}, | ||
"required": [ "name" ], | ||
"additionalProperties": false, | ||
"type": "object" | ||
} | ||
}, | ||
"required": [ "secretRef" ] | ||
} | ||
] | ||
} | ||
}, | ||
"expose": { | ||
@@ -540,0 +623,0 @@ "$id": "#/properties/expose", |
@@ -1,5 +0,6 @@ | ||
const path = require('path') | ||
const { exists, copy } = require('../../../cds').utils | ||
const { join } = require('path') | ||
const { exists } = require('../../../cds').utils | ||
const ProjectReader = require('../../util/projectReader') | ||
const { mergeYAML } = require('../../util/merge') | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
const { OPTION_DESTINATIONS } = require('../../constants') | ||
@@ -13,9 +14,18 @@ | ||
async getDependencies() { | ||
getDependencies() { | ||
return [OPTION_DESTINATIONS] | ||
} | ||
async canRun() { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
const { hasMta, hasHelm } = projectDescriptor.cap | ||
if (!hasHelm && hasMta) { | ||
throw `'cds add html5-repo' is not available for Cloud Foundry yet` | ||
} | ||
return true | ||
} | ||
static hasFacet(_, projectPath) { | ||
// REVISIT: Should be detectable without helm charts | ||
return exists(path.join(projectPath, 'chart', 'templates', 'html5-apps-repo-host.yaml')) | ||
return exists(join(projectPath, 'chart', 'templates', 'html5-apps-repo-host.yaml')) | ||
} | ||
@@ -27,3 +37,3 @@ | ||
async runDependentMerging() { | ||
async runDependentMerging(context = {}) { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
@@ -33,4 +43,11 @@ const { appName, hasHelm } = projectDescriptor.cap | ||
if (hasHelm) { | ||
//in case facet is being added to the already exisiting charts folder | ||
let isIndependentCommand = false | ||
if(Object.keys(context).length == 0){ | ||
isIndependentCommand = true | ||
context.projectPath = this.projectPath | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')) | ||
} | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'values.yaml'), | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
{ | ||
@@ -58,10 +75,10 @@ html5_apps_repo_host: { | ||
} | ||
}, | ||
null, { forceOverwrite: true } | ||
} | ||
) | ||
await copy(path.join(__dirname, 'files', '_html5_deployment_helpers.tpl'), path.join(this.projectPath, 'chart', 'templates', '_html5_deployment_helpers.tpl')) | ||
await copy(path.join(__dirname, 'files', 'html5-apps-deployer-job.yaml'), path.join(this.projectPath, 'chart', 'templates', 'html5-apps-deployer-job.yaml')) | ||
await copy(path.join(__dirname, 'files', 'html5-apps-repo-host.yaml'), path.join(this.projectPath, 'chart', 'templates', 'html5-apps-repo-host.yaml')) | ||
await copyAndTrack(join(__dirname, 'files', '_html5_deployment_helpers.tpl'), join(this.projectPath, 'chart', 'templates', '_html5_deployment_helpers.tpl'), context) | ||
await copyAndTrack(join(__dirname, 'files', 'html5-apps-deployer-job.yaml'), join(this.projectPath, 'chart', 'templates', 'html5-apps-deployer-job.yaml'), context) | ||
await copyAndTrack(join(__dirname, 'files', 'html5-apps-repo-host.yaml'), join(this.projectPath, 'chart', 'templates', 'html5-apps-repo-host.yaml'), context) | ||
if(isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData) | ||
} | ||
} | ||
} |
const fs = require('fs').promises; | ||
const os = require('os'); | ||
const path = require('path'); | ||
const { join, relative } = require('path'); | ||
@@ -20,3 +20,3 @@ const commandUtil = require('../../util/commandUtil'); | ||
static hasFacet(_, projectPath) { | ||
return exists(path.join(projectPath, 'pom.xml')) | ||
return exists(join(projectPath, 'pom.xml')) | ||
} | ||
@@ -42,3 +42,3 @@ | ||
const tempFolder = await fs.mkdtemp(path.join(os.tmpdir(), `${this.projectName}_`)); | ||
const tempFolder = await fs.mkdtemp(join(os.tmpdir(), `${this.projectName}_`)); | ||
try { | ||
@@ -49,3 +49,3 @@ await commandUtil.spawnCommand('mvn', cmdLine, { | ||
await copy(path.join(tempFolder, artifactId), this.projectPath); | ||
await copy(join(tempFolder, artifactId), this.projectPath); | ||
} catch (err) { | ||
@@ -62,3 +62,3 @@ if (err.code === 'ENOENT' && err.path === 'mvn') { | ||
async finalize() { | ||
const relativeProjectPath = path.relative(this.cwd, this.projectPath); | ||
const relativeProjectPath = relative(this.cwd, this.projectPath); | ||
if (relativeProjectPath && relativeProjectPath !== '.') { | ||
@@ -65,0 +65,0 @@ LOG.info(`Continue with 'cd ${relativeProjectPath}'`); |
@@ -1,2 +0,2 @@ | ||
const path = require('path') | ||
const { join } = require('path') | ||
const cds = require('../../../cds') | ||
@@ -20,2 +20,3 @@ const ProjectReader = require('../../util/projectReader') | ||
} | ||
return true | ||
} | ||
@@ -36,4 +37,4 @@ | ||
const cdsTemplateFile = forProfile ? 'cds.profile.package.json.hbs' : 'cds.package.json' | ||
const cdsTemplatePath = path.join(__dirname, 'files', cdsTemplateFile) | ||
await mergeJSON(path.join(this.projectPath, 'package.json'), cdsTemplatePath, projectDescriptor) | ||
const cdsTemplatePath = join(__dirname, 'files', cdsTemplateFile) | ||
await mergeJSON(join(this.projectPath, 'package.json'), cdsTemplatePath, projectDescriptor) | ||
} | ||
@@ -51,3 +52,3 @@ } | ||
const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml') | ||
const mtaYAMLPath = join(this.projectPath, 'mta.yaml') | ||
await mergeYAML( | ||
@@ -54,0 +55,0 @@ mtaYAMLPath, |
const { join } = require('path'); | ||
const { exists, path } = require('../../../cds').utils | ||
const { exists } = require('../../../cds').utils | ||
const { copyFiles } = require('../../util/templateUtil') | ||
@@ -20,3 +20,3 @@ const ProjectReader = require('../../util/projectReader'); | ||
if (!exists(join(this.projectPath, 'mta.yaml'))) { | ||
await copyFiles(path.join(__dirname, 'files'), this.projectPath, projectDescriptor); | ||
await copyFiles(join(__dirname, 'files'), this.projectPath, projectDescriptor); | ||
} | ||
@@ -23,0 +23,0 @@ |
@@ -10,5 +10,5 @@ const ProjectReader = require('../../util/projectReader') | ||
async getDependencies() { | ||
getDependencies() { | ||
return [OPTION_MULTITENANCY, OPTION_TOGGLES, OPTION_EXTENSIBILITY] | ||
} | ||
} |
{ | ||
"name": "cap-mtx-sidecar", | ||
"dependencies": { | ||
"@sap/cds": "^6.0.2", | ||
"@sap/cds-mtxs": "^1.0.1", | ||
"@sap/hdi-deploy": "^4.4.1", | ||
"@sap/xssec": "^3.2.13", | ||
"express": "^4.18.1", | ||
"hdb": "^0.19.3", | ||
"@sap/cds": "^6.3.1", | ||
"@sap/cds-mtxs": "^1.3.1", | ||
"@sap/hdi-deploy": "^4.5.1", | ||
"@sap/xssec": "^3.2.14", | ||
"express": "^4.18.2", | ||
"hdb": "^0.19.5", | ||
"passport": "^0.6.0" | ||
@@ -16,5 +16,2 @@ }, | ||
}, | ||
"engines": { | ||
"node": "^16.15.0" | ||
}, | ||
"cds": { | ||
@@ -21,0 +18,0 @@ "requires": { |
@@ -0,5 +1,7 @@ | ||
const { join } = require('path') | ||
const cds = require('../../../cds') | ||
const { path, copy, exists } = cds.utils | ||
const { copy, exists } = cds.utils | ||
const ProjectReader = require('../../util/projectReader') | ||
const { mergeJSON, mergeYAML, sortDependencies } = require('../../util/merge') | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
const { | ||
@@ -22,3 +24,3 @@ srvNode, srvJava, // Server | ||
!!env.requires?.multitenancy || !!env.requires?.db?.multiTenant || | ||
this.isJava && exists(path.join(projectPath, 'mtx', 'sidecar')) || false | ||
this.isJava && exists(join(projectPath, 'mtx', 'sidecar')) || false | ||
} | ||
@@ -30,11 +32,11 @@ | ||
if (isNodejs) { | ||
const packageJSONPath = path.join(this.projectPath, 'package.json') | ||
const packageJSONPath = join(this.projectPath, 'package.json') | ||
const cdsTemplateFile = forProfile ? 'cds.package.json.hbs' : 'cds.package.json' | ||
await mergeJSON(packageJSONPath, path.join(__dirname, 'files', cdsTemplateFile), projectDescriptor) | ||
await mergeJSON(packageJSONPath, path.join(__dirname, 'files', 'dependencies.package.json')) | ||
await mergeJSON(packageJSONPath, join(__dirname, 'files', cdsTemplateFile), projectDescriptor) | ||
await mergeJSON(packageJSONPath, join(__dirname, 'files', 'dependencies.package.json')) | ||
await sortDependencies(packageJSONPath) | ||
} else if (isJava) { | ||
const cdsrcJSONPath = path.join(this.projectPath, '.cdsrc.json') | ||
await mergeJSON(cdsrcJSONPath, path.join(__dirname, 'files', 'java', '.cdsrc.json')) | ||
await copy(path.join(__dirname, 'files', 'java', 'package.json'), path.join(this.projectPath, 'mtx', 'sidecar', 'package.json')) | ||
const cdsrcJSONPath = join(this.projectPath, '.cdsrc.json') | ||
await mergeJSON(cdsrcJSONPath, join(__dirname, 'files', 'java', '.cdsrc.json')) | ||
await copy(join(__dirname, 'files', 'java', 'package.json'), join(this.projectPath, 'mtx', 'sidecar', 'package.json')) | ||
} | ||
@@ -44,3 +46,3 @@ await this.runDependentMerging() | ||
async runDependentMerging() { | ||
async runDependentMerging(context = {}) { | ||
const projectDescriptor = await this.projectReader.read() | ||
@@ -72,4 +74,4 @@ const { isNodejs, isJava, hasMta, hasHelm, hasApprouter, hasXsuaa, hasHana } = projectDescriptor.cap | ||
relationships.push({ | ||
insert: [serviceManager, 'name'], | ||
into: [mtxSidecar, 'requires', 'name'], | ||
insert: [serviceManager, 'name'], | ||
into: [mtxSidecar, 'requires', 'name'], | ||
}) | ||
@@ -79,4 +81,4 @@ } | ||
const templateMtaPath = path.join(__dirname, `files`, `mta.yaml.hbs`) | ||
const mtaPath = path.join(this.projectPath, 'mta.yaml') | ||
const templateMtaPath = join(__dirname, `files`, `mta.yaml.hbs`) | ||
const mtaPath = join(this.projectPath, 'mta.yaml') | ||
const mergingRules = { additions, overwrites, relationships } | ||
@@ -86,23 +88,69 @@ await mergeYAML(mtaPath, templateMtaPath, projectDescriptor, mergingRules) | ||
let isIndependentCommand = false | ||
if (hasHelm) { | ||
//in case facet is being added to the already exisiting charts folder | ||
if (Object.keys(context).length == 0) { | ||
isIndependentCommand = true | ||
context.projectPath = this.projectPath | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')) | ||
} | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'values.yaml'), | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
join(__dirname, 'files', 'values.yaml.hbs'), | ||
projectDescriptor | ||
) | ||
await mergeYAML( | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
{ | ||
xsuaa: { | ||
serviceOfferingName: 'saas-registry', | ||
servicePlanName: 'application' | ||
srv: { | ||
envFrom: [ | ||
{ | ||
configMapRef: { | ||
name: "{{ .Release.Name }}-mtxs-configmap", | ||
tpl: true | ||
} | ||
} | ||
] | ||
} | ||
}, | ||
null, { forceOverwrite: true } | ||
projectDescriptor | ||
) | ||
//if (hasXsuaa) { // REVISIT: Can we get rid of this dependency? | ||
await copy( | ||
path.join(__dirname, 'files', 'xsuaa.yaml'), | ||
path.join(this.projectPath, 'chart', 'templates', 'xsuaa.yaml') | ||
if (isJava) { | ||
await mergeYAML( | ||
join(this.projectPath, 'chart', 'Chart.yaml'), | ||
join(__dirname, 'files', 'chart.yaml'), | ||
projectDescriptor, | ||
{ | ||
additions: [{ | ||
ref: `web-application-sidecar`, | ||
in: `dependencies`, | ||
where: [{ | ||
property: 'alias', | ||
isEqualTo: 'sidecar' | ||
}] | ||
}] | ||
} | ||
) | ||
//} | ||
await copy( | ||
path.join(__dirname, 'files', 'saas-registry.yaml'), | ||
path.join(this.projectPath, 'chart', 'templates', 'saas-registry.yaml') | ||
} | ||
const mtxsConfigmapPath = isNodejs | ||
? join(__dirname, 'files', 'mtxs-configmap.yaml') | ||
: join(__dirname, 'files', 'java', 'mtxs-configmap.yaml'); | ||
// add mtxs configmap | ||
await copyAndTrack( | ||
mtxsConfigmapPath, | ||
join(this.projectPath, 'chart', 'templates', 'mtxs-configmap.yaml'), | ||
context | ||
) | ||
await copyAndTrack( | ||
join(__dirname, 'files', 'saas-registry.yaml'), | ||
join(this.projectPath, 'chart', 'templates', 'saas-registry.yaml'), | ||
context | ||
) | ||
if (isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData) | ||
} | ||
@@ -113,3 +161,3 @@ | ||
const template = new ApprouterTemplate(this.projectPath, this.generator) | ||
await template.runDependentMerging() | ||
await template.runDependentMerging(context) | ||
} | ||
@@ -120,3 +168,3 @@ | ||
const template = new HanaTemplate(this.projectPath, this.generator) | ||
await template.runDependentMerging() | ||
await template.runDependentMerging(context) | ||
} | ||
@@ -126,4 +174,4 @@ | ||
await mergeJSON( | ||
path.join(this.projectPath, 'xs-security.json'), | ||
path.join(__dirname, 'files', 'xs-security.json.hbs'), | ||
join(this.projectPath, 'xs-security.json'), | ||
join(__dirname, 'files', 'xs-security.json.hbs'), | ||
projectDescriptor, | ||
@@ -135,6 +183,2 @@ { | ||
where: [{ property: 'name', isEqualTo: '$XSAPPNAME.mtcallback' }], | ||
}, { | ||
ref: 'scope-subscriber', | ||
in: 'scopes', | ||
where: [{ property: 'name', isEqualTo: '$XSAPPNAME.cds.Subscriber' }], | ||
}] | ||
@@ -147,8 +191,10 @@ } | ||
// REVISIT: Shared xs-security.json location for Helm and MTA? | ||
await copy( | ||
path.join(this.projectPath, 'xs-security.json'), | ||
path.join(this.projectPath, 'chart', 'xs-security.json') | ||
await copyAndTrack( | ||
join(this.projectPath, 'xs-security.json'), | ||
join(this.projectPath, 'chart', 'xs-security.json'), | ||
context | ||
) | ||
if (isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData) | ||
} | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
const path = require('path'); | ||
const { join, relative } = require('path'); | ||
const { mkdirp } = require('../../../cds').utils | ||
@@ -31,15 +31,12 @@ const { COMMAND_ADD, OPTION_JAVA, OPTION_NODEJS, URLS } = require('../../constants') | ||
const env = await this.getEnv(); | ||
const { projectPath, projectName } = this | ||
await copyFiles(join(__dirname, 'files'), projectPath, { projectName }, this.options.force) | ||
const values = { | ||
projectName: this.projectName | ||
} | ||
await copyFiles(path.join(__dirname, 'files'), this.projectPath, values, this.options.force) | ||
await mkdirp(this.projectPath, env.folders.db); | ||
await mkdirp(this.projectPath, env.folders.srv); | ||
await mkdirp(this.projectPath, env.folders.app); | ||
await mkdirp(projectPath, env.folders.db); | ||
await mkdirp(projectPath, env.folders.srv); | ||
await mkdirp(projectPath, env.folders.app); | ||
} | ||
async finalize() { | ||
const relativeProjectPath = path.relative(this.cwd, this.projectPath); | ||
const relativeProjectPath = relative(this.cwd, this.projectPath); | ||
if (relativeProjectPath && relativeProjectPath !== '.') { | ||
@@ -46,0 +43,0 @@ LOG.info(`Continue with 'cd ${relativeProjectPath}'`); |
@@ -1,2 +0,2 @@ | ||
const path = require('path'); | ||
const { join } = require('path'); | ||
const { exists } = require('../../../cds').utils | ||
@@ -17,4 +17,4 @@ const { copyFiles } = require('../../util/templateUtil') | ||
if (exists(path.join(this.projectPath, 'Jenkinsfile')) || | ||
exists(path.join(this.projectPath, '.pipeline/config.yml'))) { | ||
if (exists(join(this.projectPath, 'Jenkinsfile')) || | ||
exists(join(this.projectPath, '.pipeline/config.yml'))) { | ||
throw new Error(`Pipeline support file exists. Use --force to overwrite.`); | ||
@@ -27,3 +27,3 @@ } | ||
async run() { | ||
await copyFiles(path.join(__dirname, 'files'), this.projectPath, {}, this.options.force); | ||
await copyFiles(join(__dirname, 'files'), this.projectPath, {}, this.options.force); | ||
} | ||
@@ -30,0 +30,0 @@ |
@@ -1,2 +0,2 @@ | ||
const path = require('path'); | ||
const { join } = require('path'); | ||
const { copyFiles } = require('../../util/templateUtil') | ||
@@ -53,7 +53,7 @@ const commandUtil = require('../../util/commandUtil'); | ||
const folders = (await this.getEnv()).folders; | ||
const dbFolder = path.join(this.projectPath, folders.db); | ||
await copyFiles(path.join(__dirname, 'files', 'nodejs', 'db'), dbFolder, {}, this.options.force); | ||
const dbFolder = join(this.projectPath, folders.db); | ||
await copyFiles(join(__dirname, 'files', 'nodejs', 'db'), dbFolder, {}, this.options.force); | ||
const srvFolder = path.join(this.projectPath, folders.srv); | ||
await copyFiles(path.join(__dirname, 'files', 'nodejs', 'srv'), srvFolder, { | ||
const srvFolder = join(this.projectPath, folders.srv); | ||
await copyFiles(join(__dirname, 'files', 'nodejs', 'srv'), srvFolder, { | ||
dbFolder: folders.db.replace(/[\\/]+$/, '') | ||
@@ -60,0 +60,0 @@ }, this.options.force); |
const cds = require('../../cds'); | ||
const path = require('path'); | ||
const TemplateUtil = require('../util/templateUtil'); | ||
const { PROJECT_TYPE } = require('../constants'); | ||
@@ -30,6 +28,5 @@ const { exists } = require('../../cds').utils; | ||
* Returns an array of required templates. These templates will also be added if not already included. | ||
* Declared async to allow complex calculation of the dependencies. | ||
* @returns an array with depending templates, might be empty or null | ||
*/ | ||
async getDependencies() { | ||
getDependencies() { | ||
} | ||
@@ -36,0 +33,0 @@ |
@@ -1,2 +0,2 @@ | ||
const cds = require('../../../cds'), { path } = cds.utils | ||
const { join } = require('path') | ||
const ProjectReader = require('../../util/projectReader') | ||
@@ -19,9 +19,9 @@ const { mergeJSON, sortDependencies } = require('../../util/merge') | ||
if (isNodejs) { | ||
const packageJSONPath = path.join(this.projectPath, 'package.json') | ||
const packageJSONPath = join(this.projectPath, 'package.json') | ||
const cdsTemplateFile = forProfile ? 'cds.package.json.hbs' : 'cds.package.json' | ||
await mergeJSON(packageJSONPath, path.join(__dirname, 'files', cdsTemplateFile), projectDescriptor) | ||
await mergeJSON(packageJSONPath, join(__dirname, 'files', cdsTemplateFile), projectDescriptor) | ||
await sortDependencies(packageJSONPath) | ||
} else if (isJava) { | ||
const cdsrcPath = path.join(this.projectPath, '.cdsrc.json') | ||
const cdsTemplateFile = path.join(__dirname, 'files', forProfile ? 'cdsrc.json.hbs' : 'cdsrc.json') | ||
const cdsrcPath = join(this.projectPath, '.cdsrc.json') | ||
const cdsTemplateFile = join(__dirname, 'files', forProfile ? 'cdsrc.json.hbs' : 'cdsrc.json') | ||
await mergeJSON(cdsrcPath, cdsTemplateFile, projectDescriptor) | ||
@@ -28,0 +28,0 @@ } |
@@ -1,6 +0,5 @@ | ||
const path = require('path') | ||
const cds = require('../../../cds') | ||
const { copy } = cds.utils | ||
const { join } = require('path') | ||
const ProjectReader = require('../../util/projectReader') | ||
const { mergeJSON, mergeYAML } = require('../../util/merge') | ||
const { copyAndTrack, parseMd5File, writeMd5File } = require('../../util/md5Tracking') | ||
const { srvNode, srvJava, xsuaa, mtxSidecar } = require('../_merging/registry-mta') | ||
@@ -21,3 +20,3 @@ const { PROJECT_TYPE } = require('../../constants') | ||
const { projectPath } = this | ||
const templatePath = path.join(__dirname, 'files') | ||
const templatePath = join(__dirname, 'files') | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
@@ -28,12 +27,12 @@ const projectType = await this.getProjectType(); | ||
if (projectType === PROJECT_TYPE.java) { | ||
const cdsrcJSONPath = path.join(projectPath, '.cdsrc.json') | ||
const cdsrcJSONPath = join(projectPath, '.cdsrc.json') | ||
const cdsTemplateFile = forProfile ? 'cds.cdsrc.json.hbs' : 'cds.cdsrc.json' | ||
const cdsTemplatePath = path.join(templatePath, cdsTemplateFile) | ||
const cdsTemplatePath = join(templatePath, cdsTemplateFile) | ||
await mergeJSON(cdsrcJSONPath, cdsTemplatePath, projectDescriptor) | ||
} else if (projectType === PROJECT_TYPE.nodejs) { | ||
const packageJSONPath = path.join(projectPath, 'package.json') | ||
const packageJSONPath = join(projectPath, 'package.json') | ||
const cdsTemplateFile = forProfile ? 'cds.package.json.hbs' : 'cds.package.json' | ||
const cdsTemplatePath = path.join(templatePath, cdsTemplateFile) | ||
const cdsTemplatePath = join(templatePath, cdsTemplateFile) | ||
await mergeJSON(packageJSONPath, cdsTemplatePath, projectDescriptor) | ||
const dependenciesTemplatePath = path.join(templatePath, 'dependencies.package.json') | ||
const dependenciesTemplatePath = join(templatePath, 'dependencies.package.json') | ||
await mergeJSON(packageJSONPath, dependenciesTemplatePath) | ||
@@ -45,3 +44,3 @@ } | ||
async runDependentMerging() { | ||
async runDependentMerging( context = {}) { | ||
const projectDescriptor = await this.projectReader.read(this.options) | ||
@@ -52,3 +51,3 @@ const { isMultitenant, isExtensible, hasMta, hasHelm, isNodejs, isJava } = projectDescriptor.cap | ||
const xsSecurity = await (async () => { try { | ||
const models = await cds.load(path.join(this.projectPath, cds.env.folders.srv)) | ||
const models = await cds.load(join(this.projectPath, cds.env.folders.srv)) | ||
return cds.compile.to.xsuaa(models) | ||
@@ -65,3 +64,3 @@ } catch (error) { /* ignore */ } | ||
}))} | ||
const xsSecurityPath = path.join(this.projectPath, 'xs-security.json') | ||
const xsSecurityPath = join(this.projectPath, 'xs-security.json') | ||
await mergeJSON(xsSecurityPath, xsSecurity, projectDescriptor, mergingSemantics) | ||
@@ -74,3 +73,3 @@ | ||
const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml') | ||
const mtaYAMLPath = join(this.projectPath, 'mta.yaml') | ||
const relationships = [{ | ||
@@ -97,16 +96,26 @@ insert: [xsuaa, 'name'], | ||
if (hasHelm) { | ||
await copy( | ||
path.join(__dirname, 'files', 'xsuaa.yaml'), | ||
path.join(this.projectPath, 'chart', 'templates', 'xsuaa.yaml') | ||
//in case facet is being added to the already exisiting charts folder | ||
let isIndependentCommand = false; | ||
if(Object.keys(context).length == 0){ | ||
isIndependentCommand = true; | ||
context.projectPath = this.projectPath; | ||
context.oldTrackingData = context.newTrackingData = await parseMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5')); | ||
} | ||
await copyAndTrack( | ||
join(__dirname, 'files', 'xsuaa.yaml'), | ||
join(this.projectPath, 'chart', 'templates', 'xsuaa.yaml'), | ||
context | ||
) | ||
await mergeYAML( | ||
path.join(this.projectPath, 'chart', 'values.yaml'), | ||
path.join(__dirname, 'files', 'values.yaml.hbs'), | ||
projectDescriptor, { forceOverwrite: true } | ||
join(this.projectPath, 'chart', 'values.yaml'), | ||
join(__dirname, 'files', 'values.yaml.hbs'), | ||
projectDescriptor | ||
) | ||
// REVISIT: Shared xs-security.json location for Helm and MTA? | ||
await copy( | ||
path.join(this.projectPath, 'xs-security.json'), | ||
path.join(this.projectPath, 'chart', 'xs-security.json') | ||
await copyAndTrack( | ||
join(this.projectPath, 'xs-security.json'), | ||
join(this.projectPath, 'chart', 'xs-security.json'), | ||
context | ||
) | ||
if(isIndependentCommand) await writeMd5File(join(this.projectPath, 'chart', '.cds-add-helm-files.md5'), context.newTrackingData); | ||
} | ||
@@ -120,10 +129,11 @@ | ||
const multitenancyTemplate = new MultitenancyTemplate(this.projectPath, this.generator) | ||
await multitenancyTemplate.runDependentMerging() | ||
await multitenancyTemplate.runDependentMerging(context) | ||
} | ||
if (isExtensible) { | ||
const ExtensibilityTemplate = require(`../extensibility`) | ||
const extensibilityTemplate = new ExtensibilityTemplate(this.projectPath, this.generator) | ||
await extensibilityTemplate.runDependentMerging() | ||
await extensibilityTemplate.runDependentMerging(context) | ||
} | ||
} | ||
} |
@@ -58,3 +58,3 @@ const YAML = require('@sap/cds-foss').yaml | ||
async function mergeYAML(into, from, projectDescriptor, semantics) { | ||
async function mergeYAML(into, from, projectDescriptor, semantics = {}) { | ||
const target = | ||
@@ -316,6 +316,23 @@ typeof into === 'string' ? await readYAML(into) : | ||
async function removeFromYAML(name, keyPaths) { | ||
const yaml = await readYAML(name) | ||
for (const keyPath of keyPaths) { | ||
let node = yaml | ||
const keys = keyPath.split('.') | ||
for (const [index, key] of keys.entries()) { | ||
if (index === keys.length - 1) { | ||
node.delete(key) | ||
} else { | ||
node = node.get(key) | ||
} | ||
} | ||
} | ||
await writeYAML(name, yaml) | ||
} | ||
module.exports = { | ||
sortDependencies, | ||
mergeJSON, | ||
mergeYAML | ||
mergeYAML, | ||
removeFromYAML | ||
} |
@@ -92,8 +92,11 @@ const path = require('path') | ||
const root = this.projectPath | ||
const nullLogger = { debug: () => {}, log: () => {}, warn: () => {}, error: () => {}, write: () => {}} | ||
const buildTasks = await new BuildTaskFactory(nullLogger, cds).getTasks({ root, resolve: true, mta: false }) | ||
const nullLogger = { debug: () => { }, log: () => { }, warn: () => { }, error: () => { }, write: () => { } } | ||
// no file path resolving as the directories might not exist - e.g. cds add will create the mtx/sidecar folder | ||
const buildTasks = await new BuildTaskFactory(nullLogger, cds).getTasks({ root: this.projectPath, resolve: false, mta: false }) | ||
await Promise.all(buildTasks.map(async (task) => { | ||
const relDestPath = path.relative(root, task.dest)?.replace(/\\/g, '/') | ||
const srcPath = path.resolve(this.projectPath, task.src) | ||
const srcFolder = path.basename(srcPath) | ||
const relDestPath = path.join(env?.build?.target ?? "gen", task.dest || task.src)?.replace(/\\/g, '/') | ||
@@ -104,3 +107,3 @@ switch (task.for) { | ||
if (this._hasHanaServiceBinding(env)) { | ||
cap.db.push({ path: relDestPath, name: path.basename(task.src) }) | ||
cap.db.push({ path: relDestPath, name: srcFolder }) | ||
} | ||
@@ -114,4 +117,4 @@ break | ||
path: relDestPath, | ||
name: path.basename(task.src), | ||
ext: await this._getJavaExtDescriptor(task) | ||
name: srcFolder, | ||
ext: await this._getJavaExtDescriptor(srcPath) | ||
} | ||
@@ -124,3 +127,3 @@ break | ||
path: relDestPath, | ||
name: path.basename(task.src) | ||
name: srcFolder | ||
} | ||
@@ -149,8 +152,8 @@ break | ||
/** | ||
* Determines java specific properties for the given build task. | ||
* @param {object} task | ||
* Determines java specific properties for the given module source path. | ||
* @param {object} srcPath | ||
*/ | ||
async _getJavaExtDescriptor(task) { | ||
async _getJavaExtDescriptor(srcPath) { | ||
// by default spring-boot:repackage is used creating an executable jar archive | ||
const pomJson = await this._parseXml(path.join(task.src, 'pom.xml')) | ||
const pomJson = await this._parseXml(path.join(srcPath, 'pom.xml')) | ||
if (pomJson) { | ||
@@ -157,0 +160,0 @@ const dependencies = pomJson?.project?.dependencies?.[0]?.dependency |
{ | ||
"name": "@sap/cds-dk", | ||
"version": "6.3.2", | ||
"version": "6.4.0", | ||
"description": "Command line client and development toolkit for the SAP Cloud Application Programming Model", | ||
@@ -19,3 +19,3 @@ "homepage": "https://cap.cloud.sap/", | ||
"dependencies": { | ||
"@sap/cds": "^6.3.2", | ||
"@sap/cds": "^6.4.0", | ||
"@sap/cds-foss": "^4", | ||
@@ -38,3 +38,3 @@ "@sap/eslint-plugin-cds": "^2.6.0", | ||
"optionalDependencies": { | ||
"@sap/cds-mtxs": "^1.3.0", | ||
"@sap/cds-mtxs": "^1.4.0", | ||
"sqlite3": "^5.0.4" | ||
@@ -41,0 +41,0 @@ }, |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
1352927
263
28107
97
+ Added@humanwhocodes/config-array@0.11.8(transitive)
+ Added@sap/cds@6.4.0(transitive)
+ Added@sap/cds-compiler@3.5.0(transitive)
+ Added@sap/cds-mtxs@1.4.0(transitive)
+ Addedaxios@1.2.1(transitive)
+ Addedeslint@8.29.0(transitive)
+ Addedfastq@1.14.0(transitive)
+ Addedglobals@13.19.0(transitive)
+ Addedminimatch@5.1.1(transitive)
+ Addedminipass@4.0.0(transitive)
+ Addedsqlite3@5.1.4(transitive)
+ Addedtar@6.1.13(transitive)
+ Addeduglify-js@3.17.4(transitive)
- Removed@humanwhocodes/config-array@0.11.7(transitive)
- Removed@sap/cds@6.3.2(transitive)
- Removed@sap/cds-compiler@3.4.4(transitive)
- Removed@sap/cds-mtxs@1.3.2(transitive)
- Removed@sap/instance-manager@3.4.0(transitive)
- Removed@sap/xssec@3.2.14(transitive)
- Removedasn1@0.2.6(transitive)
- Removedaxios@0.26.11.2.0(transitive)
- Removedbuffer-equal-constant-time@1.0.1(transitive)
- Removedclone@2.1.1(transitive)
- Removedecdsa-sig-formatter@1.0.11(transitive)
- Removedeslint@8.28.0(transitive)
- Removedfastq@1.13.0(transitive)
- Removedglobals@13.18.0(transitive)
- Removedjsonwebtoken@8.5.1(transitive)
- Removedjwa@1.4.1(transitive)
- Removedjws@3.2.2(transitive)
- Removedlodash.includes@4.3.0(transitive)
- Removedlodash.isboolean@3.0.3(transitive)
- Removedlodash.isinteger@4.0.4(transitive)
- Removedlodash.isnumber@3.0.3(transitive)
- Removedlodash.isplainobject@4.0.6(transitive)
- Removedlodash.isstring@4.0.1(transitive)
- Removedlodash.once@4.1.1(transitive)
- Removedlru-cache@4.1.1(transitive)
- Removedmicromatch@4.0.5(transitive)
- Removedminimatch@5.1.0(transitive)
- Removednode-rsa@1.1.1(transitive)
- Removedpseudomap@1.0.2(transitive)
- Removedsemver@5.7.1(transitive)
- Removedsqlite3@5.1.2(transitive)
- Removedtar@6.1.12(transitive)
- Removeduglify-js@3.17.3(transitive)
- Removeduuid@7.0.0(transitive)
- Removedvalid-url@1.0.9(transitive)
- Removedyallist@2.1.2(transitive)
Updated@sap/cds@^6.4.0