Skip to content

Commit 82fbc14

Browse files
committed
* Add debug option via the command line additional to config setting. (--debug)
* Fix export not using subdir format * Add support for more tables (service portal related) * NOTE: Some folders like widgets are now sp_widgets (to group SP together). Ensure you rename both records/widgets and records/.sync_data/widgets to be "sp_widgets" OR define your own "folders" mapping in your config.json * Add more debugging for problematic folder/sync configs and failed downloads * Fix readme/documentation issues
1 parent 9d588d9 commit 82fbc14

File tree

6 files changed

+101
-24
lines changed

6 files changed

+101
-24
lines changed

CHANGES.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
# FileSync Changes
22

3+
* 2017-03-26 (**Version 4.2.4**)
4+
* Add debug option via the command line additional to config setting. (`--debug`)
5+
* Fix export not using subdir format
6+
* Add support for more tables (service portal related)
7+
* NOTE: Some folders like widgets are now sp_widgets (to group SP together). Ensure you rename both records/widgets and records/.sync_data/widgets to be "sp_widgets" OR define your own "folders" mapping in your config.json
8+
* Add more debugging for problematic folder/sync configs and failed downloads
9+
* Fix readme/documentation issues
10+
311
* 2016-12-22 (**Version 4.2.3**)
4-
* Support searching for and downloading records via a URL as search criteria
12+
* Improved support for searching and downloading records.
13+
* Eg. `node bin/app.js --config config.json --search <URL>`
514

615
* 2016-11-01 (**Version 4.2.2**)
716
* Add new search feature allowing easier downloading of single records

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
sn-filesync -- ServiceNow FileSync (v4.2.2)
1+
sn-filesync -- ServiceNow FileSync (v4.2.4)
22
=================
33

