From a98b4258acf5568d5e45e53d4ef772fc20eaaaf6 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sun, 18 Feb 2024 19:34:21 +0000 Subject: [PATCH] Added ability to fetch and display GitHub metrics for a service --- .../components/things/ItemGitHubMetrics.astro | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 web/src/components/things/ItemGitHubMetrics.astro diff --git a/web/src/components/things/ItemGitHubMetrics.astro b/web/src/components/things/ItemGitHubMetrics.astro new file mode 100644 index 0000000..6d722dc --- /dev/null +++ b/web/src/components/things/ItemGitHubMetrics.astro @@ -0,0 +1,156 @@ +--- +import FontAwesome from "@components/form/FontAwesome.svelte"; +const { github } = Astro.props; + + +const [user, repo] = github.split("/"); + + +/** + * For a given `user/repo` fetch repository stats from the GitHub API data + * If API key is available through env var, use it to increase rate limit + * Returns the response data and status code (200 == success) + * @param repo + */ +const fetchGitHubData = async (repo: string) => { + const apiKey = import.meta.env.GITHUB_API_KEY; + const headers = new Headers(); + if (apiKey) { + headers.append("Authorization", `token ${apiKey}`); + } + + let data = {}; + let statusCode = 0; + + const response = await fetch(`https://api.github.com/repos/${repo}`, { + headers: headers, + }).catch((e) => { + console.error(`Network error: ${e.message}`); + // Return a placeholder response to handle this gracefully + return null; + }); + + // Check if fetch was successful but caught by the catch block + if (!response) { + return { data, statusCode: 503 }; // Use an appropriate error status code + } + + statusCode = response.status; + + // Only attempt to parse JSON if the response was OK + if (response.ok) { + data = await response.json(); + } else { + console.error(`HTTP error: Received status code ${response.status}`); + } + + return { data, statusCode }; +}; + + +/** + * Given a license object, return SPDX ID, or a formatted name + * @param license + */ +const formatLicense = (license: { spdx_id?: string, name?: string }) => { + if (!license) { + return "Unknown"; + } + if (license.spdx_id === "NOASSERTION") { + return "No License"; + } + return license.spdx_id; +} + +/** + * Given a (possibly large) number, return a formatted string + * E.g. If greater than thousand, then return in k format + * @param num + */ +const formatBigNumber = (num: number) => { + if (num > 1000) { + return `${(num / 1000).toFixed(1)}k`; + } + return num; +} + +// Initiate GitHub fetch, and make available to the component +const stats = await fetchGitHubData(github); + +const { + stargazers_count, forks_count, open_issues_count, language, license, owner, +} = stats.data; + + +--- + +
+ + + + {github} + + { stats.statusCode === 200 && stats.data && ( + + {formatBigNumber(stargazers_count)} + + + {formatBigNumber(forks_count)} + + + {formatBigNumber(open_issues_count)} + + + {formatLicense(license)} + + + {language} + + )} +
+ + +