Files
orca/config/scripts/package-linux-formats.test.mjs
T
OrcaWinandm4air 1882458f44 ci: scope orcad smoke and parallelize Linux packages (#23314)
* ci: scope orcad smoke and parallelize Linux package formats

* ci: validate packaging when its copy dependency changes

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 20:44:15 -07:00

212 lines
7.1 KiB
JavaScript

import {
chmodSync,
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
readdirSync,
readlinkSync,
rmSync,
statSync,
symlinkSync,
writeFileSync
} from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import { linuxFormatArguments, packageLinuxFormats } from './package-linux-formats.mjs'
let root
let preparedDirectory
let outputDirectory
const targets = ['AppImage', 'deb', 'rpm']
const valueAfter = (args, flag) => args[args.indexOf(flag) + 1]
beforeEach(() => {
root = mkdtempSync(join(tmpdir(), 'orca formats with spaces-'))
preparedDirectory = join(root, 'prepared app')
outputDirectory = join(root, 'output packages')
mkdirSync(join(preparedDirectory, 'resources'), { recursive: true })
mkdirSync(outputDirectory)
writeFileSync(join(preparedDirectory, 'resources/package-type'), 'AppImage')
writeFileSync(join(preparedDirectory, 'resources/app.asar'), 'verified application')
writeFileSync(join(preparedDirectory, 'orca-ide'), 'executable')
chmodSync(join(preparedDirectory, 'orca-ide'), 0o755)
})
afterEach(() => rmSync(root, { recursive: true, force: true }))
function emitPackage(args) {
const format = valueAfter(args, '--linux')
const app = valueAfter(args, '--prepackaged')
const output = valueAfter(args, '--config.directories.output')
writeFileSync(join(app, 'resources/package-type'), format)
mkdirSync(output, { recursive: true })
writeFileSync(join(output, `orca.${format}`), format)
writeFileSync(join(output, 'latest-linux.yml'), format)
return { format, app, output }
}
it('preserves configured hooks, architecture, names, and PR compression with exact argv', () => {
const args = linuxFormatArguments({
format: 'deb',
appDirectory: '/app with spaces',
outputDirectory: '/out with spaces'
})
expect(args).toEqual([
'--config',
'config/electron-builder.config.cjs',
'--linux',
'deb',
'--x64',
'--publish',
'never',
'--prepackaged',
'/app with spaces',
'--config.directories.output',
'/out with spaces',
'--config.deb.compression=gz',
'--config.rpm.compression=gzip'
])
expect(() => linuxFormatArguments({ format: 'zip' })).toThrow('Unsupported Linux package format')
})
describe('independent Linux package formats', () => {
it('starts all formats before awaiting completion and isolates metadata writes', async () => {
if (process.platform !== 'win32') {
symlinkSync('resources/package-type', join(preparedDirectory, 'marker-link'))
}
let release
const gate = new Promise((resolve) => {
release = resolve
})
const copies = []
await packageLinuxFormats({
preparedDirectory,
outputDirectory,
runBuilder: async (args) => {
const app = valueAfter(args, '--prepackaged')
const format = valueAfter(args, '--linux')
expect(readFileSync(join(app, 'resources/package-type'), 'utf8')).toBe('AppImage')
expect(readFileSync(join(app, 'resources/app.asar'), 'utf8')).toBe('verified application')
if (process.platform !== 'win32') {
expect(readlinkSync(join(app, 'marker-link'))).toBe('resources/package-type')
expect(statSync(join(app, 'orca-ide')).mode & 0o777).toBe(0o755)
expect(statSync(join(app, 'resources/package-type')).ino).not.toBe(
statSync(join(preparedDirectory, 'resources/package-type')).ino
)
}
copies.push(app)
if (copies.length === 3) {
release()
}
await gate
expect(readdirSync(outputDirectory)).toHaveLength(1)
emitPackage(args)
await Promise.resolve()
expect(readFileSync(join(app, 'resources/package-type'), 'utf8')).toBe(format)
}
})
expect(new Set(copies).size).toBe(3)
expect(readFileSync(join(preparedDirectory, 'resources/package-type'), 'utf8')).toBe('AppImage')
expect(readFileSync(join(preparedDirectory, 'resources/app.asar'), 'utf8')).toBe(
'verified application'
)
for (const format of targets) {
expect(readFileSync(join(outputDirectory, `orca.${format}`), 'utf8')).toBe(format)
expect(
readFileSync(
join(outputDirectory, 'linux-package-formats', format, 'latest-linux.yml'),
'utf8'
)
).toBe(format)
}
expect(
readdirSync(outputDirectory).some((name) => name.startsWith('.linux-package-formats-'))
).toBe(false)
})
it('settles every worker before cleanup and exposes no partial artifact on failure', async () => {
const finished = []
let release
const gate = new Promise((resolve) => {
release = resolve
})
await expect(
packageLinuxFormats({
preparedDirectory,
outputDirectory,
runBuilder: async (args) => {
const format = valueAfter(args, '--linux')
if (format === 'AppImage') {
throw new Error('compression failed')
}
if (format === 'rpm') {
release()
}
await gate
const { app } = emitPackage(args)
expect(existsSync(app)).toBe(true)
finished.push(format)
}
})
).rejects.toMatchObject({
message: 'Linux package formats failed',
errors: [
expect.objectContaining({
message: 'AppImage packaging failed',
cause: expect.objectContaining({ message: 'compression failed' })
})
]
})
expect(finished.sort()).toEqual(['deb', 'rpm'])
expect(readdirSync(outputDirectory)).toEqual([])
expect(readFileSync(join(preparedDirectory, 'resources/package-type'), 'utf8')).toBe('AppImage')
})
it('rejects missing artifacts even when the builder reports success', async () => {
await expect(
packageLinuxFormats({
preparedDirectory,
outputDirectory,
runBuilder: async (args) => {
const result = emitPackage(args)
if (result.format === 'rpm') {
writeFileSync(join(result.output, 'orca.rpm'), '')
}
}
})
).rejects.toThrow('Linux package formats failed')
expect(readdirSync(outputDirectory)).toEqual([])
})
it('does not replace existing output packages', async () => {
writeFileSync(join(outputDirectory, 'orca.deb'), 'previous package')
await expect(
packageLinuxFormats({
preparedDirectory,
outputDirectory,
runBuilder: async (args) => {
emitPackage(args)
}
})
).rejects.toThrow('Refusing to replace existing package output')
expect(readdirSync(outputDirectory)).toEqual(['orca.deb'])
expect(readFileSync(join(outputDirectory, 'orca.deb'), 'utf8')).toBe('previous package')
})
it('rejects a tree already mutated by a previous root-package build', async () => {
writeFileSync(join(preparedDirectory, 'resources/package-type'), 'rpm')
await expect(
packageLinuxFormats({
preparedDirectory,
outputDirectory,
runBuilder: async () => {
throw new Error('must not run')
}
})
).rejects.toThrow('Expected a fresh Linux directory build')
expect(readdirSync(outputDirectory)).toEqual([])
})
})