Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4973633
added support for gitea for changelogs
WilcoSp Sep 2, 2026
36d2ac9
...
WilcoSp Sep 2, 2026
0756d22
adding support for bitbucket to changelog
WilcoSp Sep 2, 2026
cc30bd0
added an timeout & added fallback for if gitea host isn't defined
WilcoSp Sep 2, 2026
d04de2a
adding more timeout when trying to retrieve markdown from releases
WilcoSp Sep 2, 2026
36c408f
handling timeout
WilcoSp Sep 2, 2026
be0c0ba
added support for sourcehut
WilcoSp Sep 9, 2026
dcb22eb
fixed forgotten base urls for sourcehut
WilcoSp Sep 9, 2026
f80b041
..
WilcoSp Sep 9, 2026
3b3e2ce
..
WilcoSp Sep 9, 2026
9090c84
Merge branch 'npmx-dev:main' into changelog/gitea
WilcoSp Sep 12, 2026
444487b
added support for gitee
WilcoSp Sep 12, 2026
29e36c6
added support for getting markdown from gitea & gitee
WilcoSp Sep 12, 2026
ca52fec
..
WilcoSp Sep 12, 2026
acb5674
fixed some issues & made gitee issues case insensitive
WilcoSp Sep 13, 2026
d99597f
source hut now also has support for issues
WilcoSp Sep 16, 2026
5e70f3c
added tests for commits
WilcoSp Sep 16, 2026
440bcfd
added tests to parse plain links
WilcoSp Sep 16, 2026
b48f102
Merge branch 'main' into changelog/gitea
WilcoSp Sep 16, 2026
f50adc3
corrected gitee issue IDs
WilcoSp Sep 17, 2026
8afa301
Merge branch 'changelog/gitea' of github.com:WilcoSp/npmx.dev into ch…
WilcoSp Sep 17, 2026
e225494
Update server/utils/changelog/baseFileUrl.ts
trueberryless Sep 19, 2026
18e8db4
Merge branch 'main' into changelog/gitea
trueberryless Sep 19, 2026
a4cef05
Merge branch 'main' into changelog/gitea
trueberryless Sep 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions server/api/changelog/md/[provider]/[owner]/[repo]/[...path].get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import { resolveURL } from 'ufo'
import * as v from 'valibot'
import { getBaseFileUrl } from '~~/server/utils/changelog/baseFileUrl'
import {
createBitbucketRepoInfo,
createForgejoRepoInfo,
createGiteaRepoInfo,
createGiteeRepoInfo,
createGithubRepoInfo,
createGitLabRepoInfo,
createTangledInfo,
createSourcehutRepoInfo,
createTangledRepoInfo,
} from '~~/server/utils/changelog/mdRepoInfo'
import { validateHostWithValibot } from '~~/server/utils/changelog/validateHost'
import {
Expand Down Expand Up @@ -56,6 +60,7 @@ export default defineCachedEventHandler(
headers: {
'User-Agent': 'npmx.dev',
},
timeout: 15_000,
})
const markdown = v.parse(v.string(), data)
if (raw != undefined) {
Expand Down Expand Up @@ -113,6 +118,14 @@ function getRepoInfo(
case 'gitlab':
return createGitLabRepoInfo(host ?? 'gitlab.com', owner, repo, path)
case 'tangled':
return createTangledInfo(owner, repo, path)
return createTangledRepoInfo(owner, repo, path)
case 'gitea':
return createGiteaRepoInfo(host ?? 'gitea.com', owner, repo, path)
case 'bitbucket':
return createBitbucketRepoInfo(owner, repo, path)
case 'sourcehut':
return createSourcehutRepoInfo(owner, repo, path)
case 'gitee':
return createGiteeRepoInfo(owner, repo, path)
}
}
74 changes: 73 additions & 1 deletion server/api/changelog/releases/[provider]/[owner]/[repo].get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@ import {
GithubReleaseCollectionSchama,
ForgejoReleaseCollectionSchema,
GitlabReleaseCollectionSchema,
GiteaReleaseCollectionSchema,
GiteeReleaseCollectionSchema,
} from '~~/shared/schemas/changelog/release'
import { changelogRenderer } from '~~/server/utils/changelog/markdown'
import { createForgejoRepoInfo, createGithubRepoInfo } from '~~/server/utils/changelog/mdRepoInfo'
import {
createForgejoRepoInfo,
createGiteaRepoInfo,
createGithubRepoInfo,
} from '~~/server/utils/changelog/mdRepoInfo'
import { validateHostWithValibot } from '~~/server/utils/changelog/validateHost'

