89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
import type { Repository } from "@/lib/types/http";
|
|
|
|
export type TaskPullRequestLinkTarget = {
|
|
id: string;
|
|
title: string;
|
|
repositoryId?: string;
|
|
repositories?: Array<{ repository_id: string }>;
|
|
};
|
|
|
|
export type GitHubPRRepoRef = {
|
|
owner: string;
|
|
repo: string;
|
|
repositoryId: string;
|
|
};
|
|
|
|
export type ParsedPullRequestURL = {
|
|
owner: string;
|
|
repo: string;
|
|
number: number;
|
|
url: string;
|
|
};
|
|
|
|
export function githubReposForTask(
|
|
task: TaskPullRequestLinkTarget,
|
|
repositories: Repository[],
|
|
): GitHubPRRepoRef[] {
|
|
const repoIds = new Set((task.repositories ?? []).map((repo) => repo.repository_id));
|
|
if (task.repositoryId) repoIds.add(task.repositoryId);
|
|
|
|
return repositories
|
|
.filter((repo) => repoIds.has(repo.id) && repo.provider === "github")
|
|
.map((repo) => ({
|
|
owner: repo.provider_owner,
|
|
repo: repo.provider_name,
|
|
repositoryId: repo.id,
|
|
}))
|
|
.filter((repo) => repo.owner && repo.repo);
|
|
}
|
|
|
|
export function parseGitHubPullRequestURL(input: string): ParsedPullRequestURL | null {
|
|
const match = input
|
|
.trim()
|
|
.match(/^(?:https?:\/\/)?github\.com\/([^/\s]+)\/([^/\s]+)\/pull\/(\d+)(?:[/?#].*)?$/i);
|
|
if (!match) return null;
|
|
const [, owner, repo, number] = match;
|
|
const parsedNumber = Number(number);
|
|
if (!Number.isSafeInteger(parsedNumber) || parsedNumber <= 0) return null;
|
|
return {
|
|
owner,
|
|
repo,
|
|
number: parsedNumber,
|
|
url: `https://github.com/${owner}/${repo}/pull/${parsedNumber}`,
|
|
};
|
|
}
|
|
|
|
function positivePullRequestNumber(input: string): string | null {
|
|
const number = input.replace(/^#/, "");
|
|
if (!/^\d+$/.test(number)) return null;
|
|
const parsedNumber = Number(number);
|
|
if (!Number.isSafeInteger(parsedNumber) || parsedNumber <= 0) return null;
|
|
return String(parsedNumber);
|
|
}
|
|
|
|
export function pullRequestPayload(input: string, githubRepos: GitHubPRRepoRef[]) {
|
|
const trimmed = input.trim();
|
|
const inferredNumber = positivePullRequestNumber(trimmed);
|
|
const inferredRepo = inferredNumber && githubRepos.length === 1 ? githubRepos[0] : null;
|
|
if (inferredRepo && inferredNumber) {
|
|
return {
|
|
pr_url: `https://github.com/${inferredRepo.owner}/${inferredRepo.repo}/pull/${inferredNumber}`,
|
|
repository_id: inferredRepo.repositoryId,
|
|
};
|
|
}
|
|
|
|
const parsed = parseGitHubPullRequestURL(trimmed);
|
|
const matchingRepo = parsed
|
|
? githubRepos.find(
|
|
(repo) =>
|
|
repo.owner.toLowerCase() === parsed.owner.toLowerCase() &&
|
|
repo.repo.toLowerCase() === parsed.repo.toLowerCase(),
|
|
)
|
|
: null;
|
|
|
|
return {
|
|
pr_url: parsed?.url ?? trimmed,
|
|
repository_id: matchingRepo?.repositoryId,
|
|
};
|
|
}
|