@memberjunction/testing-cli 5.37.0 → 5.39.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.
@@ -1,24 +1,49 @@
1
1
  /**
2
- * @fileoverview Compare command implementation
2
+ * @fileoverview Compare command — compares two test suite runs to detect regressions
3
3
  * @module @memberjunction/testing-cli
4
4
  */
5
5
  import { UserInfo } from '@memberjunction/core';
6
6
  import { CompareFlags } from '../types.js';
7
7
  /**
8
- * Compare command - Compare test runs to detect regressions
9
- *
10
- * Note: This is a placeholder implementation. Full comparison requires
11
- * tracking test runs with version/commit metadata.
8
+ * Compare command — Compare two test suite runs to detect regressions
12
9
  */
13
10
  export declare class CompareCommand {
11
+ execute(runId1: string | undefined, runId2: string | undefined, flags: CompareFlags, contextUser?: UserInfo): Promise<void>;
14
12
  /**
15
- * Execute the compare command
13
+ * Resolve --from-json flag values into a {previous, current} file pair.
14
+ *
15
+ * Supports two modes:
16
+ * - Two file paths → returns them in declared order
17
+ * - One directory → finds two newest regression runs by mtime, looking for:
18
+ * (a) <dir>/run-* /results.json — per-run folder pattern (current)
19
+ * (b) <dir>/results-*.json — flat archive pattern (legacy)
20
+ * Both patterns are scanned together and sorted by mtime,
21
+ * so a directory with a mix works fine.
16
22
  *
17
- * @param runId1 - First run ID (optional)
18
- * @param runId2 - Second run ID (optional)
19
- * @param flags - Command flags
20
- * @param contextUser - Optional user context (will be fetched if not provided)
23
+ * Returns null (and prints an error) if the inputs can't be resolved.
21
24
  */
22
- execute(runId1: string | undefined, runId2: string | undefined, flags: CompareFlags, contextUser?: UserInfo): Promise<void>;
25
+ private resolveFromJsonPaths;
26
+ /**
27
+ * Compare two results.json files directly without querying the database.
28
+ * Used when the Docker regression DB is ephemeral and results are archived
29
+ * as JSON artifacts instead.
30
+ */
31
+ private executeFromJson;
32
+ /**
33
+ * Parse a results.json file into the normalized SuiteRunSummary shape.
34
+ * Expected shape matches what `mj test suite --format=json --output=...` produces.
35
+ */
36
+ private parseResultsJson;
37
+ /**
38
+ * Core comparison logic — takes two normalized suite runs and produces the
39
+ * full ComparisonResult. Shared between the DB path and the JSON path.
40
+ */
41
+ private buildComparisonResult;
42
+ /**
43
+ * Find the most recent completed suite run matching a given field/value.
44
+ * Used to resolve --version and --commit flags to concrete run IDs.
45
+ */
46
+ private findLatestSuiteRunBy;
47
+ private formatComparison;
23
48
  }
24
49
  //# sourceMappingURL=compare.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxC;;;;;GAKG;AACH,qBAAa,cAAc;IACvB;;;;;;;OAOG;IACG,OAAO,CACT,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,YAAY,EACnB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,IAAI,CAAC;CAyBnB"}
1
+ {"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAqB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAmDxC;;GAEG;AACH,qBAAa,cAAc;IACjB,OAAO,CACT,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,YAAY,EACnB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,IAAI,CAAC;IA0LhB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,oBAAoB;IAoD5B;;;;OAIG;YACW,eAAe;IA4B7B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA+CxB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAqE7B;;;OAGG;YACW,oBAAoB;IAwBlC,OAAO,CAAC,gBAAgB;CA8F3B"}
@@ -1,46 +1,481 @@
1
1
  /**
2
- * @fileoverview Compare command implementation
2
+ * @fileoverview Compare command — compares two test suite runs to detect regressions
3
3
  * @module @memberjunction/testing-cli
4
4
  */
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ import { RunView, Metadata } from '@memberjunction/core';
5
8
  import { OutputFormatter } from '../utils/output-formatter.js';
