cht-conf 3.9.1 → 3.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +1 -1
- package/package.json +5 -3
- package/src/bin/index.js +1 -1
- package/src/fn/check-git.js +2 -2
- package/src/fn/move-contacts.js +35 -11
- package/src/fn/upload-custom-translations.js +2 -2
- package/src/lib/api.js +13 -2
- package/src/lib/main.js +8 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## [3.9.5](https://github.com/medic/cht-conf/compare/v3.9.4...v3.9.5) (2022-01-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **#458:** return non-zero code when exiting with failure ([516bff0](https://github.com/medic/cht-conf/commit/516bff0eabec2d3c13a16a994212280d77358c7e)), closes [#458](https://github.com/medic/cht-conf/issues/458)
|
|
7
|
+
|
|
8
|
+
## [3.9.4](https://github.com/medic/cht-conf/compare/v3.9.3...v3.9.4) (2022-01-05)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **#460:** log useful error messages when api connection fails ([#461](https://github.com/medic/cht-conf/issues/461)) ([095a55c](https://github.com/medic/cht-conf/commit/095a55c9254c6872696cbee2fe42f244fc1fc4a8)), closes [#460](https://github.com/medic/cht-conf/issues/460) [#460](https://github.com/medic/cht-conf/issues/460)
|
|
14
|
+
|
|
15
|
+
## [3.9.3](https://github.com/medic/cht-conf/compare/v3.9.2...v3.9.3) (2021-12-16)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **#455:** allow empty translation constants ([ac170d7](https://github.com/medic/cht-conf/commit/ac170d7cce13a6a500d89884d4ca63801f06a969)), closes [#455](https://github.com/medic/cht-conf/issues/455)
|
|
21
|
+
|
|
22
|
+
## [3.9.2](https://github.com/medic/cht-conf/compare/v3.9.1...v3.9.2) (2021-12-08)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Performance Improvements
|
|
26
|
+
|
|
27
|
+
* **#432:** refactor the moving of reports to use a recursive function to improve performance ([c17b43b](https://github.com/medic/cht-conf/commit/c17b43b4d89b29b813db4be6e0f2d2c0a1e6c94d)), closes [#432](https://github.com/medic/cht-conf/issues/432)
|
|
28
|
+
|
|
1
29
|
## [3.9.1](https://github.com/medic/cht-conf/compare/v3.9.0...v3.9.1) (2021-11-16)
|
|
2
30
|
|
|
3
31
|
|
package/README.md
CHANGED
|
@@ -282,7 +282,7 @@ To develop a new action or improve an existing one, check the ["Actions" doc](sr
|
|
|
282
282
|
|
|
283
283
|
## Testing
|
|
284
284
|
|
|
285
|
-
Execute `npm test` to run static analysis checks and the test suite.
|
|
285
|
+
Execute `npm test` to run static analysis checks and the test suite. Requires Docker to run integration tests against a CouchDB instance.
|
|
286
286
|
|
|
287
287
|
## Executing your local branch
|
|
288
288
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cht-conf",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.5",
|
|
4
4
|
"description": "Configure CHT deployments",
|
|
5
5
|
"main": "./src/lib/main.js",
|
|
6
6
|
"engines": {
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"clean": "rm -rf ./build/",
|
|
11
11
|
"eslint": "eslint src/**/*.js test/*.js test/**/*.js",
|
|
12
|
-
"
|
|
12
|
+
"docker-start-couchdb": "npm run docker-stop-couchdb && docker run -d -p 6984:5984 --rm --name cht-conf-couchdb couchdb:2.3.1 && sh test/scripts/wait_for_response_code.sh 6984 200 CouchDB",
|
|
13
|
+
"docker-stop-couchdb": "docker stop cht-conf-couchdb || true",
|
|
14
|
+
"test": "npm run eslint && npm run docker-start-couchdb && npm run clean && mkdir -p build/test && cp -r test/data build/test/data && cd build/test && nyc --reporter=html mocha --forbid-only ../../test/**/*.spec.js && cd ../.. && npm run docker-stop-couchdb",
|
|
13
15
|
"semantic-release": "semantic-release"
|
|
14
16
|
},
|
|
15
17
|
"bin": {
|
|
@@ -34,7 +36,7 @@
|
|
|
34
36
|
"homepage": "https://github.com/medic/cht-conf#readme",
|
|
35
37
|
"dependencies": {
|
|
36
38
|
"@hapi/joi": "^16.1.8",
|
|
37
|
-
"@medic/translation-checker": "1.0.
|
|
39
|
+
"@medic/translation-checker": "^1.0.1",
|
|
38
40
|
"canonical-json": "0.0.4",
|
|
39
41
|
"csv-parse": "^4.16.0",
|
|
40
42
|
"dom-compare": "^0.6.0",
|
package/src/bin/index.js
CHANGED
package/src/fn/check-git.js
CHANGED
|
@@ -18,7 +18,7 @@ module.exports = {
|
|
|
18
18
|
warn('Changes untracked or to be committed:\n' + status);
|
|
19
19
|
if (!userPrompt.keyInYN('Are you sure you want to continue?')) {
|
|
20
20
|
error('User failed to confirm action.');
|
|
21
|
-
process.exit(
|
|
21
|
+
process.exit(1);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
info('Fetching git upstream...');
|
|
@@ -27,7 +27,7 @@ module.exports = {
|
|
|
27
27
|
warn(syncStatus);
|
|
28
28
|
if (!userPrompt.keyInYN('Are you sure you want to continue?')) {
|
|
29
29
|
error('User failed to confirm action.');
|
|
30
|
-
process.exit(
|
|
30
|
+
process.exit(1);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
package/src/fn/move-contacts.js
CHANGED
|
@@ -10,6 +10,7 @@ const pouch = require('../lib/db');
|
|
|
10
10
|
const { warn, trace, info, error } = require('../lib/log');
|
|
11
11
|
|
|
12
12
|
const HIERARCHY_ROOT = 'root';
|
|
13
|
+
const BATCH_SIZE = 10000;
|
|
13
14
|
|
|
14
15
|
module.exports = {
|
|
15
16
|
requiresInstance: true,
|
|
@@ -49,19 +50,15 @@ const updateLineagesAndStage = async (options, db) => {
|
|
|
49
50
|
trace(`Considering primary contact updates to ${ancestors.length} ancestor(s) of contact ${prettyPrintDocument(contactDoc)}.`);
|
|
50
51
|
const updatedAncestors = replaceLineageInAncestors(descendantsAndSelf, ancestors);
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
trace(`${reportsCreatedByDescendants.length} report(s) created by these affected contact(s) will update`);
|
|
54
|
-
const updatedReports = replaceLineageInReports(reportsCreatedByDescendants, replacementLineage, contactId);
|
|
53
|
+
minifyLineageAndWriteToDisk([...updatedDescendants, ...updatedAncestors], options);
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
writeDocumentToDisk(options, updatedDoc);
|
|
59
|
-
});
|
|
55
|
+
const movedReportsCount = await moveReports(db, descendantsAndSelf, options, replacementLineage, contactId);
|
|
56
|
+
trace(`${movedReportsCount} report(s) created by these affected contact(s) will be updated`);
|
|
60
57
|
|
|
61
58
|
affectedContactCount += updatedDescendants.length + updatedAncestors.length;
|
|
62
|
-
affectedReportCount +=
|
|
59
|
+
affectedReportCount += movedReportsCount;
|
|
63
60
|
|
|
64
|
-
info(`Staged updates to ${prettyPrintDocument(contactDoc)}. ${updatedDescendants.length} contact(s) and ${
|
|
61
|
+
info(`Staged updates to ${prettyPrintDocument(contactDoc)}. ${updatedDescendants.length} contact(s) and ${movedReportsCount} report(s).`);
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
info(`Staged changes to lineage information for ${affectedContactCount} contact(s) and ${affectedReportCount} report(s).`);
|
|
@@ -129,7 +126,7 @@ const prepareDocumentDirectory = ({ docDirectoryPath, force }) => {
|
|
|
129
126
|
fs.deleteFilesInFolder(docDirectoryPath);
|
|
130
127
|
} else {
|
|
131
128
|
error('User failed to confirm action.');
|
|
132
|
-
process.exit(
|
|
129
|
+
process.exit(1);
|
|
133
130
|
}
|
|
134
131
|
}
|
|
135
132
|
};
|
|
@@ -155,6 +152,31 @@ ${bold('OPTIONS')}
|
|
|
155
152
|
`);
|
|
156
153
|
};
|
|
157
154
|
|
|
155
|
+
const moveReports = async (db, descendantsAndSelf, writeOptions, replacementLineage, contactId) => {
|
|
156
|
+
const contactIds = descendantsAndSelf.map(contact => contact._id);
|
|
157
|
+
|
|
158
|
+
let skip = 0;
|
|
159
|
+
let reportDocsBatch;
|
|
160
|
+
do {
|
|
161
|
+
info(`Processing ${skip} to ${skip + BATCH_SIZE} report docs`);
|
|
162
|
+
reportDocsBatch = await fetch.reportsCreatedBy(db, contactIds, skip);
|
|
163
|
+
|
|
164
|
+
const updatedReports = replaceLineageInReports(reportDocsBatch, replacementLineage, contactId);
|
|
165
|
+
minifyLineageAndWriteToDisk(updatedReports, writeOptions);
|
|
166
|
+
|
|
167
|
+
skip += reportDocsBatch.length;
|
|
168
|
+
} while (reportDocsBatch.length >= BATCH_SIZE);
|
|
169
|
+
|
|
170
|
+
return skip;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const minifyLineageAndWriteToDisk = (docs, parsedArgs) => {
|
|
174
|
+
docs.forEach(doc => {
|
|
175
|
+
lineageManipulation.minifyLineagesInDoc(doc);
|
|
176
|
+
writeDocumentToDisk(parsedArgs, doc);
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
|
|
158
180
|
const writeDocumentToDisk = ({ docDirectoryPath }, doc) => {
|
|
159
181
|
const destinationPath = path.join(docDirectoryPath, `${doc._id}.doc.json`);
|
|
160
182
|
if (fs.exists(destinationPath)) {
|
|
@@ -214,10 +236,12 @@ const fetch = {
|
|
|
214
236
|
.filter(doc => doc && doc.type !== 'tombstone');
|
|
215
237
|
},
|
|
216
238
|
|
|
217
|
-
reportsCreatedBy: async (db, contactIds) => {
|
|
239
|
+
reportsCreatedBy: async (db, contactIds, skip) => {
|
|
218
240
|
const reports = await db.query('medic-client/reports_by_freetext', {
|
|
219
241
|
keys: contactIds.map(id => [`contact:${id}`]),
|
|
220
242
|
include_docs: true,
|
|
243
|
+
limit: BATCH_SIZE,
|
|
244
|
+
skip: skip,
|
|
221
245
|
});
|
|
222
246
|
|
|
223
247
|
return reports.rows.map(row => row.doc);
|
|
@@ -66,7 +66,7 @@ const execute = async () => {
|
|
|
66
66
|
errMsg += '\nYou can use messages-ex.properties to add placeholders missing from the reference context.';
|
|
67
67
|
}
|
|
68
68
|
log.error(errMsg);
|
|
69
|
-
return process.exit(
|
|
69
|
+
return process.exit(1);
|
|
70
70
|
}
|
|
71
71
|
} else {
|
|
72
72
|
throw err;
|
|
@@ -78,7 +78,7 @@ const execute = async () => {
|
|
|
78
78
|
const languageCode = id.substring('messages-'.length);
|
|
79
79
|
if (!isLanguageCodeValid(languageCode)) {
|
|
80
80
|
log.error(`The language code '${languageCode}' is not valid. It must begin with a letter(a–z, A-Z), followed by any number of hyphens, underscores, letters, or numbers.`);
|
|
81
|
-
return process.exit(
|
|
81
|
+
return process.exit(1);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
let languageName = iso639.getName(languageCode);
|
package/src/lib/api.js
CHANGED
|
@@ -99,8 +99,19 @@ const api = {
|
|
|
99
99
|
await request.get(url);
|
|
100
100
|
return true;
|
|
101
101
|
} catch (err) {
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
if (err.statusCode === 401) {
|
|
103
|
+
log.error(`Authentication failed connecting to ${url}. `
|
|
104
|
+
+ 'Check the supplied username and password and try again.');
|
|
105
|
+
} else if (err.statusCode === 403) {
|
|
106
|
+
log.error(`Insufficient permissions connecting to ${url}. `
|
|
107
|
+
+ 'You need to use admin permissions to execute this command.');
|
|
108
|
+
} else if (err.statusCode) {
|
|
109
|
+
log.error(`Received error code ${err.statusCode} connecting to ${url}. `
|
|
110
|
+
+ 'Check the server and and try again.');
|
|
111
|
+
} else {
|
|
112
|
+
log.error(`Failed to get a response from ${url}. Maybe you entered the wrong URL, `
|
|
113
|
+
+ 'wrong port or the instance is not started. Please check and try again.');
|
|
114
|
+
}
|
|
104
115
|
return false;
|
|
105
116
|
}
|
|
106
117
|
},
|
package/src/lib/main.js
CHANGED
|
@@ -57,7 +57,7 @@ module.exports = async (argv, env) => {
|
|
|
57
57
|
|
|
58
58
|
if(argv.length <= 2) {
|
|
59
59
|
usage(0);
|
|
60
|
-
return
|
|
60
|
+
return 1;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
const cmdArgs = require('minimist')(argv.slice(2), {
|
|
@@ -94,7 +94,7 @@ module.exports = async (argv, env) => {
|
|
|
94
94
|
|
|
95
95
|
if (cmdArgs.archive && !cmdArgs.destination) {
|
|
96
96
|
error('--destination=<path to save files> is required with --archive.');
|
|
97
|
-
return
|
|
97
|
+
return 1;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
if (cmdArgs['accept-self-signed-certs']) {
|
|
@@ -131,7 +131,7 @@ module.exports = async (argv, env) => {
|
|
|
131
131
|
const unsupported = actions.filter(a => !supportedActions.includes(a));
|
|
132
132
|
if(unsupported.length) {
|
|
133
133
|
error(`Unsupported action(s): ${unsupported.join(' ')}`);
|
|
134
|
-
return
|
|
134
|
+
return 1;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
if (cmdArgs['skip-git-check']) {
|
|
@@ -164,7 +164,7 @@ module.exports = async (argv, env) => {
|
|
|
164
164
|
apiUrl = getApiUrl(cmdArgs, env);
|
|
165
165
|
if (!apiUrl) {
|
|
166
166
|
error('Failed to obtain a url to the API');
|
|
167
|
-
return
|
|
167
|
+
return 1;
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -184,7 +184,7 @@ module.exports = async (argv, env) => {
|
|
|
184
184
|
);
|
|
185
185
|
|
|
186
186
|
if (apiUrl && !await api().available()) {
|
|
187
|
-
return
|
|
187
|
+
return 1;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
const productionUrlMatch = environment.instanceUrl && environment.instanceUrl.match(/^https:\/\/(?:[^@]*@)?(.*)\.(app|dev)\.medicmobile\.org(?:$|\/)/);
|
|
@@ -194,7 +194,7 @@ module.exports = async (argv, env) => {
|
|
|
194
194
|
`against non-matching instance: \x1b[31m${redactBasicAuth(environment.instanceUrl)}\x1b[33m`);
|
|
195
195
|
if(!userPrompt.keyInYN()) {
|
|
196
196
|
error('User failed to confirm action.');
|
|
197
|
-
return
|
|
197
|
+
return 1;
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
|
|
@@ -218,6 +218,8 @@ module.exports = async (argv, env) => {
|
|
|
218
218
|
if (actions.length > 1) {
|
|
219
219
|
await info('All actions completed.');
|
|
220
220
|
}
|
|
221
|
+
|
|
222
|
+
return 0;
|
|
221
223
|
};
|
|
222
224
|
|
|
223
225
|
// Exists for generic mocking purposes
|