Skip to content

Commit 8ec30e4

Browse files
committed
core: add codeberg autofill
1 parent f91d389 commit 8ec30e4

File tree

2 files changed

+55
-18
lines changed

2 files changed

+55
-18
lines changed

src/cli/commands/add.ts

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,48 @@ export function stem(value: string): string {
4242
}
4343

4444
export function github(uri: string): { owner: string; repo: string } | null {
45-
const https = uri.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
45+
return hosted(uri, "github.com");
46+
}
47+
48+
export function codeberg(uri: string): { owner: string; repo: string } | null {
49+
return hosted(uri, "codeberg.org");
50+
}
51+
52+
function hosted(uri: string, host: string): { owner: string; repo: string } | null {
53+
const escaped = host.replace(/\./g, "\\.");
54+
const https = uri.match(new RegExp(`^https?:\\/\\/${escaped}\\/([^/]+)\\/([^/]+?)(?:\\.git)?\\/?$`));
4655
if (https) {
4756
return { owner: https[1]!, repo: https[2]! };
4857
}
4958

50-
const ssh = uri.match(/^ssh:\/\/git@github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
59+
const ssh = uri.match(new RegExp(`^ssh:\\/\\/git@${escaped}\\/([^/]+)\\/([^/]+?)(?:\\.git)?\\/?$`));
5160
if (ssh) {
5261
return { owner: ssh[1]!, repo: ssh[2]! };
5362
}
5463

55-
const scp = uri.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/);
64+
const scp = uri.match(new RegExp(`^git@${escaped}:([^/]+)\\/([^/]+?)(?:\\.git)?$`));
5665
if (scp) {
5766
return { owner: scp[1]!, repo: scp[2]! };
5867
}
5968

6069
return null;
6170
}
6271

72+
async function apiDescription(url: string, accept: string): Promise<string> {
73+
const response = await fetch(url, {
74+
headers: {
75+
accept,
76+
"user-agent": "dotllm",
77+
},
78+
});
79+
if (!response.ok) return "";
80+
81+
const raw = await response.json();
82+
const result = RepoShape.safeParse(raw);
83+
if (!result.success) return "";
84+
return result.data.description ?? "";
85+
}
86+
6387
function gitName(uri: string): string {
6488
const dir = path.resolve(uri);
6589
if (!fs.existsSync(dir)) return "";
@@ -78,22 +102,19 @@ function gitName(uri: string): string {
78102
}
79103

80104
async function remoteDescription(uri: string): Promise<string> {
81-
const repo = github(uri);
82-
if (!repo) return "";
105+
const gh = github(uri);
106+
if (gh) {
107+
const url = `https://api.github.com/repos/${gh.owner}/${gh.repo}`;
108+
return apiDescription(url, "application/vnd.github+json");
109+
}
83110

84-
const url = `https://api.github.com/repos/${repo.owner}/${repo.repo}`;
85-
const response = await fetch(url, {
86-
headers: {
87-
accept: "application/vnd.github+json",
88-
"user-agent": "dotllm",
89-
},
90-
});
91-
if (!response.ok) return "";
111+
const cb = codeberg(uri);
112+
if (cb) {
113+
const url = `https://codeberg.org/api/v1/repos/${cb.owner}/${cb.repo}`;
114+
return apiDescription(url, "application/json");
115+
}
92116

93-
const raw = await response.json();
94-
const result = RepoShape.safeParse(raw);
95-
if (!result.success) return "";
96-
return result.data.description ?? "";
117+
return "";
97118
}
98119

99120
async function prefill(uri: string): Promise<{ name: string; description: string }> {

test/cli/github.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { test, expect } from "bun:test"
2-
import { github } from "@spader/dotllm/cli/commands/add"
2+
import { codeberg, github } from "@spader/dotllm/cli/commands/add"
33

44
test("HTTPS with .git", () => {
55
expect(github("https://github.com/acme/foo.git")).toEqual({ owner: "acme", repo: "foo" })
@@ -37,3 +37,19 @@ test("malformed returns null", () => {
3737
test("extra path segments returns null", () => {
3838
expect(github("https://github.com/acme/foo/tree/main")).toBeNull()
3939
})
40+
41+
test("Codeberg HTTPS with .git", () => {
42+
expect(codeberg("https://codeberg.org/acme/foo.git")).toEqual({ owner: "acme", repo: "foo" })
43+
})
44+
45+
test("Codeberg SSH SCP", () => {
46+
expect(codeberg("git@codeberg.org:acme/foo.git")).toEqual({ owner: "acme", repo: "foo" })
47+
})
48+
49+
test("Codeberg SSH URL", () => {
50+
expect(codeberg("ssh://git@codeberg.org/acme/foo.git")).toEqual({ owner: "acme", repo: "foo" })
51+
})
52+
53+
test("non-Codeberg returns null", () => {
54+
expect(codeberg("https://github.com/acme/foo.git")).toBeNull()
55+
})

0 commit comments

Comments
 (0)