feat: add repo clone job
This commit is contained in:
87
apps/worker/src/jobs/clone.ts
Normal file
87
apps/worker/src/jobs/clone.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { simpleGit } from "simple-git";
|
||||||
|
import { mkdtemp, readdir, stat } from "node:fs/promises";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import type { CloneResult } from "@codeboard/shared";
|
||||||
|
|
||||||
|
async function countFiles(dir: string): Promise<{ files: number; lines: number }> {
|
||||||
|
let files = 0;
|
||||||
|
let lines = 0;
|
||||||
|
|
||||||
|
const entries = await readdir(dir, { withFileTypes: true });
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
||||||
|
const fullPath = join(dir, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
const sub = await countFiles(fullPath);
|
||||||
|
files += sub.files;
|
||||||
|
lines += sub.lines;
|
||||||
|
} else {
|
||||||
|
files++;
|
||||||
|
const fileStat = await stat(fullPath);
|
||||||
|
lines += Math.ceil(fileStat.size / 40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { files, lines };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function cloneRepository(repoUrl: string): Promise<CloneResult> {
|
||||||
|
const tmpDir = await mkdtemp(join(tmpdir(), "codeboard-"));
|
||||||
|
const git = simpleGit();
|
||||||
|
|
||||||
|
await git.clone(repoUrl, tmpDir, ["--depth", "1", "--single-branch"]);
|
||||||
|
|
||||||
|
const localGit = simpleGit(tmpDir);
|
||||||
|
const log = await localGit.log({ maxCount: 1 });
|
||||||
|
const lastCommit = log.latest?.hash ?? "unknown";
|
||||||
|
|
||||||
|
const repoName = repoUrl
|
||||||
|
.replace(/\.git$/, "")
|
||||||
|
.split("/")
|
||||||
|
.slice(-1)[0] ?? "unknown";
|
||||||
|
|
||||||
|
const { files: totalFiles, lines: totalLines } = await countFiles(tmpDir);
|
||||||
|
|
||||||
|
const languageCounts: Record<string, number> = {};
|
||||||
|
const extMap: Record<string, string> = {
|
||||||
|
".ts": "TypeScript", ".tsx": "TypeScript",
|
||||||
|
".js": "JavaScript", ".jsx": "JavaScript",
|
||||||
|
".py": "Python", ".go": "Go",
|
||||||
|
".rs": "Rust", ".java": "Java",
|
||||||
|
".rb": "Ruby", ".php": "PHP",
|
||||||
|
};
|
||||||
|
|
||||||
|
async function scanLanguages(dir: string) {
|
||||||
|
const entries = await readdir(dir, { withFileTypes: true });
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
||||||
|
const fullPath = join(dir, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
await scanLanguages(fullPath);
|
||||||
|
} else {
|
||||||
|
const ext = entry.name.slice(entry.name.lastIndexOf("."));
|
||||||
|
const lang = extMap[ext];
|
||||||
|
if (lang) {
|
||||||
|
const fileStat = await stat(fullPath);
|
||||||
|
languageCounts[lang] = (languageCounts[lang] ?? 0) + fileStat.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await scanLanguages(tmpDir);
|
||||||
|
|
||||||
|
return {
|
||||||
|
localPath: tmpDir,
|
||||||
|
metadata: {
|
||||||
|
name: repoName,
|
||||||
|
description: "",
|
||||||
|
defaultBranch: "main",
|
||||||
|
languages: languageCounts,
|
||||||
|
stars: 0,
|
||||||
|
lastCommit,
|
||||||
|
totalFiles,
|
||||||
|
totalLines,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user