Files
ycode/scripts/updates/prepare-release.mjs
T

72 lines
2.7 KiB
JavaScript

import fsp from 'node:fs/promises'
import path from 'node:path'
import {
DEFAULT_BASE_URL,
DEFAULT_PRIVATE_KEY,
DEFAULT_PUBLIC_KEY,
assertOutsideRepo,
buildManifestPayload,
canonicalNow,
createSignedManifest,
normalizeBaseUrl,
parseOptions,
readPrivateKey,
readPublicKey,
resolvePath,
serializeSignedManifest,
usageError,
verifyReleaseInstaller,
verifySignedManifest,
writeFileAtomic
} from './lib.mjs'
const usage = `Usage:
node scripts/updates/prepare-release.mjs --installer <YCode-Setup.exe> --version <x.y.z>
--notes-zh <text> --notes-en <text> [--base-url <url>] [--published-at <ISO>]
[--private-key <path>] [--public-key <path>] [--output <latest.json>]
This validates the actual EXE ProductVersion, current package.json version, size and SHA-256,
then signs exact JSON.stringify(payload) with Ed25519. It never deploys.
`
async function main() {
const options = parseOptions(process.argv.slice(2), {
values: ['installer', 'version', 'notes-zh', 'notes-en', 'base-url', 'published-at', 'private-key', 'public-key', 'output']
})
if (!options.installer || !options.version || !options['notes-zh'] || !options['notes-en']) {
throw new Error('--installer, --version, --notes-zh and --notes-en are required')
}
const baseUrl = normalizeBaseUrl(options['base-url'] || DEFAULT_BASE_URL)
const installerPath = resolvePath(options.installer)
const installer = await verifyReleaseInstaller(installerPath, options.version)
const output = resolvePath(options.output || path.join('.tmp', 'updates', options.version, 'latest.json'))
const privateKeyPath = await assertOutsideRepo(
resolvePath(options['private-key'] || DEFAULT_PRIVATE_KEY),
'Private key'
)
const privateKey = await readPrivateKey(privateKeyPath)
const publicKeyPath = resolvePath(options['public-key'] || DEFAULT_PUBLIC_KEY)
const publicKey = await readPublicKey(publicKeyPath)
const payload = buildManifestPayload({
version: options.version,
publishedAt: options['published-at'] || canonicalNow(),
notes: { zh: options['notes-zh'], en: options['notes-en'] },
installer,
baseUrl
})
const document = createSignedManifest({ payload, privateKeyPem: privateKey, publicKeyPem: publicKey, baseUrl })
verifySignedManifest(document, publicKey, { baseUrl })
await writeFileAtomic(output, serializeSignedManifest(document))
await fsp.access(output)
console.log(`Manifest: ${output}`)
console.log(`Version: ${payload.version}`)
console.log(`Installer: ${installer.filename}`)
console.log(`Size: ${installer.size}`)
console.log(`SHA-256: ${installer.sha256}`)
console.log(`URL: ${payload.platforms['windows-x64'].url}`)
}
main().catch((error) => usageError(usage, error))