Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
110 lines
6.5 KiB
JavaScript
110 lines
6.5 KiB
JavaScript
const assert = require('node:assert/strict')
|
|
const test = require('node:test')
|
|
const fs = require('node:fs')
|
|
const os = require('node:os')
|
|
const path = require('node:path')
|
|
const vm = require('node:vm')
|
|
const { stagePublicAPIContext } = require('./stage_public_api_context.cjs')
|
|
|
|
const release = 'public-20260921-040700'
|
|
|
|
function publisher(t, action, failBuild = false) {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'public-api-publisher-'))
|
|
t.after(() => fs.rmSync(root, { recursive: true, force: true }))
|
|
const source = path.join(root, 'src')
|
|
for (const directory of ['scripts', 'migrations', 'frontend/dist']) fs.mkdirSync(path.join(source, directory), { recursive: true })
|
|
fs.mkdirSync(path.join(root, 'acceptance'))
|
|
fs.writeFileSync(path.join(source, 'scripts/Dockerfile.public-api'), fs.readFileSync(path.join(__dirname, 'Dockerfile.public-api')))
|
|
fs.writeFileSync(path.join(source, 'WeKnora-native-acceptance-next'), 'reviewed-api', { mode: 0o755 })
|
|
fs.writeFileSync(path.join(source, 'migrations/001.sql'), 'SELECT 1;\n')
|
|
fs.writeFileSync(path.join(root, 'acceptance/runtime.env'), 'DB_NAME=yawan_native_acceptance_20260915\n')
|
|
const directory = path.join(root, 'releases', release)
|
|
if (action === 'refreshAPI') {
|
|
fs.mkdirSync(directory, { recursive: true })
|
|
fs.writeFileSync(path.join(directory, 'manifest.json'), JSON.stringify({ release, stage: 'origin-ready',
|
|
api_image: 'yawan-api:previous', api_image_id: 'sha256:previous' }))
|
|
}
|
|
const calls = []
|
|
const module = { exports: {} }
|
|
const injectedRequire = name => {
|
|
if (name === 'node:fs') return { ...fs, copyFileSync(from, to, flags) {
|
|
if (from === '/Users/macclaw/.cloudflared/config.yml') {
|
|
calls.push({ kind: 'tunnel-backup', to })
|
|
return fs.writeFileSync(to, 'previous tunnel configuration\n')
|
|
}
|
|
return fs.copyFileSync(from, to, flags)
|
|
} }
|
|
if (name === 'node:child_process') return { execFileSync(binary, args) {
|
|
assert.equal(binary, 'docker')
|
|
assert.deepEqual(Array.from(args.slice(0, 2)), ['--context', 'colima-yawan'])
|
|
const command = Array.from(args.slice(2))
|
|
calls.push({ kind: 'docker', command })
|
|
if (command[0] === 'build' && command[2].startsWith('yawan-api:')) {
|
|
if (failBuild) throw new Error('stubbed API build failure')
|
|
assert.deepEqual(fs.readdirSync(command.at(-1)).sort(), ['Dockerfile', 'WeKnora-native-acceptance-next', 'migrations'])
|
|
}
|
|
return command[0] === 'image' ? 'sha256:built-image\n' : ''
|
|
} }
|
|
if (name === './preserve_frontend_assets.cjs') return { preserveFrontendAssets() { calls.push({ kind: 'retain-assets' }); return { retained: 7 } } }
|
|
if (name === './stage_public_api_context.cjs') return { stagePublicAPIContext }
|
|
return require(name)
|
|
}
|
|
const context = { require: injectedRequire, module, __dirname: path.join(source, 'scripts'), URL, AbortSignal,
|
|
fetch: async () => ({ ok: true }), console: { log() {} }, recordIdle: () => calls.push({ kind: 'idle' }) }
|
|
vm.runInNewContext(fs.readFileSync(path.join(__dirname, 'publish_public_runtime.cjs'), 'utf8')
|
|
+ '\n;idle = recordIdle; globalThis.actions = { prepare, refreshAPI };', context)
|
|
return { root, source, directory, calls, run: () => context.actions[action](release) }
|
|
}
|
|
|
|
test('prepare builds its API from the release snapshot after backups and retains frontend behavior', t => {
|
|
const value = publisher(t, 'prepare')
|
|
value.run()
|
|
const builds = value.calls.filter(call => call.kind === 'docker' && call.command[0] === 'build')
|
|
assert.deepEqual(builds.map(call => call.command), [
|
|
['build', '-t', `yawan-api:${release}`, path.join(value.directory, 'api-context')],
|
|
['build', '-t', `yawan-frontend:${release}`, path.join(value.source, 'frontend')],
|
|
])
|
|
const firstBuild = value.calls.indexOf(builds[0])
|
|
const backups = value.calls.filter(call => call.kind === 'docker' && call.command.includes('pg_dump'))
|
|
assert.equal(backups.length, 2)
|
|
assert.ok(backups.every(call => value.calls.indexOf(call) < firstBuild))
|
|
assert.ok(value.calls.find(call => call.kind === 'tunnel-backup'))
|
|
assert.ok(value.calls.find(call => call.kind === 'retain-assets'))
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(value.directory, 'manifest.json')))
|
|
assert.equal(manifest.stage, 'prepared')
|
|
assert.equal(manifest.api_image_id, 'sha256:built-image')
|
|
assert.equal(manifest.frontend_image_id, 'sha256:built-image')
|
|
assert.equal(manifest.retained_assets.retained, 7)
|
|
})
|
|
|
|
test('refresh-api uses its immutable revision snapshot and preserves idle and image identity checks', async t => {
|
|
const value = publisher(t, 'refreshAPI')
|
|
await value.run()
|
|
const buildIndex = value.calls.findIndex(call => call.kind === 'docker' && call.command[0] === 'build')
|
|
const build = value.calls[buildIndex].command
|
|
const revision = build[2].match(/-api-(\d{17})$/)[1]
|
|
assert.deepEqual(build, ['build', '-t', `yawan-api:${release}-api-${revision}`, path.join(value.directory, `api-context-${revision}`)])
|
|
const idleIndexes = value.calls.flatMap((call, index) => call.kind === 'idle' ? [index] : [])
|
|
const stopIndex = value.calls.findIndex(call => call.kind === 'docker' && call.command[0] === 'stop')
|
|
assert.equal(idleIndexes.length, 2)
|
|
assert.ok(idleIndexes[0] < buildIndex && buildIndex < idleIndexes[1] && idleIndexes[1] < stopIndex)
|
|
const start = value.calls.find(call => call.kind === 'docker' && call.command[0] === 'run').command
|
|
assert.equal(start.at(-1), 'sha256:built-image')
|
|
assert.ok(start.includes('WEKNORA_REVIEWED_API_IMAGE=sha256:built-image'))
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(value.directory, 'manifest.json')))
|
|
assert.equal(manifest.api_image_id, 'sha256:built-image')
|
|
assert.deepEqual(manifest.previous_apis, [{ image: 'yawan-api:previous', image_id: 'sha256:previous',
|
|
container: `yawan-native-acceptance-before-${revision}` }])
|
|
})
|
|
|
|
test('an API build failure retains the staged context and never stops the running API', async t => {
|
|
const value = publisher(t, 'refreshAPI', true)
|
|
await assert.rejects(value.run(), /stubbed API build failure/)
|
|
assert.equal(value.calls.some(call => call.kind === 'docker' && ['stop', 'rename', 'run'].includes(call.command[0])), false)
|
|
const build = value.calls.find(call => call.kind === 'docker' && call.command[0] === 'build').command
|
|
assert.equal(fs.readFileSync(path.join(build.at(-1), 'WeKnora-native-acceptance-next'), 'utf8'), 'reviewed-api')
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(value.directory, 'manifest.json')))
|
|
assert.equal(manifest.api_image_id, 'sha256:previous')
|
|
assert.equal(manifest.stage, 'origin-ready')
|
|
})
|