From 7b629e022675961a22e6b3d898e937f383e88418 Mon Sep 17 00:00:00 2001 From: nully0x <40327060+nully0x@users.noreply.github.com> Date: Fri, 29 Nov 2024 08:08:26 +0100 Subject: [PATCH] chore: implement rust support (#12) * chore: implement rust support * chore: remove commented code --- src/utils/dockerUtils.ts | 16 ++-- src/utils/runner.ts | 80 ++++++++------------ src/utils/testRepoManager.ts | 2 +- supportedLanguageDockerfiles/rust/Dockerfile | 6 +- 4 files changed, 41 insertions(+), 63 deletions(-) diff --git a/src/utils/dockerUtils.ts b/src/utils/dockerUtils.ts index c2f6787..de20f4a 100644 --- a/src/utils/dockerUtils.ts +++ b/src/utils/dockerUtils.ts @@ -22,20 +22,20 @@ export async function buildDockerImage( export async function runInDocker( imageName: string, command: string, -): Promise { +): Promise<{ stdout: string; stderr: string; exitCode: number }> { const containerName = `container-${Date.now()}-${Math.random().toString(36).substring(7)}`; try { const { stdout, stderr } = await execAsync( `docker run --name ${containerName} --rm ${imageName} ${command}`, ); - return stdout + stderr; + return { stdout, stderr, exitCode: 0 }; } catch (error: any) { - // For test failures, we want to capture the output rather than treat it as an error - if (error.stdout || error.stderr) { - return error.stdout + error.stderr; - } - // For actual Docker errors, return an error message - return `Docker execution error: ${error.message}`; + // For test or compilation failures, return the output and error code + return { + stdout: error.stdout || "", + stderr: error.stderr || "", + exitCode: error.code || 1, + }; } finally { // Ensure the container is removed even if there's an error await removeContainer(containerName).catch(console.error); diff --git a/src/utils/runner.ts b/src/utils/runner.ts index b3418ed..b9376ab 100644 --- a/src/utils/runner.ts +++ b/src/utils/runner.ts @@ -60,21 +60,31 @@ export async function runTestProcess(request: TestRunRequest): Promise { progress.progress_details.current_step, ); - const appDir = path.join(repoDir, "app"); - await fs.mkdir(appDir, { recursive: true }); - - const testFileName = `stage${progress.progress_details.current_step}${TestRepoManager.getTestExtension(language)}`; - await fs.writeFile(path.join(appDir, testFileName), testContent); - logger.info("Test file written", { testFileName }); + if (language === "rust") { + const testsDir = path.join(repoDir, "tests"); + await fs.mkdir(testsDir, { recursive: true }); + const testFileName = `stage${progress.progress_details.current_step}${TestRepoManager.getTestExtension(language)}`; + await fs.writeFile(path.join(testsDir, testFileName), testContent); + } else { + const appDir = path.join(repoDir, "app"); + await fs.mkdir(appDir, { recursive: true }); + const testFileName = `stage${progress.progress_details.current_step}${TestRepoManager.getTestExtension(language)}`; + await fs.writeFile(path.join(appDir, testFileName), testContent); + } // Create run.sh with modified commands const runScript = `#!/bin/bash set -e # Exit on any error - # Run the tests based on the language if [ -f "requirements.txt" ]; then # For Python projects pytest ./app/stage${progress.progress_details.current_step}${TestRepoManager.getTestExtension(language)} -v + elif [ -f "Cargo.toml" ]; then + # For Rust projects + # Build first (quietly) + cargo build > /dev/null 2>&1 + # Run tests and show only test output + cargo test --test stage${progress.progress_details.current_step}_test else # For TypeScript projects bun test ./app/stage${progress.progress_details.current_step}${TestRepoManager.getTestExtension(language)} @@ -94,23 +104,28 @@ export async function runTestProcess(request: TestRunRequest): Promise { stage: progress.progress_details.current_step, }); - const testOutput = await runInDocker(imageName, languageConfig.runCommand); + const testResult = await runInDocker(imageName, languageConfig.runCommand); logger.info("Test execution completed", { commitSha }); - logger.info("Test output:", { testOutput }); + logger.info("Test output:", { + stdout: testResult.stdout, + stderr: testResult.stderr, + exitCode: testResult.exitCode, + }); - // Clean and parse the test output - const cleanedOutput = cleanTestOutput(testOutput); - const success = isTestSuccessful(testOutput); + // Success is now determined by exit code(using this to avoid having to parse stdout/stderr for success/failure) + const success = testResult.exitCode === 0; + const output = success + ? testResult.stdout + : `${testResult.stderr}\n${testResult.stdout}`; - const testResult: TestResult = { + const result: TestResult = { event_type: EVENT_TYPE, repoUrl, commitSha, success, - output: cleanedOutput, + output: output.trim(), }; - - await reportResults(commitSha, testResult); + await reportResults(commitSha, result); } catch (error: any) { logger.error("Error during test process", { error, commitSha }); const errorMessage = @@ -134,36 +149,3 @@ export async function runTestProcess(request: TestRunRequest): Promise { } } } - -function isTestSuccessful(output: string): boolean { - if (output.includes("pytest")) { - // For Python tests - check for failures and errors - const hasFailed = - output.includes(" FAILED ") || - output.includes("= FAILURES =") || - output.includes(" ERROR ") || - output.includes("!!!!!!!!!!!!!!!!!!!! Interrupted:"); - return !hasFailed; - } else { - // For TypeScript tests (unchanged) - const failMatch = output.match(/(\d+)\s+fail/); - const failCount = failMatch ? parseInt(failMatch[1]) : 0; - return failCount === 0; - } -} - -function cleanTestOutput(output: string): string { - if (output.includes("pytest")) { - // For Python tests, return the complete test output - return output.trim(); - } else { - // Handle TypeScript test output (unchanged) - const testRunMatch = output.match( - /app\/stage\d+\.test\.ts:[\s\S]+?Ran \d+ tests across \d+ files\./, - ); - if (testRunMatch) { - return testRunMatch[0].trim(); - } - } - return output.trim(); -} diff --git a/src/utils/testRepoManager.ts b/src/utils/testRepoManager.ts index 5a93d45..e3d535f 100644 --- a/src/utils/testRepoManager.ts +++ b/src/utils/testRepoManager.ts @@ -49,7 +49,7 @@ export class TestRepoManager { public static getTestExtension(language: string): string { const extensions: Record = { typescript: ".test.ts", - rust: ".test.rs", + rust: "_test.rs", python: "_test.py", // Add more languages as needed }; diff --git a/supportedLanguageDockerfiles/rust/Dockerfile b/supportedLanguageDockerfiles/rust/Dockerfile index 71fca9f..9dc4168 100644 --- a/supportedLanguageDockerfiles/rust/Dockerfile +++ b/supportedLanguageDockerfiles/rust/Dockerfile @@ -5,11 +5,7 @@ WORKDIR /app # Copy the entire application COPY . . -# Build dependencies to cache them -RUN cargo build --release - # Make the run.sh script executable RUN chmod +x /app/.hxckr/run.sh -# Make the run.sh script executable -ENTRYPOINT ["/bin/bash"] +CMD ["/bin/bash"]