From b220dfed92b49ad84a6eff7164e52efcdf872f81 Mon Sep 17 00:00:00 2001 From: omo50 <144749186+omo50@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:51:33 -0600 Subject: [PATCH] chore(ci): update changelog stipender --- tools/changelog/generate-changelog.ts | 70 +++++++++++++++++---------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/tools/changelog/generate-changelog.ts b/tools/changelog/generate-changelog.ts index b4d1fdad2..08c193c29 100644 --- a/tools/changelog/generate-changelog.ts +++ b/tools/changelog/generate-changelog.ts @@ -1,9 +1,10 @@ -import { execSync } from 'child_process'; +import { execFileSync } from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; +import * as crypto from 'crypto'; function runGit(args: string[], cwd?: string): string { - return execSync(`git ${args.join(' ')}`, { cwd, encoding: 'utf-8' }).trim(); + return execFileSync('git', args, { cwd, encoding: 'utf-8' }).trim(); } function generateChangelog(manifestPathStr: string): string { @@ -11,36 +12,50 @@ function generateChangelog(manifestPathStr: string): string { const pDir = path.dirname(manifestPath); if (!fs.existsSync(manifestPath)) { - console.error(`Manifest not found at: ${manifestPathStr}`); - process.exit(1); + throw new Error(`manifest not found: ${manifestPathStr}`); } - const manifestContent = fs.readFileSync(manifestPath, 'utf-8'); - const manifest = JSON.parse(manifestContent); - const rawName = manifest.name; + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')); + const rawName: string = manifest.name ?? path.basename(pDir); const changelogFile = path.join(pDir, 'changelog.md'); let notes = fs.existsSync(changelogFile) ? fs.readFileSync(changelogFile, 'utf-8') : `update for ${rawName}`; - let prevHash = 'HEAD~1'; + let prevHash: string | null = null; try { const prevBumpLog = runGit(['log', '-n', '2', '--format=%H', '--', manifestPathStr]); - const lines = prevBumpLog.split('\n'); - if (lines.length > 1) { - prevHash = lines[1]; + const hashes = prevBumpLog.split('\n').filter(Boolean); + if (hashes.length > 1) { + prevHash = hashes[1]; } - } catch (error) { - console.warn('could not find previous manifest bump, defaulting to HEAD~1'); + } catch (e) { + console.warn(`could not read git log for manifest: ${e}`); } - let commitLines: string[] = []; - try { - const logs = runGit(['log', `${prevHash}..HEAD`, '--format=%h %s - %an', '--', pDir]); - commitLines = logs.split('\n').filter(line => line.includes(': ')); - } catch (error) { - console.warn(`could not fetch git logs for ${pDir}`); + const commitLines: string[] = []; + if (prevHash) { + try { + const logs = runGit([ + 'log', + `${prevHash}..HEAD`, + '--format=%h%x09%s%x09%an', + '--', + pDir, + ]); + for (const line of logs.split('\n')) { + const parts = line.split('\t'); + if (parts.length !== 3) continue; + const [hash, subject, author] = parts; + if (!subject.includes(': ')) continue; + commitLines.push(`${hash} ${subject} - ${author}`); + } + } catch (e) { + console.warn(`could not fetch git logs for ${pDir}: ${e}`); + } + } else { + console.warn('no prior manifest bump found; skipping automated commit log'); } if (commitLines.length > 0) { @@ -56,20 +71,25 @@ function generateChangelog(manifestPathStr: string): string { const args = process.argv.slice(2); if (args.length === 0) { - console.error('Usage: tsx generate-changelog.ts '); + console.error('usage: tsx changelog.ts '); process.exit(1); } -const targetManifest = args[0]; -const finalNotes = generateChangelog(targetManifest); +let finalNotes: string; +try { + finalNotes = generateChangelog(args[0]); +} catch (e) { + console.error(`${e instanceof Error ? e.message : e}`); + process.exit(1); +} const outPath = process.env.GITHUB_OUTPUT; if (outPath) { - const delimiter = 'EOF_NOTES_DELIMITER'; + const delimiter = `EOF_${crypto.randomBytes(8).toString('hex')}`; fs.appendFileSync(outPath, `notes<<${delimiter}\n${finalNotes.trim()}\n${delimiter}\n`); - console.log(`successfully wrote changelog for ${targetManifest} to GITHUB_OUTPUT`); + console.log(`wrote changelog for ${args[0]} to GITHUB_OUTPUT`); } else { console.log('\nCHANGELOG PREVIEW\n'); console.log(finalNotes.trim()); - console.log('\n\n'); + console.log('\nEND\n'); } \ No newline at end of file