visual-journal / scripts /deploy-hf-space.test.mjs
misonL's picture
Deploy a623efc to Docker Space
6825c0c verified
Raw
History Blame
10.4 kB
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import {
GIT_ARCHIVE_MAX_BUFFER_BYTES,
assertDeployMarkerMatches,
buildDeployMarker,
buildDeployMarkerRouteSource,
buildUploadArgs,
extractUploadCommitSha,
findRemoteDeletePaths,
parseRepositorySlug,
waitForRunning
} from './deploy-hf-space.mjs';
describe('HF Space deploy script', () => {
it('extracts the Space commit SHA from hf upload JSON output', () => {
const sha = extractUploadCommitSha(
[
'Start hashing 189 files.',
'{"url":"https://huggingface.co/spaces/misonL/gpt-image-playground-customer/commit/32151b6aeaec0e59f14d1aaa87fba160ca8410df"}'
].join('\n')
);
assert.equal(sha, '32151b6aeaec0e59f14d1aaa87fba160ca8410df');
});
it('rejects upload output without a Space commit URL', () => {
assert.throws(() => extractUploadCommitSha('{"url":"https://huggingface.co/spaces/misonL/demo"}'), /commit SHA or commit URL/);
});
it('extracts the Space commit SHA from direct hf upload JSON fields', () => {
assert.equal(
extractUploadCommitSha('{"sha":"cccccccccccccccccccccccccccccccccccccccc"}'),
'cccccccccccccccccccccccccccccccccccccccc'
);
assert.equal(
extractUploadCommitSha('{"commit_sha":"dddddddddddddddddddddddddddddddddddddddd"}'),
'dddddddddddddddddddddddddddddddddddddddd'
);
});
it('extracts the Space commit SHA when hf prints warning lines before JSON', () => {
const sha = extractUploadCommitSha(
[
'[WARN] retrying upload metadata',
'{"url":"https://huggingface.co/spaces/misonL/gpt-image-playground-customer/commit/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}',
'done'
].join('\n')
);
assert.equal(sha, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
});
it('builds upload args without embedding newline characters in commit metadata', () => {
const args = buildUploadArgs({
sourceDir: '/tmp/source',
localSha: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
repoSlug: 'MisonL/gpt-image-playground-customer'
});
assert.equal(args.includes('--json'), true);
assert.equal(args[args.indexOf('--commit-message') + 1], 'Deploy bbbbbbb to Docker Space');
assert.equal(
args[args.indexOf('--commit-description') + 1],
'Source: MisonL/gpt-image-playground-customer@bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
);
assert.equal(args.some((arg) => arg.includes('\n')), false);
});
it('uses a provided repository slug in upload commit metadata', () => {
const args = buildUploadArgs({
sourceDir: '/tmp/source',
localSha: 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
repoSlug: 'owner/repo'
});
assert.equal(args[args.indexOf('--commit-description') + 1], 'Source: owner/repo@eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee');
});
it('parses GitHub repository slugs from common origin URL formats', () => {
assert.equal(parseRepositorySlug('https://github.com/MisonL/gpt-image-playground-customer.git'), 'MisonL/gpt-image-playground-customer');
assert.equal(parseRepositorySlug('git@github.com:MisonL/gpt-image-playground-customer.git'), 'MisonL/gpt-image-playground-customer');
assert.throws(() => parseRepositorySlug('not-a-github-url'), /Set REPO_SLUG=owner\/repo/);
});
it('requires an explicit repository slug for upload metadata', () => {
assert.throws(
() =>
buildUploadArgs({
sourceDir: '/tmp/source',
localSha: 'ffffffffffffffffffffffffffffffffffffffff'
}),
/REPO_SLUG is required/
);
});
it('keeps enough buffer for repository archives used by Space uploads', () => {
assert.ok(GIT_ARCHIVE_MAX_BUFFER_BYTES >= 128 * 1024 * 1024);
});
it('adds delete args for remote files that are no longer in git HEAD', () => {
const args = buildUploadArgs({
sourceDir: '/tmp/source',
localSha: '1111111111111111111111111111111111111111',
repoSlug: 'owner/repo',
deletePaths: ['old-file.md', 'scripts/old-script.mjs']
});
assert.deepEqual(args.slice(-4), ['--delete', 'old-file.md', '--delete', 'scripts/old-script.mjs']);
});
it('rejects unsafe delete path values before invoking hf upload', () => {
assert.throws(
() =>
buildUploadArgs({
sourceDir: '/tmp/source',
localSha: '2222222222222222222222222222222222222222',
repoSlug: 'owner/repo',
deletePaths: ['bad\npath']
}),
/deletePaths must contain/
);
});
it('finds stale remote files deterministically', () => {
assert.deepEqual(
findRemoteDeletePaths(new Set(['README.md', 'src/app.ts']), ['old.md', 'src/app.ts', 'README.md']),
['old.md']
);
});
it('builds a non-secret deploy marker for service-side deployment verification', () => {
const marker = buildDeployMarker(
'3333333333333333333333333333333333333333',
new Date('2026-06-20T10:00:00.000Z'),
'deploy-333'
);
assert.deepEqual(marker, {
schema_version: 1,
local_sha: '3333333333333333333333333333333333333333',
created_at: '2026-06-20T10:00:00.000Z',
deploy_id: 'deploy-333'
});
assert.doesNotMatch(JSON.stringify(marker), /key|token|secret|password/i);
});
it('builds a unique deploy marker id when none is provided', () => {
const first = buildDeployMarker('3333333333333333333333333333333333333333', new Date('2026-06-20T10:00:00.000Z'));
const second = buildDeployMarker('3333333333333333333333333333333333333333', new Date('2026-06-20T10:00:00.000Z'));
assert.match(first.deploy_id, /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
assert.notEqual(first.deploy_id, second.deploy_id);
});
it('rejects short deploy marker commit shas before upload', () => {
assert.throws(() => buildDeployMarker('3333333'), /full git commit SHA/);
});
it('rejects unsafe deploy marker ids before upload', () => {
assert.throws(
() =>
buildDeployMarker(
'3333333333333333333333333333333333333333',
new Date('2026-06-20T10:00:00.000Z'),
'deploy\n333'
),
/deployId must be/
);
});
it('rejects stale deploy markers from an older same-commit deployment', () => {
const expected = buildDeployMarker(
'3333333333333333333333333333333333333333',
new Date('2026-06-20T10:00:00.000Z'),
'deploy-current'
);
const stale = buildDeployMarker(
'3333333333333333333333333333333333333333',
new Date('2026-06-20T09:00:00.000Z'),
'deploy-stale'
);
assert.throws(() => assertDeployMarkerMatches(stale, expected), /created_at mismatch/);
assert.deepEqual(assertDeployMarkerMatches(expected, expected), expected);
});
it('rejects deploy markers with a stale deploy id even when the source commit and timestamp match', () => {
const expected = buildDeployMarker(
'3333333333333333333333333333333333333333',
new Date('2026-06-20T10:00:00.000Z'),
'deploy-current'
);
const stale = {
...expected,
deploy_id: 'deploy-stale'
};
assert.throws(() => assertDeployMarkerMatches(stale, expected), /deploy_id mismatch/);
});
it('waits for the public service marker after management reports the new Space commit running', async () => {
const marker = buildDeployMarker(
'5555555555555555555555555555555555555555',
new Date('2026-06-20T12:00:00.000Z'),
'deploy-555'
);
let verifyCount = 0;
const runtime = await waitForRunning('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', marker, {
attempts: 2,
intervalMs: 0,
readInfo: () => ({
runtime: { stage: 'RUNNING' },
sha: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
}),
verifyMarker: async () => {
verifyCount += 1;
if (verifyCount === 1) throw new Error('deploy marker deploy_id mismatch');
return marker;
},
sleep: async () => {},
log: () => {}
});
assert.equal(verifyCount, 2);
assert.deepEqual(runtime, {
stage: 'RUNNING',
sha: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
service_marker_verified: true,
marker
});
});
it('builds a no-store API route for service-side deploy marker verification', () => {
const marker = buildDeployMarker(
'4444444444444444444444444444444444444444',
new Date('2026-06-20T11:00:00.000Z'),
'deploy-444'
);
const source = buildDeployMarkerRouteSource(marker);
assert.match(source, /NextResponse\.json/);
assert.match(source, /Cache-Control/);
assert.match(source, /no-store/);
assert.match(source, /4444444444444444444444444444444444444444/);
assert.match(source, /deploy-444/);
assert.doesNotMatch(source, /key|token|secret|password/i);
});
it('keeps the generated deploy markers from being deleted on upload', () => {
assert.deepEqual(
findRemoteDeletePaths(new Set(['README.md', 'public/hf-space-deploy-marker.json', 'src/app/api/deploy-marker/route.ts']), [
'README.md',
'public/hf-space-deploy-marker.json',
'src/app/api/deploy-marker/route.ts',
'old.md'
]),
['old.md']
);
});
});