@sap-ux/deploy-tooling 0.4.5 → 0.6.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/README.md CHANGED
@@ -62,6 +62,9 @@ Options:
62
62
  --cloud target is an ABAP Cloud system
63
63
  --cloud-service-key <file-location> JSON file location with the ABAP cloud service key.
64
64
  --cloud-service-env Load ABAP cloud service properties from either a .env file or your environment variables. Secrets in your .env should not be committed to source control.
65
+ --username ABAP Service username
66
+ --password ABAP Service password
67
+ --create-transport Create a transport request during deployment
65
68
  --transport <transport-request> Transport number to record the change in the ABAP system
66
69
  --name <bsp-name> Project name of the app
67
70
  --strict-ssl Perform certificate validation (use --no-strict-ssl to deactivate it)
@@ -95,6 +98,8 @@ Options:
95
98
  --cloud target is an ABAP Cloud system
96
99
  --cloud-service-key <file-location> JSON file location with the ABAP cloud service key.
97
100
  --cloud-service-env Load ABAP cloud service properties from either a .env file or your environment variables
101
+ --username ABAP Service username
102
+ --password ABAP Service password
98
103
  --transport <transport-request> Transport number to record the change in the ABAP system
99
104
  --name <bsp-name> Project name of the app
100
105
  --strict-ssl Perform certificate validation (use --no-strict-ssl to deactivate it)
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
+ import type { AbapServiceProvider } from '@sap-ux/axios-extension';
3
4
  import type { Logger } from '@sap-ux/logger';
4
5
  import type { BackendSystem } from '@sap-ux/store';
5
6
  import type { AbapDeployConfig, UrlAbapTarget } from '../types';
