80 lines
2.6 KiB
JavaScript
80 lines
2.6 KiB
JavaScript
import path from 'node:path'
|
|
import {
|
|
DEFAULT_BASE_URL,
|
|
DEFAULT_PUBLIC_KEY,
|
|
DEFAULT_SSH_HOST,
|
|
normalizeBaseUrl,
|
|
parseOptions,
|
|
resolvePath,
|
|
usageError
|
|
} from './lib.mjs'
|
|
import {
|
|
publishLocalRelease,
|
|
publishViaSsh,
|
|
readLatestViaSsh,
|
|
readLocalLatest,
|
|
validateReleaseBundle
|
|
} from './transport.mjs'
|
|
|
|
const usage = `Usage:
|
|
node scripts/updates/deploy.mjs --manifest <latest.json> --installer <YCode-Setup.exe>
|
|
[--transport ssh|local] [--base-url <url>] [--public-key <path>]
|
|
[--ssh-host local001] [--local-root <dir>] [--dry-run]
|
|
|
|
The SSH transport uploads to /srv/ycode-staging, verifies the current signed latest.json,
|
|
installs an immutable version directory, then atomically replaces latest.json.
|
|
The local transport is for temporary fake-transport tests only.
|
|
`
|
|
|
|
async function main() {
|
|
const options = parseOptions(process.argv.slice(2), {
|
|
values: ['manifest', 'installer', 'transport', 'base-url', 'public-key', 'ssh-host', 'local-root'],
|
|
booleans: ['dry-run']
|
|
})
|
|
if (!options.manifest || !options.installer) throw new Error('--manifest and --installer are required')
|
|
|
|
const transport = options.transport || 'ssh'
|
|
if (transport !== 'ssh' && transport !== 'local') throw new Error('--transport must be ssh or local')
|
|
if (transport === 'local' && !options['local-root']) throw new Error('--local-root is required for local transport')
|
|
|
|
const baseUrl = normalizeBaseUrl(options['base-url'] || DEFAULT_BASE_URL)
|
|
const publicKeyPath = resolvePath(options['public-key'] || DEFAULT_PUBLIC_KEY)
|
|
const release = await validateReleaseBundle({
|
|
manifestPath: resolvePath(options.manifest),
|
|
installerPath: resolvePath(options.installer),
|
|
publicKeyPath,
|
|
baseUrl
|
|
})
|
|
|
|
let current
|
|
if (transport === 'ssh') {
|
|
current = await readLatestViaSsh(options['ssh-host'] || DEFAULT_SSH_HOST, release.publicKeyPem, baseUrl)
|
|
} else {
|
|
current = await readLocalLatest(resolvePath(options['local-root']), release.publicKeyPem, baseUrl)
|
|
}
|
|
|
|
if (options['dry-run']) {
|
|
console.log(`Verified ${release.document.payload.version} for ${transport} publication.`)
|
|
console.log(`Current latest: ${current.document?.payload.version || 'none'}`)
|
|
return
|
|
}
|
|
|
|
if (transport === 'ssh') {
|
|
await publishViaSsh({
|
|
host: options['ssh-host'] || DEFAULT_SSH_HOST,
|
|
release,
|
|
current
|
|
})
|
|
} else {
|
|
await publishLocalRelease({
|
|
root: path.resolve(options['local-root']),
|
|
release,
|
|
current
|
|
})
|
|
}
|
|
|
|
console.log(`Published ${release.document.payload.version} via ${transport}.`)
|
|
}
|
|
|
|
main().catch((error) => usageError(usage, error))
|