Skip to content

Commit 03ec085

Browse files
authored
feat: fetch repo metadata in staticProps (bazel-contrib#180)
By avoiding a client-side useEffect, we get static content that the search crawler will be able to index. Then the full-text search can match on content of the repo descriptions
1 parent d78c1b7 commit 03ec085

File tree

7 files changed

+117
-74
lines changed

7 files changed

+117
-74
lines changed

.github/workflows/deploy.yml

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ jobs:
2121
concurrency: ci-${{ github.ref }} # Recommended if you intend to make multiple deployments in quick succession.
2222
runs-on: ubuntu-latest
2323
steps:
24-
- name: Checkout 🛎️
25-
uses: actions/checkout@v5
24+
- uses: actions/checkout@v5
25+
with:
26+
submodules: true
2627

2728
- name: Install pnpm
2829
uses: pnpm/action-setup@v2.4.1
@@ -33,10 +34,6 @@ jobs:
3334
run: |
3435
./install_bins.sh
3536
36-
- name: Checkout BCR submodule
37-
run: |
38-
git submodule update --init -- data/bazel-central-registry
39-
4037
- name: Checkout latest commit of BCR submodule
4138
if: ${{ !inputs.bcrCommitHash }}
4239
working-directory: data/bazel-central-registry
@@ -49,6 +46,26 @@ jobs:
4946
run: |
5047
git checkout ${{ inputs.bcrCommitHash }}
5148
49+
- name: Find latest successful run of another workflow
50+
id: find-run
51+
env:
52+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53+
run: |
54+
run_id=$(gh run list \
55+
--workflow "fetch_repo_metadata.yml" \
56+
--branch main \
57+
--json databaseId,status,conclusion \
58+
--jq 'map(select(.status=="completed" and .conclusion=="success")) | first | .databaseId')
59+
echo "run_id=$run_id" >> $GITHUB_OUTPUT
60+
61+
- name: Download and extract artifact
62+
env:
63+
GH_TOKEN: ${{ github.token }}
64+
run: |
65+
gh run download ${{ steps.find-run.outputs.run_id }} \
66+
--name github_metadata \
67+
--dir data/github_metadata
68+
5269
- name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
5370
run: |
5471
pnpm install --frozen-lockfile

.github/workflows/test.yml

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ jobs:
1212
concurrency: ci-${{ github.ref }} # Recommended if you intend to make multiple deployments in quick succession.
1313
runs-on: ubuntu-latest
1414
steps:
15-
- name: Checkout 🛎️
16-
uses: actions/checkout@v5
15+
- uses: actions/checkout@v5
16+
with:
17+
submodules: true
1718

1819
- name: Install pnpm
1920
uses: pnpm/action-setup@v2.4.1
@@ -29,10 +30,6 @@ jobs:
2930
- name: Check prettier formatting
3031
run: pnpm prettier-check
3132

32-
- name: Checkout BCR submodule
33-
run: |
34-
git submodule update --init -- data/bazel-central-registry
35-
3633
- name: Checkout latest commit of BCR submodule
3734
if: ${{ !inputs.bcrCommitHash }}
3835
working-directory: data/bazel-central-registry
@@ -45,6 +42,26 @@ jobs:
4542
run: |
4643
git checkout ${{ inputs.bcrCommitHash }}
4744
45+
- name: Find latest successful run of another workflow
46+
id: find-run
47+
env:
48+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
49+
run: |
50+
run_id=$(gh run list \
51+
--workflow "fetch_repo_metadata.yml" \
52+
--branch main \
53+
--json databaseId,status,conclusion \
54+
--jq 'map(select(.status=="completed" and .conclusion=="success")) | first | .databaseId')
55+
echo "run_id=$run_id" >> $GITHUB_OUTPUT
56+
57+
- name: Download and extract artifact
58+
env:
59+
GH_TOKEN: ${{ github.token }}
60+
run: |
61+
gh run download ${{ steps.find-run.outputs.run_id }} \
62+
--name github_metadata \
63+
--dir data/github_metadata
64+
4865
- name: Build 🔧 # Outputs the result to the 'build' folder.
4966
run: pnpm run build
5067
env:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ yarn-error.log*
4040
.netlify
4141

4242
/bazel-*
43+
/data/github_metadata/*.json

data/githubMetadata.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as fs from 'fs'
2+
import * as path from 'path'
3+
4+
export interface GithubRepositoryMetadata {
5+
description: string | null
6+
license: { spdx_id: string; name: string; url: string } | null
7+
topics: string[] | null
8+
stargazers: number | null
9+
}
10+
11+
/**
12+
* Reads GitHub metadata from static JSON files generated by GitHub Actions.
13+
* This replaces client-side API calls with build-time static data.
14+
*/
15+
export async function getGithubRepositoryMetadata(
16+
moduleName: string
17+
): Promise<GithubRepositoryMetadata | null> {
18+
try {
19+
const metadataPath = path.join(
20+
process.cwd(),
21+
'data',
22+
'github_metadata',
23+
`${moduleName}.github_metadata.json`
24+
)
25+
26+
if (!fs.existsSync(metadataPath)) {
27+
return null
28+
}
29+
30+
const fileContent = fs.readFileSync(metadataPath, 'utf-8')
31+
const rawData = JSON.parse(fileContent)
32+
33+
// Transform the GitHub API response format to our interface
34+
return {
35+
description: rawData.description || null,
36+
license: rawData.licenseInfo
37+
? {
38+
spdx_id: rawData.licenseInfo.key || '',
39+
name: rawData.licenseInfo.name || '',
40+
url: `https://opensource.org/licenses/${rawData.licenseInfo.key}`,
41+
}
42+
: null,
43+
topics:
44+
rawData.repositoryTopics?.nodes?.map((topic: any) => topic.name) ||
45+
null,
46+
stargazers: rawData.stargazerCount || null,
47+
}
48+
} catch (error) {
49+
console.warn(`Failed to read GitHub metadata for ${moduleName}:`, error)
50+
return null
51+
}
52+
}

data/github_metadata/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This folder is populated during CI runs by downloading a GitHub Actions artifact.
2+
See .github/workflows/fetch_repo_metadata.yml

data/moduleStaticProps.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ModuleInfo,
88
reverseDependencies,
99
} from './utils'
10+
import { getGithubRepositoryMetadata } from './githubMetadata'
1011

1112
export interface VersionInfo {
1213
version: string
@@ -44,12 +45,19 @@ export const getStaticPropsModulePage = async (
4445
const latestVersion = versions[0]
4546
const selectedVersion = version || latestVersion
4647

48+
// Get GitHub metadata from static JSON files
49+
const githubMetadata = await getGithubRepositoryMetadata(module)
50+
if (!githubMetadata) {
51+
console.warn(`No GitHub metadata found for module ${module}`)
52+
}
53+
4754
return {
4855
props: {
4956
metadata,
5057
versionInfos,
5158
selectedVersion,
5259
reverseDependencies: await reverseDependencies(module),
60+
githubMetadata,
5361
},
5462
}
5563
}

pages/modules/[module].tsx

Lines changed: 8 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
getStaticPropsModulePage,
1818
VersionInfo,
1919
} from '../../data/moduleStaticProps'
20+
import { GithubRepositoryMetadata } from '../../data/githubMetadata'
2021
import { formatDistance, parseISO } from 'date-fns'
2122
import { faGlobe, faScaleBalanced } from '@fortawesome/free-solid-svg-icons'
2223

@@ -25,6 +26,7 @@ interface ModulePageProps {
2526
versionInfos: VersionInfo[]
2627
selectedVersion: string
2728
reverseDependencies: string[]
29+
githubMetadata: GithubRepositoryMetadata | null
2830
}
2931

3032
const GITHUB_API_USER_AGENT = 'Bazel Central Registry UI'
@@ -40,6 +42,7 @@ const ModulePage: NextPage<ModulePageProps> = ({
4042
versionInfos,
4143
selectedVersion,
4244
reverseDependencies,
45+
githubMetadata,
4346
}) => {
4447
const router = useRouter()
4548
const { module } = router.query
@@ -61,12 +64,11 @@ const ModulePage: NextPage<ModulePageProps> = ({
6164
selectedVersion
6265
)
6366

64-
const {
65-
description: repoDescription,
66-
license: repoLicense,
67-
topics: repoTopics,
68-
stargazers: repoStargazers,
69-
} = useGithubMetadata(firstGithubRepository)
67+
// Use GitHub metadata from static build-time data instead of client-side hook
68+
const repoDescription = githubMetadata?.description || undefined
69+
const repoLicense = githubMetadata?.license || undefined
70+
const repoTopics = githubMetadata?.topics || undefined
71+
const repoStargazers = githubMetadata?.stargazers || undefined
7072

7173
const isQualifiedForShowAllVersions =
7274
versionInfos.length > NUM_VERSIONS_ON_PAGE_LOAD
@@ -621,60 +623,4 @@ const useDetectReleaseFormatViaGithubApi = (
621623
return releaseTagFormat
622624
}
623625

624-
const useGithubMetadata = (metadataRepository: string | undefined) => {
625-
const githubOwnerAndRepo = metadataRepository?.replace('github:', '')
626-
const [description, setDescription] = useState<string | undefined>(undefined)
627-
const [license, setLicense] = useState<
628-
{ spdx_id: string; name: string; url: string } | undefined
629-
>()
630-
const [topics, setTopics] = useState<string[]>([])
631-
const [stargazers, setStargazers] = useState<number | undefined>(undefined)
632-
633-
useEffect(() => {
634-
const fetchRepoDescription = async () => {
635-
if (!githubOwnerAndRepo) {
636-
return
637-
}
638-
639-
try {
640-
const response = await fetch(
641-
`https://api.github.com/repos/${githubOwnerAndRepo}`,
642-
{
643-
method: 'GET',
644-
headers: {
645-
Accept: 'application/vnd.github+json',
646-
'User-Agent': GITHUB_API_USER_AGENT,
647-
'X-GitHub-Api-Version': GITHUB_API_VERSION,
648-
},
649-
}
650-
)
651-
652-
if (response.ok) {
653-
const repoData = await response.json()
654-
setStargazers(repoData.stargazers_count)
655-
setDescription(repoData.description)
656-
if (repoData.license) {
657-
setLicense(repoData.license)
658-
}
659-
660-
if (Array.isArray(repoData.topics)) {
661-
setTopics(repoData.topics)
662-
}
663-
}
664-
} catch (error) {
665-
console.error('Failed to fetch repository description:', error)
666-
}
667-
}
668-
669-
fetchRepoDescription()
670-
}, [githubOwnerAndRepo])
671-
672-
return {
673-
description,
674-
license,
675-
topics,
676-
stargazers,
677-
}
678-
}
679-
680626
export default ModulePage

0 commit comments

Comments
 (0)