const TIMEOUT_TIME = 15_000

export default defineCachedEventHandler(
async event => {
const provider = getRouterParam(event, 'provider') as ProviderId
Expand All @@ -39,6 +47,10 @@ export default defineCachedEventHandler(
return await getReleasesFromForgejo(owner, repo, host)
case 'gitlab':
return await getReleasesFromGitlab(owner, repo, host)
case 'gitea':
return await getReleasesFromGitea(owner, repo, host)
case 'gitee':
return await getReleasesFromGitee(owner, repo)

default:
throw createError({
Expand Down Expand Up @@ -79,6 +91,7 @@ async function getReleasesFromGithub(owner: string, repo: string) {
'Accept': '*/*',
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
})

const { releases } = v.parse(GithubReleaseCollectionSchama, data)
Expand Down Expand Up @@ -107,6 +120,7 @@ async function getReleasesFromForgejo(owner: string, repo: string, host: string)
headers: {
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
})
const releases = v.parse(ForgejoReleaseCollectionSchema, data)

Expand Down Expand Up @@ -137,6 +151,7 @@ async function getReleasesFromGitlab(owner: string, repo: string, host: string)
headers: {
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
})

const releases = v.parse(GitlabReleaseCollectionSchema, data)
Expand All @@ -158,3 +173,60 @@ async function getReleasesFromGitlab(owner: string, repo: string, host: string)
} satisfies ReleaseData
})
}

