tewip-ai 0.51.0 → 0.52.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.
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Which files in a project are migrations at all.
|
|
2
|
+
//
|
|
3
|
+
// Split out of schema-command.ts in Phase 44, when the corpus harness needed to ask the question
|
|
4
|
+
// across a whole checkout rather than across a diff and that file went past the 300-line rule.
|
|
5
|
+
// Keeping it in one place is the point: the alternative was a copy of these patterns in a script,
|
|
6
|
+
// and two definitions of "is this a migration" drift the moment one of them is fixed.
|
|
7
|
+
import { readdirSync, statSync } from 'node:fs';
|
|
8
|
+
import { join, relative } from 'node:path';
|
|
9
|
+
// A directory called `migration/` says what is probably in it, not what every file in it is. This
|
|
10
|
+
// matched *anything* underneath one, so Keycloak's `docs/guides/migration/index.adoc` and its 113
|
|
11
|
+
// `migration/migrators/MigrateTo12_0_0.java` classes - application code that moves data between
|
|
12
|
+
// Keycloak versions, nothing to do with a schema file - were selected as migrations and then listed
|
|
13
|
+
// as ones Tewip could not read. 205 files chosen in order to read 89. A "could not read" list that
|
|
14
|
+
// is mostly documentation teaches the reader to skip the list.
|
|
15
|
+
//
|
|
16
|
+
// So the directory decides *where*, and the extension decides *whether it could hold DDL at all*.
|
|
17
|
+
const MIGRATION_DIR = /(^|\/)(migrations?|migration|db\/migrate|prisma\/migrations|alembic|flyway|changelogs?|sql)\//i;
|
|
18
|
+
const COULD_HOLD_DDL = /\.(sql|py|rb|js|mjs|cjs|ts|php|cs|xml|ya?ml|json|go|exs?)$/i;
|
|
19
|
+
// Flyway's Java migrations are real, and they are named the way Flyway requires: `V2__add_index.java`
|
|
20
|
+
// or `R__rebuild_views.java`. Keycloak's `MigrateTo12_0_0.java` is not one. Taking `.java` on the
|
|
21
|
+
// strength of its directory alone is what filled that list with source files.
|
|
22
|
+
const FLYWAY_JAVA = /(^|\/)[VR][\w.]*__[\w.-]+\.(java|kt|scala)$/;
|
|
23
|
+
export const MIGRATION = {
|
|
24
|
+
test: (path) => MIGRATION_DIR.test(path) && (COULD_HOLD_DDL.test(path) || FLYWAY_JAVA.test(path)),
|
|
25
|
+
};
|
|
26
|
+
// A changelog is often not in a directory that says so. OpenMRS keeps 44 Liquibase changelogs in
|
|
27
|
+
// `api/src/main/resources/` named `liquibase-*.xml`, and the path filter saw none of them - so a
|
|
28
|
+
// real healthcare system with 44 migration files was told it had none. The name counts too.
|
|
29
|
+
//
|
|
30
|
+
// And a changelog is named for what it is, but hardly ever *only* that. Phase 42 taught this filter
|
|
31
|
+
// to read `liquibase-update-to-latest.xml` and it still missed Keycloak's 83, every one called
|
|
32
|
+
// `jpa-changelog-<version>.xml`: the word had to *begin* the name. Prefixes are the norm once a
|
|
33
|
+
// project has more than one database. Letting a release-notes `CHANGELOG.xml` through costs nothing,
|
|
34
|
+
// because `dialectOf` still has to find `<databaseChangeLog` in it before it is read as a migration.
|
|
35
|
+
export const NAMED_MIGRATION = /(^|\/)[\w.-]*(liquibase|changelog)[\w.-]*\.(xml|ya?ml|json)$/i;
|
|
36
|
+
export const SCHEMA_FILE = /\.(sql)$|(^|\/)(migrations?|migration|db\/migrate)\/.*\.(py|rb|js|ts|php|cs)$/i;
|
|
37
|
+
/**
|
|
38
|
+
* Every migration in a whole repository, by the same filters a diff is read through.
|
|
39
|
+
*
|
|
40
|
+
* `schemaFiles` answers "which of these changed files are migrations", which is the question a pull
|
|
41
|
+
* request asks. "What migrations does this project have at all" is a different question, and the
|
|
42
|
+
* corpus harness needs it to re-derive a verified number across a pinned checkout.
|
|
43
|
+
*/
|
|
44
|
+
export function migrationsUnder(root, limit = 20_000) {
|
|
45
|
+
const skip = new Set(['node_modules', '.git', 'dist', 'build', 'target', 'vendor', '__pycache__', '.venv', 'venv', '.next', '.cache']);
|
|
46
|
+
const found = [];
|
|
47
|
+
const walk = (where, depth) => {
|
|
48
|
+
if (depth > 12 || found.length >= limit)
|
|
49
|
+
return;
|
|
50
|
+
let entries;
|
|
51
|
+
try {
|
|
52
|
+
entries = readdirSync(where);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
if (skip.has(entry) || entry.startsWith('.'))
|
|
59
|
+
continue;
|
|
60
|
+
const full = join(where, entry);
|
|
61
|
+
let info;
|
|
62
|
+
try {
|
|
63
|
+
info = statSync(full);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (info.isDirectory()) {
|
|
69
|
+
walk(full, depth + 1);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const rel = relative(root, full).replaceAll(String.fromCharCode(92), '/');
|
|
73
|
+
if (SCHEMA_FILE.test(rel) || MIGRATION.test(rel) || NAMED_MIGRATION.test(rel))
|
|
74
|
+
found.push(rel);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
walk(root, 0);
|
|
78
|
+
return found.sort();
|
|
79
|
+
}
|
|
@@ -13,18 +13,8 @@ import { dirname, resolve } from 'node:path';
|
|
|
13
13
|
import { changeSummary } from '../quality/grounding.js';
|
|
14
14
|
import { dialectOf, forwardOnly, irreversible, readFramework } from './frameworks.js';
|
|
15
15
|
import { readSql } from './statements.js';
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// `api/src/main/resources/` named `liquibase-*.xml`, and the path filter saw none of them - so a
|
|
19
|
-
// real healthcare system with 44 migration files was told it had none. The name counts too.
|
|
20
|
-
// A changelog is named for what it is, but hardly ever *only* that. Phase 42 taught this filter to
|
|
21
|
-
// read `liquibase-update-to-latest.xml` and it still missed Keycloak's 83 files, every one of them
|
|
22
|
-
// called `jpa-changelog-<version>.xml`: the name was required to *begin* with the word. Prefixes are
|
|
23
|
-
// the norm - a project with more than one database names each changelog after its module. So the
|
|
24
|
-
// word may sit anywhere in the name. Letting a release-notes `CHANGELOG.xml` through costs nothing,
|
|
25
|
-
// because `dialectOf` still has to find `<databaseChangeLog` in it before it is read as a migration.
|
|
26
|
-
const NAMED_MIGRATION = /(^|\/)[\w.-]*(liquibase|changelog)[\w.-]*\.(xml|ya?ml|json)$/i;
|
|
27
|
-
const SCHEMA_FILE = /\.(sql)$|(^|\/)(migrations?|migration|db\/migrate)\/.*\.(py|rb|js|ts|php|cs)$/i;
|
|
16
|
+
import { MIGRATION, NAMED_MIGRATION, SCHEMA_FILE, migrationsUnder } from './migration-files.js';
|
|
17
|
+
export { migrationsUnder };
|
|
28
18
|
/** The schema files in this change. */
|
|
29
19
|
export function schemaFiles(cmd) {
|
|
30
20
|
const named = cmd.files !== undefined && cmd.files.length > 0;
|
|
@@ -30,6 +30,13 @@ const CHECKS = [
|
|
|
30
30
|
/\bpytest\s*\.\s*(raises|warns|approx|fail)\b/,
|
|
31
31
|
/\bnp\s*\.\s*testing\s*\.\s*assert/,
|
|
32
32
|
/\bassert_(frame|series|index)_equal\b/,
|
|
33
|
+
// A bare `fail(...)`, which is how JUnit, TestNG and Go spell "this must not be reached" once the
|
|
34
|
+
// assertion is statically imported. `Assert.fail(...)` was already read by the pattern below;
|
|
35
|
+
// `fail(...)` on its own was not, so OpenMRS's RefByUuidTest - whose only real check is a `fail()`
|
|
36
|
+
// in the catch, beside a deliberate `assertTrue(true)` in the try - was called a tautology that
|
|
37
|
+
// "no change to the code can falsify". Make `getRefByUuid` throw and it falsifies immediately.
|
|
38
|
+
// The leading class keeps `shouldFail(` and `canFail(` out, and the paren must come next.
|
|
39
|
+
/(^|[^\w.])(?:Assert(?:ions)?\s*\.\s*)?fail\s*\(/,
|
|
33
40
|
// Java, Kotlin, C#, Scala.
|
|
34
41
|
/\bAssert(ions)?\s*\./,
|
|
35
42
|
/\bassertThat\s*\(/,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tewip-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"mcpName": "io.github.hmamut39/tewip",
|
|
5
5
|
"description": "Tewip finds why each failing test failed - real bug, flaky test, environment, test data or changed selector - for any stack, from the command line, CI, or your editor.",
|
|
6
6
|
"keywords": [
|
|
@@ -63,7 +63,9 @@
|
|
|
63
63
|
"typecheck": "tsc --noEmit",
|
|
64
64
|
"build": "tsc -p tsconfig.build.json",
|
|
65
65
|
"prepack": "npm run build",
|
|
66
|
-
"tewip": "node cli/tewip.ts"
|
|
66
|
+
"tewip": "node cli/tewip.ts",
|
|
67
|
+
"version": "node scripts/sync-version.ts && git add server.json",
|
|
68
|
+
"corpus": "node scripts/corpus.ts"
|
|
67
69
|
},
|
|
68
70
|
"license": "Apache-2.0",
|
|
69
71
|
"devDependencies": {
|