Repository: Accenture/sfmc-devtools
Pull request #488 (2022-10-29 22:14:03)

release 4.1.1


Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index e0b925af..8426b970 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -39,6 +39,7 @@ body:
           label: Version
           description: What version of our software are you running? (mcdev --version)
           options:
+              - 4.1.1
               - 4.1.0
               - 4.0.2
               - 4.0.1
diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml
index 20fd491b..d19b38e8 100644
--- a/.github/workflows/npm-publish.yml
+++ b/.github/workflows/npm-publish.yml
@@ -4,30 +4,30 @@
 name: Publish NPM on Release
 
 on:
-  release:
-    types: [created]
+    release:
+        types: [published]
 
 jobs:
-  build:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 14
-      - run: npm ci
-      - run: npm test
+    build:
+        runs-on: ubuntu-latest
+        steps:
+            - uses: actions/checkout@v2
+            - uses: actions/setup-node@v1
+              with:
+                  node-version: 16
+            - run: npm ci
+            - run: npm test
 
-  publish-npm:
-    needs: build
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 14
-          registry-url: https://registry.npmjs.org/
-      - run: npm ci
-      - run: npm publish
-        env:
-          NODE_AUTH_TOKEN: ${{secrets.npm_token}}
+    publish-npm:
+        needs: build
+        runs-on: ubuntu-latest
+        steps:
+            - uses: actions/checkout@v2
+            - uses: actions/setup-node@v1
+              with:
+                  node-version: 16
+                  registry-url: https://registry.npmjs.org/
+            - run: npm ci
+            - run: npm publish
+              env:
+                  NODE_AUTH_TOKEN: ${{secrets.npm_token}}
diff --git a/README.md b/README.md
index 8862bad1..04ff4b54 100644
--- a/README.md
+++ b/README.md
@@ -123,7 +123,7 @@ If you experience issues installing Accenture SFMC DevTools, please check out th
 1. Install Accenture SFMC DevTools by running `npm install -g mcdev` (prefix with `sudo` on MacOS)
    - If you get an error, please see the below troubleshooting section.
 
-When completed run `mcdev --version` and it will show you which version you installed (e.g. `4.1.0`).
+When completed run `mcdev --version` and it will show you which version you installed (e.g. `4.1.1`).
 
 > **_Side note for proud nerds_:**
 >
@@ -277,10 +277,10 @@ _Note: Regardless of which tag or branch you install_
 **Install specific version (using a version tag on npm):**
 
 ```bash
-npm install -g mcdev@4.1.0
+npm install -g mcdev@4.1.1
 ```
 
