Files
xinmi/scripts/preserve_frontend_assets.cjs
yawan f7fc992f57
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
2026-09-22 16:19:06 +08:00

50 lines
2.4 KiB
JavaScript

const fs = require('node:fs')
const path = require('node:path')
const { execFileSync } = require('node:child_process')
// Snapshot only this build, before adding older hashed chunks for open tabs.
function preserveFrontendAssets(root, revision) {
if (!/^[a-zA-Z0-9-]+$/.test(revision)) throw new Error('Invalid asset revision')
const assets = path.join(root, 'src/frontend/dist/assets')
const archive = path.join(root, 'frontend-asset-archives')
fs.mkdirSync(archive, { recursive: true })
const previous = fs.readdirSync(archive).filter(name => fs.statSync(path.join(archive, name)).isDirectory())
.sort((a, b) => fs.statSync(path.join(archive, b)).mtimeMs - fs.statSync(path.join(archive, a)).mtimeMs).slice(0, 3)
const snapshot = path.join(archive, revision)
if (fs.existsSync(snapshot)) throw new Error('Asset snapshot already exists')
fs.cpSync(assets, snapshot, { recursive: true, errorOnExist: true, force: false })
if (!previous.length) {
const docker = (...args) => execFileSync('docker', ['--context', 'colima-yawan', ...args], { encoding: 'utf8' }).trim()
const containers = docker('ps', '-a', '--filter', 'name=yawan-public-frontend', '--format', '{{.Names}}').split('\n').filter(Boolean)
for (const container of containers) {
if (!/^yawan-public-frontend(?:-before-[a-zA-Z0-9-]+)?$/.test(container)) continue
const name = `bootstrap-${container}`
const destination = path.join(archive, name)
if (!fs.existsSync(destination)) docker('cp', `${container}:/usr/share/nginx/html/assets`, destination)
previous.push(name)
}
}
let retained = 0
for (const name of previous) retained += mergeAssets(path.join(archive, name), assets)
const now = new Date()
fs.utimesSync(snapshot, now, now)
return { retained, previous_builds: previous.length }
}
function mergeAssets(source, destination) {
let copied = 0
for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
const from = path.join(source, entry.name), to = path.join(destination, entry.name)
if (entry.isSymbolicLink()) throw new Error('Asset symlinks are not supported')
if (entry.isDirectory()) {
fs.mkdirSync(to, { recursive: true })
copied += mergeAssets(from, to)
} else if (entry.isFile() && !fs.existsSync(to)) {
fs.copyFileSync(from, to, fs.constants.COPYFILE_EXCL)
copied++
}
}
return copied
}
module.exports = { preserveFrontendAssets, mergeAssets }