diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 62c84843f..c92b821ed 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -5693,7 +5693,8 @@ DevOps helper class
* [DevOps](#DevOps)
* [.getDeltaList(properties, [range], [saveToDeployDir], [filterPaths])](#DevOps.getDeltaList) ⇒ Promise.<Array.<TYPE.DeltaPkgItem>>
* [~delta](#DevOps.getDeltaList..delta) : Array.<TYPE.DeltaPkgItem>
- * [~copied](#DevOps.getDeltaList..copied) : TYPE.DeltaPkgItem
+ * [~buObjects](#DevOps.getDeltaList..buObjects) : Object.<string, TYPE.BuObject>
+ * [~copied](#DevOps.getDeltaList..copied) : Array.<TYPE.DeltaPkgItem>
* [.buildDeltaDefinitions(properties, range, [diffArr])](#DevOps.buildDeltaDefinitions) ⇒ Promise.<Array.<TYPE.DeltaPkgItem>>
* [~deltaDeployAll](#DevOps.buildDeltaDefinitions..deltaDeployAll) : Array.<TYPE.DeltaPkgItem>
* [.document(directory, jsonReport)](#DevOps.document) ⇒ void
@@ -5718,15 +5719,20 @@ Interactive commit selection if no commits are passed.
* [.getDeltaList(properties, [range], [saveToDeployDir], [filterPaths])](#DevOps.getDeltaList) ⇒ Promise.<Array.<TYPE.DeltaPkgItem>>
* [~delta](#DevOps.getDeltaList..delta) : Array.<TYPE.DeltaPkgItem>
- * [~copied](#DevOps.getDeltaList..copied) : TYPE.DeltaPkgItem
+ * [~buObjects](#DevOps.getDeltaList..buObjects) : Object.<string, TYPE.BuObject>
+ * [~copied](#DevOps.getDeltaList..copied) : Array.<TYPE.DeltaPkgItem>
#### getDeltaList~delta : Array.<TYPE.DeltaPkgItem>
**Kind**: inner constant of [getDeltaList
](#DevOps.getDeltaList)
+
+
+#### getDeltaList~buObjects : Object.<string, TYPE.BuObject>
+**Kind**: inner constant of [getDeltaList
](#DevOps.getDeltaList)
-#### getDeltaList~copied : TYPE.DeltaPkgItem
+#### getDeltaList~copied : Array.<TYPE.DeltaPkgItem>
**Kind**: inner constant of [getDeltaList
](#DevOps.getDeltaList)
diff --git a/lib/util/devops.js b/lib/util/devops.js
index 788a3a7f0..429ace721 100644
--- a/lib/util/devops.js
+++ b/lib/util/devops.js
@@ -3,6 +3,7 @@ const File = require('./file');
const path = require('node:path');
const inquirer = require('inquirer');
const Util = require('./util');
+const Cli = require('./cli');
const git = require('simple-git')();
const Builder = require('../Builder');
const MetadataType = require('../MetadataTypeInfo');
@@ -104,7 +105,7 @@ const DevOps = {
}
// get metadata type from file name
- file.type = path.basename(file.file).split('.')[1].split('-').shift();
+ file.type = file.file.split('/')[3];
return file;
})
@@ -130,7 +131,14 @@ const DevOps = {
file.externalKey = null;
file.name = path.basename(file.file).split('.').shift();
} else {
- file.externalKey = path.basename(file.file).split('.').shift();
+ // find the key in paths like:
+ // - retrieve/cred/bu/asset/block/016aecc7-7063-4b78-93f4-aa119ea933c7.asset-block-meta.html
+ // - retrieve/cred/bu/asset/message/003c1ef5-f538-473a-91da-26942024a64a/blocks/views.html.slots.[bottom-8frq7iw2k99].asset-message-meta.html
+ // - retrieve/cred/bu/query/03efd5f1-ba1f-487a-9c9a-36aeb2ae5192.query-meta.sql
+ file.externalKey =
+ file.type === 'asset'
+ ? file.file.split('/')[5].split('.')[0] // assets have an additional folder level for their subtype
+ : file.file.split('/')[4].split('.')[0];
file.name = null;
}
@@ -207,8 +215,83 @@ const DevOps = {
Util.logger.info(`Saved report in ${path.join(directoryDeltaPkg, 'delta_package.md')}`);
// Copy filtered list of files into deploy directory
+ // only do that if we do not use templating
if (saveToDeployDir) {
- /** @type {TYPE.DeltaPkgItem} */
+ // if templating is not used, we need to add related files to the delta package
+ const typeKeysMap = {};
+ /** @type {Object.} */
+ const buObjects = {};
+ for (const file of delta) {
+ if (file.gitAction === 'delete' || file.type === 'folder') {
+ continue;
+ }
+ if (typeKeysMap[file.type]) {
+ typeKeysMap[file.type].push(file.externalKey);
+ } else {
+ typeKeysMap[file.type] = [file.externalKey];
+ }
+ if (!buObjects[`${file._credential}/${file._businessUnit}`]) {
+ buObjects[`${file._credential}/${file._businessUnit}`] =
+ await Cli.getCredentialObject(
+ properties,
+ `${file._credential}/${file._businessUnit}`
+ );
+ }
+ }
+ // a bit crude but works for now
+ for (const buObject of Object.values(buObjects)) {
+ for (const type in typeKeysMap) {
+ MetadataType[type].buObject = buObject;
+ MetadataType[type].properties = properties;
+ const additionalFiles = await MetadataType[type].getFilesToCommit(
+ typeKeysMap[type]
+ );
+ if (additionalFiles?.length) {
+ delta.push(
+ ...additionalFiles
+ .map((filePath) => ({
+ file: path.normalize(filePath).split('\\').join('/'),
+ type,
+ gitAction: 'add/update',
+ }))
+ .filter(
+ // avoid adding files that we already have in the list
+ (addFile) =>
+ !delta.find((existFile) => existFile.file === addFile.file)
+ )
+ );
+ }
+ }
+ }
+
+ let responses;
+ if (!Util.skipInteraction) {
+ // deploy folder is in targets for definition creation
+ // recommend to purge their content first
+ responses = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'isPurgeDeployFolder',
+ message:
+ 'Do you want to empty the deploy folder (ensures no files from previous deployments remain)?',
+ default: true,
+ },
+ ]);
+ }
+ if (Util.skipInteraction || responses.isPurgeDeployFolder) {
+ // Clear output folder structure for selected sub-type
+ for (const buObject of Object.values(buObjects)) {
+ await File.remove(
+ File.normalizePath([
+ properties.directories.deploy,
+ buObject.credential,
+ buObject.businessUnit,
+ ])
+ );
+ }
+ }
+
+ /** @type {TYPE.DeltaPkgItem[]} */
const copied = delta.map((file) =>
File.copyFile(
file.file,
@@ -395,7 +478,7 @@ const DevOps = {
},
]);
}
- if (skipInteraction || responses.isPurgeDeployFolders) {
+ if (skipInteraction || responses.isPurgeDeployFolder) {
// Clear output folder structure for selected sub-type
await File.remove(File.normalizePath([properties.directories.deploy]));
}