Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/1272 add --metadata option to delete&retrieve #1274

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/Retriever.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ class Retriever {
}

/**
* helper for {@link Retriever.retrieve} to get all dependencies of the given types
* helper for Retriever.retrieve to get all dependencies of the given types
*
* @param {string[]} metadataTypes list of metadata types to retrieve; can include subtypes!
* @returns {string[]} unique list dependent metadata types
Expand Down
127 changes: 123 additions & 4 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import { Util } from './util/util.js';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import Mcdev from './index.js';

/**
* @typedef {import('../types/mcdev.d.js').TypeKeyCombo} TypeKeyCombo
*/
yargs(hideBin(process.argv))
.scriptName('mcdev')
.usage('$0 <command> [options]')
Expand Down Expand Up @@ -37,11 +41,23 @@ yargs(hideBin(process.argv))
group: 'Options for retrieve:',
describe:
'filter metadata components (can include % as wildcard or _ for a single character)',
})
.option('metadata', {
type: 'string',
alias: 'm',
group: 'Options for retrieve:',
describe:
'type or type:key or type:i:id or type:n:name to retrieve; if not provided, all metadata will be retrieved',
});
},
handler: (argv) => {
Mcdev.setOptions(argv);
Mcdev.retrieve(argv.BU, csvToArray(argv.TYPE), csvToArray(argv.KEY));
const typeKeyCombo = metadataToTypeKey(argv.metadata);
if ('undefined' === typeof typeKeyCombo) {
Mcdev.retrieve(argv.BU, csvToArray(argv.TYPE), csvToArray(argv.KEY));
} else {
Mcdev.retrieve(argv.BU, typeKeyCombo);
}
},
})
// @ts-expect-error
Expand Down Expand Up @@ -104,6 +120,7 @@ yargs(hideBin(process.argv))
describe:
"optionally ensure that updates to shared DataExtensions become visible in child BU's data designer (SF Known issue W-11031095)",
});
// TODO: add option --metadata
},
handler: (argv) => {
Mcdev.setOptions(argv);
Expand Down Expand Up @@ -191,7 +208,7 @@ yargs(hideBin(process.argv))
})
// @ts-expect-error
.command({
command: 'delete <BU> <TYPE> <EXTERNALKEY>',
command: 'delete <BU> [TYPE] [KEY]',
aliases: ['del'],
desc: 'deletes metadata of selected type and external key',
builder: (yargs) => {
Expand All @@ -205,14 +222,29 @@ yargs(hideBin(process.argv))
type: 'string',
describe: 'metadata type to delete from;',
})
.positional('EXTERNALKEY', {
.positional('KEY', {
type: 'string',
describe: 'the key to delete',
})
.option('metadata', {
type: 'string',
alias: 'm',
group: 'Options for retrieve:',
describe:
'type or type:key or type:i:id or type:n:name to retrieve; if not provided, all metadata will be retrieved',
});
},
handler: (argv) => {
Mcdev.setOptions(argv);
Mcdev.deleteByKey(argv.BU, argv.TYPE, argv.EXTERNALKEY);
const typeKeyCombo = metadataToTypeKey(argv.metadata, ['key', 'id'], true);
if ('undefined' === typeof typeKeyCombo) {
if (argv.TYPE && argv.KEY) {
Mcdev.deleteByKey(argv.BU, argv.TYPE, argv.KEY);
}
} else {
const type = Object.keys(typeKeyCombo)[0];
Mcdev.deleteByKey(argv.BU, type, typeKeyCombo[type][0]);
}
},
})
// @ts-expect-error
Expand Down Expand Up @@ -240,6 +272,7 @@ yargs(hideBin(process.argv))
group: 'Options for explainTypes:',
describe: 'optionaly return info in json format',
});
// TODO: add option --metadata
},
handler: (argv) => {
Mcdev.setOptions(argv);
Expand Down Expand Up @@ -436,6 +469,7 @@ yargs(hideBin(process.argv))
type: 'string',
describe: 'key(s) of the metadata component(s)',
});
// TODO: add option --metadata
},
handler: (argv) => {
Mcdev.setOptions(argv);
Expand All @@ -461,6 +495,7 @@ yargs(hideBin(process.argv))
type: 'string',
describe: 'key(s) of the metadata component(s)',
});
// TODO: add option --metadata
},
handler: (argv) => {
Mcdev.setOptions(argv);
Expand Down Expand Up @@ -498,6 +533,7 @@ yargs(hideBin(process.argv))
describe:
'optionally start existing schedule instead of running item once immediately (only works for automations)',
});
// TODO: add option --metadata
},
handler: (argv) => {
Mcdev.setOptions(argv);
Expand Down Expand Up @@ -530,6 +566,7 @@ yargs(hideBin(process.argv))
describe:
'filter metadata components (can include % as wildcard or _ for a single character)',
});
// TODO: add option --metadata
},
handler: (argv) => {
Mcdev.setOptions(argv);
Expand Down Expand Up @@ -562,6 +599,7 @@ yargs(hideBin(process.argv))
describe:
'filter metadata components (can include % as wildcard or _ for a single character)',
});
// TODO: add option --metadata
},
handler: (argv) => {
Mcdev.setOptions(argv);
Expand Down Expand Up @@ -606,6 +644,7 @@ yargs(hideBin(process.argv))
describe:
'optionally start existing schedule instead of running item once immediately (only works for automations)',
});
// TODO: add option --metadata
},
handler: (argv) => {
Mcdev.setOptions(argv);
Expand Down Expand Up @@ -680,3 +719,83 @@ function csvToArray(csv) {
.filter(Boolean)
: [csv.trim()].filter(Boolean);
}
/**
* helper to convert CSVs into an array. if only one value was given, it's also returned as an array
*
* @param {string|string[]} metadataOption potentially comma-separated value or null
* @param {string[]} [allowedIdentifiers] 'key', 'id', 'name'
* @param {boolean} [firstOnly] removes all but the first entry if enabled
* @returns {void|TypeKeyCombo} values split into an array.
*/
function metadataToTypeKey(
metadataOption,
allowedIdentifiers = ['key', 'id', 'name'],
firstOnly = false
) {
if (!metadataOption) {
return;
} else if (!Array.isArray(metadataOption)) {
metadataOption = [metadataOption];
}
if (firstOnly) {
// delete everything but the first entry
metadataOption.length = 1;
}
const metadataOptionMap = metadataOption.map((item) => {
const itemArr = item.split(':');
switch (itemArr.length) {
case 1: {
return { type: itemArr[0] };
}
case 2: {
if (allowedIdentifiers.includes('key')) {
return { type: itemArr[0], key: itemArr[1] };
}
break;
}
case 3: {
switch (itemArr[1]) {
case 'key':
case 'k': {
if (allowedIdentifiers.includes('key')) {
return { type: itemArr[0], key: itemArr[2] };
}
break;
}
case 'id':
case 'i': {
if (allowedIdentifiers.includes('id')) {
return { type: itemArr[0], id: itemArr[2] };
}
break;
}
case 'name':
case 'n': {
if (allowedIdentifiers.includes('name')) {
return { type: itemArr[0], name: itemArr[2] };
}
}
}
}
}
});
const response = {};
for (const item of metadataOptionMap) {
if (item) {
if (item.key || item.id || item.name) {
if (!response[item.type]) {
response[item.type] = [];
}
response[item.type].push(
item.key || (item.id ? 'id:' + item.id : item.name ? 'name:' + item.name : null)
);
} else {
if (!response[item.type]) {
response[item.type] = null;
}
}
}
}

return Object.keys(response).length >= 1 ? response : undefined;
}
Loading