Skip to content

Commit 09a7c3f

Browse files
committed
fix: truing up some bad regex
1 parent da5b5b3 commit 09a7c3f

File tree

2 files changed

+74
-99
lines changed

2 files changed

+74
-99
lines changed

src/utils/datacodeBinaryExecutor.ts

Lines changed: 7 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,10 @@ export class DatacodeBinaryExecutor {
9595
timeout: 30_000,
9696
});
9797

98-
// Parse created files from output if available
99-
const filesCreated: string[] = [];
100-
const filePattern = /Created (?:file|directory): (.+)/g;
101-
let match;
102-
while ((match = filePattern.exec(stdout)) !== null) {
103-
filesCreated.push(match[1]);
104-
}
98+
// Parse the template directory from init output
99+
// Python CLI outputs: "Copying template to <dir>"
100+
const copyMatch = /Copying template to (.+)/.exec(stdout);
101+
const filesCreated = copyMatch ? [copyMatch[1].trim()] : undefined;
105102

106103
return {
107104
stdout: stdout.trim(),
@@ -159,26 +156,11 @@ export class DatacodeBinaryExecutor {
159156
timeout: 60_000,
160157
});
161158

162-
// Parse scan results from output
163-
const permissions: string[] = [];
164-
const requirements: string[] = [];
159+
// Parse scanned files from output
160+
// Python CLI outputs: "Scanning <file>..."
165161
const filesScanned: string[] = [];
166-
167-
// Parse permissions (expected format: "Permission required: <permission>")
168-
const permissionPattern = /Permission required: (.+)/g;
162+
const filePattern = /Scanning (.+)\.\.\./g;
169163
let match;
170-
while ((match = permissionPattern.exec(stdout)) !== null) {
171-
permissions.push(match[1].trim());
172-
}
173-
174-
// Parse requirements (expected format: "Dependency found: <requirement>")
175-
const requirementPattern = /Dependency found: (.+)/g;
176-
while ((match = requirementPattern.exec(stdout)) !== null) {
177-
requirements.push(match[1].trim());
178-
}
179-
180-
// Parse scanned files (expected format: "Scanned: <file>")
181-
const filePattern = /Scanned: (.+)/g;
182164
while ((match = filePattern.exec(stdout)) !== null) {
183165
filesScanned.push(match[1].trim());
184166
}
@@ -187,8 +169,6 @@ export class DatacodeBinaryExecutor {
187169
stdout: stdout.trim(),
188170
stderr: stderr.trim(),
189171
workingDirectory: workingDir,
190-
permissions: permissions.length > 0 ? permissions : undefined,
191-
requirements: requirements.length > 0 ? requirements : undefined,
192172
filesScanned: filesScanned.length > 0 ? filesScanned : undefined,
193173
};
194174
} catch (error) {
@@ -224,36 +204,9 @@ export class DatacodeBinaryExecutor {
224204
timeout: 120_000,
225205
});
226206

227-
// Parse archive path from output
228-
let archivePath: string | undefined;
229-
const archivePathPattern = /Archive created: (.+\.zip)/i;
230-
const archiveMatch = archivePathPattern.exec(stdout);
231-
if (archiveMatch) {
232-
archivePath = archiveMatch[1].trim();
233-
}
234-
235-
// Parse file count from output
236-
let fileCount: number | undefined;
237-
const fileCountPattern = /(\d+) files? (?:added|included|archived)/i;
238-
const countMatch = fileCountPattern.exec(stdout);
239-
if (countMatch) {
240-
fileCount = parseInt(countMatch[1], 10);
241-
}
242-
243-
// Parse archive size from output
244-
let archiveSize: string | undefined;
245-
const sizePattern = /Archive size: (.+)/i;
246-
const sizeMatch = sizePattern.exec(stdout);
247-
if (sizeMatch) {
248-
archiveSize = sizeMatch[1].trim();
249-
}
250-
251207
return {
252208
stdout: stdout.trim(),
253209
stderr: stderr.trim(),
254-
archivePath,
255-
fileCount,
256-
archiveSize,
257210
};
258211
} catch (error) {
259212
const spawnError = error as SpawnError;
@@ -368,36 +321,9 @@ export class DatacodeBinaryExecutor {
368321
return;
369322
}
370323

371-
// Parse deployment ID from output
372-
let deploymentId: string | undefined;
373-
const deploymentIdPattern = /Deployment ID: (.+)/i;
374-
const deploymentMatch = deploymentIdPattern.exec(stdoutTrimmed);
375-
if (deploymentMatch) {
376-
deploymentId = deploymentMatch[1].trim();
377-
}
378-
379-
// Parse endpoint URL from output
380-
let endpointUrl: string | undefined;
381-
const endpointUrlPattern = /Endpoint URL: (.+)/i;
382-
const endpointMatch = endpointUrlPattern.exec(stdoutTrimmed);
383-
if (endpointMatch) {
384-
endpointUrl = endpointMatch[1].trim();
385-
}
386-
387-
// Parse deployment status from output
388-
let status: string | undefined;
389-
const statusPattern = /Status: (.+)/i;
390-
const statusMatch = statusPattern.exec(stdoutTrimmed);
391-
if (statusMatch) {
392-
status = statusMatch[1].trim();
393-
}
394-
395324
resolve({
396325
stdout: stdoutTrimmed,
397326
stderr: stderrTrimmed,
398-
deploymentId,
399-
endpointUrl,
400-
status,
401327
});
402328
});
403329

