chore(release): 优化发布脚本并统一表名

- publish_release.py: 自动加载.env,macOS Universal拆分为x86_64+aarch64,七牛云目录按平台区分
- 重命名表 mjk_release_packages -> mjk_app_release_packages,同步约束名
- 更新相关文档
This commit is contained in:
小鱼开发
2026-05-26 10:13:52 +08:00
parent 915339d42a
commit 8cddaec70e
5 changed files with 73 additions and 27 deletions
+7 -7
View File
@@ -71,7 +71,7 @@ INSERT INTO app_releases (version, release_date, notes, mandatory) VALUES
('0.2.0', '2026-04-20 10:00:00', '新增:批量导出功能\n优化:性能提升 30%', FALSE);
```
#### 2.1.2 release_packages - 平台包信息
#### 2.1.2 mjk_app_release_packages - 平台包信息
| 字段 | 类型 | 说明 | 约束 |
|------|------|------|------|
@@ -97,7 +97,7 @@ INSERT INTO app_releases (version, release_date, notes, mandatory) VALUES
**示例数据**:
```sql
INSERT INTO release_packages (release_id, platform, architecture, filename, file_url, file_size, file_hash) VALUES
INSERT INTO mjk_app_release_packages (release_id, platform, architecture, filename, file_url, file_size, file_hash) VALUES
(2, 'darwin', 'x86_64', 'meijiaka_0.1.1_darwin_x86_64.dmg',
'https://cdn.meijiaka.com/releases/meijiaka_0.1.1_darwin_x86_64.dmg',
102400000, 'sha256:abc123...'),
@@ -129,7 +129,7 @@ INSERT INTO release_packages (release_id, platform, architecture, filename, file
CREATE INDEX idx_releases_release_date ON app_releases(release_date DESC);
-- 平台包复合索引
CREATE INDEX idx_packages_platform_arch ON release_packages(platform, architecture);
CREATE INDEX idx_packages_platform_arch ON mjk_app_release_packages(platform, architecture);
-- 下载统计
CREATE INDEX idx_downloads_release_id ON update_downloads(release_id);
@@ -151,7 +151,7 @@ CREATE TABLE IF NOT EXISTS app_releases (
);
-- 创建平台包信息表
CREATE TABLE IF NOT EXISTS release_packages (
CREATE TABLE IF NOT EXISTS mjk_app_release_packages (
id SERIAL PRIMARY KEY,
release_id INTEGER NOT NULL REFERENCES app_releases(id) ON DELETE CASCADE,
platform VARCHAR(20) NOT NULL,
@@ -177,8 +177,8 @@ CREATE TABLE IF NOT EXISTS update_downloads (
-- 创建索引
CREATE INDEX IF NOT EXISTS idx_releases_version ON app_releases(version);
CREATE INDEX IF NOT EXISTS idx_releases_release_date ON app_releases(release_date DESC);
CREATE INDEX IF NOT EXISTS idx_packages_platform_arch ON release_packages(platform, architecture);
CREATE INDEX IF NOT EXISTS idx_packages_release_id ON release_packages(release_id);
CREATE INDEX IF NOT EXISTS idx_packages_platform_arch ON mjk_app_release_packages(platform, architecture);
CREATE INDEX IF NOT EXISTS idx_packages_release_id ON mjk_app_release_packages(release_id);
CREATE INDEX IF NOT EXISTS idx_downloads_release_id ON update_downloads(release_id);
CREATE INDEX IF NOT EXISTS idx_downloads_download_at ON update_downloads(download_at);
@@ -240,7 +240,7 @@ class AppRelease(Base):
class ReleasePackage(Base):
"""平台包信息"""
__tablename__ = "release_packages"
__tablename__ = "mjk_app_release_packages"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
release_id: Mapped[int] = mapped_column(
+1 -1
View File
@@ -170,4 +170,4 @@ Tauri updater 插件已内置跨平台安装逻辑,前端代码无需区分平
| `tauri-app/src-tauri/tauri.conf.json` | updater 配置:公钥 + endpoint URL |
| `python-api/scripts/publish_release.py` | 发版脚本(扫描 .sig → 上传七牛云 → 写数据库) |
| `python-api/app/api/v1/update.py` | 后端更新检查 API |
| `python-api/app/models/update.py` | 数据库模型(`app_releases` / `release_packages` |
| `python-api/app/models/update.py` | 数据库模型(`mjk_app_releases` / `mjk_app_release_packages` |
@@ -0,0 +1,29 @@
"""rename mjk_release_packages to mjk_app_release_packages
Revision ID: 8d901bc90e67
Revises: 7149f61a2f9c
Create Date: 2026-05-26 10:05:16.921079
"""
from typing import Sequence, Union
from alembic import op
# revision identifiers, used by Alembic.
revision: str = '8d901bc90e67'
down_revision: Union[str, Sequence[str], None] = '7149f61a2f9c'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
op.execute("ALTER TABLE IF EXISTS mjk_release_packages RENAME TO mjk_app_release_packages")
op.execute("ALTER INDEX IF EXISTS uix_pkg_platform_arch RENAME TO uix_app_pkg_platform_arch")
def downgrade() -> None:
"""Downgrade schema."""
op.execute("ALTER INDEX IF EXISTS uix_app_pkg_platform_arch RENAME TO uix_pkg_platform_arch")
op.execute("ALTER TABLE IF EXISTS mjk_app_release_packages RENAME TO mjk_release_packages")
+2 -2
View File
@@ -38,7 +38,7 @@ class AppRelease(Base):
class ReleasePackage(Base):
"""平台安装包信息"""
__tablename__ = "mjk_release_packages"
__tablename__ = "mjk_app_release_packages"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
release_id: Mapped[int] = mapped_column(
@@ -60,5 +60,5 @@ class ReleasePackage(Base):
release: Mapped["AppRelease"] = relationship("AppRelease", back_populates="packages")
__table_args__ = (
UniqueConstraint("release_id", "platform", "architecture", name="uix_pkg_platform_arch"),
UniqueConstraint("release_id", "platform", "architecture", name="uix_app_pkg_platform_arch"),
)
+34 -17
View File
@@ -24,6 +24,9 @@ import sys
from pathlib import Path
import httpx
from dotenv import load_dotenv
load_dotenv()
def find_packages(bundle_dir: Path) -> list[dict]:
@@ -37,21 +40,30 @@ def find_packages(bundle_dir: Path) -> list[dict]:
print(f"警告: 签名文件存在但安装包缺失: {pkg_file}")
continue
# 解析文件名:{name}_{version}_{target}_{arch}.app.tar.gz
parts = pkg_file.stem.split("_")
# 最后一个部分可能是 arch,需要处理
arch = "aarch64" if "aarch64" in pkg_file.name or "arm64" in pkg_file.name else "x86_64"
signature = sig_file.read_text().strip()
file_size = pkg_file.stat().st_size
filename = pkg_file.name
packages.append({
"platform": "darwin",
"architecture": arch,
"filename": pkg_file.name,
"local_path": str(pkg_file),
"signature": signature,
"file_size": pkg_file.stat().st_size,
})
# 判断文件名是否包含架构标识
has_arch_marker = any(marker in filename for marker in ["aarch64", "arm64", "x86_64"])
if has_arch_marker:
# 文件名含架构标识,按标识解析
arch = "aarch64" if "aarch64" in filename or "arm64" in filename else "x86_64"
archs = [arch]
else:
# Universal Binary:同时支持 x86_64 和 aarch64
archs = ["x86_64", "aarch64"]
for arch in archs:
packages.append({
"platform": "darwin",
"architecture": arch,
"filename": filename,
"local_path": str(pkg_file),
"signature": signature,
"file_size": file_size,
})
# Windows: .exe + .exe.sig
for sig_file in bundle_dir.rglob("*.exe.sig"):
@@ -165,16 +177,21 @@ def main():
print(f" - {p['platform']}-{p['architecture']}: {p['filename']} ({p['file_size'] / 1024 / 1024:.1f} MB)")
# 2. 上传到七牛云(或构造 URL)
# 按 local_path 去重,同一个文件只上传一次
uploaded = {} # local_path -> file_url
for p in packages:
if args.skip_upload:
if not args.base_url:
print("错误: --skip-upload 时必须提供 --base-url")
sys.exit(1)
p["file_url"] = f"{args.base_url.rstrip('/')}/{p['filename']}"
p["file_url"] = f"{args.base_url.rstrip('/')}/{p['platform']}/{p['filename']}"
else:
key = f"releases/{args.version}/{p['filename']}"
print(f"上传 {p['filename']} 到七牛云...")
p["file_url"] = upload_to_qiniu(p["local_path"], key)
local_path = p["local_path"]
if local_path not in uploaded:
key = f"meijiaka-zy/releases/{args.version}/{p['platform']}/{p['filename']}"
print(f"上传 {p['filename']} ({p['platform']}) 到七牛云...")
uploaded[local_path] = upload_to_qiniu(local_path, key)
p["file_url"] = uploaded[local_path]
# 删除临时字段
del p["local_path"]