Something went wrong. Try again.
Browser extension: detect and subscribe to standard.site publications on ATProto
Something went wrong. Try again.
4.1 kB · 96 lines
JavaScript
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697// Release-time Conventional Commits versioner (npm run bump): scan the// commits since the last version change, pick the highest bump they call for// (breaking -> major, feat -> minor, fix/perf -> patch), and stage it into// package.json, package-lock.json, and public/manifest.json. This used to// run as a commit-msg hook, but bumping on every feat/fix rewrote the same// three files in every branch and parallel worktrees kept conflicting on// them. deploy-ext.sh still makes no version decisions; it only checks// agreement.import { execFileSync } from 'node:child_process'import { readFileSync, writeFileSync } from 'node:fs'import { GIT_SHAPES, HEADER, bumpFor } from './conventional.mjs'
const FILES = ['package.json', 'package-lock.json', 'public/manifest.json']const RANK = { major: 3, minor: 2, patch: 1 }
const git = (...args) => execFileSync('git', args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] })
const current = JSON.parse(readFileSync('package.json', 'utf8')).versionconst parts = /^(\d+)\.(\d+)\.(\d+)$/.exec(current)if (!parts) { console.error(`version-bump: cannot bump non-x.y.z version "${current}"`) process.exit(1)}
// Pending edits to the release files would get swept into the bump.const pending = git('status', '--porcelain', '--', ...FILES).trim()if (pending) { console.error(`version-bump: uncommitted changes to release files:\n${pending}`) console.error('version-bump: commit or stash them first') process.exit(1)}
// Anchor on the commit that set the current version: walk the commits that// touched package.json, newest first, while they still hold the current// version. Works with or without release tags.let anchor = nullfor (const sha of git('log', '--format=%H', '--', 'package.json').split('\n').filter(Boolean)) { if (JSON.parse(git('show', `${sha}:package.json`)).version !== current) break anchor = sha}if (!anchor) { console.error('version-bump: no commit sets the current version — is package.json committed?') process.exit(1)}
// One message per commit since the anchor, NUL-separated.const messages = git('log', '--format=%B%x00', `${anchor}..HEAD`) .split('\0') .map((message) => message.replace(/^\n/, '')) .filter((message) => message.trim() !== '')
let bump = nulllet releasing = 0for (const message of messages) { const lines = message.split('\n') const header = lines.find((line) => line.trim() !== '') ?? '' if (GIT_SHAPES.test(header)) continue if (!HEADER.test(header)) { console.error(`version-bump: skipping non-conventional header: "${header}"`) continue } const one = bumpFor(header, lines) if (!one) continue releasing += 1 if (!bump || RANK[one] > RANK[bump]) bump = one}
const anchorShort = anchor.slice(0, 7)if (!bump) { console.log(`version-bump: no releasing commits since ${anchorShort} (${messages.length} scanned); nothing to do`) process.exit(0)}
const [major, minor, patch] = parts.slice(1).map(Number)const next = bump === 'major' ? `${major + 1}.0.0` : bump === 'minor' ? `${major}.${minor + 1}.0` : `${major}.${minor}.${patch + 1}`
// String-replace the hand-maintained files so their formatting survives; the// lockfile is npm-written 2-space JSON, which stringify round-trips.for (const file of ['package.json', 'public/manifest.json']) { const text = readFileSync(file, 'utf8') const needle = `"version": "${current}"` if (!text.includes(needle)) { console.error(`version-bump: ${file} has no ${needle}`) process.exit(1) } writeFileSync(file, text.replace(needle, `"version": "${next}"`))}const lock = JSON.parse(readFileSync('package-lock.json', 'utf8'))lock.version = nextif (lock.packages?.['']) lock.packages[''].version = nextwriteFileSync('package-lock.json', JSON.stringify(lock, null, 2) + '\n')execFileSync('git', ['add', ...FILES])
console.log(`version-bump: staged ${current} -> ${next} (${bump}) from ${releasing} releasing commits since ${anchorShort}`)console.log(`version-bump: next: git commit -m "chore(release): v${next}" && git tag "v${next}" -a -m "release v${next}" && git push --follow-tags`)