From 406d712c266132723c9a2c5d8ea423c3b4526fa8 Mon Sep 17 00:00:00 2001 From: SplittyDev Date: Wed, 24 May 2023 00:01:43 +0200 Subject: [PATCH 1/5] Add GitLab client and util --- badgers-web/src/utils/GitLab.ts | 89 +++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 badgers-web/src/utils/GitLab.ts diff --git a/badgers-web/src/utils/GitLab.ts b/badgers-web/src/utils/GitLab.ts new file mode 100644 index 0000000..6b5a17b --- /dev/null +++ b/badgers-web/src/utils/GitLab.ts @@ -0,0 +1,89 @@ +// Supports GitLab API v4 + +/** + * GitLab API base url + */ +const API_BASE = 'https://gitlab.com/api/v4'; + +type ProjectInfo = { + owner: string + repo: string +} + +type GetRepositoryArgs = ProjectInfo & { + license: boolean +} + +/** + * A subset of the GitLab repository response. + * + * @see https://docs.gitlab.com/api/projects.html#get-single-project + */ +type GetRepositoryResponse = { + id: number + default_branch: string + name: string + license: { + key: string + name: string + nickname: string + } + forks_count: number + star_count: number +} + +type Release = { + name: string + tag_name: string + upcoming_release: boolean +} + +/** + * GitLab API client + */ +class GitLabClient { + privateToken: string + + constructor(privateToken: string) { + this.privateToken = privateToken + } + + /** + * Build a GitLab API url with authentication. + */ + buildUrl(path: string, query: Record = {}): string { + const queryArgs = { + ...query, + private_token: this.privateToken, + } + const queryString = Object + .entries(queryArgs) + .map(([key, value]) => `${key}=${encodeURIComponent(value)}`) + .join('&') + return `${API_BASE}/${path}?${queryString}` + } + + async getRepository({ owner, repo, license }: GetRepositoryArgs): Promise { + const repoId = encodeURIComponent(`${owner}/${repo}`) + const resp = await fetch(this.buildUrl(`projects/${repoId}`, { license })) + if (resp.status !== 200) return null + return await resp.json() as GetRepositoryResponse + } + + async getLatestRelease({ owner, repo }: ProjectInfo): Promise { + const repoId = encodeURIComponent(`${owner}/${repo}`) + const resp = await fetch(this.buildUrl(`projects/${repoId}/releases`)) + if (resp.status !== 200) return null + const releases = await resp.json() as Array + if (releases.length === 0) return null + const latestNonUpcomingRelease = releases.find(r => !r.upcoming_release) + if (latestNonUpcomingRelease === undefined) return null + return latestNonUpcomingRelease + } +} + +export default class GitLab { + static getClient(): GitLabClient { + return new GitLabClient(process.env.GITLAB_TOKEN as string); + } +} From ff57dd81d13d5d4e01ec72b09017e065d35163b0 Mon Sep 17 00:00:00 2001 From: SplittyDev Date: Wed, 24 May 2023 00:01:54 +0200 Subject: [PATCH 2/5] Update README with GitLab env --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60a0cd5..56a4898 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Building SpaceBadgers has been a labor of love, aiming to offer a superior, reli ## Development ### Environment Variables -> Paste this template into `badgers-web/.env.local` +> Paste this template into `badgers-web/.env.local` for local development ```py # Frontend Configuration @@ -53,7 +53,8 @@ NEXT_PUBLIC_WEB_PROTO = "http" # Web frontend protocol NEXT_PUBLIC_WEB_HOST = "127.0.0.1:3000" # Web frontend host # API Tokens -GITHUB_TOKEN = "ghp_Foo1234567" # Required for GitHub badges +GITHUB_TOKEN = "ghp_Foo1234567" # Required for GitHub badges (private token) +GITLAB_TOKEN = "glfoo-zKvC1234" # Required for GitLab badges (private token) CRATESIO_TOKEN = "cio51fdR1234567" # Required for crates.io badges ``` From 860c654d9db974b34ead058fa2a8a59fffd24880 Mon Sep 17 00:00:00 2001 From: SplittyDev Date: Wed, 24 May 2023 00:02:30 +0200 Subject: [PATCH 3/5] Add GitLab endpoints to homepage --- badgers-web/src/app/page.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/badgers-web/src/app/page.tsx b/badgers-web/src/app/page.tsx index 9fc9e93..edb88a0 100644 --- a/badgers-web/src/app/page.tsx +++ b/badgers-web/src/app/page.tsx @@ -145,6 +145,19 @@ export default function Home() { +
+
+ + + + + + + + + +
+
From 4124cf3f36a4fa9d2cdc1968925c56fcb8d9bdeb Mon Sep 17 00:00:00 2001 From: SplittyDev Date: Wed, 24 May 2023 00:02:52 +0200 Subject: [PATCH 4/5] Add GitLab license endpoint --- .../gitlab/license/[owner]/[repo]/route.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 badgers-web/src/app/gitlab/license/[owner]/[repo]/route.ts diff --git a/badgers-web/src/app/gitlab/license/[owner]/[repo]/route.ts b/badgers-web/src/app/gitlab/license/[owner]/[repo]/route.ts new file mode 100644 index 0000000..b228c72 --- /dev/null +++ b/badgers-web/src/app/gitlab/license/[owner]/[repo]/route.ts @@ -0,0 +1,21 @@ +import { NextRequest } from "next/server" + +import Badge from '@/utils/Badge' +import GitLab from '@/utils/GitLab' + +interface Params { + params: { + owner: string + repo: string + } +} + +export async function GET(request: NextRequest, { params: { owner, repo } }: Params) { + const repoData = await GitLab.getClient().getRepository({ owner, repo, license: true }) + const licenseName = repoData?.license?.nickname ?? repoData?.license?.key + return await Badge.generate(request, 'license', licenseName ?? 'unknown', { + color: !!licenseName ? 'blue' : 'gray' + }) +} + +export const runtime = 'edge' From 3d0eb8aaa1612cb14d6537fbf23c47e586a93074 Mon Sep 17 00:00:00 2001 From: SplittyDev Date: Wed, 24 May 2023 00:02:59 +0200 Subject: [PATCH 5/5] Add GitLab release endpoint --- .../gitlab/release/[owner]/[repo]/route.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 badgers-web/src/app/gitlab/release/[owner]/[repo]/route.ts diff --git a/badgers-web/src/app/gitlab/release/[owner]/[repo]/route.ts b/badgers-web/src/app/gitlab/release/[owner]/[repo]/route.ts new file mode 100644 index 0000000..e7a3ad6 --- /dev/null +++ b/badgers-web/src/app/gitlab/release/[owner]/[repo]/route.ts @@ -0,0 +1,23 @@ +import { NextRequest } from "next/server" + +import Badge from '@/utils/Badge' +import GitLab from '@/utils/GitLab' + +interface Params { + params: { + owner: string + repo: string + } +} + +export async function GET(request: NextRequest, { params: { owner, repo } }: Params) { + const release = await GitLab.getClient().getLatestRelease({ owner, repo }) + const shortestName = [release?.tag_name, release?.name] + .filter(Boolean) + .reduce((a, b) => a!.length < b!.length ? a : b) + return await Badge.generate(request, 'release', shortestName ?? 'None', { + color: !!shortestName ? 'blue' : 'yellow' + }) +} + +export const runtime = 'edge'