@@ -446,27 +372,9 @@ export class DatacodeBinaryExecutor {
446372
timeout: 300_000,
447373
});
448374

449-
// Parse status from output
450-
let status: string | undefined;
451-
const statusPattern = /Status: (.+)/i;
452-
const statusMatch = statusPattern.exec(stdout);
453-
if (statusMatch) {
454-
status = statusMatch[1].trim();
455-
}
456-
457-
// Parse run output from output
458-
let output: string | undefined;
459-
const outputPattern = /Output: (.+)/i;
460-
const outputMatch = outputPattern.exec(stdout);
461-
if (outputMatch) {
462-
output = outputMatch[1].trim();
463-
}
464-
465375
return {
466376
stdout: stdout.trim(),
467377
stderr: stderr.trim(),
468-
status,
469-
output,
470378
};
471379
} catch (error) {
472380
const spawnError = error as SpawnError;

test/utils/datacodeBinaryExecutor.test.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,73 @@ import { DatacodeBinaryExecutor } from '../../src/utils/datacodeBinaryExecutor.j
2121

2222
const execAsync = promisify(exec);
2323

24+
// ── Regex unit tests (no subprocess) ─────────────────────────────────────────
25+
// These tests verify that the stdout parsing patterns match the actual Python CLI
26+
// output format. They run purely in-process and do not require the binary.
27+
28+
describe('DatacodeBinaryExecutor stdout parsing patterns', () => {
29+
describe('init: /Copying template to (.+)/', () => {
30+
const pattern = /Copying template to (.+)/;
31+
32+
it('extracts directory from actual Python CLI output', () => {
33+
const stdout =
34+
'Copying template to /home/user/my-package\nStart developing by updating the code in /home/user/my-package/payload/entrypoint.py';
35+
const match = pattern.exec(stdout);
36+
expect(match).to.not.be.null;
37+
expect(match![1].trim()).to.equal('/home/user/my-package');
38+
});
39+
40+
it('returns null when output does not contain expected line', () => {
41+
const stdout = 'Created file: /some/file.py';
42+
const match = pattern.exec(stdout);
43+
expect(match).to.be.null;
44+
});
45+
46+
it('trims trailing whitespace from captured path', () => {
47+
const stdout = 'Copying template to /some/dir ';
48+
const match = pattern.exec(stdout);
49+
expect(match![1].trim()).to.equal('/some/dir');
50+
});
51+
});
52+
53+
describe('scan: /Scanning (.+)\\.\\.\\./ (global)', () => {
54+
const pattern = /Scanning (.+)\.\.\./g;
55+
56+
it('extracts the entrypoint file being scanned', () => {
57+
const stdout =
58+
'Dumping scan results to config file: ./payload/config.json\nScanning payload/entrypoint.py...\n{"sdkVersion":"1.0.0"}';
59+
const filesScanned: string[] = [];
60+
let match;
61+
while ((match = pattern.exec(stdout)) !== null) {
62+
filesScanned.push(match[1].trim());
63+
}
64+
expect(filesScanned).to.deep.equal(['payload/entrypoint.py']);
65+
});
66+
67+
it('collects multiple scanned files when present', () => {
68+
const stdout = 'Scanning a.py...\nScanning b.py...';
69+
const filesScanned: string[] = [];
70+
let match;
71+
while ((match = pattern.exec(stdout)) !== null) {
72+
filesScanned.push(match[1].trim());
73+
}
74+
expect(filesScanned).to.deep.equal(['a.py', 'b.py']);
75+
});
76+
77+
it('returns empty array when no scanning lines present', () => {
78+
const stdout = 'Permission required: READ_DATA\nDependency found: pandas';
79+
const filesScanned: string[] = [];
80+
let match;
81+
while ((match = pattern.exec(stdout)) !== null) {
82+
filesScanned.push(match[1].trim());
83+
}
84+
expect(filesScanned).to.be.empty;
85+
});
86+
});
87+
});
88+
89+
// ── Integration tests (require datacustomcode binary) ────────────────────────
90+
2491
describe('DatacodeBinaryExecutor', () => {
2592
const $$ = new TestContext();
2693

0 commit comments

Comments
 (0)