diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 12f1a6e..26600c3 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -7,6 +7,9 @@ on: branches: [main, "feat/**", "fix/**", "chore/**"] workflow_dispatch: +env: + APP_EXPORT_FONT: /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf + jobs: docs-check: runs-on: ubuntu-latest @@ -19,6 +22,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - 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 @@ -66,9 +73,18 @@ jobs: steps: - uses: actions/checkout@v4 - name: 安装 Rust 工具链 - shell: bash 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" - - run: cargo fmt --check && cargo test --lib --locked && cargo clippy --lib --locked -- -D warnings + - 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 diff --git a/backend/app/extensions/archive.py b/backend/app/extensions/archive.py index 58640ff..b74c729 100644 --- a/backend/app/extensions/archive.py +++ b/backend/app/extensions/archive.py @@ -82,6 +82,8 @@ def install_zip(data: bytes, kind: str, storage: Path, install: Callable[[Path], if written > MAX_EXPANDED_BYTES: raise ApiError(413, 'EXTENSION_ZIP_TOO_LARGE', 'ZIP 解压后不能超过 50 MiB。') output.write(chunk) + if (entry.external_attr >> 16) & 0o111: + target.chmod(0o755) manifest = f'{kind}.yaml' root = destination if not (root / manifest).is_file(): diff --git a/backend/extensions/community/build_packages.py b/backend/extensions/community/build_packages.py index 462ef72..c57e2f1 100644 --- a/backend/extensions/community/build_packages.py +++ b/backend/extensions/community/build_packages.py @@ -3,6 +3,7 @@ import hashlib import json import re import subprocess +import sys import tempfile import zipfile from pathlib import Path @@ -24,12 +25,15 @@ def build(output: Path | None = None) -> dict: if identity == 'markdown-workbench': with tempfile.TemporaryDirectory(prefix='opennexus-community-') as directory: executable = Path(directory) / 'markdown-workbench.exe' - subprocess.run([ + rustc_command = [ 'rustc', '--edition=2021', '--crate-name', 'markdown_workbench', '-C', 'metadata=opennexus-community-v1', '-C', 'opt-level=s', - '-C', 'strip=symbols', '-C', 'link-arg=-Wl,--no-insert-timestamp', - str(source / 'server.rs'), '-o', str(executable), - ], check=True) + '-C', 'strip=symbols', + ] + 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() manifest = (source / f'{kind}.yaml').read_text(encoding='utf-8') 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): info = zipfile.ZipInfo(f'{identity}/{name}', date_time=(1980, 1, 1, 0, 0, 0)) 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 content = generated.get(name) if content is None: