prepare-installed-update.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. /** Allocate operator qualification materials or inspect journals; never signs, uploads, or installs. */
  2. import { execFileSync } from 'node:child_process'
  3. import { readFile } from 'node:fs/promises'
  4. import { resolve } from 'node:path'
  5. import { collectInstalledUpdateJournals, createInstalledUpdateRun, inspectInstalledUpdateJournals } from './installed-update-qualification.ts'
  6. import { prepareInstalledUpdateBootstrap } from './prepare-installed-update-bootstrap.ts'
  7. import { prepareInstalledUpdateRuntime } from './prepare-installed-update-runtime.ts'
  8. import { planInstalledUpdateDistribution } from './installed-update-distribution.ts'
  9. import { prepareInstalledUpdateApplication } from './prepare-installed-update-application.ts'
  10. const repository = resolve(import.meta.dirname, '../../..')
  11. async function main(): Promise<void> {
  12. const [command, original, successor, directory, ...extra] = process.argv.slice(2)
  13. if (command === 'collect' && original !== undefined && successor !== undefined && directory === undefined) {
  14. console.log(JSON.stringify({ collection: await collectInstalledUpdateJournals(original, successor), operatorAcceptance: 'pending' }, null, 2))
  15. return
  16. }
  17. if (command === 'application' && original !== undefined && successor === undefined) {
  18. console.log(JSON.stringify(await prepareInstalledUpdateApplication(original, resolve(repository, 'apps/desktop')), null, 2))
  19. return
  20. }
  21. if (command === 'files' && original !== undefined && successor !== undefined && directory === undefined) {
  22. console.log(JSON.stringify(await planInstalledUpdateDistribution(original, successor), null, 2))
  23. return
  24. }
  25. if (command === 'bootstrap' && original !== undefined && successor === undefined) {
  26. console.log(JSON.stringify({ bootstrap: await prepareInstalledUpdateBootstrap(original), launched: false }, null, 2))
  27. return
  28. }
  29. if (command === 'runtime' && original !== undefined && successor === undefined) {
  30. console.log(JSON.stringify(await prepareInstalledUpdateRuntime(original,
  31. resolve(repository, 'apps/desktop/.desktop-build/targets/win-x64/dsh')), null, 2))
  32. return
  33. }
  34. if ((command !== 'init' && command !== 'inspect') || original === undefined || successor === undefined
  35. || extra.length !== 0 || (command === 'init' && directory !== undefined) || (command === 'inspect' && directory === undefined)) {
  36. throw new Error('usage: prepare-installed-update.ts init <original-test-version> <successor-test-version> | bootstrap <run.json> | runtime <run.json> | application <run.json> | files <run.json> <version> | collect <run.json> <journal-directory> | inspect <original-test-version> <successor-test-version> <journal-directory>')
  37. }
  38. if (command === 'inspect') {
  39. const evidence = await inspectInstalledUpdateJournals(directory!, [original, successor])
  40. console.log(JSON.stringify(evidence, null, 2))
  41. if (evidence.recordedFlow === 'incomplete') process.exitCode = 2
  42. return
  43. }
  44. const metadata = JSON.parse(await readFile(resolve(repository, 'package.json'), 'utf8')) as { version: string }
  45. const git = (args: string[]): string => execFileSync('git', args, { cwd: repository, encoding: 'utf8', windowsHide: true }).trim()
  46. const run = await createInstalledUpdateRun(resolve(repository, 'apps/desktop/.desktop-build/qualification'), [original, successor], {
  47. version: metadata.version, commit: git(['rev-parse', 'HEAD']),
  48. dirtyFiles: git(['status', '--porcelain=v1', '--untracked-files=normal']).split('\n').filter(Boolean),
  49. })
  50. console.log(JSON.stringify({ manifest: resolve(run.root, 'run.json'), appId: run.appId,
  51. versions: run.versions, feedUrl: `${run.origin}/${run.feedKey}`, artifactsPrepared: false, published: false }, null, 2))
  52. }
  53. main().catch(() => {
  54. // Inputs may be logs or local configuration; do not echo arbitrary exception details.
  55. console.error('installed update preparation failed; verify arguments, Git checkout, versions, and local evidence files. No remote operation was attempted.')
  56. process.exitCode = 1
  57. })