feat: add GitHub service for PAT validation, forking, and PR management
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
import { Router } from "express";
|
||||
import { readConfig, writeConfig } from "../services/workspace.service.js";
|
||||
import { REPOS } from "../config/repos.js";
|
||||
import {
|
||||
validatePat,
|
||||
forkRepo,
|
||||
listUserForks,
|
||||
createPullRequest,
|
||||
listPullRequests,
|
||||
} from "../services/github.service.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
async function getPat(): Promise<string> {
|
||||
const config = await readConfig();
|
||||
const pat = config.githubPat;
|
||||
if (!pat) throw new Error("GitHub PAT not configured");
|
||||
return pat;
|
||||
}
|
||||
|
||||
router.post("/validate-pat", async (req, res) => {
|
||||
try {
|
||||
const { pat } = req.body;
|
||||
if (!pat) {
|
||||
res.status(400).json({ error: "PAT is required" });
|
||||
return;
|
||||
}
|
||||
const result = await validatePat(pat);
|
||||
|
||||
const config = await readConfig();
|
||||
await writeConfig({ ...config, githubPat: pat });
|
||||
|
||||
res.json(result);
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : "Invalid PAT";
|
||||
res.status(401).json({ error: message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/fork", async (req, res) => {
|
||||
try {
|
||||
const pat = await getPat();
|
||||
const { repo: repoName } = req.body;
|
||||
const repoDef = REPOS.find((r) => r.name === repoName);
|
||||
if (!repoDef) {
|
||||
res.status(400).json({ error: `Unknown repo: ${repoName}` });
|
||||
return;
|
||||
}
|
||||
const [owner, repo] = repoDef.upstream.split("/");
|
||||
const result = await forkRepo(pat, owner, repo);
|
||||
res.json(result);
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : "Fork failed";
|
||||
res.status(500).json({ error: message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/forks", async (_req, res) => {
|
||||
try {
|
||||
const pat = await getPat();
|
||||
const forks = await listUserForks(pat);
|
||||
res.json(forks);
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : "Failed to list forks";
|
||||
res.status(500).json({ error: message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/pr", async (req, res) => {
|
||||
try {
|
||||
const pat = await getPat();
|
||||
const { repo: repoName, title, body, headBranch } = req.body;
|
||||
const repoDef = REPOS.find((r) => r.name === repoName);
|
||||
if (!repoDef) {
|
||||
res.status(400).json({ error: `Unknown repo: ${repoName}` });
|
||||
return;
|
||||
}
|
||||
|
||||
const { login } = await import("../services/github.service.js").then((m) =>
|
||||
m.validatePat(pat),
|
||||
);
|
||||
|
||||
const result = await createPullRequest(pat, {
|
||||
upstream: repoDef.upstream,
|
||||
repo: repoName,
|
||||
title,
|
||||
body,
|
||||
head: `${login}:${headBranch}`,
|
||||
base: repoDef.branch,
|
||||
});
|
||||
res.json(result);
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : "PR creation failed";
|
||||
res.status(500).json({ error: message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/prs/:repo", async (req, res) => {
|
||||
try {
|
||||
const pat = await getPat();
|
||||
const repoName = req.params.repo;
|
||||
const repoDef = REPOS.find((r) => r.name === repoName);
|
||||
if (!repoDef) {
|
||||
res.status(400).json({ error: `Unknown repo: ${repoName}` });
|
||||
return;
|
||||
}
|
||||
const [owner, repo] = repoDef.upstream.split("/");
|
||||
const prs = await listPullRequests(pat, owner, repo);
|
||||
res.json(prs);
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : "Failed to list PRs";
|
||||
res.status(500).json({ error: message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user