feat: add GitHub service for PAT validation, forking, and PR management

This commit is contained in:
plenarius
2026-04-20 21:54:09 -04:00
parent 6e3abb0b07
commit f54816a622
6 changed files with 442 additions and 7 deletions
@@ -0,0 +1,70 @@
import { Octokit } from "@octokit/rest";
import { REPOS } from "../config/repos.js";
export async function validatePat(pat: string) {
const octokit = new Octokit({ auth: pat });
const { data, headers } = await octokit.rest.users.getAuthenticated();
const scopes = (headers["x-oauth-scopes"] || "")
.split(",")
.map((s: string) => s.trim())
.filter(Boolean);
return { login: data.login, scopes };
}
export async function forkRepo(pat: string, owner: string, repo: string) {
const octokit = new Octokit({ auth: pat });
const { data } = await octokit.rest.repos.createFork({ owner, repo });
return { fullName: data.full_name, cloneUrl: data.clone_url };
}
export async function listUserForks(pat: string) {
const octokit = new Octokit({ auth: pat });
const { data: user } = await octokit.rest.users.getAuthenticated();
const login = user.login;
const results: Array<{ repo: string; forked: boolean; fullName?: string }> = [];
for (const repo of REPOS) {
try {
const { data } = await octokit.rest.repos.get({
owner: login,
repo: repo.name,
});
results.push({ repo: repo.name, forked: true, fullName: data.full_name });
} catch {
results.push({ repo: repo.name, forked: false });
}
}
return results;
}
export async function createPullRequest(
pat: string,
opts: { upstream: string; repo: string; title: string; body: string; head: string; base: string },
) {
const octokit = new Octokit({ auth: pat });
const [owner, repo] = opts.upstream.split("/");
const { data } = await octokit.rest.pulls.create({
owner,
repo,
title: opts.title,
body: opts.body,
head: opts.head,
base: opts.base,
});
return { number: data.number, url: data.html_url };
}
export async function listPullRequests(pat: string, owner: string, repo: string) {
const octokit = new Octokit({ auth: pat });
const { data } = await octokit.rest.pulls.list({ owner, repo, state: "open" });
return data.map((pr) => ({
number: pr.number,
title: pr.title,
state: pr.state,
url: pr.html_url,
user: pr.user?.login || "",
createdAt: pr.created_at,
}));
}