chore: streamline compatibility tracking and documentation
Release / Validate Templates (push) Canceled after 0s
Release / Package & Release (push) Canceled after 0s

This commit is contained in:
KenanZhu committed 2026-10-09 11:43:02 +08:00
1 parent 92d2ba9889
commit 23f0456622
16 files changed
+476 -259

No files matched your search

+1 -1
View File
@@ -19,4 +19,4 @@ DOCS
---
**Full Changelog:** [v1.0.1...v1.27.2](https://github.com/KenanZhu/GiteaMailTemplates/compare/v1.0.1...v1.27.2)
**Full Changelog:** [v1.0.1...v1.27.2](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/compare/v1.0.1...v1.27.2)
+1 -1
View File
@@ -19,4 +19,4 @@ DOCS
---
**Full Changelog:** [v1.27.2...v1.27.3](https://github.com/KenanZhu/GiteaMailTemplates/compare/v1.27.2...v1.27.3)
**Full Changelog:** [v1.27.2...v1.27.3](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/compare/v1.27.2...v1.27.3)
+1 -1
View File
@@ -18,4 +18,4 @@ DOCS
---
**Full Changelog:** [v1.27.3...v28.0.0](https://github.com/KenanZhu/GiteaMailTemplates/compare/v1.27.3...v28.0.0)
**Full Changelog:** [v1.27.3...v28.0.0](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/compare/v1.27.3...v28.0.0)
+137
View File
@@ -0,0 +1,137 @@
"""Offline tests for the compatibility tracker."""
import importlib.util
import io
import json
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
SCRIPT = Path(__file__).with_name("track_gitea_release.py")
SPEC = importlib.util.spec_from_file_location("track_gitea_release", SCRIPT)
TRACKER = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(TRACKER)
class TrackerTests(unittest.TestCase):
def setUp(self):
self.directory = tempfile.TemporaryDirectory(prefix="tracker-test-", dir=TRACKER.ROOT)
self.addCleanup(self.directory.cleanup)
self.root = Path(self.directory.name)
self.paths = ("COMPATIBILITY.md", "README.md", "AGENTS.md", "docs/README.zh-CN.md")
self.originals = {}
for name in self.paths:
destination = self.root / name
destination.parent.mkdir(parents=True, exist_ok=True)
content = (TRACKER.ROOT / name).read_text(encoding="utf-8")
destination.write_text(content, encoding="utf-8")
self.originals[name] = content
def read(self, name):
return (self.root / name).read_text(encoding="utf-8")
def assert_unchanged(self):
for name, content in self.originals.items():
self.assertEqual(content, self.read(name), name)
def test_new_release_adds_only_pending_rows(self):
changed = TRACKER.apply_release(self.root, "28.2.0", "2026-11-01")
self.assertEqual({self.root / name for name in self.paths}, set(changed))
compatibility = self.read("COMPATIBILITY.md")
self.assertIn("| 28.2.0 | [PENDING] Compatibility verification", compatibility)
self.assertIn("| **28.2.0** | 2026-11-01 | [PENDING]", compatibility)
self.assertIn("| **v28.0.0** | **28.0.0** | **28.0.0** | [PASS] Active |", compatibility)
self.assertIn("Latest verified:** Release v28.0.0", compatibility)
self.assertIn("Gitea-28.2.0%20%5BPENDING%5D%20%7C%2028.0.0%20tested-yellow", self.read("README.md"))
self.assertIn("Gitea 28.2.0:** [PENDING]", self.read("README.md"))
self.assertIn("Gitea 28.2.0:** [PENDING]", self.read("docs/README.zh-CN.md"))
self.assertIn("Gitea release: 28.2.0 [PENDING]", self.read("AGENTS.md"))
self.assertIn("Latest tested:** Gitea 28.0.0", self.read("README.md"))
self.assertIn("最新测试:** Gitea 28.0.0", self.read("docs/README.zh-CN.md"))
self.assertEqual([], TRACKER.apply_release(self.root, "28.2.0", "2026-11-01"))
def test_existing_version_is_idempotent(self):
self.assertEqual([], TRACKER.apply_release(self.root, "28.1.0", "2026-10-06"))
self.assert_unchanged()
def test_partial_update_is_repaired(self):
compatibility = self.root / "COMPATIBILITY.md"
partial = self.read("COMPATIBILITY.md").replace("| 28.1.0 | [PENDING] Compatibility verification; no tested template release yet |\n", "")
compatibility.write_text(partial, encoding="utf-8")
self.assertEqual([compatibility], TRACKER.apply_release(self.root, "28.1.0", "2026-10-06"))
self.assertIn("| 28.1.0 | [PENDING] Compatibility verification", self.read("COMPATIBILITY.md"))
def test_older_version_does_not_rewrite_history(self):
self.assertEqual([], TRACKER.apply_release(self.root, "28.0.0", "2026-09-29"))
self.assert_unchanged()
def test_dry_run_does_not_write(self):
self.assertEqual(4, len(TRACKER.apply_release(self.root, "28.2.0", "2026-11-01", dry_run=True)))
self.assert_unchanged()
def test_missing_marker_fails_without_writing(self):
compatibility = self.root / "COMPATIBILITY.md"
compatibility.write_text(self.read("COMPATIBILITY.md").replace("<!-- TRACKER:HISTORY -->", ""), encoding="utf-8")
with self.assertRaises(ValueError):
TRACKER.apply_release(self.root, "28.2.0", "2026-11-01")
self.assertEqual(self.originals["README.md"], self.read("README.md"))
def test_unknown_marker_fails_without_writing(self):
news = self.root / "docs/NEWS.md"
news.write_text("Gitea 28.1.0 [PENDING] <!-- TRACKER:FUTURE-UNKNOWN -->\n", encoding="utf-8")
with self.assertRaisesRegex(ValueError, "Unknown TRACKER marker"):
TRACKER.apply_release(self.root, "28.2.0", "2026-11-01")
self.assert_unchanged()
def test_new_marked_document_is_discovered(self):
news = self.root / "docs/NEWS.md"
news.write_text("Gitea 28.1.0 [PENDING] <!-- TRACKER:UPSTREAM -->\n", encoding="utf-8")
changed = TRACKER.apply_release(self.root, "28.2.0", "2026-11-01")
self.assertIn(news, changed)
self.assertEqual("Gitea 28.2.0 [PENDING] <!-- TRACKER:UPSTREAM -->\n", news.read_text(encoding="utf-8"))
def test_disagreeing_tested_versions_fail(self):
chinese = self.root / "docs/README.zh-CN.md"
chinese.write_text(self.read("docs/README.zh-CN.md").replace("**最新测试:** Gitea 28.0.0", "**最新测试:** Gitea 28.1.0"), encoding="utf-8")
with self.assertRaisesRegex(ValueError, "disagree"):
TRACKER.apply_release(self.root, "28.2.0", "2026-11-01")
def test_after_verification_new_version_becomes_pending(self):
english = self.root / "README.md"
chinese = self.root / "docs/README.zh-CN.md"
agents = self.root / "AGENTS.md"
english.write_text(self.read("README.md")
.replace("**Latest tested:** Gitea 28.0.0", "**Latest tested:** Gitea 28.1.0")
.replace("Gitea-28.1.0%20%5BPENDING%5D%20%7C%2028.0.0%20tested-yellow", "Gitea-28.1.0%20%7C%2028.1.0%20tested-blue")
.replace("**Upstream Gitea 28.1.0:** [PENDING]", "**Upstream Gitea 28.1.0:** [PASS]"), encoding="utf-8")
chinese.write_text(self.read("docs/README.zh-CN.md")
.replace("**最新测试:** Gitea 28.0.0", "**最新测试:** Gitea 28.1.0")
.replace("**上游 Gitea 28.1.0:** [PENDING]", "**上游 Gitea 28.1.0:** [PASS]"), encoding="utf-8")
agents.write_text(self.read("AGENTS.md").replace("28.1.0 [PENDING]", "28.1.0 [PASS]"), encoding="utf-8")
TRACKER.apply_release(self.root, "28.2.0", "2026-11-01")
self.assertIn("Gitea-28.2.0%20%5BPENDING%5D%20%7C%2028.1.0%20tested-yellow", self.read("README.md"))
self.assertIn("Gitea 28.2.0:** [PENDING]", self.read("README.md"))
self.assertIn("Latest tested:** Gitea 28.1.0", self.read("README.md"))
self.assertIn("最新测试:** Gitea 28.1.0", self.read("docs/README.zh-CN.md"))
def test_invalid_version_rejected(self):
with self.assertRaises(ValueError):
TRACKER.apply_release(self.root, "28.2.0-rc1", "2026-11-01")
def test_release_api_uses_published_date(self):
payload = {"tag_name": "v28.2.0", "published_at": "2026-11-01T08:15:00Z", "draft": False, "prerelease": False}
with patch.object(TRACKER, "urlopen", return_value=io.BytesIO(json.dumps(payload).encode("utf-8"))) as mocked:
self.assertEqual(("28.2.0", "2026-11-01"), TRACKER.fetch_release("28.2.0"))
self.assertEqual(f"{TRACKER.RELEASES_API}/tags/v28.2.0", mocked.call_args.args[0].full_url)
def test_prerelease_is_rejected(self):
payload = {"tag_name": "v28.2.0", "published_at": "2026-11-01T08:15:00Z", "prerelease": True}
with patch.object(TRACKER, "urlopen", return_value=io.BytesIO(json.dumps(payload).encode("utf-8"))):
with self.assertRaises(ValueError):
TRACKER.fetch_release(None)
if __name__ == "__main__":
unittest.main()
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/env python3
"""Record a new upstream Gitea release without changing verified compatibility."""
import argparse
import json
import os
import re
import sys
from datetime import date
from pathlib import Path
from urllib.request import Request, urlopen
ROOT = Path(__file__).resolve().parents[2]
RELEASES_API = "https://api.github.com/repos/go-gitea/gitea/releases"
VERSION_RE = re.compile(r"v?(\d+)\.(\d+)\.(\d+)\Z")
ROW_RE = re.compile(r"^\|\s*(?:\*\*)?(\d+\.\d+\.\d+)(?:\*\*)?\s*\|")
INLINE_VERSION_RE = re.compile(r"(?<!\d)\d+\.\d+\.\d+(?!\d)")
STATUS_RE = re.compile(r"\[(?:PENDING|PASS|WARN|FAIL|UNSUPPORTED)\]")
MARKER_RE = re.compile(r"<!-- TRACKER:([A-Z][A-Z0-9-]*) -->")
BADGE_RE = re.compile(r"Gitea-(\d+\.\d+\.\d+)(?:%20(?:pending|%5BPENDING%5D))?%20%7C%20(\d+\.\d+\.\d+)%20tested-(?:blue|yellow)")
TABLES = {
"VERSION-MAP": "| Gitea version | Template release |",
"HISTORY": "| Gitea | Release Date | Mail Template Changes | Breaking? |",
}
AUTO_MARKERS = frozenset((*TABLES, "BADGE", "UPSTREAM"))
MANUAL_MARKERS = frozenset(("LATEST-TESTED", "LATEST-VERIFIED"))
REQUIRED_MARKERS = {"VERSION-MAP": 1, "HISTORY": 1, "BADGE": 1, "UPSTREAM": 3, "LATEST-TESTED": 2, "LATEST-VERIFIED": 1}
def version_key(value):
match = VERSION_RE.fullmatch(value)
if not match:
raise ValueError(f"Expected a stable X.Y.Z version, got {value!r}")
return tuple(int(part) for part in match.groups())
def fetch_release(requested_version):
endpoint = f"{RELEASES_API}/tags/v{requested_version}" if requested_version else f"{RELEASES_API}/latest"
request = Request(endpoint, headers={"Accept": "application/vnd.github+json", "User-Agent": "gitea-mail-templates-tracker"})
token = os.environ.get("GITHUB_TOKEN")
if token:
request.add_header("Authorization", f"Bearer {token}")
with urlopen(request, timeout=20) as response:
release = json.load(response)
if release.get("draft") or release.get("prerelease"):
raise ValueError("Draft and prerelease Gitea versions are not tracked")
version = str(release["tag_name"]).removeprefix("v")
version_key(version)
if requested_version and version != requested_version:
raise ValueError(f"Release tag mismatch: expected {requested_version}, got {version}")
published = release.get("published_at")
if not published:
raise ValueError(f"Release v{version} has no published_at date")
release_date = date.fromisoformat(published[:10]).isoformat()
return version, release_date
def table(lines, marker_index, expected_header):
header = marker_index + 1
if header + 1 >= len(lines) or lines[header].strip() != expected_header:
raise ValueError(f"Unexpected table header after {lines[marker_index].strip()}")
if not re.fullmatch(r"\|[\s|:-]+\|", lines[header + 1].strip()):
raise ValueError(f"Missing Markdown table separator after {lines[marker_index].strip()}")
first = header + 2
end = first
while end < len(lines) and lines[end].startswith("|"):
end += 1
versions = set()
for line in lines[first:end]:
match = ROW_RE.match(line)
if not match:
if expected_header == TABLES["HISTORY"] and re.match(r"^\|\s*\*\*≤\s*\d+\.\d+\.x\*\*\s*\|", line):
continue
raise ValueError(f"Malformed version row after {lines[marker_index].strip()}: {line.strip()}")
if match.group(1) in versions:
raise ValueError(f"Duplicate version after {lines[marker_index].strip()}: {match.group(1)}")
versions.add(match.group(1))
if not versions:
raise ValueError(f"Empty version table after {lines[marker_index].strip()}")
return first, versions
def documents(root):
"""Discover Markdown docs; new docs opt in by adding a known TRACKER marker."""
paths = sorted((*root.glob("*.md"), *root.glob("docs/**/*.md")))
result = {path: path.read_text(encoding="utf-8").splitlines(keepends=True) for path in paths}
markers = []
for path, lines in result.items():
for index, line in enumerate(lines):
for match in MARKER_RE.finditer(line):
name = match.group(1)
if name not in AUTO_MARKERS | MANUAL_MARKERS:
raise ValueError(f"Unknown TRACKER marker {name} in {path}")
markers.append((path, index, name))
for name, minimum in REQUIRED_MARKERS.items():
count = sum(item[2] == name for item in markers)
if count < minimum or (name in TABLES or name == "BADGE") and count != minimum:
raise ValueError(f"Expected {minimum} TRACKER:{name} marker(s), found {count}")
return result, markers
def latest_tested(documents_by_path, markers):
versions = set()
for path, index, name in markers:
if name == "LATEST-TESTED":
match = re.search(r"Gitea\s+(\d+\.\d+\.\d+)", documents_by_path[path][index])
if not match:
raise ValueError(f"Missing Gitea version beside TRACKER:LATEST-TESTED in {path}")
versions.add(match.group(1))
if len(versions) != 1:
raise ValueError(f"LATEST-TESTED markers disagree: {sorted(versions)}")
return versions.pop()
def update_marker(lines, index, name, version, release_date, tested):
if name in TABLES:
first, versions = table(lines, index, TABLES[name])
if version not in versions:
if name == "VERSION-MAP":
row = f"| {version} | [PENDING] Compatibility verification; no tested template release yet |\n"
else:
row = f"| **{version}** | {release_date} | [PENDING] Mail-template compatibility verification | TBD |\n"
lines.insert(first, row)
elif name == "UPSTREAM":
versions = list(INLINE_VERSION_RE.finditer(lines[index]))
if len(STATUS_RE.findall(lines[index])) != 1 or len(versions) != 1:
raise ValueError("TRACKER:UPSTREAM needs exactly one status and version on the same line")
line = INLINE_VERSION_RE.sub(version, lines[index], count=1)
lines[index] = STATUS_RE.sub("[PENDING]", line, count=1)
elif name == "BADGE":
match = BADGE_RE.search(lines[index])
if not match or match.group(2) != tested:
raise ValueError("TRACKER:BADGE has an unexpected format or tested version")
badge = f"Gitea-{version}%20%5BPENDING%5D%20%7C%20{tested}%20tested-yellow"
lines[index] = BADGE_RE.sub(badge, lines[index], count=1)
def apply_release(root, version, release_date, dry_run=False):
target = version_key(version)
date.fromisoformat(release_date)
originals, markers = documents(root)
tested = latest_tested(originals, markers)
history_path, history_index, _ = next(item for item in markers if item[2] == "HISTORY")
history_first, _ = table(originals[history_path], history_index, TABLES["HISTORY"])
latest = version_key(ROW_RE.match(originals[history_path][history_first]).group(1))
if target < latest or target <= version_key(tested):
return []
updated = {path: lines.copy() for path, lines in originals.items()}
for path, index, name in sorted(markers, key=lambda item: (str(item[0]), item[1]), reverse=True):
if name in AUTO_MARKERS:
update_marker(updated[path], index, name, version, release_date, tested)
changed = [path for path in updated if updated[path] != originals[path]]
if not dry_run:
for path in changed:
path.write_text("".join(updated[path]), encoding="utf-8")
return changed
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--version", default=os.environ.get("GITEA_VERSION"), help="Specific stable Gitea version; omit for latest release")
parser.add_argument("--release-date", help="YYYY-MM-DD; use with --version for offline checks")
parser.add_argument("--dry-run", action="store_true", help="Check without changing repository documentation")
args = parser.parse_args()
if args.release_date and not args.version:
parser.error("--release-date requires --version")
if args.version:
args.version = args.version.removeprefix("v")
version_key(args.version)
if args.release_date:
version, release_date = args.version, date.fromisoformat(args.release_date).isoformat()
else:
version, release_date = fetch_release(args.version)
changed = apply_release(ROOT, version, release_date, dry_run=args.dry_run)
print(f"Gitea {version}: {', '.join(str(path.relative_to(ROOT)) for path in changed) if changed else 'already tracked'}")
output_path = os.environ.get("GITHUB_OUTPUT")
if output_path:
with open(output_path, "a", encoding="utf-8") as output:
output.write(f"version={version}\nchanged={'true' if changed else 'false'}\n")
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except (KeyError, OSError, ValueError) as error:
sys.exit(f"Tracker failed: {error}")
+23 -95
View File
@@ -2,12 +2,11 @@ name: Gitea Version Tracker
on:
schedule:
# Daily at 08:00 UTC — check for new Gitea releases
- cron: '0 8 * * *'
workflow_dispatch:
inputs:
version:
description: 'Gitea version (e.g. 1.27.0) — leave empty to auto-detect'
description: 'Stable Gitea version (e.g. 28.2.0); empty means latest'
required: false
jobs:
@@ -20,103 +19,32 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Determine latest Gitea version
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Test tracker
run: python -B -m unittest discover -s .github/scripts -p 'test_*.py'
- name: Record pending Gitea release
id: version
run: |
if [ -n "${{ github.event.inputs.version }}" ]; then
NEW_VERSION="${{ github.event.inputs.version }}"
else
# Fetch latest release from GitHub API (go-gitea/gitea mirror)
RELEASE_JSON=$(curl -sSf https://api.github.com/repos/go-gitea/gitea/releases/latest)
NEW_VERSION=$(echo "$RELEASE_JSON" | jq -r '.tag_name')
fi
# Strip 'v' prefix if present (API returns v1.27.0, we use 1.27.0)
NEW_VERSION="${NEW_VERSION#v}"
echo "New Gitea version: $NEW_VERSION"
# Parse marker line AND embedded OFFSET to locate the data row
MARKER_INFO=$(grep -n 'TRACKER:QUICK-REF-MAX' COMPATIBILITY.md)
MARKER_LINE=$(echo "$MARKER_INFO" | cut -d: -f1)
OFFSET=$(echo "$MARKER_INFO" | sed 's/.*OFFSET=\([0-9]*\).*/\1/')
CURRENT=$(sed -n "$((MARKER_LINE + OFFSET))p" COMPATIBILITY.md | awk -F'|' '{gsub(/\*| /, "", $4); print $4}')
echo "Current max tested: $CURRENT"
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "current_version=$CURRENT" >> $GITHUB_OUTPUT
if [ "$NEW_VERSION" = "$CURRENT" ]; then
echo "No new Gitea release detected. Skipping."
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "New version detected: $CURRENT → $NEW_VERSION"
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: COMPATIBILITY.md — Quick Reference (max tested version)
if: steps.version.outputs.skip != 'true'
run: |
NEW="${{ steps.version.outputs.new_version }}"
# Parse marker line and embedded OFFSET to locate the data row
MARKER_INFO=$(grep -n 'TRACKER:QUICK-REF-MAX' COMPATIBILITY.md)
MARKER=$(echo "$MARKER_INFO" | cut -d: -f1)
OFFSET=$(echo "$MARKER_INFO" | sed 's/.*OFFSET=\([0-9]*\).*/\1/')
TARGET=$((MARKER + OFFSET))
# Update column 4 (Max Tested) and column 5 (Status) in the pipe-separated row
awk -i inplace -F'|' -v OFS='|' -v ver="${NEW}" '
NR == '$TARGET' { $4 = " **" ver "** "; $5 = " ⏳ Pending Verification " }
{ print }
' COMPATIBILITY.md
- name: COMPATIBILITY.md — Version History table
if: steps.version.outputs.skip != 'true'
run: |
NEW="${{ steps.version.outputs.new_version }}"
TODAY=$(date +%Y-%m-%d)
# Parse marker line and embedded OFFSET for the insertion point
MARKER_INFO=$(grep -n 'TRACKER:VERSION-INSERT' COMPATIBILITY.md)
MARKER=$(echo "$MARKER_INFO" | cut -d: -f1)
OFFSET=$(echo "$MARKER_INFO" | sed 's/.*OFFSET=\([0-9]*\).*/\1/')
INSERT=$((MARKER + OFFSET))
ROW="| **${NEW}** | ${TODAY} | ⏳ Pending Verification | TBD |"
sed -i "${INSERT}a ${ROW}" COMPATIBILITY.md
- name: README.md — pending badge
if: steps.version.outputs.skip != 'true'
run: |
NEW="${{ steps.version.outputs.new_version }}"
# Badge: update version, change label tested→pending, color blue→yellow
sed -i "/TRACKER:BADGE/s/%20[0-9a-z.-]*%20tested-blue/%20${NEW}%20pending-yellow/" README.md
run: python -B .github/scripts/track_gitea_release.py
env:
GITEA_VERSION: ${{ github.event.inputs.version }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create Pull Request
if: steps.version.outputs.skip != 'true'
if: steps.version.outputs.changed == 'true'
uses: peter-evans/create-pull-request@v7
with:
branch: track/gitea-${{ steps.version.outputs.new_version }}
commit-message: "docs: track Gitea ${{ steps.version.outputs.new_version }} — pending verification"
title: "Track Gitea ${{ steps.version.outputs.new_version }} — ⏳ Pending Verification"
add-paths: '*.md'
branch: track/gitea-${{ steps.version.outputs.version }}
commit-message: "docs: track Gitea ${{ steps.version.outputs.version }} pending verification"
title: "Track Gitea ${{ steps.version.outputs.version }} compatibility"
body: |
Gitea **${{ steps.version.outputs.new_version }}** has been released.
Gitea **${{ steps.version.outputs.version }}** is recorded as [PENDING] across the marked documentation. Verified/tested ranges remain unchanged.
This PR:
- Updates the compatibility matrix in `COMPATIBILITY.md`
- Marks the new version as pending in the `README.md` badge
- Marks the new version as **⏳ Pending Verification**
## Verification Checklist
- [ ] Check [Gitea changelog](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md) for mail template changes
- [ ] Review diff of official templates: `git diff v${{ steps.version.outputs.current_version }}..v${{ steps.version.outputs.new_version }} -- templates/mail/ services/mailer/`
- [ ] Run `cd tools && go run . preview all` to confirm templates still render
- [ ] Run `cd tools && go test ./...` to verify push-notification data paths
- [ ] Update status from ⏳ to ✅ (compatible) or ❌ (breaking) in COMPATIBILITY.md
- [ ] Update the `Mail Template Changes` and `Breaking?` columns with accurate notes
- [ ] After verification, update `TRACKER:LATEST-VERIFIED` and the English/Chinese `TRACKER:LATEST-TESTED` lines; switch the README badge from pending to tested
## Semantic tracking
Once verified, update the tracked Gitea version:
- [ ] If templates changed, mark the top **Template Release** row `Unreleased` until the fix is tagged; if no change is needed, retain the verified release tag
- [ ] Update the README release status and compatibility matrix to distinguish source fixes from published packages
- [ ] Write `.github/release-notes/vX.Y.Z.md` before tagging; the release workflow uses this file for the published notes
- [ ] Tag a new release when shipping template fixes — `git tag vX.Y.Z && git push origin vX.Y.Z` (the release workflow packages automatically)
labels: compatibility, automated
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- [ ] Review upstream mail templates, mailer data, functions, and translation keys.
- [ ] Run `cd tools && go test ./...` and `go run . preview all`.
- [ ] Record findings in `COMPATIBILITY.md`; update tested ranges and status text only after verification.
- [ ] If template changes are needed, release them separately with reviewed notes and assets.
+11 -1
View File
@@ -34,16 +34,26 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Verify release notes
run: test -s ".github/release-notes/${GITHUB_REF_NAME}.md"
- name: Generate static preview for the archive
working-directory: tools
run: go run . preview all
- name: Package themes/
run: |
VERSION=${GITHUB_REF#refs/tags/}
ARCHIVE="gitea-mail-templates-${VERSION}"
mkdir -p "dist/${ARCHIVE}/docs"
mkdir -p "dist/${ARCHIVE}/docs" "dist/${ARCHIVE}/preview"
cp -r themes LICENSE README.md CONTRIBUTING.md COMPATIBILITY.md "dist/${ARCHIVE}/"
cp docs/README.zh-CN.md docs/CONTRIBUTING.zh-CN.md "dist/${ARCHIVE}/docs/"
cp -r docs/images "dist/${ARCHIVE}/docs/"
cp preview/index.html preview/rendered.js "dist/${ARCHIVE}/preview/"
cd dist
zip -r "${ARCHIVE}.zip" "${ARCHIVE}"
tar -czf "${ARCHIVE}.tar.gz" "${ARCHIVE}"