trm-core 10.0.1 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.txt +14 -0
- package/dist/actions/checkEngines/analyze.js +6 -0
- package/dist/actions/checkSapEntries/analyze.d.ts +2 -0
- package/dist/actions/checkSapEntries/analyze.js +100 -18
- package/dist/actions/commons/setSystemPackages.js +1 -1
- package/dist/actions/commons/utils/actionLocks.d.ts +2 -1
- package/dist/actions/commons/utils/actionLocks.js +8 -1
- package/dist/actions/commons/utils/index.d.ts +1 -0
- package/dist/actions/commons/utils/index.js +1 -0
- package/dist/actions/commons/utils/packageCleanup.d.ts +8 -0
- package/dist/actions/commons/utils/packageCleanup.js +59 -10
- package/dist/actions/commons/utils/releaseDeletionTransport.js +11 -4
- package/dist/actions/commons/utils/trmBackend.d.ts +20 -0
- package/dist/actions/commons/utils/trmBackend.js +64 -0
- package/dist/actions/install/addNamespace.js +5 -0
- package/dist/actions/install/checkSapEntries.js +1 -1
- package/dist/actions/install/checkTransports.js +40 -1
- package/dist/actions/install/generateLandscapeTransport.js +4 -1
- package/dist/actions/install/generateUpdateTransport.d.ts +7 -0
- package/dist/actions/install/generateUpdateTransport.js +75 -8
- package/dist/actions/install/importBatch.js +0 -0
- package/dist/actions/install/index.d.ts +10 -0
- package/dist/actions/install/index.js +6 -3
- package/dist/actions/install/init.js +12 -2
- package/dist/actions/install/prepareCust.js +9 -4
- package/dist/actions/install/prepareDevc.js +9 -4
- package/dist/actions/install/prepareLang.js +9 -4
- package/dist/actions/install/prepareTadir.js +9 -4
- package/dist/actions/install/setInstallDevclass.js +17 -3
- package/dist/actions/install/updatePackageData.d.ts +5 -0
- package/dist/actions/install/updatePackageData.js +37 -18
- package/dist/client/RESTClient.js +2 -5
- package/dist/client/RFCClient.js +3 -5
- package/dist/systemConnector/SystemConnectorBase.js +25 -3
- package/dist/transport/Transport.js +17 -3
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ const trm_commons_2 = require("trm-commons");
|
|
|
19
19
|
const systemConnector_1 = require("../../systemConnector");
|
|
20
20
|
const commons_1 = require("../../commons");
|
|
21
21
|
const utils_1 = require("../commons/utils");
|
|
22
|
+
const crypto_1 = require("crypto");
|
|
22
23
|
/** Throws when any of the objects is locked in a SAP transport request. */
|
|
23
24
|
function checkObjectsLocks(e071) {
|
|
24
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -205,6 +206,11 @@ exports.checkTransports = {
|
|
|
205
206
|
if (skippedCust.includes(transport.trkorr)) {
|
|
206
207
|
readEntries = false;
|
|
207
208
|
}
|
|
209
|
+
// the fixed TADIR transport of trm-server/trm-rest only comes with the artifact (below)
|
|
210
|
+
if ((context.runtime.isTrmServer || context.runtime.isTrmRest) && transport.type === transport_1.TrmTransportIdentifier.TADIR
|
|
211
|
+
&& utils_1.TRM_FIXED_TADIR_TRANSPORTS[context.runtime.package.data.manifest.name] === transport.trkorr) {
|
|
212
|
+
readEntries = false;
|
|
213
|
+
}
|
|
208
214
|
if (readEntries) {
|
|
209
215
|
const entries = yield context.rawInput.packageData.registry.transportEntries(context.runtime.package.data.manifest.name, context.runtime.package.data.manifest.version, transport.trkorr);
|
|
210
216
|
const binaries = {
|
|
@@ -235,6 +241,29 @@ exports.checkTransports = {
|
|
|
235
241
|
}
|
|
236
242
|
}
|
|
237
243
|
}
|
|
244
|
+
// The registry metadata can omit a transport of the release, and the fixed TADIR transport of
|
|
245
|
+
// trm-server and trm-rest is never downloaded alone: read them from the artifact, once its integrity is verified.
|
|
246
|
+
if (!context.runtime.transports.devc || !context.runtime.transports.tadir) {
|
|
247
|
+
trm_commons_1.Logger.log(`No ${!context.runtime.transports.devc ? 'DEVC' : 'TADIR'} transport to download from the registry: reading the release artifact`, true);
|
|
248
|
+
trm_commons_1.Logger.loading(`Reading package transports from the release artifact...`);
|
|
249
|
+
const artifact = yield context.rawInput.packageData.registry.downloadArtifact(context.runtime.package.data.manifest.name, context.runtime.package.data.manifest.version);
|
|
250
|
+
const expectedChecksum = context.runtime.package.data.checksum;
|
|
251
|
+
const checksum = (0, crypto_1.createHash)('sha512').update(artifact.binary).digest('base64');
|
|
252
|
+
if (!expectedChecksum || checksum !== expectedChecksum) {
|
|
253
|
+
trm_commons_1.Logger.error(`SECURITY ISSUE! Release artifact integrity does NOT match the registry SHA ${expectedChecksum}: received ${checksum}`, { important: true });
|
|
254
|
+
throw new Error(`Cannot continue due to security issues.`);
|
|
255
|
+
}
|
|
256
|
+
for (const binary of yield artifact.getTransportBinaries()) {
|
|
257
|
+
if (binary.type === transport_1.TrmTransportIdentifier.DEVC && !context.runtime.transports.devc) {
|
|
258
|
+
context.runtime.transports.devc = { binaries: binary };
|
|
259
|
+
mergeEntries(binary.entries);
|
|
260
|
+
}
|
|
261
|
+
else if (binary.type === transport_1.TrmTransportIdentifier.TADIR && !context.runtime.transports.tadir) {
|
|
262
|
+
context.runtime.transports.tadir = { binaries: binary };
|
|
263
|
+
mergeEntries(binary.entries);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
238
267
|
}
|
|
239
268
|
//4- check devc and tadir existance
|
|
240
269
|
if (!context.runtime.transports.devc) {
|
|
@@ -272,6 +301,7 @@ exports.checkTransports = {
|
|
|
272
301
|
}
|
|
273
302
|
//8- check objects existance
|
|
274
303
|
const checkedTadir = existenceCheckObjects(mergedTADIR);
|
|
304
|
+
trm_commons_1.Logger.loading(`Checking whether ${checkedTadir.length} package object${checkedTadir.length === 1 ? '' : 's'} already exist${checkedTadir.length === 1 ? 's' : ''}...`);
|
|
275
305
|
const existingObjects = checkedTadir.length > 0 ? yield findExistingObjects(context, checkedTadir) : [];
|
|
276
306
|
// lock-resources checks again, once locked, that no other object appeared
|
|
277
307
|
context.runtime.existingObjects = existingObjects;
|
|
@@ -279,9 +309,18 @@ exports.checkTransports = {
|
|
|
279
309
|
//if updating and existing object is part of the package (devclass in hierarchy) ok, else throw error
|
|
280
310
|
if (existingObjects.length > 0) {
|
|
281
311
|
// Name the installed TRM package that contains each existing object: it can't be taken over silently.
|
|
312
|
+
trm_commons_1.Logger.loading(`Checking ownership of ${existingObjects.length} existing object${existingObjects.length === 1 ? '' : 's'}...`);
|
|
282
313
|
const owners = new Map();
|
|
314
|
+
// objects share few SAP packages: look each one up once
|
|
315
|
+
const packageOwners = new Map();
|
|
283
316
|
for (const o of existingObjects) {
|
|
284
|
-
|
|
317
|
+
if (!o.devclass) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (!packageOwners.has(o.devclass)) {
|
|
321
|
+
packageOwners.set(o.devclass, (0, utils_1.getOwningInstallation)(o.devclass, context.rawInput.contextData.systemPackages || [], context.runtime.update));
|
|
322
|
+
}
|
|
323
|
+
const owner = yield packageOwners.get(o.devclass);
|
|
285
324
|
if (owner) {
|
|
286
325
|
owners.set(o, owner.packageName);
|
|
287
326
|
}
|
|
@@ -125,7 +125,10 @@ exports.generateLandscapeTransport = {
|
|
|
125
125
|
//8- lock objects
|
|
126
126
|
//what is lockable gets locked here
|
|
127
127
|
//all workbench should be lockable here
|
|
128
|
-
|
|
128
|
+
//a legacy backend has no API for it
|
|
129
|
+
if (!context.legacyBackend) {
|
|
130
|
+
yield context.output.transport.lock();
|
|
131
|
+
}
|
|
129
132
|
}),
|
|
130
133
|
revert: (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
131
134
|
if (context.output.transport && (yield context.output.transport.canBeDeleted())) {
|
|
@@ -18,3 +18,10 @@ export declare function keepsInstalledCustomizing(context: InstallWorkflowContex
|
|
|
18
18
|
* release without an incoming one.
|
|
19
19
|
*/
|
|
20
20
|
export declare const generateUpdateTransport: Step<InstallWorkflowContext>;
|
|
21
|
+
/**
|
|
22
|
+
* Workflow step that cleans up an upgrade of trm-server or trm-rest, last in the install (see
|
|
23
|
+
* {@link generateUpdateTransport}); every other package is cleaned up before its import. The installed
|
|
24
|
+
* release runs the install: deleting its objects first would remove the APIs the install still calls.
|
|
25
|
+
* Once the upgrade is complete, only the objects the new release doesn't ship are deleted, with its APIs.
|
|
26
|
+
*/
|
|
27
|
+
export declare const generatePostImportUpdateTransport: Step<InstallWorkflowContext>;
|
|
@@ -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.generateUpdateTransport = exports.deleteTemporaryCleanupPackages = void 0;
|
|
12
|
+
exports.generatePostImportUpdateTransport = exports.generateUpdateTransport = exports.deleteTemporaryCleanupPackages = void 0;
|
|
13
13
|
exports.keepsInstalledCustomizing = keepsInstalledCustomizing;
|
|
14
14
|
const trm_commons_1 = require("trm-commons");
|
|
15
15
|
const stopWarning_1 = require("../stopWarning");
|
|
@@ -60,6 +60,11 @@ function keepsInstalledCustomizing(context) {
|
|
|
60
60
|
exports.generateUpdateTransport = {
|
|
61
61
|
name: 'generate-update-transport',
|
|
62
62
|
filter: (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
|
+
if (context.runtime.selfUpdate) {
|
|
64
|
+
// The installed release runs this install: its objects are cleaned up after the import
|
|
65
|
+
trm_commons_1.Logger.log(`Upgrade cleanup of ${context.rawInput.packageData.name} runs after the import`, true);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
63
68
|
//a local (.trm) upgrade generates its deletion transport through the registry the artifact was published to
|
|
64
69
|
if (context.runtime.update) {
|
|
65
70
|
return true;
|
|
@@ -70,19 +75,78 @@ exports.generateUpdateTransport = {
|
|
|
70
75
|
}
|
|
71
76
|
}),
|
|
72
77
|
run: (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
-
|
|
78
|
+
yield cleanupPreviousRelease(context, false);
|
|
79
|
+
}),
|
|
80
|
+
revert: revertUpdateCleanup
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Workflow step that cleans up an upgrade of trm-server or trm-rest, last in the install (see
|
|
84
|
+
* {@link generateUpdateTransport}); every other package is cleaned up before its import. The installed
|
|
85
|
+
* release runs the install: deleting its objects first would remove the APIs the install still calls.
|
|
86
|
+
* Once the upgrade is complete, only the objects the new release doesn't ship are deleted, with its APIs.
|
|
87
|
+
*/
|
|
88
|
+
exports.generatePostImportUpdateTransport = {
|
|
89
|
+
name: 'generate-post-import-update-transport',
|
|
90
|
+
filter: (context) => __awaiter(void 0, void 0, void 0, function* () { return !!context.runtime.selfUpdate; }),
|
|
91
|
+
run: (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
92
|
+
var _a, _b, _c;
|
|
93
|
+
// The new release is installed: a failed cleanup leaves objects of the previous one, it doesn't undo the install
|
|
94
|
+
try {
|
|
95
|
+
yield cleanupPreviousRelease(context, true);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
let revertError;
|
|
99
|
+
if (!context.revert.deleImportStarted) {
|
|
100
|
+
try {
|
|
101
|
+
yield revertUpdateCleanup(context);
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
revertError = e;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const version = context.runtime.update.manifest.get().version;
|
|
108
|
+
trm_commons_1.Logger.warning(`Cleanup of ${context.rawInput.packageData.name} ${version} failed: ${error instanceof Error ? error.message : String(error)}`, { important: true });
|
|
109
|
+
if (revertError) {
|
|
110
|
+
trm_commons_1.Logger.warning(`Cleanup could not be undone either: ${revertError instanceof Error ? revertError.message : String(revertError)}`, { important: true });
|
|
111
|
+
}
|
|
112
|
+
trm_commons_1.Logger.warning(`${context.rawInput.packageData.name} ${context.runtime.package.data.manifest.version} is installed. Objects of ${version} it doesn't ship may be left on ${systemConnector_1.SystemConnector.getDest()}: delete them manually.`, { important: true });
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// The landscape transport is already released: the deletion follows it to the target
|
|
116
|
+
const targetSystem = (_b = (_a = context.rawInput.installData) === null || _a === void 0 ? void 0 : _a.landscapeTransport) === null || _b === void 0 ? void 0 : _b.targetSystem;
|
|
117
|
+
if (targetSystem && ((_c = context.output) === null || _c === void 0 ? void 0 : _c.transport) && (0, utils_1.isDeletionForwardable)(context)) {
|
|
118
|
+
try {
|
|
119
|
+
yield (0, utils_1.forwardDeletionTransport)(context, targetSystem);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
trm_commons_1.Logger.warning(`Deletion transport ${context.revert.dele.trkorr} could not be added to the ${targetSystem} import queue: ${error instanceof Error ? error.message : String(error)}. Add it in STMS after ${context.output.transport.trkorr}.`, { important: true });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}),
|
|
126
|
+
revert: (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
127
|
+
// The imported release stays (see import-batch): objects it doesn't ship stay deleted too.
|
|
128
|
+
// A cleanup that stopped before its deletion transport is undone.
|
|
129
|
+
if (context.revert.deleImportStarted) {
|
|
130
|
+
trm_commons_1.Logger.log(`Keeping the cleanup of ${context.rawInput.packageData.name}: its imported release is not rolled back`, true);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
yield revertUpdateCleanup(context);
|
|
134
|
+
})
|
|
135
|
+
};
|
|
136
|
+
function cleanupPreviousRelease(context, incomingImported) {
|
|
137
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
138
|
+
var _a, _b, _c;
|
|
74
139
|
if (!context.runtime.stopWarningShown) {
|
|
75
140
|
context.runtime.stopWarningShown = true;
|
|
76
141
|
(0, stopWarning_1.stopWarning)('install');
|
|
77
142
|
}
|
|
78
143
|
// The cleanup deletes and re-imports the root package: read it now, so the import can put it back
|
|
79
144
|
// under the superpackage it has on this system (prepare-devc reads it after the cleanup).
|
|
80
|
-
if (((_b = (_a = context.rawInput.installData) === null || _a === void 0 ? void 0 : _a.installDevclass) === null || _b === void 0 ? void 0 : _b.keepOriginal) && !context.runtime.rootDevclassBeforeImport) {
|
|
145
|
+
if (!incomingImported && ((_b = (_a = context.rawInput.installData) === null || _a === void 0 ? void 0 : _a.installDevclass) === null || _b === void 0 ? void 0 : _b.keepOriginal) && !context.runtime.rootDevclassBeforeImport) {
|
|
81
146
|
context.runtime.rootDevclassBeforeImport = yield systemConnector_1.SystemConnector.getDevclass(context.runtime.package.hierarchy.devclass);
|
|
82
147
|
}
|
|
83
148
|
// Read the target lazily: a failure reading the previous release must still be tracked first.
|
|
84
149
|
const installDevclass = (_c = context.rawInput.installData) === null || _c === void 0 ? void 0 : _c.installDevclass;
|
|
85
|
-
const importData = (_d = context.rawInput.installData) === null || _d === void 0 ? void 0 : _d.import;
|
|
86
150
|
const keepCustomizing = keepsInstalledCustomizing(context);
|
|
87
151
|
if (keepCustomizing) {
|
|
88
152
|
const skipped = context.runtime.skippedCust || [];
|
|
@@ -97,6 +161,7 @@ exports.generateUpdateTransport = {
|
|
|
97
161
|
? flattenDevclasses(context.runtime.package.hierarchy)
|
|
98
162
|
: installDevclass.replacements.map(replacement => replacement.installDevclass);
|
|
99
163
|
},
|
|
164
|
+
incomingImported,
|
|
100
165
|
prefix: `(${transport_1.Transport.getTransportIcon()} Upgrade cleanup) `,
|
|
101
166
|
actionName: 'Update',
|
|
102
167
|
requireDeletion: false,
|
|
@@ -107,8 +172,10 @@ exports.generateUpdateTransport = {
|
|
|
107
172
|
return incomingCustomizingRows(context);
|
|
108
173
|
}
|
|
109
174
|
});
|
|
110
|
-
})
|
|
111
|
-
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
function revertUpdateCleanup(context) {
|
|
178
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
179
|
// Rollback of the imported objects ran first: when it failed, they are still on the system
|
|
113
180
|
// and the previous release must not be restored over them.
|
|
114
181
|
const restore = !(context.revert.cleanupImported && !context.revert.cleanupSucceeded);
|
|
@@ -118,5 +185,5 @@ exports.generateUpdateTransport = {
|
|
|
118
185
|
if (restore) {
|
|
119
186
|
yield (0, utils_1.deleteCleanupStagingPackages)(context);
|
|
120
187
|
}
|
|
121
|
-
})
|
|
122
|
-
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
Binary file
|
|
@@ -222,6 +222,11 @@ type WorkflowRuntime = {
|
|
|
222
222
|
lockedNamespaces?: string[];
|
|
223
223
|
/** Required SAP entries missing on the system: the install is aborted by check-engines, with the unmet engines. */
|
|
224
224
|
missingSapEntries?: number;
|
|
225
|
+
/**
|
|
226
|
+
* Upgrade of trm-server or trm-rest: the installed release runs the install itself. Its objects are
|
|
227
|
+
* only cleaned up after the incoming release is imported, and the import can't be rolled back.
|
|
228
|
+
*/
|
|
229
|
+
selfUpdate?: boolean;
|
|
225
230
|
};
|
|
226
231
|
/** Dependency queued for install: missing from the system, or installed in an incompatible version. */
|
|
227
232
|
export type InstallDependencyEntry = {
|
|
@@ -300,6 +305,11 @@ export type InstallActionOutput = {
|
|
|
300
305
|
/** Internal state shared by package-install workflow steps and rollback handlers. */
|
|
301
306
|
export interface InstallWorkflowContext extends IActionContext {
|
|
302
307
|
lockScope?: ActionLockScope;
|
|
308
|
+
/**
|
|
309
|
+
* trm-server/trm-rest upgrade on a backend older than the APIs this trm-core needs (see isLegacyTrmBackend):
|
|
310
|
+
* only the APIs of the installed generation are used.
|
|
311
|
+
*/
|
|
312
|
+
legacyBackend?: boolean;
|
|
303
313
|
/** Custom namespaces already locked by the parent installs of a dependency install. */
|
|
304
314
|
inheritedNamespaceLocks?: string[];
|
|
305
315
|
/** Original action input; optional groups are normalized during initialization. */
|
|
@@ -87,15 +87,18 @@ const installWorkflow = [
|
|
|
87
87
|
generateLandscapeTransport_1.generateLandscapeTransport,
|
|
88
88
|
executePostActivities_1.executePostActivities,
|
|
89
89
|
releaseLandscapeTransport_1.releaseLandscapeTransport,
|
|
90
|
-
updatePackageData_1.updatePackageData
|
|
90
|
+
updatePackageData_1.updatePackageData,
|
|
91
|
+
generateUpdateTransport_1.generatePostImportUpdateTransport
|
|
91
92
|
];
|
|
92
93
|
function runInstall(inputData_1, retainRollback_1) {
|
|
93
94
|
return __awaiter(this, arguments, void 0, function* (inputData, retainRollback, inheritedNamespaceLocks = []) {
|
|
94
95
|
var _a;
|
|
95
|
-
const lockScope = new utils_2.ActionLockScope(WORKFLOW_NAME);
|
|
96
|
-
const context = { rawInput: inputData, lockScope, inheritedNamespaceLocks };
|
|
97
96
|
//a local artifact is locked under the package it installs, as a remote install of it would be
|
|
98
97
|
const lockPackage = yield (0, utils_2.resolveInstallPackage)(inputData.packageData.registry, inputData.packageData.name);
|
|
98
|
+
// A legacy backend has no action locks: only trm-server and trm-rest can install there, to upgrade it.
|
|
99
|
+
const legacyBackend = (0, utils_2.isTrmBackendPackage)(lockPackage.registry, lockPackage.name) && (yield (0, utils_2.isLegacyTrmBackend)());
|
|
100
|
+
const lockScope = new utils_2.ActionLockScope(WORKFLOW_NAME, !legacyBackend);
|
|
101
|
+
const context = { rawInput: inputData, lockScope, inheritedNamespaceLocks, legacyBackend };
|
|
99
102
|
yield lockScope.acquire([(0, utils_2.packageLockResource)(lockPackage.registry, lockPackage.name)]);
|
|
100
103
|
const release = () => __awaiter(this, void 0, void 0, function* () {
|
|
101
104
|
var _a;
|
|
@@ -225,10 +225,16 @@ exports.init = {
|
|
|
225
225
|
//5- check if already installed
|
|
226
226
|
context.runtime.update = context.rawInput.contextData.systemPackages.find(o => manifest_1.Manifest.compare(o.manifest, new manifest_1.Manifest(context.runtime.package.data.manifest), false));
|
|
227
227
|
if (context.runtime.update) {
|
|
228
|
+
const installedVersion = context.runtime.update.manifest.get().version;
|
|
229
|
+
// trm-server and trm-rest run this install: see the selfUpdate steps
|
|
230
|
+
context.runtime.selfUpdate = context.runtime.isTrmServer || context.runtime.isTrmRest;
|
|
228
231
|
context.runtime.previousInstallPackages = yield systemConnector_1.SystemConnector.getInstallPackages(context.rawInput.packageData.name, context.runtime.installRegistry);
|
|
229
|
-
|
|
232
|
+
// A legacy backend has no install transports table: trm-server and trm-rest ship
|
|
233
|
+
// no customizing or translations, so there is nothing recorded to read.
|
|
234
|
+
if (!context.legacyBackend) {
|
|
235
|
+
context.runtime.previousInstallTransports = yield systemConnector_1.SystemConnector.getInstallTransports(context.rawInput.packageData.name, context.runtime.installRegistry);
|
|
236
|
+
}
|
|
230
237
|
const installVersion = context.runtime.package.data.manifest.version;
|
|
231
|
-
const installedVersion = context.runtime.update.manifest.get().version;
|
|
232
238
|
//transports TRM generated for the package (e.g. of a rolled back release) aren't changes made on the system
|
|
233
239
|
const dirtyEntries = yield (0, utils_1.withoutOwnTrmTransports)(context.runtime.update.getDirtyEntries(), context.runtime.update.packageName);
|
|
234
240
|
if ((0, semver_1.eq)(installVersion, installedVersion)) {
|
|
@@ -266,6 +272,10 @@ exports.init = {
|
|
|
266
272
|
trm_commons_1.Logger.warning(`${context.rawInput.packageData.name} has changes made on ${systemConnector_1.SystemConnector.getDest()} that will be overwritten!`, { important: true });
|
|
267
273
|
(0, utils_1.logDirtyEntries)(dirtyEntries);
|
|
268
274
|
}
|
|
275
|
+
if (context.runtime.isTrmServer && (0, semver_1.valid)(installedVersion) && (0, semver_1.lt)(installedVersion, utils_1.TRM_SERVER_API_VERSION) && !(0, semver_1.lt)(installVersion, utils_1.TRM_SERVER_API_VERSION)) {
|
|
276
|
+
// the install continues with the imported release: an unauthorized user can't complete it
|
|
277
|
+
trm_commons_1.Logger.warning(`trm-server ${utils_1.TRM_SERVER_API_VERSION} authorizes users with authorization object ZTRM_AUTH (ACTVT 16) instead of table /ATRM/USERS: ${systemConnector_1.SystemConnector.getLogonUser()} and the other TRM users need it.`, { important: true });
|
|
278
|
+
}
|
|
269
279
|
}
|
|
270
280
|
}
|
|
271
281
|
else {
|
|
@@ -94,10 +94,15 @@ exports.prepareCust = {
|
|
|
94
94
|
trTarget: systemConnector_1.SystemConnector.getDest()
|
|
95
95
|
});
|
|
96
96
|
//3- test import transport
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
if (context.legacyBackend) {
|
|
98
|
+
trm_commons_1.Logger.log(`Skipping test import: legacy TRM backend`, true);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
trm_commons_1.Logger.loading(`Testing import...`);
|
|
102
|
+
const testRc = yield cust.instance.import(true);
|
|
103
|
+
if (testRc < 0 || testRc > 8) {
|
|
104
|
+
throw new Error(`Test import of customizing failed: check logs.`);
|
|
105
|
+
}
|
|
101
106
|
}
|
|
102
107
|
}));
|
|
103
108
|
}
|
|
@@ -93,10 +93,15 @@ exports.prepareDevc = {
|
|
|
93
93
|
trTarget: systemConnector_1.SystemConnector.getDest()
|
|
94
94
|
});
|
|
95
95
|
//4- test import transport
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
if (context.legacyBackend) {
|
|
97
|
+
trm_commons_1.Logger.log(`Skipping test import: legacy TRM backend`, true);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
trm_commons_1.Logger.loading(`Testing import...`);
|
|
101
|
+
const testRc = yield context.runtime.transports.devc.instance.import(true);
|
|
102
|
+
if (testRc < 0 || testRc > 8) {
|
|
103
|
+
throw new Error(`Test import of SAP packages failed: check logs.`);
|
|
104
|
+
}
|
|
100
105
|
}
|
|
101
106
|
}));
|
|
102
107
|
}),
|
|
@@ -90,10 +90,15 @@ exports.prepareLang = {
|
|
|
90
90
|
trTarget: systemConnector_1.SystemConnector.getDest()
|
|
91
91
|
});
|
|
92
92
|
//3- test import transport
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
if (context.legacyBackend) {
|
|
94
|
+
trm_commons_1.Logger.log(`Skipping test import: legacy TRM backend`, true);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
trm_commons_1.Logger.loading(`Testing import...`);
|
|
98
|
+
const testRc = yield context.runtime.transports.lang.instance.import(true);
|
|
99
|
+
if (testRc < 0 || testRc > 8) {
|
|
100
|
+
throw new Error(`Test import of translations failed: check logs.`);
|
|
101
|
+
}
|
|
97
102
|
}
|
|
98
103
|
}));
|
|
99
104
|
}),
|
|
@@ -75,10 +75,15 @@ exports.prepareTadir = {
|
|
|
75
75
|
trTarget: systemConnector_1.SystemConnector.getDest()
|
|
76
76
|
});
|
|
77
77
|
//3- test import transport
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
if (context.legacyBackend) {
|
|
79
|
+
trm_commons_1.Logger.log(`Skipping test import: legacy TRM backend`, true);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
trm_commons_1.Logger.loading(`Testing import...`);
|
|
83
|
+
const testRc = yield context.runtime.transports.tadir.instance.import(true);
|
|
84
|
+
if (testRc < 0 || testRc > 8) {
|
|
85
|
+
throw new Error(`Test import of workbench failed: check logs.`);
|
|
86
|
+
}
|
|
82
87
|
}
|
|
83
88
|
}));
|
|
84
89
|
}),
|
|
@@ -58,7 +58,21 @@ exports.setInstallDevclass = {
|
|
|
58
58
|
}
|
|
59
59
|
}),
|
|
60
60
|
run: (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
61
|
-
var _a, _b, _c;
|
|
61
|
+
var _a, _b, _c, _d;
|
|
62
|
+
// trm-server and trm-rest are installed in `$` packages (`$TRM...`), unless they are already in their
|
|
63
|
+
// original `/ATRM/` packages: then they stay there. They are never renamed otherwise.
|
|
64
|
+
if (context.runtime.isTrmServer || context.runtime.isTrmRest) {
|
|
65
|
+
const original = (((_a = context.runtime.update) === null || _a === void 0 ? void 0 : _a.getDevclass()) || '').trim().toUpperCase().startsWith('/ATRM/');
|
|
66
|
+
context.rawInput.installData.installDevclass.replacements = (0, addNamespace_1.flattenDevclasses)(context.runtime.package.hierarchy).map(originalDevclass => ({
|
|
67
|
+
originalDevclass,
|
|
68
|
+
installDevclass: original ? originalDevclass : (0, commons_1.adjustTrmServerRestDevclass)(originalDevclass)
|
|
69
|
+
}));
|
|
70
|
+
context.rawInput.installData.installDevclass.keepOriginal = context.rawInput.installData.installDevclass.replacements
|
|
71
|
+
.every(o => o.installDevclass === o.originalDevclass);
|
|
72
|
+
(0, addNamespace_1.getInstallNamespace)(context);
|
|
73
|
+
trm_commons_1.Logger.log(`${context.rawInput.packageData.name} SAP packages: ${context.rawInput.installData.installDevclass.replacements.map(o => `${o.originalDevclass} -> ${o.installDevclass}`).join(', ')}`, true);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
62
76
|
//1- find already defined replacements in system
|
|
63
77
|
if (context.rawInput.installData.installDevclass.replacements.length <= 0) {
|
|
64
78
|
//no input replacements = get from the trm table devclass replacements the corresponding name
|
|
@@ -78,7 +92,7 @@ exports.setInstallDevclass = {
|
|
|
78
92
|
//the release root can have a new original name (e.g. moved to a namespace): a renamed installation keeps its root
|
|
79
93
|
//package, matched by position, so the installation stays where the customer put it
|
|
80
94
|
const releaseRoot = context.runtime.package.hierarchy.devclass;
|
|
81
|
-
const installedRoot = (
|
|
95
|
+
const installedRoot = (_b = context.runtime.update) === null || _b === void 0 ? void 0 : _b.getDevclass();
|
|
82
96
|
if (installedRoot && !context.rawInput.installData.installDevclass.replacements.some(o => o.originalDevclass === releaseRoot)) {
|
|
83
97
|
const storedRoot = context.rawInput.installData.installDevclass.replacements.find(o => o.installDevclass.trim().toUpperCase() === installedRoot.trim().toUpperCase());
|
|
84
98
|
if (storedRoot && storedRoot.installDevclass !== storedRoot.originalDevclass) {
|
|
@@ -133,7 +147,7 @@ exports.setInstallDevclass = {
|
|
|
133
147
|
if (context.runtime.update && hasCustomization) {
|
|
134
148
|
//the installed root devclass can be unknown: fall back to the stored root replacement
|
|
135
149
|
const installedRootDevclass = context.runtime.update.getDevclass()
|
|
136
|
-
|| ((
|
|
150
|
+
|| ((_d = (_c = context.runtime.previousInstallPackages) === null || _c === void 0 ? void 0 : _c.find(o => o.originalDevclass === context.runtime.package.hierarchy.devclass)) === null || _d === void 0 ? void 0 : _d.installDevclass);
|
|
137
151
|
if (installedRootDevclass) {
|
|
138
152
|
updateNamespace = (0, commons_1.getPackageNamespace)(installedRootDevclass);
|
|
139
153
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Step } from "@simonegaffurini/sammarksworkflow";
|
|
2
2
|
import { InstallWorkflowContext } from ".";
|
|
3
|
+
/**
|
|
4
|
+
* Records the installed release: TRM packages table row, install packages and install transports.
|
|
5
|
+
* A trm-server/trm-rest upgrade also records it right after its import, which is never rolled back.
|
|
6
|
+
*/
|
|
7
|
+
export declare function recordInstalledRelease(context: InstallWorkflowContext): Promise<void>;
|
|
3
8
|
/**
|
|
4
9
|
* Workflow step that records the installed release in the target system's TRM package table.
|
|
5
10
|
*
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.updatePackageData = void 0;
|
|
13
|
+
exports.recordInstalledRelease = recordInstalledRelease;
|
|
13
14
|
const trm_commons_1 = require("trm-commons");
|
|
14
15
|
const systemConnector_1 = require("../../systemConnector");
|
|
15
16
|
const utils_1 = require("../commons/utils");
|
|
@@ -33,20 +34,12 @@ function installDevcRows(packageName, packageRegistry, replacements) {
|
|
|
33
34
|
}));
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
*
|
|
41
|
-
* 1- commit new values
|
|
42
|
-
*
|
|
43
|
-
*/
|
|
44
|
-
exports.updatePackageData = {
|
|
45
|
-
name: 'update-package-data',
|
|
46
|
-
run: (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
* Records the installed release: TRM packages table row, install packages and install transports.
|
|
38
|
+
* A trm-server/trm-rest upgrade also records it right after its import, which is never rolled back.
|
|
39
|
+
*/
|
|
40
|
+
function recordInstalledRelease(context) {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47
42
|
var _a, _b;
|
|
48
|
-
trm_commons_1.Logger.loading(`Finalizing install...`);
|
|
49
|
-
//1- commit new values
|
|
50
43
|
trm_commons_1.Logger.loading(`Updating TRM data...`);
|
|
51
44
|
const originalTransport = context.runtime.transports.tadir.instance.trkorr;
|
|
52
45
|
const installTransport = (_a = context.output.transport) === null || _a === void 0 ? void 0 : _a.trkorr;
|
|
@@ -79,7 +72,8 @@ exports.updatePackageData = {
|
|
|
79
72
|
: [])
|
|
80
73
|
]);
|
|
81
74
|
context.revert.metadataPackageRegistry = packageRegistry;
|
|
82
|
-
|
|
75
|
+
// A trm-server/trm-rest upgrade is not rolled back after its import: nothing to restore
|
|
76
|
+
if (context.runtime.update && !context.runtime.selfUpdate) {
|
|
83
77
|
// The installed packages may have been read without their rows: read the stored row
|
|
84
78
|
// before writing, so the revert restores it exactly, or removes the row it wrote.
|
|
85
79
|
// A failed read aborts before any write.
|
|
@@ -101,18 +95,43 @@ exports.updatePackageData = {
|
|
|
101
95
|
// fail while returning the response.
|
|
102
96
|
context.revert.metadataWriteStarted = true;
|
|
103
97
|
yield systemConnector_1.SystemConnector.setInstallDevc(installDevc);
|
|
104
|
-
|
|
105
|
-
|
|
98
|
+
// A legacy backend has neither API: trm-server and trm-rest have no stale mappings nor install transports
|
|
99
|
+
if (!context.legacyBackend) {
|
|
100
|
+
if (staleInstallDevc.length > 0) {
|
|
101
|
+
yield systemConnector_1.SystemConnector.deleteInstallDevc(staleInstallDevc);
|
|
102
|
+
}
|
|
103
|
+
context.revert.metadataTransportsWriteStarted = true;
|
|
104
|
+
yield systemConnector_1.SystemConnector.setInstallTransports(context.rawInput.packageData.name, packageRegistry, installTr);
|
|
106
105
|
}
|
|
107
|
-
context.revert.metadataTransportsWriteStarted = true;
|
|
108
|
-
yield systemConnector_1.SystemConnector.setInstallTransports(context.rawInput.packageData.name, packageRegistry, installTr);
|
|
109
106
|
yield systemConnector_1.SystemConnector.updateTrmPackageData(context.revert.metadataPackageRow);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Workflow step that records the installed release in the target system's TRM package table.
|
|
111
|
+
*
|
|
112
|
+
* Creates/update record in TRM packages table, with its install packages and the
|
|
113
|
+
* customizing and translation transports imported on this system
|
|
114
|
+
*
|
|
115
|
+
* 1- commit new values
|
|
116
|
+
*
|
|
117
|
+
*/
|
|
118
|
+
exports.updatePackageData = {
|
|
119
|
+
name: 'update-package-data',
|
|
120
|
+
run: (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
121
|
+
trm_commons_1.Logger.loading(`Finalizing install...`);
|
|
122
|
+
//1- commit new values
|
|
123
|
+
yield recordInstalledRelease(context);
|
|
110
124
|
}),
|
|
111
125
|
revert: (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
112
126
|
// First installs remove the newly written row through the same atomic SAP operation.
|
|
113
127
|
if (!context.revert.metadataWriteStarted) {
|
|
114
128
|
return;
|
|
115
129
|
}
|
|
130
|
+
if (context.runtime.selfUpdate) {
|
|
131
|
+
// The imported release stays installed (see import-batch): its record is kept
|
|
132
|
+
trm_commons_1.Logger.log(`Keeping the TRM data of the imported ${context.rawInput.packageData.name}`, true);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
116
135
|
if (!context.runtime.update) {
|
|
117
136
|
if (context.revert.metadataPackageRow) {
|
|
118
137
|
yield systemConnector_1.SystemConnector.restoreInstallMetadata({
|
|
@@ -510,11 +510,8 @@ class RESTClient {
|
|
|
510
510
|
}
|
|
511
511
|
importTransport(trkorr, system, test) {
|
|
512
512
|
return __awaiter(this, void 0, void 0, function* () {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
trkorr: trkorr.trim().toUpperCase(),
|
|
516
|
-
test: test ? 'X' : ' '
|
|
517
|
-
})).data;
|
|
513
|
+
// as RFC: TEST is only sent for a test import
|
|
514
|
+
const result = (yield this._axiosInstance.post('/import_tr', Object.assign({ system: system.trim().toUpperCase(), trkorr: trkorr.trim().toUpperCase() }, (test ? { test: 'X' } : {})))).data;
|
|
518
515
|
if (result && result.testResult) {
|
|
519
516
|
return result.testResult;
|
|
520
517
|
}
|
package/dist/client/RFCClient.js
CHANGED
|
@@ -631,11 +631,9 @@ class RFCClient {
|
|
|
631
631
|
}
|
|
632
632
|
importTransport(trkorr, system, test) {
|
|
633
633
|
return __awaiter(this, void 0, void 0, function* () {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
test: test ? 'X' : ' '
|
|
638
|
-
});
|
|
634
|
+
// TEST is only sent for a test import: releases before trm-server 7 have no such parameter, and
|
|
635
|
+
// their RFC metadata stays cached in this process even after a newer release is imported
|
|
636
|
+
const result = yield this._call("/ATRM/IMPORT_TR", Object.assign({ system: system.trim().toUpperCase(), trkorr: trkorr.trim().toUpperCase() }, (test ? { test: 'X' } : {})));
|
|
639
637
|
if (result && result.testResult) {
|
|
640
638
|
return this.parseImportTransportResult(result['testResult'], '/ATRM/IMPORT_TR');
|
|
641
639
|
}
|
|
@@ -430,14 +430,36 @@ class SystemConnectorBase {
|
|
|
430
430
|
}
|
|
431
431
|
getExistingObjects(objects) {
|
|
432
432
|
return __awaiter(this, void 0, void 0, function* () {
|
|
433
|
-
|
|
433
|
+
// TADIR is read in batches of objects of the same type: one read per object is slow on large packages
|
|
434
|
+
const batchSize = 25;
|
|
435
|
+
const key = (pgmid, object, objName) => `${pgmid.trim().toUpperCase()} ${object.trim().toUpperCase()} ${objName.trim().toUpperCase()}`;
|
|
436
|
+
const found = new Map();
|
|
437
|
+
const singles = [];
|
|
438
|
+
const byType = new Map();
|
|
434
439
|
for (const object of objects) {
|
|
440
|
+
// an option line holds 72 characters: "OR ( OBJ_NAME EQ '...' )"
|
|
441
|
+
if (object.objName.trim().replace(/'/g, "''").length > 50 || /\s(AND|OR)\s/i.test(object.objName)) {
|
|
442
|
+
singles.push(object);
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
const type = `${object.pgmid.trim().toUpperCase()} ${object.object.trim().toUpperCase()}`;
|
|
446
|
+
byType.set(type, [...(byType.get(type) || []), object]);
|
|
447
|
+
}
|
|
448
|
+
for (const [type, typeObjects] of byType) {
|
|
449
|
+
const [pgmid, object] = type.split(' ');
|
|
450
|
+
for (let i = 0; i < typeObjects.length; i += batchSize) {
|
|
451
|
+
const names = typeObjects.slice(i, i + batchSize).map(o => o.objName.trim().toUpperCase().replace(/'/g, "''"));
|
|
452
|
+
const tadir = yield this.readTable('TADIR', [{ fieldName: 'PGMID' }, { fieldName: 'OBJECT' }, { fieldName: 'OBJ_NAME' }, { fieldName: 'DEVCLASS' }, { fieldName: 'SRCSYSTEM' }, { fieldName: 'AUTHOR' }], `PGMID EQ '${pgmid}' AND OBJECT EQ '${object}' AND ( ${names.map(name => `OBJ_NAME EQ '${name}'`).join(' OR ')} )`);
|
|
453
|
+
tadir.forEach(o => found.set(key(o.pgmid, o.object, o.objName), o));
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
for (const object of singles) {
|
|
435
457
|
const oTadir = yield this.getObject(object.pgmid, object.object, object.objName);
|
|
436
458
|
if (oTadir) {
|
|
437
|
-
|
|
459
|
+
found.set(key(object.pgmid, object.object, object.objName), oTadir);
|
|
438
460
|
}
|
|
439
461
|
}
|
|
440
|
-
return
|
|
462
|
+
return objects.map(o => found.get(key(o.pgmid, o.object, o.objName))).filter(Boolean);
|
|
441
463
|
});
|
|
442
464
|
}
|
|
443
465
|
getNamespace(namespace) {
|