mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-10-26 16:55:08 +00:00
Review found that `apps/desktop/README.md#release-versions` and the 2026-09-16 version-derivation note already specify this convention, and that three of their requirements were reversed without saying so. The rules themselves are right; what was wrong was leaving them undocumented and rejecting one of the forms they prescribe. A stable base takes `-test.YYYYMMDD.index`, which validation refused because such a version ranks below its base. That ordering is the point: the form belongs to a test feed that never serves the production release. Both READMEs, the older note, and a new note now record which requirements this change reverses and why. Three defects the review found, each reproducible: - `afterPack` compared the bundled runtime against the product version, which broke installed-update qualification: that flow passes a runtime whose version was deliberately rewritten. The expected version is now a parameter the preparer supplies, and `verifyDesktopRuntime` says "bundled X is not the expected Y" rather than naming Electron. - Upload could only learn the published version from a shell variable, conflicting with "release fields come only from the target file". It reads the completion record packaging wrote, and a mismatch now prints the version that record holds. - Automatic numbering read one listing page and one fixed directory. It now follows every page, discards a listing it could not finish rather than reusing an index that would overwrite a published installer, bounds the request through the client's own timeout, and reads the directory an unsigned build actually writes. Also: `npm run` and `yarn run` set `npm_execpath` too, so the pnpm resolution checks the path names pnpm; the argument separator can arrive after a run script's preset arguments, not only first; and the toolchain probe, parser, build commit, and tarball readers now have specs.
52 lines
2.3 KiB
TypeScript
52 lines
2.3 KiB
TypeScript
import { execFileSync } from 'node:child_process'
|
|
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { basename, dirname, join } from 'node:path'
|
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
import { capture, pnpmCommand } from './process.ts'
|
|
import { packedIdentity, tarballFiles } from './tarball.ts'
|
|
|
|
const directories: string[] = []
|
|
|
|
afterEach(async () => {
|
|
for (const directory of directories.splice(0)) await rm(directory, { recursive: true, force: true })
|
|
})
|
|
|
|
/**
|
|
* Pack one manifest into a tarball shaped like `npm pack` output.
|
|
* @returns Absolute path of the archive.
|
|
*/
|
|
async function packedTarball(name: string, version: string): Promise<string> {
|
|
const directory = await mkdtemp(join(tmpdir(), 'dsh-tarball-'))
|
|
directories.push(directory)
|
|
const contents = join(directory, 'package')
|
|
await import('node:fs/promises').then(async fs => fs.mkdir(contents))
|
|
await writeFile(join(contents, 'package.json'), JSON.stringify({ name, version }))
|
|
await writeFile(join(contents, 'index.js'), '')
|
|
const archive = join(directory, `${name.replaceAll('/', '-').replace('@', '')}-${version}.tgz`)
|
|
execFileSync('tar', ['-czf', basename(archive), 'package'], { cwd: dirname(archive) })
|
|
return archive
|
|
}
|
|
|
|
describe('release process helpers', () => {
|
|
it('runs pnpm through a JavaScript entry, which spawnSync can start on Windows', () => {
|
|
const [command, ...args] = pnpmCommand()
|
|
expect(command === 'pnpm' || /node(?:\.exe)?$/iu.test(command)).toBe(true)
|
|
if (command !== 'pnpm') expect(args[0]).toMatch(/pnpm/u)
|
|
expect(capture(command, [...args, '--version'])).toMatch(/^\d+\.\d+\.\d+/u)
|
|
})
|
|
})
|
|
|
|
describe('release tarball readers', () => {
|
|
it('lists members of an archive under an absolute path', async () => {
|
|
// GNU tar reads the colon in a Windows drive path as a remote host, so the readers run beside the archive.
|
|
const archive = await packedTarball('@deepseek-ai/dsh-probe', '1.2.3')
|
|
expect(tarballFiles(archive)).toEqual(expect.arrayContaining(['package/package.json', 'package/index.js']))
|
|
})
|
|
|
|
it('reads what an archive declares about itself', async () => {
|
|
const archive = await packedTarball('@deepseek-ai/dsh-probe', '1.2.3')
|
|
expect(packedIdentity(archive)).toEqual({ name: '@deepseek-ai/dsh-probe', version: '1.2.3' })
|
|
})
|
|
})
|