Files
orca/config/scripts/node-server-package-workflow-contract.test.mjs
T

130 lines
5.3 KiB
JavaScript

import { spawnSync } from 'node:child_process'
import { readFileSync } from 'node:fs'
import { join, win32 } from 'node:path'
import { describe, expect, it, vi } from 'vitest'
import { resolveNodeServerNpmInvocation } from './node-server-npm-invocation.mjs'
const dockerfile = readFileSync(join('config', 'docker', 'node-server', 'Dockerfile'), 'utf8')
const releaseWorkflow = readFileSync(join('.github', 'workflows', 'release-cut.yml'), 'utf8')
describe('Node server package workflow contract', () => {
it('verifies the selected Node archive before extracting it', () => {
const checksumDownload = dockerfile.indexOf('SHASUMS256.txt')
const checksumVerification = dockerfile.indexOf('sha256sum -c -')
const extraction = dockerfile.indexOf('tar -xJf "$archive"')
expect(checksumDownload).toBeGreaterThanOrEqual(0)
expect(checksumVerification).toBeGreaterThan(checksumDownload)
expect(extraction).toBeGreaterThan(checksumVerification)
expect(dockerfile).toContain('grep " ${archive}$" SHASUMS256.txt')
})
it('invokes the adjacent npm CLI through Node on Windows', () => {
const executablePath = win32.join('C:\\', 'node', 'node.exe')
const invocation = resolveNodeServerNpmInvocation({
platform: 'win32',
executablePath,
pathExists: vi.fn(() => true)
})
expect(invocation).toEqual({
command: executablePath,
prefixArgs: [win32.join('C:\\', 'node', 'node_modules', 'npm', 'bin', 'npm-cli.js')]
})
})
it('uses npm directly outside Windows', () => {
expect(resolveNodeServerNpmInvocation({ platform: 'linux' })).toEqual({
command: 'npm',
prefixArgs: []
})
})
it('fails before packing when the adjacent Windows npm CLI is absent', () => {
expect(() =>
resolveNodeServerNpmInvocation({
platform: 'win32',
executablePath: win32.join('C:\\', 'node', 'node.exe'),
pathExists: () => false
})
).toThrow('npm CLI is missing beside Node')
})
it('publishes the exact verified package through npm trusted publishing', () => {
expect(releaseWorkflow).toMatch(/publish-npm-server:\n[\s\S]*?id-token: write/)
expect(releaseWorkflow).toContain('pnpm run verify:node-server-package')
expect(releaseWorkflow).toContain('pnpm run verify:node-server-docker -- --ubuntu 20.04')
expect(releaseWorkflow).toMatch(
/publish-npm-server:[\s\S]*?verify-release-required-assets\.mjs/
)
expect(releaseWorkflow).toContain('npm 11.5.1 or newer is required for trusted publishing')
expect(releaseWorkflow).toContain(
'npm publish "$archive" --access public --tag "$dist_tag" --provenance'
)
expect(releaseWorkflow).toContain('different immutable bytes')
expect(releaseWorkflow).toMatch(/publish-release:\n[\s\S]*?- publish-npm-server/)
})
it('advances rc only for an unsuffixed release candidate', () => {
expect(releaseWorkflow).toContain(
'if [[ "$version" =~ ^[0-9]+\\.[0-9]+\\.[0-9]+-rc\\.(0|[1-9][0-9]*)$ ]]'
)
expect(releaseWorkflow).toContain('dist_tag=rc')
expect(releaseWorkflow).toContain('elif [[ "$version" == *-* ]]')
expect(releaseWorkflow).toContain('dist_tag=build')
expect(releaseWorkflow).toContain('dist_tag=latest')
})
it('repairs the expected dist-tag when an immutable publish is retried', () => {
const immutableMatch = releaseWorkflow.indexOf(
'@stablyai/orca@$version is already published with the expected bytes.'
)
const tagRead = releaseWorkflow.indexOf(
'npm view "@stablyai/orca" dist-tags --json --prefer-online'
)
const oidcExchange = releaseWorkflow.indexOf(
'/-/npm/v1/oidc/token/exchange/package/%40stablyai%2Forca'
)
const tagRepair = releaseWorkflow.indexOf(
'npm dist-tag add "@stablyai/orca@$version" "$dist_tag"'
)
const repairedTagCheck = releaseWorkflow.indexOf('repaired_tag_version=')
expect(tagRead).toBeGreaterThan(immutableMatch)
expect(oidcExchange).toBeGreaterThan(tagRead)
expect(tagRepair).toBeGreaterThan(oidcExchange)
expect(repairedTagCheck).toBeGreaterThan(tagRepair)
expect(releaseWorkflow).toContain('NODE_AUTH_TOKEN="$npm_token" npm dist-tag add')
expect(releaseWorkflow).toContain('node - "$version" "$remote_tag_version"')
expect(releaseWorkflow).toContain('compare(candidate, current) > 0')
expect(releaseWorkflow).toContain(
'npm dist-tag $dist_tag already points to newer $remote_tag_version; leaving it unchanged.'
)
expect(releaseWorkflow.indexOf('compare(candidate, current) > 0')).toBeLessThan(oidcExchange)
})
it('never repairs a dist-tag backward', () => {
const match = releaseWorkflow.match(
/node - "\$version" "\$remote_tag_version" <<'NODE'\n([\s\S]*?)\n {10}NODE/
)
expect(match?.[1]).toBeDefined()
const comparisonScript = match?.[1]?.replace(/^ {10}/gm, '') ?? ''
const cases = [
['1.5.0', '1.4.9', 0],
['1.4.9', '1.5.0', 1],
['1.5.0-rc.4', '1.5.0-rc.3', 0],
['1.5.0-rc.3', '1.5.0-rc.4', 1],
['1.5.0', '1.5.0-rc.9', 0],
['1.5.0-rc.9', '1.5.0', 1],
['1.5.0-rc.4.perf', '1.5.0-rc.4', 0]
]
for (const [candidate, current, expectedStatus] of cases) {
const result = spawnSync(process.execPath, ['-', candidate, current], {
input: comparisonScript
})
expect(result.status, `${candidate} compared with ${current}`).toBe(expectedStatus)
}
})
})