@produtype/core 0.91.0 → 0.93.0
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.
|
@@ -157,6 +157,34 @@ function parsePyprojectSections(text, runtimeOnly) {
|
|
|
157
157
|
}
|
|
158
158
|
return deps;
|
|
159
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Everything after `src/main/java` is a package name, not a project layout.
|
|
162
|
+
*
|
|
163
|
+
* spring-petclinic lives in `org.springframework.samples.petclinic`, so every one of
|
|
164
|
+
* its thirty Java files sat under a path segment called `samples`, and the rule that
|
|
165
|
+
* removes sample code removed the whole application: twelve files, an HTML front end,
|
|
166
|
+
* no backend, and `client-app` at high confidence for a Spring Boot server.
|
|
167
|
+
*
|
|
168
|
+
* It was not only `samples`. `spring-test/src/main/java/org/springframework/mock/`
|
|
169
|
+
* holds forty-four files — `MockHttpServletRequest` and its neighbours, shipped in the
|
|
170
|
+
* jar and the whole point of that module — and the rule that removes `mocks/` removed
|
|
171
|
+
* every one of them. A package can be called anything: `vendor`, `testing`, `fixtures`
|
|
172
|
+
* are all ordinary domain words.
|
|
173
|
+
*
|
|
174
|
+
* Maven and Gradle fix the `src/main/<language>` prefix, so directory rules are
|
|
175
|
+
* applied to the path *up to* it and never to the package below.
|
|
176
|
+
*
|
|
177
|
+
* Only `main` is named, and that is a statement of intent rather than a rule doing
|
|
178
|
+
* work: `src/test/java/...` stays excluded either way, because the boundary itself
|
|
179
|
+
* contains `test` and the directory rule matches it. Writing `main|test` here fails
|
|
180
|
+
* no test, which is worth saying instead of implying a protection that is not there.
|
|
181
|
+
*/
|
|
182
|
+
const JVM_MAIN_SOURCE_ROOT = /(^|\/)src\/main\/(java|kotlin|scala|groovy)\//;
|
|
183
|
+
/** The part of the path that describes layout rather than package. */
|
|
184
|
+
function layoutPartOf(file) {
|
|
185
|
+
const root = JVM_MAIN_SOURCE_ROOT.exec(file);
|
|
186
|
+
return root ? file.slice(0, root.index + root[0].length) : file;
|
|
187
|
+
}
|
|
160
188
|
function isTestOrExamplePath(file) {
|
|
161
189
|
// `__mocks__` was missing, and a mock is the most misleading file in a repository:
|
|
162
190
|
// `application_fee_percent: null` inside a Stripe fixture made an open-source CRM read
|
|
@@ -164,7 +192,8 @@ function isTestOrExamplePath(file) {
|
|
|
164
192
|
// `fixtures` was listed and `fixture` was not, so `extra/fixture/authsources.php`
|
|
165
193
|
// made PHP one of the languages of an Elixir analytics product — and of cal.com,
|
|
166
194
|
// which is TypeScript.
|
|
167
|
-
|
|
195
|
+
const layout = layoutPartOf(file);
|
|
196
|
+
return /(^|\/)(__tests__|__mocks__|mocks?|tests?|test-data|fixtures?|frontend-example)(\/|$)/i.test(layout)
|
|
168
197
|
/**
|
|
169
198
|
* The conventions other ecosystems use, which this list did not know.
|
|
170
199
|
*
|
|
@@ -175,7 +204,7 @@ function isTestOrExamplePath(file) {
|
|
|
175
204
|
* would have parsed the same files and reached the same wrong conclusion, which is
|
|
176
205
|
* the argument for fixing what gets read before fixing how.
|
|
177
206
|
*/
|
|
178
|
-
|| /(^|\/)(spec|specs|e2e|integration-tests?|cypress|playwright|testing)(\/|$)/i.test(
|
|
207
|
+
|| /(^|\/)(spec|specs|e2e|integration-tests?|cypress|playwright|testing)(\/|$)/i.test(layout)
|
|
179
208
|
|| /\.(e2e|e2e-spec|cy|stories)\.(ts|tsx|js|jsx|mjs|cjs)$/i.test(file)
|
|
180
209
|
|| /_spec\.rb$/i.test(file)
|
|
181
210
|
|| /_test\.(go|py|rb|java|cs|php)$/i.test(file)
|
|
@@ -219,7 +248,7 @@ function isTestOrExamplePath(file) {
|
|
|
219
248
|
* spell it. A repository whose every source file is a sample now has no source
|
|
220
249
|
* files, and says so — which is the honest answer for one.
|
|
221
250
|
*/
|
|
222
|
-
|| /(^|\/)(samples?|snippets?|codesnippets)(\/|$)/i.test(
|
|
251
|
+
|| /(^|\/)(samples?|snippets?|codesnippets)(\/|$)/i.test(layout)
|
|
223
252
|
/**
|
|
224
253
|
* Somebody else's code, vendored in.
|
|
225
254
|
*
|
|
@@ -228,7 +257,7 @@ function isTestOrExamplePath(file) {
|
|
|
228
257
|
* crate copied in whole. A manifest under a vendor directory is a statement about
|
|
229
258
|
* that library, not about this product.
|
|
230
259
|
*/
|
|
231
|
-
|| /(^|\/)(vendor|vendored|third[-_]?party|external[-_]crates)(\/|$)/i.test(
|
|
260
|
+
|| /(^|\/)(vendor|vendored|third[-_]?party|external[-_]crates)(\/|$)/i.test(layout);
|
|
232
261
|
}
|
|
233
262
|
/**
|
|
234
263
|
* Extensions the detectors can read.
|
|
@@ -60,7 +60,25 @@ async function detectObservability(ctx) {
|
|
|
60
60
|
const healthFiles = ctx.files.all.filter((file) => /(^|\/)(health|healthz|readyz|liveness|readiness)(\/route|\.[a-z]+)?$|(^|\/)(health|healthz|readyz)\//i.test(file));
|
|
61
61
|
for (const file of healthFiles)
|
|
62
62
|
evidence.push({ type: 'file', value: file, claim: 'health' });
|
|
63
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Spring Boot Actuator, which is the endpoint rather than a route to it.
|
|
65
|
+
*
|
|
66
|
+
* Adding `spring-boot-starter-actuator` publishes `/actuator/health` — exposed by
|
|
67
|
+
* default, with no route written anywhere — so a project that has it cannot be
|
|
68
|
+
* found by searching for a path. spring-petclinic declares it in both its pom and
|
|
69
|
+
* its build.gradle and was reported as having no health endpoint.
|
|
70
|
+
*
|
|
71
|
+
* A deliberate dependency, unlike two things this file and its neighbour decline to
|
|
72
|
+
* count: Dropwizard's admin `/healthcheck`, which every Dropwizard application has
|
|
73
|
+
* for being Dropwizard, and Django's `SecurityMiddleware`, which `startproject`
|
|
74
|
+
* writes into every new project. Actuator is in no Spring application by default.
|
|
75
|
+
*/
|
|
76
|
+
const actuator = (0, detectContext_1.hasAnyGradleDep)(ctx, ['spring-boot-starter-actuator']);
|
|
77
|
+
for (const dep of actuator)
|
|
78
|
+
evidence.push({ type: 'dependency', value: dep, claim: 'health' });
|
|
79
|
+
const hasHealth = healthFiles.length > 0
|
|
80
|
+
|| actuator.length > 0
|
|
81
|
+
|| hits.some((h) => /\/(health|healthz|readyz|livez|alive)\b/i.test(h.snippet));
|
|
64
82
|
const hasReqId = hits.some((h) => /x-request-id|correlation-id/i.test(h.snippet));
|
|
65
83
|
// Structured logging without a logging library is still structured logging. What
|
|
66
84
|
// matters is that entries are machine-readable and correlated, not which package
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@produtype/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.93.0",
|
|
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": {
|