-**Warning**: When you used the above method to install Accenture SFMC DevTools for a specific version or tag, trying to [update Accenture SFMC DevTools](#updating-mcdev) might not download the most recently published official version but instead stay on the version or branch you previously selected (in the above examples: develop, 4.1.0)!
+**Warning**: When you used the above method to install Accenture SFMC DevTools for a specific version or tag, trying to [update Accenture SFMC DevTools](#updating-mcdev) might not download the most recently published official version but instead stay on the version or branch you previously selected (in the above examples: develop, 4.1.1)!
 
 > **Note**: The version is currently _not_ updated on the developer branch until a new release is published. Hence, you will not see a change if you run `mcdev --version`.
 
@@ -1494,7 +1494,7 @@ Assuming you cloned Accenture SFMC DevTools into `C:\repos\sfmc-devtools\` (or `
 
 This should tell npm to create a symlink to your cloned local directoty, allowing you to see updates you make in your mcdev repo instantly.
 
-To test your new **global** developer setup, run `mcdev --version` in CLI which should return the current version (e.g. `4.1.0`). Then, go into your mcdev repo and update the version with the suffix `-dev`, e.g. to `4.1.0-dev` and then run `mcdev --version` again to verify that your change propagates instantly.
+To test your new **global** developer setup, run `mcdev --version` in CLI which should return the current version (e.g. `4.1.1`). Then, go into your mcdev repo and update the version with the suffix `-dev`, e.g. to `4.1.1-dev` and then run `mcdev --version` again to verify that your change propagates instantly.
 
 > **Not recommended:** Alternatively, you can install it locally only by opening a terminal in your project directory and executing `npm install --save-dev "C:\repos\sfmc-devtools"`
 > To run the local version you need to prepend "npx" before your commands, e.g. `npx mcdev --version`
@@ -1532,7 +1532,7 @@ The following explains how you _could_ install it locally for certain edge cases
 4. Afterwards, install Accenture SFMC DevTools by running `npm install --save-dev mcdev`
    - If you get an error, please see the below troubleshooting section.
 
-When completed run `mcdev --version` and it will show you which version you installed (e.g. `4.1.0`).
+When completed run `mcdev --version` and it will show you which version you installed (e.g. `4.1.1`).
 
 ### 9.3. NPM Scripts
 
diff --git a/boilerplate/files/.vscode/settings.json b/boilerplate/files/.vscode/settings.json
index b5ec813a..3677550e 100644
--- a/boilerplate/files/.vscode/settings.json
+++ b/boilerplate/files/.vscode/settings.json
@@ -1,4 +1,7 @@
 {
+    "workbench.editorAssociations": {
+        "*.md": "vscode.markdown.preview.editor"
+    },
     "explorer.fileNesting.enabled": true,
     "explorer.fileNesting.expand": false,
     "explorer.fileNesting.patterns": {
diff --git a/boilerplate/forcedUpdates.json b/boilerplate/forcedUpdates.json
index 024daa89..0cd0ed8b 100644
--- a/boilerplate/forcedUpdates.json
+++ b/boilerplate/forcedUpdates.json
@@ -1,4 +1,8 @@
 [
+    {
+        "version": "4.1.1",
+        "files": [".vscode/settings.json"]
+    },
     {
         "version": "4.0.0",
         "files": [".vscode/settings.json", ".vscode/extensions.json", ".prettierrc"]
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index a8aa7bb7..b59c07d2 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -346,10 +346,10 @@ Source and target business units are also compared before the deployment to appl
     * [new Deployer(properties, buObject)](#new_Deployer_new)
     * _instance_
         * [.metadata](#Deployer+metadata) : <code>TYPE.MultiMetadataTypeMap</code>
-        * [._deploy([typeArr], [keyArr], [fromRetrieve])](#Deployer+_deploy) ⇒ <code>Promise</code>
+        * [._deploy([typeArr], [keyArr], [fromRetrieve])](#Deployer+_deploy) ⇒ <code>Promise.&lt;TYPE.MultiMetadataTypeMap&gt;</code>
     * _static_
-        * [.deploy(businessUnit, [selectedTypesArr], [keyArr], [fromRetrieve])](#Deployer.deploy) ⇒ <code>Promise.&lt;void&gt;</code>
-        * [._deployBU(cred, bu, properties, [typeArr], [keyArr], [fromRetrieve])](#Deployer._deployBU) ⇒ <code>Promise</code>
+        * [.deploy(businessUnit, [selectedTypesArr], [keyArr], [fromRetrieve])](#Deployer.deploy) ⇒ <code>Promise.&lt;Object.&lt;string, TYPE.MultiMetadataTypeMap&gt;&gt;</code>
+        * [._deployBU(cred, bu, properties, [typeArr], [keyArr], [fromRetrieve])](#Deployer._deployBU) ⇒ <code>Promise.&lt;TYPE.MultiMetadataTypeMap&gt;</code>
         * [.readBUMetadata(deployDir, [typeArr], [listBadKeys])](#Deployer.readBUMetadata) ⇒ <code>TYPE.MultiMetadataTypeMap</code>
         * [.createFolderDefinitions(deployDir, metadata, metadataTypeArr)](#Deployer.createFolderDefinitions) ⇒ <code>void</code>
 
@@ -370,11 +370,11 @@ Creates a Deployer, uses v2 auth if v2AuthOptions are passed.
 **Kind**: instance property of [<code>Deployer</code>](#Deployer)  
 <a name="Deployer+_deploy"></a>
 
-### deployer.\_deploy([typeArr], [keyArr], [fromRetrieve]) ⇒ <code>Promise</code>
+### deployer.\_deploy([typeArr], [keyArr], [fromRetrieve]) ⇒ <code>Promise.&lt;TYPE.MultiMetadataTypeMap&gt;</code>
 Deploy all metadata that is located in the deployDir
 
 **Kind**: instance method of [<code>Deployer</code>](#Deployer)  
-**Returns**: <code>Promise</code> - Promise  
+**Returns**: <code>Promise.&lt;TYPE.MultiMetadataTypeMap&gt;</code> - Promise of all deployed metadata  
 
 | Param | Type | Description |
 | --- | --- | --- |
@@ -384,11 +384,11 @@ Deploy all metadata that is located in the deployDir
 
 <a name="Deployer.deploy"></a>
 
-### Deployer.deploy(businessUnit, [selectedTypesArr], [keyArr], [fromRetrieve]) ⇒ <code>Promise.&lt;void&gt;</code>
+### Deployer.deploy(businessUnit, [selectedTypesArr], [keyArr], [fromRetrieve]) ⇒ <code>Promise.&lt;Object.&lt;string, TYPE.MultiMetadataTypeMap&gt;&gt;</code>
 Deploys all metadata located in the 'deploy' directory to the specified business unit
 
 **Kind**: static method of [<code>Deployer</code>](#Deployer)  
-**Returns**: <code>Promise.&lt;void&gt;</code> - -  
+**Returns**: <code>Promise.&lt;Object.&lt;string, TYPE.MultiMetadataTypeMap&gt;&gt;</code> - deployed metadata per BU (first key: bu name, second key: metadata type)  
 
 | Param | Type | Description |
 | --- | --- | --- |
@@ -399,11 +399,11 @@ Deploys all metadata located in the 'deploy' directory to the specified business
 
 <a name="Deployer._deployBU"></a>
 
-### Deployer.\_deployBU(cred, bu, properties, [typeArr], [keyArr], [fromRetrieve]) ⇒ <code>Promise</code>
+### Deployer.\_deployBU(cred, bu, properties, [typeArr], [keyArr], [fromRetrieve]) ⇒ <code>Promise.&lt;TYPE.MultiMetadataTypeMap&gt;</code>
 helper for deploy()
 
 **Kind**: static method of [<code>Deployer</code>](#Deployer)  
-**Returns**: <code>Promise</code> - ensure that BUs are worked on sequentially  
+**Returns**: <code>Promise.&lt;TYPE.MultiMetadataTypeMap&gt;</code> - ensure that BUs are worked on sequentially  
 
 | Param | Type | Description |
 | --- | --- | --- |
@@ -456,7 +456,7 @@ main class
     * [.explainTypes()](#Mcdev.explainTypes) ⇒ <code>void</code>
     * [.upgrade([skipInteraction])](#Mcdev.upgrade) ⇒ <code>Promise.&lt;boolean&gt;</code>
     * [.retrieve(businessUnit, [selectedTypesArr], [keys], [changelogOnly])](#Mcdev.retrieve) ⇒ <code>Promise.&lt;object&gt;</code>
-    * [.deploy(businessUnit, [selectedTypesArr], [keyArr], [fromRetrieve])](#Mcdev.deploy) ⇒ <code>Promise.&lt;void&gt;</code>
+    * [.deploy(businessUnit, [selectedTypesArr], [keyArr], [fromRetrieve])](#Mcdev.deploy) ⇒ <code>Promise.&lt;Object.&lt;string, TYPE.MultiMetadataTypeMap&gt;&gt;</code>
     * [.initProject([credentialsName], [skipInteraction])](#Mcdev.initProject) ⇒ <code>Promise.&lt;void&gt;</code>
     * [.findBUs(credentialsName)](#Mcdev.findBUs) ⇒ <code>Promise.&lt;void&gt;</code>
     * [.document(businessUnit, type)](#Mcdev.document) ⇒ <code>Promise.&lt;void&gt;</code>
@@ -545,11 +545,11 @@ Retrieve all metadata from the specified business unit into the local file syste
 
 <a name="Mcdev.deploy"></a>
 
-### Mcdev.deploy(businessUnit, [selectedTypesArr], [keyArr], [fromRetrieve]) ⇒ <code>Promise.&lt;void&gt;</code>
+### Mcdev.deploy(businessUnit, [selectedTypesArr], [keyArr], [fromRetrieve]) ⇒ <code>Promise.&lt;Object.&lt;string, TYPE.MultiMetadataTypeMap&gt;&gt;</code>
 Deploys all metadata located in the 'deploy' directory to the specified business unit
 
 **Kind**: static method of [<code>Mcdev</code>](#Mcdev)  
-**Returns**: <code>Promise.&lt;void&gt;</code> - -  
+**Returns**: <code>Promise.&lt;Object.&lt;string, TYPE.MultiMetadataTypeMap&gt;&gt;</code> - deployed metadata per BU (first key: bu name, second key: metadata type)  
 
 | Param | Type | Default | Description |
 | --- | --- | --- | --- |
@@ -2943,7 +2943,7 @@ Provides default functionality that can be overwritten by child metadata type cl
     * [.buObject](#MetadataType.buObject) : <code>TYPE.BuObject</code>
     * [.getJsonFromFS(dir, [listBadKeys])](#MetadataType.getJsonFromFS) ⇒ <code>TYPE.MetadataTypeMap</code>
     * [.getFieldNamesToRetrieve([additionalFields])](#MetadataType.getFieldNamesToRetrieve) ⇒ <code>Array.&lt;string&gt;</code>
-    * [.deploy(metadata, deployDir, retrieveDir, buObject)](#MetadataType.deploy) ⇒ <code>Promise.&lt;object&gt;</code>
+    * [.deploy(metadata, deployDir, retrieveDir, buObject)](#MetadataType.deploy) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMap&gt;</code>
     * [.postDeployTasks(metadata, originalMetadata)](#MetadataType.postDeployTasks) ⇒ <code>void</code>
     * [.postRetrieveTasks(metadata, targetDir, [isTemplating])](#MetadataType.postRetrieveTasks) ⇒ <code>TYPE.MetadataTypeItem</code>
     * [.retrieve(retrieveDir, [additionalFields], buObject, [subType], [key])](#MetadataType.retrieve) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
@@ -3030,11 +3030,11 @@ Returns fieldnames of Metadata Type. 'this.definition.fields' variable only set
 
 <a name="MetadataType.deploy"></a>
 
-### MetadataType.deploy(metadata, deployDir, retrieveDir, buObject) ⇒ <code>Promise.&lt;object&gt;</code>
+### MetadataType.deploy(metadata, deployDir, retrieveDir, buObject) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMap&gt;</code>
 Deploys metadata
 
 **Kind**: static method of [<code>MetadataType</code>](#MetadataType)  
-**Returns**: <code>Promise.&lt;object&gt;</code> - Promise of keyField => metadata map  
+**Returns**: <code>Promise.&lt;TYPE.MetadataTypeMap&gt;</code> - Promise of keyField => metadata map  
 
 | Param | Type | Description |
 | --- | --- | --- |
diff --git a/lib/Deployer.js b/lib/Deployer.js
index 8ea575d2..d2a42b08 100644
--- a/lib/Deployer.js
+++ b/lib/Deployer.js
@@ -48,10 +48,11 @@ class Deployer {
      * @param {TYPE.SupportedMetadataTypes[]} [selectedTypesArr] limit deployment to given metadata type
      * @param {string[]} [keyArr] limit deployment to given metadata keys
      * @param {boolean} [fromRetrieve] optionally deploy whats defined via selectedTypesArr + keyArr directly from retrieve folder instead of from deploy folder
-     * @returns {Promise.<void>} -
+     * @returns {Promise.<Object.<string,TYPE.MultiMetadataTypeMap>>} deployed metadata per BU (first key: bu name, second key: metadata type)
      */
     static async deploy(businessUnit, selectedTypesArr, keyArr, fromRetrieve) {
         Util.logger.info('mcdev:: Deploy');
+        const buMultiMetadataTypeMap = {};
         const properties = await config.getProperties();
         if (!(await config.checkProperties(properties))) {
             return null;
@@ -87,9 +88,18 @@ class Deployer {
                 2,
                 false
             );
+
             for (const buPath of deployFolders.filter((r) => r.includes(path.sep))) {
                 const [cred, bu] = buPath.split(path.sep);
-                await this._deployBU(cred, bu, properties, selectedTypesArr, keyArr, fromRetrieve);
+                const multiMetadataTypeMap = await this._deployBU(
+                    cred,
+                    bu,
+                    properties,
+                    selectedTypesArr,
+                    keyArr,
+                    fromRetrieve
+                );
+                buMultiMetadataTypeMap[cred + '/' + bu] = multiMetadataTypeMap;
                 counter_credBu++;
                 Util.logger.info('');
                 Util.restartLogger();
@@ -129,7 +139,7 @@ class Deployer {
                     false
                 );
                 for (const buPath of deployFolders) {
-                    await this._deployBU(
+                    const multiMetadataTypeMap = await this._deployBU(
                         cred,
                         buPath,
                         properties,
@@ -137,6 +147,7 @@ class Deployer {
                         keyArr,
                         fromRetrieve
                     );
+                    buMultiMetadataTypeMap[cred + '/' + buPath] = multiMetadataTypeMap;
                     counter_credBu++;
                     Util.logger.info('');
                     Util.restartLogger();
@@ -144,13 +155,22 @@ class Deployer {
                 Util.logger.info(`\n               :: ${counter_credBu} BUs for ${cred}\n`);
             } else {
                 // either bad credential or specific BU or no BU given
-                await this._deployBU(cred, bu, properties, selectedTypesArr, keyArr, fromRetrieve);
+                const multiMetadataTypeMap = await this._deployBU(
+                    cred,
+                    bu,
+                    properties,
+                    selectedTypesArr,
+                    keyArr,
+                    fromRetrieve
+                );
                 counter_credBu++;
+                buMultiMetadataTypeMap[cred + '/' + bu] = multiMetadataTypeMap;
             }
         }
         if (counter_credBu !== 0) {
             Util.logger.info(`\n               :: Deployed ${counter_credBu} BUs\n`);
         }
+        return buMultiMetadataTypeMap;
     }
     /**
      * helper for deploy()
@@ -161,22 +181,25 @@ class Deployer {
      * @param {TYPE.SupportedMetadataTypes[]} [typeArr] limit deployment to given metadata type
      * @param {string[]} [keyArr] limit deployment to given metadata keys
      * @param {boolean} [fromRetrieve] optionally deploy whats defined via selectedTypesArr + keyArr directly from retrieve folder instead of from deploy folder
-     * @returns {Promise} ensure that BUs are worked on sequentially
+     * @returns {Promise.<TYPE.MultiMetadataTypeMap>} ensure that BUs are worked on sequentially
      */
     static async _deployBU(cred, bu, properties, typeArr, keyArr, fromRetrieve) {
         const buPath = `${cred}/${bu}`;
         Util.logger.info(`::Deploying ${buPath}`);
         const buObject = await Cli.getCredentialObject(properties, buPath, null, true);
+        let multiMetadataTypeMap;
+
         if (buObject !== null) {
             cache.initCache(buObject);
             const deployer = new Deployer(properties, buObject);
             try {
                 // await is required or the calls end up conflicting
-                await deployer._deploy(typeArr, keyArr, fromRetrieve);
+                multiMetadataTypeMap = await deployer._deploy(typeArr, keyArr, fromRetrieve);
             } catch (ex) {
                 Util.logger.errorStack(ex, 'mcdev.deploy failed');
             }
         }
+        return multiMetadataTypeMap;
     }
 
     /**
@@ -185,7 +208,7 @@ class Deployer {
      * @param {TYPE.SupportedMetadataTypes[]} [typeArr] limit deployment to given metadata type (can include subtype)
      * @param {string[]} [keyArr] limit deployment to given metadata keys
      * @param {boolean} [fromRetrieve] if true, no folders will be updated/created
-     * @returns {Promise} Promise
+     * @returns {Promise.<TYPE.MultiMetadataTypeMap>} Promise of all deployed metadata
      */
     async _deploy(typeArr, keyArr, fromRetrieve) {
         if (await File.pathExists(this.deployDir)) {
@@ -232,6 +255,8 @@ class Deployer {
             const result = await MetadataTypeInfo[type].retrieveForCache(this.buObject, subType);
             cache.setMetadata(type, result.metadata);
         }
+        /** @type {TYPE.MultiMetadataTypeMap} */
+        const multiMetadataTypeMap = {};
         // deploy metadata files, extending cache once deploys
         for (const metadataType of deployOrder) {
             // TODO rewrite to allow deploying only a specific sub-type
@@ -246,9 +271,11 @@ class Deployer {
                     this.retrieveDir,
                     this.buObject
                 );
+                multiMetadataTypeMap[type] = result;
                 cache.mergeMetadata(type, result);
             }
         }
+        return multiMetadataTypeMap;
     }
 
     /**
diff --git a/lib/index.js b/lib/index.js
index e0f3f897..9db0978c 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -285,7 +285,7 @@ class Mcdev {
      * @param {TYPE.SupportedMetadataTypes[]} [selectedTypesArr] limit deployment to given metadata type
      * @param {string[]} [keyArr] limit deployment to given metadata keys
      * @param {boolean} [fromRetrieve] optionally deploy whats defined via selectedTypesArr + keyArr directly from retrieve folder instead of from deploy folder
-     * @returns {Promise.<void>} -
+     * @returns {Promise.<Object.<string,TYPE.MultiMetadataTypeMap>>} deployed metadata per BU (first key: bu name, second key: metadata type)
      */
     static async deploy(businessUnit, selectedTypesArr, keyArr, fromRetrieve = false) {
         return Deployer.deploy(businessUnit, selectedTypesArr, keyArr, fromRetrieve);
diff --git a/lib/metadataTypes/Asset.js b/lib/metadataTypes/Asset.js
index b46f61a7..e231ef2f 100644
--- a/lib/metadataTypes/Asset.js
+++ b/lib/metadataTypes/Asset.js
@@ -527,7 +527,7 @@ class Asset extends MetadataType {
         if (
             buObject.mid &&
             metadata.memberId !== buObject.mid &&
-            !metadata[this.definition.keyField].startsWith(buObject.mid)
+            !metadata[this.definition.keyField].endsWith(buObject.mid)
         ) {
             // #3 make sure customer key is unique by suffixing it with target MID (unless we are deploying to the same MID)
             // check if this suffixed with the source MID
diff --git a/lib/metadataTypes/ImportFile.js b/lib/metadataTypes/ImportFile.js
index dacc4a37..b9c5b001 100644
--- a/lib/metadataTypes/ImportFile.js
+++ b/lib/metadataTypes/ImportFile.js
@@ -134,23 +134,37 @@ class ImportFile extends MetadataType {
         delete metadata.r__ftpLocation_name;
 
         if (metadata.c__destinationType === 'DataExtension') {
-            metadata.destinationObjectId = cache.searchForField(
-                'dataExtension',
-                metadata.r__dataExtension_CustomerKey,
-                'CustomerKey',
-                'ObjectID'
-            );
-            delete metadata.r__dataExtension_CustomerKey;
+            if (metadata.r__dataExtension_CustomerKey) {
+                metadata.destinationObjectId = cache.searchForField(
+                    'dataExtension',
+                    metadata.r__dataExtension_CustomerKey,
+                    'CustomerKey',
+                    'ObjectID'
+                );
+                delete metadata.r__dataExtension_CustomerKey;
+            } else {
+                throw new Error('Import Destination DataExtension not defined');
+            }
         } else if (metadata.c__destinationType === 'List') {
-            metadata.destinationObjectId = cache.getListObjectId(
-                metadata.r__list_PathName,
-                'ObjectID'
+            if (metadata.r__list_PathName) {
+                metadata.destinationObjectId = cache.getListObjectId(
+                    metadata.r__list_PathName,
+                    'ObjectID'
+                );
+                // destinationId is also needed for List types
+                metadata.destinationId = cache.getListObjectId(metadata.r__list_PathName, 'ID');
+                delete metadata.r__list_PathName;
+            } else {
+                throw new Error('Import Destination List not defined');
+            }
+        } else {
+            Util.logger.debug(
+                ` - importFile ${metadata[this.definition.keyField]}: Import Destination Type ${
+                    metadata.c__destinationType
+                } not fully supported. Deploy might fail.`
             );
-            // destinationId is also needed for List types
-            metadata.destinationId = cache.getListObjectId(metadata.r__list_PathName, 'ID');
-            delete metadata.r__list_PathName;
         }
-        // When the destinationObjectTypeId is 584 is refers to Mobile Connect which is not supported as an Import Type
+        // When the destinationObjectTypeId is 584 it refers to Mobile Connect which is not supported as an Import Type
         metadata.destinationObjectTypeId =
             this.definition.destinationObjectTypeMapping[metadata.c__destinationType];
         metadata.subscriberImportTypeId =
diff --git a/lib/metadataTypes/MetadataType.js b/lib/metadataTypes/MetadataType.js
index 76badf7f..9abe6aa7 100644
--- a/lib/metadataTypes/MetadataType.js
+++ b/lib/metadataTypes/MetadataType.js
@@ -104,7 +104,7 @@ class MetadataType {
      * @param {string} deployDir directory where deploy metadata are saved
      * @param {string} retrieveDir directory where metadata after deploy should be saved
      * @param {TYPE.BuObject} buObject properties for auth
-     * @returns {Promise.<object>} Promise of keyField => metadata map
+     * @returns {Promise.<TYPE.MetadataTypeMap>} Promise of keyField => metadata map
      */
     static async deploy(metadata, deployDir, retrieveDir, buObject) {
         const upsertResults = await this.upsert(metadata, deployDir, buObject);
diff --git a/lib/util/devops.js b/lib/util/devops.js
index 30c55c5a..90af575f 100644
--- a/lib/util/devops.js
+++ b/lib/util/devops.js
@@ -407,7 +407,7 @@ const DevOps = {
                 );
             }
             await Promise.all(bdPromises);
-            Util.logger.info(`- ✔️  Deploy defintions created`);
+            Util.logger.info(`- ✔️  Deploy definitions created`);
             if (
                 properties.directories.templateBuilds == properties.directories.deploy ||
                 (Array.isArray(properties.directories.templateBuilds) &&
diff --git a/lib/util/util.js b/lib/util/util.js
index c78378c0..99b40b24 100644
--- a/lib/util/util.js
+++ b/lib/util/util.js
@@ -428,10 +428,20 @@ const Util = {
  * @returns {object} initiated logger for console and file
  */
 function createNewLoggerTransport() {
+    // {
+    //   error: 0,
+    //   warn: 1,
+    //   info: 2,
+    //   http: 3,
+    //   verbose: 4,
+    //   debug: 5,
+    //   silly: 6
+    // }
+    const logFileName = new Date().toISOString().split(':').join('.');
     return {
         console: new winston.transports.Console({
             // Write logs to Console
-            level: 'info',
+            level: 'info', // log error, warn, info
             format: winston.format.combine(
                 winston.format.colorize(),
                 winston.format.timestamp({ format: 'HH:mm:ss' }),
@@ -441,9 +451,18 @@ function createNewLoggerTransport() {
         }),
         file: new winston.transports.File({
             // Write logs to logfile
-            filename: 'logs/' + new Date().toISOString().split(':').join('.') + '.log',
-            // filename: 'logs/' + Math.floor(Date.now() / 1000) + '.log',
-            level: 'debug',
+            filename: 'logs/' + logFileName + '.log',
+            level: 'debug', // log everything
+            format: winston.format.combine(
+                winston.format.timestamp({ format: 'HH:mm:ss.SSS' }),
+                winston.format.simple(),
+                winston.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`)
+            ),
+        }),
+        fileError: new winston.transports.File({
+            // Write logs to additional error-logfile for better visibility of errors
+            filename: 'logs/' + logFileName + '-errors.log',
+            level: 'error', // only log errors
             format: winston.format.combine(
                 winston.format.timestamp({ format: 'HH:mm:ss.SSS' }),
                 winston.format.simple(),
@@ -461,7 +480,11 @@ function startLogger() {
     Util.loggerTransports = createNewLoggerTransport();
     const myWinston = winston.createLogger({
         levels: winston.config.npm.levels,
-        transports: [Util.loggerTransports.console, Util.loggerTransports.file],
+        transports: [
+            Util.loggerTransports.console,
+            Util.loggerTransports.file,
+            Util.loggerTransports.fileError,
+        ],
     });
     const winstonError = myWinston.error;
     const winstonExtension = {
diff --git a/package-lock.json b/package-lock.json
index af611db5..dfeec645 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
     "name": "mcdev",
-    "version": "4.1.0",
+    "version": "4.1.1",
     "lockfileVersion": 2,
     "requires": true,
     "packages": {
         "": {
             "name": "mcdev",
-            "version": "4.1.0",
+            "version": "4.1.1",
             "license": "MIT",
             "dependencies": {
                 "cli-progress": "3.11.2",
@@ -36,10 +36,10 @@
                 "assert": "2.0.0",
                 "axios-mock-adapter": "1.21.2",
                 "chai": "4.3.6",
-                "eslint": "8.25.0",
+                "eslint": "8.26.0",
                 "eslint-config-prettier": "8.5.0",
                 "eslint-config-ssjs": "1.1.11",
-                "eslint-plugin-jsdoc": "39.3.13",
+                "eslint-plugin-jsdoc": "39.3.25",
                 "eslint-plugin-mocha": "10.1.0",
                 "eslint-plugin-prettier": "4.2.1",
                 "eslint-plugin-unicorn": "44.0.2",
@@ -58,6 +58,9 @@
             "funding": {
                 "type": "corporate",
                 "url": "https://github.com/Accenture/sfmc-devtools"
+            },
+            "optionalDependencies": {
+                "fsevents": "*"
             }
         },
         "node_modules/@babel/code-frame": {
@@ -323,9 +326,9 @@
             }
         },
         "node_modules/@es-joy/jsdoccomment": {
-            "version": "0.32.0",
-            "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.32.0.tgz",
-            "integrity": "sha512-sbA+4b9VZSf9DJqGrTRS6jxclyA5WpWiKXWxVqEN5HP4LOECJGfZlTS82l9w/byp4pXGPYsf5WQrW2iDG7+cKw==",
+            "version": "0.33.4",
+            "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.33.4.tgz",
+            "integrity": "sha512-02XyYuvR/Gn+3BT6idHVNQ4SSQlA1X1FeEfeKm2ypv8ANB6Lt9KRFZ2S7y5xjwR+EPQ/Rzb0XFaD+xKyqe4ALw==",
             "dev": true,
             "dependencies": {
                 "comment-parser": "1.3.1",
@@ -333,7 +336,7 @@
                 "jsdoc-type-pratt-parser": "~3.1.0"
             },
             "engines": {
-                "node": "^14 || ^16 || ^17 || ^18"
+                "node": "^14 || ^16 || ^17 || ^18 || ^19"
             }
         },
         "node_modules/@eslint/eslintrc": {
@@ -382,9 +385,9 @@
             "dev": true
         },
         "node_modules/@humanwhocodes/config-array": {
-            "version": "0.10.7",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
-            "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==",
+            "version": "0.11.6",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.6.tgz",
+            "integrity": "sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==",
             "dev": true,
             "dependencies": {
                 "@humanwhocodes/object-schema": "^1.2.1",
@@ -2639,14 +2642,15 @@
             }
         },
         "node_modules/eslint": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz",
-            "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==",
+            "version": "8.26.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",
+            "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==",
             "dev": true,
             "dependencies": {
                 "@eslint/eslintrc": "^1.3.3",
-                "@humanwhocodes/config-array": "^0.10.5",
+                "@humanwhocodes/config-array": "^0.11.6",
                 "@humanwhocodes/module-importer": "^1.0.1",
+                "@nodelib/fs.walk": "^1.2.8",
                 "ajv": "^6.10.0",
                 "chalk": "^4.0.0",
                 "cross-spawn": "^7.0.2",
@@ -2662,14 +2666,14 @@
                 "fast-deep-equal": "^3.1.3",
                 "file-entry-cache": "^6.0.1",
                 "find-up": "^5.0.0",
-                "glob-parent": "^6.0.1",
+                "glob-parent": "^6.0.2",
                 "globals": "^13.15.0",
-                "globby": "^11.1.0",
                 "grapheme-splitter": "^1.0.4",
                 "ignore": "^5.2.0",
                 "import-fresh": "^3.0.0",
                 "imurmurhash": "^0.1.4",
                 "is-glob": "^4.0.0",
+                "is-path-inside": "^3.0.3",
                 "js-sdsl": "^4.1.4",
                 "js-yaml": "^4.1.0",
                 "json-stable-stringify-without-jsonify": "^1.0.1",
@@ -2721,12 +2725,12 @@
             }
         },
         "node_modules/eslint-plugin-jsdoc": {
-            "version": "39.3.13",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.13.tgz",
-            "integrity": "sha512-yF16kYmoz8pcEZXxX2kdaBwWFvXrUpxuF+ZgG/0PKLKcT9lGKFi4Mn0Mk/KqJeMgUprFDCzNTjnzYGf8tdNrAA==",
+            "version": "39.3.25",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.25.tgz",
+            "integrity": "sha512-7JiFOOaipz7Z7lNQ9sMJ6cdvclmVUwNYtFWGS3a0k0uEFcdZPPD64WOfENuyNHpl86C0AKIEPgOpZby5kd+pew==",
             "dev": true,
             "dependencies": {
-                "@es-joy/jsdoccomment": "~0.32.0",
+                "@es-joy/jsdoccomment": "~0.33.4",
                 "comment-parser": "1.3.1",
                 "debug": "^4.3.4",
                 "escape-string-regexp": "^4.0.0",
@@ -2735,7 +2739,7 @@
                 "spdx-expression-parse": "^3.0.1"
             },
             "engines": {
-                "node": "^14 || ^16 || ^17 || ^18"
+                "node": "^14 || ^16 || ^17 || ^18 || ^19"
             },
             "peerDependencies": {
                 "eslint": "^7.0.0 || ^8.0.0"
@@ -3426,6 +3430,19 @@
             "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
             "dev": true
         },
+        "node_modules/fsevents": {
+            "version": "2.3.2",
+            "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+            "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+            "hasInstallScript": true,
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+            }
+        },
         "node_modules/function-bind": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -8921,9 +8938,9 @@
             }
         },
         "@es-joy/jsdoccomment": {
-            "version": "0.32.0",
-            "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.32.0.tgz",
-            "integrity": "sha512-sbA+4b9VZSf9DJqGrTRS6jxclyA5WpWiKXWxVqEN5HP4LOECJGfZlTS82l9w/byp4pXGPYsf5WQrW2iDG7+cKw==",
+            "version": "0.33.4",
+            "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.33.4.tgz",
+            "integrity": "sha512-02XyYuvR/Gn+3BT6idHVNQ4SSQlA1X1FeEfeKm2ypv8ANB6Lt9KRFZ2S7y5xjwR+EPQ/Rzb0XFaD+xKyqe4ALw==",
             "dev": true,
             "requires": {
                 "comment-parser": "1.3.1",
@@ -8969,9 +8986,9 @@
             }
         },
         "@humanwhocodes/config-array": {
-            "version": "0.10.7",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
-            "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==",
+            "version": "0.11.6",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.6.tgz",
+            "integrity": "sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==",
             "dev": true,
             "requires": {
                 "@humanwhocodes/object-schema": "^1.2.1",
@@ -10693,14 +10710,15 @@
             "dev": true
         },
         "eslint": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz",
-            "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==",
+            "version": "8.26.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",
+            "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==",
             "dev": true,
             "requires": {
                 "@eslint/eslintrc": "^1.3.3",
-                "@humanwhocodes/config-array": "^0.10.5",
+                "@humanwhocodes/config-array": "^0.11.6",
                 "@humanwhocodes/module-importer": "^1.0.1",
+                "@nodelib/fs.walk": "^1.2.8",
                 "ajv": "^6.10.0",
                 "chalk": "^4.0.0",
                 "cross-spawn": "^7.0.2",
@@ -10716,14 +10734,14 @@
                 "fast-deep-equal": "^3.1.3",
                 "file-entry-cache": "^6.0.1",
                 "find-up": "^5.0.0",
-                "glob-parent": "^6.0.1",
+                "glob-parent": "^6.0.2",
                 "globals": "^13.15.0",
-                "globby": "^11.1.0",
                 "grapheme-splitter": "^1.0.4",
                 "ignore": "^5.2.0",
                 "import-fresh": "^3.0.0",
                 "imurmurhash": "^0.1.4",
                 "is-glob": "^4.0.0",
+                "is-path-inside": "^3.0.3",
                 "js-sdsl": "^4.1.4",
                 "js-yaml": "^4.1.0",
                 "json-stable-stringify-without-jsonify": "^1.0.1",
@@ -10773,12 +10791,12 @@
             "requires": {}
         },
         "eslint-plugin-jsdoc": {
-            "version": "39.3.13",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.13.tgz",
-            "integrity": "sha512-yF16kYmoz8pcEZXxX2kdaBwWFvXrUpxuF+ZgG/0PKLKcT9lGKFi4Mn0Mk/KqJeMgUprFDCzNTjnzYGf8tdNrAA==",
+            "version": "39.3.25",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.25.tgz",
+            "integrity": "sha512-7JiFOOaipz7Z7lNQ9sMJ6cdvclmVUwNYtFWGS3a0k0uEFcdZPPD64WOfENuyNHpl86C0AKIEPgOpZby5kd+pew==",
             "dev": true,
             "requires": {
-                "@es-joy/jsdoccomment": "~0.32.0",
+                "@es-joy/jsdoccomment": "~0.33.4",
                 "comment-parser": "1.3.1",
                 "debug": "^4.3.4",
                 "escape-string-regexp": "^4.0.0",
@@ -11266,6 +11284,12 @@
             "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
             "dev": true
         },
+        "fsevents": {
+            "version": "2.3.2",
+            "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+            "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+            "optional": true
+        },
         "function-bind": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
diff --git a/package.json b/package.json
index 700c43fa..cc110f02 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
     "name": "mcdev",
-    "version": "4.1.0",
+    "version": "4.1.1",
     "description": "Accenture Salesforce Marketing Cloud DevTools",
     "author": "joern.berkefeld, douglas.midgley, robert.zimmermann, maciej.barnas",
     "license": "MIT",
@@ -64,10 +64,10 @@
         "assert": "2.0.0",
         "axios-mock-adapter": "1.21.2",
         "chai": "4.3.6",
-        "eslint": "8.25.0",
+        "eslint": "8.26.0",
         "eslint-config-prettier": "8.5.0",
         "eslint-config-ssjs": "1.1.11",
-        "eslint-plugin-jsdoc": "39.3.13",
+        "eslint-plugin-jsdoc": "39.3.25",
         "eslint-plugin-mocha": "10.1.0",
         "eslint-plugin-prettier": "4.2.1",
         "eslint-plugin-unicorn": "44.0.2",
@@ -80,6 +80,9 @@
         "npm-run-all": "4.1.5",
         "prettier-eslint": "15.0.1"
     },
+    "optionalDependencies": {
+        "fsevents": "*"
+    },
     "lint-staged": {
         "*.{js,jsx,ts,tsx}": [
             "eslint --fix"


Test patch:
diff --git a/test/mockRoot/.mcdevrc.json b/test/mockRoot/.mcdevrc.json
index 7b62d5c9..b783947d 100644
--- a/test/mockRoot/.mcdevrc.json
+++ b/test/mockRoot/.mcdevrc.json
@@ -63,5 +63,5 @@
             "triggeredSendDefinition"
         ]
     },
-    "version": "4.1.0"
+    "version": "4.1.1"
 }