refactor(catalog): register focused Harmony plugins and accelerate mainland CI
This commit is contained in:
@@ -16,10 +16,28 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: https://github.com/actions/checkout@v4
|
- name: Check out catalog from Gitea
|
||||||
- run: corepack enable && corepack pnpm install --frozen-lockfile
|
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
|
- name: Register completed release
|
||||||
run: node tools/sync-release.mjs --publish
|
working-directory: catalog
|
||||||
|
run: |
|
||||||
|
source tools/ci-runtime.sh
|
||||||
|
node tools/sync-release.mjs --publish
|
||||||
env:
|
env:
|
||||||
GITEA_SERVER_URL: ${{ gitea.server_url }}
|
GITEA_SERVER_URL: ${{ gitea.server_url }}
|
||||||
GITEA_TOKEN: ${{ secrets.PLUGIN_RELEASE_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.PLUGIN_RELEASE_TOKEN }}
|
||||||
@@ -27,3 +45,5 @@ jobs:
|
|||||||
CATALOG_REPOSITORY: ${{ gitea.repository }}
|
CATALOG_REPOSITORY: ${{ gitea.repository }}
|
||||||
RELEASE_REPOSITORY: ${{ inputs.repository }}
|
RELEASE_REPOSITORY: ${{ inputs.repository }}
|
||||||
RELEASE_TAG: ${{ inputs.tag }}
|
RELEASE_TAG: ${{ inputs.tag }}
|
||||||
|
NPM_REGISTRY: ${{ vars.NPM_REGISTRY }}
|
||||||
|
NODE_MIRROR: ${{ vars.NODE_MIRROR }}
|
||||||
|
|||||||
@@ -1,23 +1,27 @@
|
|||||||
# Trove Curios
|
# Trove Curios
|
||||||
|
|
||||||
让桌面,多一点顺手。
|
**让桌面,多一些可能。**
|
||||||
|
|
||||||
Trove 官方插件库。发现喜欢的 Curio,装进你的工作台,让常用能力触手可及。
|
发现专注、轻巧的桌面工具,把常用能力带到手边。
|
||||||
|
|
||||||
## 小工具,大用途
|
## Harmony Mirror
|
||||||
|
|
||||||
每个 Curio 专注一件事,用轻巧的独立工具承接日常操作,把更多空间留给手头的工作。
|
让鸿蒙,来到桌面。独立投屏窗口,鼠标与键盘直接操作手机。
|
||||||
|
|
||||||
### [Harmony Connector](https://git.render.ink/trove-plugins/harmony-connector)
|
[探索 Harmony Mirror →](https://git.render.ink/trove-curios/harmony-mirror)
|
||||||
|
|
||||||
让设备,更近一步。连接 Mac 与鸿蒙手机,整夹收发照片与文档,随时掌握传输速度;管理应用,在独立窗口中投屏,用鼠标和键盘完成日常操作。
|
## Harmony Assistant
|
||||||
|
|
||||||
## 按你的习惯组合
|
鸿蒙随行,资料有序。收发完整文件夹,管理应用,让重要资料留在身边。
|
||||||
|
|
||||||
按需安装,自由搭配。工具各自更新,也能通过服务相互配合,让你的工作方式逐渐长成自己的样子。
|
[探索 Harmony Assistant →](https://git.render.ink/trove-curios/harmony-assistant)
|
||||||
|
|
||||||
## 从桌面,开始
|
## 带到你的桌面
|
||||||
|
|
||||||
打开 Trove,发现 Curios,为下一个灵感和下一项任务留出空间。
|
在 Trove 的「软件源」中添加 Git 仓库:
|
||||||
|
|
||||||
[探索 Trove](https://trove.render.ink) · [发现 Curios](https://trove.render.ink/curios) · [开发者文档](docs/development.md)
|
```text
|
||||||
|
https://git.render.ink/trove/curios.git
|
||||||
|
```
|
||||||
|
|
||||||
|
选择喜欢的 Curio,安装,即刻使用。
|
||||||
|
|||||||
+15
-3
@@ -1,6 +1,6 @@
|
|||||||
# 官方软件源的维护与发布
|
# 官方软件源的维护与发布
|
||||||
|
|
||||||
`trove/curios` 保存官方软件源索引、插件仓库登记和发布工具。底座在 `trove/app`;插件源码与安装包分别位于 `trove-plugins` 下各仓库的代码和 Releases。
|
`trove/curios` 保存官方软件源索引、插件仓库登记和发布工具。底座在 `trove/app`;插件源码与安装包分别位于 `trove-curios` 下各仓库的代码和 Releases。
|
||||||
|
|
||||||
## 仓库职责
|
## 仓库职责
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
## 发布协议
|
## 发布协议
|
||||||
|
|
||||||
插件仓库根目录的 `release.json` 声明仓库、插件 ID 和是否为共享测试套件。普通插件 tag 为 `v<curio.json version>`;测试套件独立打 tag,各测试插件保留自身版本。
|
插件仓库根目录的 `release.json` 声明仓库、插件 ID。每个仓库只发布一个插件,tag 为 `v<curio.json version>`。
|
||||||
|
|
||||||
Release 先以草稿创建,上传每个平台的 `.curio` 和 `trove-release.json` 后再发布。描述文件包含仓库、tag、源码 commit、插件 Manifest 摘要,以及附件名、平台、大小和 SHA-256。插件图标以小型图片 Data URL 收录,私有图片也无需额外鉴权。
|
Release 先以草稿创建,上传每个平台的 `.curio` 和 `trove-release.json` 后再发布。描述文件包含仓库、tag、源码 commit、插件 Manifest 摘要,以及附件名、平台、大小和 SHA-256。插件图标以小型图片 Data URL 收录,私有图片也无需额外鉴权。
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ Release 先以草稿创建,上传每个平台的 `.curio` 和 `trove-release.j
|
|||||||
|
|
||||||
## 新增插件
|
## 新增插件
|
||||||
|
|
||||||
1. 在 `trove-plugins` 创建独立仓库,添加源码、`curio.json`、`release.json` 和发布 workflow。
|
1. 在 `trove-curios` 创建独立仓库,添加源码、`curio.json`、`release.json` 和发布 workflow。
|
||||||
2. 将仓库与 ID 登记到 `source/repositories.json`,授予收录机器人读取该仓库的代码与 Release 的权限。
|
2. 将仓库与 ID 登记到 `source/repositories.json`,授予收录机器人读取该仓库的代码与 Release 的权限。
|
||||||
3. 在对应平台准备构建环境与 Trove CLI,提交源码,运行插件仓库的手动发布脚本并上传 Release。
|
3. 在对应平台准备构建环境与 Trove CLI,提交源码,运行插件仓库的手动发布脚本并上传 Release。
|
||||||
|
|
||||||
@@ -45,3 +45,15 @@ Release 成功但收录失败时,在插件 Actions 手动运行发布 workflow
|
|||||||
## 自动化身份
|
## 自动化身份
|
||||||
|
|
||||||
`trove-publisher` 负责跨仓库通信:可以读取源代码、触发源 Actions,并读取已登记插件的 Release;没有底座仓库访问权限,也不能直接改写源代码。源索引写入由源 workflow 自身的任务令牌完成。
|
`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/)。
|
||||||
|
|||||||
@@ -3,23 +3,15 @@
|
|||||||
"name": "Trove 官方软件源",
|
"name": "Trove 官方软件源",
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
"repository": "trove-plugins/harmony-connector",
|
"repository": "trove-curios/harmony-mirror",
|
||||||
"ids": [
|
"ids": [
|
||||||
"dev.trove.harmony-connector"
|
"dev.trove.harmony-mirror"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"repository": "trove-plugins/test-suite",
|
"repository": "trove-curios/harmony-assistant",
|
||||||
"suite": true,
|
|
||||||
"ids": [
|
"ids": [
|
||||||
"dev.trove.qa.host",
|
"dev.trove.harmony-assistant"
|
||||||
"dev.trove.qa.isolation",
|
|
||||||
"dev.trove.qa.self",
|
|
||||||
"dev.trove.qa.provider",
|
|
||||||
"dev.trove.qa.consumer",
|
|
||||||
"dev.trove.qa.optional",
|
|
||||||
"dev.trove.qa.autostart",
|
|
||||||
"dev.trove.qa.upgrade"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -20,7 +20,7 @@ files.set('trove-release.json', descriptorBytes);
|
|||||||
let release = await api(`${route}/releases/tags/${encodeURIComponent(tag)}`, { missing: true });
|
let release = await api(`${route}/releases/tags/${encodeURIComponent(tag)}`, { missing: true });
|
||||||
if (!release) release = await api(`${route}/releases`, { method: 'POST', body: {
|
if (!release) release = await api(`${route}/releases`, { method: 'POST', body: {
|
||||||
tag_name: tag, target_commitish: descriptor.commit, name: tag, draft: true,
|
tag_name: tag, target_commitish: descriptor.commit, name: tag, draft: true,
|
||||||
prerelease: config.suite ? false : tag.slice(1).split('+')[0].includes('-'),
|
prerelease: tag.slice(1).split('+')[0].includes('-'),
|
||||||
body: `${config.name} ${tag}\n\n通过 Trove 软件源安装和更新。`,
|
body: `${config.name} ${tag}\n\n通过 Trove 软件源安装和更新。`,
|
||||||
} });
|
} });
|
||||||
for (const [name, bytes] of files) {
|
for (const [name, bytes] of files) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export async function releasePlan(entriesFile, tag) {
|
|||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
const manifest = entry.manifest;
|
const manifest = entry.manifest;
|
||||||
if (!config.ids.includes(manifest.id) || !valid(manifest.version)) throw new Error('Unexpected plugin identity/version');
|
if (!config.ids.includes(manifest.id) || !valid(manifest.version)) throw new Error('Unexpected plugin identity/version');
|
||||||
if (!config.suite && tag !== `v${manifest.version}`) throw new Error('Release tag must match curio.json');
|
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');
|
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);
|
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');
|
if (digest(bytes) !== entry.artifact.sha256 || bytes.length !== entry.artifact.size) throw new Error('Package differs from build metadata');
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ if (object?.type !== 'commit' || object.sha !== descriptor.commit) throw new Err
|
|||||||
const additions = []; const identities = new Set();
|
const additions = []; const identities = new Set();
|
||||||
for (const plugin of descriptor.plugins) {
|
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 (!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 (!publisher.suite && tag !== `v${plugin.version}`) throw new Error('Plugin version differs from release tag');
|
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');
|
if (!Array.isArray(plugin.artifacts) || !plugin.artifacts.length) throw new Error('Plugin has no artifacts');
|
||||||
for (const artifact of plugin.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');
|
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');
|
||||||
|
|||||||
Reference in New Issue
Block a user