Add in folder and in file logic

Improve reusability
Add in folder
Add in file
restructure metadata file
This commit is contained in:
Sébastien Colladon 2017-06-25 18:49:17 +02:00
Родитель f81dfeb663
Коммит c0502d2813
11 изменённых файлов: 138 добавлений и 38 удалений

Просмотреть файл

@ -51,6 +51,9 @@ $ sgp -h
}, console.log);
```
### Module
Add CLI parameters to build package.xml for only certain types
## Built With

5
bin/cli Normal file → Executable file
Просмотреть файл

@ -1,4 +1,7 @@
#!/usr/bin/env node
'use strict';
// TODO improve parameter to concentrate on create only certaine type
const program = require('commander');
const orchestrator = require('../index.js');
@ -14,5 +17,5 @@ program
orchestrator(program, console.log)
.catch(function(err){
console.log(err);
throw err;
});

Просмотреть файл

@ -25,7 +25,8 @@ module.exports = (config,logger) => {
const xml = xmlbuilder.create('Package')
.att('xmlns', 'http://soap.sforce.com/2006/04/metadata')
.dec('1.0', 'UTF-8');
result.forEach(elem => {if(!!elem) xml.importDocument(elem)});
[].concat(...result).filter(elem => !!elem).forEach(elem => xml.importDocument(elem));
xml.ele('version')
.t(config.apiVersion);
const xmlContent = xml.end({ pretty: true, indent: ' ', newline: '\n' });

Просмотреть файл

@ -1,14 +1,21 @@
'use strict';
const CustomLabels = require('../strategies/type-strategies/customlabel-type-strategy');
const CustomLabel = require('../strategies/type-strategies/customlabel-type-strategy');
const SubDef = require('../strategies/type-strategies/subdefinition-type-strategy');
const Standard = require('../strategies/type-strategies/standard-type-strategy');
const InFolder = require('../strategies/type-strategies/infolder-type-strategy');
const metadata = require('../utils/metadata');
// TODO CustomObject
// TODO Workflow
// TODO email template and report dashboard and Document
const classes = {
'CustomLabels' : CustomLabels
'CustomLabels' : CustomLabel,
'Workflow' : SubDef,
'CustomObject' : SubDef,
'EmailTemplate' : InFolder,
'Document' : InFolder,
'Report' : InFolder,
'Dashboard' : InFolder
};
module.exports = class StandardStrategy {

Просмотреть файл

@ -17,21 +17,23 @@ module.exports = class CustomLabelStrategy extends AbstractTypeStrategy {
Promise.all(
this.child.children
.sort((a,b) => a.name.localeCompare(b.name))
.map( aCustomLabelNode => readFileAsync(aCustomLabelNode.path,'utf8').then(xml2jsAsync))
.map( aNode => readFileAsync(aNode,'utf8').then(xml2jsAsync))
).then(result => {
let isEmpty = true;
const types = []
const type = xmlbuilder.create('types');
result.forEach( customLabelFile => {
const customLabelDefinitions = customLabelFile.CustomLabels.labels
const definitions = customLabelFile.content.CustomLabels.labels
.sort((a,b) => a.fullName[0].localeCompare(b.fullName[0]));
isEmpty &= customLabelDefinitions.length == 0;
customLabelDefinitions.forEach(customLabelDefinition => {
isEmpty &= definitions.length == 0;
definitions.forEach(aDefinition => {
type.ele('members')
.t(customLabelDefinition.fullName[0]);
.t(aDefinition.fullName[0]);
})
})
type.ele('name').t(metadata[this.child.name].children[metadata[this.child.name].xmlName]);
resolve(isEmpty ? undefined : type);
types.push(type)
resolve(isEmpty ? undefined : types);
}).catch(reject);
});
return promise;

Просмотреть файл

@ -0,0 +1,32 @@
const metadata = require('../../utils/metadata');
const xmlbuilder = require('xmlbuilder');
module.exports = class StandardStrategy {
constructor(child) {
this.child = child;
}
build(){
const promise = new Promise((resolve, reject) => {
const children = this.child.children.filter(elem => !elem.name.startsWith('.') && !elem.name.endsWith('-meta.xml'))
if(children.length == 0) {
resolve();
}
const types = []
const type = xmlbuilder.create('types');
children.sort((a,b) => a.name.localeCompare(b.name))
.forEach(subChild => {
type.ele('members')
.t(subChild.name.replace(/\.[^/.]+$/,''));
subChild.children && subChild.children.filter(elem => elem.extension && elem.extension != '.xml' && !elem.name.startsWith('.')).sort().forEach(subsubChild => {
type.ele('members')
.t(subChild.name+'/'+subsubChild.name.replace(/\.[^/.]+$/,''));
})
})
type.ele('name').t(metadata[this.child.name].xmlName);
types.push(type)
resolve(types)
});
return promise;
}
};

Просмотреть файл

@ -12,6 +12,7 @@ module.exports = class StandardStrategy {
if(children.length == 0) {
resolve();
}
const types = []
const type = xmlbuilder.create('types');
children.sort((a,b) => a.name.localeCompare(b.name))
.forEach(subChild => {
@ -19,7 +20,8 @@ module.exports = class StandardStrategy {
.t(subChild.name.replace(/\.[^/.]+$/,''));
})
type.ele('name').t(metadata[this.child.name].xmlName);
resolve(type)
types.push(type)
resolve(types)
});
return promise;
}

Просмотреть файл

@ -0,0 +1,49 @@
const metadata = require('../../utils/metadata');
const xmlbuilder = require('xmlbuilder');
const xml2jsAsync = require('../../utils/async-xml-parser');
const readFileAsync = require('../../utils/async-read-file')
const AbstractTypeStrategy = require('./standard-type-strategy');
module.exports = class SubDefinitionStrategy extends AbstractTypeStrategy {
constructor(child) {
super(child);
}
build(){
const promise = new Promise((resolve, reject) => {
if(this.child.children.length == 0) {
resolve();
}
Promise.all(
this.child.children
.sort((a,b) => a.name.localeCompare(b.name))
.map( aNode => readFileAsync(aNode,'utf8').then(xml2jsAsync))
).then(result => {
const struct = {}
struct[metadata[this.child.name].xmlName] = [];
result.forEach( aFile => {
struct[metadata[this.child.name].xmlName].push(aFile.name.replace(/\.[^/.]+$/,''));
const objectName = Object.keys(aFile.content)[0];
for(let childDef in aFile.content[objectName]) if(metadata[this.child.name].children.hasOwnProperty(childDef)) {
struct[metadata[this.child.name].children[childDef].typeName] = struct[metadata[this.child.name].children[childDef].typeName] || [];
aFile.content[objectName][childDef].forEach(elem => struct[metadata[this.child.name].children[childDef].typeName].push(aFile.name.replace(/\.[^/.]+$/,'') + '.' + elem[metadata[this.child.name].children[childDef].name][0]));
}
})
const types = []
Object.keys(struct).sort().forEach(aStruc => {
const type = xmlbuilder.create('types');
struct[aStruc].sort().forEach(elem => {
type.ele('members')
.t(elem);
})
type.ele('name').t(aStruc);
types.push(type);
})
resolve(types.length == 0 ? undefined : types);
}).catch(reject);
});
return promise;
}
};

Просмотреть файл

@ -1,10 +1,11 @@
const fs = require('fs');
const readFileAsync = (path) => {
const readFileAsync = (file) => {
const promise = new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
fs.readFile(file.path, (err, data) => {
if (err) reject(err);
resolve(data);
file.content = data;
resolve(file);
});
});
return promise;

Просмотреть файл

@ -1,11 +1,12 @@
const xml2js = require('xml2js');
const parseStringAsync = (fileContent) => {
const parseStringAsync = (file) => {
const promise = new Promise((resolve, reject) => {
const parser = new xml2js.Parser();
parser.parseString(fileContent, (err, result) => {
parser.parseString(file.content, (err, result) => {
if (err) reject(err);
resolve(result);
file.content = result;
resolve(file);
});
});
return promise;

Просмотреть файл

@ -44,18 +44,17 @@ module.exports = {
"objects":{
"xmlName":"CustomObject",
"children":{
"actionOverrides":"ActionOverride",
"fields":"CustomField",
"businessProcesses":"BusinessProcess",
"recordTypes":"RecordType",
"webLinks":"WebLink",
"validationRules":"ValidationRule",
"namedFilters":"NamedFilter",
"sharingReasons":"SharingReason",
"listViews":"ListView",
"fieldSets":"FieldSet",
"sharingRecalculations":"SharingRecalculation",
"compactLayouts":"CompactLayout"
"actionOverrides":{"typeName":"ActionOverride","name":"actionName"},
"fields":{"typeName":"CustomField","name":"fullName"},
"businessProcesses":{"typeName":"BusinessProcess","name":"fullName"},
"recordTypes":{"typeName":"RecordType","name":"fullName"},
"webLinks":{"typeName":"WebLink","name":"fullName"},
"validationRules":{"typeName":"ValidationRule","name":"fullName"},
"namedFilters":{"typeName":"NamedFilter","name":"fullName"},
"sharingReasons":{"typeName":"SharingReason","name":"fullName"},
"listViews":{"typeName":"ListView","name":"fullName"},
"fieldSets":{"typeName":"FieldSet","name":"fullName"},
"compactLayouts":{"typeName":"WorkflowAlert","name":"fullName"}
}
},
"reportTypes":{
@ -151,14 +150,14 @@ module.exports = {
"workflows":{
"xmlName":"Workflow",
"children":{
"alerts":"WorkflowAlert",
"tasks":"WorkflowTask",
"outboundMessages":"WorkflowOutboundMessage",
"fieldUpdates":"WorkflowFieldUpdate",
"rules":"WorkflowRule",
"emailRecipients":"WorkflowEmailRecipient",
"timeTriggers":"WorkflowTimeTrigger",
"actionReferences":"WorkflowActionReference"
"alerts":{"typeName":"WorkflowAlert","name":"fullName"},
"tasks":{"typeName" : "WorkflowTask", "name" : "fullName"},
"outboundMessages":{"typeName" : "WorkflowOutboundMessage","name" : "fullName"},
"fieldUpdates":{"typeName" : "WorkflowFieldUpdate", "name" : "fullName"},
"rules":{"typeName" : "WorkflowRule", "name" : "fullName"},
"emailRecipients":{"typeName" : "WorkflowEmailRecipient", "name" : "fullName"},
"timeTriggers":{"typeName" : "WorkflowTimeTrigger", "name" : "fullName"},
"actionReferences":{"typeName" : "WorkflowActionReference", "name" : "fullName"}
}
},
"assignmentRules":{