ci: revert automated IDL releases and changelogs

This reverts commit ef2c8c1a8e.
This commit is contained in:
DiheChen committed 2026-11-04 11:52:54 +08:00
1 parent ef2c8c1a8e
commit 76b97fb6ab
5 files changed
+38 -285

No files matched your search

+1 -29
View File
@@ -3,7 +3,7 @@ name: CI
on:
push:
branches: [master]
tags: ['v*.*.*']
tags: ['v*']
pull_request:
workflow_dispatch:
@@ -162,31 +162,3 @@ jobs:
repository="$(printf '%s' "${GITHUB_REPOSITORY}" | tr '[:upper:]' '[:lower:]')"
printf '%s' "$GITHUB_TOKEN" | helm registry login ghcr.io --username "$GITHUB_ACTOR" --password-stdin
helm push "${RUNNER_TEMP}/helm-packages/alisten-${chart_version}.tgz" "oci://ghcr.io/${repository}/charts"
release:
needs: helm-release
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Generate release notes
shell: bash
run: |
set -euo pipefail
python scripts/generate_changelog.py --tag "$GITHUB_REF_NAME" --output release-notes.md
test -s release-notes.md
- name: Publish release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
body_path: release-notes.md
files: protocol/idl.json
fail_on_unmatched_files: true
+37
View File
@@ -0,0 +1,37 @@
name: Release assets
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: 要上传附件的 Release tag
required: true
type: string
concurrency:
group: release-assets-${{ github.event.release.tag_name || inputs.tag }}
permissions:
contents: read
jobs:
idl:
runs-on: ubuntu-latest
permissions:
contents: write
env:
TAG: ${{ github.event.release.tag_name || inputs.tag }}
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v7
with:
ref: refs/tags/${{ env.TAG }}
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
- run: go run ./cmd/protocolgen -check
- run: gh release upload "$TAG" protocol/idl.json --clobber
- run: gh release download "$TAG" --pattern idl.json --output - | cmp - protocol/idl.json
-222
View File
@@ -1,222 +0,0 @@
"""根据正式版本标签生成项目 Changelog。"""
from __future__ import annotations
import argparse
import json
import re
import subprocess
import sys
from collections import defaultdict
from dataclasses import dataclass
from pathlib import Path
VERSION_TAG_PATTERN = re.compile(r"^v(\d+)\.(\d+)\.(\d+)$")
# type 与 emoji 之间的空格可有可无(\s*),同时兼容 "feat ✨:" 旧格式与 "feat✨:" 新格式
COMMIT_PATTERN = re.compile(
r"^(?P<type>[A-Za-z]+)(?:\s*[^\w\s:(]+)?"
r"(?:\((?P<scope>[^)]+)\))?\s*:\s*(?P<message>.+)$"
)
GITHUB_NOREPLY_PATTERN = re.compile(
r"^(?:\d+\+)?(?P<username>[^@]+)@users\.noreply\.github\.com$",
re.IGNORECASE,
)
DEFAULT_NICKNAME_MAP_PATH = Path(__file__).with_name("git-nickname-username.json")
CATEGORY_BY_TYPE = {
"feat": "✨ Features",
"fix": "🐛 Bug Fixes",
"patch": "🐛 Bug Fixes",
"perf": "🚀 Performance Improvements",
"refactor": "🎨 Code Refactoring",
"docs": "📚 Documentation",
"deps": "🧩 Dependency Updates",
"build": "🧩 Dependency Updates",
"test": "🧪 Tests",
"ci": "⚙️ Continuous Integration",
"chore": "🧹 Maintenance",
"style": "🧹 Maintenance",
"format": "🧹 Maintenance",
"config": "🧹 Maintenance",
}
CATEGORY_ORDER = tuple(dict.fromkeys(CATEGORY_BY_TYPE.values())) + ("Other Changes",)
@dataclass(frozen=True)
class Commit:
subject: str
author_name: str
author_email: str
category: str
def run_git(*args: str) -> str:
result = subprocess.run(
["git", *args],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding="utf-8",
)
return result.stdout
def parse_version_tag(tag: str) -> tuple[int, int, int] | None:
match = VERSION_TAG_PATTERN.fullmatch(tag)
if not match:
return None
return int(match.group(1)), int(match.group(2)), int(match.group(3))
def get_release_tags() -> list[str]:
tags = [line.strip() for line in run_git("tag", "--list").splitlines()]
versions = [
(version, tag)
for tag in tags
if (version := parse_version_tag(tag)) is not None
]
return [tag for _, tag in sorted(versions, reverse=True)]
def get_previous_tag(tag: str, tags: list[str]) -> str | None:
index = tags.index(tag)
return tags[index + 1] if index + 1 < len(tags) else None
def read_commit_records(tag: str, previous_tag: str | None) -> list[str]:
revision = f"{previous_tag}..{tag}" if previous_tag else tag
output = run_git(
"log",
"--no-merges",
"--format=%an%x1f%ae%x1f%s%x1e",
revision,
)
return [record.strip() for record in output.split("\x1e") if record.strip()]
def load_nickname_map(path: Path = DEFAULT_NICKNAME_MAP_PATH) -> dict[str, str]:
if not path.exists():
return {}
data = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(data, dict):
raise ValueError(f"Git 昵称映射配置必须是 JSON 对象:{path}")
return {
name: username
for name, username in data.items()
if not name.startswith("$") and isinstance(username, str)
}
def format_author(name: str, email: str, nickname_map: dict[str, str]) -> str:
mapped_username = nickname_map.get(name.strip())
if mapped_username:
return f"@{mapped_username}"
match = GITHUB_NOREPLY_PATTERN.fullmatch(email.strip())
return f"@{match.group('username')}" if match else name.strip()
def parse_commit_record(record: str) -> Commit:
fields = record.split("\x1f", maxsplit=2)
if len(fields) != 3:
raise ValueError("Git 提交记录格式损坏")
author_name, author_email, raw_subject = (field.strip() for field in fields)
match = COMMIT_PATTERN.fullmatch(raw_subject)
if not match:
return Commit(raw_subject, author_name, author_email, "Other Changes")
commit_type = match.group("type").lower()
scope = match.group("scope")
message = match.group("message").strip()
subject = f"*({scope})* {message}" if scope else message
category = CATEGORY_BY_TYPE.get(commit_type, "Other Changes")
return Commit(subject, author_name, author_email, category)
def render_version(tag: str, tags: list[str], nickname_map: dict[str, str]) -> str:
if parse_version_tag(tag) is None:
raise ValueError(f"不是正式版本标签:{tag}")
if tag not in tags:
raise ValueError(f"正式版本标签不存在:{tag}")
run_git("rev-parse", "--verify", f"refs/tags/{tag}")
previous_tag = get_previous_tag(tag, tags)
commits = [parse_commit_record(record) for record in read_commit_records(tag, previous_tag)]
grouped: dict[str, list[Commit]] = defaultdict(list)
for commit in commits:
grouped[commit.category].append(commit)
date = run_git("log", "-1", "--format=%cs", tag).strip()
lines = [f"## {tag.removeprefix('v')} ({date})"]
for category in CATEGORY_ORDER:
category_commits = grouped.get(category)
if not category_commits:
continue
lines.extend(("", f"### {category}", ""))
lines.extend(
f"- {commit.subject} {format_author(commit.author_name, commit.author_email, nickname_map)}"
for commit in category_commits
)
return "\n".join(lines) + "\n"
def render_unreleased(nickname_map: dict[str, str]) -> str:
"""无 tag 时,将 HEAD 视为未发布版本,范围为全部提交。"""
commits = [parse_commit_record(record) for record in read_commit_records("HEAD", None)]
grouped: dict[str, list[Commit]] = defaultdict(list)
for commit in commits:
grouped[commit.category].append(commit)
lines = ["## 未发布"]
for category in CATEGORY_ORDER:
category_commits = grouped.get(category)
if not category_commits:
continue
lines.extend(("", f"### {category}", ""))
lines.extend(
f"- {commit.subject} {format_author(commit.author_name, commit.author_email, nickname_map)}"
for commit in category_commits
)
return "\n".join(lines) + "\n"
def render_changelog(tags: list[str], nickname_map: dict[str, str]) -> str:
if not tags:
return render_unreleased(nickname_map)
sections = [render_version(tag, tags, nickname_map).rstrip() for tag in tags]
return "# 更新日志\n\n" + "\n\n".join(sections) + "\n"
def parse_args(argv: list[str] | None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="根据正式版本标签生成项目 Changelog")
mode = parser.add_mutually_exclusive_group(required=True)
mode.add_argument("--tag", help="只生成指定正式版本的发布说明")
mode.add_argument("--all", action="store_true", help="生成全部正式版本的 Changelog")
parser.add_argument("--output", type=Path, help="将结果写入指定文件")
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
try:
tags = get_release_tags()
nickname_map = load_nickname_map()
content = (
render_changelog(tags, nickname_map)
if args.all
else render_version(args.tag, tags, nickname_map)
)
if args.output:
args.output.write_text(content, encoding="utf-8", newline="\n")
else:
sys.stdout.buffer.write(content.encode("utf-8"))
return 0
except (subprocess.CalledProcessError, ValueError, OSError) as error:
detail = error.stderr.strip() if isinstance(error, subprocess.CalledProcessError) else str(error)
print(f"生成 Changelog 失败:{detail}", file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())
-8
View File
@@ -1,8 +0,0 @@
{
"$schema": "./git-nickname-username.schema.json",
"$comment": "Git 昵称到 GitHub 用户名的映射,用于 generate_changelog.py 脚本",
"azmiao": "azmiao",
"AZMIAO": "azmiao",
"DiheChen": "DiheChen",
"dependabot[bot]": "dependabot[bot]"
}
-26
View File
@@ -1,26 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Git Nickname to GitHub Username Mapping",
"description": "Git 提交昵称到 GitHub 用户名的映射配置,用于 generate_changelog.py 正确生成 @username 链接",
"type": "object",
"properties": {
"$schema": {
"type": "string",
"description": "JSON Schema 引用"
},
"$comment": {
"type": "string",
"description": "配置文件说明"
}
},
"additionalProperties": {
"type": "string",
"description": "GitHub 用户名",
"pattern": "^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}(\\[bot\\])?$"
},
"examples": [
{
"azmiao": "azmiao"
}
]
}