Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f17e607ad2 | |||
| 3cb232a84d |
+37
-278
File diff suppressed because one or more lines are too long
@@ -142,11 +142,15 @@ jobs:
|
||||
python3 scripts/check_schema_metadata.py
|
||||
|
||||
'
|
||||
- name: Check migration safety
|
||||
- name: Prepare git for migration diff
|
||||
shell: sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: "set -eu\npython3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/develop\n"
|
||||
GITHUB_SERVER_URL: ${{ github.server_url }}
|
||||
run: "set -eu\nif command -v git >/dev/null 2>&1; then\n if [ ! -d .git ]; then\n git init -q\n git config user.email \"ci@localhost\"\n git config user.name \"CI\"\n git add .\n git commit -q -m \"current\"\n REPO_URL=\"https://x-access-token:${GITHUB_TOKEN}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git\"\n git remote add origin \"$REPO_URL\"\n fi\n git fetch origin main --depth=1 -q 2>/dev/null || echo \"WARN: cannot fetch main, will check all migrations\"\nelse\n echo \"WARN: git not available, will check all migrations\"\nfi\n"
|
||||
- name: Check migration safety
|
||||
shell: sh
|
||||
run: "set -eu\nif git rev-parse origin/main >/dev/null 2>&1; then\n python3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/main\nelse\n python3 scripts/check_migration_safety.py --allow-medium-risk\nfi\n"
|
||||
- name: Job duration summary
|
||||
if: always()
|
||||
shell: sh
|
||||
@@ -399,4 +403,4 @@ jobs:
|
||||
|
||||
NOTIFY_MODE=failure JOB_NAME="Frontend Lint" python3 scripts/ci_notify.py
|
||||
|
||||
'
|
||||
'
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
name: Debug Build Schedule
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- debug/ci-build-schedule
|
||||
jobs:
|
||||
test-simple:
|
||||
name: Test Simple Job
|
||||
runs-on: host
|
||||
steps:
|
||||
- name: Hello
|
||||
shell: sh
|
||||
run: echo "Hello from simple job"
|
||||
test-matrix:
|
||||
name: Test Matrix ${{ matrix.name }}
|
||||
runs-on: host
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: A
|
||||
timeout: 5
|
||||
- name: B
|
||||
timeout: 5
|
||||
timeout-minutes: ${{ matrix.timeout }}
|
||||
steps:
|
||||
- name: Hello
|
||||
shell: sh
|
||||
run: echo "Hello from matrix job ${{ matrix.name }}"
|
||||
test-if:
|
||||
name: Test If Condition
|
||||
runs-on: host
|
||||
if: github.event_name == "push" && github.ref_name == "debug/ci-build-schedule"
|
||||
steps:
|
||||
- name: Hello
|
||||
shell: sh
|
||||
run: echo "Hello from if job"
|
||||
@@ -1,64 +0,0 @@
|
||||
name: Debug Build Schedule v2 - Copy CI Build Structure
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- debug/ci-build-schedule
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
jobs:
|
||||
build-staging:
|
||||
name: Build Staging ${{ matrix.service_display }} Image
|
||||
runs-on: host
|
||||
timeout-minutes: ${{ matrix.timeout }}
|
||||
if: github.event_name == "push" && github.ref_name == "debug/ci-build-schedule"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- service: api
|
||||
service_display: API
|
||||
timeout: 10
|
||||
- service: worker
|
||||
service_display: Worker
|
||||
timeout: 10
|
||||
- service: web
|
||||
service_display: Web
|
||||
timeout: 10
|
||||
steps:
|
||||
- name: Step 1
|
||||
shell: sh
|
||||
run: echo "Step 1"
|
||||
- name: Step 2
|
||||
shell: sh
|
||||
run: echo "Step 2"
|
||||
- name: Step 3
|
||||
shell: sh
|
||||
run: echo "Step 3"
|
||||
deploy-staging:
|
||||
name: Deploy Staging
|
||||
runs-on: host
|
||||
timeout-minutes: 15
|
||||
if: github.event_name == "push" && github.ref_name == "debug/ci-build-schedule"
|
||||
needs:
|
||||
- build-staging
|
||||
steps:
|
||||
- name: Deploy
|
||||
shell: sh
|
||||
run: echo "Deploy"
|
||||
build-production:
|
||||
name: Build Production ${{ matrix.service_display }} Image
|
||||
runs-on: host
|
||||
timeout-minutes: ${{ matrix.timeout }}
|
||||
if: startsWith(github.ref, "refs/tags/v")
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- service: api
|
||||
service_display: API
|
||||
timeout: 10
|
||||
steps:
|
||||
- name: Step 1
|
||||
shell: sh
|
||||
run: echo "Step 1"
|
||||
@@ -72,7 +72,6 @@ class EditPlanResponse(BaseModel):
|
||||
name: str
|
||||
status: str
|
||||
total_duration: float
|
||||
result_count: int = 0
|
||||
project_id: str = ""
|
||||
created_by_user_id: str = ""
|
||||
config: dict[str, Any]
|
||||
@@ -242,7 +241,6 @@ def _to_response(p: EditPlan) -> EditPlanResponse:
|
||||
name=p.name,
|
||||
status=p.status.value if hasattr(p.status, "value") else p.status,
|
||||
total_duration=p.total_duration,
|
||||
result_count=getattr(p, "result_count", 0),
|
||||
project_id=p.project_id or "",
|
||||
created_by_user_id=p.created_by_user_id or "",
|
||||
config=p.config,
|
||||
|
||||
@@ -130,8 +130,6 @@ export interface EditPlan {
|
||||
name: string;
|
||||
status: EditPlanStatus;
|
||||
total_duration: number;
|
||||
/** 生成视频数量(后端 EditPlanResponse.result_count) */
|
||||
result_count: number;
|
||||
config: EditPlanConfig;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
@@ -163,21 +161,14 @@ export interface GenerateResponse {
|
||||
clip_count: number;
|
||||
}
|
||||
|
||||
/** 剪辑计划关联的生成记录(实际是 GenerationTask 对象) */
|
||||
/** 剪辑计划关联的生成记录 */
|
||||
export interface EditPlanGeneration {
|
||||
id: string; // 即 generation_task_id
|
||||
source_edit_plan_id: string;
|
||||
template_id: string;
|
||||
asset_ids: string[];
|
||||
id: string;
|
||||
edit_plan_id: string;
|
||||
generation_task_id: string;
|
||||
status: EditPlanStatus;
|
||||
progress: number;
|
||||
result_count: number;
|
||||
error_message: string;
|
||||
error_info: Record<string, unknown>;
|
||||
logs: Array<Record<string, unknown>>;
|
||||
retry_count: number;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
/** 片段生成状态 */
|
||||
|
||||
@@ -254,16 +254,6 @@ export default function EditPlans() {
|
||||
<span className="plan-duration">{formatDuration(seconds)}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "视频数",
|
||||
dataIndex: "result_count",
|
||||
key: "result_count",
|
||||
width: 80,
|
||||
align: "center",
|
||||
render: (count: number) => (
|
||||
<span className="plan-result-count">{count > 0 ? count : "—"}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "创建时间",
|
||||
dataIndex: "created_at",
|
||||
|
||||
@@ -1279,8 +1279,8 @@ const EditingPlanner: React.FC = () => {
|
||||
|
||||
{/* ═══ 生成进度弹窗 ═══ */}
|
||||
<Modal
|
||||
title={genError ? "生成失败" : generated ? "生成完成" : "正在生成视频"}
|
||||
open={generating || generated || !!genError}
|
||||
title={generated ? "生成完成" : "正在生成视频"}
|
||||
open={generating || generated}
|
||||
footer={
|
||||
generated
|
||||
? [
|
||||
|
||||
@@ -65,7 +65,7 @@ const GenerationHistoryModal: React.FC<GenerationHistoryModalProps> = ({
|
||||
return (
|
||||
<tr key={gen.id} className="ep-gh-table-row">
|
||||
<td className="ep-gh-td ep-gh-td-id">
|
||||
{gen.id ? `${gen.id.slice(0, 8)}...` : "—"}
|
||||
{gen.generation_task_id.slice(0, 8)}...
|
||||
</td>
|
||||
<td className="ep-gh-td">
|
||||
<span className={`ep-gh-status-tag ${statusClass}`}>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import JSON, Boolean, Column, DateTime, Float, Integer, String, Text, UniqueConstraint
|
||||
from sqlalchemy.orm import declarative_base
|
||||
|
||||
Base: Any = declarative_base()
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
class UserModel(Base):
|
||||
|
||||
@@ -30,13 +30,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
|
||||
@@ -102,37 +99,30 @@ def extract_upgrade_content(content: str) -> str:
|
||||
|
||||
def get_new_migrations_via_diff(diff_target: str) -> List[Path]:
|
||||
"""
|
||||
通过 Gitea API 对比目标分支,找出 alembic/versions/ 下新增的迁移文件。
|
||||
不依赖本地 git,避免 CI 环境下 git 操作不稳定的问题。
|
||||
通过 git diff 对比目标分支/commit,找出 alembic/versions/ 下新增的迁移文件。
|
||||
只包含新增文件(A状态),不包含修改或删除的文件。
|
||||
"""
|
||||
api_url = os.environ.get("GITHUB_API_URL", "")
|
||||
repo = os.environ.get("GITHUB_REPOSITORY", "")
|
||||
token = os.environ.get("GITHUB_TOKEN", "")
|
||||
branch = diff_target.replace("origin/", "")
|
||||
|
||||
if not api_url or not repo or not token:
|
||||
print("⚠️ CI 环境变量不完整,降级为检查所有迁移文件")
|
||||
return sorted(ALEMBIC_VERSIONS_DIR.glob("*.py"))
|
||||
|
||||
try:
|
||||
url = f"{api_url}/repos/{repo}/contents/alembic/versions?ref={branch}"
|
||||
req = urllib.request.Request(url, headers={"Authorization": f"token {token}"})
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
data = json.loads(resp.read().decode())
|
||||
|
||||
remote_files = {item["name"] for item in data if item["name"].endswith(".py")}
|
||||
local_files = {f.name for f in ALEMBIC_VERSIONS_DIR.glob("*.py")}
|
||||
new_file_names = sorted(local_files - remote_files)
|
||||
|
||||
if new_file_names:
|
||||
result = [ALEMBIC_VERSIONS_DIR / f for f in new_file_names]
|
||||
print(f" (API 对比 {branch} 分支,发现 {len(result)} 个新增迁移)")
|
||||
return result
|
||||
else:
|
||||
print(f" (API 对比 {branch} 分支,无新增迁移)")
|
||||
return []
|
||||
except Exception as e:
|
||||
print(f"⚠️ API 获取迁移列表失败:{e}")
|
||||
result = subprocess.run(
|
||||
[
|
||||
"git",
|
||||
"diff",
|
||||
"--name-only",
|
||||
"--diff-filter=A",
|
||||
diff_target,
|
||||
"HEAD",
|
||||
"--",
|
||||
"alembic/versions/",
|
||||
],
|
||||
cwd=str(REPO_ROOT),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
files = [line.strip() for line in result.stdout.strip().split("\n") if line.strip()]
|
||||
return [REPO_ROOT / f for f in files]
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"⚠️ git diff 失败({diff_target}):{e.stderr.strip()}")
|
||||
print(" 降级为检查所有迁移文件")
|
||||
return sorted(ALEMBIC_VERSIONS_DIR.glob("*.py"))
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# 环境变量:
|
||||
# IMAGE_TAG - 镜像版本 tag(如 commit SHA 或分支名)
|
||||
# REGISTRY_TOKEN - Registry 访问令牌
|
||||
# REGISTRY - Registry 地址(默认 xiaoxia-registry.cn-hangzhou.cr.aliyuncs.com/xiaoxiakeji)
|
||||
# REGISTRY - Registry 地址(默认 git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas)
|
||||
# REGISTRY_USER - Registry 用户名(默认 xiaoxia)
|
||||
# ENV_FILE - 环境变量文件路径
|
||||
# GENERATED_DIR - 生成文件目录
|
||||
@@ -16,9 +16,9 @@
|
||||
set -eu
|
||||
|
||||
IMAGE_TAG="${IMAGE_TAG:-}"
|
||||
REGISTRY="${REGISTRY:-xiaoxia-registry.cn-hangzhou.cr.aliyuncs.com/xiaoxiakeji}"
|
||||
REGISTRY_USER="${ACR_USERNAME:-${REGISTRY_USER:-nick0415343655}}"
|
||||
REGISTRY_TOKEN="${ACR_PASSWORD:-${REGISTRY_TOKEN:-}}"
|
||||
REGISTRY="${REGISTRY:-git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas}"
|
||||
REGISTRY_USER="${REGISTRY_USER:-xiaoxia}"
|
||||
REGISTRY_TOKEN="${REGISTRY_TOKEN:-}"
|
||||
|
||||
ENV_FILE="${ENV_FILE:-/var/lib/xiaoxia-saas-staging/.env}"
|
||||
GENERATED_DIR="${GENERATED_DIR:-/var/lib/xiaoxia-saas-staging/generated}"
|
||||
|
||||
Reference in New Issue
Block a user