Skip to content
Open
13 changes: 13 additions & 0 deletions server/api/changelog/md/[provider]/[owner]/[repo]/[...path].get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import { resolveURL } from 'ufo'
import * as v from 'valibot'
import { getBaseFileUrl } from '~~/server/utils/changelog/baseFileUrl'
import {
createBitbucketRepoInfo,
createForgejoRepoInfo,
createGiteaRepoInfo,
createGiteeRepoInfo,
createGithubRepoInfo,
createGitLabRepoInfo,
createSourcehutRepoInfo,
createTangledInfo,
} from '~~/server/utils/changelog/mdRepoInfo'
import { validateHostWithValibot } from '~~/server/utils/changelog/validateHost'
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 @@ -114,5 +119,13 @@ function getRepoInfo(
return createGitLabRepoInfo(host ?? 'gitlab.com', owner, repo, path)
case 'tangled':
return createTangledInfo(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,
})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add the same .catch() handler here as you did it for GitHub?
(Same for Gitee a few lines below)


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 seperate because they're seperately 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/main`,
raw: `https://gitee.com/${ref.owner}/${ref.repo}/raw/main`,
Comment on lines +59 to +60

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional that this hardcodes main? I believe it should be HEAD so we support arbitrary default branch names:

Suggested change
blob: `https://gitee.com/${ref.owner}/${ref.repo}/blob/main`,
raw: `https://gitee.com/${ref.owner}/${ref.repo}/raw/main`,
blob: `https://gitee.com/${ref.owner}/${ref.repo}/blob/HEAD`,
raw: `https://gitee.com/${ref.owner}/${ref.repo}/raw/HEAD`,

}
}
}
return null
}
Loading
Loading