tewip-ai 0.70.5 → 0.70.7
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.
|
@@ -62,19 +62,52 @@ ${noModelHelp()}`);
|
|
|
62
62
|
const fileName = framework.fileFor(scenario.id);
|
|
63
63
|
const file = join(framework.testDir, fileName);
|
|
64
64
|
if (existsSync(file) || (cmd.moveTo && existsSync(join(cmd.moveTo, fileName)))) {
|
|
65
|
-
|
|
65
|
+
// Every file this command writes carries "tewip" in its name, so one already sitting here is
|
|
66
|
+
// one of its own - an unverified draft from a run that did not finish, not a test the team
|
|
67
|
+
// wrote. Calling that "left untouched" sounds like a decision and hides that the file is in
|
|
68
|
+
// the test folder, where the suite is running it.
|
|
69
|
+
//
|
|
70
|
+
// Matched case-insensitively on the whole name rather than as a prefix, because only the
|
|
71
|
+
// JavaScript frameworks produce `tewip-ls-002.spec.ts`: pytest gives `test_tewip_ls_002.py`
|
|
72
|
+
// and JUnit `TewipLs002Test.java`, and a prefix check would have handed Python and Java teams
|
|
73
|
+
// the misleading message this fix exists to remove.
|
|
74
|
+
const mine = /tewip/i.test(fileName);
|
|
75
|
+
results.push({
|
|
76
|
+
id: scenario.id,
|
|
77
|
+
title: scenario.title,
|
|
78
|
+
file,
|
|
79
|
+
outcome: {
|
|
80
|
+
kind: 'rejected',
|
|
81
|
+
reason: mine
|
|
82
|
+
? `${fileName} is already here from a run that did not finish, and was never verified. It is in your test folder, so your suite is running it: delete it, or move it to .tewip/drafts/, then ask again.`
|
|
83
|
+
: `${fileName} already exists and was written by somebody else; left untouched`,
|
|
84
|
+
repairs: 0,
|
|
85
|
+
passedReliably: false,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
66
88
|
continue;
|
|
67
89
|
}
|
|
68
90
|
console.error(` ${scenario.id} ${scenario.title}`);
|
|
69
|
-
//
|
|
91
|
+
// A draft that was never verified must not stay in the project, however the run ended.
|
|
92
|
+
//
|
|
93
|
+
// SIGINT and SIGTERM were covered; nothing else was. A run of this interrupted another way -
|
|
94
|
+
// a closed pipe, an uncaught throw, a kill - left the draft in the **test folder**, where the
|
|
95
|
+
// project's own suite then runs it. Seen for real: a two-scenario run was cut short by a broken
|
|
96
|
+
// shell command, the suite went from green to red, and the next `write` reported the leftover as
|
|
97
|
+
// "already exists; left untouched", which reads like a decision rather than a casualty.
|
|
98
|
+
//
|
|
99
|
+
// `renameSync` is synchronous, so an `exit` handler can still do it: that covers every way out.
|
|
100
|
+
const rescue = () => {
|
|
101
|
+
if (!existsSync(file))
|
|
102
|
+
return;
|
|
103
|
+
mkdirSync(drafts, { recursive: true });
|
|
104
|
+
renameSync(file, join(drafts, fileName));
|
|
105
|
+
};
|
|
70
106
|
const leaveNothing = () => {
|
|
71
|
-
|
|
72
|
-
mkdirSync(drafts, { recursive: true });
|
|
73
|
-
renameSync(file, join(drafts, fileName));
|
|
74
|
-
}
|
|
107
|
+
rescue();
|
|
75
108
|
process.exit(130);
|
|
76
109
|
};
|
|
77
|
-
process.once('SIGINT', leaveNothing).once('SIGTERM', leaveNothing);
|
|
110
|
+
process.once('SIGINT', leaveNothing).once('SIGTERM', leaveNothing).once('exit', rescue);
|
|
78
111
|
let outcome;
|
|
79
112
|
try {
|
|
80
113
|
({ outcome } = await writeAndVerify(model, { framework, fileName, pages, feature: saved.feature, code, houseRules: guidanceFor(loadStandards(cmd.root), fileName) }, scenario, file, { runs: cmd.runs, repairs: cmd.repairs, mutateSource: cmd.mutateSource, log: (l) => console.error(l) }));
|
|
@@ -83,7 +116,7 @@ ${noModelHelp()}`);
|
|
|
83
116
|
outcome = { kind: 'rejected', reason: `stopped: ${error.message}`, repairs: 0, passedReliably: false };
|
|
84
117
|
}
|
|
85
118
|
finally {
|
|
86
|
-
process.off('SIGINT', leaveNothing).off('SIGTERM', leaveNothing);
|
|
119
|
+
process.off('SIGINT', leaveNothing).off('SIGTERM', leaveNothing).off('exit', rescue);
|
|
87
120
|
}
|
|
88
121
|
// Some runners take minutes per run (Angular rebuilds the app for every `ng test`): say how long
|
|
89
122
|
// the rest will take, so a slow run is not mistaken for a stuck one.
|
|
@@ -54,6 +54,35 @@ export async function runJira(cmd) {
|
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
56
|
const config = jiraFromEnv();
|
|
57
|
+
// Without a tracker, show what would be filed anyway.
|
|
58
|
+
//
|
|
59
|
+
// This file's own comment says "It shows what it would create and creates nothing until asked",
|
|
60
|
+
// and the help text says "Shows what it would create; --create actually files them" - but the
|
|
61
|
+
// refusal below ran whatever was asked, so a person who only wanted to see the list had to go and
|
|
62
|
+
// get a Jira account first. `bugs`, which does the same job for failures, has always answered this
|
|
63
|
+
// case: "No tracker was contacted: this is what would be filed."
|
|
64
|
+
//
|
|
65
|
+
// What a dry run genuinely cannot do without a server is say which scenarios are **already**
|
|
66
|
+
// filed, because that answer lives in the tracker. So it says so rather than implying the whole
|
|
67
|
+
// list is new work.
|
|
68
|
+
if (!config?.token && !cmd.create) {
|
|
69
|
+
const planned = JSON.parse(readFileSync(cmd.planFile, 'utf8'));
|
|
70
|
+
const wanted = chosen(planned.plan, cmd.only);
|
|
71
|
+
if (wanted.length === 0)
|
|
72
|
+
throw new Error(cmd.only.length ? `none of ${cmd.only.join(', ')} is in ${cmd.planFile}` : 'every scenario in the plan is already covered by a test');
|
|
73
|
+
console.log([
|
|
74
|
+
`Plan: ${planned.plan.title}`,
|
|
75
|
+
`Project: ${cmd.projectKey || '(none given)'}`,
|
|
76
|
+
'',
|
|
77
|
+
'No tracker was contacted: this is what would be filed.',
|
|
78
|
+
...wanted.map((scenario) => ` ${scenario.id} would create: ${scenario.id} ${scenario.title}`),
|
|
79
|
+
'',
|
|
80
|
+
`${wanted.length} item(s). Tewip could not check which of these you have already filed - that answer is in the tracker, not in the plan - so read the list as everything, not as new work.`,
|
|
81
|
+
'To file them, set a tracker up and add --create:',
|
|
82
|
+
jiraHelp(),
|
|
83
|
+
].join(String.fromCharCode(10)));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
57
86
|
if (!config)
|
|
58
87
|
throw new Error(jiraHelp());
|
|
59
88
|
if (!config.token)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tewip-ai",
|
|
3
|
-
"version": "0.70.
|
|
3
|
+
"version": "0.70.7",
|
|
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": [
|