diff --git a/src/utils/datacodeBinaryExecutor.ts b/src/utils/datacodeBinaryExecutor.ts
index 1774153..4c38b0e 100644
--- a/src/utils/datacodeBinaryExecutor.ts
+++ b/src/utils/datacodeBinaryExecutor.ts
@@ -95,13 +95,10 @@ export class DatacodeBinaryExecutor {
timeout: 30_000,
});
- // Parse created files from output if available
- const filesCreated: string[] = [];
- const filePattern = /Created (?:file|directory): (.+)/g;
- let match;
- while ((match = filePattern.exec(stdout)) !== null) {
- filesCreated.push(match[1]);
- }
+ // Parse the template directory from init output
+ // Python CLI outputs: "Copying template to
"
+ const copyMatch = /Copying template to (.+)/.exec(stdout);
+ const filesCreated = copyMatch ? [copyMatch[1].trim()] : undefined;
return {
stdout: stdout.trim(),
@@ -159,26 +156,11 @@ export class DatacodeBinaryExecutor {
timeout: 60_000,
});
- // Parse scan results from output
- const permissions: string[] = [];
- const requirements: string[] = [];
+ // Parse scanned files from output
+ // Python CLI outputs: "Scanning ..."
const filesScanned: string[] = [];
-
- // Parse permissions (expected format: "Permission required: ")
- const permissionPattern = /Permission required: (.+)/g;
+ const filePattern = /Scanning (.+)\.\.\./g;
let match;
- while ((match = permissionPattern.exec(stdout)) !== null) {
- permissions.push(match[1].trim());
- }
-
- // Parse requirements (expected format: "Dependency found: ")
- const requirementPattern = /Dependency found: (.+)/g;
- while ((match = requirementPattern.exec(stdout)) !== null) {
- requirements.push(match[1].trim());
- }
-
- // Parse scanned files (expected format: "Scanned: ")
- const filePattern = /Scanned: (.+)/g;
while ((match = filePattern.exec(stdout)) !== null) {
filesScanned.push(match[1].trim());
}
@@ -187,8 +169,6 @@ export class DatacodeBinaryExecutor {
stdout: stdout.trim(),
stderr: stderr.trim(),
workingDirectory: workingDir,
- permissions: permissions.length > 0 ? permissions : undefined,
- requirements: requirements.length > 0 ? requirements : undefined,
filesScanned: filesScanned.length > 0 ? filesScanned : undefined,
};
} catch (error) {
@@ -224,36 +204,9 @@ export class DatacodeBinaryExecutor {
timeout: 120_000,
});
- // Parse archive path from output
- let archivePath: string | undefined;
- const archivePathPattern = /Archive created: (.+\.zip)/i;
- const archiveMatch = archivePathPattern.exec(stdout);
- if (archiveMatch) {
- archivePath = archiveMatch[1].trim();
- }
-
- // Parse file count from output
- let fileCount: number | undefined;
- const fileCountPattern = /(\d+) files? (?:added|included|archived)/i;
- const countMatch = fileCountPattern.exec(stdout);
- if (countMatch) {
- fileCount = parseInt(countMatch[1], 10);
- }
-
- // Parse archive size from output
- let archiveSize: string | undefined;
- const sizePattern = /Archive size: (.+)/i;
- const sizeMatch = sizePattern.exec(stdout);
- if (sizeMatch) {
- archiveSize = sizeMatch[1].trim();
- }
-
return {
stdout: stdout.trim(),
stderr: stderr.trim(),
- archivePath,
- fileCount,
- archiveSize,
};
} catch (error) {
const spawnError = error as SpawnError;
@@ -368,36 +321,9 @@ export class DatacodeBinaryExecutor {
return;
}
- // Parse deployment ID from output
- let deploymentId: string | undefined;
- const deploymentIdPattern = /Deployment ID: (.+)/i;
- const deploymentMatch = deploymentIdPattern.exec(stdoutTrimmed);
- if (deploymentMatch) {
- deploymentId = deploymentMatch[1].trim();
- }
-
- // Parse endpoint URL from output
- let endpointUrl: string | undefined;
- const endpointUrlPattern = /Endpoint URL: (.+)/i;
- const endpointMatch = endpointUrlPattern.exec(stdoutTrimmed);
- if (endpointMatch) {
- endpointUrl = endpointMatch[1].trim();
- }
-
- // Parse deployment status from output
- let status: string | undefined;
- const statusPattern = /Status: (.+)/i;
- const statusMatch = statusPattern.exec(stdoutTrimmed);
- if (statusMatch) {
- status = statusMatch[1].trim();
- }
-
resolve({
stdout: stdoutTrimmed,
stderr: stderrTrimmed,
- deploymentId,
- endpointUrl,
- status,
});
});
@@ -446,27 +372,9 @@ export class DatacodeBinaryExecutor {
timeout: 300_000,
});
- // Parse status from output
- let status: string | undefined;
- const statusPattern = /Status: (.+)/i;
- const statusMatch = statusPattern.exec(stdout);
- if (statusMatch) {
- status = statusMatch[1].trim();
- }
-
- // Parse run output from output
- let output: string | undefined;
- const outputPattern = /Output: (.+)/i;
- const outputMatch = outputPattern.exec(stdout);
- if (outputMatch) {
- output = outputMatch[1].trim();
- }
-
return {
stdout: stdout.trim(),
stderr: stderr.trim(),
- status,
- output,
};
} catch (error) {
const spawnError = error as SpawnError;
diff --git a/test/utils/datacodeBinaryExecutor.test.ts b/test/utils/datacodeBinaryExecutor.test.ts
index 4844c4e..45c5f3a 100644
--- a/test/utils/datacodeBinaryExecutor.test.ts
+++ b/test/utils/datacodeBinaryExecutor.test.ts
@@ -21,6 +21,73 @@ import { DatacodeBinaryExecutor } from '../../src/utils/datacodeBinaryExecutor.j
const execAsync = promisify(exec);
+// ── Regex unit tests (no subprocess) ─────────────────────────────────────────
+// These tests verify that the stdout parsing patterns match the actual Python CLI
+// output format. They run purely in-process and do not require the binary.
+
+describe('DatacodeBinaryExecutor stdout parsing patterns', () => {
+ describe('init: /Copying template to (.+)/', () => {
+ const pattern = /Copying template to (.+)/;
+
+ it('extracts directory from actual Python CLI output', () => {
+ const stdout =
+ 'Copying template to /home/user/my-package\nStart developing by updating the code in /home/user/my-package/payload/entrypoint.py';
+ const match = pattern.exec(stdout);
+ expect(match).to.not.be.null;
+ expect(match![1].trim()).to.equal('/home/user/my-package');
+ });
+
+ it('returns null when output does not contain expected line', () => {
+ const stdout = 'Created file: /some/file.py';
+ const match = pattern.exec(stdout);
+ expect(match).to.be.null;
+ });
+
+ it('trims trailing whitespace from captured path', () => {
+ const stdout = 'Copying template to /some/dir ';
+ const match = pattern.exec(stdout);
+ expect(match![1].trim()).to.equal('/some/dir');
+ });
+ });
+
+ describe('scan: /Scanning (.+)\\.\\.\\./ (global)', () => {
+ const pattern = /Scanning (.+)\.\.\./g;
+
+ it('extracts the entrypoint file being scanned', () => {
+ const stdout =
+ 'Dumping scan results to config file: ./payload/config.json\nScanning payload/entrypoint.py...\n{"sdkVersion":"1.0.0"}';
+ const filesScanned: string[] = [];
+ let match;
+ while ((match = pattern.exec(stdout)) !== null) {
+ filesScanned.push(match[1].trim());
+ }
+ expect(filesScanned).to.deep.equal(['payload/entrypoint.py']);
+ });
+
+ it('collects multiple scanned files when present', () => {
+ const stdout = 'Scanning a.py...\nScanning b.py...';
+ const filesScanned: string[] = [];
+ let match;
+ while ((match = pattern.exec(stdout)) !== null) {
+ filesScanned.push(match[1].trim());
+ }
+ expect(filesScanned).to.deep.equal(['a.py', 'b.py']);
+ });
+
+ it('returns empty array when no scanning lines present', () => {
+ const stdout = 'Permission required: READ_DATA\nDependency found: pandas';
+ const filesScanned: string[] = [];
+ let match;
+ while ((match = pattern.exec(stdout)) !== null) {
+ filesScanned.push(match[1].trim());
+ }
+ expect(filesScanned).to.be.empty;
+ });
+ });
+});
+
+// ── Integration tests (require datacustomcode binary) ────────────────────────
+
describe('DatacodeBinaryExecutor', () => {
const $$ = new TestContext();