@@ -14,6 +15,16 @@ type ServiceAuth = Required<Pick<BackendSystem, 'serviceKeys' | 'name'>> & {
14
15
  * @returns {*} {(Promise<T | undefined>)} - Credentials
15
16
  */
16
17
  export declare function getCredentials<T extends BasicAuth | ServiceAuth | undefined>(target: UrlAbapTarget): Promise<T | undefined>;
18
+ /**
19
+ * Creates a new transport request using adt service.
20
+ *
21
+ * @param config - deployment configuration
22
+ * @param logger - reference to the logger instance
23
+ * @param provider - optional instance of the axios-extension abap service provider
24
+ * @throws error if transport request creation fails
25
+ * @returns transportRequest
26
+ */
27
+ export declare function createTransportRequest(config: AbapDeployConfig, logger: Logger, provider?: AbapServiceProvider): Promise<string>;
17
28
  /**
18
29
  * Deploy the given archive to the given target using the given app description.
19
30
  *
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.undeploy = exports.deploy = exports.getCredentials = void 0;
12
+ exports.undeploy = exports.deploy = exports.createTransportRequest = exports.getCredentials = void 0;
13
13
  const axios_extension_1 = require("@sap-ux/axios-extension");
14
14
  const btp_utils_1 = require("@sap-ux/btp-utils");
15
15
  const store_1 = require("@sap-ux/store");
@@ -109,14 +109,14 @@ function createAbapServiceProvider(options, target) {
109
109
  });
110
110
  }
111
111
  /**
112
- * Create an instance of a UI5AbapRepository service connected to the given target configuration.
112
+ * Create an instance of an AbapServiceProvider connected to the given target configuration.
113
113
  *
114
114
  * @param config - deployment configuration
115
115
  * @param logger - optional reference to the logger instance
116
116
  * @returns service instance
117
117
  */
118
- function createDeployService(config, logger) {
119
- var _a, _b, _c, _d;
118
+ function getAbapServiceProvider(config, logger) {
119
+ var _a, _b, _c;
120
120
  return __awaiter(this, void 0, void 0, function* () {
121
121
  let provider;
122
122
  const options = {};
@@ -151,7 +151,7 @@ function createDeployService(config, logger) {
151
151
  else {
152
152
  throw new Error('Unable to handle the configuration in the current environment.');
153
153
  }
154
- return provider.getUi5AbapRepository((_d = config.target) === null || _d === void 0 ? void 0 : _d.service);
154
+ return provider;
155
155
  });
156
156
  }
157
157
  /**
@@ -159,16 +159,16 @@ function createDeployService(config, logger) {
159
159
  *
160
160
  * @param command - the request type deploy | undeploy
161
161
  * @param error - thrown error object
162
- * @param service - instance of the axios-extension deployment service
162
+ * @param provider - instance of the axios-extension abap service provider
163
163
  * @param config - configuration used for the previous request
164
164
  * @param logger - reference to the logger instance
165
165
  * @param archive - archive file that is to be deployed
166
166
  */
167
- function handleError(command, error, service, config, logger, archive) {
167
+ function handleError(command, error, provider, config, logger, archive) {
168
168
  return __awaiter(this, void 0, void 0, function* () {
169
169
  const retry = config.retry === undefined ? true : config.retry;
170
170
  if (retry && (0, axios_extension_1.isAxiosError)(error)) {
171
- const success = yield handleAxiosError(command, error.response, service, config, logger, archive);
171
+ const success = yield axiosErrorRetryHandler(command, error.response, provider, config, logger, archive);
172
172
  if (success) {
173
173
  return;
174
174
  }
@@ -181,43 +181,74 @@ function handleError(command, error, service, config, logger, archive) {
181
181
  throw error;
182
182
  });
183
183
  }
184
+ /**
185
+ * Handler for 412 error code.
186
+ *
187
+ * @param command - the request type deploy | undeploy
188
+ * @param provider - instance of the axios-extension abap service provider
189
+ * @param config - configuration used for the previous request
190
+ * @param logger - reference to the logger instance
191
+ * @param archive - archive file that is to be deployed
192
+ * @returns true if the error was handled otherwise false is returned
193
+ */
194
+ function handle412Error(command, provider, config, logger, archive) {
195
+ return __awaiter(this, void 0, void 0, function* () {
196
+ logger.warn('An app in the same repository with different sap app id found.');
197
+ if (config.yes || (yield (0, prompt_1.promptConfirmation)('Do you want to overwrite (Y/n)?'))) {
198
+ yield deploymentCommands[command](provider, Object.assign(Object.assign({}, config), { safe: false, retry: false }), logger, archive);
199
+ return true;
200
+ }
201
+ else {
202
+ return false;
203
+ }
204
+ });
205
+ }
206
+ /**
207
+ * Handler for 401 error code.
208
+ *
209
+ * @param command - the request type deploy | undeploy
210
+ * @param provider - instance of the axios-extension abap service provider
211
+ * @param config - configuration used for the previous request
212
+ * @param logger - reference to the logger instance
213
+ * @param archive - archive file that is to be deployed
214
+ * @returns true if the error was handled otherwise false is returned
215
+ */
216
+ function handle401Error(command, provider, config, logger, archive) {
217
+ var _a;
218
+ return __awaiter(this, void 0, void 0, function* () {
219
+ logger.warn(`${command === "tryDeploy" /* TryCommands.Deploy */ ? 'Deployment' : 'Undeployment'} failed with authentication error.`);
220
+ 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)');
221
+ logger.info('Please enter your credentials.');
222
+ const service = getUi5AbapRepositoryService(provider, config, logger);
223
+ const credentials = yield (0, prompt_1.promptCredentials)((_a = service.defaults.auth) === null || _a === void 0 ? void 0 : _a.username);
224
+ if (Object.keys(credentials).length) {
225
+ service.defaults.auth = credentials;
226
+ yield deploymentCommands[command](provider, config, logger, archive);
227
+ return true;
228
+ }
229
+ else {
230
+ return false;
231
+ }
232
+ });
233
+ }
184
234
  /**
185
235
  * Main function for different deploy retry handling.
186
236
  *
187
237
  * @param command - the request type deploy | undeploy
188
238
  * @param response - response of that triggered and axios error
189
- * @param service - instance of the axios-extension deployment service
239
+ * @param provider - instance of the axios-extension abap service provider
190
240
  * @param config - configuration used for the previous request
191
241
  * @param logger - reference to the logger instance
192
242
  * @param archive - archive file that is to be deployed
193
243
  * @returns true if the error was handled otherwise false is return or an error is raised
194
244
  */
195
- function handleAxiosError(command, response, service, config, logger, archive) {
196
- var _a;
245
+ function axiosErrorRetryHandler(command, response, provider, config, logger, archive) {
197
246
  return __awaiter(this, void 0, void 0, function* () {
198
247
  switch (response === null || response === void 0 ? void 0 : response.status) {
199
248
  case 401:
200
- logger.warn(`${command === "tryDeploy" /* TryCommands.Deploy */ ? 'Deployment' : 'Undeployment'} failed with authentication error.`);
201
- 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)');
202
- logger.info('Please enter your credentials.');
203
- const credentials = yield (0, prompt_1.promptCredentials)((_a = service.defaults.auth) === null || _a === void 0 ? void 0 : _a.username);
204
- if (Object.keys(credentials).length) {
205
- service.defaults.auth = credentials;
206
- yield deploymentCommands[command](service, config, logger, archive);
207
- return true;
208
- }
209
- else {
210
- return false;
211
- }
249
+ return handle401Error(command, provider, config, logger, archive);
212
250
  case 412:
213
- logger.warn('An app in the same repository with different sap app id found.');
214
- if (config.yes || (yield (0, prompt_1.promptConfirmation)('Do you want to overwrite (Y/n)?'))) {
215
- yield deploymentCommands[command](service, Object.assign(Object.assign({}, config), { safe: false, retry: false }), logger, archive);
216
- return true;
217
- }
218
- else {
219
- return false;
220
- }
251
+ return handle412Error(command, provider, config, logger, archive);
221
252
  default:
222
253
  return false;
223
254
  }
@@ -226,20 +257,56 @@ function handleAxiosError(command, response, service, config, logger, archive) {
226
257
  /**
227
258
  * Generate a Ui5AbapRepositoryService instance from the supplied deployment config.
228
259
  *
260
+ * @param provider - instance of the axios-extension abap service provider
229
261
  * @param config - deployment configuration
230
262
  * @param logger - reference to the logger instance
231
263
  * @returns service returns the UI5 ABAP Repository service
232
264
  */
233
- function getAbapService(config, logger) {
265
+ function getUi5AbapRepositoryService(provider, config, logger) {
266
+ var _a;
267
+ const service = provider.getUi5AbapRepository((_a = config.target) === null || _a === void 0 ? void 0 : _a.service);
268
+ service.log = logger;
269
+ if (!config.strictSsl) {
270
+ logger.warn('You chose not to validate SSL certificate. Please verify the server certificate is trustful before proceeding. See documentation for recommended configuration (https://help.sap.com/viewer/17d50220bcd848aa854c9c182d65b699/Latest/en-US/4b318bede7eb4021a8be385c46c74045.html).');
271
+ }
272
+ return service;
273
+ }
274
+ /**
275
+ * Creates a new transport request using adt service.
276
+ *
277
+ * @param config - deployment configuration
278
+ * @param logger - reference to the logger instance
279
+ * @param provider - optional instance of the axios-extension abap service provider
280
+ * @throws error if transport request creation fails
281
+ * @returns transportRequest
282
+ */
283
+ function createTransportRequest(config, logger, provider) {
284
+ var _a;
234
285
  return __awaiter(this, void 0, void 0, function* () {
235
- const service = yield createDeployService(config, logger);
236
- service.log = logger;
237
- if (!config.strictSsl) {
238
- logger.warn('You chose not to validate SSL certificate. Please verify the server certificate is trustful before proceeding. See documentation for recommended configuration (https://help.sap.com/viewer/17d50220bcd848aa854c9c182d65b699/Latest/en-US/4b318bede7eb4021a8be385c46c74045.html).');
286
+ try {
287
+ if (!provider) {
288
+ provider = yield getAbapServiceProvider(config, logger);
289
+ }
290
+ const adtService = yield provider.getAdtService(axios_extension_1.TransportRequestService);
291
+ logger.debug(`ADTService created for application ${config.app.name}, ${!adtService}.`);
292
+ const transportRequest = yield (adtService === null || adtService === void 0 ? void 0 : adtService.createTransportRequest({
293
+ packageName: (_a = config.app.package) !== null && _a !== void 0 ? _a : '',
294
+ ui5AppName: config.app.name,
295
+ description: 'Created by @sap-ux/deploy-tooling'
296
+ }));
297
+ if (transportRequest) {
298
+ logger.info(`Transport request ${transportRequest} created for application ${config.app.name}.`);
299
+ return transportRequest;
300
+ }
301
+ throw new Error(`Transport request could not be created for application ${config.app.name}.`);
302
+ }
303
+ catch (e) {
304
+ logger.error(`Transport request could not be created for application ${config.app.name}. Please create it manually and re-run deployment configuration for this project.`);
305
+ throw e;
239
306
  }
240
- return service;
241
307
  });
242
308
  }
309
+ exports.createTransportRequest = createTransportRequest;
243
310
  /**
244
311
  * Generic method to run the deployment request i.e. deploy | undeploy.
245
312
  *
@@ -250,22 +317,28 @@ function getAbapService(config, logger) {
250
317
  */
251
318
  function runCommand(command, config, logger, archive = Buffer.from('')) {
252
319
  return __awaiter(this, void 0, void 0, function* () {
253
- const service = yield getAbapService(config, logger);
320
+ const provider = yield getAbapServiceProvider(config, logger);
254
321
  logger.info(`Starting to ${command === "tryDeploy" /* TryCommands.Deploy */ ? 'deploy' : 'undeploy'}${config.test === true ? ' in test mode' : ''}.`);
255
- yield deploymentCommands[command](service, config, logger, archive);
322
+ yield deploymentCommands[command](provider, config, logger, archive);
256
323
  });
257
324
  }
258
325
  /**
259
326
  * Try executing the deployment command and handle known errors.
260
327
  *
261
- * @param service - instance of the axios-extension deployment service
328
+ * @param provider - instance of the axios-extension abap service provider
262
329
  * @param config - deployment configuration
263
330
  * @param logger - reference to the logger instance
264
331
  * @param archive - archive file that is to be deployed
265
332
  */
266
- function tryDeploy(service, config, logger, archive) {
333
+ function tryDeploy(provider, config, logger, archive) {
267
334
  return __awaiter(this, void 0, void 0, function* () {
268
335
  try {
336
+ if (config.createTransport) {
337
+ config.app.transport = yield createTransportRequest(config, logger, provider);
338
+ // Reset as we dont want other flows kicking it off again!
339
+ config.createTransport = false;
340
+ }
341
+ const service = getUi5AbapRepositoryService(provider, config, logger);
269
342
  yield service.deploy({ archive, bsp: config.app, testMode: config.test, safeMode: config.safe });
270
343
  if (config.test === true) {
271
344
  logger.info('Deployment in TestMode completed. A successful TestMode execution does not necessarily mean that your upload will be successful.');
@@ -275,7 +348,7 @@ function tryDeploy(service, config, logger, archive) {
275
348
  }
276
349
  }
277
350
  catch (error) {
278
- yield handleError("tryDeploy" /* TryCommands.Deploy */, error, service, config, logger, archive);
351
+ yield handleError("tryDeploy" /* TryCommands.Deploy */, error, provider, config, logger, archive);
279
352
  }
280
353
  });
281
354
  }
@@ -298,13 +371,14 @@ exports.deploy = deploy;
298
371
  /**
299
372
  * Try executing the undeployment command and handle known errors.
300
373
  *
301
- * @param service - instance of the axios-extension deployment service
374
+ * @param provider - instance of the axios-extension abap service provider
302
375
  * @param config - deployment configuration
303
376
  * @param logger - reference to the logger instance
304
377
  */
305
- function tryUndeploy(service, config, logger) {
378
+ function tryUndeploy(provider, config, logger) {
306
379
  return __awaiter(this, void 0, void 0, function* () {
307
380
  try {
381
+ const service = getUi5AbapRepositoryService(provider, config, logger);
308
382
  yield service.undeploy({ bsp: config.app, testMode: config.test });
309
383
  if (config.test === true) {
310
384
  logger.info('Undeployment in TestMode completed. A successful TestMode execution does not necessarily mean that your undeploy will be successful.');
@@ -314,7 +388,7 @@ function tryUndeploy(service, config, logger) {
314
388
  }
315
389
  }
316
390
  catch (error) {
317
- yield handleError("tryUndeploy" /* TryCommands.UnDeploy */, error, service, config, logger, Buffer.from(''));
391
+ yield handleError("tryUndeploy" /* TryCommands.UnDeploy */, error, provider, config, logger, Buffer.from(''));
318
392
  }
319
393
  });
320
394
  }
@@ -13,7 +13,7 @@ export declare function promptConfirmation(message: string): Promise<boolean>;
13
13
  * @param username - optional username that is to be offered as default
14
14
  * @returns credentials object with username/password
15
15
  */
16
- export declare function promptCredentials(username?: string): Promise<prompts.Answers<"password" | "username">>;
16
+ export declare function promptCredentials(username?: string): Promise<prompts.Answers<"username" | "password">>;
17
17
  /**
18
18
  * Prompt for the location of the service keys.
19
19
  *
@@ -145,6 +145,22 @@ function mergeTarget(baseTarget, options) {
145
145
  service: (_d = options.service) !== null && _d !== void 0 ? _d : baseTarget === null || baseTarget === void 0 ? void 0 : baseTarget.service
146
146
  };
147
147
  }
148
+ /**
149
+ * Merge CLI and environment credentials.
150
+ *
151
+ * @param taskConfig - base configuration from the file
152
+ * @param options - CLI options
153
+ * @returns merged credentials
154
+ */
155
+ function mergeCredentials(taskConfig, options) {
156
+ var _a, _b, _c, _d;
157
+ let credentials = taskConfig.credentials;
158
+ // Support CLI params and|or dotenv file
159
+ if (options.username || process.env.SERVICE_USERNAME) {
160
+ credentials = Object.assign(Object.assign({}, (credentials !== null && credentials !== void 0 ? credentials : {})), { username: (_b = (_a = options.username) !== null && _a !== void 0 ? _a : process.env.SERVICE_USERNAME) !== null && _b !== void 0 ? _b : '', password: (_d = (_c = options.password) !== null && _c !== void 0 ? _c : process.env.SERVICE_PASSWORD) !== null && _d !== void 0 ? _d : '' });
161
+ }
162
+ return credentials;
163
+ }
148
164
  /**
149
165
  * Merge the configuration from the ui5*.yaml with CLI options.
150
166
  *
@@ -162,12 +178,13 @@ function mergeConfig(taskConfig, options) {
162
178
  transport: (_g = options.transport) !== null && _g !== void 0 ? _g : (_h = taskConfig.app) === null || _h === void 0 ? void 0 : _h.transport
163
179
  };
164
180
  const target = mergeTarget(taskConfig.target, options);
165
- const config = { app, target, credentials: taskConfig.credentials };
181
+ const config = { app, target, credentials: mergeCredentials(taskConfig, options) };
166
182
  config.test = mergeFlag(options.test, taskConfig.test);
167
183
  config.safe = mergeFlag(options.safe, taskConfig.safe);
168
184
  config.keep = mergeFlag(options.keep, taskConfig.keep);
169
185
  config.strictSsl = mergeFlag(options.strictSsl, taskConfig.strictSsl);
170
186
  config.yes = mergeFlag(options.yes, taskConfig.yes);
187
+ config.createTransport = mergeFlag(options.createTransport, taskConfig.createTransport);
171
188
  config.retry = process.env.NO_RETRY ? !process.env.NO_RETRY : mergeFlag(options.retry, taskConfig.retry);
172
189
  if (!options.archiveUrl && !options.archivePath && !options.archiveFolder) {
173
190
  options.archiveFolder = 'dist';
package/dist/cli/index.js CHANGED
@@ -39,6 +39,16 @@ function createCommand(name) {
39
39
  .addOption(new commander_1.Option('--cloud-service-key <file-location>', 'JSON file location with the ABAP cloud service key.').conflicts('destination'))
40
40
  .addOption(new commander_1.Option('--cloud-service-env', 'Read ABAP cloud service properties from environment variables or .env file').conflicts(['cloudServiceKey', 'destination']))
41
41
  .option('--transport <transport-request>', 'Transport number to record the change in the ABAP system')
42
+ .addOption(new commander_1.Option('--username <username>', 'ABAP System username').conflicts([
43
+ 'cloudServiceKey',
44
+ 'cloudServiceEnv',
45
+ 'destination'
46
+ ]))
47
+ .addOption(new commander_1.Option('--password <password>', 'ABAP System password').conflicts([
48
+ 'cloudServiceKey',
49
+ 'cloudServiceEnv',
50
+ 'destination'
51
+ ]))
42
52
  .option('--name <bsp-name>', 'Project name of the app')
43
53
  .option('--strict-ssl', 'Perform certificate validation (use --no-strict-ssl to deactivate it)')
44
54
  .option('--query-params <param1=value&param2=value>', 'Additional parameters that are to be added to calls to the target.')
@@ -48,6 +58,7 @@ function createCommand(name) {
48
58
  command
49
59
  .option('--package <abap-package>', 'Package name for deploy target ABAP system')
50
60
  .option('--description <description>', 'Project description of the app')
61
+ .addOption(new commander_1.Option('--create-transport', 'Create transport request during deployment').conflicts(['transport']))
51
62
  // SafeMode: Example: If the deployment would overwrite a repository that contains an app with a different sap.app/id and SafeMode is true, HTTP status code 412 (Precondition Failed) with further information would be returned.
52
63
  .option('--safe', 'Prevents accidentally breaking deployments.')
53
64
  .option('--keep', 'Keep a copy of the deployed archive in the project folder.');
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import task from './ui5';
2
+ import { createTransportRequest } from './base';
3
+ export * from './types';
2
4
  export * from './cli';
3
- export { task };
5
+ export { task, createTransportRequest };
4
6
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -17,8 +17,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.task = void 0;
20
+ exports.createTransportRequest = exports.task = void 0;
21
21
  const ui5_1 = __importDefault(require("./ui5"));
22
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);
23
26
  __exportStar(require("./cli"), exports);
24
27
  //# sourceMappingURL=index.js.map
@@ -50,6 +50,10 @@ export interface CommonOptions {
50
50
  * '--no-retry' cli param negates the retry value which is true by default
51
51
  */
52
52
  retry?: boolean;
53
+ /**
54
+ * If set to true, a transport request will be created during deployment
55
+ */
56
+ createTransport?: boolean;
53
57
  }
54
58
  export interface AbapDeployConfig extends CommonOptions {
55
59
  target: AbapTarget;
@@ -64,5 +68,7 @@ export interface CliOptions extends Partial<BspConfig>, Partial<DestinationAbapT
64
68
  cloudServiceKey?: string;
65
69
  queryParams?: string;
66
70
  cloudServiceEnv?: boolean;
71
+ username?: string;
72
+ password?: string;
67
73
  }
68
74
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Adeploy-tooling"
11
11
  },
12
- "version": "0.4.5",
12
+ "version": "0.6.0",
13
13
  "license": "Apache-2.0",
14
14
  "author": "@SAP/ux-tools-team",
15
15
  "main": "dist/index.js",