11import { test } from "node:test"
22import assert from "node:assert/strict"
33
4- import { github , bitbucket , forgeForHostname } from "../forges.js"
4+ import { github , bitbucket , codeberg , forgeForHostname } from "../forges.js"
55
66//
77// forgeForHostname
@@ -14,6 +14,10 @@ test("forgeForHostname matches bitbucket.org", () => {
1414 assert . equal ( forgeForHostname ( "bitbucket.org" ) , bitbucket )
1515} )
1616
17+ test ( "forgeForHostname matches codeberg.org" , ( ) => {
18+ assert . equal ( forgeForHostname ( "codeberg.org" ) , codeberg )
19+ } )
20+
1721test ( "forgeForHostname matches a subdomain containing the hostname" , ( ) => {
1822 // hostnames are matched as substrings of the page hostname
1923 assert . equal ( forgeForHostname ( "www.github.com" ) , github )
@@ -189,3 +193,70 @@ test("bitbucket.authHeader builds a Bearer Authorization header", () => {
189193 Authorization : "Bearer bb_secret" ,
190194 } )
191195} )
196+
197+ //
198+ // codeberg adapter (Forgejo / Gitea-compatible API)
199+ //
200+ test ( "codeberg.parseUrl extracts owner, repo and filepath from a src URL" , ( ) => {
201+ const url = new URL ( "https://codeberg.org/forgejo/forgejo/src/branch/forgejo/README.md" )
202+ assert . deepEqual ( codeberg . parseUrl ( url ) , {
203+ projectKey : "forgejo" ,
204+ repoSlug : "forgejo" ,
205+ filepath : "README.md" ,
206+ origin : "https://codeberg.org" ,
207+ } )
208+ } )
209+
210+ test ( "codeberg.parseUrl keeps nested file paths intact" , ( ) => {
211+ const url = new URL ( "https://codeberg.org/acme/widget/src/commit/deadbeef/dir/app.js" )
212+ assert . equal ( codeberg . parseUrl ( url ) . filepath , "dir/app.js" )
213+ } )
214+
215+ test ( "codeberg.parseUrl returns null for a non-file URL" , ( ) => {
216+ assert . equal ( codeberg . parseUrl ( new URL ( "https://codeberg.org/acme/widget" ) ) , null )
217+ } )
218+
219+ test ( "codeberg.listPRsUrl builds the pulls endpoint" , ( ) => {
220+ const info = { projectKey : "acme" , repoSlug : "widget" }
221+ assert . equal (
222+ codeberg . listPRsUrl ( info ) ,
223+ "https://codeberg.org/api/v1/repos/acme/widget/pulls" )
224+ } )
225+
226+ test ( "codeberg.filesUrl builds the files endpoint for a PR" , ( ) => {
227+ const info = { projectKey : "acme" , repoSlug : "widget" }
228+ assert . equal (
229+ codeberg . filesUrl ( info , { number : 42 } ) ,
230+ "https://codeberg.org/api/v1/repos/acme/widget/pulls/42/files" )
231+ } )
232+
233+ test ( "codeberg.prWebUrl builds the web URL of a PR" , ( ) => {
234+ const info = { projectKey : "acme" , repoSlug : "widget" , origin : "https://codeberg.org" }
235+ assert . equal (
236+ codeberg . prWebUrl ( info , 42 ) ,
237+ "https://codeberg.org/acme/widget/pulls/42" )
238+ } )
239+
240+ test ( "codeberg.prNumber reads the number off a PR object" , ( ) => {
241+ assert . equal ( codeberg . prNumber ( { number : 7 , title : "ignored" } ) , 7 )
242+ } )
243+
244+ test ( "codeberg.pullRequests returns the list response as-is" , ( ) => {
245+ const prs = [ { number : 1 } , { number : 2 } ]
246+ assert . equal ( codeberg . pullRequests ( prs ) , prs )
247+ } )
248+
249+ test ( "codeberg.filenames maps files to their filename" , ( ) => {
250+ const files = [ { filename : "a.js" } , { filename : "dir/b.js" } ]
251+ assert . deepEqual ( codeberg . filenames ( files ) , [ "a.js" , "dir/b.js" ] )
252+ } )
253+
254+ test ( "codeberg exposes no rate-limit endpoint" , ( ) => {
255+ assert . equal ( codeberg . rateLimit , null )
256+ } )
257+
258+ test ( "codeberg.authHeader builds a token Authorization header" , ( ) => {
259+ assert . deepEqual ( codeberg . authHeader ( "cb_secret" ) , {
260+ Authorization : "token cb_secret" ,
261+ } )
262+ } )
0 commit comments