chore(release): 版本发布 - 准备 v1.5.7.1 预览版

This commit is contained in:
ddCat
2026-09-22 09:23:18 +08:00
parent e0e6be450b
commit b2a1bcc8d9
9 changed files with 55 additions and 32 deletions

View File

@@ -15,7 +15,7 @@ done
tags=(--tag "$IMAGE:sha-$GITHUB_SHA" --tag "$IMAGE:sha-${GITHUB_SHA:0:7}")
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
[[ "${VERSION_TAG:?}" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]] || { echo "Invalid version image tag" >&2; exit 1; }
[[ "${VERSION_TAG:?}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?([.-][0-9A-Za-z.-]+)?$ ]] || { echo "Invalid version image tag" >&2; exit 1; }
tags+=(--tag "$IMAGE:$VERSION_TAG")
elif [[ "$GITHUB_REF" == refs/heads/main ]]; then
current_sha=$(gh api "repos/${GITHUB_REPOSITORY:?}/git/ref/heads/main" --jq '.object.sha')

View File

@@ -204,7 +204,7 @@ jobs:
shell: bash
run: |
prerelease_args=()
if [[ "$GITHUB_REF_NAME" == *-* || "$GITHUB_REF_NAME" == *.rc* ]]; then
if [[ "$GITHUB_REF_NAME" == *-* || "$GITHUB_REF_NAME" == *.rc* || "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
prerelease_args+=(--prerelease)
fi
gh release create "$GITHUB_REF_NAME" \

View File

@@ -1,5 +1,10 @@
# CHANGELOG
## v1.5.7.1
- 预览版:包含 v1.5.7 之后主分支已合入的画布批量生成一致性、素材批量删除、Live2D 配置导入、模型选择、Agent 运行稳定性、声明式文本流和后台运维界面改进。
- 修复在线更新版本比较,使四段版本号 `v1.5.7.1` 可以被 Host Updater 识别并高于 `v1.5.7`;该版本标记为 GitHub 预发布,不覆盖正式版 `latest`。
## v1.5.7
- 合并 PR #549(原作者 @15657306288):新增图片 / 视频列表分析、动态多维表格、视频分镜转换与关键帧绑定,以及批量生成设置;参考图上限前后端统一为 10。

View File

@@ -1 +1 @@
v1.5.7
v1.5.7.1

View File

@@ -6,8 +6,8 @@ import (
)
type versionPart struct {
major, minor, patch int
pre []string
core []int
pre []string
}
func IsReleaseVersion(raw string) bool {
@@ -32,11 +32,18 @@ func CompareVersions(left, right string) int {
}
func compareParsedVersions(a, b versionPart) int {
for _, pair := range [][2]int{{a.major, b.major}, {a.minor, b.minor}, {a.patch, b.patch}} {
if pair[0] < pair[1] {
for index := 0; index < len(a.core) || index < len(b.core); index++ {
left, right := 0, 0
if index < len(a.core) {
left = a.core[index]
}
if index < len(b.core) {
right = b.core[index]
}
if left < right {
return -1
}
if pair[0] > pair[1] {
if left > right {
return 1
}
}
@@ -78,16 +85,18 @@ func parseVersion(raw string) (versionPart, bool) {
value = strings.SplitN(value, "+", 2)[0]
parts := strings.SplitN(value, "-", 2)
core := strings.Split(parts[0], ".")
if len(core) != 3 {
if len(core) < 3 {
return versionPart{}, false
}
major, err1 := strconv.Atoi(core[0])
minor, err2 := strconv.Atoi(core[1])
patch, err3 := strconv.Atoi(core[2])
if err1 != nil || err2 != nil || err3 != nil {
return versionPart{}, false
coreNumbers := make([]int, len(core))
for index, value := range core {
number, err := strconv.Atoi(value)
if err != nil {
return versionPart{}, false
}
coreNumbers[index] = number
}
parsed := versionPart{major: major, minor: minor, patch: patch}
parsed := versionPart{core: coreNumbers}
if len(parts) == 2 && parts[1] != "" {
parsed.pre = strings.FieldsFunc(parts[1], func(r rune) bool { return r == '.' || r == '-' })
}

View File

@@ -11,6 +11,8 @@ func TestCompareVersions(t *testing.T) {
{"v1.2.0-preview.10", "v1.2.0-preview.3", 1},
{"v1.2.0-preview.3", "v1.2.0", -1},
{"v1.2.1", "v1.2.0", 1},
{"v1.5.7.1", "v1.5.7", 1},
{"v1.5.7.1", "v1.5.7.2", -1},
{"v1.2.0", "v1.2.0", 0},
{"vsha-5509b17", "v1.5.0", -1},
{"sha-5509b17", "v1.5.0", -1},

View File

@@ -14,7 +14,7 @@ description: Host Updater、Release 检查、数据库备份迁移、健康验
## 安全更新顺序
1. 从 GitHub Releases 读取包含预览版在内的最高语义版本,并与 `.env` 中固定的 `CANVAS_IMAGE_TAG` 比较。`sha-*` 这类非正式镜像标签一律视为低于正式 Release,避免把 `vsha-5509b17` 字典序比较成比 `v1.5.0` 更新。
2. 下载目标版本的 `docker-compose.deploy.yml`,执行 `docker compose config --quiet`,检查部署文件、磁盘空间和当前版本。当前标签不是 `vX.Y.Z` 时,健康检查只确认服务就绪,不要求构建号和镜像标签逐字相同。
2. 下载目标版本的 `docker-compose.deploy.yml`,执行 `docker compose config --quiet`,检查部署文件、磁盘空间和当前版本。当前标签不是 `vX.Y.Z` 或 `vX.Y.Z.N` 时,健康检查只确认服务就绪,不要求构建号和镜像标签逐字相同。
3. 创建 `backup-YYYYMMDD-HHMMSS.zip.partial`,其中包含 PostgreSQL custom-format dump、后端数据目录 tar 和元数据;写入完成后 `fsync`、原子改名,并复核 ZIP 结构和 SHA-256。
4. 拉取目标 backend/web 镜像并要求存在仓库 `sha256` 摘要。任何失败都在停服前中止。
5. 停止 web/backend,等待 Backend 的 SIGTERM drain 完成;PostgreSQL 和 Redis 保持运行。

View File

@@ -124,7 +124,11 @@ function adminPopupContainer(node?: HTMLElement) {
export function AdminShell() {
const userId = useUserStore((state) => state.user?.id);
return <AdminDensityProvider key={userId || "anonymous"} userId={userId}><AdminShellLayout /></AdminDensityProvider>;
return (
<AdminDensityProvider key={userId || "anonymous"} userId={userId}>
<AdminShellLayout />
</AdminDensityProvider>
);
}
function AdminShellLayout() {

View File

@@ -91,7 +91,9 @@ export default function AnalyticsPanel({ users, channels }: Props) {
else next.delete("rangePreset");
setSearchParams(next, { replace: true });
void reload();
return () => { requestSequence.current += 1; };
return () => {
requestSequence.current += 1;
};
}, [filters, rangePreset]);
useEffect(() => {
@@ -275,7 +277,19 @@ export default function AnalyticsPanel({ users, channels }: Props) {
</ListToolbar>
{financeUnavailable && <Alert type="warning" showIcon title="后端未返回完整财务统计,缺失金额显示为 --。请确认后端已更新并重启后刷新。" />}
{loadError && <Alert type="error" showIcon title="统计数据读取失败" description={loadError} action={<Button size="small" onClick={() => void reload()}>重试</Button>} />}
{loadError && (
<Alert
type="error"
showIcon
title="统计数据读取失败"
description={loadError}
action={
<Button size="small" onClick={() => void reload()}>
重试
</Button>
}
/>
)}
<section className="admin-analytics-health-grid" aria-label="运营健康指标">
<AnalyticsHealthCard
@@ -300,19 +314,8 @@ export default function AnalyticsPanel({ users, channels }: Props) {
detail={data ? (data.kpi.upstreamRequests ? "真实上游请求成功率" : "当前范围暂无请求") : undefined}
tone={!data || !data.kpi.upstreamRequests ? "neutral" : data.kpi.successRate < 90 ? "warning" : "success"}
/>
<AnalyticsHealthCard
icon={<Clock3 className="size-4" />}
label="P95 请求耗时"
value={data && data.kpi.upstreamRequests > 0 ? formatDuration(data.kpi.p95DurationMs) : "--"}
detail="筛选范围内的上游请求"
/>
<AnalyticsHealthCard
icon={<Workflow className="size-4" />}
label="当前排队"
value={data ? formatNumber(data.kpi.currentQueuedTasks) : "--"}
detail="实时快照 · 非历史累计"
tone={data?.kpi.currentQueuedTasks ? "warning" : "neutral"}
/>
<AnalyticsHealthCard icon={<Clock3 className="size-4" />} label="P95 请求耗时" value={data && data.kpi.upstreamRequests > 0 ? formatDuration(data.kpi.p95DurationMs) : "--"} detail="筛选范围内的上游请求" />
<AnalyticsHealthCard icon={<Workflow className="size-4" />} label="当前排队" value={data ? formatNumber(data.kpi.currentQueuedTasks) : "--"} detail="实时快照 · 非历史累计" tone={data?.kpi.currentQueuedTasks ? "warning" : "neutral"} />
<AnalyticsHealthCard
icon={<CircleDollarSign className="size-4" />}
label="费用统计(积分)"