From 557ed8afd08aff5bbf652d18c2b563f5f01dc0a0 Mon Sep 17 00:00:00 2001 From: render Date: Fri, 11 Sep 2026 10:58:33 +0800 Subject: [PATCH] chore(catalog): initialize production plugin source --- .gitea/workflows/sync-release.yml | 49 +++++++++++++++++ .gitignore | 11 ++++ .npmrc | 1 + README.md | 27 ++++++++++ docs/development.md | 59 +++++++++++++++++++++ docs/versioning.md | 9 ++++ package.json | 14 +++++ pnpm-lock.yaml | 24 +++++++++ source/index.json | 54 +++++++++++++++++++ source/repositories.json | 18 +++++++ tools/ci-runtime.sh | 25 +++++++++ tools/gitea.mjs | 87 +++++++++++++++++++++++++++++++ tools/notify-release.mjs | 7 +++ tools/prepare-release.mjs | 11 ++++ tools/publish-release.mjs | 40 ++++++++++++++ tools/release-catalog.mjs | 35 +++++++++++++ tools/release-plan.mjs | 45 ++++++++++++++++ tools/sync-release.mjs | 80 ++++++++++++++++++++++++++++ 18 files changed, 596 insertions(+) create mode 100644 .gitea/workflows/sync-release.yml create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 README.md create mode 100644 docs/development.md create mode 100644 docs/versioning.md create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 source/index.json create mode 100644 source/repositories.json create mode 100644 tools/ci-runtime.sh create mode 100644 tools/gitea.mjs create mode 100644 tools/notify-release.mjs create mode 100644 tools/prepare-release.mjs create mode 100644 tools/publish-release.mjs create mode 100644 tools/release-catalog.mjs create mode 100644 tools/release-plan.mjs create mode 100644 tools/sync-release.mjs diff --git a/.gitea/workflows/sync-release.yml b/.gitea/workflows/sync-release.yml new file mode 100644 index 0000000..8f2a5ff --- /dev/null +++ b/.gitea/workflows/sync-release.yml @@ -0,0 +1,49 @@ +name: Register plugin release +on: + workflow_dispatch: + inputs: + repository: + description: Plugin repository (owner/name) + required: true + type: string + tag: + description: Published release tag + required: true + type: string +jobs: + register: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check out catalog from Gitea + env: + CHECKOUT_TOKEN: ${{ secrets.GITEA_TOKEN }} + GITEA_SERVER_URL: ${{ gitea.server_url }} + run: | + set -eu + auth_script=$(mktemp) + trap 'rm -f "$auth_script"' EXIT + cat > "$auth_script" <<'AUTH' + #!/bin/sh + case "$1" in + *Username*) printf '%s\n' x-access-token ;; + *) printf '%s\n' "$CHECKOUT_TOKEN" ;; + esac + AUTH + chmod 700 "$auth_script" + GIT_ASKPASS="$auth_script" GIT_TERMINAL_PROMPT=0 git clone --quiet --depth 1 --branch main "$GITEA_SERVER_URL/trove/curios.git" catalog + - name: Register completed release + working-directory: catalog + run: | + source tools/ci-runtime.sh + node tools/sync-release.mjs --publish + env: + GITEA_SERVER_URL: ${{ gitea.server_url }} + GITEA_TOKEN: ${{ secrets.PLUGIN_RELEASE_TOKEN }} + CATALOG_WRITE_TOKEN: ${{ secrets.GITEA_TOKEN }} + CATALOG_REPOSITORY: ${{ gitea.repository }} + RELEASE_REPOSITORY: ${{ inputs.repository }} + RELEASE_TAG: ${{ inputs.tag }} + NPM_REGISTRY: ${{ vars.NPM_REGISTRY }} + NODE_MIRROR: ${{ vars.NODE_MIRROR }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b63ec40 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +node_modules/ +dist/ +.env +.env.* +*.curio +.DS_Store +target/ +.trove/ +/curios/ +/shared/ +/vendor/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..7549542 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmmirror.com diff --git a/README.md b/README.md new file mode 100644 index 0000000..a09545c --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# Trove Curios + +**让桌面,多一些可能。** + +发现专注、轻巧的桌面工具,把常用能力带到手边。 + +## Harmony Mirror + +让鸿蒙,来到桌面。独立投屏窗口,鼠标与键盘直接操作手机。 + +[探索 Harmony Mirror →](https://git.render.ink/trove-curios/harmony-mirror) + +## Harmony Assistant + +鸿蒙随行,资料有序。收发完整文件夹,管理应用,让重要资料留在身边。 + +[探索 Harmony Assistant →](https://git.render.ink/trove-curios/harmony-assistant) + +## 带到你的桌面 + +在 Trove 的「软件源」中添加 Git 仓库: + +```text +https://git.render.ink/trove/curios.git +``` + +选择喜欢的 Curio,安装,即刻使用。 diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..2357c03 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,59 @@ +# 官方软件源的维护与发布 + +`trove/curios` 保存官方软件源索引、插件仓库登记和发布工具。底座在 `trove/app`;插件源码与安装包分别位于 `trove-curios` 下各仓库的代码和 Releases。 + +## 仓库职责 + +- `source/repositories.json`:登记插件 ID 与发布仓库的对应关系。 +- `source/index.json`:底座消费的 Source Index v1,保留版本、兼容范围、平台、Release 附件 URL、大小与 SHA-256。 +- `tools/prepare-release.mjs`:手动构建后生成发布目录。 +- `tools/publish-release.mjs`:可选的命令行上传工具,上传全部附件后发布 Release。 +- `tools/notify-release.mjs`:由插件仓库的 Linux workflow 在 Release 发布后触发源收录。 +- `tools/sync-release.mjs`:校验登记关系和附件,合并版本,通过文件 SHA 比较后更新远端索引。 +- `.gitea/workflows/sync-release.yml`:在 Linux runner 上执行收录。 + +安装包不进入 Git,所有 `*.curio` 都被忽略。Git 软件源仍指向 `https://git.render.ink/trove/curios.git`。 + +## 发布协议 + +插件仓库根目录的 `release.json` 声明仓库、插件 ID。每个仓库只发布一个插件,tag 为 `v`。 + +Release 先以草稿创建,上传每个平台的 `.curio` 和 `trove-release.json` 后再发布。描述文件包含仓库、tag、源码 commit、插件 Manifest 摘要,以及附件名、平台、大小和 SHA-256。插件图标以小型图片 Data URL 收录,私有图片也无需额外鉴权。 + +本机手动生成发布目录,上传全部附件并发布 Release 后,插件的 Linux workflow 使用 `CATALOG_TOKEN` 调用源仓库的 `sync-release.yml`,传入 `repository` 与 `tag`。收录只接受登记仓库及其所属插件 ID,并下载附件校验大小和 SHA-256。 + +源 workflow 使用 `PLUGIN_RELEASE_TOKEN` 读取私有插件 Release,使用本任务的 `GITEA_TOKEN` 更新自身索引。写入以 Gitea Contents API 的当前文件 SHA 为前提,并发冲突后重新读取、重新合并,不覆盖其他发布。 + +相同插件 ID、版本和平台的产物不可变。重复收录没有副作用;相同版本的 URL、大小或 SHA-256 发生变化会报错。 + +## 新增插件 + +1. 在 `trove-curios` 创建独立仓库,添加源码、`curio.json`、`release.json` 和发布 workflow。 +2. 将仓库与 ID 登记到 `source/repositories.json`,授予收录机器人读取该仓库的代码与 Release 的权限。 +3. 在对应平台准备构建环境与 Trove CLI,提交源码,运行插件仓库的手动发布脚本并上传 Release。 + +现有插件仓库中的发布 workflow 可作为模板。发布工具从源仓库检出,统一维护。 + +## 失败恢复 + +Release 成功但收录失败时,在插件 Actions 手动运行发布 workflow,填写已有 tag;该 workflow 使用 Linux runner,只重试收录,不重新构建或替换附件。也可在源仓库直接运行收录 workflow。 + +## 私有源 + +当前仓库保持私有。底座用本机 Git 凭据读取索引;下载同一 Git 服务器上的私有 Release 附件时,在服务器要求鉴权后查询 Git HTTPS credential helper。账户必须能读取源仓库和对应插件仓库。SSH 密钥仅用于 Git,附件下载还需要本机 HTTPS 凭据。凭据不写进索引或安装包。 + +## 自动化身份 + +`trove-publisher` 负责跨仓库通信:可以读取源代码、触发源 Actions,并读取已登记插件的 Release;没有底座仓库访问权限,也不能直接改写源代码。源索引写入由源 workflow 自身的任务令牌完成。 + +## 大陆网络环境 + +发布流程直接从本 Gitea 拉取源代码,不依赖 GitHub 的 checkout/setup-node Action,也不在 Linux runner 上构建 macOS 原生产物。 + +- npm 默认 `https://registry.npmmirror.com`;仓库级 `.npmrc` 也使用该镜像。 +- runner 已有 Node.js 22+ 时直接复用;否则从 `https://npmmirror.com/mirrors/node` 下载固定 Node.js 22.23.2,并校验预置的官方 SHA-256。 +- 收录只安装锁定版本的 semver,不下载 Corepack/pnpm,不执行 npm 生命周期脚本。 +- Actions Variables `NPM_REGISTRY`、`NODE_MIRROR` 可覆盖镜像地址,未设置时采用上述国内地址。 +- Linux job 需要 bash、git、curl、tar、xz 和 CA 证书。runner 容器镜像拉取发生在 workflow 执行前;如更换 runner 镜像,应在 VPS 的 Docker 配置或 runner 配置中使用可访问的镜像仓库。 + +参考:[npmmirror 使用说明](https://npmmirror.com/)、[Gitea Action 下载机制](https://docs.gitea.com/usage/actions/faq/)。 diff --git a/docs/versioning.md b/docs/versioning.md new file mode 100644 index 0000000..7d793c8 --- /dev/null +++ b/docs/versioning.md @@ -0,0 +1,9 @@ +# 版本与 Release + +每个正式插件独立维护 `curio.json` 的版本,并以 `v` tag 发布对应源码快照。原生项目中的版本必须与 Manifest 一致。 + +安装包存放在该插件仓库的 Gitea Release 附件中。附件按插件 ID、版本、平台命名,不使用 `latest` 之类可变下载地址。`trove-release.json` 记录本次发布的所有产物;源索引由收录 workflow 生成。 + +相同插件 ID、版本、平台的已发布内容不能覆盖,修复应发布新版本。一个插件在源索引中对应一个条目,版本位于其 `versions` 数组内。 + +详细流程见 [官方软件源的维护与发布](development.md)。 diff --git a/package.json b/package.json new file mode 100644 index 0000000..df1bcd9 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "trove-catalog", + "version": "0.1.0", + "private": true, + "type": "module", + "packageManager": "pnpm@11.23.0", + "scripts": { + "release:sync": "node tools/sync-release.mjs", + "release:publish": "node tools/publish-release.mjs" + }, + "dependencies": { + "semver": "7.7.2" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..007b6e4 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,24 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + semver: + specifier: 7.7.2 + version: 7.7.2 + +packages: + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + +snapshots: + + semver@7.7.2: {} diff --git a/source/index.json b/source/index.json new file mode 100644 index 0000000..9ed61ef --- /dev/null +++ b/source/index.json @@ -0,0 +1,54 @@ +{ + "schemaVersion": 1, + "id": "trove-official", + "name": "Trove 官方软件源", + "generatedAt": "2026-09-11T10:38:56+08:00", + "curios": [ + { + "id": "dev.trove.harmony-assistant", + "name": "Harmony Assistant", + "description": "在 Mac 上管理鸿蒙设备,收发文件与完整文件夹、安装应用、保存资料备份。", + "icon": "data:image/png;base64,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", + "versions": [ + { + "version": "0.1.0", + "engine": { + "trove": ">=0.1.0 <1.0.0" + }, + "releasedAt": "2026-09-11T10:38:47+08:00", + "artifacts": [ + { + "target": "aarch64-apple-darwin", + "url": "https://git.render.ink/trove-curios/harmony-assistant/releases/download/v0.1.0/dev.trove.harmony-assistant-0.1.0-aarch64-apple-darwin.curio", + "sha256": "da291aaedc48b120308f9c36318aa070ab74f6105a099bed20b0b7d1ba19a64f", + "size": 2787269 + } + ] + } + ] + }, + { + "id": "dev.trove.harmony-mirror", + "name": "Harmony Mirror", + "description": "在 Mac 独立窗口中流畅呈现鸿蒙屏幕,通过鼠标和键盘直接操作。", + "icon": "data:image/png;base64,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", + "versions": [ + { + "version": "0.1.0", + "engine": { + "trove": ">=0.1.0 <1.0.0" + }, + "releasedAt": "2026-09-11T10:38:56+08:00", + "artifacts": [ + { + "target": "aarch64-apple-darwin", + "url": "https://git.render.ink/trove-curios/harmony-mirror/releases/download/v0.1.0/dev.trove.harmony-mirror-0.1.0-aarch64-apple-darwin.curio", + "sha256": "36ab16a65bb0f2b04a0287cfa543129337a73c7a6671eb5ae075ca343401434e", + "size": 2080067 + } + ] + } + ] + } + ] +} diff --git a/source/repositories.json b/source/repositories.json new file mode 100644 index 0000000..5fe32c6 --- /dev/null +++ b/source/repositories.json @@ -0,0 +1,18 @@ +{ + "id": "trove-official", + "name": "Trove 官方软件源", + "repositories": [ + { + "repository": "trove-curios/harmony-mirror", + "ids": [ + "dev.trove.harmony-mirror" + ] + }, + { + "repository": "trove-curios/harmony-assistant", + "ids": [ + "dev.trove.harmony-assistant" + ] + } + ] +} diff --git a/tools/ci-runtime.sh b/tools/ci-runtime.sh new file mode 100644 index 0000000..aba63f0 --- /dev/null +++ b/tools/ci-runtime.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Source this file in a Linux job after checking out the catalog. +set -euo pipefail +export npm_config_registry="${NPM_REGISTRY:-https://registry.npmmirror.com}" +export COREPACK_NPM_REGISTRY="$npm_config_registry" +export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 +if ! command -v node >/dev/null || ! node -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 22 ? 0 : 1)'; then + case "$(uname -m)" in + x86_64) node_arch=x64; node_sha=d60acfe00a2932254bb0ad20e01b0d74397a0875595de719654b214f4b03f307 ;; + aarch64|arm64) node_arch=arm64; node_sha=fff4078c5def658577f92c88db7db3bc0072924bfb93fe52c1e744a54e94abb8 ;; + *) echo 'Unsupported Linux runner architecture' >&2; exit 1 ;; + esac + node_archive="node-v22.23.2-linux-${node_arch}.tar.xz" + node_cache="${RUNNER_TEMP:-/tmp}/trove-node-22.23.2-${node_arch}" + mkdir -p "$node_cache" + curl --fail --location --retry 3 --connect-timeout 15 --max-time 180 \ + "${NODE_MIRROR:-https://npmmirror.com/mirrors/node}/v22.23.2/$node_archive" -o "$node_cache/$node_archive" + # Hashes are pinned from the official nodejs.org SHASUMS256.txt. + printf '%s %s\n' "$node_sha" "$node_cache/$node_archive" | sha256sum --check --status + tar -xJf "$node_cache/$node_archive" -C "$node_cache" --strip-components=1 + export PATH="$node_cache/bin:$PATH" +fi +node --version +# The catalog only needs semver; avoid downloading pnpm/Corepack in each job. +npm install --ignore-scripts --no-audit --no-fund --package-lock=false diff --git a/tools/gitea.mjs b/tools/gitea.mjs new file mode 100644 index 0000000..e99a60e --- /dev/null +++ b/tools/gitea.mjs @@ -0,0 +1,87 @@ +import { execFileSync } from 'node:child_process'; + +const origin = new URL(process.env.GITEA_SERVER_URL || 'https://git.render.ink'); +if (origin.protocol !== 'https:' || origin.username || origin.password) throw new Error('Gitea requires an HTTPS origin without credentials'); +export const server = origin.origin; +export const catalogRepository = process.env.CATALOG_REPOSITORY || 'trove/curios'; + +export function repositoryPath(repository) { + if (!/^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/.test(repository)) throw new Error('Invalid repository name'); + return repository.split('/').map(encodeURIComponent).join('/'); +} + +export async function api(route, { token = process.env.GITEA_TOKEN, method = 'GET', body, missing = false } = {}) { + const auth = authorization(token); + const response = await fetch(`${server}/api/v1${route}`, { + method, redirect: 'error', signal: AbortSignal.timeout(60_000), + headers: { Authorization: auth, ...(body && !(body instanceof FormData) ? { 'Content-Type': 'application/json' } : {}) }, + body: body instanceof FormData ? body : body === undefined ? undefined : JSON.stringify(body), + }); + if (missing && response.status === 404) return null; + if (!response.ok) { + const error = new Error(`Gitea ${method} ${route.split('?')[0]} returned HTTP ${response.status}`); + error.status = response.status; + throw error; + } + if (response.status === 204) return null; + return response.json(); +} + +// Keep credentials on this Gitea origin; release storage may redirect to a CDN. +export async function download(url, token = process.env.GITEA_TOKEN, limit = 512 * 1024 * 1024) { + let current = new URL(url); + for (let redirects = 0; redirects <= 5; redirects++) { + if (current.protocol !== 'https:' || current.username || current.password) throw new Error('Invalid release download URL'); + const response = await fetch(current, { + redirect: 'manual', signal: AbortSignal.timeout(120_000), + headers: current.origin === server ? { Authorization: authorization(token) } : {}, + }); + if ([301, 302, 303, 307, 308].includes(response.status)) { + const location = response.headers.get('location'); + await response.body?.cancel(); + if (!location) throw new Error('Release redirect has no location'); + current = new URL(location, current); + continue; + } + if (!response.ok) throw new Error(`Release download returned HTTP ${response.status}`); + const chunks = []; let size = 0; + for await (const chunk of response.body) { + size += chunk.length; + if (size > limit) throw new Error('Release download exceeds declared size limit'); + chunks.push(chunk); + } + return Buffer.concat(chunks); + } + throw new Error('Too many release download redirects'); +} + +let localAuthorization; +function authorization(token) { + if (token) return `token ${token}`; + if (process.env.GITEA_ACTIONS === 'true') throw new Error('Workflow token is missing'); + if (!localAuthorization) { + let output; + try { + output = execFileSync('git', ['-c', 'credential.interactive=false', 'credential', 'fill'], { + input: `url=${server}\n\n`, encoding: 'utf8', timeout: 10_000, + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, stdio: ['pipe', 'pipe', 'ignore'], + }); + } catch { + throw new Error('Set GITEA_TOKEN or configure Git HTTPS credentials'); + } + const fields = Object.fromEntries(output.trim().split('\n').map(line => { + const separator = line.indexOf('='); return [line.slice(0, separator), line.slice(separator + 1)]; + })); + if (!fields.username || !fields.password) throw new Error('Set GITEA_TOKEN or configure Git HTTPS credentials'); + localAuthorization = `Basic ${Buffer.from(`${fields.username}:${fields.password}`).toString('base64')}`; + } + return localAuthorization; +} + +export async function notifyCatalog(repository, tag) { + await api(`/repos/${repositoryPath(catalogRepository)}/actions/workflows/sync-release.yml/dispatches`, { + token: process.env.CATALOG_TOKEN, + method: 'POST', body: { ref: 'main', inputs: { repository, tag } }, + }); + console.log(`Requested catalog registration: ${repository}@${tag}`); +} diff --git a/tools/notify-release.mjs b/tools/notify-release.mjs new file mode 100644 index 0000000..1082166 --- /dev/null +++ b/tools/notify-release.mjs @@ -0,0 +1,7 @@ +import { api, notifyCatalog, repositoryPath } from './gitea.mjs'; +const repository = process.env.GITEA_REPOSITORY; +const tag = process.env.RELEASE_TAG; +if (!tag) throw new Error('RELEASE_TAG is required'); +const release = await api(`/repos/${repositoryPath(repository)}/releases/tags/${encodeURIComponent(tag)}`); +if (release.draft || !release.assets.some(asset => asset.name === 'trove-release.json')) throw new Error('A completed release with trove-release.json is required'); +await notifyCatalog(repository, tag); diff --git a/tools/prepare-release.mjs b/tools/prepare-release.mjs new file mode 100644 index 0000000..af06c4e --- /dev/null +++ b/tools/prepare-release.mjs @@ -0,0 +1,11 @@ +import { mkdir, writeFile, rm } from 'node:fs/promises'; +import { parseArgs } from 'node:util'; +import { releasePlan } from './release-plan.mjs'; +const { values } = parseArgs({ options: { entries: { type: 'string' }, tag: { type: 'string' } } }); +if (!values.entries) throw new Error('--entries is required'); +const { files, descriptor } = await releasePlan(values.entries, values.tag); +await rm('dist/release', { recursive: true, force: true }); +await mkdir('dist/release', { recursive: true }); +for (const [name, bytes] of files) await writeFile(`dist/release/${name}`, bytes); +console.log(`Prepared ${files.size} release files in dist/release/`); +console.log(`Create draft release ${descriptor.tag} at commit ${descriptor.commit}, upload every file, then publish.`); diff --git a/tools/publish-release.mjs b/tools/publish-release.mjs new file mode 100644 index 0000000..447579d --- /dev/null +++ b/tools/publish-release.mjs @@ -0,0 +1,40 @@ +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.'); diff --git a/tools/release-catalog.mjs b/tools/release-catalog.mjs new file mode 100644 index 0000000..258b42d --- /dev/null +++ b/tools/release-catalog.mjs @@ -0,0 +1,35 @@ +import { gt } from 'semver'; + +// Published identity is (Curio ID, version, target). Existing identities are immutable. +export function appendRelease(catalog, manifest, artifact, releasedAt) { + const next = structuredClone(catalog); + let curio = next.curios.find(item => item.id === manifest.id); + if (!curio) { + curio = { id: manifest.id, name: manifest.name, description: manifest.description ?? '', ...(manifest.icon ? { icon: manifest.icon } : {}), versions: [] }; + next.curios.push(curio); + } + let version = curio.versions.find(item => item.version === manifest.version); + if (version && version.engine.trove !== manifest.engine.trove) { + throw new Error(`${manifest.id}@${manifest.version}: published engine range cannot change; bump the plugin version`); + } + const existing = version?.artifacts.find(item => item.target === artifact.target); + if (existing) { + for (const key of ['sha256', 'size', 'url']) { + if (existing[key] !== artifact[key]) throw new Error(`${manifest.id}@${manifest.version}/${artifact.target}: published ${key} differs; bump the plugin version`); + } + return next; + } + if (!version) { + const newest = curio.versions.every(item => gt(manifest.version, item.version)); + version = { version: manifest.version, engine: structuredClone(manifest.engine), releasedAt, artifacts: [] }; + curio.versions.unshift(version); + if (newest) { + curio.name = manifest.name; + curio.description = manifest.description ?? ''; + if (manifest.icon) curio.icon = manifest.icon; + } + } + version.artifacts.push(structuredClone(artifact)); + next.generatedAt = next.generatedAt > releasedAt ? next.generatedAt : releasedAt; + return next; +} diff --git a/tools/release-plan.mjs b/tools/release-plan.mjs new file mode 100644 index 0000000..01e99ad --- /dev/null +++ b/tools/release-plan.mjs @@ -0,0 +1,45 @@ +import { readFile } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import { execFileSync } from 'node:child_process'; +import path from 'node:path'; +import { valid } from 'semver'; + +export async function releasePlan(entriesFile, tag) { + const config = JSON.parse(await readFile('release.json', 'utf8')); + const repository = config.repository; + if (!tag || !/^[a-zA-Z0-9][a-zA-Z0-9._+-]*$/.test(tag)) throw new Error('A release tag is required'); + const commit = execFileSync('git', ['rev-parse', 'HEAD'], { encoding: 'utf8' }).trim(); + const entries = JSON.parse(await readFile(entriesFile, 'utf8')).filter(entry => !entry.fault); + if (!entries.length) throw new Error('No packages to publish'); + const plugins = new Map(); const files = new Map(); + const digest = bytes => createHash('sha256').update(bytes).digest('hex'); + for (const entry of entries) { + const manifest = entry.manifest; + if (!config.ids.includes(manifest.id) || !valid(manifest.version)) throw new Error('Unexpected plugin identity/version'); + if (tag !== `v${manifest.version}`) throw new Error('Release tag must match curio.json'); + if (!['any', 'aarch64-apple-darwin', 'x86_64-apple-darwin'].includes(entry.artifact.target)) throw new Error('Unsupported package target'); + const bytes = await readFile(entry.file); + if (digest(bytes) !== entry.artifact.sha256 || bytes.length !== entry.artifact.size) throw new Error('Package differs from build metadata'); + const asset = `${manifest.id}-${manifest.version}-${entry.artifact.target}.curio`; + if (files.has(asset)) throw new Error(`Duplicate release asset: ${asset}`); + files.set(asset, bytes); + const key = `${manifest.id}@${manifest.version}`; + if (!plugins.has(key)) { + let icon; + if (manifest.icon) { + const file = path.resolve(entry.directory, manifest.icon); + if (!file.startsWith(path.resolve(entry.directory) + path.sep)) throw new Error('Icon escapes package directory'); + const data = await readFile(file); + const type = { '.svg': 'image/svg+xml', '.png': 'image/png', '.jpg': 'image/jpeg', '.webp': 'image/webp' }[path.extname(file)]; + if (type && data.length <= 64 * 1024) icon = `data:${type};base64,${data.toString('base64')}`; + } + plugins.set(key, { id: manifest.id, name: manifest.name, description: manifest.description ?? '', icon, + version: manifest.version, engine: manifest.engine, artifacts: [] }); + } + plugins.get(key).artifacts.push({ target: entry.artifact.target, asset, sha256: entry.artifact.sha256, size: bytes.length }); + } + const descriptor = Buffer.from(JSON.stringify({ schemaVersion: 1, repository, tag, commit, plugins: [...plugins.values()] }, null, 2) + '\n'); + files.set('trove-release.json', descriptor); + return { files, descriptor: JSON.parse(descriptor) }; + +} diff --git a/tools/sync-release.mjs b/tools/sync-release.mjs new file mode 100644 index 0000000..a4c6ee1 --- /dev/null +++ b/tools/sync-release.mjs @@ -0,0 +1,80 @@ +import { readFile, writeFile } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import { parseArgs } from 'node:util'; +import { valid, validRange, rcompare } from 'semver'; +import { api, download, server, catalogRepository, repositoryPath } from './gitea.mjs'; +import { appendRelease } from './release-catalog.mjs'; + +const { values } = parseArgs({ options: { + repository: { type: 'string' }, tag: { type: 'string' }, publish: { type: 'boolean', default: false }, +} }); +const repository = values.repository || process.env.RELEASE_REPOSITORY; +const tag = values.tag || process.env.RELEASE_TAG; +const config = JSON.parse(await readFile(new URL('../source/repositories.json', import.meta.url), 'utf8')); +const publisher = config.repositories.find(item => item.repository === repository); +if (!publisher || !tag) throw new Error('Repository is not registered in this catalog, or tag is missing'); +const release = await api(`/repos/${repositoryPath(repository)}/releases/tags/${encodeURIComponent(tag)}`); +if (release.draft) throw new Error('Draft releases cannot enter the catalog'); +const descriptorAsset = release.assets.find(asset => asset.name === 'trove-release.json'); +if (!descriptorAsset) throw new Error('Release has no trove-release.json attachment'); +const descriptor = JSON.parse(await download(descriptorAsset.browser_download_url, undefined, 1024 * 1024)); +if (descriptor.schemaVersion !== 1 || descriptor.repository !== repository || descriptor.tag !== tag || !Array.isArray(descriptor.plugins) || !descriptor.plugins.length) throw new Error('Invalid release descriptor'); +if (!/^[a-f0-9]{40,64}$/.test(descriptor.commit)) throw new Error('Invalid release commit'); +const refs = await api(`/repos/${repositoryPath(repository)}/git/refs/tags/${encodeURIComponent(tag)}`); +let object = (Array.isArray(refs) ? refs.find(ref => ref.ref === `refs/tags/${tag}`) : refs)?.object; +for (let depth = 0; object?.type === 'tag' && depth < 5; depth++) { + object = (await api(`/repos/${repositoryPath(repository)}/git/tags/${object.sha}`)).object; +} +if (object?.type !== 'commit' || object.sha !== descriptor.commit) throw new Error('Release tag differs from package source commit'); +const additions = []; const identities = new Set(); +for (const plugin of descriptor.plugins) { + if (!publisher.ids.includes(plugin.id) || !valid(plugin.version) || !validRange(plugin.engine?.trove) || typeof plugin.name !== 'string' || !plugin.name.trim()) throw new Error('Unexpected plugin identity or compatibility range'); + if (tag !== `v${plugin.version}`) throw new Error('Plugin version differs from release tag'); + if (!Array.isArray(plugin.artifacts) || !plugin.artifacts.length) throw new Error('Plugin has no artifacts'); + for (const artifact of plugin.artifacts) { + if (!['any', 'aarch64-apple-darwin', 'x86_64-apple-darwin'].includes(artifact.target) || !/^[a-f0-9]{64}$/.test(artifact.sha256) || !Number.isSafeInteger(artifact.size) || artifact.size < 1 || artifact.size > 512 * 1024 * 1024) throw new Error('Invalid artifact metadata'); + const identity = `${plugin.id}@${plugin.version}/${artifact.target}`; + if (identities.has(identity)) throw new Error('Duplicate artifact identity'); + identities.add(identity); + const asset = release.assets.find(asset => asset.name === artifact.asset); + if (!asset || asset.size !== artifact.size || new URL(asset.browser_download_url).origin !== server) throw new Error('Artifact is not a matching release attachment'); + const bytes = await download(asset.browser_download_url, undefined, artifact.size); + if (bytes.length !== artifact.size || createHash('sha256').update(bytes).digest('hex') !== artifact.sha256) throw new Error(`Release checksum mismatch: ${identity}`); + additions.push({ plugin, artifact: { target: artifact.target, url: asset.browser_download_url, sha256: artifact.sha256, size: artifact.size } }); + } +} + +function merge(index) { + if (index.schemaVersion !== 1 || index.id !== config.id || !Array.isArray(index.curios)) throw new Error('Unexpected source identity'); + for (const { plugin, artifact } of additions) { + index = appendRelease(index, plugin, artifact, release.published_at || release.created_at); + } + index.curios.sort((a, b) => a.id.localeCompare(b.id)); + for (const plugin of index.curios) plugin.versions.sort((a, b) => rcompare(a.version, b.version)); + return JSON.stringify(index, null, 2) + '\n'; +} + +if (!values.publish) { + const file = new URL('../source/index.json', import.meta.url); + await writeFile(file, merge(JSON.parse(await readFile(file, 'utf8')))); + console.log(`Updated local catalog with ${repository}@${tag}`); +} else { + // Gitea's contents SHA provides compare-and-swap. On concurrent publications, + // re-read and merge the latest index instead of overwriting another release. + const route = `/repos/${repositoryPath(catalogRepository)}/contents/source/index.json`; + for (let attempt = 0; attempt < 6; attempt++) { + const file = await api(`${route}?ref=main`, { token: process.env.CATALOG_WRITE_TOKEN }); + const before = Buffer.from(file.content, 'base64').toString('utf8'); + const content = merge(JSON.parse(before)); + if (content === before) { console.log('Release already registered'); break; } + try { + await api(route, { token: process.env.CATALOG_WRITE_TOKEN, method: 'PUT', body: { + branch: 'main', sha: file.sha, content: Buffer.from(content).toString('base64'), + message: `chore(catalog): register ${repository}@${tag}`, + } }); + console.log(`Registered ${repository}@${tag}`); break; + } catch (error) { + if (![409, 422].includes(error.status) || attempt === 5) throw error; + } + } +}