mirror of
https://gitee.com/zoujingli/ThinkAdmin.git
synced 2026-06-07 04:28:11 +08:00
为 ThinkAdmin 主仓库补强 v6-dev 与 v8-dev 的自动化处理机制,避免两个开发分支在插件仓库分支、发布 Tag 与 Release Notes 生成时互相覆盖。 主要内容: - 拆分工作流仅允许 v6-dev 与 v8-dev,按同名分支推送各插件仓库。 - 发布工作流按 v6.* / v8.* Tag 自动选择对应开发分支,并要求 Tag 指向对应分支最新提交。 - 发布脚本同步推送插件分支和同名 Tag,遇到冲突 Tag 会拒绝覆盖。 - 新增中文 Release Notes 生成器,按提交前缀自动汇总本次变更内容。 - 静态分析步骤兼容 v6-dev 未定义 analyse 脚本的情况,避免旧分支发布失败。
119 lines
3.6 KiB
Python
Executable File
119 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
from __future__ import annotations
|
||
|
||
import os
|
||
import re
|
||
import subprocess
|
||
from collections import OrderedDict
|
||
from pathlib import Path
|
||
|
||
CURRENT_TAG = os.environ["CURRENT_TAG"]
|
||
PREVIOUS_TAG = os.environ.get("PREVIOUS_TAG", "")
|
||
RELEASE_BRANCH = os.environ.get("RELEASE_BRANCH", "")
|
||
GITHUB_REPOSITORY = os.environ.get("GITHUB_REPOSITORY", "zoujingli/ThinkAdmin")
|
||
|
||
GROUPS = OrderedDict([
|
||
("feat", "新增功能"),
|
||
("fix", "问题修复"),
|
||
("refactor", "重构调整"),
|
||
("perf", "性能优化"),
|
||
("pref", "性能优化"),
|
||
("style", "样式调整"),
|
||
("docs", "文档更新"),
|
||
("test", "测试质量"),
|
||
("build", "构建发布"),
|
||
("ci", "持续集成"),
|
||
("chore", "工程维护"),
|
||
("other", "其他变更"),
|
||
])
|
||
|
||
PREFIX_RE = re.compile(r"^(?P<type>[a-z]+)(?:\((?P<scope>[^)]+)\))?[::]\s*(?P<title>.+)$")
|
||
|
||
|
||
def git_lines(*args: str) -> list[str]:
|
||
out = subprocess.check_output(["git", *args], text=True)
|
||
return [line for line in out.splitlines() if line]
|
||
|
||
|
||
def release_range() -> str:
|
||
if PREVIOUS_TAG:
|
||
return f"{PREVIOUS_TAG}..{CURRENT_TAG}"
|
||
return CURRENT_TAG
|
||
|
||
|
||
def commits() -> list[tuple[str, str]]:
|
||
lines = git_lines("log", "--pretty=format:%H%x01%s", release_range())
|
||
result: list[tuple[str, str]] = []
|
||
for line in lines:
|
||
sha, subject = line.split("\x01", 1)
|
||
result.append((sha, subject))
|
||
return result
|
||
|
||
|
||
def normalize(subject: str) -> tuple[str, str]:
|
||
match = PREFIX_RE.match(subject)
|
||
if not match:
|
||
return "other", subject
|
||
typ = match.group("type")
|
||
title = match.group("title")
|
||
if typ not in GROUPS:
|
||
typ = "other"
|
||
scope = match.group("scope")
|
||
if scope:
|
||
title = f"【{scope}】{title}"
|
||
return typ, title
|
||
|
||
|
||
def main() -> None:
|
||
grouped: dict[str, list[str]] = {key: [] for key in GROUPS}
|
||
all_commits = commits()
|
||
|
||
for sha, subject in all_commits:
|
||
typ, title = normalize(subject)
|
||
grouped[typ].append(f"- {title} ({sha[:8]})")
|
||
|
||
lines: list[str] = []
|
||
lines.append(f"## Release {CURRENT_TAG}")
|
||
lines.append("")
|
||
if RELEASE_BRANCH:
|
||
lines.append(f"- 发布分支:`{RELEASE_BRANCH}`")
|
||
if PREVIOUS_TAG:
|
||
compare_url = f"https://github.com/{GITHUB_REPOSITORY}/compare/{PREVIOUS_TAG}...{CURRENT_TAG}"
|
||
lines.append(f"- 对比范围:[`{PREVIOUS_TAG}...{CURRENT_TAG}`]({compare_url})")
|
||
else:
|
||
lines.append("- 对比范围:首次发布标签")
|
||
lines.append(f"- 提交数量:{len(all_commits)}")
|
||
lines.append("")
|
||
|
||
lines.append("## 本次变更摘要")
|
||
lines.append("")
|
||
summary = [f"{label} {len(items)} 项" for key, label in GROUPS.items() if (items := grouped[key])]
|
||
lines.append("、".join(summary) if summary else "- 本次发布没有检测到提交变更。")
|
||
lines.append("")
|
||
|
||
lines.append("## 变更明细")
|
||
lines.append("")
|
||
for key, label in GROUPS.items():
|
||
items = grouped[key]
|
||
if not items:
|
||
continue
|
||
lines.append(f"### {label}")
|
||
lines.extend(items)
|
||
lines.append("")
|
||
|
||
lines.append("## 发布说明")
|
||
lines.append("")
|
||
lines.append("- 主仓库 Release 由 GitHub Actions 自动创建。")
|
||
lines.append("- 插件仓库会同步推送同名分支和同名 Tag,Packagist 可通过 GitHub Hook 自动刷新。")
|
||
lines.append("- v6 与 v8 使用不同主版本号 Tag,避免两个开发分支发布互相覆盖。")
|
||
lines.append("")
|
||
|
||
out = Path("log") / f"{CURRENT_TAG}.md"
|
||
out.parent.mkdir(parents=True, exist_ok=True)
|
||
out.write_text("\n".join(lines), encoding="utf-8")
|
||
print(out)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|