hypertwist/website/scripts/run-vps-same-origin-live-deploy-lib.test.mjs
2026-06-22 08:07:39 +00:00

129 lines
4.2 KiB
JavaScript

import { describe, expect, it } from 'vitest'
import {
buildDefaultLiveDeployBundleDir,
buildRemoteLiveDeployScript,
buildStageBundleRemoteCommand,
buildStageCheckoutRemoteCommand,
buildSshArgs,
extractLiveDeploySummary,
resolveLiveDeployOptions,
sanitizeLiveDeployManifest,
} from './run-vps-same-origin-live-deploy-lib.mjs'
function createManifest() {
return {
deploymentTier: 'preview',
checkoutRoot: '/srv/hypertwist/current',
publicOrigin: 'https://hypertwist.app',
serviceUser: 'hypertwist',
serviceGroup: 'hypertwist',
supportEmail: 'hello@hypertwist.app',
publicDocsUrl: 'https://hypertwist.app/resources',
releaseNotesUrl: 'https://hypertwist.app/changelog',
correspondingSourceUrl: 'https://git.scriptoriumai.io/scriptoriumadmin/hypertwist',
openSourceRepoUrl: 'https://git.scriptoriumai.io/scriptoriumadmin/hypertwist',
operatorCheckoutUrl: '',
windowsDownloadUrl: '',
releaseManifestVersion: '',
windowsRelease: {
buildId: '',
sha256: '',
publishedAt: '',
},
server: {
port: '3011',
billingStatePath: '/var/lib/hypertwist/auth/hypertwist-billing-state.json',
paddleWebhookSecret: 'super-secret-token',
},
}
}
describe('resolveLiveDeployOptions', () => {
it('normalizes the required CLI inputs', () => {
const options = resolveLiveDeployOptions({
manifestPath: 'deploy/hypertwist.same-origin.bundle.json',
identityFile: '/tmp/key',
vpsHost: '212.227.13.220',
vpsUser: 'root',
archiveSource: 'worktree',
bundleDir: '',
healthUrl: '',
waitSeconds: '45',
keepBundleDir: true,
skipLiveValidation: false,
json: true,
dryRun: false,
manifest: createManifest(),
gitRef: 'abc1234',
})
expect(options.vpsUser).toBe('root')
expect(options.archiveSource).toBe('worktree')
expect(options.bundleDir).toBe('/tmp/hypertwist-live-deploy-abc1234')
expect(options.healthUrl).toBe('https://hypertwist.app')
expect(options.waitSeconds).toBe(45)
expect(options.keepBundleDir).toBe(true)
})
})
describe('sanitizeLiveDeployManifest', () => {
it('masks secret-like values before dry-run output', () => {
const sanitized = sanitizeLiveDeployManifest(createManifest())
expect(sanitized.server.paddleWebhookSecret).toBe('su***en')
})
})
describe('buildRemoteLiveDeployScript', () => {
it('includes the expected root-owned deployment steps and summary marker', () => {
const script = buildRemoteLiveDeployScript({
checkoutRoot: '/srv/hypertwist/current',
bundleDir: '/tmp/hypertwist-live-deploy-abc1234',
keepBundleDir: false,
manifest: createManifest(),
})
expect(script).toContain('useradd --system')
expect(script).toContain('npm ci && npm --prefix server ci && npm run build')
expect(script).toContain('systemctl restart "$SERVICE_NAME"')
expect(script).toContain('nginx -t')
expect(script).toContain('__HYPERTWIST_LIVE_DEPLOY_SUMMARY__')
})
})
describe('extractLiveDeploySummary', () => {
it('parses the emitted summary marker from remote output', () => {
const summary = extractLiveDeploySummary([
'[live_checkout_root] /srv/hypertwist/current',
'__HYPERTWIST_LIVE_DEPLOY_SUMMARY__{"ok":true,"serviceStatus":"active","nginxStatus":"active"}',
].join('\n'))
expect(summary).toEqual({
ok: true,
serviceStatus: 'active',
nginxStatus: 'active',
})
})
})
describe('ssh helpers', () => {
it('builds the archive and ssh command shapes', () => {
expect(buildDefaultLiveDeployBundleDir('abc1234')).toBe('/tmp/hypertwist-live-deploy-abc1234')
expect(buildStageCheckoutRemoteCommand('/srv/hypertwist/current')).toContain('tar -xf - -C "/srv/hypertwist/current"')
expect(buildStageBundleRemoteCommand('/tmp/hypertwist-live-deploy-abc1234')).toContain('tar -xf - -C "/tmp/hypertwist-live-deploy-abc1234"')
expect(buildSshArgs({
identityFile: '/tmp/key',
vpsUser: 'root',
vpsHost: '212.227.13.220',
remoteCommand: 'echo hello',
})).toEqual([
'-i',
'/tmp/key',
'-o',
'StrictHostKeyChecking=no',
'root@212.227.13.220',
'echo hello',
])
})
})