2026-06-23 12:15:28 +08:00
|
|
|
|
// 從 git log 產生更新紀錄資料,輸出到 src/data/changelog.json
|
|
|
|
|
|
// 正式版(build 後)沒有 git 也能直接讀 JSON 顯示;dev 與 build 前會自動重新產生。
|
|
|
|
|
|
import { execFileSync } from 'node:child_process'
|
2026-07-13 15:44:42 +08:00
|
|
|
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
2026-06-23 12:15:28 +08:00
|
|
|
|
import { dirname, resolve } from 'node:path'
|
|
|
|
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
|
|
|
|
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
|
|
|
|
const outFile = resolve(here, '../src/data/changelog.json')
|
|
|
|
|
|
|
|
|
|
|
|
const UNIT = '\x1f' // 欄位分隔(unit separator)
|
|
|
|
|
|
const RECORD = '\x1e' // 紀錄分隔(record separator)
|
|
|
|
|
|
|
|
|
|
|
|
function readGitLog() {
|
|
|
|
|
|
const format = ['%H', '%h', '%ad', '%s', '%b'].join(UNIT) + RECORD
|
|
|
|
|
|
const raw = execFileSync(
|
|
|
|
|
|
'git',
|
|
|
|
|
|
['log', `--pretty=format:${format}`, '--date=format:%Y-%m-%d'],
|
|
|
|
|
|
{ cwd: resolve(here, '..'), encoding: 'utf8', maxBuffer: 1024 * 1024 * 16 },
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return raw
|
|
|
|
|
|
.split(RECORD)
|
|
|
|
|
|
.map((chunk) => chunk.replace(/^\s+/, ''))
|
|
|
|
|
|
.filter(Boolean)
|
|
|
|
|
|
.map((chunk) => {
|
|
|
|
|
|
const [hash, shortHash, date, subject, body = ''] = chunk.split(UNIT)
|
|
|
|
|
|
return {
|
|
|
|
|
|
hash,
|
|
|
|
|
|
shortHash,
|
|
|
|
|
|
date,
|
|
|
|
|
|
subject: subject.trim(),
|
|
|
|
|
|
body: body.trim(),
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-13 15:44:42 +08:00
|
|
|
|
// 讀取既有的 changelog.json(Docker build 內由 COPY . . 帶進來),取不到時回傳 null。
|
|
|
|
|
|
function readExisting() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = JSON.parse(readFileSync(outFile, 'utf8'))
|
|
|
|
|
|
return Array.isArray(data.entries) ? data.entries : null
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-23 12:15:28 +08:00
|
|
|
|
function main() {
|
|
|
|
|
|
let entries = []
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
entries = readGitLog()
|
|
|
|
|
|
} catch (error) {
|
2026-07-13 15:44:42 +08:00
|
|
|
|
console.warn('[generate-changelog] 讀取 git log 失敗:', error.message)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// git 取不到(或拿到 0 筆,常見於 Docker build 內沒有 .git)時,
|
|
|
|
|
|
// 若已有非空的 changelog.json 就沿用,避免把好資料覆蓋成空清單。
|
|
|
|
|
|
if (entries.length === 0) {
|
|
|
|
|
|
const existing = readExisting()
|
|
|
|
|
|
if (existing && existing.length > 0) {
|
|
|
|
|
|
console.log(`[generate-changelog] git 無資料,保留既有 ${existing.length} 筆更新紀錄不覆蓋`)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-06-23 12:15:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const payload = {
|
|
|
|
|
|
generatedAt: new Date().toISOString(),
|
|
|
|
|
|
entries,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mkdirSync(dirname(outFile), { recursive: true })
|
|
|
|
|
|
writeFileSync(outFile, JSON.stringify(payload, null, 2) + '\n', 'utf8')
|
|
|
|
|
|
console.log(`[generate-changelog] 已輸出 ${entries.length} 筆更新紀錄到 ${outFile}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
main()
|