72 lines
2.7 KiB
JavaScript
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))
|