9
+ import { initializeMJProvider, closeMJProvider, getContextUser } from '../lib/mj-provider.js';
6
10
  /**
7
- * Compare command - Compare test runs to detect regressions
8
- *
9
- * Note: This is a placeholder implementation. Full comparison requires
10
- * tracking test runs with version/commit metadata.
11
+ * Compare command — Compare two test suite runs to detect regressions
11
12
  */
12
13
  export class CompareCommand {
14
+ async execute(runId1, runId2, flags, contextUser) {
15
+ // --from-json: compare two results.json files directly (no DB required).
16
+ // Designed for comparing Docker regression runs where the DB is ephemeral.
17
+ //
18
+ // Accepts either:
19
+ // - Two file paths: --from-json PREV.json --from-json CURR.json
20
+ // - One directory: --from-json <dir> (picks two newest results-*.json by mtime)
21
+ if (flags.fromJson && flags.fromJson.length > 0) {
22
+ if (flags.tag) {
23
+ console.warn(`Warning: --tag is ignored with --from-json — results.json does not currently emit the Tags field. ` +
24
+ `Use DB mode (drop --from-json) to filter by tag.`);
25
+ }
26
+ const resolved = this.resolveFromJsonPaths(flags.fromJson);
27
+ if (resolved) {
28
+ return this.executeFromJson(resolved.previous, resolved.current, flags);
29
+ }
30
+ }
31
+ try {
32
+ await initializeMJProvider();
33
+ if (!contextUser) {
34
+ contextUser = await getContextUser();
35
+ }
36
+ const rv = new RunView();
37
+ let previousRunId;
38
+ let currentRunId;
39
+ // Detect if user provided any explicit selector
40
+ const hasVersionFlag = flags.version && flags.version.length >= 2;
41
+ const hasCommitFlag = flags.commit && flags.commit.length >= 2;
42
+ const hasExplicitIds = Boolean(runId1 && runId2);
43
+ if (hasExplicitIds) {
44
+ // Explicit two-run comparison
45
+ previousRunId = runId1;
46
+ currentRunId = runId2;
47
+ }
48
+ else if (hasVersionFlag) {
49
+ // Compare by version: -v <previous> -v <current>
50
+ const [prevRun, currRun] = await Promise.all([
51
+ this.findLatestSuiteRunBy(rv, 'AgentVersion', flags.version[0], contextUser, flags.tag),
52
+ this.findLatestSuiteRunBy(rv, 'AgentVersion', flags.version[1], contextUser, flags.tag),
53
+ ]);
54
+ if (!prevRun) {
55
+ console.error(OutputFormatter.formatError(`No completed suite run found with AgentVersion='${flags.version[0]}'`));
56
+ process.exit(2);
57
+ }
58
+ if (!currRun) {
59
+ console.error(OutputFormatter.formatError(`No completed suite run found with AgentVersion='${flags.version[1]}'`));
60
+ process.exit(2);
61
+ }
62
+ previousRunId = prevRun.ID;
63
+ currentRunId = currRun.ID;
64
+ }
65
+ else if (hasCommitFlag) {
66
+ // Compare by git commit: -c <previous> -c <current>
67
+ const [prevRun, currRun] = await Promise.all([
68
+ this.findLatestSuiteRunBy(rv, 'GitCommit', flags.commit[0], contextUser, flags.tag),
69
+ this.findLatestSuiteRunBy(rv, 'GitCommit', flags.commit[1], contextUser, flags.tag),
70
+ ]);
71
+ if (!prevRun) {
72
+ console.error(OutputFormatter.formatError(`No completed suite run found with GitCommit='${flags.commit[0]}'`));
73
+ process.exit(2);
74
+ }
75
+ if (!currRun) {
76
+ console.error(OutputFormatter.formatError(`No completed suite run found with GitCommit='${flags.commit[1]}'`));
77
+ process.exit(2);
78
+ }
79
+ previousRunId = prevRun.ID;
80
+ currentRunId = currRun.ID;
81
+ }
82
+ else {
83
+ // Default behavior: compare the two most recent completed suite runs.
84
+ // Triggered by --latest OR by running `mj test compare` with no args.
85
+ // When --tag is provided, restrict to runs whose Tags JSON array
86
+ // includes the tag. Tags is stored as a JSON array string like
87
+ // `["staging-nightly","sonnet-4.6"]`, so we LIKE-match the quoted
88
+ // form to avoid false-positives where the tag is a substring of
89
+ // another tag (e.g. "prod" matching "production").
90
+ let extraFilter = "Status IN ('Completed', 'Failed')";
91
+ if (flags.tag) {
92
+ const escaped = flags.tag.replace(/'/g, "''");
93
+ extraFilter += ` AND Tags LIKE '%"${escaped}"%'`;
94
+ }
95
+ const runs = await rv.RunView({
96
+ EntityName: 'MJ: Test Suite Runs',
97
+ ExtraFilter: extraFilter,
98
+ OrderBy: 'StartedAt DESC',
99
+ MaxRows: 2,
100
+ ResultType: 'entity_object'
101
+ }, contextUser);
102
+ if (!runs.Success || runs.Results.length < 2) {
103
+ const tagSuffix = flags.tag ? ` matching tag '${flags.tag}'` : '';
104
+ console.error(OutputFormatter.formatError(`Need at least 2 completed suite runs to compare${tagSuffix} (found ${runs.Results?.length ?? 0})`));
105
+ process.exit(2);
106
+ }
107
+ currentRunId = runs.Results[0].ID;
108
+ previousRunId = runs.Results[1].ID;
109
+ }
110
+ // Load both suite runs
111
+ const md = new Metadata(); // global-provider-ok: CLI tool runs in single-user, single-connection context
112
+ const previousRun = await md.GetEntityObject('MJ: Test Suite Runs', contextUser);
113
+ const currentRun = await md.GetEntityObject('MJ: Test Suite Runs', contextUser);
114
+ const prevLoaded = await previousRun.Load(previousRunId);
115
+ const currLoaded = await currentRun.Load(currentRunId);
116
+ if (!prevLoaded) {
117
+ console.error(OutputFormatter.formatError(`Suite run not found: ${previousRunId}`));
118
+ process.exit(2);
119
+ }
120
+ if (!currLoaded) {
121
+ console.error(OutputFormatter.formatError(`Suite run not found: ${currentRunId}`));
122
+ process.exit(2);
123
+ }
124
+ // Load test runs for both suite runs
125
+ const [prevTestsResult, currTestsResult] = await Promise.all([
126
+ rv.RunView({
127
+ EntityName: 'MJ: Test Runs',
128
+ ExtraFilter: `TestSuiteRunID='${previousRunId}'`,
129
+ OrderBy: 'Sequence',
130
+ ResultType: 'entity_object'
131
+ }, contextUser),
132
+ rv.RunView({
133
+ EntityName: 'MJ: Test Runs',
134
+ ExtraFilter: `TestSuiteRunID='${currentRunId}'`,
135
+ OrderBy: 'Sequence',
136
+ ResultType: 'entity_object'
137
+ }, contextUser)
138
+ ]);
139
+ // Normalize to SuiteRunSummary shape so we can share comparison logic with --from-json path
140
+ const previousSummary = {
141
+ RunId: previousRunId,
142
+ SuiteName: previousRun.Suite,
143
+ StartedAt: previousRun.StartedAt?.toISOString().split('T')[0] ?? 'unknown',
144
+ Tests: (prevTestsResult.Success ? prevTestsResult.Results : []).map(t => ({
145
+ TestID: t.TestID,
146
+ TestName: t.Test,
147
+ Status: t.Status,
148
+ Score: t.Score,
149
+ DurationSeconds: t.DurationSeconds,
150
+ })),
151
+ };
152
+ const currentSummary = {
153
+ RunId: currentRunId,
154
+ SuiteName: currentRun.Suite,
155
+ StartedAt: currentRun.StartedAt?.toISOString().split('T')[0] ?? 'unknown',
156
+ Tests: (currTestsResult.Success ? currTestsResult.Results : []).map(t => ({
157
+ TestID: t.TestID,
158
+ TestName: t.Test,
159
+ Status: t.Status,
160
+ Score: t.Score,
161
+ DurationSeconds: t.DurationSeconds,
162
+ })),
163
+ };
164
+ const result = this.buildComparisonResult(previousSummary, currentSummary);
165
+ // Format output
166
+ const format = flags.format || 'console';
167
+ const output = this.formatComparison(result, format, flags.diffOnly);
168
+ console.log(output);
169
+ if (flags.output) {
170
+ OutputFormatter.writeToFile(output, flags.output);
171
+ }
172
+ await closeMJProvider();
173
+ // Exit codes: 0 = no regressions, 1 = regressions detected, 2 = data error
174
+ process.exit(result.Regressions > 0 ? 1 : 0);
175
+ }
176
+ catch (error) {
177
+ console.error(OutputFormatter.formatError('Failed to compare test runs', error));
178
+ try {
179
+ await closeMJProvider();
180
+ }
181
+ catch { /* ignore */ }
182
+ process.exit(2);
183
+ }
184
+ }
13
185
  /**
14
- * Execute the compare command
186
+ * Resolve --from-json flag values into a {previous, current} file pair.
15
187
  *
16
- * @param runId1 - First run ID (optional)
17
- * @param runId2 - Second run ID (optional)
18
- * @param flags - Command flags
19
- * @param contextUser - Optional user context (will be fetched if not provided)
188
+ * Supports two modes:
189
+ * - Two file paths → returns them in declared order
190
+ * - One directory → finds two newest regression runs by mtime, looking for:
191
+ * (a) <dir>/run-* /results.json — per-run folder pattern (current)
192
+ * (b) <dir>/results-*.json — flat archive pattern (legacy)
193
+ * Both patterns are scanned together and sorted by mtime,
194
+ * so a directory with a mix works fine.
195
+ *
196
+ * Returns null (and prints an error) if the inputs can't be resolved.
20
197
  */
21
- async execute(runId1, runId2, flags, contextUser) {
198
+ resolveFromJsonPaths(inputs) {
199
+ if (inputs.length >= 2) {
200
+ return { previous: inputs[0], current: inputs[1] };
201
+ }
202
+ // Single argument — must be a directory
203
+ const candidate = path.resolve(inputs[0]);
204
+ if (!fs.existsSync(candidate)) {
205
+ console.error(OutputFormatter.formatError(`Path does not exist: ${candidate}`));
206
+ process.exit(2);
207
+ }
208
+ const stats = fs.statSync(candidate);
209
+ if (!stats.isDirectory()) {
210
+ console.error(OutputFormatter.formatError(`--from-json needs either two file paths or one directory (got one file: ${candidate})`));
211
+ process.exit(2);
212
+ }
213
+ const entries = fs.readdirSync(candidate, { withFileTypes: true });
214
+ const found = [];
215
+ for (const entry of entries) {
216
+ // Per-run folder pattern: <dir>/run-*/results.json
217
+ if (entry.isDirectory() && entry.name.startsWith('run-')) {
218
+ const resultsFile = path.join(candidate, entry.name, 'results.json');
219
+ if (fs.existsSync(resultsFile)) {
220
+ found.push({ path: resultsFile, mtime: fs.statSync(resultsFile).mtimeMs });
221
+ }
222
+ }
223
+ // Flat archive pattern: <dir>/results-*.json (legacy)
224
+ else if (entry.isFile() && /^results-.*\.json$/.test(entry.name)) {
225
+ const full = path.join(candidate, entry.name);
226
+ found.push({ path: full, mtime: fs.statSync(full).mtimeMs });
227
+ }
228
+ }
229
+ found.sort((a, b) => b.mtime - a.mtime);
230
+ if (found.length < 2) {
231
+ console.error(OutputFormatter.formatError(`Need at least 2 archived regression runs in ${candidate} (found ${found.length}). ` +
232
+ `Looked for: run-*/results.json and results-*.json`));
233
+ process.exit(2);
234
+ }
235
+ // Newest is "current", second-newest is "previous"
236
+ return { previous: found[1].path, current: found[0].path };
237
+ }
238
+ /**
239
+ * Compare two results.json files directly without querying the database.
240
+ * Used when the Docker regression DB is ephemeral and results are archived
241
+ * as JSON artifacts instead.
242
+ */
243
+ async executeFromJson(previousJsonPath, currentJsonPath, flags) {
22
244
  try {
23
- console.log(OutputFormatter.formatInfo('Compare command not yet implemented'));
24
- console.log('\nPlanned features:');
25
- console.log(' - Compare two specific test runs by ID');
26
- console.log(' - Compare runs by version or git commit');
27
- console.log(' - Detect regressions in scores or pass rates');
28
- console.log(' - Show performance and cost differences');
29
- console.log(' - Filter with --diff-only to show only changes');
30
- console.log('\nRequires:');
31
- console.log(' - Test Run Results with version/commit metadata');
32
- console.log(' - Comparison algorithms for detecting regressions');
33
- // TODO: Implement full comparison
34
- // - Load two test runs from database
35
- // - Compare scores, pass/fail status, duration, cost
36
- // - Identify regressions (score decreased, new failures)
37
- // - Display side-by-side comparison
38
- // - Exit with non-zero if regressions detected
245
+ const previous = this.parseResultsJson(previousJsonPath);
246
+ const current = this.parseResultsJson(currentJsonPath);
247
+ const result = this.buildComparisonResult(previous, current);
248
+ const format = flags.format || 'console';
249
+ const output = this.formatComparison(result, format, flags.diffOnly);
250
+ console.log(output);
251
+ if (flags.output) {
252
+ OutputFormatter.writeToFile(output, flags.output);
253
+ }
254
+ // Exit codes: 0 = no regressions, 1 = regressions detected, 2 = data error
255
+ process.exit(result.Regressions > 0 ? 1 : 0);
39
256
  }
40
257
  catch (error) {
41
- console.error(OutputFormatter.formatError('Failed to compare test runs', error));
42
- process.exit(1);
258
+ console.error(OutputFormatter.formatError('Failed to compare results.json files', error));
259
+ process.exit(2);
260
+ }
261
+ }
262
+ /**
263
+ * Parse a results.json file into the normalized SuiteRunSummary shape.
264
+ * Expected shape matches what `mj test suite --format=json --output=...` produces.
265
+ */
266
+ parseResultsJson(filePath) {
267
+ const resolvedPath = path.resolve(filePath);
268
+ if (!fs.existsSync(resolvedPath)) {
269
+ throw new Error(`Results file not found: ${resolvedPath}`);
270
+ }
271
+ let raw;
272
+ try {
273
+ raw = JSON.parse(fs.readFileSync(resolvedPath, 'utf-8'));
274
+ }
275
+ catch (e) {
276
+ throw new Error(`Invalid JSON in ${resolvedPath}: ${e.message}`);
277
+ }
278
+ const data = raw;
279
+ if (!data || !Array.isArray(data.testResults)) {
280
+ throw new Error(`${resolvedPath} does not look like a suite results file (missing testResults array)`);
281
+ }
282
+ const startedAt = data.startedAt ? data.startedAt.split('T')[0] : 'unknown';
283
+ return {
284
+ RunId: data.suiteRunId ?? path.basename(resolvedPath),
285
+ SuiteName: data.suiteName ?? 'unknown',
286
+ StartedAt: startedAt,
287
+ Tests: data.testResults.map(t => ({
288
+ TestID: t.testId ?? t.testName ?? 'unknown',
289
+ TestName: t.testName ?? t.testId ?? 'unknown',
290
+ Status: t.status ?? 'Unknown',
291
+ Score: typeof t.score === 'number' ? t.score : null,
292
+ DurationSeconds: typeof t.durationMs === 'number' ? t.durationMs / 1000 : null,
293
+ })),
294
+ };
295
+ }
296
+ /**
297
+ * Core comparison logic — takes two normalized suite runs and produces the
298
+ * full ComparisonResult. Shared between the DB path and the JSON path.
299
+ */
300
+ buildComparisonResult(previous, current) {
301
+ const prevMap = new Map();
302
+ for (const t of previous.Tests)
303
+ prevMap.set(t.TestID, t);
304
+ const currMap = new Map();
305
+ for (const t of current.Tests)
306
+ currMap.set(t.TestID, t);
307
+ const allTestIds = new Set([...prevMap.keys(), ...currMap.keys()]);
308
+ const comparisons = [];
309
+ for (const testId of allTestIds) {
310
+ const prev = prevMap.get(testId);
311
+ const curr = currMap.get(testId);
312
+ const prevScore = prev?.Score ?? null;
313
+ const currScore = curr?.Score ?? null;
314
+ const prevStatus = prev?.Status ?? null;
315
+ const currStatus = curr?.Status ?? null;
316
+ const scoreDelta = (prevScore != null && currScore != null) ? currScore - prevScore : null;
317
+ let change;
318
+ if (!prev) {
319
+ change = 'new';
320
+ }
321
+ else if (!curr) {
322
+ change = 'removed';
323
+ }
324
+ else if (prevStatus === 'Passed' && currStatus !== 'Passed') {
325
+ change = 'regression';
326
+ }
327
+ else if (prevStatus !== 'Passed' && currStatus === 'Passed') {
328
+ change = 'improvement';
329
+ }
330
+ else if (scoreDelta != null && scoreDelta < -0.1) {
331
+ change = 'regression';
332
+ }
333
+ else if (scoreDelta != null && scoreDelta > 0.1) {
334
+ change = 'improvement';
335
+ }
336
+ else {
337
+ change = 'unchanged';
338
+ }
339
+ comparisons.push({
340
+ TestID: testId,
341
+ TestName: curr?.TestName ?? prev?.TestName ?? testId,
342
+ PreviousStatus: prevStatus,
343
+ CurrentStatus: currStatus,
344
+ PreviousScore: prevScore,
345
+ CurrentScore: currScore,
346
+ ScoreDelta: scoreDelta,
347
+ PreviousDurationS: prev?.DurationSeconds ?? null,
348
+ CurrentDurationS: curr?.DurationSeconds ?? null,
349
+ Change: change,
350
+ });
351
+ }
352
+ const order = { regression: 0, improvement: 1, new: 2, removed: 3, unchanged: 4 };
353
+ comparisons.sort((a, b) => order[a.Change] - order[b.Change]);
354
+ return {
355
+ PreviousRunId: previous.RunId,
356
+ CurrentRunId: current.RunId,
357
+ PreviousSuiteName: previous.SuiteName,
358
+ CurrentSuiteName: current.SuiteName,
359
+ PreviousDate: previous.StartedAt,
360
+ CurrentDate: current.StartedAt,
361
+ Regressions: comparisons.filter(c => c.Change === 'regression').length,
362
+ Improvements: comparisons.filter(c => c.Change === 'improvement').length,
363
+ Unchanged: comparisons.filter(c => c.Change === 'unchanged').length,
364
+ NewTests: comparisons.filter(c => c.Change === 'new').length,
365
+ RemovedTests: comparisons.filter(c => c.Change === 'removed').length,
366
+ Tests: comparisons,
367
+ };
368
+ }
369
+ /**
370
+ * Find the most recent completed suite run matching a given field/value.
371
+ * Used to resolve --version and --commit flags to concrete run IDs.
372
+ */
373
+ async findLatestSuiteRunBy(rv, fieldName, value, contextUser, tag) {
374
+ // Escape single quotes for SQL safety
375
+ const safeValue = value.replace(/'/g, "''");
376
+ let extraFilter = `${fieldName}='${safeValue}' AND Status IN ('Completed', 'Failed')`;
377
+ if (tag) {
378
+ const safeTag = tag.replace(/'/g, "''");
379
+ extraFilter += ` AND Tags LIKE '%"${safeTag}"%'`;
380
+ }
381
+ const result = await rv.RunView({
382
+ EntityName: 'MJ: Test Suite Runs',
383
+ ExtraFilter: extraFilter,
384
+ OrderBy: 'StartedAt DESC',
385
+ MaxRows: 1,
386
+ ResultType: 'entity_object'
387
+ }, contextUser);
388
+ return result.Success && result.Results.length > 0 ? result.Results[0] : null;
389
+ }
390
+ formatComparison(result, format, diffOnly) {
391
+ if (format === 'json') {
392
+ return JSON.stringify(diffOnly ? { ...result, Tests: result.Tests.filter(t => t.Change !== 'unchanged') } : result, null, 2);
393
+ }
394
+ const lines = [];
395
+ const tests = diffOnly ? result.Tests.filter(t => t.Change !== 'unchanged') : result.Tests;
396
+ if (format === 'markdown') {
397
+ lines.push('# Regression Comparison');
398
+ lines.push('');
399
+ lines.push(`**Previous**: ${result.PreviousSuiteName} (${result.PreviousDate}, run ${result.PreviousRunId.substring(0, 8)})`);
400
+ lines.push(`**Current**: ${result.CurrentSuiteName} (${result.CurrentDate}, run ${result.CurrentRunId.substring(0, 8)})`);
401
+ lines.push('');
402
+ lines.push('## Summary');
403
+ lines.push('');
404
+ lines.push(`- **Regressions**: ${result.Regressions}`);
405
+ lines.push(`- **Improvements**: ${result.Improvements}`);
406
+ lines.push(`- **Unchanged**: ${result.Unchanged}`);
407
+ if (result.NewTests > 0)
408
+ lines.push(`- **New tests**: ${result.NewTests}`);
409
+ if (result.RemovedTests > 0)
410
+ lines.push(`- **Removed tests**: ${result.RemovedTests}`);
411
+ lines.push('');
412
+ if (result.Regressions > 0) {
413
+ lines.push('## Regressions');
414
+ lines.push('');
415
+ lines.push('| Test | Previous | Current | Delta |');
416
+ lines.push('|------|----------|---------|-------|');
417
+ for (const t of tests.filter(t => t.Change === 'regression')) {
418
+ const prev = t.PreviousScore != null ? `${(t.PreviousScore * 100).toFixed(0)}% ${t.PreviousStatus}` : '-';
419
+ const curr = t.CurrentScore != null ? `${(t.CurrentScore * 100).toFixed(0)}% ${t.CurrentStatus}` : '-';
420
+ const delta = t.ScoreDelta != null ? `${t.ScoreDelta > 0 ? '+' : ''}${(t.ScoreDelta * 100).toFixed(0)}%` : '-';
421
+ lines.push(`| ${t.TestName} | ${prev} | ${curr} | ${delta} |`);
422
+ }
423
+ lines.push('');
424
+ }
425
+ if (result.Improvements > 0) {
426
+ lines.push('## Improvements');
427
+ lines.push('');
428
+ lines.push('| Test | Previous | Current | Delta |');
429
+ lines.push('|------|----------|---------|-------|');
430
+ for (const t of tests.filter(t => t.Change === 'improvement')) {
431
+ const prev = t.PreviousScore != null ? `${(t.PreviousScore * 100).toFixed(0)}% ${t.PreviousStatus}` : '-';
432
+ const curr = t.CurrentScore != null ? `${(t.CurrentScore * 100).toFixed(0)}% ${t.CurrentStatus}` : '-';
433
+ const delta = t.ScoreDelta != null ? `+${(t.ScoreDelta * 100).toFixed(0)}%` : '-';
434
+ lines.push(`| ${t.TestName} | ${prev} | ${curr} | ${delta} |`);
435
+ }
436
+ lines.push('');
437
+ }
438
+ if (!diffOnly) {
439
+ lines.push('## All Tests');
440
+ lines.push('');
441
+ lines.push('| Test | Previous | Current | Delta | Change |');
442
+ lines.push('|------|----------|---------|-------|--------|');
443
+ for (const t of tests) {
444
+ const prev = t.PreviousScore != null ? `${(t.PreviousScore * 100).toFixed(0)}%` : '-';
445
+ const curr = t.CurrentScore != null ? `${(t.CurrentScore * 100).toFixed(0)}%` : '-';
446
+ const delta = t.ScoreDelta != null ? `${t.ScoreDelta > 0 ? '+' : ''}${(t.ScoreDelta * 100).toFixed(0)}%` : '-';
447
+ lines.push(`| ${t.TestName} | ${prev} | ${curr} | ${delta} | ${t.Change} |`);
448
+ }
449
+ lines.push('');
450
+ }
451
+ lines.push('---');
452
+ lines.push('*Generated by MJ Regression Test Runner*');
453
+ }
454
+ else {
455
+ // Console format
456
+ const hasRegressions = result.Regressions > 0;
457
+ lines.push('');
458
+ lines.push(` Regression Comparison`);
459
+ lines.push(` ─────────────────────────────────────────`);
460
+ lines.push(` Previous: ${result.PreviousDate} (${result.PreviousRunId.substring(0, 8)})`);
461
+ lines.push(` Current: ${result.CurrentDate} (${result.CurrentRunId.substring(0, 8)})`);
462
+ lines.push('');
463
+ lines.push(` Regressions: ${result.Regressions}${hasRegressions ? ' ⚠️' : ''}`);
464
+ lines.push(` Improvements: ${result.Improvements}`);
465
+ lines.push(` Unchanged: ${result.Unchanged}`);
466
+ lines.push('');
467
+ for (const t of tests) {
468
+ if (diffOnly && t.Change === 'unchanged')
469
+ continue;
470
+ const icon = t.Change === 'regression' ? '▼' : t.Change === 'improvement' ? '▲' : t.Change === 'new' ? '+' : t.Change === 'removed' ? '-' : ' ';
471
+ const prev = t.PreviousScore != null ? `${(t.PreviousScore * 100).toFixed(0)}%` : ' -';
472
+ const curr = t.CurrentScore != null ? `${(t.CurrentScore * 100).toFixed(0)}%` : ' -';
473
+ const delta = t.ScoreDelta != null ? `${t.ScoreDelta > 0 ? '+' : ''}${(t.ScoreDelta * 100).toFixed(0)}%` : ' -';
474
+ lines.push(` ${icon} ${t.TestName.padEnd(45)} ${prev.padStart(4)} → ${curr.padStart(4)} (${delta.padStart(5)}) ${t.Change}`);
475
+ }
476
+ lines.push('');
43
477
  }
478
+ return lines.join('\n');
44
479
  }
45
480
  }
46
481
  //# sourceMappingURL=compare.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IACvB;;;;;;;OAOG;IACH,KAAK,CAAC,OAAO,CACT,MAA0B,EAC1B,MAA0B,EAC1B,KAAmB,EACnB,WAAsB;QAEtB,IAAI,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,UAAU,CAAC,qCAAqC,CAAC,CAAC,CAAC;YAC/E,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;YAEnE,kCAAkC;YAClC,qCAAqC;YACrC,qDAAqD;YACrD,yDAAyD;YACzD,oCAAoC;YACpC,+CAA+C;QAEnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,WAAW,CAAC,6BAA6B,EAAE,KAAc,CAAC,CAAC,CAAC;YAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACL,CAAC;CACJ"}
1
+ {"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"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"}
@@ -17,5 +17,10 @@ export declare class RunCommand {
17
17
  * @param contextUser - Optional user context (will be fetched if not provided)
18
18
  */
19
19
  execute(testId: string | undefined, flags: RunFlags, contextUser?: UserInfo): Promise<void>;
20
+ /**
21
+ * Validate that a test is ready to execute without actually running it.
22
+ * Catches misconfigured oracles, malformed JSON, and missing drivers.
23
+ */
24
+ private dryRunValidation;
20
25
  }
21
26
  //# sourceMappingURL=run.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAOpC;;GAEG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,OAAO,CAAwB;IAEvC;;;;;;OAMG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAmIpG"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAQpC;;GAEG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,OAAO,CAAwB;IAEvC;;;;;;OAMG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA8KjG;;;OAGG;IACH,OAAO,CAAC,gBAAgB;CA2F3B"}