+
+export const ForgejoReleaseSchama = v.object({
+ id: v.number(),
+ tag_name: v.string(),
+ name: v.string(),
+ body: v.string(),
+ html_url: v.pipe(v.string(), v.url()),
+ draft: v.boolean(),
+ prerelease: v.boolean(),
+ published_at: v.pipe(v.string(), v.isoTimestamp()),
+})
+
+export const ForgejoReleaseCollectionSchema = v.array(ForgejoReleaseSchama)
+
+export const GitlabReleaseSchame = v.object({
+ tag_name: v.string(),
+ name: v.string(),
+ description: v.string(),
+ released_at: v.pipe(v.string(), v.isoTimestamp()),
+ upcoming_release: v.boolean(),
+ commit: v.object({
+ short_id: v.string(),
+ }),
+ _links: v.object({
+ self: v.pipe(v.string(), v.url()),
+ }),
+})
+
+export const GitlabReleaseCollectionSchema = v.array(GitlabReleaseSchame)
diff --git a/shared/types/changelog.ts b/shared/types/changelog.ts
index d3e5f5858b..d885882467 100644
--- a/shared/types/changelog.ts
+++ b/shared/types/changelog.ts
@@ -6,6 +6,7 @@ export interface ChangelogReleaseInfo {
provider: ProviderId
repo: `${string}/${string}`
link: string
+ host?: string
}
export interface ChangelogMarkdownInfo {
@@ -20,6 +21,7 @@ export interface ChangelogMarkdownInfo {
* link to a rendered changelog markdown file
*/
link: string
+ host?: string
}
export type ChangelogInfo = ChangelogReleaseInfo | ChangelogMarkdownInfo
@@ -33,4 +35,5 @@ export interface ReleaseData {
publishedAt?: string
toc?: TocItem[]
link: string
+ tag: string
}
diff --git a/shared/utils/constants.ts b/shared/utils/constants.ts
index 955cfe76ce..529e5947be 100644
--- a/shared/utils/constants.ts
+++ b/shared/utils/constants.ts
@@ -45,14 +45,15 @@ export const ERROR_GRAVATAR_FETCH_FAILED = 'Failed to fetch Gravatar profile.'
export const ERROR_GRAVATAR_EMAIL_UNAVAILABLE = "User's email not accessible."
export const ERROR_NEED_REAUTH = 'User needs to reauthenticate'
-export const ERROR_CHANGELOG_NOT_FOUND =
- 'No releases or changelogs have been found for this package'
+export const ERROR_CHANGELOG_NOT_FOUND = 'No release or changelog had been found for this package'
export const ERROR_CHANGELOG_RELEASES_FAILED = 'Failed to get releases'
export const ERROR_CHANGELOG_FILE_FAILED = 'Failed to get changelog markdown'
export const ERROR_THROW_INCOMPLETE_PARAM = "Couldn't do request due to incomplete parameters"
// for ungh.cc when api keys are exhausted, name is broad in case more proxies are going to be used
export const ERROR_UNGH_API_KEY_EXHAUSTED =
"Couldn't fetch resources due to ungh api keys being exhausted"
+export const ERROR_UNKNOWN_GIT_HOST =
+ 'No host given or given host is not a known host for the given provider'
// microcosm services
export const CONSTELLATION_HOST = 'constellation.microcosm.blue'
diff --git a/shared/utils/git-providers.ts b/shared/utils/git-providers.ts
index e4ba18dfd7..050ecf046c 100644
--- a/shared/utils/git-providers.ts
+++ b/shared/utils/git-providers.ts
@@ -288,6 +288,8 @@ export function normalizeGitUrl(input: string): string | null {
return url.includes('://') ? url : `https://${url}`
}
+export const NEED_HOST = ['gitlab', 'gitea', 'forgejo', 'radicle']
+
export function parseRepoUrl(input: string): RepoRef | null {
const normalized = normalizeGitUrl(input)
if (!normalized) return null
@@ -301,7 +303,7 @@ export function parseRepoUrl(input: string): RepoRef | null {
if (!provider.matchHost(host)) continue
const parsed = provider.parsePath(parts)
if (parsed) {
- const needsHost = ['gitlab', 'gitea', 'forgejo', 'radicle'].includes(provider.id)
+ const needsHost = NEED_HOST.includes(provider.id)
return {
provider: provider.id,
owner: parsed.owner,
@@ -393,3 +395,11 @@ export const ALL_KNOWN_GIT_API_ORIGINS: readonly string[] = [
...FORGEJO_HOSTS.map(host => `https://${host}`),
...GITEA_HOSTS.map(host => `https://${host}`),
]
+
+/**
+ * validates whether the given host is part of the known hosts of a provider
+ */
+export function validateHost(provider: ProviderId, host: string) {
+ const providerConfig = providers.find(config => config.id == provider)
+ return !!providerConfig?.matchHost(host)
+}
diff --git a/test/nuxt/a11y.spec.ts b/test/nuxt/a11y.spec.ts
index a44ef8acf2..61d2be2977 100644
--- a/test/nuxt/a11y.spec.ts
+++ b/test/nuxt/a11y.spec.ts
@@ -274,6 +274,7 @@ import {
TabList,
TabItem,
TabPanel,
+ ButtonCopyMd,
} from '#components'
// Server variant components must be imported directly to test the server-side render
@@ -2810,6 +2811,21 @@ describe('component accessibility audits', () => {
})
})
+ describe('ButtonCopyMd', () => {
+ it('should have no accessibility violations', async () => {
+ const component = await mountSuspended(ButtonCopyMd, {
+ props: {
+ fetchMarkdown: () => Promise.resolve(),
+ markdown: '# hallo',
+ status: 'success',
+ text: 'copy test',
+ },
+ })
+ const results = await runAxe(component)
+ expect(results.violations).toEqual([])
+ })
+ })
+
describe('CallToAction', () => {
it('should have no accessibility violations', async () => {
const component = await mountSuspended(CallToAction)
@@ -2848,7 +2864,9 @@ describe('component accessibility audits', () => {
title: '1.0.0',
publishedAt: '2026-02-11 10:00:00.000Z',
link: 'https://github.com/nuxt/nuxt/releases/tag/v4.4.5',
+ tag: 'test',
},
+ baseUrl: '/api/changelog/releases/test/test',
tocHeaderClass: 'toc',
},
})
diff --git a/test/unit/server/utils/changelog/markdown.spec.ts b/test/unit/server/utils/changelog/markdown.spec.ts
index 05302f3277..55f841b1b7 100644
--- a/test/unit/server/utils/changelog/markdown.spec.ts
+++ b/test/unit/server/utils/changelog/markdown.spec.ts
@@ -1,5 +1,6 @@
import type { MarkdownRepoInfo } from '~~/server/utils/changelog/markdown'
import { describe, expect, it, vi, beforeAll } from 'vitest'
+import { createGithubRepoInfo, createGitLabRepoInfo } from '~~/server/utils/changelog/mdRepoInfo'
// testing changelog specific needs, others things are tested at ../readme.spec.ts
@@ -22,18 +23,11 @@ beforeAll(() => {
const { changelogRenderer } = await import('#server/utils/changelog/markdown')
function changelogMdinfo(): MarkdownRepoInfo {
- return {
- blobBaseUrl: `https://github.com/test-owner/test-repo/blob/HEAD`,
- rawBaseUrl: `https://raw.githubusercontent.com/test-owner/test-repo/HEAD`,
- }
+ return createGithubRepoInfo('test-owner', 'test-repo')
}
function changelogMdInfoWithPath() {
- return {
- blobBaseUrl: `https://github.com/test-owner/test-repo/blob/HEAD`,
- rawBaseUrl: `https://raw.githubusercontent.com/test-owner/test-repo/HEAD`,
- path: 'packages/test/changelog.md',
- }
+ return createGithubRepoInfo('test-owner', 'test-repo', 'packages/test/changelog.md')
}
describe('URL Resolution', () => {
@@ -518,25 +512,267 @@ describe('Heading & toc resolution', () => {
})
})
-describe('ATX heading #issue/#pr exemption', () => {
- it("shouldn't turn issues/PRs into headings", async () => {
+describe('Turn plaintext #isssue/#pr, !pr, @account & commmit into links', () => {
+ describe('ATX heading #issue/#pr exemption & turn into links', () => {
+ it("shouldn't turn issues/PRs into headings but into links", async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+ const markdown = `#2869 hello
+
+ #2717 world`
+
+ const result = renderer(markdown)
+ expect(result.html).toBe(
+ '#2869 hello
\n #2717 world
\n',
+ )
+ })
+
+ it("shouldn't turn issues/PRs in list into headings but into links", async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+ const markdown = `- #2869 hello
+- #2717 world`
+
+ const result = renderer(markdown)
+ expect(result.html).toBe(
+ '\n',
+ )
+ })
+ })
+
+ it('should turn issue/pr & account into links', async () => {
const info = changelogMdinfo()
const renderer = await changelogRenderer(info)
- const markdown = `#2869 hello
+ // text from date-fns v4.3.0
+ const markdown = `- Fixed pt locale first day of week to be Sunday. See #4195 by @ImRodry.
+- Fixed zh-CN, zh-HK, and zh-TW locale month parsing for October, November, and December. See #4194 by @puneetdixit200.
+`
+ const result = renderer(markdown)
-#2717 world`
+ expect(result.html).toBe(`
+- Fixed pt locale first day of week to be Sunday. See #4195 by @ImRodry.
+- Fixed zh-CN, zh-HK, and zh-TW locale month parsing for October, November, and December. See #4194 by @puneetdixit200.
+
+`)
+ })
+
+ it('should turn issue/pr into links between ()', async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+ // text comes from npmx release 0.15.0
+ const markdown = `- Minor ui improvements (#2834)
+- deps: Update module-replacements (#2838)
+- Release v0.15.0 (#2835)`
const result = renderer(markdown)
- expect(result.html).toBe('#2869 hello
\n#2717 world
\n')
+
+ expect(result.html).toBe(`
+- Minor ui improvements (#2834)
+- deps: Update module-replacements (#2838)
+- Release v0.15.0 (#2835)
+
+`)
})
- it("shouldn't turn issues/PRs in list into headings", async () => {
+ it('should turn mutliple issue/pr after each other issues/pr into links', async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+ // test from fullcalendar v6.1.18
+ const markdown = 'fix: Optimize custom content-injection rerendering performance (#3003, #7650)'
+
+ const result = renderer(markdown)
+
+ expect(result.html).toBe(
+ `fix: Optimize custom content-injection rerendering performance (#3003, #7650)
\n`,
+ )
+ })
+
+ it('should turn accounts into lists', async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+ // from npmx release 0.13.0, wanted to a release with many accounts mentioned
+ const markdown = `### ❤️ Contributors\n\n- Daniel Roe (@danielroe)\n- Alex Savelyev (@alexdln)\n- Alec Lloyd Probert (@graphieros)\n- cylewaitforit (@cylewaitforit)\n- Vinayak (@VinayakMaharaj)\n- Robin de Vos (@Codefoxdev)\n- Patrick Dewey (@ptdewey)\n- Dominik Dorfmeister 🔮 (@TkDodo)\n- Philippe Serhal (@serhalp)\n- Wilco (@WilcoSp)\n- Willow (GHOST) (@ghostdevv)\n- Aryan Pingle (@aryanpingle)\n- Roman (@gameroman)\n- Matteo Gabriele (@MatteoGabriele)\n- Alberto Rico (@alrico88)\n- TAKAHASHI Shuuji (@shuuji3)\n- Bugo (@dragomano)\n- Sasha (@Sasha125588)\n- Iestyn (@IestynGage)\n- Torben Haack (@t128n)\n- Mutsumi (@BabyLy233)\n- Bonsak Schiledrop (@bonsak)\n`
+
+ const result = renderer(markdown)
+
+ expect(result.html)
+ .toBe(`
+
+`)
+ })
+
+ it('should not turn @org/package into account link', async () => {
const info = changelogMdinfo()
const renderer = await changelogRenderer(info)
- const markdown = `- #2869 hello
-- #2717 world`
+
+ const markdown = `- Bump @tiptap/y-tiptap to version ^3.0.5\n- @tiptap/core@3.26.1\n - @tiptap/pm@3.26.1`
+
+ const result = renderer(markdown)
+
+ expect(result.html).toBe(`
+- Bump @tiptap/y-tiptap to version ^3.0.5
+- @tiptap/core@3.26.1
+
+
+`)
+ })
+
+ it('should turn commits into links', async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+ // from tiptap 3.27.1, 3.27.0, 3.26.0 & npmx 0.14.0 & 0.14.1
+ const markdown = `- a16901d: Fix ordered list parsing so under-indented continuation lines preserve their first character
+- Updated dependencies [6270b99]
+- 7fb19eb: Only add hash attributes to nodes, not to marks.
+- Release v0.14.0 36128a54
+- Empty (4cab893c)`
const result = renderer(markdown)
- expect(result.html).toBe('\n- #2869 hello
\n- #2717 world
\n
\n')
+
+ expect(result.html).toBe(`
+- a16901d: Fix ordered list parsing so under-indented continuation lines preserve their first character
+- Updated dependencies [6270b99]
+- 7fb19eb: Only add hash attributes to nodes, not to marks.
+- Release v0.14.0 36128a5
+- Empty (4cab893)
+
+`)
+ })
+
+ it('should not format an issue/pr into a commit', async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+
+ const markdown = `lorem ipsum is fixed in #1234567`
+
+ const result = renderer(markdown)
+
+ expect(result.html).toBe(
+ `lorem ipsum is fixed in #1234567
\n`,
+ )
+ })
+
+ it('should format gitlab merge requests', async () => {
+ const info = createGitLabRepoInfo('gitlab.com', 'test', 'test')
+ const renderer = await changelogRenderer(info)
+
+ const markdown = `!123 hallo\n\nhttps://gitlab.com/test/test/-/merge_requests/321 world`
+ const result = renderer(markdown)
+
+ expect(result.html).toBe(
+ `!123 hallo
+!321 world
+`,
+ )
+ })
+
+ it('should format at proto @account handle but not @version', async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+
+ const markdown = `nppmx @npmx.dev\n\n3po @3po.at.proto\n\nlorem @1.2.3 ipsum`
+ const result = renderer(markdown)
+
+ expect(result.html).toBe(
+ `nppmx @npmx.dev
+3po @3po.at.proto
+lorem @1.2.3 ipsum
+`,
+ )
+ })
+
+ it("shouldn't format package@version", async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+ const markdown = `install package with package@latest or specific version like package@1.2.3`
+
+ const result = renderer(markdown)
+ expect(result.html).toBe(
+ `install package with package@latest or specific version like package@1.2.3
+`,
+ )
+ })
+
+ it("shouldn't format email as git link", async () => {
+ const info = changelogMdinfo()
+ const renderer = await changelogRenderer(info)
+ const markdown = `email to test@package.test to get in contact`
+
+ const result = renderer(markdown)
+ expect(result.html).toBe(
+ `email to test@package.test to get in contact
+`,
+ )
+ })
+})
+
+describe('format unformatted/auto links to git', () => {
+ // links to account won't be formatted, this is something also git providers don't do
+ it('should turn issue, pr, commit & compare links to formatted links', async () => {
+ const info = createGithubRepoInfo('vueuse', 'vueuse')
+ const renderer = await changelogRenderer(info)
+ // from vueuse 14.3.0 (last 2 links changed from `issues` -> `pull`)
+ const markdown = `- Expose pointer event onLongPress - by mrcwbr in https://github.com/vueuse/vueuse/issues/5295 https://github.com/vueuse/vueuse/commit/b1688bd2
+- createInjectionState: Non-undefined return when default specified - by Laupetin in https://github.com/vueuse/vueuse/issues/5306 https://github.com/vueuse/vueuse/commit/b0c51c27
+- createReusableTemplate: Add support for specifying component names - by wbolster in https://github.com/vueuse/vueuse/pull/5300 https://github.com/vueuse/vueuse/commit/ea29d5cb
+- nuxt: Add composable variants to auto imports - by OrbisK in https://github.com/vueuse/vueuse/issues/5285 https://github.com/vueuse/vueuse/commit/ac2ef95d
+
+https://github.com/vueuse/vueuse/compare/v14.2.1...v14.3.0`
+
+ const result = renderer(markdown)
+ expect(result.html).toBe(`
+- Expose pointer event onLongPress - by mrcwbr in #5295 b1688bd
+- createInjectionState: Non-undefined return when default specified - by Laupetin in #5306 b0c51c2
+- createReusableTemplate: Add support for specifying component names - by wbolster in #5300 ea29d5c
+- nuxt: Add composable variants to auto imports - by OrbisK in #5285 ac2ef95
+
+v14.2.1...v14.3.0
+`)
+ })
+
+ it('should ignore formatted links', async () => {
+ const info = createGithubRepoInfo('vueuse', 'vueuse')
+ const renderer = await changelogRenderer(info)
+
+ const markdown = `- Expose pointer event onLongPress - by mrcwbr in https://github.com/vueuse/vueuse/issues/5295 https://github.com/vueuse/vueuse/commit/b1688bd2
+- createInjectionState: Non-undefined return when default specified - by Laupetin in [!5306](https://github.com/vueuse/vueuse/issues/5306) [(b0c51)](https://github.com/vueuse/vueuse/commit/b0c51c27)
+- createReusableTemplate: Add support for specifying component names - by wbolster in https://github.com/vueuse/vueuse/pull/5300 https://github.com/vueuse/vueuse/commit/ea29d5cb
+- nuxt: Add composable variants to auto imports - by OrbisK in [$5285](https://github.com/vueuse/vueuse/issues/5285) [(ac2ef)](https://github.com/vueuse/vueuse/commit/ac2ef95d)
+
+[View changes on GitHub](https://github.com/vueuse/vueuse/compare/v14.2.1...v14.3.0)`
+ const result = renderer(markdown)
+ expect(result.html).toBe(`
+- Expose pointer event onLongPress - by mrcwbr in #5295 b1688bd
+- createInjectionState: Non-undefined return when default specified - by Laupetin in !5306 (b0c51)
+- createReusableTemplate: Add support for specifying component names - by wbolster in #5300 ea29d5c
+- nuxt: Add composable variants to auto imports - by OrbisK in $5285 (ac2ef)
+
+View changes on GitHub
+`)
})
})
diff --git a/test/unit/server/utils/changelog/validateHost.spec.ts b/test/unit/server/utils/changelog/validateHost.spec.ts
new file mode 100644
index 0000000000..a83491fed9
--- /dev/null
+++ b/test/unit/server/utils/changelog/validateHost.spec.ts
@@ -0,0 +1,199 @@
+import type { ProviderId } from '~~/shared/utils/git-providers'
+import { describe, expect, it } from 'vitest'
+import { object, safeParse } from 'valibot'
+import { validateHostWithValibot } from '~~/server/utils/changelog/validateHost'
+
+function createSchema(provider: ProviderId) {
+ return object({
+ host: validateHostWithValibot(provider),
+ })
+}
+
+// host === 'radicle.at' || host === 'app.radicle.at' || host === 'seed.radicle.at',
+describe("shouldn't require 'host' from providers that don't need it", () => {
+ it('should allow github without host', () => {
+ const schema = createSchema('github')
+ expect(safeParse(schema, {}).success).toBeTruthy()
+ })
+
+ it('should allow codeberg without host', () => {
+ const schema = createSchema('codeberg')
+ expect(safeParse(schema, {}).success).toBeTruthy()
+ })
+
+ it('should allow tangled without host', () => {
+ const schema = createSchema('tangled')
+ expect(safeParse(schema, {}).success).toBeTruthy()
+ })
+})
+
+describe('should require host to be given', () => {
+ it('should require gitlab to have a host', () => {
+ const schema = createSchema('gitlab')
+ expect(safeParse(schema, {}).success).toBeFalsy()
+ })
+
+ it('should require forgejo to have a host', () => {
+ const schema = createSchema('forgejo')
+ expect(safeParse(schema, {}).success).toBeFalsy()
+ })
+
+ it('should require gitea to have a host', () => {
+ const schema = createSchema('gitea')
+ expect(safeParse(schema, {}).success).toBeFalsy()
+ })
+
+ it('should require radicle to have a host', () => {
+ const schema = createSchema('radicle')
+ expect(safeParse(schema, {}).success).toBeFalsy()
+ })
+})
+
+describe('should only allow known host for provider', () => {
+ describe('gitlab', () => {
+ it('should allow gitlab', () => {
+ const schema = createSchema('gitlab')
+ expect(safeParse(schema, { host: 'gitlab.com' }).success).toBeTruthy()
+ })
+
+ it('should allow framagit.org', () => {
+ const schema = createSchema('gitlab')
+ expect(safeParse(schema, { host: 'framagit.org' }).success).toBeTruthy()
+ })
+
+ it("shouldn't allow next.forgejo.org", () => {
+ const schema = createSchema('gitlab')
+ expect(safeParse(schema, { host: 'next.forgejo.org' }).success).toBeFalsy()
+ })
+ it("shouldn't allow gitea.com", () => {
+ const schema = createSchema('gitlab')
+ expect(safeParse(schema, { host: 'gitea.com' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow radicle.at", () => {
+ const schema = createSchema('gitlab')
+ expect(safeParse(schema, { host: 'radicle.at' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow seed.radicle.at", () => {
+ const schema = createSchema('gitlab')
+ expect(safeParse(schema, { host: 'seed.radicle.at' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow banana.org", () => {
+ const schema = createSchema('gitlab')
+ expect(safeParse(schema, { host: 'banana.org' }).success).toBeFalsy()
+ })
+ })
+
+ describe('forgejo', () => {
+ it("shouldn't allow gitlab", () => {
+ const schema = createSchema('forgejo')
+ expect(safeParse(schema, { host: 'gitlab.com' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow framagit.org", () => {
+ const schema = createSchema('forgejo')
+ expect(safeParse(schema, { host: 'framagit.org' }).success).toBeFalsy()
+ })
+
+ it('should allow next.forgejo.org', () => {
+ const schema = createSchema('forgejo')
+ expect(safeParse(schema, { host: 'next.forgejo.org' }).success).toBeTruthy()
+ })
+
+ it("shouldn't allow gitea.com", () => {
+ const schema = createSchema('forgejo')
+ expect(safeParse(schema, { host: 'gitea.com' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow radicle.at", () => {
+ const schema = createSchema('forgejo')
+ expect(safeParse(schema, { host: 'radicle.at' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow seed.radicle.at", () => {
+ const schema = createSchema('forgejo')
+ expect(safeParse(schema, { host: 'seed.radicle.at' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow banana.org", () => {
+ const schema = createSchema('forgejo')
+ expect(safeParse(schema, { host: 'banana.org' }).success).toBeFalsy()
+ })
+ })
+
+ describe('gitea', () => {
+ it("shouldn't allow gitlab", () => {
+ const schema = createSchema('gitea')
+ expect(safeParse(schema, { host: 'gitlab.com' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow framagit.org", () => {
+ const schema = createSchema('gitea')
+ expect(safeParse(schema, { host: 'framagit.org' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow next.forgejo.org", () => {
+ const schema = createSchema('gitea')
+ expect(safeParse(schema, { host: 'next.forgejo.org' }).success).toBeFalsy()
+ })
+
+ it('should allow gitea.com', () => {
+ const schema = createSchema('gitea')
+ expect(safeParse(schema, { host: 'gitea.com' }).success).toBeTruthy()
+ })
+
+ it("shouldn't allow radicle.at", () => {
+ const schema = createSchema('gitea')
+ expect(safeParse(schema, { host: 'radicle.at' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow seed.radicle.at", () => {
+ const schema = createSchema('gitea')
+ expect(safeParse(schema, { host: 'seed.radicle.at' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow banana.org", () => {
+ const schema = createSchema('gitea')
+ expect(safeParse(schema, { host: 'banana.org' }).success).toBeFalsy()
+ })
+ })
+
+ describe('radicle', () => {
+ it("shouldn't allow gitlab", () => {
+ const schema = createSchema('radicle')
+ expect(safeParse(schema, { host: 'gitlab.com' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow framagit.org", () => {
+ const schema = createSchema('radicle')
+ expect(safeParse(schema, { host: 'framagit.org' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow next.forgejo.org", () => {
+ const schema = createSchema('radicle')
+ expect(safeParse(schema, { host: 'next.forgejo.org' }).success).toBeFalsy()
+ })
+
+ it("shouldn't allow gitea.com", () => {
+ const schema = createSchema('radicle')
+ expect(safeParse(schema, { host: 'gitea.com' }).success).toBeFalsy()
+ })
+
+ it('should allow radicle.at', () => {
+ const schema = createSchema('radicle')
+ expect(safeParse(schema, { host: 'radicle.at' }).success).toBeTruthy()
+ })
+
+ it('should allow seed.radicle.at', () => {
+ const schema = createSchema('radicle')
+ expect(safeParse(schema, { host: 'seed.radicle.at' }).success).toBeTruthy()
+ })
+
+ it("shouldn't allow banana.org", () => {
+ const schema = createSchema('radicle')
+ expect(safeParse(schema, { host: 'banana.org' }).success).toBeFalsy()
+ })
+ })
+})