diff --git a/.vscode/launch.json b/.vscode/launch.json
index 8880465..4e94752 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -18,4 +18,4 @@
"preLaunchTask": "${defaultBuildTask}"
}
]
-}
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 2a8dbd1..2b49ae0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "keployio",
- "version": "1.0.7",
+ "version": "1.0.6",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "keployio",
- "version": "1.0.7",
+ "version": "1.0.6",
"dependencies": {
"@sentry/node": "^8.28.0",
"acorn-walk": "^8.3.3",
@@ -14,6 +14,11 @@
"js-yaml": "^4.1.0",
"sinon": "^17.0.1",
"svelte": "^4.2.12",
+ "tree-sitter": "^0.21.1",
+ "tree-sitter-go": "^0.23.0",
+ "tree-sitter-java": "^0.21.0",
+ "tree-sitter-javascript": "^0.21.4",
+ "tree-sitter-python": "^0.21.0",
"uuid": "^10.0.0",
"walk": "^2.3.15",
"yaml": "^2.4.2"
@@ -3571,6 +3576,26 @@
"path-to-regexp": "^6.2.1"
}
},
+ "node_modules/node-addon-api": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.1.0.tgz",
+ "integrity": "sha512-yBY+qqWSv3dWKGODD6OGE6GnTX7Q2r+4+DfpqxHSHh8x0B4EKP9+wVGLS6U/AM1vxSNNmUEuIV5EGhYwPpfOwQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "^18 || ^20 || >= 21"
+ }
+ },
+ "node_modules/node-gyp-build": {
+ "version": "4.8.1",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
+ "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
+ "license": "MIT",
+ "bin": {
+ "node-gyp-build": "bin.js",
+ "node-gyp-build-optional": "optional.js",
+ "node-gyp-build-test": "build-test.js"
+ }
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -4804,6 +4829,98 @@
"tree-kill": "cli.js"
}
},
+ "node_modules/tree-sitter": {
+ "version": "0.21.1",
+ "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz",
+ "integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "node-addon-api": "^8.0.0",
+ "node-gyp-build": "^4.8.0"
+ }
+ },
+ "node_modules/tree-sitter-go": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/tree-sitter-go/-/tree-sitter-go-0.23.0.tgz",
+ "integrity": "sha512-6wycuKQCTRz/8OTlBL7xvUZP9aeznxKbWh5xYD1u0WXTCAwQM/xUQr92SKwcZexn9IIMczbzfjGgm6e5iFvSBA==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "node-addon-api": "^8.1.0",
+ "node-gyp-build": "^4.8.1"
+ },
+ "peerDependencies": {
+ "tree-sitter": "^0.21.0"
+ },
+ "peerDependenciesMeta": {
+ "tree_sitter": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tree-sitter-java": {
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/tree-sitter-java/-/tree-sitter-java-0.21.0.tgz",
+ "integrity": "sha512-CKJiTo1uc3SUsgEcaZgufGx8my6dzihy8JR/JsJH40Tj3uSe2/eFLk+0q+fpbosGAyY4YiXJtEoFB2O4bS2yOw==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "node-addon-api": "^8.0.0",
+ "node-gyp-build": "^4.8.0"
+ },
+ "peerDependencies": {
+ "tree-sitter": "^0.21.0"
+ },
+ "peerDependenciesMeta": {
+ "tree_sitter": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tree-sitter-javascript": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.21.4.tgz",
+ "integrity": "sha512-Lrk8yahebwrwc1sWJE9xPcz1OnnqiEV7Dh5fbN6EN3wNAdu9r06HpTqLqDwUUbnG4EB46Sfk+FJFAOldfoKLOw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "node-addon-api": "^8.0.0",
+ "node-gyp-build": "^4.8.1"
+ },
+ "peerDependencies": {
+ "tree-sitter": "^0.21.1"
+ },
+ "peerDependenciesMeta": {
+ "tree_sitter": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tree-sitter-python": {
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/tree-sitter-python/-/tree-sitter-python-0.21.0.tgz",
+ "integrity": "sha512-IUKx7JcTVbByUx1iHGFS/QsIjx7pqwTMHL9bl/NGyhyyydbfNrpruo2C7W6V4KZrbkkCOlX8QVrCoGOFW5qecg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "node-addon-api": "^7.1.0",
+ "node-gyp-build": "^4.8.0"
+ },
+ "peerDependencies": {
+ "tree-sitter": "^0.21.0"
+ },
+ "peerDependenciesMeta": {
+ "tree_sitter": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tree-sitter-python/node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "license": "MIT"
+ },
"node_modules/ts-api-utils": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
@@ -7648,6 +7765,16 @@
"path-to-regexp": "^6.2.1"
}
},
+ "node-addon-api": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.1.0.tgz",
+ "integrity": "sha512-yBY+qqWSv3dWKGODD6OGE6GnTX7Q2r+4+DfpqxHSHh8x0B4EKP9+wVGLS6U/AM1vxSNNmUEuIV5EGhYwPpfOwQ=="
+ },
+ "node-gyp-build": {
+ "version": "4.8.1",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
+ "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw=="
+ },
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -8536,6 +8663,58 @@
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"dev": true
},
+ "tree-sitter": {
+ "version": "0.21.1",
+ "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz",
+ "integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==",
+ "requires": {
+ "node-addon-api": "^8.0.0",
+ "node-gyp-build": "^4.8.0"
+ }
+ },
+ "tree-sitter-go": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/tree-sitter-go/-/tree-sitter-go-0.23.0.tgz",
+ "integrity": "sha512-6wycuKQCTRz/8OTlBL7xvUZP9aeznxKbWh5xYD1u0WXTCAwQM/xUQr92SKwcZexn9IIMczbzfjGgm6e5iFvSBA==",
+ "requires": {
+ "node-addon-api": "^8.1.0",
+ "node-gyp-build": "^4.8.1"
+ }
+ },
+ "tree-sitter-java": {
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/tree-sitter-java/-/tree-sitter-java-0.21.0.tgz",
+ "integrity": "sha512-CKJiTo1uc3SUsgEcaZgufGx8my6dzihy8JR/JsJH40Tj3uSe2/eFLk+0q+fpbosGAyY4YiXJtEoFB2O4bS2yOw==",
+ "requires": {
+ "node-addon-api": "^8.0.0",
+ "node-gyp-build": "^4.8.0"
+ }
+ },
+ "tree-sitter-javascript": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.21.4.tgz",
+ "integrity": "sha512-Lrk8yahebwrwc1sWJE9xPcz1OnnqiEV7Dh5fbN6EN3wNAdu9r06HpTqLqDwUUbnG4EB46Sfk+FJFAOldfoKLOw==",
+ "requires": {
+ "node-addon-api": "^8.0.0",
+ "node-gyp-build": "^4.8.1"
+ }
+ },
+ "tree-sitter-python": {
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/tree-sitter-python/-/tree-sitter-python-0.21.0.tgz",
+ "integrity": "sha512-IUKx7JcTVbByUx1iHGFS/QsIjx7pqwTMHL9bl/NGyhyyydbfNrpruo2C7W6V4KZrbkkCOlX8QVrCoGOFW5qecg==",
+ "requires": {
+ "node-addon-api": "^7.1.0",
+ "node-gyp-build": "^4.8.0"
+ },
+ "dependencies": {
+ "node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="
+ }
+ }
+ },
"ts-api-utils": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
diff --git a/package.json b/package.json
index 63d442b..7727ba2 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "keployio",
"displayName": "Keploy",
"description": "Streamline testing with the power of Keploy, directly in your favorite IDE.",
- "version": "1.0.7",
+ "version": "1.0.6",
"publisher": "Keploy",
"icon": "media/logo.png",
"pricing": "Free",
@@ -21,7 +21,8 @@
],
"activationEvents": [
"onCommand:keploy.utg",
- "onLanguage:javascript"
+ "onLanguage:javascript",
+ "onUri:keploy.handleUri"
],
"main": "./out/extension.js",
"contributes": {
@@ -81,6 +82,11 @@
"group": "navigation",
"when": "keploy.signedIn != true && view == Keploy-Sidebar"
},
+ {
+ "command": "keploy.SignInWithOthers",
+ "group": "navigation",
+ "when": "keploy.signedIn != true && view == Keploy-Sidebar"
+ },
{
"command": "keploy.SignOut",
"group": "navigation",
@@ -94,6 +100,11 @@
"title": "Sign In",
"when": "keploy.signedIn != true && view == Keploy-Sidebar"
},
+ {
+ "command": "keploy.SignInWithOthers",
+ "title": "Sign In With Others",
+ "when": "keploy.signedIn != true && view == Keploy-Sidebar"
+ },
{
"command": "keploy.SignOut",
"title": "Sign Out",
@@ -205,6 +216,11 @@
"js-yaml": "^4.1.0",
"sinon": "^17.0.1",
"svelte": "^4.2.12",
+ "tree-sitter": "^0.21.1",
+ "tree-sitter-java": "^0.21.0",
+ "tree-sitter-go": "^0.23.0",
+ "tree-sitter-javascript": "^0.21.4",
+ "tree-sitter-python": "^0.21.0",
"uuid": "^10.0.0",
"walk": "^2.3.15",
"yaml": "^2.4.2"
diff --git a/scripts/utg.sh b/scripts/utg.sh
index f3c49ef..edd3638 100644
--- a/scripts/utg.sh
+++ b/scripts/utg.sh
@@ -5,18 +5,46 @@ export API_KEY="1234"
sourceFilePath=$1
testFilePath=$2
+coverageReportPath=$3
+command=$4
-# Add env variables to the npm test command
-# utgEnv=" -- --coverage --coverageReporters=text --coverageReporters=cobertura --coverageDirectory=./coverage"
+# Get the file extension
+extension="${sourceFilePath##*.}"
-# testCommand="npm test "+ $utgEnv
+# If the file is a Python file, install pytest-cov
+if [ "$extension" = "py" ]; then
+ echo "Installing pytest-cov..."
+ pip3 install pytest-cov --break-system-packages
+fi
+if [ "$extension" = "go" ]; then
+ echo "Installing Go coverage tools..."
+ go install github.com/axw/gocov/gocov@v1.1.0
+ go install github.com/AlekSi/gocov-xml@v1.1.0
+ export PATH=$PATH:$(go env GOPATH)/bin
+fi
-keploy gen --source-file-path="$sourceFilePath" \
- --test-file-path="$testFilePath" \
- --test-command="npm test -- --coverage --coverageReporters=text --coverageReporters=cobertura --coverageDirectory=./coverage
-" \
- --coverage-report-path="./coverage/cobertura-coverage.xml"\
- --llmApiVersion "2024-02-01" --llmBaseUrl "https://api.keploy.io" --max-iterations "10"
+# Add env variables to the npm test command
+# utgEnv=" -- --coverage --coverageReporters=text --coverageReporters=cobertura --coverageDirectory=./coverage"
+# Construct the keploy gen command
+if [ "$extension" = "java" ]; then
+ keploy gen --source-file-path="$sourceFilePath" \
+ --test-file-path="$testFilePath" \
+ --test-command="$command" \
+ --coverage-report-path="$coverageReportPath" \
+ --llmApiVersion "2024-02-01" \
+ --llmBaseUrl "https://api.keploy.io" \
+ --max-iterations "10" \
+ --coverageFormat jacoco
+else
+ keploy gen --source-file-path="$sourceFilePath" \
+ --test-file-path="$testFilePath" \
+ --test-command="$command" \
+ --coverage-report-path="$coverageReportPath" \
+ --llmApiVersion "2024-02-01" \
+ --llmBaseUrl "https://api.keploy.io" \
+ --max-iterations "10" \
+ --coverageFormat cobertura
+fi
\ No newline at end of file
diff --git a/src/OneClickInstall.ts b/src/OneClickInstall.ts
index 89e1469..23265a0 100644
--- a/src/OneClickInstall.ts
+++ b/src/OneClickInstall.ts
@@ -3,7 +3,7 @@ import { exec } from 'child_process';
export default function executeKeployOneClickCommand(): void {
// check before if keploy has been installed first
const checkKeployExistsCommand = `keploy`;
- const installationCommand = `curl--silent - O - L https://keploy.io/install.sh && bash install.sh`;
+ const installationCommand = `curl --silent -O -L https://keploy.io/install.sh && bash install.sh`;
exec(checkKeployExistsCommand, (error, stdout, stderr) => {
if (error) {
diff --git a/src/SignIn.ts b/src/SignIn.ts
index dd432dd..bf33024 100644
--- a/src/SignIn.ts
+++ b/src/SignIn.ts
@@ -1,5 +1,6 @@
import * as vscode from 'vscode';
import * as http from 'http';
+import * as fs from 'fs'
import { v4 as uuidv4 } from 'uuid';
const os = require('os');
const { execSync } = require('child_process');
@@ -65,6 +66,10 @@ export async function getMicrosoftAccessToken() {
}
}
+function generateRandomState() {
+ return [...Array(30)].map(() => Math.random().toString(36)[2]).join('');
+}
+
export default async function SignInWithGitHub() {
@@ -109,10 +114,70 @@ export default async function SignInWithGitHub() {
res.end('
State mismatch. Authentication failed.
');
}
server.close();
- }
+ }
}).listen(3000); // Change the port if needed
}
+
+export async function SignInWithOthers() {
+ const state = generateRandomState(); // Generate a secure random state
+ const authUrl = `http://localhost:3000/signin?vscode=true&state=${state}`;
+ vscode.env.openExternal(vscode.Uri.parse(authUrl));
+
+ return new Promise((resolve, reject) => {
+ const server = http.createServer(async (req, res) => {
+ res.setHeader('Access-Control-Allow-Origin', '*');
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
+ if (req.method === 'OPTIONS') {
+ res.writeHead(200);
+ res.end();
+ return;
+ }
+
+ if (req && req.url && req.url.startsWith('/login/keploy/callback')) {
+ const url = new URL(req.url, `http://${req.headers.host}`);
+ const receivedState = url.searchParams.get('state');
+ const token = url.searchParams.get('token');
+ console.log("Received state:", receivedState);
+ console.log("Received token:", token);
+
+ if (!receivedState || !token) {
+ res.writeHead(400, { 'Content-Type': 'application/json' });
+ res.end(JSON.stringify({ error: 'Missing state or token' }));
+ reject(new Error('Missing state or token'));
+ server.close();
+ return;
+ }
+
+ try {
+ // Simulate processing the token
+ console.log("Processing token...");
+
+ res.writeHead(200, { 'Content-Type': 'application/json' });
+ res.end(JSON.stringify({ message: 'Token received and processed', token, receivedState }));
+
+ // Resolve the promise with the token
+ resolve(token.toString());
+ } catch (err) {
+ console.error('Error processing token:', err);
+ res.writeHead(500, { 'Content-Type': 'application/json' });
+ res.end(JSON.stringify({ error: 'Internal Server Error' }));
+ reject(err);
+ } finally {
+ server.close(); // Close the server once the request is handled
+ }
+ } else {
+ res.writeHead(404, { 'Content-Type': 'application/json' });
+ res.end(JSON.stringify({ error: 'Not Found' }));
+ }
+ }).listen(3001, () => {
+ console.log('Server listening on port 3001');
+ });
+ });
+}
+
+
// async function fetchAccessToken(code: string | null) {
// // Exchange the authorization code for an access token
// const response = await fetch('https://app.keploy.io/token', {
@@ -163,17 +228,56 @@ export async function loginAPI(url = "", provider = "", code = "") {
export async function getInstallationID(): Promise {
let id;
+
+ const dbusPath = "/var/lib/dbus/machine-id";
+ // dbusPathEtc is the default path for dbus machine id located in /etc.
+ // Some systems (like Fedora 20) only know this path.
+ // Sometimes it's the other way round.
+ const dbusPathEtc = "/etc/machine-id";
+
+ // Reads the content of a file and returns it as a string.
+ // If the file cannot be read, it throws an error.
+ function readFile(filePath: string): string {
+ try {
+ return fs.readFileSync(filePath, 'utf-8').trim();
+ } catch (err) {
+ throw new Error(`Error reading file ${filePath}: ${err}`);
+ }
+ }
+
+ function machineID(): string {
+ let id = "";
+ try {
+ id = readFile(dbusPath);
+ } catch (err) {
+ // Try the fallback path
+ try {
+ id = readFile(dbusPathEtc);
+ } catch (err) {
+ console.error("Failed to read machine ID from both paths:", err);
+ throw new Error("Failed to get machine ID");
+ }
+ }
+ return id;
+ }
try {
const inDocker = process.env.IN_DOCKER === 'true';
if (inDocker) {
id = process.env.INSTALLATION_ID;
} else {
- // Run the macOS specific command to get the IOPlatformUUID
- const output = execSync('ioreg -rd1 -c IOPlatformExpertDevice').toString();
- id = extractID(output);
+ const platform = os.platform();
+ if (platform === 'darwin') {
+ // macOS specific command to get the IOPlatformUUID
+ const output = execSync('ioreg -rd1 -c IOPlatformExpertDevice').toString();
+ id = extractID(output);
+ } else if (platform === 'linux') {
+ // Use the new machineID function for Linux
+ id = machineID();
+ } else {
+ throw new Error(`Unsupported platform: ${platform}`);
+ }
}
-
if (!id) {
console.error("Got empty machine id");
throw new Error("Empty machine id");
@@ -223,7 +327,7 @@ export async function validateFirst(token: string, serverURL: string): Promise<{
GitHubToken: token,
InstallationID: installationID,
};
-
+ console.log("Request Body:", requestBody);
try {
const response: AxiosResponse = await axios.post(url, requestBody, {
headers: { 'Content-Type': 'application/json' },
diff --git a/src/Utg.ts b/src/Utg.ts
index 3e957f9..6f65312 100644
--- a/src/Utg.ts
+++ b/src/Utg.ts
@@ -4,57 +4,96 @@ import * as path from 'path';
async function Utg(context: vscode.ExtensionContext) {
+
try {
return new Promise((resolve, reject) => {
try {
- // Create a terminal named "Keploy Terminal"
const terminal = vscode.window.createTerminal("Keploy Terminal");
-
terminal.show();
- // Your command logic here
+
const editor = vscode.window.activeTextEditor;
let currentFilePath = "";
if (editor) {
const document = editor.document;
currentFilePath = document.uri.fsPath;
vscode.window.showInformationMessage(`Current opened file: ${currentFilePath}`);
- // Add your additional logic here
} else {
vscode.window.showInformationMessage('No file is currently opened.');
+ return;
}
- const scriptPath = path.join(context.extensionPath, 'scripts', 'utg.sh');
-
+ const scriptPath = path.join(context.extensionPath, 'scripts', 'utg.sh');
const sourceFilePath = currentFilePath;
ensureTestFileExists(sourceFilePath);
-
if (!vscode.workspace.workspaceFolders) {
vscode.window.showErrorMessage('No workspace is opened.');
return;
}
- const rootDir = vscode.workspace.workspaceFolders[0].uri.fsPath; // Root directory of the project
- const testDir = path.join(rootDir, 'test');
- const testFilePath = path.join(testDir, path.basename(sourceFilePath).replace('.js', '.test.js'));
- if (!fs.existsSync(testFilePath)) {
- vscode.window.showInformationMessage("Test doesn't exists", testFilePath);
- fs.writeFileSync(testFilePath, `// Test file for ${testFilePath}`);
+
+ const rootDir = vscode.workspace.workspaceFolders[0].uri.fsPath;
+ const extension = path.extname(sourceFilePath);
+ let testFilePath: string;
+ let command: string;
+ let coverageReportPath: string;
+ let testFileContent:string;
+
+ if (extension === '.js' || extension === '.ts') {
+ testFilePath = path.join(path.join(rootDir, 'test'), path.basename(sourceFilePath).replace(extension, `.test${extension}`));
+ if (!fs.existsSync(testFilePath)) {
+ vscode.window.showInformationMessage("Test doesn't exist", testFilePath);
+ fs.writeFileSync(testFilePath, `// Test file for ${testFilePath}`);
+ }
+ command = `npm test -- --coverage --coverageReporters=text --coverageReporters=cobertura --coverageDirectory=./coverage`;
+ coverageReportPath = "./coverage/cobertura-coverage.xml";
+
+ } else if (extension === '.py') {
+ const testDir = path.join(rootDir,'test');
+ testFilePath = path.join(rootDir,'test_'+ path.basename(sourceFilePath));
+ if (!fs.existsSync(testFilePath)) {
+ vscode.window.showInformationMessage("Test doesn't exist", testFilePath);
+ fs.writeFileSync(testFilePath, `// Test file for ${testFilePath}`);
+ }
+ command = `pytest --cov=${path.basename(sourceFilePath,'.py')} --cov-report=xml:coverage.xml ${testFilePath}`;
+ coverageReportPath = "./coverage.xml";
+
+ }else if (extension === '.java') {
+ const testDir = path.join(rootDir, 'src', 'test', 'java');
+ const testFileName = path.basename(sourceFilePath).replace('.java', 'Test.java');
+ testFilePath = path.join(testDir, testFileName);
+
+ if (!fs.existsSync(testFilePath)) {
+ vscode.window.showInformationMessage("Test doesn't exist", testFilePath);
+ fs.writeFileSync(testFilePath, `// Test file for ${testFilePath}`);
+ }
+ command = `mvn clean test jacoco:report`;
+ coverageReportPath = "./target/site/jacoco/jacoco.xml";
+ } else if (extension === '.go') {
+ const testDir = path.join(rootDir, 'test');
+ testFilePath = path.join(testDir, path.basename(sourceFilePath).replace('.go', '_test.go'));
+
+ if (!fs.existsSync(testFilePath)) {
+ vscode.window.showInformationMessage("Test doesn't exist", testFilePath);
+ const uniqueFuncName = path.basename(sourceFilePath).replace('.go', 'Test')
+ testFileContent = `package main\n\nimport "testing"`;
+ fs.writeFileSync(testFilePath, testFileContent); }
+ command = `go test -v ./... -coverprofile=coverage.out && gocov convert coverage.out | gocov-xml > coverage.xml`;
+ coverageReportPath = "./coverage.xml";
+ }
+ else {
+ vscode.window.showErrorMessage(`Unsupported file type: ${extension}`);
+ return;
}
- vscode.window.showInformationMessage("testFilePath", testFilePath);
- const coverageReportPath = "./coverage/cobertura-coverage.xml";
- terminal.sendText(`sh "${scriptPath}" "${sourceFilePath}" "${testFilePath}" "${coverageReportPath}";`);
+ terminal.sendText(`sh "${scriptPath}" "${sourceFilePath}" "${testFilePath}" "${coverageReportPath}" "${command}";`);
- // Listen for terminal close event
const disposable = vscode.window.onDidCloseTerminal(eventTerminal => {
- console.log('Terminal closed');
if (eventTerminal === terminal) {
- disposable.dispose(); // Dispose the listener
- resolve(); // Resolve the promise
+ disposable.dispose();
+ resolve();
}
});
-
- } catch (error) {
+ } catch (error) {
console.log(error);
vscode.window.showErrorMessage('Error occurred Keploy utg: ' + error);
reject(error);
@@ -72,25 +111,38 @@ async function ensureTestFileExists(sourceFilePath: string): Promise {
vscode.window.showErrorMessage('No workspace is opened.');
return;
}
- const rootDir = path.dirname(vscode.workspace.workspaceFolders[0].uri.fsPath); // Root directory of the project
- const testDir = path.join(rootDir, 'test');
- const relativeSourceFilePath = path.relative(rootDir, sourceFilePath);
+ // const rootDir = vscode.workspace.workspaceFolders[0].uri.fsPath; // Root directory of the project
+ const extension = path.extname(sourceFilePath);
+ const sourceDir = path.dirname(sourceFilePath); // Directory of the source file
+ const testDir = path.join(sourceDir, 'test'); // 'test' directory under the source directory
const sourceFileName = path.basename(sourceFilePath);
- const testFileName = sourceFileName.replace('.js', '.test.js');
- const testFilePath = path.join(testDir, relativeSourceFilePath.replace(sourceFileName, testFileName));
+ let testFileName: string;
+ let testFileContent = '';
+
+ if (extension === '.js' || extension === '.ts') {
+ testFileName = sourceFileName.replace(extension, `.test${extension}`);
+ } else if (extension === '.py') {
+ testFileName = "test_" + sourceFileName;
+ } else if (extension === '.java') {
+ testFileName = sourceFileName.replace('.java', 'Test.java');
+ } else if (extension === '.go') {
+ testFileName = sourceFileName.replace('.go', '_test.go');
+ testFileContent = `package main\n\nimport "testing"`;
+ } else {
+ vscode.window.showErrorMessage(`Unsupported file type: ${extension}`);
+ return;
+ }
+
+ const testFilePath = path.join(testDir, testFileName);
+ console.log(testFilePath, testDir, "testFilePath");
if (!fs.existsSync(testDir)) {
fs.mkdirSync(testDir, { recursive: true });
}
- const testFileDir = path.dirname(testFilePath);
- if (!fs.existsSync(testFileDir)) {
- fs.mkdirSync(testFileDir, { recursive: true });
- }
-
if (!fs.existsSync(testFilePath)) {
- fs.writeFileSync(testFilePath, `// Test file for ${sourceFileName}`);
+ fs.writeFileSync(testFilePath, testFileContent);
vscode.window.showInformationMessage(`Created test file: ${testFilePath}`);
} else {
vscode.window.showInformationMessage(`Test file already exists: ${testFilePath}`);
diff --git a/src/extension.ts b/src/extension.ts
index 3294ee9..c9d038e 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -1,6 +1,6 @@
import * as vscode from 'vscode';
import { SidebarProvider } from './SidebarProvider';
-import SignIn, { validateFirst } from './SignIn';
+import SignIn, { validateFirst,SignInWithOthers } from './SignIn';
import oneClickInstall from './OneClickInstall';
import { getKeployVersion, getCurrentKeployVersion } from './version';
import { downloadAndUpdate, downloadAndUpdateDocker } from './updateKeploy';
@@ -9,6 +9,11 @@ import { getGitHubAccessToken, getMicrosoftAccessToken, getInstallationID } from
import * as acorn from 'acorn';
import * as walk from 'acorn-walk';
import { SentryInit } from './sentryInit';
+import TreeSitter from 'tree-sitter';
+import TreeSitterJavaScript from 'tree-sitter-javascript';
+import TreeSitterPython from 'tree-sitter-python';
+import TreeSitterJava from 'tree-sitter-java';
+import TreeSitterGo from 'tree-sitter-go';
class KeployCodeLensProvider implements vscode.CodeLensProvider {
onDidChangeCodeLenses?: vscode.Event | undefined;
@@ -18,7 +23,15 @@ class KeployCodeLensProvider implements vscode.CodeLensProvider {
token: vscode.CancellationToken
): vscode.CodeLens[] | Thenable {
const fileName = document.uri.fsPath;
- if (fileName.endsWith('.test.js') || fileName.endsWith('.test.ts')) {
+ if (
+ fileName.endsWith('.test.js') ||
+ fileName.endsWith('.test.ts') ||
+ fileName.endsWith('Test.java') || // Check for Java test file ending
+ fileName.includes('/Test') || // Check for Java test file prefix in the path
+ fileName.includes('/test/') || // Skip files in a "tests" directory
+ fileName.endsWith('_test.go') ||
+ fileName.includes('test_')
+ ) {
return [];
}
@@ -26,30 +39,88 @@ class KeployCodeLensProvider implements vscode.CodeLensProvider {
const codeLenses: vscode.CodeLens[] = [];
try {
- const ast = acorn.parse(text, { ecmaVersion: 2020, sourceType: 'module' });
+ const parser = new TreeSitter();
+
+ if (fileName.endsWith('.js') || fileName.endsWith('.ts')) {
+ parser.setLanguage(TreeSitterJavaScript);
+ } else if (fileName.endsWith('.py')) {
+ parser.setLanguage(TreeSitterPython);
+ } else if (fileName.endsWith('.java')) {
+ parser.setLanguage(TreeSitterJava);
+ } else if (fileName.endsWith('.go')) {
+ parser.setLanguage(TreeSitterGo);
+ } else {
+ return codeLenses; // Return if file type is unsupported
+ }
+
+ const tree = parser.parse(text);
+ const cursor = tree.walk();
- walk.fullAncestor(ast, (node: any, state: any, ancestors: any[]) => {
- if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
- const line = document.positionAt(node.start).line;
+ const traverseTree = (cursor: TreeSitter.TreeCursor, ancestors: TreeSitter.SyntaxNode[] = []) => {
+ const node = cursor.currentNode;
+
+ if (
+ (fileName.endsWith('.js') || fileName.endsWith('.ts')) &&
+ (node.type === 'function_declaration' || node.type === 'function_expression')
+ ) {
+ const line = document.positionAt(node.startIndex).line;
const range = new vscode.Range(line, 0, line, 0);
codeLenses.push(new vscode.CodeLens(range, {
title: '🐰 Generate unit tests',
command: 'keploy.utg',
arguments: [document.uri.fsPath]
}));
- } else if (node.type === 'ArrowFunctionExpression') {
- const parent = ancestors[ancestors.length - 2];
- if (parent.type !== 'CallExpression' || (parent.callee.property?.name !== 'then' && parent.callee.property?.name !== 'catch')) {
- const line = document.positionAt(node.start).line;
- const range = new vscode.Range(line, 0, line, 0);
- codeLenses.push(new vscode.CodeLens(range, {
- title: '🐰 Generate unit tests',
- command: 'keploy.utg',
- arguments: [document.uri.fsPath]
- }));
+ } else if (fileName.endsWith('.js') || fileName.endsWith('.ts')) {
+ if (node.type === 'arrow_function') {
+ const parent = ancestors[ancestors.length - 1];
+ if (parent?.type !== 'CallExpression') {
+ const line = document.positionAt(node.startIndex).line;
+ const range = new vscode.Range(line, 0, line, 0);
+ codeLenses.push(new vscode.CodeLens(range, {
+ title: '🐰 Generate unit tests',
+ command: 'keploy.utg',
+ arguments: [document.uri.fsPath]
+ }));
+ }
}
+ } else if (fileName.endsWith('.py') && node.type === 'function_definition') {
+ const line = document.positionAt(node.startIndex).line;
+ const range = new vscode.Range(line, 0, line, 0);
+ codeLenses.push(new vscode.CodeLens(range, {
+ title: '🐰 Generate unit tests',
+ command: 'keploy.utg',
+ arguments: [document.uri.fsPath]
+ }));
+ } else if (fileName.endsWith('.java') && (node.type === 'method_declaration' || node.type === 'constructor_declaration')) {
+ const line = document.positionAt(node.startIndex).line;
+ const range = new vscode.Range(line, 0, line, 0);
+ codeLenses.push(new vscode.CodeLens(range, {
+ title: '🐰 Generate unit tests',
+ command: 'keploy.utg',
+ arguments: [document.uri.fsPath]
+ }));
+ } else if (fileName.endsWith('.go') && (node.type === 'function_declaration' || node.type === 'method_declaration')) {
+ const line = document.positionAt(node.startIndex).line;
+ const range = new vscode.Range(line, 0, line, 0);
+ codeLenses.push(new vscode.CodeLens(range, {
+ title: '🐰 Generate unit tests',
+ command: 'keploy.utg',
+ arguments: [document.uri.fsPath]
+ }));
}
- });
+
+ // Traverse to the first child node
+ if (cursor.gotoFirstChild()) {
+ traverseTree(cursor, ancestors.concat(node));
+ cursor.gotoParent(); // Go back to parent after finishing with the child
+ }
+ // Traverse to the next sibling node
+ if (cursor.gotoNextSibling()) {
+ traverseTree(cursor, ancestors);
+ }
+ };
+
+ traverseTree(cursor);
} catch (error) {
console.error(error);
@@ -63,6 +134,11 @@ const Sentry = SentryInit()
export function activate(context: vscode.ExtensionContext) {
const sidebarProvider = new SidebarProvider(context.extensionUri);
context.subscriptions.push(
+ vscode.window.registerUriHandler({
+ handleUri(uri: vscode.Uri): vscode.ProviderResult {
+ vscode.window.showInformationMessage(`URI handler called: ${uri.toString()}`);
+ }
+ }),
vscode.window.registerWebviewViewProvider(
"Keploy-Sidebar",
sidebarProvider
@@ -74,7 +150,20 @@ export function activate(context: vscode.ExtensionContext) {
vscode.languages.registerCodeLensProvider(
{ language: 'typescript', scheme: 'file' },
new KeployCodeLensProvider()
- )
+ ),
+ vscode.languages.registerCodeLensProvider(
+ { language: 'python', scheme: 'file' },
+ new KeployCodeLensProvider()
+ ),
+ vscode.languages.registerCodeLensProvider(
+ { language: 'go', scheme: 'file' },
+ new KeployCodeLensProvider()
+ ),
+ vscode.languages.registerCodeLensProvider(
+ { language: 'java', scheme: 'file' },
+ new KeployCodeLensProvider()
+ ),
+
);
@@ -132,7 +221,31 @@ export function activate(context: vscode.ExtensionContext) {
}
});
+ let signInWithOthersCommand = vscode.commands.registerCommand('keploy.SignInWithOthers', async () => {
+ try {
+ const result = await SignInWithOthers();
+ const accessToken = result as string; // Assert that result is a string
+ getInstallationID();
+
+ await context.globalState.update('accessToken', accessToken);
+
+ if (Boolean(accessToken)) {
+ vscode.window.showInformationMessage('You are now signed in!');
+ vscode.commands.executeCommand('setContext', 'keploy.signedIn', true);
+ vscode.commands.executeCommand('setContext', 'keploy.signedOut', false);
+ } else {
+ console.log('Validation failed for the user !');
+ vscode.window.showInformationMessage('Failed to sign in Keploy!');
+ }
+ } catch (error) {
+ // console.error('Error during sign-in:', error);
+ vscode.window.showInformationMessage('Failed to sign in Keploy!');
+ }
+ });
+
context.subscriptions.push(signInCommand);
+ context.subscriptions.push(signInWithOthersCommand);
+
}
@@ -250,7 +363,6 @@ export function activate(context: vscode.ExtensionContext) {
});
context.subscriptions.push(disposable);
-
}