@sap-ux/deploy-tooling 0.19.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base/archive.js +3 -9
- package/dist/base/config.d.ts +1 -1
- package/dist/base/config.js +8 -14
- package/dist/base/deploy.d.ts +1 -1
- package/dist/base/deploy.js +32 -37
- package/dist/base/index.d.ts +3 -3
- package/dist/base/index.js +3 -19
- package/dist/base/prompt.js +3 -9
- package/dist/base/validate.d.ts +1 -1
- package/dist/base/validate.js +45 -52
- package/dist/cli/archive.d.ts +1 -1
- package/dist/cli/archive.js +9 -15
- package/dist/cli/config.d.ts +1 -1
- package/dist/cli/config.js +18 -21
- package/dist/cli/index.js +43 -48
- package/dist/index.d.ts +4 -4
- package/dist/index.js +5 -26
- package/dist/types/index.js +1 -4
- package/dist/ui5/archive.js +3 -9
- package/dist/ui5/index.d.ts +2 -2
- package/dist/ui5/index.js +18 -19
- package/package.json +14 -12
package/dist/base/archive.js
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getAppDescriptorVariant = getAppDescriptorVariant;
|
|
7
|
-
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
1
|
+
import AdmZip from 'adm-zip';
|
|
8
2
|
/**
|
|
9
3
|
* Check whether a given zip files contains an adaptation project and if yes returns the contained manisfest.appdesc_variant.
|
|
10
4
|
*
|
|
11
5
|
* @param archive buffer representing a zip file
|
|
12
6
|
* @returns the descriptor as object if the archive contains an adaptation project otherwise undefined
|
|
13
7
|
*/
|
|
14
|
-
function getAppDescriptorVariant(archive) {
|
|
8
|
+
export function getAppDescriptorVariant(archive) {
|
|
15
9
|
try {
|
|
16
|
-
const zip = new
|
|
10
|
+
const zip = new AdmZip(archive);
|
|
17
11
|
const file = zip.getEntry('manifest.appdescr_variant');
|
|
18
12
|
if (file) {
|
|
19
13
|
return JSON.parse(file.getData().toString());
|
package/dist/base/config.d.ts
CHANGED
package/dist/base/config.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.getConfigForLogging = getConfigForLogging;
|
|
4
|
-
exports.throwConfigMissingError = throwConfigMissingError;
|
|
5
|
-
exports.isBspConfig = isBspConfig;
|
|
6
|
-
exports.validateConfig = validateConfig;
|
|
7
|
-
const btp_utils_1 = require("@sap-ux/btp-utils");
|
|
8
|
-
const system_access_1 = require("@sap-ux/system-access");
|
|
1
|
+
import { isAppStudio } from '@sap-ux/btp-utils';
|
|
2
|
+
import { isUrlTarget } from '@sap-ux/system-access';
|
|
9
3
|
/**
|
|
10
4
|
* Clones the given config and removes secrets so that it can be printed to a log file.
|
|
11
5
|
*
|
|
12
6
|
* @param config - config object
|
|
13
7
|
* @returns config object that can be logged
|
|
14
8
|
*/
|
|
15
|
-
function getConfigForLogging(config) {
|
|
9
|
+
export function getConfigForLogging(config) {
|
|
16
10
|
if (config.credentials?.password) {
|
|
17
11
|
return {
|
|
18
12
|
...config,
|
|
@@ -28,7 +22,7 @@ function getConfigForLogging(config) {
|
|
|
28
22
|
*
|
|
29
23
|
* @param property Invalid missing property
|
|
30
24
|
*/
|
|
31
|
-
function throwConfigMissingError(property) {
|
|
25
|
+
export function throwConfigMissingError(property) {
|
|
32
26
|
throw new Error(`Invalid deployment configuration. Property ${property} is missing.`);
|
|
33
27
|
}
|
|
34
28
|
/**
|
|
@@ -38,13 +32,13 @@ function throwConfigMissingError(property) {
|
|
|
38
32
|
* @returns reference to the given target config
|
|
39
33
|
*/
|
|
40
34
|
function validateTarget(target) {
|
|
41
|
-
if (
|
|
35
|
+
if (isUrlTarget(target)) {
|
|
42
36
|
if (target.client) {
|
|
43
37
|
target.client = (target.client + '').padStart(3, '0');
|
|
44
38
|
}
|
|
45
39
|
}
|
|
46
40
|
else if (!target.destination) {
|
|
47
|
-
throwConfigMissingError(
|
|
41
|
+
throwConfigMissingError(isAppStudio() ? 'target-destination' : 'target-url');
|
|
48
42
|
}
|
|
49
43
|
return target;
|
|
50
44
|
}
|
|
@@ -54,7 +48,7 @@ function validateTarget(target) {
|
|
|
54
48
|
* @param config - config to be checked
|
|
55
49
|
* @returns true if it is of type BSP config
|
|
56
50
|
*/
|
|
57
|
-
function isBspConfig(config) {
|
|
51
|
+
export function isBspConfig(config) {
|
|
58
52
|
return config.name !== undefined;
|
|
59
53
|
}
|
|
60
54
|
/**
|
|
@@ -64,7 +58,7 @@ function isBspConfig(config) {
|
|
|
64
58
|
* @param logger Logger used by deploy tooling
|
|
65
59
|
* @returns reference to the given config
|
|
66
60
|
*/
|
|
67
|
-
function validateConfig(config, logger) {
|
|
61
|
+
export function validateConfig(config, logger) {
|
|
68
62
|
if (!config) {
|
|
69
63
|
throw new Error('The deployment configuration is missing.');
|
|
70
64
|
}
|
package/dist/base/deploy.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AbapServiceProvider } from '@sap-ux/axios-extension';
|
|
2
2
|
import type { Logger } from '@sap-ux/logger';
|
|
3
|
-
import type { AbapDeployConfig } from '../types';
|
|
3
|
+
import type { AbapDeployConfig } from '../types/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* Creates a new transport request using adt service.
|
|
6
6
|
*
|
package/dist/base/deploy.js
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const prompt_1 = require("./prompt");
|
|
11
|
-
const system_access_1 = require("@sap-ux/system-access");
|
|
12
|
-
const archive_1 = require("./archive");
|
|
13
|
-
const validate_1 = require("./validate");
|
|
14
|
-
const inquirer_common_1 = require("@sap-ux/inquirer-common");
|
|
1
|
+
import { isAxiosError, TransportRequestService } from '@sap-ux/axios-extension';
|
|
2
|
+
import { LogLevel } from '@sap-ux/logger';
|
|
3
|
+
import { writeFileSync } from 'node:fs';
|
|
4
|
+
import { getConfigForLogging, isBspConfig, throwConfigMissingError } from './config.js';
|
|
5
|
+
import { promptConfirmation } from './prompt.js';
|
|
6
|
+
import { createAbapServiceProvider, getCredentialsWithPrompts } from '@sap-ux/system-access';
|
|
7
|
+
import { getAppDescriptorVariant } from './archive.js';
|
|
8
|
+
import { validateBeforeDeploy, formatSummary, showAdditionalInfoForOnPrem, checkForCredentials } from './validate.js';
|
|
9
|
+
import { ErrorHandler } from '@sap-ux/inquirer-common';
|
|
15
10
|
/**
|
|
16
11
|
* Handle exceptions thrown, in some cases we to retry them.
|
|
17
12
|
*
|
|
@@ -23,8 +18,8 @@ const inquirer_common_1 = require("@sap-ux/inquirer-common");
|
|
|
23
18
|
* @param archive - archive file that is to be deployed
|
|
24
19
|
*/
|
|
25
20
|
async function handleError(command, error, provider, config, logger, archive) {
|
|
26
|
-
if (
|
|
27
|
-
const gaLink = new
|
|
21
|
+
if (ErrorHandler.isCertError(error)) {
|
|
22
|
+
const gaLink = new ErrorHandler(undefined, undefined, '@sap-ux/deploy-tooling')
|
|
28
23
|
.getValidationErrorHelp(error)
|
|
29
24
|
?.toString();
|
|
30
25
|
if (gaLink) {
|
|
@@ -32,15 +27,15 @@ async function handleError(command, error, provider, config, logger, archive) {
|
|
|
32
27
|
}
|
|
33
28
|
}
|
|
34
29
|
const retry = config.retry === undefined ? true : config.retry;
|
|
35
|
-
if (retry &&
|
|
30
|
+
if (retry && isAxiosError(error)) {
|
|
36
31
|
const success = await axiosErrorRetryHandler(command, error.response, provider, config, logger, archive);
|
|
37
32
|
if (success) {
|
|
38
33
|
return;
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
36
|
logger.error(`${command === tryDeploy ? 'Deployment' : 'Undeployment'} has failed.`);
|
|
42
|
-
logger.debug(
|
|
43
|
-
if (!config.verbose && !(config.log !== undefined && config.log >=
|
|
37
|
+
logger.debug(getConfigForLogging(config));
|
|
38
|
+
if (!config.verbose && !(config.log !== undefined && config.log >= LogLevel.Debug)) {
|
|
44
39
|
logger.error('Change logging level to debug your issue\n\t(see examples https://github.com/SAP/open-ux-tools/tree/main/packages/deploy-tooling#configuration-with-logging-enabled)');
|
|
45
40
|
}
|
|
46
41
|
throw error;
|
|
@@ -57,7 +52,7 @@ async function handleError(command, error, provider, config, logger, archive) {
|
|
|
57
52
|
*/
|
|
58
53
|
async function handle412Error(command, provider, config, logger, archive) {
|
|
59
54
|
logger.warn('An app in the same repository with different sap app id found.');
|
|
60
|
-
if (config.yes || (await
|
|
55
|
+
if (config.yes || (await promptConfirmation('Do you want to overwrite (Y/n)?'))) {
|
|
61
56
|
await command(provider, { ...config, safe: false, retry: false }, logger, archive);
|
|
62
57
|
return true;
|
|
63
58
|
}
|
|
@@ -77,10 +72,10 @@ async function handle412Error(command, provider, config, logger, archive) {
|
|
|
77
72
|
*/
|
|
78
73
|
async function handle401Error(command, provider, config, logger, archive) {
|
|
79
74
|
logger.warn(`${command === tryDeploy ? 'Deployment' : 'Undeployment'} failed with authentication error.`);
|
|
80
|
-
if (await
|
|
75
|
+
if (await checkForCredentials(config.target.destination, logger)) {
|
|
81
76
|
logger.info('Please maintain correct credentials to avoid seeing this error\n\t(see help: https://www.npmjs.com/package/@sap/ux-ui5-tooling#setting-environment-variables-in-a-env-file)');
|
|
82
77
|
logger.info('Please enter your credentials.');
|
|
83
|
-
const credentials = await
|
|
78
|
+
const credentials = await getCredentialsWithPrompts(provider.defaults?.auth?.username);
|
|
84
79
|
if (Object.keys(credentials).length) {
|
|
85
80
|
if (config.target.serviceKey) {
|
|
86
81
|
config.target.serviceKey.uaa.username = credentials.username;
|
|
@@ -148,12 +143,12 @@ function getDeployService(factoryFn, config, logger) {
|
|
|
148
143
|
* @throws error if transport request creation fails
|
|
149
144
|
* @returns transportRequest
|
|
150
145
|
*/
|
|
151
|
-
async function createTransportRequest(config, logger, provider) {
|
|
146
|
+
export async function createTransportRequest(config, logger, provider) {
|
|
152
147
|
if (!provider) {
|
|
153
148
|
provider = await createProvider(config, logger);
|
|
154
149
|
}
|
|
155
|
-
const adtService = await provider.getAdtService(
|
|
156
|
-
const ui5AppName =
|
|
150
|
+
const adtService = await provider.getAdtService(TransportRequestService);
|
|
151
|
+
const ui5AppName = isBspConfig(config.app) ? config.app.name : '';
|
|
157
152
|
const description = `For ABAP repository ${ui5AppName}, created by SAP Open UX Tools`;
|
|
158
153
|
const transportRequest = await adtService?.createTransportRequest({
|
|
159
154
|
packageName: config.app.package ?? '',
|
|
@@ -174,7 +169,7 @@ async function createTransportRequest(config, logger, provider) {
|
|
|
174
169
|
* @returns an instance of an ABAP service provider
|
|
175
170
|
*/
|
|
176
171
|
async function createProvider(config, logger) {
|
|
177
|
-
return await
|
|
172
|
+
return await createAbapServiceProvider(config.target, {
|
|
178
173
|
auth: config.credentials,
|
|
179
174
|
ignoreCertErrors: !config.strictSsl
|
|
180
175
|
}, !!config.target.scp, logger);
|
|
@@ -189,7 +184,7 @@ async function createProvider(config, logger) {
|
|
|
189
184
|
*/
|
|
190
185
|
async function tryDeployToLrep(provider, config, logger, archive) {
|
|
191
186
|
logger.debug('No BSP name provided, checking if it is an adaptation project');
|
|
192
|
-
const descriptor =
|
|
187
|
+
const descriptor = getAppDescriptorVariant(archive);
|
|
193
188
|
if (descriptor) {
|
|
194
189
|
if (config.test) {
|
|
195
190
|
throw new Error('Deployment in test mode not supported for deployments to the layered repository.');
|
|
@@ -206,7 +201,7 @@ async function tryDeployToLrep(provider, config, logger, archive) {
|
|
|
206
201
|
}
|
|
207
202
|
}
|
|
208
203
|
else {
|
|
209
|
-
|
|
204
|
+
throwConfigMissingError('app-name');
|
|
210
205
|
}
|
|
211
206
|
}
|
|
212
207
|
/**
|
|
@@ -225,10 +220,10 @@ async function tryDeploy(provider, config, logger, archive) {
|
|
|
225
220
|
config.createTransport = false;
|
|
226
221
|
}
|
|
227
222
|
// check if deployment of BSP is requested
|
|
228
|
-
if (
|
|
223
|
+
if (isBspConfig(config.app)) {
|
|
229
224
|
if (config.test === true) {
|
|
230
|
-
const validateOutput = await
|
|
231
|
-
logger.info(`Results of validating the deployment configuration settings:${
|
|
225
|
+
const validateOutput = await validateBeforeDeploy(config, provider, logger);
|
|
226
|
+
logger.info(`Results of validating the deployment configuration settings:${formatSummary(validateOutput.summary)}`);
|
|
232
227
|
}
|
|
233
228
|
const service = getDeployService(provider.getUi5AbapRepository?.bind(provider), config, logger);
|
|
234
229
|
await service.deploy({
|
|
@@ -246,7 +241,7 @@ async function tryDeploy(provider, config, logger, archive) {
|
|
|
246
241
|
}
|
|
247
242
|
else {
|
|
248
243
|
logger.info('Deployment Successful.');
|
|
249
|
-
if (await
|
|
244
|
+
if (await showAdditionalInfoForOnPrem(`${config.target.destination}`)) {
|
|
250
245
|
logger.info('(Note: As the destination is configured using an On-Premise SAP Cloud Connector, you will need to replace the host in the URL above with the internal host)');
|
|
251
246
|
}
|
|
252
247
|
}
|
|
@@ -262,9 +257,9 @@ async function tryDeploy(provider, config, logger, archive) {
|
|
|
262
257
|
* @param config - deployment configuration
|
|
263
258
|
* @param logger - reference to the logger instance
|
|
264
259
|
*/
|
|
265
|
-
async function deploy(archive, config, logger) {
|
|
260
|
+
export async function deploy(archive, config, logger) {
|
|
266
261
|
if (config.keep) {
|
|
267
|
-
|
|
262
|
+
writeFileSync(`archive.zip`, new Uint8Array(archive));
|
|
268
263
|
}
|
|
269
264
|
const provider = await createProvider(config, logger);
|
|
270
265
|
logger.info(`Starting to deploy${config.test === true ? ' in test mode' : ''}.`);
|
|
@@ -290,12 +285,12 @@ async function tryUndeploy(provider, config, logger) {
|
|
|
290
285
|
transport: config.app.transport
|
|
291
286
|
});
|
|
292
287
|
}
|
|
293
|
-
else if (
|
|
288
|
+
else if (isBspConfig(config.app)) {
|
|
294
289
|
const service = getDeployService(provider.getUi5AbapRepository?.bind(provider), config, logger);
|
|
295
290
|
await service.undeploy({ bsp: config.app, testMode: config.test });
|
|
296
291
|
}
|
|
297
292
|
else {
|
|
298
|
-
|
|
293
|
+
throwConfigMissingError('app-name');
|
|
299
294
|
}
|
|
300
295
|
if (config.test === true) {
|
|
301
296
|
logger.info('Undeployment in TestMode completed. A successful TestMode execution does not necessarily mean that your undeploy will be successful.');
|
|
@@ -314,7 +309,7 @@ async function tryUndeploy(provider, config, logger) {
|
|
|
314
309
|
* @param config - deployment configuration
|
|
315
310
|
* @param logger - reference to the logger instance
|
|
316
311
|
*/
|
|
317
|
-
async function undeploy(config, logger) {
|
|
312
|
+
export async function undeploy(config, logger) {
|
|
318
313
|
const provider = await createProvider(config, logger);
|
|
319
314
|
logger.info(`Starting to undeploy ${config.test === true ? ' in test mode' : ''}.`);
|
|
320
315
|
await tryUndeploy(provider, config, logger);
|
package/dist/base/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from './config';
|
|
2
|
-
export * from './deploy';
|
|
3
|
-
export * from './prompt';
|
|
1
|
+
export * from './config.js';
|
|
2
|
+
export * from './deploy.js';
|
|
3
|
+
export * from './prompt.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/base/index.js
CHANGED
|
@@ -1,20 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./config"), exports);
|
|
18
|
-
__exportStar(require("./deploy"), exports);
|
|
19
|
-
__exportStar(require("./prompt"), exports);
|
|
1
|
+
export * from './config.js';
|
|
2
|
+
export * from './deploy.js';
|
|
3
|
+
export * from './prompt.js';
|
|
20
4
|
//# sourceMappingURL=index.js.map
|
package/dist/base/prompt.js
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.promptConfirmation = promptConfirmation;
|
|
7
|
-
const prompts_1 = __importDefault(require("prompts"));
|
|
1
|
+
import prompts from 'prompts';
|
|
8
2
|
/**
|
|
9
3
|
* Prompt for confirmation.
|
|
10
4
|
*
|
|
11
5
|
* @param message - the message to be shown for confirmation.
|
|
12
6
|
* @returns true if confirmed, otherwise false
|
|
13
7
|
*/
|
|
14
|
-
async function promptConfirmation(message) {
|
|
8
|
+
export async function promptConfirmation(message) {
|
|
15
9
|
let abort = false;
|
|
16
|
-
const { confirm } = await (
|
|
10
|
+
const { confirm } = await prompts({
|
|
17
11
|
type: 'confirm',
|
|
18
12
|
name: 'confirm',
|
|
19
13
|
initial: true,
|
package/dist/base/validate.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AbapServiceProvider } from '@sap-ux/axios-extension';
|
|
2
2
|
import type { Logger } from '@sap-ux/logger';
|
|
3
|
-
import type { AbapDeployConfig } from '../types';
|
|
3
|
+
import type { AbapDeployConfig } from '../types/index.js';
|
|
4
4
|
export type ValidationInputs = {
|
|
5
5
|
appName: string;
|
|
6
6
|
description: string;
|
package/dist/base/validate.js
CHANGED
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
exports.checkForCredentials = checkForCredentials;
|
|
8
|
-
const axios_extension_1 = require("@sap-ux/axios-extension");
|
|
9
|
-
const chalk_1 = require("chalk");
|
|
10
|
-
const project_input_validator_1 = require("@sap-ux/project-input-validator");
|
|
11
|
-
const node_os_1 = require("node:os");
|
|
12
|
-
const btp_utils_1 = require("@sap-ux/btp-utils");
|
|
13
|
-
var SummaryStatus;
|
|
1
|
+
import { TransportChecksService, ListPackageService, AtoService } from '@sap-ux/axios-extension';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { validateAppName, validateAppDescription, validateClient, validatePackage, validateTransportRequestNumber, validateUrl } from '@sap-ux/project-input-validator';
|
|
4
|
+
import { EOL } from 'node:os';
|
|
5
|
+
import { isAppStudio, isOnPremiseDestination, listDestinations, Authentication } from '@sap-ux/btp-utils';
|
|
6
|
+
export var SummaryStatus;
|
|
14
7
|
(function (SummaryStatus) {
|
|
15
8
|
SummaryStatus[SummaryStatus["Valid"] = 0] = "Valid";
|
|
16
9
|
SummaryStatus[SummaryStatus["Invalid"] = 1] = "Invalid";
|
|
17
10
|
SummaryStatus[SummaryStatus["Unknown"] = 2] = "Unknown";
|
|
18
|
-
})(SummaryStatus || (
|
|
19
|
-
|
|
11
|
+
})(SummaryStatus || (SummaryStatus = {}));
|
|
12
|
+
export const summaryMessage = {
|
|
20
13
|
allClientCheckPass: 'SAPUI5 ABAP Repository follows the rules of creating BSP application',
|
|
21
14
|
adtServiceUndefined: 'AdtService cannot be instantiated',
|
|
22
15
|
packageCheckPass: 'Package is found on ABAP system',
|
|
@@ -37,7 +30,7 @@ let cachedDestinationsList = {};
|
|
|
37
30
|
* @param logger Logger used by deploy tooling
|
|
38
31
|
* @returns Validation result and a summary report of identified issues.
|
|
39
32
|
*/
|
|
40
|
-
async function validateBeforeDeploy(config, provider, logger) {
|
|
33
|
+
export async function validateBeforeDeploy(config, provider, logger) {
|
|
41
34
|
const output = {
|
|
42
35
|
summary: [],
|
|
43
36
|
result: true
|
|
@@ -65,26 +58,26 @@ async function validateBeforeDeploy(config, provider, logger) {
|
|
|
65
58
|
* @param summary A list of summary records
|
|
66
59
|
* @returns Formatted summary string
|
|
67
60
|
*/
|
|
68
|
-
function formatSummary(summary) {
|
|
61
|
+
export function formatSummary(summary) {
|
|
69
62
|
const summaryStr = summary
|
|
70
63
|
.map((next) => {
|
|
71
64
|
let statusSymbol = '';
|
|
72
65
|
switch (next.status) {
|
|
73
66
|
case SummaryStatus.Valid:
|
|
74
|
-
statusSymbol =
|
|
67
|
+
statusSymbol = chalk.green('√');
|
|
75
68
|
break;
|
|
76
69
|
case SummaryStatus.Invalid:
|
|
77
|
-
statusSymbol =
|
|
70
|
+
statusSymbol = chalk.red('×');
|
|
78
71
|
break;
|
|
79
72
|
case SummaryStatus.Unknown:
|
|
80
73
|
default:
|
|
81
|
-
statusSymbol =
|
|
74
|
+
statusSymbol = chalk.yellow('?');
|
|
82
75
|
break;
|
|
83
76
|
}
|
|
84
77
|
return `${' '.repeat(4)}${statusSymbol} ${next.message}`;
|
|
85
78
|
})
|
|
86
79
|
.reduce((aggregated, current) => {
|
|
87
|
-
return `${aggregated}${
|
|
80
|
+
return `${aggregated}${EOL}${current}`;
|
|
88
81
|
}, '');
|
|
89
82
|
return summaryStr;
|
|
90
83
|
}
|
|
@@ -126,22 +119,22 @@ async function validateInputTextFormat(input, output, provider, logger) {
|
|
|
126
119
|
// A sequence of client-side validations. No early termination of detecting invalid inputs.
|
|
127
120
|
// Setting output.result to false if any of the checks is invalid.
|
|
128
121
|
// Add individual error messages into output.summary array if validation failed.
|
|
129
|
-
let result =
|
|
122
|
+
let result = validateAppName(input.appName, prefix);
|
|
130
123
|
processInputValidationResult(result, output);
|
|
131
|
-
result =
|
|
124
|
+
result = validateAppDescription(input.description);
|
|
132
125
|
processInputValidationResult(result, output);
|
|
133
|
-
result =
|
|
126
|
+
result = validateTransportRequestNumber(input.transport, input.package);
|
|
134
127
|
processInputValidationResult(result, output);
|
|
135
|
-
result =
|
|
128
|
+
result = validatePackage(input.package);
|
|
136
129
|
processInputValidationResult(result, output);
|
|
137
|
-
result =
|
|
130
|
+
result = validateClient(input.client);
|
|
138
131
|
processInputValidationResult(result, output);
|
|
139
132
|
result = validateUrlForOnPremTargetOnly(input.destination, input.url);
|
|
140
133
|
processInputValidationResult(result, output);
|
|
141
134
|
// If all the text validation passed, only show the following success message.
|
|
142
135
|
if (output.result) {
|
|
143
136
|
output.summary.push({
|
|
144
|
-
message:
|
|
137
|
+
message: summaryMessage.allClientCheckPass,
|
|
145
138
|
status: SummaryStatus.Valid
|
|
146
139
|
});
|
|
147
140
|
}
|
|
@@ -155,12 +148,12 @@ async function validateInputTextFormat(input, output, provider, logger) {
|
|
|
155
148
|
* @returns
|
|
156
149
|
*/
|
|
157
150
|
function validateUrlForOnPremTargetOnly(destination, url) {
|
|
158
|
-
if (
|
|
151
|
+
if (isAppStudio() && destination) {
|
|
159
152
|
// No validation required for destination name
|
|
160
153
|
return true;
|
|
161
154
|
}
|
|
162
155
|
else if (url) {
|
|
163
|
-
return
|
|
156
|
+
return validateUrl(url);
|
|
164
157
|
}
|
|
165
158
|
else {
|
|
166
159
|
return 'Invalid deploy target';
|
|
@@ -177,10 +170,10 @@ function validateUrlForOnPremTargetOnly(destination, url) {
|
|
|
177
170
|
*/
|
|
178
171
|
async function getSystemPrefix(output, provider, logger) {
|
|
179
172
|
try {
|
|
180
|
-
const adtService = await provider.getAdtService(
|
|
173
|
+
const adtService = await provider.getAdtService(AtoService);
|
|
181
174
|
if (!adtService) {
|
|
182
175
|
output.summary.push({
|
|
183
|
-
message: `${
|
|
176
|
+
message: `${summaryMessage.adtServiceUndefined} for AtoService`,
|
|
184
177
|
status: SummaryStatus.Unknown
|
|
185
178
|
});
|
|
186
179
|
output.result = false;
|
|
@@ -196,7 +189,7 @@ async function getSystemPrefix(output, provider, logger) {
|
|
|
196
189
|
logger.error(e.message);
|
|
197
190
|
logger.debug(e);
|
|
198
191
|
output.summary.push({
|
|
199
|
-
message:
|
|
192
|
+
message: summaryMessage.atoAdtAccessError,
|
|
200
193
|
status: SummaryStatus.Unknown
|
|
201
194
|
});
|
|
202
195
|
output.result = false;
|
|
@@ -238,10 +231,10 @@ async function validatePackageWithAdt(input, output, provider, logger) {
|
|
|
238
231
|
// ADT expects input package
|
|
239
232
|
const inputPackage = input.package;
|
|
240
233
|
try {
|
|
241
|
-
const adtService = await provider.getAdtService(
|
|
234
|
+
const adtService = await provider.getAdtService(ListPackageService);
|
|
242
235
|
if (!adtService) {
|
|
243
236
|
output.summary.push({
|
|
244
|
-
message: `${
|
|
237
|
+
message: `${summaryMessage.adtServiceUndefined} for ListPackageService`,
|
|
245
238
|
status: SummaryStatus.Unknown
|
|
246
239
|
});
|
|
247
240
|
output.result = false;
|
|
@@ -251,13 +244,13 @@ async function validatePackageWithAdt(input, output, provider, logger) {
|
|
|
251
244
|
const isValidPackage = packages.includes(inputPackage);
|
|
252
245
|
if (isValidPackage) {
|
|
253
246
|
output.summary.push({
|
|
254
|
-
message:
|
|
247
|
+
message: summaryMessage.packageCheckPass,
|
|
255
248
|
status: SummaryStatus.Valid
|
|
256
249
|
});
|
|
257
250
|
}
|
|
258
251
|
else {
|
|
259
252
|
output.summary.push({
|
|
260
|
-
message:
|
|
253
|
+
message: summaryMessage.packageNotFound,
|
|
261
254
|
status: SummaryStatus.Invalid
|
|
262
255
|
});
|
|
263
256
|
output.result = false;
|
|
@@ -267,7 +260,7 @@ async function validatePackageWithAdt(input, output, provider, logger) {
|
|
|
267
260
|
logger.error(e.message);
|
|
268
261
|
logger.debug(e);
|
|
269
262
|
output.summary.push({
|
|
270
|
-
message:
|
|
263
|
+
message: summaryMessage.pacakgeAdtAccessError,
|
|
271
264
|
status: SummaryStatus.Unknown
|
|
272
265
|
});
|
|
273
266
|
output.result = false;
|
|
@@ -286,10 +279,10 @@ async function validateTransportRequestWithAdt(input, output, provider, logger)
|
|
|
286
279
|
return;
|
|
287
280
|
}
|
|
288
281
|
try {
|
|
289
|
-
const adtService = await provider.getAdtService(
|
|
282
|
+
const adtService = await provider.getAdtService(TransportChecksService);
|
|
290
283
|
if (!adtService) {
|
|
291
284
|
output.summary.push({
|
|
292
|
-
message: `${
|
|
285
|
+
message: `${summaryMessage.adtServiceUndefined} for TransportChecksService`,
|
|
293
286
|
status: SummaryStatus.Unknown
|
|
294
287
|
});
|
|
295
288
|
output.result = false;
|
|
@@ -299,13 +292,13 @@ async function validateTransportRequestWithAdt(input, output, provider, logger)
|
|
|
299
292
|
const isValidTrList = trList.findIndex((tr) => tr.transportNumber === input.transport) >= 0;
|
|
300
293
|
if (isValidTrList) {
|
|
301
294
|
output.summary.push({
|
|
302
|
-
message:
|
|
295
|
+
message: summaryMessage.transportCheckPass,
|
|
303
296
|
status: SummaryStatus.Valid
|
|
304
297
|
});
|
|
305
298
|
}
|
|
306
299
|
else {
|
|
307
300
|
output.summary.push({
|
|
308
|
-
message:
|
|
301
|
+
message: summaryMessage.transportNotFound,
|
|
309
302
|
status: SummaryStatus.Invalid
|
|
310
303
|
});
|
|
311
304
|
output.result = false;
|
|
@@ -316,9 +309,9 @@ async function validateTransportRequestWithAdt(input, output, provider, logger)
|
|
|
316
309
|
// transport request list. If input packge is local package, no transport request
|
|
317
310
|
// is returned and LocalPackageError is thrown as exception.
|
|
318
311
|
// LocalPackageError is acceptable for validation purpose here.
|
|
319
|
-
if (e.message ===
|
|
312
|
+
if (e.message === TransportChecksService.LocalPackageError) {
|
|
320
313
|
output.summary.push({
|
|
321
|
-
message:
|
|
314
|
+
message: summaryMessage.transportNotRequired,
|
|
322
315
|
status: SummaryStatus.Valid
|
|
323
316
|
});
|
|
324
317
|
}
|
|
@@ -326,7 +319,7 @@ async function validateTransportRequestWithAdt(input, output, provider, logger)
|
|
|
326
319
|
logger.error(e.message);
|
|
327
320
|
logger.debug(e);
|
|
328
321
|
output.summary.push({
|
|
329
|
-
message:
|
|
322
|
+
message: summaryMessage.transportAdtAccessError,
|
|
330
323
|
status: SummaryStatus.Unknown
|
|
331
324
|
});
|
|
332
325
|
output.result = false;
|
|
@@ -340,11 +333,11 @@ async function validateTransportRequestWithAdt(input, output, provider, logger)
|
|
|
340
333
|
* @param destination Identifier for destination to be checked.
|
|
341
334
|
* @returns Promise boolean.
|
|
342
335
|
*/
|
|
343
|
-
async function showAdditionalInfoForOnPrem(destination) {
|
|
336
|
+
export async function showAdditionalInfoForOnPrem(destination) {
|
|
344
337
|
let showInfo = false;
|
|
345
|
-
if (
|
|
346
|
-
const destinations = await
|
|
347
|
-
showInfo =
|
|
338
|
+
if (isAppStudio() && destination) {
|
|
339
|
+
const destinations = await listDestinations();
|
|
340
|
+
showInfo = isOnPremiseDestination(destinations[destination]);
|
|
348
341
|
}
|
|
349
342
|
return showInfo;
|
|
350
343
|
}
|
|
@@ -355,11 +348,11 @@ async function showAdditionalInfoForOnPrem(destination) {
|
|
|
355
348
|
* @param logger Logger from the calling context.
|
|
356
349
|
* @returns Promise boolean.
|
|
357
350
|
*/
|
|
358
|
-
async function checkForCredentials(destination, logger) {
|
|
351
|
+
export async function checkForCredentials(destination, logger) {
|
|
359
352
|
let check = true;
|
|
360
|
-
if (destination &&
|
|
353
|
+
if (destination && isAppStudio()) {
|
|
361
354
|
const destinations = await getDestinations();
|
|
362
|
-
if (destinations[destination].Authentication ===
|
|
355
|
+
if (destinations[destination].Authentication === Authentication.SAML_ASSERTION) {
|
|
363
356
|
logger.warn(`The SAP BTP destination is misconfigured, please check you have the appropriate trusts and permissions enabled.`);
|
|
364
357
|
check = false;
|
|
365
358
|
}
|
|
@@ -373,7 +366,7 @@ async function checkForCredentials(destination, logger) {
|
|
|
373
366
|
*/
|
|
374
367
|
async function getDestinations() {
|
|
375
368
|
if (Object.keys(cachedDestinationsList).length === 0) {
|
|
376
|
-
cachedDestinationsList = await
|
|
369
|
+
cachedDestinationsList = await listDestinations();
|
|
377
370
|
}
|
|
378
371
|
return cachedDestinationsList;
|
|
379
372
|
}
|
package/dist/cli/archive.d.ts
CHANGED
package/dist/cli/archive.js
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getArchive = getArchive;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const promises_1 = require("node:fs/promises");
|
|
9
|
-
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
10
|
-
const node_https_1 = require("node:https");
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import ZipFile from 'adm-zip';
|
|
4
|
+
import { Agent } from 'node:https';
|
|
11
5
|
/**
|
|
12
6
|
* Get/read zip file from the given path.
|
|
13
7
|
*
|
|
@@ -18,7 +12,7 @@ const node_https_1 = require("node:https");
|
|
|
18
12
|
async function getArchiveFromPath(logger, path) {
|
|
19
13
|
logger.info(`Loading archive from ${path}`);
|
|
20
14
|
try {
|
|
21
|
-
const data = await
|
|
15
|
+
const data = await readFile(path);
|
|
22
16
|
logger.info(`Archive loaded from ${path}`);
|
|
23
17
|
return data;
|
|
24
18
|
}
|
|
@@ -37,8 +31,8 @@ async function getArchiveFromPath(logger, path) {
|
|
|
37
31
|
async function fetchArchiveFromUrl(logger, url, rejectUnauthorized) {
|
|
38
32
|
try {
|
|
39
33
|
logger.info(`Fetching archive from ${url}.`);
|
|
40
|
-
const response = await
|
|
41
|
-
httpsAgent: new
|
|
34
|
+
const response = await axios.get(url, {
|
|
35
|
+
httpsAgent: new Agent({ rejectUnauthorized }),
|
|
42
36
|
responseType: 'arraybuffer'
|
|
43
37
|
});
|
|
44
38
|
logger.info(`Archive fetched from ${url}.`);
|
|
@@ -58,7 +52,7 @@ async function fetchArchiveFromUrl(logger, url, rejectUnauthorized) {
|
|
|
58
52
|
function createArchiveFromFolder(logger, path) {
|
|
59
53
|
try {
|
|
60
54
|
logger.info(`Creating archive from ${path}.`);
|
|
61
|
-
const zip = new
|
|
55
|
+
const zip = new ZipFile();
|
|
62
56
|
zip.addLocalFolder(path);
|
|
63
57
|
for (const entry of zip.getEntries()) {
|
|
64
58
|
logger.debug(`Adding ${entry.entryName}`);
|
|
@@ -77,7 +71,7 @@ function createArchiveFromFolder(logger, path) {
|
|
|
77
71
|
* @param options - options provided via CLI
|
|
78
72
|
* @returns Buffer containing the zip file
|
|
79
73
|
*/
|
|
80
|
-
async function getArchive(logger, options) {
|
|
74
|
+
export async function getArchive(logger, options) {
|
|
81
75
|
if (options.archivePath) {
|
|
82
76
|
return getArchiveFromPath(logger, options.archivePath);
|
|
83
77
|
}
|
package/dist/cli/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AbapDeployConfig, CliOptions } from '../types';
|
|
1
|
+
import type { AbapDeployConfig, CliOptions } from '../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Tries to read the version of the modules package.json but in case of an error, it returns the manually maintained version matching major.minor of the module.
|
|
4
4
|
*
|
package/dist/cli/config.js
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const node_fs_1 = require("node:fs");
|
|
8
|
-
const node_path_1 = require("node:path");
|
|
9
|
-
const types_1 = require("../types");
|
|
1
|
+
import { UI5Config } from '@sap-ux/ui5-config';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, isAbsolute, join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { NAME } from '../types/index.js';
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
7
|
/**
|
|
11
8
|
* Tries to read the version of the modules package.json but in case of an error, it returns the manually maintained version matching major.minor of the module.
|
|
12
9
|
*
|
|
13
10
|
* @returns the version of the deploy tooling.
|
|
14
11
|
*/
|
|
15
|
-
function getVersion() {
|
|
12
|
+
export function getVersion() {
|
|
16
13
|
try {
|
|
17
|
-
const packageInfo =
|
|
14
|
+
const packageInfo = readFileSync(join(__dirname, '../../package.json'), 'utf-8');
|
|
18
15
|
return JSON.parse(packageInfo).version;
|
|
19
16
|
}
|
|
20
17
|
catch (error) {
|
|
@@ -27,10 +24,10 @@ function getVersion() {
|
|
|
27
24
|
* @param path - path to the ui5*.yaml file
|
|
28
25
|
* @returns the configuration object or throws an error if it cannot be read.
|
|
29
26
|
*/
|
|
30
|
-
async function getDeploymentConfig(path) {
|
|
31
|
-
const content =
|
|
32
|
-
const ui5Config = await
|
|
33
|
-
const config = ui5Config.findCustomTask(
|
|
27
|
+
export async function getDeploymentConfig(path) {
|
|
28
|
+
const content = readFileSync(path, 'utf-8');
|
|
29
|
+
const ui5Config = await UI5Config.newInstance(content);
|
|
30
|
+
const config = ui5Config.findCustomTask(NAME)?.configuration;
|
|
34
31
|
if (!config) {
|
|
35
32
|
throw new Error('The deployment configuration is missing.');
|
|
36
33
|
}
|
|
@@ -44,7 +41,7 @@ async function getDeploymentConfig(path) {
|
|
|
44
41
|
*/
|
|
45
42
|
function readServiceKeyFromFile(path) {
|
|
46
43
|
try {
|
|
47
|
-
return JSON.parse(
|
|
44
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
48
45
|
}
|
|
49
46
|
catch (error) {
|
|
50
47
|
throw new Error(`Unable to read service key from from ${path}`);
|
|
@@ -159,7 +156,7 @@ function mergeCredentials(taskConfig, options) {
|
|
|
159
156
|
* @param options - CLI options
|
|
160
157
|
* @returns the merged config
|
|
161
158
|
*/
|
|
162
|
-
async function mergeConfig(taskConfig, options) {
|
|
159
|
+
export async function mergeConfig(taskConfig, options) {
|
|
163
160
|
const app = {
|
|
164
161
|
name: options.name ?? taskConfig.app?.name,
|
|
165
162
|
description: options.description ?? taskConfig.app?.description,
|
|
@@ -179,11 +176,11 @@ async function mergeConfig(taskConfig, options) {
|
|
|
179
176
|
if (!options.archiveUrl && !options.archivePath && !options.archiveFolder) {
|
|
180
177
|
options.archiveFolder = 'dist';
|
|
181
178
|
}
|
|
182
|
-
if (options.config && options.archiveFolder && !
|
|
183
|
-
options.archiveFolder =
|
|
179
|
+
if (options.config && options.archiveFolder && !isAbsolute(options.archiveFolder)) {
|
|
180
|
+
options.archiveFolder = join(dirname(options.config), options.archiveFolder);
|
|
184
181
|
}
|
|
185
|
-
if (options.config && options.archivePath && !
|
|
186
|
-
options.archivePath =
|
|
182
|
+
if (options.config && options.archivePath && !isAbsolute(options.archivePath)) {
|
|
183
|
+
options.archivePath = join(dirname(options.config), options.archivePath);
|
|
187
184
|
}
|
|
188
185
|
return config;
|
|
189
186
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,47 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const types_1 = require("../types");
|
|
10
|
-
const archive_1 = require("./archive");
|
|
11
|
-
const config_1 = require("./config");
|
|
12
|
-
const dotenv_1 = require("dotenv");
|
|
13
|
-
const ui5_config_1 = require("@sap-ux/ui5-config");
|
|
1
|
+
import { Option, Command } from 'commander';
|
|
2
|
+
import { ToolsLogger, ConsoleTransport, LogLevel } from '@sap-ux/logger';
|
|
3
|
+
import { deploy, getConfigForLogging, undeploy, validateConfig } from '../base/index.js';
|
|
4
|
+
import { NAME } from '../types/index.js';
|
|
5
|
+
import { getArchive } from './archive.js';
|
|
6
|
+
import { getDeploymentConfig, getVersion, mergeConfig } from './config.js';
|
|
7
|
+
import { config as loadEnvConfig } from 'dotenv';
|
|
8
|
+
import { replaceEnvVariables } from '@sap-ux/ui5-config';
|
|
14
9
|
/**
|
|
15
10
|
* Create an instance of a command runner for deployment.
|
|
16
11
|
*
|
|
17
12
|
* @param name - command name
|
|
18
13
|
* @returns instance of the command
|
|
19
14
|
*/
|
|
20
|
-
function createCommand(name) {
|
|
21
|
-
const command = new
|
|
15
|
+
export function createCommand(name) {
|
|
16
|
+
const command = new Command(name)
|
|
22
17
|
.option('-c, --config <path-to-yaml>', 'Path to config yaml file')
|
|
23
18
|
.option('-y, --yes', 'yes to all questions', false)
|
|
24
19
|
.option('-n, --no-retry', `do not retry if ${name} fails for any reason`, true) // retry by default when true, if passed from cli, will set to false
|
|
25
20
|
.option('--verbose', 'verbose log output', false);
|
|
26
21
|
// options to set (or overwrite) values that are otherwise read from the `ui5*.yaml`
|
|
27
22
|
command
|
|
28
|
-
.addOption(new
|
|
29
|
-
.addOption(new
|
|
30
|
-
.addOption(new
|
|
31
|
-
.addOption(new
|
|
32
|
-
.addOption(new
|
|
33
|
-
.addOption(new
|
|
34
|
-
.addOption(new
|
|
35
|
-
.addOption(new
|
|
36
|
-
.addOption(new
|
|
23
|
+
.addOption(new Option('--destination <destination>', 'Destination in SAP BTP pointing to an ABAP system').conflicts('url'))
|
|
24
|
+
.addOption(new Option('--url <target-url>', 'URL of target ABAP system').conflicts('destination'))
|
|
25
|
+
.addOption(new Option('--connect-path <path>', 'Service URL path used to retrieve credentials from secure storage'))
|
|
26
|
+
.addOption(new Option('--client <sap-client>', 'Client number of target ABAP system').conflicts('destination'))
|
|
27
|
+
.addOption(new Option('--cloud', 'Target is an ABAP Cloud system').conflicts('destination'))
|
|
28
|
+
.addOption(new Option('--service <service-path>', 'Target alias for deployment service'))
|
|
29
|
+
.addOption(new Option('--authentication-type <authentication-type>', 'Authentication type for the app'))
|
|
30
|
+
.addOption(new Option('--cloud-service-key <file-location>', 'JSON file location with the ABAP cloud service key.').conflicts('destination'))
|
|
31
|
+
.addOption(new Option('--cloud-service-env', 'Read ABAP cloud service properties from environment variables or .env file').conflicts(['cloudServiceKey', 'destination']))
|
|
37
32
|
.option('--package <abap-package>', 'Package name for deploy target ABAP system')
|
|
38
33
|
.option('--transport <transport-request>', 'Transport number to record the change in the ABAP system')
|
|
39
|
-
.addOption(new
|
|
40
|
-
.addOption(new
|
|
34
|
+
.addOption(new Option('--create-transport', 'Create transport request during deployment').conflicts(['transport']))
|
|
35
|
+
.addOption(new Option('--username <username>', 'ABAP System username').conflicts([
|
|
41
36
|
'cloudServiceKey',
|
|
42
37
|
'cloudServiceEnv'
|
|
43
38
|
]))
|
|
44
|
-
.addOption(new
|
|
39
|
+
.addOption(new Option('--password <password>', 'ABAP System password').conflicts([
|
|
45
40
|
'cloudServiceKey',
|
|
46
41
|
'cloudServiceEnv'
|
|
47
42
|
]))
|
|
@@ -58,20 +53,20 @@ function createCommand(name) {
|
|
|
58
53
|
.option('--keep', 'Keep a copy of the deployed archive in the project folder.');
|
|
59
54
|
// alternatives to provide the archive
|
|
60
55
|
command
|
|
61
|
-
.addOption(new
|
|
62
|
-
.addOption(new
|
|
56
|
+
.addOption(new Option('--archive-url <url>', 'Download app bundle from this url and upload this bundle for deployment').conflicts(['archivePath', 'archiveFolder']))
|
|
57
|
+
.addOption(new Option('--archive-path <path>', 'Provide path of the app bundle for deployment').conflicts([
|
|
63
58
|
'archiveUrl',
|
|
64
59
|
'archiveFolder'
|
|
65
60
|
]))
|
|
66
|
-
.addOption(new
|
|
61
|
+
.addOption(new Option('--archive-folder <path>', 'Provide path to a folder for deployment').conflicts([
|
|
67
62
|
'archiveUrl',
|
|
68
63
|
'archivePath'
|
|
69
64
|
]));
|
|
70
65
|
}
|
|
71
66
|
else if (name === 'undeploy') {
|
|
72
|
-
command.addOption(new
|
|
67
|
+
command.addOption(new Option('--lrep <namespace>', 'Undeploy the given namespace from the layered repository (for adaptation projects)').conflicts(['test', 'name']));
|
|
73
68
|
}
|
|
74
|
-
return command.version(
|
|
69
|
+
return command.version(getVersion(), '-v, --version', 'version of the deploy tooling');
|
|
75
70
|
}
|
|
76
71
|
/**
|
|
77
72
|
* Prepare the run of the task based on the configured command i.e. read and validate configuration and create logger.
|
|
@@ -83,33 +78,33 @@ async function prepareRun(cmd) {
|
|
|
83
78
|
if (process.argv.length < 3) {
|
|
84
79
|
cmd.help();
|
|
85
80
|
}
|
|
86
|
-
(
|
|
81
|
+
loadEnvConfig();
|
|
87
82
|
const options = cmd.parse().opts();
|
|
88
|
-
const logLevel = options.verbose ?
|
|
89
|
-
const logger = new
|
|
90
|
-
transports: [new
|
|
83
|
+
const logLevel = options.verbose ? LogLevel.Silly : LogLevel.Info;
|
|
84
|
+
const logger = new ToolsLogger({
|
|
85
|
+
transports: [new ConsoleTransport()],
|
|
91
86
|
logLevel,
|
|
92
|
-
logPrefix:
|
|
87
|
+
logPrefix: NAME
|
|
93
88
|
});
|
|
94
89
|
// Handle empty config when not passed in
|
|
95
|
-
const taskConfig = options.config ? await
|
|
96
|
-
const config = await
|
|
97
|
-
if (logLevel >=
|
|
98
|
-
logger.debug(
|
|
90
|
+
const taskConfig = options.config ? await getDeploymentConfig(options.config) : {};
|
|
91
|
+
const config = await mergeConfig(taskConfig, options);
|
|
92
|
+
if (logLevel >= LogLevel.Debug) {
|
|
93
|
+
logger.debug(getConfigForLogging(config));
|
|
99
94
|
}
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
validateConfig(config);
|
|
96
|
+
replaceEnvVariables(config);
|
|
102
97
|
return { cmd, logger, config, options };
|
|
103
98
|
}
|
|
104
99
|
/**
|
|
105
100
|
* Function that is to be executed when the exposed deploy command is executed.
|
|
106
101
|
*/
|
|
107
|
-
async function runDeploy() {
|
|
102
|
+
export async function runDeploy() {
|
|
108
103
|
const cmd = createCommand('deploy');
|
|
109
104
|
try {
|
|
110
105
|
const { logger, options, config } = await prepareRun(cmd);
|
|
111
|
-
const archive = await
|
|
112
|
-
await
|
|
106
|
+
const archive = await getArchive(logger, options);
|
|
107
|
+
await deploy(archive, config, logger);
|
|
113
108
|
}
|
|
114
109
|
catch (error) {
|
|
115
110
|
cmd.error(error.message);
|
|
@@ -118,11 +113,11 @@ async function runDeploy() {
|
|
|
118
113
|
/**
|
|
119
114
|
* Function that is to be executed when the exposed undeploy command is executed.
|
|
120
115
|
*/
|
|
121
|
-
async function runUndeploy() {
|
|
116
|
+
export async function runUndeploy() {
|
|
122
117
|
const cmd = createCommand('undeploy');
|
|
123
118
|
try {
|
|
124
119
|
const { logger, config } = await prepareRun(cmd);
|
|
125
|
-
await
|
|
120
|
+
await undeploy(config, logger);
|
|
126
121
|
}
|
|
127
122
|
catch (error) {
|
|
128
123
|
cmd.error(error.message);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import task from './ui5';
|
|
2
|
-
import { createTransportRequest } from './base';
|
|
3
|
-
export * from './types';
|
|
4
|
-
export * from './cli';
|
|
1
|
+
import task from './ui5/index.js';
|
|
2
|
+
import { createTransportRequest } from './base/index.js';
|
|
3
|
+
export * from './types/index.js';
|
|
4
|
+
export * from './cli/index.js';
|
|
5
5
|
export { task, createTransportRequest };
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
-
};
|
|
19
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.createTransportRequest = exports.task = void 0;
|
|
21
|
-
const ui5_1 = __importDefault(require("./ui5"));
|
|
22
|
-
exports.task = ui5_1.default;
|
|
23
|
-
const base_1 = require("./base");
|
|
24
|
-
Object.defineProperty(exports, "createTransportRequest", { enumerable: true, get: function () { return base_1.createTransportRequest; } });
|
|
25
|
-
__exportStar(require("./types"), exports);
|
|
26
|
-
__exportStar(require("./cli"), exports);
|
|
1
|
+
import task from './ui5/index.js';
|
|
2
|
+
import { createTransportRequest } from './base/index.js';
|
|
3
|
+
export * from './types/index.js';
|
|
4
|
+
export * from './cli/index.js';
|
|
5
|
+
export { task, createTransportRequest };
|
|
27
6
|
//# sourceMappingURL=index.js.map
|
package/dist/types/index.js
CHANGED
package/dist/ui5/archive.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.createUi5Archive = createUi5Archive;
|
|
7
|
-
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
1
|
+
import ZipFile from 'adm-zip';
|
|
8
2
|
/**
|
|
9
3
|
* Create an archive of files in the workspace.
|
|
10
4
|
*
|
|
@@ -14,10 +8,10 @@ const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
|
14
8
|
* @param exclude - array of regex patterns used to exclude folders from archive
|
|
15
9
|
* @returns {*} {Promise<Buffer>} - archive
|
|
16
10
|
*/
|
|
17
|
-
async function createUi5Archive(logger, workspace, projectName, exclude = []) {
|
|
11
|
+
export async function createUi5Archive(logger, workspace, projectName, exclude = []) {
|
|
18
12
|
logger.info('Creating archive with UI5 build result.');
|
|
19
13
|
const prefix = `/resources/${projectName}/`;
|
|
20
|
-
const zip = new
|
|
14
|
+
const zip = new ZipFile();
|
|
21
15
|
const resources = await workspace.byGlob(`${prefix}**/*`);
|
|
22
16
|
for (const resource of resources) {
|
|
23
17
|
if (!exclude.some((regex) => RegExp(regex, 'g').exec(resource.getPath()))) {
|
package/dist/ui5/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TaskParameters } from '@ui5/builder';
|
|
2
|
-
import type { AbapDeployConfig } from '../types';
|
|
2
|
+
import type { AbapDeployConfig } from '../types/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Custom task to upload the build result to the UI5 ABAP Repository.
|
|
5
5
|
*
|
|
@@ -8,5 +8,5 @@ import type { AbapDeployConfig } from '../types';
|
|
|
8
8
|
* @param params.options - project properties and configuration
|
|
9
9
|
*/
|
|
10
10
|
declare function task({ workspace, options }: TaskParameters<AbapDeployConfig>): Promise<void>;
|
|
11
|
-
export
|
|
11
|
+
export default task;
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/ui5/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const ui5_config_1 = require("@sap-ux/ui5-config");
|
|
1
|
+
import { LogLevel, ToolsLogger, UI5ToolingTransport } from '@sap-ux/logger';
|
|
2
|
+
import { NAME } from '../types/index.js';
|
|
3
|
+
import { deploy, validateConfig } from '../base/index.js';
|
|
4
|
+
import { createUi5Archive } from './archive.js';
|
|
5
|
+
import { config as loadEnvConfig } from 'dotenv';
|
|
6
|
+
import { replaceEnvVariables } from '@sap-ux/ui5-config';
|
|
8
7
|
/**
|
|
9
8
|
* Resolves a log level value from ui5.yaml configuration to a LogLevel enum value.
|
|
10
9
|
* ui5.yaml delivers all scalar values as strings (e.g. "verbose"), but LogLevel is
|
|
@@ -20,12 +19,12 @@ function resolveLogLevel(value) {
|
|
|
20
19
|
return value;
|
|
21
20
|
}
|
|
22
21
|
if (typeof value === 'string') {
|
|
23
|
-
const key = Object.keys(
|
|
22
|
+
const key = Object.keys(LogLevel).find((k) => k.toLowerCase() === value.toLowerCase());
|
|
24
23
|
if (key !== undefined) {
|
|
25
|
-
return
|
|
24
|
+
return LogLevel[key];
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
|
-
return
|
|
27
|
+
return LogLevel.Info;
|
|
29
28
|
}
|
|
30
29
|
/**
|
|
31
30
|
* Custom task to upload the build result to the UI5 ABAP Repository.
|
|
@@ -35,18 +34,18 @@ function resolveLogLevel(value) {
|
|
|
35
34
|
* @param params.options - project properties and configuration
|
|
36
35
|
*/
|
|
37
36
|
async function task({ workspace, options }) {
|
|
38
|
-
(
|
|
39
|
-
const moduleName = `${
|
|
37
|
+
loadEnvConfig();
|
|
38
|
+
const moduleName = `${NAME} ${options.projectName}`;
|
|
40
39
|
const logLevel = resolveLogLevel(options.configuration?.log);
|
|
41
|
-
const logger = new
|
|
42
|
-
if (logLevel >=
|
|
40
|
+
const logger = new ToolsLogger({ transports: [new UI5ToolingTransport({ moduleName })], logLevel });
|
|
41
|
+
if (logLevel >= LogLevel.Debug) {
|
|
43
42
|
logger.debug({ ...options.configuration, credentials: undefined });
|
|
44
43
|
}
|
|
45
|
-
const config =
|
|
46
|
-
|
|
44
|
+
const config = validateConfig(options.configuration, logger);
|
|
45
|
+
replaceEnvVariables(config);
|
|
47
46
|
// The calling client can use either the projectNamespace or projectName when creating the workspace, needs to match when creating the archive.
|
|
48
|
-
const archive = await
|
|
49
|
-
await
|
|
47
|
+
const archive = await createUi5Archive(logger, workspace, options.projectNamespace ?? options.projectName, config.exclude);
|
|
48
|
+
await deploy(archive, config, logger);
|
|
50
49
|
}
|
|
51
|
-
|
|
50
|
+
export default task;
|
|
52
51
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap-ux/deploy-tooling",
|
|
3
3
|
"description": "UI5 CLI tasks to deploy to ABAP systems",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"repository": {
|
|
5
6
|
"type": "git",
|
|
6
7
|
"url": "https://github.com/SAP/open-ux-tools.git",
|
|
@@ -9,7 +10,7 @@
|
|
|
9
10
|
"bugs": {
|
|
10
11
|
"url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Adeploy-tooling"
|
|
11
12
|
},
|
|
12
|
-
"version": "0.
|
|
13
|
+
"version": "1.0.0",
|
|
13
14
|
"license": "Apache-2.0",
|
|
14
15
|
"author": "@SAP/ux-tools-team",
|
|
15
16
|
"main": "dist/index.js",
|
|
@@ -31,19 +32,20 @@
|
|
|
31
32
|
"dotenv": "17.4.2",
|
|
32
33
|
"prompts": "2.4.2",
|
|
33
34
|
"adm-zip": "0.5.16",
|
|
34
|
-
"chalk": "
|
|
35
|
-
"@sap-ux/
|
|
36
|
-
"@sap-ux/
|
|
37
|
-
"@sap-ux/inquirer-common": "0.
|
|
38
|
-
"@sap-ux/logger": "0.
|
|
39
|
-
"@sap-ux/system-access": "0.
|
|
40
|
-
"@sap-ux/ui5-config": "0.
|
|
41
|
-
"@sap-ux/project-input-validator": "0.
|
|
35
|
+
"chalk": "5.3.0",
|
|
36
|
+
"@sap-ux/btp-utils": "2.0.0",
|
|
37
|
+
"@sap-ux/axios-extension": "2.0.0",
|
|
38
|
+
"@sap-ux/inquirer-common": "1.0.0",
|
|
39
|
+
"@sap-ux/logger": "1.0.0",
|
|
40
|
+
"@sap-ux/system-access": "1.0.0",
|
|
41
|
+
"@sap-ux/ui5-config": "1.0.0",
|
|
42
|
+
"@sap-ux/project-input-validator": "1.0.0"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
45
|
+
"@jest/globals": "30.3.0",
|
|
44
46
|
"@types/prompts": "2.4.9",
|
|
45
47
|
"@types/adm-zip": "0.5.8",
|
|
46
|
-
"@sap-ux/store": "
|
|
48
|
+
"@sap-ux/store": "2.0.0"
|
|
47
49
|
},
|
|
48
50
|
"engines": {
|
|
49
51
|
"node": ">=22.x"
|
|
@@ -55,8 +57,8 @@
|
|
|
55
57
|
"format": "prettier --write '**/*.{js,json,ts,yaml,yml}' --ignore-path ../../.prettierignore",
|
|
56
58
|
"lint": "eslint",
|
|
57
59
|
"lint:fix": "eslint --fix",
|
|
58
|
-
"test": "jest --ci --forceExit --detectOpenHandles --colors",
|
|
59
|
-
"test-u": "jest --ci --forceExit --detectOpenHandles --colors -u",
|
|
60
|
+
"test": "cross-env NODE_OPTIONS='--experimental-vm-modules' jest --ci --forceExit --detectOpenHandles --colors",
|
|
61
|
+
"test-u": "cross-env NODE_OPTIONS='--experimental-vm-modules' jest --ci --forceExit --detectOpenHandles --colors -u",
|
|
60
62
|
"link": "pnpm link --global",
|
|
61
63
|
"unlink": "pnpm unlink --global"
|
|
62
64
|
}
|