44
[![NPM](https://nodei.co/npm-dl/sn-filesync.png?height=3&months=9)](https://nodei.co/npm-dl/sn-filesync/)

bin/app.js

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ var constants = {
5757
constants.chokiWatcherIgnore = [/[\/\\]\./, '**/*' + constants.fullRecordSuffix];
5858

5959
// default to ok.
60-
var multiDownloadStatus = constants.DOWNLOAD_OK;
60+
var multiDownloadStatus = constants.DOWNLOAD_OK,
61+
// support the end user
62+
listOfFailedFiles = [];
6163

6264
var testsRunning = false;
6365

@@ -98,6 +100,9 @@ function init() {
98100
winston.error('Configuration error:'.red, e.message);
99101
exitApp();
100102
}
103+
if (argv.debug) {
104+
config.debug = true;
105+
}
101106

102107
setupLogging();
103108

@@ -253,9 +258,15 @@ function extractTableFromName(str) {
253258
* Example
254259
* http://localhost:16008/nav_to.do?uri=%2Fsp_widget.do%3Fsys_id%3Df37aa302cb70020000f8d856634c9cfc%26sysparm_record_target%3Dsp_widget
255260
*
261+
* OR
262+
*
263+
* http://localhost:16008/nav_to.do?uri=sp_angular_provider.do?sys_id=06e836f0d722120023c84f80de6103a1"
264+
*
256265
*/
257-
start = str.replace('_list', '').split('.do%3F');
258-
end = start[0].split('uri=%2F');
266+
// normalise the string
267+
str = str.replace(/\%2F/g, '').replace(/\%3F/g, '');
268+
start = str.replace('_list', '').split('.do');
269+
end = start[1].split('uri=');
259270
table = end.pop();
260271

261272
} else if (str.indexOf('.do') >= 0) {
@@ -881,6 +892,7 @@ function addConfigFiles() {
881892
// each file to create
882893
for (var file in root.preLoadList[folder]) {
883894
var filePath = path.join(r, folder, root.preLoadList[folder][file]);
895+
884896
addToPreLoadList(filePath, {
885897
filePath: filePath
886898
});
@@ -897,6 +909,7 @@ function addToPreLoadList(filePath, options) {
897909
filePath: filePath
898910
};
899911
// only process if we don't already have it in the list
912+
// todo: assumes all file names are unique!
900913
if (typeof filesToPreLoad[filePath] == 'undefined') {
901914
filesToPreLoad[filePath] = options;
902915
addFile(filePath);
@@ -934,7 +947,7 @@ function displayHelp() {
934947
function handleError(err, context) {
935948
logit.error(err);
936949
if (context) {
937-
logit.error(' handleError context:', context);
950+
logit.error('handleError context:', context);
938951
}
939952
}
940953

@@ -970,9 +983,13 @@ function exportCurrentSetup(exportConfigPath) {
970983
for (var i in watchedFolders) {
971984
// remove sensitive data that may exist
972985
delete exportConfig.roots[watchedFolders[i]].auth;
986+
987+
// remove caching properties
988+
delete exportConfig.roots[watchedFolders[i]].root;
989+
973990
// overwrite remaining sensitive data
974991
exportConfig.roots[watchedFolders[i]].user = '<your user name>';
975-
exportConfig.roots[watchedFolders[i]].pass = '<your password (which will be encrypted)>';
992+
exportConfig.roots[watchedFolders[i]].pass = '<your password (which will become encrypted)>';
976993

977994
exportConfig.roots[watchedFolders[i]].preLoadList = {};
978995
}
@@ -991,13 +1008,14 @@ function exportCurrentSetup(exportConfigPath) {
9911008
var f = new FileRecord(config, file),
9921009
folder = f.getFolderName(),
9931010
fileName = f.getFileName(),
1011+
exportPath = f.getFileSubDirPath(),
9941012
rootDir = f.getRoot();
9951013

9961014
// add to appropriate preLoadList folder array
9971015
if (!exportConfig.roots[rootDir].preLoadList[folder]) {
9981016
exportConfig.roots[rootDir].preLoadList[folder] = [];
9991017
}
1000-
exportConfig.roots[rootDir].preLoadList[folder].push(fileName);
1018+
exportConfig.roots[rootDir].preLoadList[folder].push(exportPath);
10011019
}
10021020
})
10031021
.on('ready', function () {
@@ -1050,7 +1068,11 @@ function decrementQueue() {
10501068
notifyEnabled = true;
10511069
// show one notification to represent if all files were downloaded or not
10521070
if (multiDownloadStatus == constants.DOWNLOAD_FAIL) {
1053-
logit.error('Some or all files failed to download'.red);
1071+
logit.error('Files failed to download.'.red + ' See list below for details.');
1072+
// TODO, show what files failed
1073+
logit.info(listOfFailedFiles);
1074+
// reset list
1075+
listOfFailedFiles = [];
10541076
notifyUser(msgCodes.COMPLEX_ERROR);
10551077
} else {
10561078
notifyUser(msgCodes.ALL_DOWNLOADS_COMPLETE);
@@ -1100,7 +1122,12 @@ function validResponse(err, obj, db, map, fileRecord) {
11001122

11011123
function receive(file, allDoneCallBack) {
11021124
var map = fileRecords[file].getSyncMap(),
1103-
fileMeta = fileRecords[file].getMeta();
1125+
fileMeta = fileRecords[file].getMeta(),
1126+
// the sys_id either comes from the meta (if already exists) or the file name or not at all
1127+
sys_id = fileMeta.sys_id || extractSysIdFromName(map.keyValue) || false,
1128+
// map.keyValue could be like "insert_problem.d5e561f3c0a8000901a883289848f88d"
1129+
// this is a combination of sys_id and name. Use sys_id from name when possible and ignore the query
1130+
query = sys_id ? '' : map.key + '=' + map.keyValue;
11041131

11051132
logit.debug('Adding:', {
11061133
file: file,
@@ -1117,12 +1144,13 @@ function receive(file, allDoneCallBack) {
11171144
var db = {
11181145
table: map.table,
11191146
field: map.field,
1120-
query: map.key + '=' + map.keyValue,
1121-
sys_id: fileMeta.sys_id || false
1147+
query: query,
1148+
sys_id: sys_id
11221149
};
11231150

11241151
snc.table(db.table).getRecords(db, function (err, obj) {
11251152
var isValid = validResponse(err, obj, db, map, fileRecords[file]);
1153+
11261154
if (!isValid) {
11271155
decrementQueue();
11281156
allDoneCallBack(false);
@@ -1134,6 +1162,7 @@ function receive(file, allDoneCallBack) {
11341162
objName = record.name; // TODO : use objName instead of file var.
11351163

11361164

1165+
11371166
// legacy concept (still needed??... TODO: don't allow creation of 0 byte files!)
11381167
if (record[db.field].length < 1) {
11391168
logit.warn('**WARNING : this record is 0 bytes'.red);
@@ -1379,7 +1408,8 @@ function addFile(file, callback) {
13791408
// default callback
13801409
callback = callback || function (complete) {
13811410
if (!complete) {
1382-
logit.info(('Could not add file: ' + file).red);
1411+
logit.warn(('Could not add file: ' + file));
1412+
listOfFailedFiles.push(file);
13831413
multiDownloadStatus = constants.DOWNLOAD_FAIL;
13841414
}
13851415
};
@@ -1542,10 +1572,16 @@ function watchFolders() {
15421572

15431573
addFile(file);
15441574
}
1575+
} else {
1576+
// file could be invalid (eg, folder mapping missing)
1577+
logit.warn('File cannot be tracked because it is not valid: %s', file);
15451578
}
15461579

15471580
} else {
1548-
trackFile(file);
1581+
if (!trackFile(file)) {
1582+
// file could be invalid (eg, folder mapping missing)
1583+
logit.warn('File cannot be tracked because it is not valid: %s', file);
1584+
}
15491585
}
15501586
})
15511587
.on('change', onChange)

lib/file-record.js

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,6 @@ method.clearMetaFile = function (callback) {
106106
}
107107
});
108108
};
109-
110-
method.getFileName = function () {
111-
return path.basename(this.filePath);
112-
};
113-
114109
// track if a file has been discovered by the watcher or not as a "new" record field to download
115110
method.setNewlyDiscoveredFile = function (isNew) {
116111
this._isNewFile = isNew;
@@ -119,6 +114,22 @@ method.isNewlyDiscoveredFile = function () {
119114
return this._isNewFile;
120115
};
121116

117+
/**
118+
* Returns the full path to the file minus the path to the root dir
119+
*/
120+
method.getFilePathRelativeToRoot = function () {
121+
return this.filePath.replace(this.rootDir + SLASH, '');
122+
};
123+
124+
method.getFileSubDirPath = function () {
125+
var p = this.getFilePathRelativeToRoot();
126+
return p.replace(this.getFolderName() + SLASH, '');
127+
};
128+
129+
method.getFileName = function () {
130+
return path.basename(this.filePath);
131+
};
132+
122133
method.getFolderName = function () {
123134
// remove file name from path
124135
var dir = path.dirname(this.filePath),
@@ -229,7 +240,7 @@ method.getSyncMap = function () {
229240
// validate parent folder is mapped
230241
var map = this.config.folders[folder];
231242
if (!map) {
232-
this.logger.warn('No map');
243+
this.logger.warn('No mapping for this folder: %s', folder);
233244
return null;
234245
}
235246

lib/records.config.json

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,37 @@
139139
},
140140
"subDirPattern": "web_service_definition"
141141
},
142-
"widgets": {
142+
"sp_widgets": {
143143
"table": "sp_widget",
144144
"key": "name",
145145
"fields": {
146146
"client.js": "client_script",
147147
"demo.js": "demo_data",
148148
"server.js": "script",
149149
"html": "template",
150-
"scss": "scss"
151-
}
150+
"css": "css"
151+
},
152+
"subDirPattern": "servicenow_<servicenow>"
153+
},
154+
"sp_header_footer": {
155+
"table": "sp_header_footer",
156+
"key": "name",
157+
"fields": {
158+
"client.js": "client_script",
159+
"demo.js": "demo_data",
160+
"server.js": "script",
161+
"html": "template",
162+
"css": "css"
163+
},
164+
"subDirPattern": "servicenow_<servicenow>"
165+
},
166+
"sp_providers": {
167+
"table": "sp_angular_provider",
168+
"key": "name",
169+
"fields": {
170+
"js": "script"
171+
},
172+
"subDirPattern": "type"
152173
}
153174
}
154175
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sn-filesync",
3-
"version": "4.2.3",
3+
"version": "4.2.4",
44
"description": "Enables out of instance record updates for ServiceNow.",
55
"main": "bin/app.js",
66
"bin": {

0 commit comments

Comments
 (0)