Files

132 lines
5.1 KiB
JavaScript

#!/usr/bin/env node
import { readFileSync, writeFileSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const desktopRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const args = process.argv.slice(2)
const write = args.includes('--write')
const expectIndex = args.indexOf('--expect')
const expected = expectIndex >= 0 ? args[expectIndex + 1] : undefined
const knownArgs = new Set(['--write', '--expect', expected])
const unknown = args.filter(arg => !knownArgs.has(arg))
if (expectIndex >= 0 && !expected) {
throw new Error('--expect requires a version')
}
if (unknown.length > 0) {
throw new Error(`unknown argument(s): ${unknown.join(', ')}`)
}
const paths = {
packageJson: join(desktopRoot, 'package.json'),
packageLock: join(desktopRoot, 'package-lock.json'),
generatedVersion: join(desktopRoot, 'src', 'version.ts'),
cargoToml: join(desktopRoot, 'tray', 'Cargo.toml'),
cargoLock: join(desktopRoot, 'tray', 'Cargo.lock'),
tauriConfig: join(desktopRoot, 'tray', 'tauri.conf.json'),
trayPackageJson: join(desktopRoot, 'tray', 'package.json'),
trayPackageLock: join(desktopRoot, 'tray', 'package-lock.json')
}
const packageJson = JSON.parse(readFileSync(paths.packageJson, 'utf8'))
const version = packageJson.version
if (typeof version !== 'string' || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version)) {
throw new Error(`desktop/package.json has an invalid SemVer version: ${String(version)}`)
}
if (expected && expected !== version) {
throw new Error(`tag version ${expected} does not match desktop/package.json ${version}`)
}
function replaceChecked(path, label, pattern, replacement) {
const current = readFileSync(path, 'utf8')
if (!pattern.test(current)) {
throw new Error(`could not locate ${label} in ${path}`)
}
pattern.lastIndex = 0
const next = current.replace(pattern, replacement)
if (next !== current) {
writeFileSync(path, next)
}
}
if (write) {
let packageLockVersionCount = 0
replaceChecked(
paths.packageLock,
'root package-lock versions',
/("version"\s*:\s*")[^"]+(")/g,
(match, prefix, suffix) => {
packageLockVersionCount += 1
return packageLockVersionCount <= 2 ? `${prefix}${version}${suffix}` : match
}
)
if (packageLockVersionCount < 2) {
throw new Error('desktop/package-lock.json did not contain both root version fields')
}
replaceChecked(
paths.generatedVersion,
'generated CLI version',
/(export const VERSION\s*=\s*)["'][^"']+["'](\s+as const)/,
`$1${JSON.stringify(version)}$2`
)
replaceChecked(
paths.cargoToml,
'Cargo package version',
/(\[package\][\s\S]*?^version\s*=\s*")[^"]+("\s*$)/m,
`$1${version}$2`
)
replaceChecked(
paths.cargoLock,
'Cargo lock package version',
/(\[\[package\]\]\s*\r?\nname\s*=\s*"hermes-relay-tray"\s*\r?\nversion\s*=\s*")[^"]+("\s*$)/m,
`$1${version}$2`
)
const tauriConfig = JSON.parse(readFileSync(paths.tauriConfig, 'utf8'))
tauriConfig.version = version
writeFileSync(paths.tauriConfig, JSON.stringify(tauriConfig, null, 2) + '\n')
for (const packagePath of [paths.trayPackageJson, paths.trayPackageLock]) {
const metadata = JSON.parse(readFileSync(packagePath, 'utf8'))
metadata.version = version
if (metadata.packages?.['']) metadata.packages[''].version = version
writeFileSync(packagePath, JSON.stringify(metadata, null, 2) + '\n')
}
}
const packageLock = JSON.parse(readFileSync(paths.packageLock, 'utf8'))
const generatedVersionText = readFileSync(paths.generatedVersion, 'utf8')
const cargoTomlText = readFileSync(paths.cargoToml, 'utf8')
const cargoLockText = readFileSync(paths.cargoLock, 'utf8')
const tauriConfig = JSON.parse(readFileSync(paths.tauriConfig, 'utf8'))
const trayPackageJson = JSON.parse(readFileSync(paths.trayPackageJson, 'utf8'))
const trayPackageLock = JSON.parse(readFileSync(paths.trayPackageLock, 'utf8'))
const generatedVersion = generatedVersionText.match(/export const VERSION\s*=\s*["']([^"']+)["']/)?.[1]
const cargoVersion = cargoTomlText.match(/\[package\][\s\S]*?^version\s*=\s*"([^"]+)"/m)?.[1]
const cargoLockVersion = cargoLockText.match(
/\[\[package\]\]\s*\r?\nname\s*=\s*"hermes-relay-tray"\s*\r?\nversion\s*=\s*"([^"]+)"/m
)?.[1]
const locations = [
['package-lock root', packageLock.version],
['package-lock workspace root', packageLock.packages?.['']?.version],
['generated src/version.ts', generatedVersion],
['Cargo package', cargoVersion],
['Cargo lock package', cargoLockVersion],
['Tauri config', tauriConfig.version],
['tray package', trayPackageJson.version],
['tray package-lock root', trayPackageLock.version],
['tray package-lock workspace root', trayPackageLock.packages?.['']?.version]
]
const mismatches = locations.filter(([, value]) => value !== version)
if (mismatches.length > 0) {
for (const [label, value] of mismatches) {
console.error(`version mismatch: ${label} is ${String(value)}, expected ${version}`)
}
console.error('Run `npm run sync:version` from desktop/ to repair generated metadata.')
process.exit(1)
}
console.log(`CLI version sync OK: ${version}`)