async function getReleasesFromGitea(owner: string, repo: string, host: string) {
const data = await $fetch(`https://${host}/api/v1/repos/${owner}/${repo}/releases?draft=false`, {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
headers: {
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
})
const releases = v.parse(GiteaReleaseCollectionSchema, data)

const render = await changelogRenderer(createGiteaRepoInfo(host, owner, repo))

return releases.map(r => {
const { html, toc } = render(r.body, r.id)
return {
id: r.id,
html: html?.replace(/(?<!>)\n/g, '<br>') ?? null,
title: r.name || r.tag_name,
prerelease: r.prerelease,
toc,
link: r.html_url,
publishedAt: r.published_at,
draft: r.draft,
tag: r.tag_name,
} satisfies ReleaseData
})
}

async function getReleasesFromGitee(owner: string, repo: string) {
const data = await $fetch(
`https://gitee.com/api/v5/repos/${owner}/${repo}/releases?per_page=30`,
{
headers: {
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
},
)

const releases = v.parse(GiteeReleaseCollectionSchema, data)

const render = await changelogRenderer(createGiteeRepoInfo(owner, repo))

return releases.map(r => {
const { html, toc } = render(r.body, r.id)
return {
id: r.id,
html: html?.replace(/(?<!>)\n/g, '<br>') ?? null,
title: r.name || r.tag_name,
prerelease: r.prerelease,
toc,
link: `https://gitee.com/${owner}/${repo}/releases/tag/${r.tag_name}`,
publishedAt: r.created_at,
tag: r.tag_name,
} satisfies ReleaseData
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ import * as v from 'valibot'
import { ERROR_THROW_INCOMPLETE_PARAM } from '~~/shared/utils/constants'
import {
ForgejoReleaseSchama,
GiteaReleaseSchema,
GiteeReleaseSchema,
GithubReleaseCollectionSchama,
GitlabReleaseSchame,
} from '~~/shared/schemas/changelog/release'
import { validateHostWithValibot } from '~~/server/utils/changelog/validateHost'

const TIMEOUT_TIME = 15_000

export default defineCachedEventHandler(
async event => {
const provider = getRouterParam(event, 'provider') as ProviderId
Expand Down Expand Up @@ -40,6 +44,10 @@ export default defineCachedEventHandler(
return await getMarkdownFromForgejo(owner, repo, encodedTag, host)
case 'gitlab':
return await getMarkdownFromGitlab(owner, repo, encodedTag, host)
case 'gitea':
return await getMarkdownFromGitea(owner, repo, encodedTag, host)
case 'gitee':
return await getMarkdownFromGitee(owner, repo, encodedTag)
default:
throw createError({
status: 404,
Expand Down Expand Up @@ -84,8 +92,9 @@ async function getMarkdownFromGithub(owner: string, repo: string, tag: string, e
'User-Agent': 'npmx.dev',
},
ignoreResponseError: true,
timeout: TIMEOUT_TIME,
},
)
).catch(() => null)

const parsed = v.safeParse(v.object({ body: v.string() }), responseGithub)

Expand All @@ -101,6 +110,7 @@ async function getMarkdownFromGithub(owner: string, repo: string, tag: string, e
'Accept': '*/*',
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
})

const { releases } = v.parse(GithubReleaseCollectionSchama, responseUngh)
Expand Down Expand Up @@ -129,6 +139,7 @@ async function getMarkdownFromForgejo(
headers: {
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
})

const release = v.parse(ForgejoReleaseSchama, data)
Expand All @@ -150,9 +161,50 @@ async function getMarkdownFromGitlab(
headers: {
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
})

const release = v.parse(GitlabReleaseSchame, data)

return release.description
}

async function getMarkdownFromGitea(
owner: string,
repo: string,
/** tag should be encoded */
tag: string,
host: string = 'gitea.com',
) {
const data = await $fetch(`https://${host}/api/v1/repos/${owner}/${repo}/releases/tags/${tag}`, {
headers: {
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
})
Comment thread
WilcoSp marked this conversation as resolved.

const release = v.parse(GiteaReleaseSchema, data)

return release.body
}

async function getMarkdownFromGitee(
owner: string,
repo: string,
/** tag should be encoded */
tag: string,
) {
const data = await $fetch(
`https://gitee.com/api/v5/repos/${owner}/${repo}/releases/tags/${tag}`,
{
headers: {
'User-Agent': 'npmx.dev',
},
timeout: TIMEOUT_TIME,
},
)

const release = v.parse(GiteeReleaseSchema, data)

return release.body
}
27 changes: 26 additions & 1 deletion server/utils/changelog/baseFileUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ export function getBaseFileUrl(ref: RepoRef): RepoFileUrl | null {
raw: `https://codeberg.org/${ref.owner}/${ref.repo}/raw/branch/HEAD`,
}
case 'forgejo': {
const host = ref.host
return {
blob: `https://${ref.host}/${ref.owner}/${ref.repo}/src/branch/HEAD`,
raw: `https://${ref.host}/${ref.owner}/${ref.repo}/raw/branch/HEAD`,
}
}
case 'gitea': {
// although similar to forgejo, we keep these separate because they're separately maintained projects
const host = ref.host ?? 'gitea.com'
return {
blob: `https://${host}/${ref.owner}/${ref.repo}/src/branch/HEAD`,
raw: `https://${host}/${ref.owner}/${ref.repo}/raw/branch/HEAD`,
Expand All @@ -35,6 +42,24 @@ export function getBaseFileUrl(ref: RepoRef): RepoFileUrl | null {
raw: `https://tangled.org/${ref.owner}/${ref.repo}/raw/HEAD`,
}
}
case 'bitbucket': {
return {
blob: `https://bitbucket.org/${ref.owner}/${ref.repo}/src/HEAD`,
raw: `https://bitbucket.org/${ref.owner}/${ref.repo}/raw/HEAD`,
}
}
case 'sourcehut': {
return {
blob: `https://git.sr.ht/${ref.owner}/${ref.repo}/tree/HEAD/item`,
raw: `https://git.sr.ht/${ref.owner}/${ref.repo}/blob/HEAD`,
}
}
case 'gitee': {
return {
blob: `https://gitee.com/${ref.owner}/${ref.repo}/blob/HEAD`,
raw: `https://gitee.com/${ref.owner}/${ref.repo}/raw/HEAD`,
}
}
}
return null
}
Loading
Loading