package-target.spec.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { describe, expect, it } from 'vitest'
  2. import {
  3. desktopElectronBuilderArguments,
  4. desktopElectronBuilderEnvironment,
  5. parseDesktopPackageInvocation,
  6. resolveDesktopPackageTarget,
  7. withoutDesktopUploadCredentials,
  8. withoutWindowsSigningEnvironment,
  9. } from '../scripts/package-target.ts'
  10. describe('desktop package target', () => {
  11. it('selects matching runtime and electron-builder architectures', () => {
  12. expect(resolveDesktopPackageTarget('mac-arm64', 'darwin', 'arm64')).toMatchObject({
  13. platform: 'darwin', arch: 'arm64', builderPlatform: '--mac', builderArch: '--arm64',
  14. })
  15. expect(resolveDesktopPackageTarget('mac-x64', 'darwin', 'x64')).toMatchObject({
  16. platform: 'darwin', arch: 'x64', builderPlatform: '--mac', builderArch: '--x64',
  17. })
  18. expect(resolveDesktopPackageTarget('win-x64', 'win32', 'x64')).toMatchObject({
  19. platform: 'win32', arch: 'x64', builderPlatform: '--win', builderArch: '--x64',
  20. })
  21. })
  22. it('allows an Apple Silicon host to build the Intel target through Rosetta', () => {
  23. expect(resolveDesktopPackageTarget('mac-x64', 'darwin', 'arm64').arch).toBe('x64')
  24. })
  25. it('rejects unsupported targets and hosts before building', () => {
  26. expect(() => resolveDesktopPackageTarget('linux-x64', 'linux', 'x64')).toThrow(/unsupported target/u)
  27. expect(() => resolveDesktopPackageTarget('win-x64', 'darwin', 'arm64')).toThrow(/Windows x64/u)
  28. expect(() => resolveDesktopPackageTarget('mac-arm64', 'darwin', 'x64')).toThrow(/Apple Silicon/u)
  29. expect(() => resolveDesktopPackageTarget('mac-arm64', 'linux', 'arm64')).toThrow(/macOS/u)
  30. expect(() => resolveDesktopPackageTarget('mac-x64', 'darwin', 'ppc64')).toThrow(/Rosetta/u)
  31. })
  32. it('parses installer and unpacked-directory invocations', () => {
  33. expect(parseDesktopPackageInvocation(['mac-arm64'], 'darwin', 'arm64').directory).toBe(false)
  34. expect(parseDesktopPackageInvocation(['mac-arm64', '--dir'], 'darwin', 'arm64').directory).toBe(true)
  35. expect(parseDesktopPackageInvocation([], 'darwin', 'arm64').target.name).toBe('mac-arm64')
  36. expect(parseDesktopPackageInvocation(['--prepare-only'], 'darwin', 'arm64').prepareOnly).toBe(true)
  37. expect(() => parseDesktopPackageInvocation(['mac-arm64', 'mac-x64'], 'darwin', 'arm64'))
  38. .toThrow(/at most one target/u)
  39. })
  40. it('keeps electron-builder publishing disabled for the separate validated upload', () => {
  41. const target = resolveDesktopPackageTarget('mac-arm64', 'darwin', 'arm64')
  42. expect(desktopElectronBuilderArguments(target, false)).toEqual([
  43. 'exec',
  44. 'electron-builder',
  45. '--config',
  46. 'electron-builder.config.mjs',
  47. '--mac',
  48. '--arm64',
  49. '--publish',
  50. 'never',
  51. ])
  52. expect(desktopElectronBuilderArguments(target, true)).toContain('--dir')
  53. })
  54. it('accepts unsigned Windows artifacts and rejects other targets or preparation-only use', () => {
  55. expect(parseDesktopPackageInvocation(['win-x64', '--unsigned'], 'win32', 'x64').unsigned).toBe(true)
  56. expect(parseDesktopPackageInvocation(['win-x64'], 'win32', 'x64').unsigned).toBe(false)
  57. expect(parseDesktopPackageInvocation(['--unsigned', '--dir'], 'win32', 'x64')).toMatchObject({
  58. unsigned: true, directory: true,
  59. })
  60. expect(() => parseDesktopPackageInvocation(['mac-arm64', '--unsigned'], 'darwin', 'arm64'))
  61. .toThrow(/requires win-x64/u)
  62. expect(() => parseDesktopPackageInvocation(['--unsigned', '--prepare-only'], 'win32', 'x64'))
  63. .toThrow(/cannot use --prepare-only/u)
  64. })
  65. it('removes ambient certificate inputs for unsigned builds and overrides an inherited signing mode', () => {
  66. const environment = {
  67. DSH_DESKTOP_APP_ID: 'com.example.desktop',
  68. DSH_DESKTOP_WINDOWS_TOKEN_PIN: 'token-secret',
  69. CSC_LINK: 'private.pfx',
  70. CSC_KEY_PASSWORD: 'secret',
  71. WIN_CSC_LINK: 'windows.pfx',
  72. CSC_IDENTITY_AUTO_DISCOVERY: 'true',
  73. DSH_DESKTOP_UNSIGNED: '1',
  74. }
  75. expect(desktopElectronBuilderEnvironment(environment, true)).toEqual({
  76. DSH_DESKTOP_APP_ID: 'com.example.desktop',
  77. CSC_IDENTITY_AUTO_DISCOVERY: 'false',
  78. DSH_DESKTOP_UNSIGNED: '1',
  79. })
  80. expect(desktopElectronBuilderEnvironment(environment, false)).toEqual({ ...environment, DSH_DESKTOP_UNSIGNED: '0' })
  81. })
  82. it.each([false, true])('pins the Windows archive filter for the NSIS decoder (unsigned: %s)', (unsigned) => {
  83. expect(desktopElectronBuilderEnvironment({
  84. DSH_DESKTOP_TARGET_PLATFORM: 'win32', ELECTRON_BUILDER_7Z_FILTER: 'ARM64',
  85. }, unsigned).ELECTRON_BUILDER_7Z_FILTER).toBe('BCJ')
  86. expect(desktopElectronBuilderEnvironment({
  87. DSH_DESKTOP_TARGET_PLATFORM: 'darwin', ELECTRON_BUILDER_7Z_FILTER: 'ARM',
  88. }, unsigned).ELECTRON_BUILDER_7Z_FILTER).toBe('ARM')
  89. })
  90. it('keeps Windows signing fields out of build and runtime preparation subprocesses', () => {
  91. expect(withoutWindowsSigningEnvironment({
  92. DSH_DESKTOP_WINDOWS_CER_FILE: 'C:\\release\\server.cer',
  93. DSH_DESKTOP_WINDOWS_TOKEN_PIN: 'token-secret',
  94. DSH_DESKTOP_WINDOWS_KEY_CONTAINER: 'container',
  95. DSH_DESKTOP_WINDOWS_SIGNTOOL: 'C:\\tools\\signtool.exe',
  96. DSH_DESKTOP_AUTO_UPDATE_ENV: 'production',
  97. })).toEqual({ DSH_DESKTOP_AUTO_UPDATE_ENV: 'production' })
  98. })
  99. it('keeps COS credentials out of every packaging subprocess', () => {
  100. expect(withoutDesktopUploadCredentials({
  101. DOWNLOAD_TEST_ORIGIN: 'https://desktop-updates.example.com',
  102. DOWNLOAD_TEST_COS_BUCKET: 'test-download-bucket',
  103. DOWNLOAD_TEST_COS_SECRET_ID: 'test-id',
  104. DOWNLOAD_TEST_COS_SECRET_KEY: 'test-key',
  105. DOWNLOAD_PROD_COS_BUCKET: 'production-download-bucket',
  106. DOWNLOAD_PROD_COS_SECRET_ID: 'production-id',
  107. DOWNLOAD_PROD_COS_SECRET_KEY: 'production-key',
  108. DSH_DESKTOP_AUTO_UPDATE_ENV: 'production',
  109. })).toEqual({
  110. DOWNLOAD_TEST_ORIGIN: 'https://desktop-updates.example.com',
  111. DOWNLOAD_TEST_COS_BUCKET: 'test-download-bucket',
  112. DOWNLOAD_PROD_COS_BUCKET: 'production-download-bucket',
  113. DSH_DESKTOP_AUTO_UPDATE_ENV: 'production',
  114. })
  115. })
  116. })