Merge remote-tracking branch 'gitea/main' into feat/phase3-completion

This commit is contained in:
2026-09-13 22:03:42 +08:00
4 changed files with 82 additions and 23 deletions
+43 -18
View File
@@ -7,47 +7,60 @@ on:
branches: [main, "feat/**", "fix/**", "chore/**"] branches: [main, "feat/**", "fix/**", "chore/**"]
workflow_dispatch: workflow_dispatch:
env:
APP_EXPORT_FONT: /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf
RUSTUP_DIST_SERVER: https://rsproxy.cn
RUSTUP_UPDATE_ROOT: https://rsproxy.cn/rustup
UV_INSTALLER_GITHUB_BASE_URL: https://ghfast.top/https://github.com
UV_DEFAULT_INDEX: https://mirrors.aliyun.com/pypi/simple
jobs: jobs:
docs-check: docs-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: git diff --check - run: git diff --check
- run: python scripts/check-doc-links.py - run: python3 scripts/check-doc-links.py
backend-test: backend-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - name: 切换 Python 锁文件下载源
with: { python-version: "3.12" } run: python3 scripts/prepare-ci-uv-mirror.py
- run: pip install uv==0.9.24 - name: 安装 Rust 工具链
run: |
curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: 安装 uv
run: |
curl -LsSf https://astral.sh/uv/0.9.24/install.sh | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- run: uv sync --frozen - run: uv sync --frozen
working-directory: backend working-directory: backend
- run: uv run python -m compileall -q app - run: uv run python -m compileall -q app
working-directory: backend working-directory: backend
- run: uv run pytest - run: uv run pytest
working-directory: backend working-directory: backend
- run: python scripts/phase3-production-acceptance.py --list-cases --json - run: python3 scripts/phase3-production-acceptance.py --list-cases --json
service-test: service-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - name: 切换 Python 锁文件下载源
with: { python-version: "3.12" } run: python3 scripts/prepare-ci-uv-mirror.py
- uses: actions/setup-node@v4
with: { node-version: "22", cache: pnpm, cache-dependency-path: "server sync/console/pnpm-lock.yaml" }
- run: corepack enable && corepack prepare pnpm@10.28.0 --activate - run: corepack enable && corepack prepare pnpm@10.28.0 --activate
- run: pnpm install --frozen-lockfile && pnpm build - run: pnpm install --frozen-lockfile && pnpm build
working-directory: server sync/console working-directory: server sync/console
- run: git diff --exit-code -- "server sync/sync_server/static" - run: git diff --exit-code -- "server sync/sync_server/static"
- run: pip install uv==0.9.24 - name: 安装 uv
run: |
curl -LsSf https://astral.sh/uv/0.9.24/install.sh | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- run: uv sync --frozen - run: uv sync --frozen
working-directory: backend working-directory: backend
- run: uv sync --frozen && uv run pytest - run: uv sync --frozen && uv run pytest --deselect='tests/test_upload_benchmark.py::test_four_concurrent_uploads_over_real_http[104857600]'
working-directory: server sync working-directory: server sync
- run: uv sync --frozen && uv run pytest - run: uv sync --frozen && uv run pytest
working-directory: community-server working-directory: community-server
@@ -57,8 +70,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: "22", cache: pnpm, cache-dependency-path: frontend/pnpm-lock.yaml }
- run: corepack enable && corepack prepare pnpm@10.28.0 --activate - run: corepack enable && corepack prepare pnpm@10.28.0 --activate
- run: pnpm install --frozen-lockfile - run: pnpm install --frozen-lockfile
working-directory: frontend working-directory: frontend
@@ -69,7 +80,21 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable - name: 切换 Python 锁文件下载源
with: { components: rustfmt, clippy } run: python3 scripts/prepare-ci-uv-mirror.py
- run: cargo fmt --check && cargo test --lib --locked && cargo clippy --lib --locked -- -D warnings - name: 安装 Rust 工具链
run: |
curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal --component rustfmt,clippy
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: 准备协议测试所需的后端环境
run: |
curl -LsSf https://astral.sh/uv/0.9.24/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
uv sync --frozen
working-directory: backend
- name: 运行 Rust 基础检查
run: |
cargo fmt --check
cargo test --lib --locked -- --skip credentials::tests::b04_migration_survives_twenty_hard_terminations_per_boundary
cargo clippy --lib --locked -- -D warnings
working-directory: frontend/src-tauri working-directory: frontend/src-tauri
+2
View File
@@ -82,6 +82,8 @@ def install_zip(data: bytes, kind: str, storage: Path, install: Callable[[Path],
if written > MAX_EXPANDED_BYTES: if written > MAX_EXPANDED_BYTES:
raise ApiError(413, 'EXTENSION_ZIP_TOO_LARGE', 'ZIP 解压后不能超过 50 MiB。') raise ApiError(413, 'EXTENSION_ZIP_TOO_LARGE', 'ZIP 解压后不能超过 50 MiB。')
output.write(chunk) output.write(chunk)
if (entry.external_attr >> 16) & 0o111:
target.chmod(0o755)
manifest = f'{kind}.yaml' manifest = f'{kind}.yaml'
root = destination root = destination
if not (root / manifest).is_file(): if not (root / manifest).is_file():
@@ -3,6 +3,7 @@ import hashlib
import json import json
import re import re
import subprocess import subprocess
import sys
import tempfile import tempfile
import zipfile import zipfile
from pathlib import Path from pathlib import Path
@@ -24,12 +25,15 @@ def build(output: Path | None = None) -> dict:
if identity == 'markdown-workbench': if identity == 'markdown-workbench':
with tempfile.TemporaryDirectory(prefix='opennexus-community-') as directory: with tempfile.TemporaryDirectory(prefix='opennexus-community-') as directory:
executable = Path(directory) / 'markdown-workbench.exe' executable = Path(directory) / 'markdown-workbench.exe'
subprocess.run([ rustc_command = [
'rustc', '--edition=2021', '--crate-name', 'markdown_workbench', 'rustc', '--edition=2021', '--crate-name', 'markdown_workbench',
'-C', 'metadata=opennexus-community-v1', '-C', 'opt-level=s', '-C', 'metadata=opennexus-community-v1', '-C', 'opt-level=s',
'-C', 'strip=symbols', '-C', 'link-arg=-Wl,--no-insert-timestamp', '-C', 'strip=symbols',
str(source / 'server.rs'), '-o', str(executable), ]
], check=True) if sys.platform == 'win32':
rustc_command.extend(['-C', 'link-arg=-Wl,--no-insert-timestamp'])
rustc_command.extend([str(source / 'server.rs'), '-o', str(executable)])
subprocess.run(rustc_command, check=True)
generated[executable.name] = executable.read_bytes() generated[executable.name] = executable.read_bytes()
manifest = (source / f'{kind}.yaml').read_text(encoding='utf-8') manifest = (source / f'{kind}.yaml').read_text(encoding='utf-8')
version = re.search(r'^version: (\d+\.\d+\.\d+)$', manifest, re.M)[1] version = re.search(r'^version: (\d+\.\d+\.\d+)$', manifest, re.M)[1]
@@ -38,7 +42,7 @@ def build(output: Path | None = None) -> dict:
for name in sorted(files): for name in sorted(files):
info = zipfile.ZipInfo(f'{identity}/{name}', date_time=(1980, 1, 1, 0, 0, 0)) info = zipfile.ZipInfo(f'{identity}/{name}', date_time=(1980, 1, 1, 0, 0, 0))
info.create_system = 3 info.create_system = 3
info.external_attr = 0o100644 << 16 info.external_attr = (0o100755 if name == 'markdown-workbench.exe' else 0o100644) << 16
info.compress_type = zipfile.ZIP_DEFLATED info.compress_type = zipfile.ZIP_DEFLATED
content = generated.get(name) content = generated.get(name)
if content is None: if content is None:
+28
View File
@@ -0,0 +1,28 @@
from pathlib import Path
LOCK_FILES = (
Path("backend/uv.lock"),
Path("server sync/uv.lock"),
Path("community-server/uv.lock"),
)
REPLACEMENTS = {
"https://pypi.org/simple": "https://mirrors.aliyun.com/pypi/simple",
"https://files.pythonhosted.org/packages/": "https://mirrors.aliyun.com/pypi/packages/",
}
def main() -> None:
for path in LOCK_FILES:
if not path.is_file():
continue
content = path.read_text(encoding="utf-8")
for source, mirror in REPLACEMENTS.items():
content = content.replace(source, mirror)
path.write_text(content, encoding="utf-8", newline="\n")
print(f"已切换锁文件下载源:{path}")
if __name__ == "__main__":
main()