🌳
pt0/deployF/staticSiteF/buildOssGitAI.mts
1import fs from 'fs/promises'
2import path from 'path'
3import { existsSync } from 'fs'
4import { execSync } from 'child_process'
18export const buildOssGitWorkingDir = async (destDir: string, opts: {skipMine?: boolean, skipReview?: boolean, skipScan?: boolean} = {}) => {
19 const shortSha = (await getHeadGitSha()).slice(0, 12)
20 console.log(`Building oss git working dir (sha: ${shortSha})...`)
21 const ossReplaceFn = await getOssReplaceFn()
22 const { forward: ossPathFwd } = await getOssPathTransformers()
23 const ossTrackedPaths = await getOssTrackedPaths() || ['pt0/']
24 const ossExcludeFn = await getOssExcludeFn()
25 const ossHook = await getOssHook()
26 const ossAuthorResolved = ossHook?.ossAuthor || ossAuthor
28 await fs.rm(destDir, {recursive: true, force: true})
29 await fs.mkdir(destDir, {recursive: true})
31 const ossGitignore = await getOssGitignoreContent()
32 const ossForbidStrA = await getOssForbidStrA()
33 const filterPnpmWs = await getFilterOssPnpmWorkspace()
34 const generatePrunedPkg = await getGeneratePrunedOssPackageJson()
35 const transformOcJson = await getTransformOssOpencodeJson()
37 const allFiles = (await getTrackedFiles(ossTrackedPaths)).filter(f => !ossExcludeFn || !ossExcludeFn(f))
38 for (const relPath of allFiles) {
39 const displayPath = ossPathFwd(relPath)
40 const destFile = path.join(destDir, displayPath)
41 await fs.mkdir(path.dirname(destFile), {recursive: true})
42 const srcAbs = path.join(ptDir, relPath)
43 const fileStat = await fs.stat(srcAbs).catch(() => null)
44 if (!fileStat?.isFile()) continue
45 const basename = path.basename(relPath)
46 if (basename === '.gitignore' && ossGitignore) {
47 await fs.writeFile(destFile, ossGitignore)
48 } else if (basename === 'pnpm-workspace.yaml' && filterPnpmWs) {
49 const raw = await fs.readFile(srcAbs, 'utf8')
50 await fs.writeFile(destFile, filterPnpmWs(raw))
51 } else if (relPath === 'package.json' && generatePrunedPkg) {
52 const monorPkg = JSON.parse(await fs.readFile(srcAbs, 'utf8'))
53 const codeDirs = ossTrackedPaths.filter(p => p.endsWith('/')).map(p => path.join(ptDir, p))
54 const prunedPkg = await generatePrunedPkg({monorPkg, codeDirs})
55 await fs.writeFile(destFile, JSON.stringify(prunedPkg, null, 2) + '\n')
56 } else if (relPath === 'opencode.json' && transformOcJson) {
57 const raw = await fs.readFile(srcAbs, 'utf8')
58 await fs.writeFile(destFile, transformOcJson(ossReplaceFn ? ossReplaceFn(raw) : raw))
59 } else if (isTextFile(relPath)) {
60 const raw = await fs.readFile(srcAbs, 'utf8')
61 const transformed = ossReplaceFn ? ossReplaceFn(raw) : raw
62 await fs.writeFile(destFile, transformed)
63 } else {
64 await fs.copyFile(srcAbs, destFile)
65 }
66 if (fileStat.mode & 0o111) await fs.chmod(destFile, fileStat.mode)
67 }
69 console.log(`Generating pnpm-lock.yaml...`)
70 pnpmInstallSync({lockfileOnly: true, cwd: destDir})
72 if (ossForbidStrA && !opts.skipScan) {
73 console.log(`Scanning oss export for forbidden strings...`)
74 const forbiddenHits: {path: string, needleStr: string, containingWord: string}[] = []
75 const scanFile = async (filePath: string, displayPath: string) => {
76 const content = await fs.readFile(filePath, 'utf8').catch(() => null)
77 if (!content) return
78 const hit = perFileGuardNeedle({needleStrA: ossForbidStrA, path: displayPath, contents: content, raiseOnFind: false})
79 if (hit) forbiddenHits.push(hit)
80 }
81 for (const relPath of allFiles) {
82 const displayPath = ossPathFwd(relPath)
83 if (!isTextFile(relPath) || displayPath.endsWith('.d.ts')) continue
84 await scanFile(path.join(destDir, displayPath), displayPath)
85 }
86 await scanFile(path.join(destDir, 'pnpm-lock.yaml'), 'pnpm-lock.yaml')
87 if (forbiddenHits.length) {
88 console.error(`\nOSS export: ${forbiddenHits.length} forbidden string hit(s):`)
89 for (const h of forbiddenHits) console.error(` ${h.path}: "${h.needleStr}" in "${h.containingWord}"`)
90 throw new Error(`oss export failed: ${forbiddenHits.length} forbidden string(s) found`)
91 }
92 }
94 if (!opts.skipReview) {
95 const reviewResult = await llmReviewDir({dir: destDir, shortSha, reviewName: 'ossgit'})
96 if (reviewResult.summary.abortedEarly || reviewResult.summary.failedChunkCount > 0) {
97 throw new Error(`oss review did not pass: ${reviewResult.summary.failedChunkCount} chunk(s) failed${reviewResult.summary.abortedEarly ? ' (aborted early)' : ''}`)
98 }
99 }
101 execSync('git init', {cwd: destDir, stdio: 'pipe'})
102 execSync(`git config user.name "${ossEnsName}"`, {cwd: destDir, stdio: 'pipe'})
103 execSync(`git config user.email "${ossEmail}"`, {cwd: destDir, stdio: 'pipe'})
104 execSync('git add -A', {cwd: destDir, stdio: 'pipe'})
105 const repoHeadSha = commitMineShaPrefix({cwd: destDir, msgBase: `oss export ${shortSha}`, tgtShaPrefix: opts.skipMine ? '' : ossRepoTgtShaPrefix})
107 console.log(`Built ${shortPtPath(destDir)} (${allFiles.length} files, head ${repoHeadSha.slice(0, 12)})`)
108 return destDir
111export const getOrBuildOssGitWorkingDir = async () => {
112 const shortSha = (await getHeadGitSha()).slice(0, 12)
113 const cacheDir = path.join(ptTmpDir, `oss-git-workdir-${shortSha}`)
114 if (existsSync(path.join(cacheDir, '.git'))) return cacheDir
115 return buildOssGitWorkingDir(cacheDir)
118export const getOrBuildOssBenchWorkdir = async () => {
119 const shortSha = (await getHeadGitSha()).slice(0, 12)
120 const cacheDir = path.join(ptTmpDir, `oss-bench-workdir-${shortSha}`)
121 if (existsSync(path.join(cacheDir, '.git'))) return cacheDir
122 return buildOssGitWorkingDir(cacheDir, {skipMine: true, skipReview: true, skipScan: true})