import { readFile } from 'node:fs/promises'; import { createHash } from 'node:crypto'; import { api, download, repositoryPath } from './gitea.mjs'; const config = JSON.parse(await readFile('release.json', 'utf8')); const descriptorBytes = await readFile('dist/release/trove-release.json'); const descriptor = JSON.parse(descriptorBytes); const { repository, tag } = descriptor; if (descriptor.schemaVersion !== 1 || repository !== config.repository) throw new Error('Unexpected release descriptor'); const route = `/repos/${repositoryPath(repository)}`; const files = new Map(); for (const plugin of descriptor.plugins) { for (const artifact of plugin.artifacts) { if (!/^[a-zA-Z0-9._+-]+\.curio$/.test(artifact.asset)) throw new Error('Invalid asset filename'); const bytes = await readFile(`dist/release/${artifact.asset}`); if (bytes.length !== artifact.size || createHash('sha256').update(bytes).digest('hex') !== artifact.sha256) throw new Error('Package changed after release preparation'); files.set(artifact.asset, bytes); } } files.set('trove-release.json', descriptorBytes); let release = await api(`${route}/releases/tags/${encodeURIComponent(tag)}`, { missing: true }); if (!release) release = await api(`${route}/releases`, { method: 'POST', body: { tag_name: tag, target_commitish: descriptor.commit, name: tag, draft: true, prerelease: tag.slice(1).split('+')[0].includes('-'), body: `${config.name} ${tag}\n\n通过 Trove 软件源安装和更新。`, } }); for (const [name, bytes] of files) { const existing = release.assets.find(asset => asset.name === name); if (existing) { const published = await download(existing.browser_download_url, undefined, bytes.length); if (!published.equals(bytes)) throw new Error(`Release asset is immutable: ${name}; publish a new version`); continue; } if (!release.draft) throw new Error(`Published release is incomplete: ${name}; publish a new version`); const form = new FormData(); form.append('attachment', new Blob([bytes]), name); const asset = await api(`${route}/releases/${release.id}/assets?name=${encodeURIComponent(name)}`, { method: 'POST', body: form }); release.assets.push(asset); } if (release.draft) await api(`${route}/releases/${release.id}`, { method: 'PATCH', body: { draft: false } }); console.log(`Published ${repository}@${tag}`); console.log('The release workflow will register these packages in the catalog.');