feat: link tasks to github references (#1471)
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
githubReposForTask,
|
||||
parseGitHubPullRequestURL,
|
||||
pullRequestPayload,
|
||||
type GitHubPRRepoRef,
|
||||
} from "./task-github-pr-url";
|
||||
import { repositoryId, workspaceId, type Repository } from "@/lib/types/http";
|
||||
|
||||
type RepoOverrides = Partial<Omit<Repository, "id" | "workspace_id">> & { id: string };
|
||||
|
||||
function repo(overrides: RepoOverrides): Repository {
|
||||
const { id, ...rest } = overrides;
|
||||
return {
|
||||
...rest,
|
||||
id: repositoryId(id),
|
||||
workspace_id: workspaceId("workspace-1"),
|
||||
name: overrides.name ?? "Repo",
|
||||
source_type: "remote",
|
||||
local_path: "",
|
||||
provider: overrides.provider ?? "github",
|
||||
provider_repo_id: "",
|
||||
provider_owner: overrides.provider_owner ?? "kdlbs",
|
||||
provider_name: overrides.provider_name ?? "kandev",
|
||||
default_branch: "main",
|
||||
worktree_branch_prefix: "",
|
||||
pull_before_worktree: false,
|
||||
setup_script: "",
|
||||
cleanup_script: "",
|
||||
dev_script: "",
|
||||
copy_files: "",
|
||||
created_at: "2026-06-23T00:00:00Z",
|
||||
updated_at: "2026-06-23T00:00:00Z",
|
||||
};
|
||||
}
|
||||
|
||||
const KANDEV_PR_URL = "https://github.com/kdlbs/kandev/pull/1471";
|
||||
|
||||
describe("githubReposForTask", () => {
|
||||
it("maps task repositories to GitHub repository ids, not task-repository row ids", () => {
|
||||
const refs = githubReposForTask(
|
||||
{
|
||||
id: "task-1",
|
||||
title: "Task",
|
||||
repositories: [{ repository_id: repositoryId("repo-1") }],
|
||||
},
|
||||
[
|
||||
repo({ id: "repo-1", provider_owner: "kdlbs", provider_name: "kandev" }),
|
||||
repo({ id: "repo-2", provider_owner: "acme", provider_name: "site" }),
|
||||
],
|
||||
);
|
||||
|
||||
expect(refs).toEqual([{ owner: "kdlbs", repo: "kandev", repositoryId: "repo-1" }]);
|
||||
});
|
||||
|
||||
it("uses the task repositoryId fallback and ignores non-GitHub repositories", () => {
|
||||
const refs = githubReposForTask(
|
||||
{ id: "task-1", title: "Task", repositoryId: repositoryId("repo-2") },
|
||||
[
|
||||
repo({ id: "repo-1", provider_owner: "kdlbs", provider_name: "kandev" }),
|
||||
repo({ id: "repo-2", provider: "gitlab", provider_owner: "acme", provider_name: "site" }),
|
||||
],
|
||||
);
|
||||
|
||||
expect(refs).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseGitHubPullRequestURL", () => {
|
||||
it("normalizes full GitHub pull request URLs", () => {
|
||||
expect(parseGitHubPullRequestURL(KANDEV_PR_URL)).toEqual({
|
||||
owner: "kdlbs",
|
||||
repo: "kandev",
|
||||
number: 1471,
|
||||
url: KANDEV_PR_URL,
|
||||
});
|
||||
expect(parseGitHubPullRequestURL("github.com/kdlbs/kandev/pull/1471/")).toEqual({
|
||||
owner: "kdlbs",
|
||||
repo: "kandev",
|
||||
number: 1471,
|
||||
url: KANDEV_PR_URL,
|
||||
});
|
||||
expect(
|
||||
parseGitHubPullRequestURL("https://github.com/kdlbs/kandev/pull/1471?tab=files#diff"),
|
||||
).toEqual({
|
||||
owner: "kdlbs",
|
||||
repo: "kandev",
|
||||
number: 1471,
|
||||
url: KANDEV_PR_URL,
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects malformed or non-GitHub pull request inputs", () => {
|
||||
expect(parseGitHubPullRequestURL("https://gitlab.com/kdlbs/kandev/pull/1471")).toBeNull();
|
||||
expect(parseGitHubPullRequestURL("https://github.com/kdlbs/kandev/issues/1471")).toBeNull();
|
||||
expect(parseGitHubPullRequestURL("https://github.com/kdlbs/kandev/pull/0")).toBeNull();
|
||||
expect(parseGitHubPullRequestURL("https://github.com/kdlbs/kandev/pull/00")).toBeNull();
|
||||
expect(parseGitHubPullRequestURL("not a url")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("pullRequestPayload", () => {
|
||||
const githubRepos: GitHubPRRepoRef[] = [
|
||||
{ owner: "kdlbs", repo: "kandev", repositoryId: "repo-1" },
|
||||
{ owner: "acme", repo: "site", repositoryId: "repo-2" },
|
||||
];
|
||||
|
||||
it("infers a bare PR number when exactly one GitHub repo is attached", () => {
|
||||
expect(pullRequestPayload("#1471", [githubRepos[0]])).toEqual({
|
||||
pr_url: KANDEV_PR_URL,
|
||||
repository_id: "repo-1",
|
||||
});
|
||||
});
|
||||
|
||||
it("does not infer bare numbers for multi-repo tasks", () => {
|
||||
expect(pullRequestPayload("1471", githubRepos)).toEqual({
|
||||
pr_url: "1471",
|
||||
repository_id: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not infer non-positive PR numbers", () => {
|
||||
expect(pullRequestPayload("#0", [githubRepos[0]])).toEqual({
|
||||
pr_url: "#0",
|
||||
repository_id: undefined,
|
||||
});
|
||||
expect(pullRequestPayload("00", [githubRepos[0]])).toEqual({
|
||||
pr_url: "00",
|
||||
repository_id: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("attaches the repository id when a URL matches a task GitHub repo", () => {
|
||||
expect(pullRequestPayload("https://github.com/ACME/site/pull/5", githubRepos)).toEqual({
|
||||
pr_url: "https://github.com/ACME/site/pull/5",
|
||||
repository_id: "repo-2",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps unmatched and malformed inputs without a repository id", () => {
|
||||
expect(pullRequestPayload("https://github.com/other/repo/pull/5", githubRepos)).toEqual({
|
||||
pr_url: "https://github.com/other/repo/pull/5",
|
||||
repository_id: undefined,
|
||||
});
|
||||
expect(pullRequestPayload(" not a url ", [githubRepos[0]])).toEqual({
|
||||
pr_url: "not a url",
|
||||
repository_id: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user