@produtype/core 1.12.0 → 1.12.1
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.
|
@@ -225,26 +225,53 @@ async function detectDatabase(ctx) {
|
|
|
225
225
|
databases.add('sqlite');
|
|
226
226
|
evidence.push({ type: 'file', value: 'sqlite db file detected' });
|
|
227
227
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Every compose file, not the first one in the list.
|
|
230
|
+
*
|
|
231
|
+
* A repository has several: `docker-compose.yml` beside `.devcontainer/
|
|
232
|
+
* docker-compose.yml`, an override for tests, one per deployment shape. This read
|
|
233
|
+
* whichever came back first and ignored the rest, so a Postgres declared only in
|
|
234
|
+
* the production compose was invisible whenever a development one sorted ahead of
|
|
235
|
+
* it — and which one that is was the filesystem's business until this session
|
|
236
|
+
* sorted the scan.
|
|
237
|
+
*
|
|
238
|
+
* The devcontainer is not excluded here, and that is the difference from
|
|
239
|
+
* `docker.presence` next door. "How does this ship" is answered by the image the
|
|
240
|
+
* product is built into; "what does it store data in" is answered by the database
|
|
241
|
+
* it talks to, and in development that is the one the devcontainer starts. The same
|
|
242
|
+
* file, two questions, two answers.
|
|
243
|
+
*/
|
|
244
|
+
const composeFiles = ctx.files.all.filter((f) => /(^|\/)(docker-compose[\w.-]*\.ya?ml|compose[\w.-]*\.ya?ml)$/.test(f)).slice(0, 8);
|
|
245
|
+
/**
|
|
246
|
+
* Each store cited once, from the first file that shows it.
|
|
247
|
+
*
|
|
248
|
+
* immich has seven compose files and all of them run Postgres and Redis, so reading
|
|
249
|
+
* every one turned two facts into eleven citations of the same two facts. A reader
|
|
250
|
+
* is promised a line they can open and argue with; eleven lines saying the same
|
|
251
|
+
* thing is not eleven times the argument.
|
|
252
|
+
*/
|
|
253
|
+
const COMPOSE_SERVICES = [
|
|
254
|
+
['postgres', /image:\s*postgres/i, /postgres:/i],
|
|
255
|
+
['redis', /image:\s*redis/i, /redis:/i],
|
|
256
|
+
['mysql', /image:\s*mysql/i, null],
|
|
257
|
+
['mongodb', /image:\s*mongo/i, null],
|
|
258
|
+
];
|
|
259
|
+
/**
|
|
260
|
+
* Counted for this reading only, not against `databases`: a store the dependencies
|
|
261
|
+
* already named still deserves the compose line beside it, and skipping on the set
|
|
262
|
+
* removed every compose citation from a project that declares its driver too.
|
|
263
|
+
*/
|
|
264
|
+
const citedFromCompose = new Set();
|
|
265
|
+
for (const composeFile of composeFiles) {
|
|
231
266
|
const text = (await (0, readTextFileSafe_1.readTextFileSafe)(ctx.root, composeFile)) ?? '';
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
evidence.push({ type: 'file', value:
|
|
240
|
-
}
|
|
241
|
-
if (/image:\s*mysql/i.test(text)) {
|
|
242
|
-
databases.add('mysql');
|
|
243
|
-
evidence.push({ type: 'file', value: 'mysql in docker-compose', file: composeFile });
|
|
244
|
-
}
|
|
245
|
-
if (/image:\s*mongo/i.test(text)) {
|
|
246
|
-
databases.add('mongodb');
|
|
247
|
-
evidence.push({ type: 'file', value: 'mongo in docker-compose', file: composeFile });
|
|
267
|
+
for (const [name, image, service] of COMPOSE_SERVICES) {
|
|
268
|
+
if (citedFromCompose.has(name))
|
|
269
|
+
continue;
|
|
270
|
+
if (!image.test(text) && !(service && service.test(text)))
|
|
271
|
+
continue;
|
|
272
|
+
databases.add(name);
|
|
273
|
+
citedFromCompose.add(name);
|
|
274
|
+
evidence.push({ type: 'file', value: `${name} in docker-compose`, file: composeFile });
|
|
248
275
|
}
|
|
249
276
|
}
|
|
250
277
|
// DATABASE_URL env reference
|
|
@@ -97,11 +97,21 @@ async function detectJobs(ctx) {
|
|
|
97
97
|
for (const name of processScripts) {
|
|
98
98
|
evidence.push({ type: 'note', value: `package.json script "${name}" starts a separate process` });
|
|
99
99
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
/**
|
|
101
|
+
* A compose service that runs one — in any of the compose files, not the first.
|
|
102
|
+
*
|
|
103
|
+
* A repository has several, and this read whichever came back first: a worker
|
|
104
|
+
* declared in the production compose was invisible whenever a development one
|
|
105
|
+
* sorted ahead of it. The same first-match reading that made `docker.presence`
|
|
106
|
+
* answer "how does this ship" with a devcontainer, one detector along.
|
|
107
|
+
*/
|
|
108
|
+
const composeFiles = ctx.files.all.filter((file) => /(^|\/)(docker-compose[\w.-]*\.ya?ml|compose[\w.-]*\.ya?ml)$/.test(file)).slice(0, 8);
|
|
109
|
+
let composeWorker = false;
|
|
110
|
+
for (const composeFile of composeFiles) {
|
|
111
|
+
const composeText = (await (0, readTextFileSafe_1.readTextFileSafe)(ctx.root, composeFile)) ?? '';
|
|
112
|
+
if (!/^\s{2}(worker|jobs?|scheduler|cron|consumer)[a-z0-9_-]*:/im.test(composeText))
|
|
113
|
+
continue;
|
|
114
|
+
composeWorker = true;
|
|
105
115
|
evidence.push({ type: 'file', value: 'a worker service in compose', file: composeFile });
|
|
106
116
|
}
|
|
107
117
|
const declarations = await (0, textSearch_1.searchInFiles)(ctx.root, ctx.files.source, JOB_DECLARATIONS, 20);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@produtype/core",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"description": "Deterministic CLI and library that analyzes a web application repository and reports how far it is from production-ready for the kind of product it is meant to be.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|