Files
Auto_Bangumi/.github/workflows/build.yml
Estrella Pan bfc7209491 fix(ci): setup-uv 固定到 v10.3.0,折叠面板补上 region 语义
- astral-sh/setup-uv 没有 v10 主版本标签,CI 无法解析 action
- ab-fold-panel 改用 NCollapse 后,标题按钮的父元素不再是整个面板,e2e 用 '..' 找不到面板内的字段。正文改为以标题命名的 region,按钮补上 aria-controls;e2e 改用 getByRole('region')
2026-10-20 13:50:27 +02:00

438 lines
16 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Build Docker
on:
pull_request:
types:
- opened
- synchronize
branches:
- main
- "3.*-dev"
push:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.14
uses: actions/setup-python@v5
with:
python-version: "3.14"
- uses: astral-sh/setup-uv@v10.3.0
with:
version: "0.13.x"
- name: Install dependencies
run: cd backend && uv sync --group dev
- name: Lint
run: cd backend && uv run ruff check src
- name: Format check
run: cd backend && uv run ruff format --check src
- name: Dead code
run: cd backend && uv run vulture
- name: Type check
run: cd backend && uv run mypy src
- name: Test
run: |
mkdir -p backend/config
cd backend && uv run pytest src/test -v -m "not e2e"
# 示例插件:校验清单并跑各自的契约 / 行为测试(与插件作者在示例目录里
# `uv run pytest` 一致)
- name: Example plugins
run: scripts/test_example_plugins.sh
webui-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 24
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 12.14.0
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: cd webui && pnpm install
- name: Lint
run: cd webui && pnpm lint
- name: Unit test
run: cd webui && pnpm test
- name: build test
run: |
cd webui && pnpm test:build
version-info:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
# 发布只由手动推送 tag 触发:
# - 稳定版:语义化版本号 tag(如 3.3.2),且必须打在 main 的提交上
# - 预发布:包含 alpha/beta 的 tag(如 3.4.0-beta.1),在 dev 分支上打
# 合并 PR 不再触发发布(防止 PR 标题被当作版本号,见 #1065)。
- name: Classify trigger
id: classify
env:
EVENT_NAME: ${{ github.event_name }}
REF_TYPE: ${{ github.ref_type }}
REF_NAME: ${{ github.ref_name }}
HEAD_REF: ${{ github.event.pull_request.head.ref }}
PR_TITLE: ${{ github.event.pull_request.title }}
run: python3 scripts/classify_release.py --output "$GITHUB_OUTPUT"
- name: Check result
run: |
echo "release: ${{ steps.classify.outputs.release }}"
echo "dev: ${{ steps.classify.outputs.dev }}"
echo "build_test: ${{ steps.classify.outputs.build_test }}"
echo "version: ${{ steps.classify.outputs.version }}"
outputs:
release: ${{ steps.classify.outputs.release }}
dev: ${{ steps.classify.outputs.dev }}
build_test: ${{ steps.classify.outputs.build_test }}
version: ${{ steps.classify.outputs.version }}
build-webui:
runs-on: ubuntu-latest
needs: [test, webui-test, version-info]
if: ${{ needs.version-info.outputs.release == 1 || needs.version-info.outputs.dev == 1 || needs.version-info.outputs.build_test == 1 }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 24
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 12.14.0
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: cd webui && pnpm install
- name: Build
run: |
cd webui && pnpm build
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: dist
path: webui/dist
build-docker:
runs-on: ubuntu-latest
needs: [build-webui, version-info]
if: ${{ needs.version-info.outputs.release == 1 || needs.version-info.outputs.dev == 1 || needs.version-info.outputs.build_test == 1 }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Create Version info via tag
working-directory: ./backend/src
run: |
echo ${{ needs.version-info.outputs.version }}
echo "VERSION='${{ needs.version-info.outputs.version }}'" >> module/__version__.py
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Docker metadata main
if: ${{ needs.version-info.outputs.release == 1 && needs.version-info.outputs.dev != 1 }}
id: meta
uses: docker/metadata-action@v5
with:
images: |
estrellaxd/auto_bangumi
ghcr.io/${{ github.repository }}
tags: |
type=raw,value=${{ needs.version-info.outputs.version }}
type=raw,value=latest
- name: Docker metadata dev
if: ${{ needs.version-info.outputs.dev == 1 }}
id: meta-dev
uses: docker/metadata-action@v5
with:
images: |
estrellaxd/auto_bangumi
ghcr.io/${{ github.repository }}
tags: |
type=raw,value=${{ needs.version-info.outputs.version }}
type=raw,value=dev-latest
- name: Login to DockerHub
if: ${{ needs.version-info.outputs.release == 1 }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Login to ghcr.io
if: ${{ needs.version-info.outputs.release == 1 }}
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.ACCESS_TOKEN }}
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: dist
path: backend/src/dist
- name: Build and push
if: ${{ needs.version-info.outputs.release == 1 && needs.version-info.outputs.dev != 1 }}
uses: docker/build-push-action@v6
with:
context: .
builder: ${{ steps.buildx.outputs.name }}
platforms: linux/amd64,linux/arm64
push: True
build-args: |
VERSION=${{ needs.version-info.outputs.version }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ github.workflow }}
cache-to: type=gha,scope=${{ github.workflow }},ignore-error=true
- name: Build and push dev
if: ${{ needs.version-info.outputs.dev == 1 }}
uses: docker/build-push-action@v6
with:
context: .
builder: ${{ steps.buildx.outputs.name }}
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name == 'push' }}
build-args: |
VERSION=${{ needs.version-info.outputs.version }}
tags: ${{ steps.meta-dev.outputs.tags }}
labels: ${{ steps.meta-dev.outputs.labels }}
cache-from: type=gha,scope=${{ github.workflow }}
cache-to: type=gha,scope=${{ github.workflow }},ignore-error=true
- name: Build test
if: ${{ needs.version-info.outputs.release == 0 }}
uses: docker/build-push-action@v6
with:
context: .
builder: ${{ steps.buildx.outputs.name }}
platforms: linux/amd64,linux/arm64
push: false
build-args: |
VERSION=${{ needs.version-info.outputs.version }}
tags: estrellaxd/auto_bangumi:test
cache-from: type=gha,scope=${{ github.workflow }}
cache-to: type=gha,scope=${{ github.workflow }},ignore-error=true
release:
runs-on: ubuntu-latest
needs: [build-docker, version-info]
if: ${{ needs.version-info.outputs.release == 1 }}
outputs:
url: ${{ steps.release.outputs.url }}
version: ${{ needs.version-info.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download artifact webui
uses: actions/download-artifact@v4
with:
name: dist
path: webui/dist
- name: Zip webui
run: |
cd webui && ls -al && tree && zip -r dist.zip dist
- name: Download artifact app
uses: actions/download-artifact@v4
with:
name: dist
path: backend/src/dist
- name: Create Version info via tag
working-directory: ./backend/src
run: |
echo ${{ needs.version-info.outputs.version }}
echo "VERSION='${{ needs.version-info.outputs.version }}'" >> module/__version__.py
- uses: astral-sh/setup-uv@v10.3.0
with:
version: "0.13.x"
- name: Generate requirements.txt for non-uv consumers (#994)
run: |
cd backend && uv export --format requirements-txt --no-hashes --no-dev -o requirements.txt
- name: Zip app
run: |
cd backend && zip -r app-v${{ needs.version-info.outputs.version }}.zip \
src pyproject.toml uv.lock requirements.txt
# 插件作者用的两个附件:autobangumi-sdk 轮子(ab_sdk + ab-plugin,不发 PyPI,
# 作者从 release 下载安装)和 autobangumi-plugin agent skill 的 zip。
# beta(预发布)与稳定版 release 都会带上它们。
- name: Build plugin SDK wheel
run: uv build --wheel backend/sdk --out-dir sdk-dist
- name: Zip plugin-author skill
run: |
cd skills && zip -r "../autobangumi-plugin-skill-${{ needs.version-info.outputs.version }}.zip" autobangumi-plugin
# 在线自动更新 bundle:module 与 ab_sdk 源码树 + pyproject/uv.lock + 前端 dist +
# manifest。同时产出 .sha256(客户端下载后据此校验完整性)。min_image_version
# 是能应用此 bundle 布局的最低镜像版本。4.x 的 module 依赖同版本的 ab_sdk 与新
# 依赖,只有 4.0 起的镜像(boot_overlay 会替换 /app/ab_sdk)能应用;已发布的
# 3.3 镜像在 beta 通道会选中最新的预发布,必须靠这个下限拒绝。本分支只发 4.x,
# 下一个大版本若再改 bundle 布局,在这里提高下限。
- name: Build update bundle
run: |
VERSION="${{ needs.version-info.outputs.version }}"
MIN_IMAGE_VERSION="4.0.0-beta.1"
STAGE="bundle_stage"
rm -rf "$STAGE"
mkdir -p "$STAGE/backend/src" "$STAGE/webui-dist"
cp -r backend/src/module "$STAGE/backend/src/module"
cp -r backend/src/ab_sdk "$STAGE/backend/src/ab_sdk"
cp backend/pyproject.toml backend/uv.lock "$STAGE/backend/"
cp -r webui/dist/. "$STAGE/webui-dist/"
LOCK_SHA=$(sha256sum backend/uv.lock | awk '{print $1}')
cat > "$STAGE/manifest.json" <<EOF
{
"version": "$VERSION",
"min_image_version": "$MIN_IMAGE_VERSION",
"lockfile_sha256": "$LOCK_SHA",
"notes": "See release notes."
}
EOF
( cd "$STAGE" && zip -r "../update-bundle-${VERSION}.zip" backend webui-dist manifest.json )
sha256sum "update-bundle-${VERSION}.zip" | awk '{print $1}' > "update-bundle-${VERSION}.zip.sha256"
# 对 bundle 做 ed25519 签名(私钥在 UPDATE_SIGNING_KEY secret,公钥随镜像
# 分发)。客户端 apply 前验签,boot_overlay 每次启动重新验签——没有 .sig
# 的 release 会被更新器拒绝,所以签名失败必须让构建失败。
- name: Sign update bundle
env:
UPDATE_SIGNING_KEY: ${{ secrets.UPDATE_SIGNING_KEY }}
run: |
if [ -z "$UPDATE_SIGNING_KEY" ]; then
echo "::error::UPDATE_SIGNING_KEY secret is not set; unsigned bundles are rejected by the updater" >&2
exit 1
fi
VERSION="${{ needs.version-info.outputs.version }}"
uv run --no-project --with cryptography python - "update-bundle-${VERSION}.zip" <<'PY'
import base64, os, sys
from pathlib import Path
from cryptography.hazmat.primitives.serialization import load_pem_private_key
bundle = Path(sys.argv[1])
key = load_pem_private_key(os.environ["UPDATE_SIGNING_KEY"].encode(), password=None)
sig = key.sign(bundle.read_bytes())
Path(str(bundle) + ".sig").write_text(base64.b64encode(sig).decode() + "\n")
print(f"signed {bundle}")
PY
- name: Generate Release info
id: release-info
run: |
if ${{ needs.version-info.outputs.dev == 1 }}; then
echo "version=🌙${{ needs.version-info.outputs.version }}" >> $GITHUB_OUTPUT
echo "pre_release=true" >> $GITHUB_OUTPUT
else
echo "version=🌟${{ needs.version-info.outputs.version }}" >> $GITHUB_OUTPUT
echo "pre_release=false" >> $GITHUB_OUTPUT
fi
- name: Read changelog
id: changelog
run: |
# Derive the changelog file from the release version's major.minor (e.g. 3.3.0-beta.1 -> 3.3.md)
CHANGELOG_VERSION=$(echo "${{ needs.version-info.outputs.version }}" | grep -oE '^[0-9]+\.[0-9]+')
CHANGELOG_FILE="docs/changelog/${CHANGELOG_VERSION}.md"
if [ -f "$CHANGELOG_FILE" ]; then
echo "body<<EOF" >> $GITHUB_OUTPUT
cat "$CHANGELOG_FILE" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
fi
- name: Release
id: release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ needs.version-info.outputs.version }}
name: ${{ steps.release-info.outputs.version }}
body: ${{ steps.changelog.outputs.body }}
draft: false
prerelease: ${{ steps.release-info.outputs.pre_release == 'true' }}
files: |
webui/dist.zip
backend/app-v${{ needs.version-info.outputs.version }}.zip
update-bundle-${{ needs.version-info.outputs.version }}.zip
update-bundle-${{ needs.version-info.outputs.version }}.zip.sha256
update-bundle-${{ needs.version-info.outputs.version }}.zip.sig
sdk-dist/*.whl
autobangumi-plugin-skill-${{ needs.version-info.outputs.version }}.zip
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
telegram:
runs-on: ubuntu-latest
needs: [release]
steps:
- name: send telegram message on push
uses: appleboy/telegram-action@master
with:
to: ${{ secrets.TELEGRAM_TO }}
token: ${{ secrets.TELEGRAM_TOKEN }}
message: |
New release: ${{ needs.release.outputs.version }}
Link: ${{ needs.release.outputs.url }}