fix(status.app): fetch the specs submodule at build time

This commit is contained in:
jinhojang6
2026-08-25 01:08:16 +09:00
committed by Jinho Jang
parent 5fcfd013d9
commit 9bd0e45384
3 changed files with 105 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'status.app': patch
---
fix(status.app): guarantee the specs submodule is present before the build
+2
View File
@@ -13,8 +13,10 @@
"dev:next": "next dev --turbopack --port 3001",
"dev:content": "contentlayer2 dev",
"watch:content": "node --watch-path=./content --watch-preserve-output ./scripts/trigger-content-compilation.cjs",
"prebuild": "node scripts/ensure-specs-content.mjs",
"build": "pnpm lint && pnpm generate:blog-search && next build",
"generate:blog-search": "tsx scripts/generate-blog-search-index.ts",
"prebuild:content": "node scripts/ensure-specs-content.mjs",
"build:content": "contentlayer2 build && :",
"build:docker": "bash -c 'set -a && . .env.local && set +a && cd ../.. && docker build -f apps/status.app/Dockerfile --secret id=infura_api_key,env=INFURA_API_KEY --secret id=greenhouse_api_key,env=GREENHOUSE_API_KEY --secret id=github_token,env=GITHUB_TOKEN --build-arg NEXT_PUBLIC_GHOST_API_URL=\"$NEXT_PUBLIC_GHOST_API_URL\" --build-arg NEXT_PUBLIC_GHOST_API_KEY=\"$NEXT_PUBLIC_GHOST_API_KEY\" --build-arg NEXT_PUBLIC_INFURA_API_KEY=\"$NEXT_PUBLIC_INFURA_API_KEY\" --build-arg NEXT_PUBLIC_HASURA_API_URL=\"$NEXT_PUBLIC_HASURA_API_URL\" --build-arg GREENHOUSE_STATUS_BOARD_ID=\"$GREENHOUSE_STATUS_BOARD_ID\" --build-arg GREENHOUSE_LOGOS_BOARD_ID=\"$GREENHOUSE_LOGOS_BOARD_ID\" -t status-web/status.app:dev .'",
"start": "next start",
@@ -0,0 +1,98 @@
#!/usr/bin/env node
//
// Guarantees `content/specs` has content before Contentlayer runs.
//
// `content/specs` is a git submodule (status-im/status-specs). A build host
// that clones the repo without `git submodule update --init` leaves the
// directory empty, Contentlayer emits zero SpecsDocs, and the build still
// succeeds, shipping an empty `/specs` hub where every `/specs/*` detail URL
// 404s. That is what took the whole specs section down in production.
//
// Order of recovery:
// 1. content already there -> nothing to do
// 2. parent repo available -> initialize the submodule
// 3. no parent repo (e.g. image build -> shallow clone the specs repo
// that drops `.git` from context)
// 4. still empty -> fail loudly instead of silently
// dropping every spec page
//
import { spawnSync } from 'node:child_process'
import { existsSync, readdirSync } from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const APP_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const SPECS_DIR = path.join(APP_DIR, 'content', 'specs')
// The docs themselves live one level down; `content/specs` itself also holds a
// README, so its mere existence says nothing about whether the docs are there.
const SPECS_DOCS_DIR = path.join(SPECS_DIR, 'status')
// Overridable so a build can pin a different fork or revision without a code
// change; defaults mirror `.gitmodules`, which is not part of every build
// context.
const SPECS_REPO_URL =
process.env.SPECS_REPO_URL ?? 'https://github.com/status-im/status-specs.git'
const SPECS_REF = process.env.SPECS_REF ?? 'master'
function hasSpecsContent() {
return existsSync(SPECS_DOCS_DIR) && readdirSync(SPECS_DOCS_DIR).length > 0
}
function run(command, args, cwd) {
const result = spawnSync(command, args, { cwd, stdio: 'inherit' })
return result.status === 0
}
function findRepositoryRoot() {
const result = spawnSync('git', ['rev-parse', '--show-toplevel'], {
cwd: APP_DIR,
encoding: 'utf8',
})
if (result.status !== 0) {
return undefined
}
return result.stdout.trim()
}
if (hasSpecsContent()) {
process.exit(0)
}
const repositoryRoot = findRepositoryRoot()
if (repositoryRoot) {
console.warn('⚠️ content/specs is empty. Initializing the submodule.')
run(
'git',
['submodule', 'update', '--init', '--recursive', '--', SPECS_DIR],
repositoryRoot,
)
}
if (!hasSpecsContent()) {
console.warn(
`⚠️ content/specs is still empty. Cloning ${SPECS_REPO_URL}#${SPECS_REF}.`,
)
run('git', [
'clone',
'--depth',
'1',
'--branch',
SPECS_REF,
SPECS_REPO_URL,
SPECS_DIR,
])
}
if (!hasSpecsContent()) {
console.error(
`\n✖ No specs content in ${SPECS_DOCS_DIR}.\n` +
` Building now would ship an empty /specs hub and 404 every /specs/* page.\n` +
` Run \`git submodule update --init --recursive\` on the build host, or set\n` +
` SPECS_REPO_URL / SPECS_REF if the specs repository moved.\n`,
)
process.exit(1)
}