chore: refresh docs and adapt workflows for Gitea
This commit is contained in:
1 parent
fec3ace600
commit
f4d96de79e
14 files changed
+986
-505
No files matched your search
@@ -1,22 +1,16 @@
|
||||
> **Correction (2026-09-23):** v1.27.2 did not fix every push notification template. Bloom, Ember, and Heritage still used the old commit ID path and can fail to render push notifications on Gitea 1.27.1+. Use v1.27.3 for the fix.
|
||||
# v1.27.2
|
||||
|
||||
FEATURES
|
||||
> **Correction (2026-09-23):** The push-notification fix in this release is incomplete. Bloom, Ember and Heritage still use the old commit ID path and can fail to render push notifications on Gitea 1.27.1+. Use v1.27.3 for the complete fix; see the [compatibility matrix](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/src/branch/main/COMPATIBILITY.md#compatibility-matrix).
|
||||
|
||||
- THEMES (Aurora)
|
||||
- Add `email-text` class to release template paragraphs for consistent typography with the rest of the theme
|
||||
## Changes
|
||||
|
||||
BUGFIXES
|
||||
- Add the `email-text` class to Aurora release paragraphs for consistent typography.
|
||||
- Update push commit paths in seven themes for Gitea 1.27.1 compatibility (`.ID` → `.UserCommit.GitCommit.ID`). The three remaining themes are covered by the correction above.
|
||||
- Replace `rgba()` colors with `#RRGGBBAA` notation across all ten themes.
|
||||
|
||||
- THEMES
|
||||
- Update push commit data paths in seven themes for Gitea 1.27.1 compatibility (`.ID` → `.UserCommit.GitCommit.ID`); see the correction above for the three remaining themes
|
||||
- Replace `rgba()` colors with `#RRGGBBAA` hex notation across all 10 themes
|
||||
## Documentation
|
||||
|
||||
DOCS
|
||||
- Record compatibility for Gitea 1.27.0, 1.27.1 and 1.27.2.
|
||||
- Maintain English and Simplified Chinese README and contributor guides.
|
||||
|
||||
- Track Gitea 1.27.0, 1.27.1, and 1.27.2 compatibility
|
||||
- Keep English and Simplified Chinese README and CONTRIBUTING files
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Full Changelog:** [v1.0.1...v1.27.2](https://gitea.kenanzhu.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,22 +1,20 @@
|
||||
FEATURES
|
||||
# v1.27.3
|
||||
|
||||
- RELEASE
|
||||
- Include English and Simplified Chinese README and CONTRIBUTING files in the release archives
|
||||
- Use reviewed release notes in the publishing workflow
|
||||
This release completes the push-notification fix for Gitea 1.27.1–1.27.3. See the [compatibility matrix](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/src/branch/main/COMPATIBILITY.md#compatibility-matrix) for recommended release combinations.
|
||||
|
||||
BUGFIXES
|
||||
## Fixes
|
||||
|
||||
- THEMES (Bloom, Ember, Heritage)
|
||||
- Fix pull request push notification commit links and abbreviated hashes for Gitea 1.27.1–1.27.3 by reading `.UserCommit.GitCommit.ID`
|
||||
- CI
|
||||
- Add a push notification regression test covering all 10 themes and run Go tests before packaging a release
|
||||
- Fix pull request push-notification links and abbreviated hashes in Bloom, Ember and Heritage by reading `.UserCommit.GitCommit.ID`.
|
||||
- Add a push-notification regression test covering all ten themes and run Go tests before packaging.
|
||||
|
||||
DOCS
|
||||
## Packaging
|
||||
|
||||
- Verify compatibility with Gitea 1.27.3; its mail templates, mailer, and locale files are unchanged from 1.27.2
|
||||
- Correct the compatibility matrix to distinguish the affected v1.27.2 archive from this fixed release
|
||||
- Include English and Simplified Chinese README and contributor guides in release archives.
|
||||
- Use reviewed release notes in the publishing workflow.
|
||||
|
||||
## Documentation
|
||||
|
||||
---
|
||||
- Record compatibility with Gitea 1.27.3, whose mail templates, mailer and locale files are unchanged from 1.27.2.
|
||||
- Distinguish the affected v1.27.2 archive from the complete fix in this release.
|
||||
|
||||
**Full Changelog:** [v1.27.2...v1.27.3](https://gitea.kenanzhu.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,21 +1,18 @@
|
||||
FEATURES
|
||||
# v28.0.0
|
||||
|
||||
- COMPATIBILITY
|
||||
- Add a Gitea 28.0.0-aligned release of all 10 themes and 11 mail types per theme
|
||||
This release targets Gitea 28.0.0 and includes ten themes with eleven mail types each. For earlier Gitea versions, use the packages listed in the [compatibility matrix](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/src/branch/main/COMPATIBILITY.md#compatibility-matrix).
|
||||
|
||||
BUGFIXES
|
||||
## Fixes
|
||||
|
||||
- THEMES (All 10)
|
||||
- Replace the removed `FileSize` function with `FormatByteSize` in release-attachment emails, preventing Gitea 28.0.0 template rendering errors
|
||||
- PREVIEW AND TESTS
|
||||
- Match the preview's file-size function to Gitea 28.0.0 and render release attachments in the example data
|
||||
- Add an all-theme regression test for release attachments and the removed function
|
||||
- Replace the removed `FileSize` function with `FormatByteSize` in release-attachment emails across all ten themes.
|
||||
- Update the preview's file-size function for Gitea 28.0.0 and include release attachments in the example data.
|
||||
- Add an all-theme regression test for release attachments and the removed function.
|
||||
|
||||
DOCS
|
||||
## Documentation
|
||||
|
||||
- Update the English and Simplified Chinese READMEs and compatibility matrix for Gitea 28.0.0
|
||||
- Clarify that v28.0.0 requires Gitea 28.0.0; use v1.27.3 for Gitea 1.25.0–1.27.3
|
||||
- Update both READMEs and the compatibility matrix for Gitea 28.0.0.
|
||||
- Document the Gitea 28.0.0 requirement and direct users of earlier versions to the compatibility matrix.
|
||||
|
||||
---
|
||||
The snapshot-based source architecture now on `main` is separate, unreleased work. It is not included in the existing v28.0.0 archives.
|
||||
|
||||
**Full Changelog:** [v1.27.3...v28.0.0](https://gitea.kenanzhu.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)
|
||||
@@ -0,0 +1,152 @@
|
||||
"""Gitea API operations for the tracker and release workflows (Python stdlib only)."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
from urllib.error import HTTPError
|
||||
from urllib.parse import quote, urlencode, urlsplit
|
||||
from urllib.request import HTTPRedirectHandler, Request, build_opener
|
||||
|
||||
|
||||
class NoRedirects(HTTPRedirectHandler):
|
||||
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
||||
# Never forward an instance token to a redirect destination.
|
||||
return None
|
||||
|
||||
|
||||
class GiteaAPI:
|
||||
def __init__(self, server, repository, token):
|
||||
parsed = urlsplit(server)
|
||||
if parsed.scheme != "https" or not parsed.netloc or parsed.username or parsed.password or parsed.query or parsed.fragment:
|
||||
raise ValueError("GITEA_SERVER_URL must be an HTTPS instance URL")
|
||||
if not re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", repository):
|
||||
raise ValueError("GITEA_REPOSITORY must be owner/repository")
|
||||
if not token:
|
||||
raise ValueError("GITEA_TOKEN is required")
|
||||
self.base = server.rstrip("/") + "/api/v1/repos/" + repository
|
||||
self.token = token
|
||||
self.opener = build_opener(NoRedirects())
|
||||
|
||||
def request(self, method, path, data=None, content_type="application/json", allow_missing=False):
|
||||
if data is not None and not isinstance(data, bytes):
|
||||
data = json.dumps(data).encode("utf-8")
|
||||
req = Request(self.base + path, data=data, method=method, headers={
|
||||
"Authorization": "token " + self.token,
|
||||
"Accept": "application/json",
|
||||
"Content-Type": content_type,
|
||||
"User-Agent": "GiteaMailTemplates-actions",
|
||||
})
|
||||
try:
|
||||
with self.opener.open(req, timeout=120) as response:
|
||||
return json.load(response)
|
||||
except HTTPError as error:
|
||||
status = error.code
|
||||
error.close()
|
||||
if allow_missing and status == 404:
|
||||
return None
|
||||
raise RuntimeError(f"Gitea API {method} {path}: HTTP {status}") from None
|
||||
|
||||
|
||||
def git(*args):
|
||||
return subprocess.check_output(["git", *args], text=True).strip()
|
||||
|
||||
|
||||
def create_pull_request(api, version):
|
||||
if not re.fullmatch(r"\d+\.\d+\.\d+", version):
|
||||
raise ValueError("Expected a stable X.Y.Z upstream version")
|
||||
branch = "track/gitea-" + version
|
||||
title = f"Track Gitea {version} compatibility"
|
||||
changed = git("diff", "--name-only", "HEAD", "--").splitlines()
|
||||
if any(not name.endswith(".md") for name in changed):
|
||||
raise ValueError("Tracker may commit only Markdown changes")
|
||||
if not changed:
|
||||
print("[PASS] No tracked documentation changes")
|
||||
return
|
||||
|
||||
# Repeated scheduled runs can find a branch from an earlier pending PR.
|
||||
# Reuse identical content, but never force-push over a changed branch.
|
||||
remote = git("ls-remote", "--heads", "origin", "refs/heads/" + branch)
|
||||
if remote:
|
||||
git("fetch", "origin", "refs/heads/" + branch)
|
||||
if git("diff", "--name-only", "FETCH_HEAD", "--"):
|
||||
raise ValueError(f"Existing {branch} differs; review it before updating the tracking PR")
|
||||
else:
|
||||
git("switch", "-c", branch)
|
||||
git("add", "--", *changed)
|
||||
git("-c", "user.name=release-bot", "-c", "user.email=release-bot@users.noreply.local",
|
||||
"commit", "-m", f"docs: track Gitea {version} pending verification")
|
||||
git("push", "origin", "HEAD:refs/heads/" + branch)
|
||||
|
||||
page = 1
|
||||
while True:
|
||||
pulls = api.request("GET", f"/pulls?state=open&base_branch=main&limit=50&page={page}")
|
||||
for pull in pulls:
|
||||
if (pull["head"]["ref"] == branch and pull["base"]["ref"] == "main"
|
||||
and pull["head"]["repo"]["full_name"] == pull["base"]["repo"]["full_name"]):
|
||||
print(f"[PASS] Tracking PR already exists: {pull['html_url']}")
|
||||
return
|
||||
if not pulls:
|
||||
break
|
||||
page += 1
|
||||
body = f"""Gitea **{version}** is recorded as [PENDING]. Verified/tested versions remain unchanged.
|
||||
|
||||
- [ ] Review upstream mail templates, mailer data, functions and translation keys.
|
||||
- [ ] Run `go test ./...` and `go run . preview all` from `tools/`.
|
||||
- [ ] Record results in `COMPATIBILITY.md`; update verified status only after testing.
|
||||
- [ ] Release template changes separately with reviewed notes and assets.
|
||||
"""
|
||||
pull = api.request("POST", "/pulls", {"title": title, "head": branch, "base": "main", "body": body})
|
||||
print(f"[PASS] Created tracking PR: {pull['html_url']}")
|
||||
|
||||
|
||||
def publish_release(api, version, root=Path(".")):
|
||||
if not re.fullmatch(r"v\d+\.\d+\.\d+", version):
|
||||
raise ValueError("Expected a stable vX.Y.Z release tag")
|
||||
root = Path(root)
|
||||
lock = json.loads((root / "gitea.lock.json").read_text(encoding="utf-8"))
|
||||
if lock["tag"] != version:
|
||||
raise ValueError("Release tag must match gitea.lock.json")
|
||||
notes = (root / ".github" / "release-notes" / (version + ".md")).read_text(encoding="utf-8")
|
||||
if not notes.strip():
|
||||
raise ValueError("Release notes are empty")
|
||||
assets = [root / "dist" / ("gitea-mail-templates-" + version + ext) for ext in (".zip", ".tar.gz")]
|
||||
for asset in assets:
|
||||
if asset.is_symlink() or not asset.is_file() or not asset.stat().st_size:
|
||||
raise ValueError(f"Missing or invalid release archive: {asset}")
|
||||
existing = api.request("GET", "/releases/tags/" + quote(version, safe=""), allow_missing=True)
|
||||
if existing is not None:
|
||||
raise ValueError("Release already exists; refusing to replace its notes or assets")
|
||||
|
||||
release = api.request("POST", "/releases", {
|
||||
"tag_name": version, "name": version, "body": notes, "draft": True, "prerelease": False,
|
||||
})
|
||||
release_id = int(release["id"])
|
||||
# Gitea accepts raw attachment data with the filename in the query string.
|
||||
# Publish only after both uploads succeed; failures leave a draft for review.
|
||||
for asset in assets:
|
||||
api.request("POST", f"/releases/{release_id}/assets?" + urlencode({"name": asset.name}),
|
||||
asset.read_bytes(), content_type="application/octet-stream")
|
||||
release = api.request("PATCH", f"/releases/{release_id}", {"draft": False})
|
||||
print(f"[PASS] Published {release['html_url']}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("operation", choices=("create-pull-request", "publish-release"))
|
||||
parser.add_argument("--version", required=True)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
api = GiteaAPI(os.environ.get("GITEA_SERVER_URL", ""), os.environ.get("GITEA_REPOSITORY", ""), os.environ.get("GITEA_TOKEN", ""))
|
||||
if args.operation == "create-pull-request":
|
||||
create_pull_request(api, args.version)
|
||||
else:
|
||||
publish_release(api, args.version)
|
||||
except (ValueError, KeyError, OSError, RuntimeError, subprocess.CalledProcessError) as error:
|
||||
parser.exit(1, f"[FAIL] {error}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,160 @@
|
||||
"""Offline Gitea API and disposable-Git workflow regression tests."""
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import Mock
|
||||
from urllib.error import HTTPError
|
||||
|
||||
|
||||
SPEC = importlib.util.spec_from_file_location("gitea_actions", Path(__file__).with_name("gitea_actions.py"))
|
||||
ACTIONS = importlib.util.module_from_spec(SPEC)
|
||||
SPEC.loader.exec_module(ACTIONS)
|
||||
|
||||
|
||||
class APITests(unittest.TestCase):
|
||||
def test_instance_url_token_and_raw_asset_request(self):
|
||||
api = ACTIONS.GiteaAPI("https://git.example/subpath/", "owner/repo", "test-token")
|
||||
response = Mock()
|
||||
response.__enter__ = Mock(return_value=response)
|
||||
response.__exit__ = Mock(return_value=False)
|
||||
response.read.return_value = b'{"id": 1}'
|
||||
api.opener = Mock()
|
||||
api.opener.open.return_value = response
|
||||
self.assertEqual({"id": 1}, api.request("POST", "/releases/1/assets?name=test.zip", b"archive", "application/octet-stream"))
|
||||
request = api.opener.open.call_args.args[0]
|
||||
self.assertEqual("https://git.example/subpath/api/v1/repos/owner/repo/releases/1/assets?name=test.zip", request.full_url)
|
||||
self.assertEqual("token test-token", request.get_header("Authorization"))
|
||||
self.assertEqual(b"archive", request.data)
|
||||
self.assertEqual("application/octet-stream", request.get_header("Content-type"))
|
||||
|
||||
def test_only_explicit_404_is_missing_and_redirects_are_refused(self):
|
||||
api = ACTIONS.GiteaAPI("https://git.example", "owner/repo", "test-token")
|
||||
api.opener = Mock()
|
||||
for status in (401, 403, 500, 302):
|
||||
api.opener.open.side_effect = HTTPError(api.base, status, "error", {}, None)
|
||||
with self.assertRaisesRegex(RuntimeError, f"HTTP {status}"):
|
||||
api.request("GET", "/releases/tags/v28.0.0", allow_missing=True)
|
||||
api.opener.open.side_effect = HTTPError(api.base, 404, "missing", {}, None)
|
||||
self.assertIsNone(api.request("GET", "/releases/tags/v28.0.0", allow_missing=True))
|
||||
self.assertIsNone(ACTIONS.NoRedirects().redirect_request(None, None, 302, "", {}, "https://elsewhere.example"))
|
||||
|
||||
def test_rejects_invalid_configuration(self):
|
||||
for server, repository, token in [("http://git.example", "owner/repo", "x"),
|
||||
("https://user:password@git.example", "owner/repo", "x"),
|
||||
("https://git.example", "../owner/repo", "x"), ("https://git.example", "owner/repo", "")]:
|
||||
with self.assertRaises(ValueError):
|
||||
ACTIONS.GiteaAPI(server, repository, token)
|
||||
|
||||
|
||||
class ReleaseTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.root = Path(self.temp.name)
|
||||
(self.root / "gitea.lock.json").write_text(json.dumps({"tag": "v28.0.0"}))
|
||||
notes = self.root / ".github/release-notes/v28.0.0.md"
|
||||
notes.parent.mkdir(parents=True)
|
||||
notes.write_text("Reviewed notes", encoding="utf-8")
|
||||
(self.root / "dist").mkdir()
|
||||
for ext in (".zip", ".tar.gz"):
|
||||
(self.root / "dist" / ("gitea-mail-templates-v28.0.0" + ext)).write_bytes(b"archive")
|
||||
|
||||
def test_existing_release_is_not_modified(self):
|
||||
api = Mock()
|
||||
api.request.return_value = {"id": 5}
|
||||
with self.assertRaisesRegex(ValueError, "already exists"):
|
||||
ACTIONS.publish_release(api, "v28.0.0", self.root)
|
||||
self.assertEqual(["GET"], [call.args[0] for call in api.request.call_args_list])
|
||||
|
||||
def test_publish_only_after_both_uploads_succeed(self):
|
||||
api = Mock()
|
||||
api.request.side_effect = [None, {"id": 5}, {"id": 6}, {"id": 7}, {"html_url": "https://git.example/release"}]
|
||||
ACTIONS.publish_release(api, "v28.0.0", self.root)
|
||||
calls = api.request.call_args_list
|
||||
self.assertEqual(["GET", "POST", "POST", "POST", "PATCH"], [c.args[0] for c in calls])
|
||||
self.assertTrue(calls[1].args[2]["draft"])
|
||||
self.assertEqual("Reviewed notes", calls[1].args[2]["body"])
|
||||
self.assertEqual("/releases/5/assets?name=gitea-mail-templates-v28.0.0.zip", calls[2].args[1])
|
||||
self.assertEqual("/releases/5/assets?name=gitea-mail-templates-v28.0.0.tar.gz", calls[3].args[1])
|
||||
self.assertEqual({"draft": False}, calls[4].args[2])
|
||||
|
||||
def test_failed_upload_leaves_draft_unpublished(self):
|
||||
api = Mock()
|
||||
api.request.side_effect = [None, {"id": 5}, RuntimeError("upload failed")]
|
||||
with self.assertRaisesRegex(RuntimeError, "upload failed"):
|
||||
ACTIONS.publish_release(api, "v28.0.0", self.root)
|
||||
self.assertNotIn("PATCH", [c.args[0] for c in api.request.call_args_list])
|
||||
|
||||
def test_bad_version_or_missing_archive_fails_before_api_call(self):
|
||||
api = Mock()
|
||||
for version in ("v28.0.1", "v28.0.0-rc1", "../../x"):
|
||||
with self.assertRaises(ValueError):
|
||||
ACTIONS.publish_release(api, version, self.root)
|
||||
(self.root / "dist/gitea-mail-templates-v28.0.0.zip").unlink()
|
||||
with self.assertRaisesRegex(ValueError, "archive"):
|
||||
ACTIONS.publish_release(api, "v28.0.0", self.root)
|
||||
api.request.assert_not_called()
|
||||
|
||||
|
||||
class PullRequestTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.root = Path(self.temp.name)
|
||||
self.previous = Path.cwd()
|
||||
os.chdir(self.root)
|
||||
self.addCleanup(os.chdir, self.previous)
|
||||
subprocess.run(["git", "init", "--bare", "remote.git"], check=True, capture_output=True)
|
||||
subprocess.run(["git", "init", "-b", "main", "work"], check=True, capture_output=True)
|
||||
os.chdir(self.root / "work")
|
||||
ACTIONS.git("config", "user.name", "test")
|
||||
ACTIONS.git("config", "user.email", "test@example.invalid")
|
||||
ACTIONS.git("remote", "add", "origin", str(self.root / "remote.git"))
|
||||
Path("README.md").write_text("Baseline\n")
|
||||
Path("source.txt").write_text("Source\n")
|
||||
ACTIONS.git("add", ".")
|
||||
ACTIONS.git("commit", "-m", "baseline")
|
||||
ACTIONS.git("push", "origin", "main")
|
||||
Path("README.md").write_text("Pending 28.1.0\n")
|
||||
|
||||
def test_create_then_reuse_branch_and_paginated_pr(self):
|
||||
api = Mock()
|
||||
api.request.side_effect = [[], {"html_url": "https://git.example/pulls/1"}]
|
||||
ACTIONS.create_pull_request(api, "28.1.0")
|
||||
self.assertEqual("track/gitea-28.1.0", ACTIONS.git("branch", "--show-current"))
|
||||
payload = api.request.call_args.args[2]
|
||||
self.assertEqual("main", payload["base"])
|
||||
self.assertEqual("track/gitea-28.1.0", payload["head"])
|
||||
self.assertIn("[PENDING]", payload["body"])
|
||||
original_head = ACTIONS.git("rev-parse", "HEAD")
|
||||
ACTIONS.git("switch", "main")
|
||||
Path("README.md").write_text("Pending 28.1.0\n")
|
||||
api.reset_mock()
|
||||
api.request.side_effect = [[{"head": {"ref": "unrelated"}}], [{
|
||||
"head": {"ref": "track/gitea-28.1.0", "repo": {"full_name": "owner/repo"}},
|
||||
"base": {"ref": "main", "repo": {"full_name": "owner/repo"}},
|
||||
"html_url": "https://git.example/pulls/1",
|
||||
}]]
|
||||
ACTIONS.create_pull_request(api, "28.1.0")
|
||||
self.assertEqual(["GET", "GET"], [c.args[0] for c in api.request.call_args_list])
|
||||
self.assertEqual(original_head, ACTIONS.git("rev-parse", "FETCH_HEAD"))
|
||||
Path("README.md").write_text("Different pending content\n")
|
||||
with self.assertRaisesRegex(ValueError, "Existing.*differs"):
|
||||
ACTIONS.create_pull_request(api, "28.1.0")
|
||||
|
||||
def test_non_documentation_change_is_not_committed(self):
|
||||
Path("source.txt").write_text("Changed source\n")
|
||||
api = Mock()
|
||||
with self.assertRaisesRegex(ValueError, "only Markdown"):
|
||||
ACTIONS.create_pull_request(api, "28.1.0")
|
||||
api.request.assert_not_called()
|
||||
self.assertEqual("baseline", ACTIONS.git("log", "-1", "--format=%s"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -12,12 +12,15 @@ on:
|
||||
jobs:
|
||||
track:
|
||||
name: Track Gitea Release
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: linux-amd64-docker-small
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
@@ -31,20 +34,14 @@ jobs:
|
||||
run: python -B .github/scripts/track_gitea_release.py
|
||||
env:
|
||||
GITEA_VERSION: ${{ github.event.inputs.version }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Optional GitHub token for upstream API rate limits; never use the Gitea job token.
|
||||
GITHUB_TOKEN: ${{ secrets.UPSTREAM_GITHUB_TOKEN }}
|
||||
|
||||
- name: Create Pull Request
|
||||
if: steps.version.outputs.changed == 'true'
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
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.version }}** is recorded as [PENDING] across the marked documentation. Verified/tested ranges remain unchanged.
|
||||
|
||||
- [ ] 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.
|
||||
run: python -B .github/scripts/gitea_actions.py create-pull-request --version "$UPSTREAM_VERSION"
|
||||
env:
|
||||
UPSTREAM_VERSION: ${{ steps.version.outputs.version }}
|
||||
GITEA_SERVER_URL: ${{ github.server_url }}
|
||||
GITEA_REPOSITORY: ${{ github.repository }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
validate:
|
||||
name: Validate Templates
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: linux-amd64-docker-small
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -41,13 +41,13 @@ jobs:
|
||||
name: Package & Release
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
needs: validate
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: linux-amd64-docker-small
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITEA_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
token: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
@@ -79,28 +79,25 @@ jobs:
|
||||
TEMPLATE_RELEASE: ${{ github.ref_name }}
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
files: |
|
||||
dist/*.zip
|
||||
dist/*.tar.gz
|
||||
fail_on_unmatched_files: true
|
||||
body_path: .github/release-notes/${{ github.ref_name }}.md
|
||||
run: python -B .github/scripts/gitea_actions.py publish-release --version "$TEMPLATE_RELEASE"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
TEMPLATE_RELEASE: ${{ github.ref_name }}
|
||||
GITEA_SERVER_URL: ${{ github.server_url }}
|
||||
GITEA_REPOSITORY: ${{ github.repository }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
sync-release-docs:
|
||||
name: Update Latest Release Documentation
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
needs: package
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: linux-amd64-docker-small
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ secrets.GITEA_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
token: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
|
||||
+28
-15
@@ -1,11 +1,13 @@
|
||||
# Gitea Compatibility
|
||||
<!-- DOC-TAGS: {"TRACKER":["LATEST-VERIFIED","VERSION-MAP","HISTORY"]} -->
|
||||
|
||||
This document tracks the compatibility between **Gitea Mail Templates** releases and **Gitea** versions.
|
||||
This document lists supported release combinations, known limitations and the checks used to assess compatibility.
|
||||
|
||||
[Project overview](README.md) · [Contributor guide](CONTRIBUTING.md) · [简体中文使用说明](docs/README.zh-CN.md)
|
||||
|
||||
## Compatibility Matrix
|
||||
|
||||
Choose by your **Gitea version**, not by the highest template tag. [PASS] means a documented compatible combination; [PENDING] has not been verified. Legacy [PASS] entries retain the project's earlier compatibility assessment and were not re-tested on every patch release during this documentation update.
|
||||
Select a template release for the Gitea version you run. `[PASS]` records a compatible combination; `[PENDING]` means verification is incomplete. Legacy entries reflect the project's recorded compatibility assessments rather than a fresh test of every patch release.
|
||||
|
||||
<!-- TRACKER:VERSION-MAP -->
|
||||
| Gitea version | Recommended template release | Status | Notes |
|
||||
@@ -33,21 +35,23 @@ v1.0.1 retains the pre-1.27 push-commit fields used by the listed Gitea 1.25/1.2
|
||||
|
||||
## Snapshot-Driven Source Status
|
||||
|
||||
The refactor on `main` is **unreleased**. It locks Gitea **v28.0.0**, commit `15b8a5805adf57c5189602008d38cccfd3c795e0`, with 13 mail files (11 entrypoints and 2 shared partials) and 28 official locale files. New source architecture supports Gitea 28+; it does not replace historical release assets or change recommendations in the published matrix.
|
||||
The source architecture on `main` is **unreleased**. Its lock pins Gitea **v28.0.0**, commit `15b8a5805adf57c5189602008d38cccfd3c795e0`, with 13 mail files (11 entrypoints and 2 shared partials) and 28 locale files. It targets Gitea 28 and later, with each new snapshot requiring review. Historical archives retain the compatibility recorded above.
|
||||
|
||||
Theme sources contain CSS and metadata only. A shared framework organizes official mail values/translations into reusable branding, action/fallback and footer controls. Its single alignment layer preserves notification branches, subjects and functional link targets while allowing presentation changes. Only generated `gitea.lock.json` is committed; immutable official inputs are downloaded to ignored `build/upstream/`. Builds fail on checksum, English-key, adapter-reference or unreviewed action-anchor changes. New mail types require framework alignment and fixtures.
|
||||
Themes contain CSS and metadata. The shared framework adapts official templates into reusable headers, action buttons, fallback links and footers while preserving notification conditions, subjects and functional URLs. Official inputs are downloaded to `build/upstream/` and verified against the committed `gitea.lock.json`. Builds reject mismatched checksums, missing English keys, changed adapter references and unreviewed action anchors. New mail types require framework support and fixtures.
|
||||
|
||||
### Translation Behavior
|
||||
|
||||
Missing translations in other languages follow the official English fallback and are reported as `[FALLBACK]`. Gitea v28.0.0's Polish `mail.team_invite.text_1` starts with malformed `%[1]z…` instead of `%[1]s`; preview preserves this official defect and reports `[UPSTREAM-WARN]`. The exception matches the exact source text; other formatting defects fail rendering.
|
||||
|
||||
Gitea 28.1.0 remains [PENDING]. Updating pending documentation does not synchronize the snapshot or verify a new version.
|
||||
### Validation Scope
|
||||
|
||||
`upstream prepare` requires the committed root lock and creates only an absent cache; `upstream verify` requires both lock and cache and performs no download. Missing locks are not inferred from cache or latest releases. Explicit `upstream sync --tag vX.Y.Z` can initialize or replace the lock, but does not update this matrix or certify compatibility. See [command usage and cache recovery](CONTRIBUTING.md#official-snapshot-updates).
|
||||
Source validation covers rendering and notification parity across all themes and languages. Optional browser checks cover static and HTTP previews, language switching and mobile layouts. An isolated Gitea smoke test checks template loading and captures a password-reset email. These checks do not establish rendering compatibility with Gmail, Outlook or Apple Mail; test those clients for your deployment. The release workflow does not automatically run the optional browser or real-Gitea suites.
|
||||
|
||||
Current-source validation includes all-theme/all-language rendering and notification parity, browser checks for static/HTTP language switching and mobile layouts, and an isolated Gitea 28.0.0 template-loading/password-reset mail smoke test. This does not certify rendering in Gmail, Outlook or Apple Mail; those clients still require deployment-specific testing. The optional real-Gitea and browser suites are not automatically run by the current release workflow.
|
||||
Snapshot preparation, cache verification and version updates are separate operations. `upstream prepare` uses the root lock to create an absent cache; `upstream verify` checks an existing cache offline. `upstream sync --tag vX.Y.Z` explicitly replaces the snapshot and lock. A successful sync does not certify compatibility or update this matrix. See [command usage and cache recovery](CONTRIBUTING.md#official-snapshot-updates).
|
||||
|
||||
## Versioning and Known Exceptions
|
||||
|
||||
Release tags name actual downloadable packages. A matching version is useful, but it is not a compatibility guarantee: v1.27.2 has a known defect, and there is no v1.27.1 template tag. Use the recommended package in the matrix; do not infer support from a tag number or from the current `main` branch.
|
||||
Release tags identify downloadable packages. Use the matrix to select a supported combination: v1.27.2 has a known defect despite its matching version number, and there is no v1.27.1 template tag. Changes on `main` become part of a release only when a new tag and archive are published.
|
||||
|
||||
- Gitea 1.27.0 changed the push-to-PR commit data shape. Gitea 1.27.1 fixed its **bundled** mail template, but custom overrides still need the new `.UserCommit.GitCommit` path. v1.27.2 updated seven themes; v1.27.3 completed the remaining three. Older v1.0.x templates use the pre-1.27 path. See the [upstream regression report](https://github.com/go-gitea/gitea/issues/38469), [upstream fix](https://github.com/go-gitea/gitea/pull/38467), and [v1.27.2 correction](.github/release-notes/v1.27.2.md).
|
||||
- Gitea 28.0.0 removed the mail-template `FileSize` function in favor of `FormatByteSize` ([mail function map](https://raw.githubusercontent.com/go-gitea/gitea/v28.0.0/modules/templates/mail.go)). v28.0.0 uses the new function; older template releases can fail when rendering release attachments. Conversely, v28.0.0 is not a drop-in replacement for earlier Gitea mail contexts.
|
||||
@@ -86,7 +90,7 @@ This table describes changes in **Gitea**, not fixes in this template repository
|
||||
|
||||
## Template Variable Reference
|
||||
|
||||
The downloaded official inputs define mail variables and calls; themes do not add business variables. The table below summarizes preview contexts. The locked upstream commit, shared alignment layer and strict fixture rendering are authoritative.
|
||||
Official templates define each mail context. The tables below summarize functions and example data relevant to development; they are not a complete API reference. Check the locked official sources and framework adapter when changing a template or fixture.
|
||||
|
||||
### Relevant Template Functions
|
||||
|
||||
@@ -126,7 +130,7 @@ The downloaded official inputs define mail variables and calls; themes do not ad
|
||||
| `repo/issue/assigned` | `Subject`, `Doer`, `Issue`, `Link`, `IsPull`, `CanReply` |
|
||||
| `repo/issue/default` | `Doer`, `Issue`, `Link`, `Body`, `ActionName`, `Comment`, `IsPull`, `IsMention`, `ReviewComments`, `CanReply` |
|
||||
|
||||
> [WARN] **`.DisplayName`** is not available in collaborator, transfer, release, workflow_run, assigned, and default templates — do not reference it.
|
||||
`.DisplayName` is available in the authentication mail contexts. Collaborator, transfer, release, workflow, assignment and issue-update templates use the context-specific fields listed above.
|
||||
|
||||
### Translation Keys
|
||||
|
||||
@@ -142,11 +146,20 @@ Official templates reference `mail.*` keys and `actions.runs.attempt`. AST-based
|
||||
|
||||
## Version Tracking
|
||||
|
||||
The [tracker workflow](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/src/branch/main/.github/workflows/gitea-tracker.yml) scans all repository Markdown files. A participating document declares its subject/content pairs in a `DOC-TAGS` JSON comment, then encloses each managed body between `<!-- TRACKER:CONTENT -->` and `<!-- /TRACKER:CONTENT -->` (or `RELEASE` equivalents). Only the first block for a repeated pair in a document is processed. `TRACKER:VERSION-MAP` and `TRACKER:HISTORY` add pending rows; `TRACKER:UPSTREAM` updates upstream versions and status; `TRACKER:BADGE` retains the last tested version. On template publication, the [release workflow](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/src/branch/main/.github/workflows/release.yml) updates `RELEASE:HEADER`, `RELEASE:SUMMARY`, and `RELEASE:CURRENT` labels; their links stay fixed at `/releases/latest`, and published tags remain unchanged. `TRACKER:LATEST-TESTED` and `TRACKER:LATEST-VERIFIED` are manual-only and change only after verification. The script rejects undeclared, unknown, or unclosed blocks and missing declarations. Actions execution and write permissions have not been verified on this Gitea host; until then, check [upstream Gitea releases](https://github.com/go-gitea/gitea/releases) and published assets manually. Publish a new template tag only when template content changes (see [Versioning and Known Exceptions](#versioning-and-known-exceptions)).
|
||||
The [tracker workflow](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/src/branch/main/.github/workflows/gitea-tracker.yml) records upstream releases as pending. Snapshot updates and compatibility verification require a separate review.
|
||||
|
||||
Participating Markdown files declare managed subject/content pairs in a `DOC-TAGS` JSON comment. Each body is enclosed by `<!-- TRACKER:CONTENT -->` and `<!-- /TRACKER:CONTENT -->`, or the corresponding `RELEASE` pair. Only the first occurrence of a repeated pair in a document is processed. Undeclared, unknown or unclosed blocks, and missing declared blocks, cause validation to fail.
|
||||
|
||||
| Managed blocks | Update policy |
|
||||
|---|---|
|
||||
| `TRACKER:VERSION-MAP`, `TRACKER:HISTORY` | Add pending rows for new upstream releases |
|
||||
| `TRACKER:UPSTREAM` | Update the upstream version and pending status |
|
||||
| `TRACKER:BADGE` | Update the upstream version while retaining the last tested version |
|
||||
| `TRACKER:LATEST-TESTED`, `TRACKER:LATEST-VERIFIED` | Updated manually after verification |
|
||||
| `RELEASE:HEADER`, `RELEASE:SUMMARY`, `RELEASE:CURRENT` | Updated by the release workflow after publication; archive labels are prepared during packaging |
|
||||
|
||||
The [release workflow](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/src/branch/main/.github/workflows/release.yml) keeps release links at `/releases/latest` and leaves published tags unchanged. Actions execution and write permissions have not been verified on the configured Gitea host. Until confirmed, check [upstream releases](https://github.com/go-gitea/gitea/releases) and published assets manually. New template tags are published when template content changes; see [versioning and known exceptions](#versioning-and-known-exceptions).
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
If you find a compatibility problem with a specific Gitea version:
|
||||
|
||||
1. Check the [Gitea changelog](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md) for recent mail template changes
|
||||
2. Open an issue with: your Gitea version, which template, and the error
|
||||
Open an issue with the Gitea version, template release or source commit, affected theme and mail type, language, reproduction steps and error output. Include the mail client for display problems. See the [reporting guide](CONTRIBUTING.md#reporting-problems) for source-build diagnostics.
|
||||
+163
-83
@@ -1,79 +1,130 @@
|
||||
# Contributing to Gitea Mail Templates
|
||||
|
||||
## Adding a Theme
|
||||
[简体中文](docs/CONTRIBUTING.zh-CN.md) · [Project overview](README.md) · [Compatibility](COMPATIBILITY.md)
|
||||
|
||||
1. Run `cd tools && go run . create <name>` to create a framework-backed theme.
|
||||
2. Edit `themes/<name>/theme.json` and `theme.css`.
|
||||
3. Run `go run . upstream prepare`, `go test ./...` and `go run . preview all` from `tools/`.
|
||||
4. Check desktop/mobile previews in English, Simplified Chinese and another official language; submit screenshots with the PR.
|
||||
Contributions to themes, tooling, tests, documentation and translations are welcome. This guide covers the current source architecture; installation and release selection are described in the [README](README.md#installation).
|
||||
|
||||
Theme names use lowercase letters, digits and hyphens, starting with a letter. Themes contain only `theme.json` and `theme.css`. New themes default to `framed` with the `standard` layout; `layout` selects a structural preset from the shared framework. The optional `shared` mode remains CSS-only and does not add framework controls.
|
||||
## Local Development
|
||||
|
||||
Shared header, action button, fallback URL, sidebar and footer controls live in `framework/mail/base/`. Structural presets live in `framework/layouts/`; they are framework code, not theme-owned mail templates. `tools/builder/framework.go` is the single alignment layer for official primary-action values and translations. Notification branches, subjects, attachments and contextual links come from downloaded official templates. Do not copy business logic into a theme.
|
||||
|
||||
## Design Guidelines
|
||||
|
||||
- Theme sources define presentation only; the shared framework organizes official mail values and translations into reusable controls.
|
||||
- Use email-compatible CSS in theme sources and presentation markup in the framework. Theme CSS cannot load external resources, generate text or hide official content; the framework's instance-hosted logo is an intentional exception to external-image avoidance.
|
||||
- The fragment validator permits tables, table rows/cells, divs and spans with presentation attributes. Review desktop and 390px mobile layouts.
|
||||
- Test Gmail, Outlook and Apple Mail where available. Browser preview does not simulate every mail client's CSS support.
|
||||
- Preserve the original theme's colors, fonts, borders, header treatment, button/fallback controls and layout. Do not replace established designs with generic cards or invented decorations.
|
||||
- Gallery screenshots must be PNG, at most 50 KiB each; 10–20 KiB is preferred. Capture the current source build with the floating inspector closed.
|
||||
|
||||
## Official Snapshot Updates
|
||||
|
||||
Only the tool-generated `gitea.lock.json` is committed: stable Gitea 28+ tag, immutable commit and file checksums. Official templates, locale JSON files, favicon, license and adapter reference sources are downloaded to ignored `build/upstream/`. Do not maintain copies in the source repository.
|
||||
|
||||
### Command Reference
|
||||
|
||||
Run the following commands from `tools/`. All three subcommands accept `--root <repository-root>` (default: `..`, relative to the working directory); place this flag after the subcommand. Paths containing spaces must be quoted.
|
||||
|
||||
```powershell
|
||||
# From tools/, with an explicit repository root:
|
||||
go run . upstream verify --root "D:\Work\Development\WebSites\GiteaMailTemplates"
|
||||
```
|
||||
|
||||
| Command | Purpose | Network and writes |
|
||||
|---|---|---|
|
||||
| `go run . upstream prepare` | Read the repository lock and prepare its exact inputs | If no cache exists, download files by locked commit, validate SHA-256 and create `build/upstream/`; otherwise verify the existing cache offline. Never changes the root lock. |
|
||||
| `go run . upstream verify` | Audit the existing cache against the root lock | Offline, read-only; does not download files. Reports `[PASS]` and non-English missing-key `[FALLBACK]` lists. |
|
||||
| `go run . upstream sync --tag vX.Y.Z` | Explicitly select an upstream version | Resolve the tag through the GitHub API, download by resolved commit and validate the snapshot; replace the cache and generate `gitea.lock.json`. Requires a stable `vX.Y.Z` tag with major version 28 or later. |
|
||||
|
||||
There is no implicit `latest`, local Gitea checkout input, token flag or authentication environment-variable support in these commands. Downloads use `api.github.com` (`sync`) and `raw.githubusercontent.com` (`sync`/first `prepare`); network errors and API rate limits are failures, not permission to change versions. Go may separately need network access for its toolchain/modules, even when snapshot verification itself is offline.
|
||||
|
||||
### Existing Clone and Offline Use
|
||||
Use **Go 1.24 or later**. From the repository root, prepare the dependencies and locked official inputs, then run the checks and generate the preview:
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
go mod download
|
||||
go run . upstream prepare
|
||||
go run . upstream verify
|
||||
go test ./...
|
||||
go run . preview all
|
||||
```
|
||||
|
||||
`build all`, `preview all` and `dev` invoke preparation automatically. They still require the root lock. A complete verified cache and already installed Go dependencies/toolchain allow offline builds. `verify` checks official inputs, adapter reference hashes and official English keys; framework-added keys/action anchors are checked by build and rendering, so `verify` alone is not a compatibility certification.
|
||||
Open `preview/index.html` in a browser, or run `go run . dev` from `tools/` and visit [http://127.0.0.1:3456](http://127.0.0.1:3456) for live reload. The development server watches themes, the framework, the lock/cache and preview fixtures.
|
||||
|
||||
The CLI uses urfave/cli and the x/net HTML parser. Python 3.11 or later is used by the documentation and packaging checks. Node.js and the dependencies in `tools/qa` are needed only for browser QA.
|
||||
|
||||
### Common Commands
|
||||
|
||||
Run these commands from `tools/`. Place flags before positional arguments.
|
||||
|
||||
| Command | Result |
|
||||
|---|---|
|
||||
| `go run . list` | List available themes |
|
||||
| `go run . create my-theme` | Create theme metadata and CSS |
|
||||
| `go run . build my-theme` | Generate one theme's installable templates |
|
||||
| `go run . build all` | Generate every theme |
|
||||
| `go run . preview all` | Build every theme and render all official languages |
|
||||
| `go run . dev` | Start the development server on port 3456 |
|
||||
| `go run . dev --port 3457` | Use a different local port |
|
||||
| `go run . delete my-theme` | Remove the named theme's source directory |
|
||||
|
||||
`build` writes to `build/themes/<name>/mail/` and records file and source hashes in `build.json`. `preview` also builds the templates, then writes `preview/rendered.js` and `preview/rendered/<locale>.js`. These generated files and the downloaded inputs are ignored by Git. Keep them out of contributions.
|
||||
|
||||
## Adding a Theme
|
||||
|
||||
1. Run `go run . create my-theme` from `tools/`.
|
||||
2. Edit `themes/my-theme/theme.json` and `theme.css`.
|
||||
3. Run `go test ./...` and `go run . preview all` from `tools/`.
|
||||
4. Check desktop and mobile layouts in English, Simplified Chinese and at least one other official language. Include screenshots with the pull request.
|
||||
|
||||
Theme names start with a lowercase letter and may contain lowercase letters, digits and hyphens. A theme directory contains only `theme.json` and `theme.css`.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-theme",
|
||||
"description": "A short description of the theme",
|
||||
"mode": "framed",
|
||||
"layout": "standard"
|
||||
}
|
||||
```
|
||||
|
||||
| Mode | Generated presentation |
|
||||
|---|---|
|
||||
| `framed` | Shared controls and a framework layout, styled with the theme's CSS. New themes use this mode with the `standard` layout. |
|
||||
| `shared` | CSS in the official head partial and the official footer partial; no additional framework controls or per-mail overrides. |
|
||||
|
||||
### Shared Framework
|
||||
|
||||
Headers, action buttons, fallback links, sidebars and footers live in `framework/mail/base/`. Layout presets live in `framework/layouts/`; the optional `layout` field selects a preset for framed themes. Colors, fonts and spacing belong in theme CSS.
|
||||
|
||||
`tools/builder/framework.go` adapts official action values and translation keys for the shared controls. Official templates retain responsibility for notification conditions, subjects, attachments and contextual links. Changes to controls or layout structure belong in the framework so all themes use the same adaptation logic.
|
||||
|
||||
Layout fragments must form balanced presentation markup. `__HEADER__` inserts the shared header, `__MAIL_TYPE__` expands to the discovered mail ID, and `__SIDEBAR__` inserts the shared sidebar in footer fragments. Deployment logos use `{{AppUrl}}assets/img/favicon.png`; generated preview data embeds the downloaded icon for offline display.
|
||||
|
||||
## Design Guidelines
|
||||
|
||||
- Use email-compatible CSS. Theme CSS must not load external resources, generate text or hide official content.
|
||||
- Use presentation markup for layout fragments. The validator accepts `table`, `tbody`, `tr`, `td`, `div` and `span` with supported presentation attributes.
|
||||
- When editing an existing theme, preserve its visual identity: palette, typography, borders, header, buttons and layout.
|
||||
- Check desktop and 390px mobile previews, including long text and URLs. Test Gmail, Outlook and Apple Mail where available; the browser preview does not emulate mail clients.
|
||||
- Keep gallery images in PNG format, at most 50 KiB each; 10–20 KiB is preferred. Follow the [capture guide](docs/images/README.md) for consistent images.
|
||||
|
||||
## Official Snapshot Updates
|
||||
|
||||
`gitea.lock.json` records a stable Gitea 28+ tag, its commit and per-file SHA-256 hashes. Official mail templates, locale catalogs, the favicon, license and reviewed adapter references are downloaded into `build/upstream/`. Only the generated root lock is committed; official files are not maintained in the source tree.
|
||||
|
||||
### Command Reference
|
||||
|
||||
Run from `tools/`. Each upstream subcommand accepts `--root <repository-root>`, defaulting to `..` relative to the working directory. Place the flag after the subcommand and quote paths containing spaces:
|
||||
|
||||
```powershell
|
||||
go run . upstream verify --root "C:\Projects\GiteaMailTemplates"
|
||||
```
|
||||
|
||||
| Command | Behavior |
|
||||
|---|---|
|
||||
| `go run . upstream prepare` | Read the root lock. Download and validate its exact inputs if the cache is absent; otherwise verify the existing cache offline. Leaves the root lock unchanged. |
|
||||
| `go run . upstream verify` | Check the existing cache against the root lock, offline and read-only. Reports `[PASS]` and lists non-English missing keys as `[FALLBACK]`. |
|
||||
| `go run . upstream sync --tag vX.Y.Z` | Resolve an explicit stable Gitea 28+ tag through the GitHub API, download and validate its files, then replace the cache and generate the root lock. |
|
||||
|
||||
`sync` uses `api.github.com`; file downloads use `raw.githubusercontent.com`. These commands do not accept a local Gitea checkout, authentication tokens or an implicit `latest` version. Network errors and API rate limits stop the operation. Go may separately need network access to download its toolchain or modules.
|
||||
|
||||
### Existing Clone and Offline Use
|
||||
|
||||
`build`, `preview` and `dev` prepare inputs automatically. They require the committed root lock and validate cached files before use. Once the cache, Go toolchain and dependencies are available, builds can run offline.
|
||||
|
||||
Use `upstream verify` to check the cache independently. It validates official file hashes, reviewed adapter references and official template keys in the English catalog. Build and rendering checks also cover framework translation keys and primary-action anchors, so cache verification is only one part of compatibility testing.
|
||||
|
||||
### Missing Lock and Explicit Version Updates
|
||||
|
||||
If `gitea.lock.json` is missing, `prepare`, `verify`, build and preview fail when opening it—even if `build/upstream/lock.json` remains. The cache lock is not a substitute. Restore the tracked root lock for a normal clone. For intentional initialization, `sync` does not require a prior root lock:
|
||||
For an existing clone, restore the tracked `gitea.lock.json` if it is missing. The copy at `build/upstream/lock.json` cannot replace it. When intentionally initializing the lock, run:
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
# Current source baseline; explicit initialization, not a release operation:
|
||||
go run . upstream sync --tag v28.0.0
|
||||
go run . upstream verify
|
||||
go test ./...
|
||||
go run . preview all
|
||||
```
|
||||
|
||||
To review another version, replace the tag explicitly (for example, `v28.1.0`, still [PENDING] here). Review the generated lock diff, align the shared framework and fixtures, run all checks and the matching-instance smoke test, then update compatibility documentation. `sync` does not build themes, update Markdown, create Git tags, commit, push or publish a release. It must not be run merely to fix a missing cache.
|
||||
To review a different version, specify its tag explicitly. Review the lock diff, update the framework adapter and fixtures as needed, and complete the checks and matching-instance smoke test before updating compatibility records. `sync` changes the cache and lock only; documentation and release publication are separate steps. Use `prepare` for a missing cache.
|
||||
|
||||
Changed translation or mail-renderer reference hashes block synchronization until the Go adapter is reviewed; downloading a newer version is not enough to approve it. Official English must contain all official template keys; builds additionally validate framework keys. Other languages fall back to English. Validation/network failures before cache replacement leave existing inputs unchanged. Cache replacement and writing the root lock are separate operations: if a filesystem failure leaves them inconsistent, subsequent verification fails; inspect both before retrying.
|
||||
Changes to the reviewed translation or mail-renderer sources require an adapter review before their reference hashes can be updated. Official English must contain all referenced keys; other languages use English fallback. New mail types require framework alignment and fixtures in `tools/data/templates_config.json`, which supplies preview metadata and example contexts. Keep integer values as integers in JSON fixtures for Go formatting.
|
||||
|
||||
Network or validation failures before cache replacement leave existing inputs unchanged. Cache replacement and root-lock writing are separate operations; if a filesystem error interrupts them, inspect both before retrying.
|
||||
|
||||
### Cache Recovery
|
||||
|
||||
`prepare` refuses corrupt, incomplete or lock-mismatched caches; it does not merge or silently repair them. `sync` also refuses to replace a non-empty invalid snapshot. After inspecting the error, preserve the exact generated cache directory by moving it aside, then run `prepare` using the reviewed root lock. For example, in PowerShell **from the repository root**, choose an unused backup name:
|
||||
`prepare` reports corrupt, incomplete or lock-mismatched caches without repairing them. `sync` also refuses to replace a non-empty invalid snapshot. Inspect the error and move the generated cache aside before preparing it again from the reviewed root lock.
|
||||
|
||||
For example, in PowerShell **from the repository root**, with an unused backup name:
|
||||
|
||||
```powershell
|
||||
Move-Item -LiteralPath .\build\upstream -Destination .\build\upstream.backup
|
||||
@@ -82,58 +133,87 @@ go run . upstream prepare
|
||||
go run . upstream verify
|
||||
```
|
||||
|
||||
Do not remove the whole `build/` directory or edit cached official files. To restore a previous version after a deliberate sync, restore its reviewed root lock and rebuild the cache in the same way. Avoid simultaneous `sync`/`prepare`/build processes against one cache; stop `dev` while replacing inputs.
|
||||
Preserve the rest of `build/` and leave official cached files unedited. To return to a previous snapshot, restore its reviewed root lock and rebuild the cache in the same way. Stop `dev` before replacing inputs, and avoid concurrent processes writing to the same cache.
|
||||
|
||||
Mail types are discovered from the snapshot. `tools/data/templates_config.json` supplies names, descriptions and mock contexts only. A new official mail type requires a fixture before preview can pass.
|
||||
### Known Upstream Formatting Issue
|
||||
|
||||
Gitea v28.0.0 has a reviewed Polish `mail.team_invite.text_1` placeholder defect. Preview preserves official behavior and reports `[UPSTREAM-WARN]`; the exception matches the exact official text. Other formatting errors fail rendering. Do not edit locale snapshots to conceal upstream defects.
|
||||
|
||||
## Local Development
|
||||
|
||||
Use **Go 1.24+**. The CLI uses urfave/cli; HTML validation uses Go's x/net HTML parser. Run `go mod download` and `upstream prepare` once; subsequent verified builds work offline.
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
go run . list
|
||||
go run . build all
|
||||
go run . preview all
|
||||
go run . dev
|
||||
# http://127.0.0.1:3456
|
||||
```
|
||||
|
||||
`build` writes installable files to `build/themes/<name>/mail/`. `preview` also builds them, then writes a small manifest and one JS bundle per official language. Open `preview/index.html` directly for static preview; its language loader supports `file://`.
|
||||
|
||||
The loopback development server watches theme CSS/metadata, shared framework, lock/cache and fixtures. It rebuilds in-process and sends SSE reloads. Installable logos reference `{{AppUrl}}assets/img/favicon.png`; only the generated static preview embeds the downloaded official icon for offline display.
|
||||
Gitea v28.0.0 contains a Polish `mail.team_invite.text_1` placeholder defect. Preview preserves the official output and reports `[UPSTREAM-WARN]`. The exception matches the exact reviewed source text; other formatting errors fail rendering. Report upstream defects without modifying the cached locale files.
|
||||
|
||||
## Verification and Release
|
||||
|
||||
Tests check deterministic framework adaptation and generation, fail-closed action anchors, official keys and preserved notification semantics. Rendering tests cover all themes/languages and push, review, reply, workflow and attachment branches. Shared controls/branding are explicit presentation additions; button labels, fallback targets and logo references are validated separately.
|
||||
### Checks for a Pull Request
|
||||
|
||||
Before a release, use an isolated Gitea instance matching the locked tag and trigger a real password-reset or notification email. The administration test-email button bypasses custom templates. Confirm template loading and capture the rendered mail without sending to real users.
|
||||
From `tools/`, run `go test ./...` and `go run . preview all`. Tests cover deterministic generation, changes to action anchors, translation keys, and notification subjects, text and links across all themes and languages. Fixtures include push, review, reply, workflow and attachment branches. Shared controls and branding are accounted for separately from official notification content.
|
||||
|
||||
The optional `tools/integration` test automates this with disposable SQLite, users, Git/SSH paths and loopback SMTP. Set `GITEA_SMOKE_BINARY` to a checksum-verified official binary of the locked version, then run `go test ./integration -v -count=1` from `tools/`. Optional browser QA lives in `tools/qa`: install its dependencies, then run `npm test` after generating preview data; `PREVIEW_DEV_URL` includes HTTP preview checks and `--update-gallery` refreshes screenshots.
|
||||
For documentation, tracker or packaging changes, run from the repository root:
|
||||
|
||||
Release tags must match the snapshot's Gitea version. Add reviewed notes at `.github/release-notes/vX.Y.Z.md`. The workflow verifies the lock and tests, packages generated themes, multilingual preview, documentation and upstream license/provenance, then updates marked release labels. Keep source-only work separate from the published compatibility matrix. Existing historical tags and assets are unchanged.
|
||||
```bash
|
||||
python -B -m unittest discover -s .github/scripts -p 'test_*.py'
|
||||
```
|
||||
|
||||
From the repository root, run `python .github/scripts/package_release.py --version vX.Y.Z --output <new-output-directory>` after `preview all` for manual packaging. The same script is used by the release workflow. It verifies source/generated hashes and all language bundles, excludes undeclared stale build directories, and refuses to overwrite existing archives.
|
||||
Keep English and Simplified Chinese guides aligned when changing shared instructions. Include a description of the change, relevant checks and screenshots for visual changes in the pull request.
|
||||
|
||||
### Browser and Gitea Checks
|
||||
|
||||
After generating preview data, run the optional browser suite:
|
||||
|
||||
```bash
|
||||
cd tools/qa
|
||||
npm install
|
||||
npx playwright install chromium
|
||||
npm test
|
||||
```
|
||||
|
||||
To use installed Chrome or Edge, set `BROWSER_EXECUTABLE_PATH` instead of installing Chromium. Set `PREVIEW_DEV_URL` to include a running HTTP preview in the checks. `npm test -- --update-gallery` also refreshes gallery screenshots.
|
||||
|
||||
Before a release, test generated overrides in an isolated Gitea instance matching the locked version and capture a real password-reset or notification email. The administration test-email button bypasses custom templates.
|
||||
|
||||
The optional `tools/integration` test uses disposable SQLite data, users, Git/SSH paths and loopback SMTP. Set `GITEA_SMOKE_BINARY` to a checksum-verified official binary matching the lock, then run `go test ./integration -v -count=1` from `tools/`. It captures mail locally without sending to real users. Without this variable, the test is skipped. The release workflow does not run the optional browser or real-Gitea checks automatically.
|
||||
|
||||
### Preparing a Release
|
||||
|
||||
Release tags must match the locked Gitea version. The current source refactor is unreleased; retain existing v28.0.0 and historical assets.
|
||||
|
||||
1. Complete automated checks, preview review and the matching-instance smoke test.
|
||||
2. Add reviewed notes at `.github/release-notes/vX.Y.Z.md` and update compatibility records with the verification results.
|
||||
3. Generate all themes and language bundles with `go run . preview all` from `tools/`.
|
||||
4. Package the release and verify its contents before publication.
|
||||
|
||||
For manual packaging, run from the repository root:
|
||||
|
||||
```bash
|
||||
python .github/scripts/package_release.py --version vX.Y.Z --output <new-output-directory>
|
||||
```
|
||||
|
||||
Replace the version and output placeholder with the reviewed tag and a new directory. The script checks source and generated hashes, includes all language bundles, excludes stale theme builds, and refuses to overwrite existing archives.
|
||||
|
||||
The release workflow uses the same script to package templates, previews, documentation, the upstream license and provenance. It also updates managed release labels. Confirm Actions support and write permissions on the configured Gitea host before relying on automated publication. See [version tracking](COMPATIBILITY.md#version-tracking) for the managed Markdown blocks.
|
||||
|
||||
### Gitea Workflow Configuration
|
||||
|
||||
Both workflows use the `linux-amd64-docker-small` runner label. The job image must support the Node.js actions used for checkout and toolchain setup, as well as Git and a POSIX shell. Go and Python are installed by the setup steps.
|
||||
|
||||
PR creation and release uploads use `.github/scripts/gitea_actions.py` and the instance's `/api/v1` API. The workflows pass the instance URL, repository and built-in `GITEA_TOKEN`; repository settings must allow the requested code, release and pull-request writes. The optional `UPSTREAM_GITHUB_TOKEN` secret is used only to query official releases on GitHub. Without it, those queries use GitHub's unauthenticated API limit.
|
||||
|
||||
The tracker reuses an existing branch when its content matches and reuses an open PR for that branch. A differing branch requires manual review; the workflow does not force-push. Release publication refuses any existing release, including a draft. New releases remain drafts until both archives upload successfully. If an upload fails, inspect the draft before retrying; published releases and assets must remain unchanged.
|
||||
|
||||
## Reporting Problems
|
||||
|
||||
Include the snapshot tag/commit, theme, email type, preview language and error. Run `go run . upstream verify` and `go run . preview all` first; attach screenshots or the relevant render diagnostic.
|
||||
Include the Gitea version, template release or source commit, theme, mail type, language and steps to reproduce. For source-build problems, include the snapshot tag/commit and output from `go run . upstream verify` or `go run . preview all`. For display problems, include the mail client and a screenshot with personal data removed.
|
||||
|
||||
## Commit Conventions
|
||||
|
||||
- `style(<name>):` — theme presentation
|
||||
- `preview:` — browser preview
|
||||
- `tools:` — CLI/build/snapshot tooling
|
||||
- `docs:` — documentation and translations
|
||||
- `fix:` — bug fixes
|
||||
- `refactor:` — restructuring
|
||||
- `chore:` — maintenance
|
||||
| Prefix | Scope |
|
||||
|---|---|
|
||||
| `style(<name>):` | Theme presentation |
|
||||
| `preview:` | Browser preview |
|
||||
| `tools:` | CLI, build and snapshot tools |
|
||||
| `docs:` | Documentation and translations |
|
||||
| `fix:` | Bug fixes |
|
||||
| `project:` | Repository configuration and project structure |
|
||||
| `refactor:` | Code restructuring |
|
||||
| `chore:` | Maintenance |
|
||||
|
||||
## Translations and License
|
||||
|
||||
- English (this document)
|
||||
- [简体中文](docs/CONTRIBUTING.zh-CN.md)
|
||||
|
||||
Contributions are licensed under MIT. Retain Gitea copyright and the upstream license when distributing derived templates.
|
||||
The [Simplified Chinese guide](docs/CONTRIBUTING.zh-CN.md) covers the same workflow. Contributions are licensed under MIT. Retain Gitea copyright and the upstream license when distributing derived templates; see [third-party notices](THIRD_PARTY_NOTICES.md).
|
||||
@@ -1,54 +1,51 @@
|
||||
# Gitea Mail Templates
|
||||
<!-- DOC-TAGS: {"TRACKER":["BADGE","LATEST-TESTED","UPSTREAM"],"RELEASE":["HEADER","SUMMARY"]} -->
|
||||
|
||||
Polished, drop-in email template themes for self-hosted [Gitea](https://about.gitea.com).
|
||||
Email themes for self-hosted [Gitea](https://about.gitea.com), with a local preview and tools for building custom mail templates.
|
||||
|
||||
[简体中文](docs/README.zh-CN.md) · [Installation](#installation) · [Preview](#preview) · [Compatibility](COMPATIBILITY.md) · [Contributing](CONTRIBUTING.md)
|
||||
|
||||
<!-- TRACKER:BADGE -->
|
||||
[](COMPATIBILITY.md)
|
||||
<!-- /TRACKER:BADGE -->
|
||||
|
||||
<!-- RELEASE:HEADER -->
|
||||
> Latest Release: [v28.0.0](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/releases/latest)
|
||||
> Latest release: [v28.0.0](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/releases/latest)
|
||||
<!-- /RELEASE:HEADER -->
|
||||
|
||||
---
|
||||
The repository includes ten themes for account, repository, issue and workflow notifications. Gitea supplies notification content and translations; themes provide the visual presentation.
|
||||
|
||||
## Philosophy
|
||||
|
||||
Most self-hosted Gitea instances use the default plain email templates. This project provides **ready-to-deploy, visually polished alternatives** — each designed for a specific community or audience, so you can pick the one that feels right for your users.
|
||||
|
||||
The source on `main` uses locked official Gitea inputs and a reusable control framework. Gitea supplies mail values, notification logic and translations; shared controls organize headers, buttons, fallback URLs and footers, while themes define styling. Official files are downloaded during development/CI, not maintained in this repository. This refactor is unreleased and uses v28.0.0 as its baseline. Source clones must build installable templates first; release archives contain ready-to-copy files. Check the [compatibility matrix](COMPATIBILITY.md) before choosing a published archive.
|
||||
|
||||
---
|
||||
The source architecture on `main` is **unreleased** and uses Gitea v28.0.0 as its baseline. It builds templates from locked official inputs and a shared layout framework. Published archives retain their original contents and compatibility. Use the [compatibility matrix](COMPATIBILITY.md#compatibility-matrix) to choose an archive for your Gitea version.
|
||||
|
||||
## Style Gallery
|
||||
|
||||
| Preview | Style | Audience | Character |
|
||||
|---|---|---|---|
|
||||
|  | **Horizon** | Enterprise / Corporate | Blue accent, slate typography, centered cards |
|
||||
|  | **Terminal** | Developers / Tech | Dark mode, monospace, green CLI accents |
|
||||
|  | **Ember** | Community / Open Source | Warm amber, rounded, humanist, inclusive |
|
||||
|  | **Bloom** | Creative / Startup | Blue glass cards, soft gradients, rounded buttons |
|
||||
|  | **Heritage** | Education / Research | Paper texture palette, navy & gold, double borders, serif typography |
|
||||
|  | **Neon** | Gaming / Web3 / Creative Tech | Cyberpunk neon glow, hot pink & cyan, synthwave energy |
|
||||
|  | **Mono** | Design Studios / Editorial | Swiss brutalist, black & white, red accent, zero radius |
|
||||
|  | **Terra** | Sustainability / Wellness | Earth tones, terracotta buttons, organic accents, soft cards |
|
||||
|  | **Ink** | Publishing / News / Literature | Newspaper columns, navy & gold rules, editorial serif and drop caps |
|
||||
|  | **Aurora** | Premium SaaS / Mindfulness | Ethereal light gradients, deep purple & teal, atmospheric glow |
|
||||
| Preview | Theme | Appearance |
|
||||
|---|---|---|
|
||||
|  | **Horizon** | Blue accents, gray text and a centered white card |
|
||||
|  | **Terminal** | Dark background, monospace text and green accents |
|
||||
|  | **Ember** | Warm orange palette, serif headings and rounded buttons |
|
||||
|  | **Bloom** | Light blue gradients, rounded cards and buttons |
|
||||
|  | **Heritage** | Navy and gold accents, double borders and serif text |
|
||||
|  | **Neon** | Dark background, pink and cyan accents and glow effects |
|
||||
|  | **Mono** | Black and white, red accents and square borders |
|
||||
|  | **Terra** | Earth tones, terracotta buttons and serif text |
|
||||
|  | **Ink** | Newspaper layout, sidebar, serif text and drop caps |
|
||||
|  | **Aurora** | Dark purple background, teal accents and soft glow effects |
|
||||
|
||||
The gallery shows the themes currently included in this repository; new themes can be added as separate directories under `themes/`.
|
||||
|
||||
> Gallery images show the current shared-framework source build, not historical release archives. Original theme palettes, typography, header treatment and button/fallback controls are preserved. See the [local preview](preview/index.html) and [capture instructions](docs/images/README.md).
|
||||
|
||||
[**Local preview gallery**](preview/index.html) — generate the preview data as described below, then open it in a browser for an interactive style switcher with desktop/mobile viewports and view mode (Modern, Source).
|
||||
|
||||
---
|
||||
Images show the current source build. For other mail types and languages, generate the [local preview](#preview). See the [capture guide](docs/images/README.md) when updating screenshots.
|
||||
|
||||
## Installation
|
||||
|
||||
### Quick Start
|
||||
### Choose a Package
|
||||
|
||||
For a source clone, build from the committed `gitea.lock.json` first (Go 1.24+; first build downloads locked inputs if the cache is absent). A missing lock is an error; the tool never selects the latest Gitea automatically:
|
||||
Check your Gitea version with `gitea --version`, then select a template release from the [compatibility matrix](COMPATIBILITY.md#compatibility-matrix).
|
||||
|
||||
| Source | Mail template directory | Preparation |
|
||||
|---|---|---|
|
||||
| Release archive | `themes/<name>/mail/` | Download and extract the archive for the recommended release |
|
||||
| Source checkout | `build/themes/<name>/mail/` | Build with Go 1.24 or later |
|
||||
|
||||
For a source checkout, run from the repository root:
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
@@ -56,147 +53,71 @@ go run . build all
|
||||
cd ..
|
||||
```
|
||||
|
||||
Choose a style, then copy its generated `mail/` directory into your Gitea custom templates path. A release archive uses `themes/<name>/mail/` instead of `build/themes/<name>/mail/`:
|
||||
The first build downloads the official files pinned by `gitea.lock.json` if the cache is absent. Later builds verify the cache before use. The root lock file is required; missing or damaged inputs are covered in the [setup and recovery guide](CONTRIBUTING.md#official-snapshot-updates).
|
||||
|
||||
### Install a Theme
|
||||
|
||||
Copy the chosen theme's `mail/` contents into `<GITEA_CUSTOM>/templates/mail/`, then restart Gitea. Confirm your instance's custom directory before copying files. Common deployment paths include:
|
||||
|
||||
| Deployment | Example custom directory |
|
||||
|---|---|
|
||||
| Linux binary | `/var/lib/gitea/custom` |
|
||||
| Docker | `/data/gitea` |
|
||||
| Windows | `C:\gitea\custom` |
|
||||
|
||||
For example, from an extracted release archive on a Linux host managed by systemd:
|
||||
|
||||
```bash
|
||||
# Locate your Gitea custom directory
|
||||
# (set by GITEA_CUSTOM; defaults shown below)
|
||||
|
||||
# Copy templates (example: Horizon style)
|
||||
mkdir -p /var/lib/gitea/custom/templates/mail
|
||||
cp -r build/themes/horizon/mail/. /var/lib/gitea/custom/templates/mail/
|
||||
|
||||
# Restart Gitea
|
||||
cp -r themes/horizon/mail/. /var/lib/gitea/custom/templates/mail/
|
||||
systemctl restart gitea
|
||||
```
|
||||
|
||||
### Custom Directory Location
|
||||
|
||||
The paths below are common deployment examples, not universal defaults. Confirm your instance's configured custom path before copying files.
|
||||
|
||||
| Platform | Example Custom Path |
|
||||
|---|---|
|
||||
| Linux (binary) | `/var/lib/gitea/custom` |
|
||||
| Linux (Docker) | `/data/gitea` |
|
||||
| Windows | `C:\gitea\custom` |
|
||||
For a source build, use `build/themes/horizon/mail/.` as the copy source. Docker and Windows installations should restart Gitea using their deployment's service or container controls.
|
||||
|
||||
### Switching Styles
|
||||
|
||||
Back up your current mail overrides before switching styles. Remove files installed by the previous theme (listed in its `build.json`), then install the new theme's complete output. This matters when switching from `framed` to `shared`: stale per-email overrides would continue using the previous layout. Preserve unrelated custom templates.
|
||||
Back up existing mail overrides before replacing a theme. Remove the previous theme's installed files, then copy the new theme's complete output. Current source builds include a `build.json` file listing the generated files; for historical archives, refer to the archive contents. Preserve unrelated custom templates.
|
||||
|
||||
```bash
|
||||
cp -r build/themes/terminal/mail/. /var/lib/gitea/custom/templates/mail/
|
||||
systemctl restart gitea
|
||||
```
|
||||
Removing old overrides is especially important when switching from `framed` to `shared` mode: files left behind can keep the previous theme's layout.
|
||||
|
||||
### Confirming It Works
|
||||
|
||||
The admin test email does not use custom mail templates. To verify your templates
|
||||
are active, trigger a real email notification. The quickest way is the password
|
||||
reset flow: log out, click **"Forgot password"** on the login page, and check the
|
||||
reset email — it will render with your custom styles.
|
||||
|
||||
---
|
||||
Trigger a notification that uses Gitea's mail templates, such as a password-reset email for a test account, and check its appearance and links. The administration test-email button does not use custom mail templates.
|
||||
|
||||
## Preview
|
||||
|
||||
Static preview works without a server after generation; the development server supports live reload. A source clone must generate the manifest and per-language bundles first. The refactor packages all official languages in future archives. Existing v28.0.0 and earlier archives retain their original contents.
|
||||
|
||||
### Official Inputs (`upstream`)
|
||||
|
||||
Run from `tools/`: `go run . upstream prepare` downloads an absent cache using the existing lock; `go run . upstream verify` checks an existing cache offline; `go run . upstream sync --tag vX.Y.Z` explicitly replaces the version and generates the lock. All support `--root <repository-root>` after the subcommand (default `..`).
|
||||
|
||||
Without the root lock, preparation, verification, build and preview fail. Restore the tracked lock for a normal clone; intentional initialization can use `go run . upstream sync --tag v28.0.0`. Sync requires network access, accepts stable Gitea 28+ tags, and does not update documentation or publish releases. Damaged/mismatched caches require inspection and recovery, not an automatic repair. See the [full command and recovery guide](CONTRIBUTING.md#official-snapshot-updates).
|
||||
The preview supports theme, mail type and language selection, rendered HTML and source views, desktop/mobile viewports, and a panel showing the example data. The v28.0.0 snapshot contains 11 mail types and 28 languages.
|
||||
|
||||
### Static Preview
|
||||
|
||||
From a source clone, generate the preview data once, then open the HTML file in a browser:
|
||||
From a source checkout, generate the preview data:
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
go run . preview all
|
||||
cd ..
|
||||
# Open preview/index.html in a browser; no server is needed.
|
||||
```
|
||||
|
||||
### Dev Server (Live Reload)
|
||||
Open [preview/index.html](preview/index.html) in a browser. Generated language bundles load on demand and work over `file://`, so no server is needed. Archives produced by the current packaging script include these bundles; historical archives retain their original preview contents.
|
||||
|
||||
Start a pure Go development server that watches theme resources, shared framework, lock/cache and fixtures, auto-rebuilds, and pushes live updates via SSE:
|
||||
### Dev Server (Live Reload)
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
go run . dev
|
||||
# Open http://127.0.0.1:3456 in a browser.
|
||||
```
|
||||
|
||||
| Capability | Static | Dev |
|
||||
|-----------|--------|-----|
|
||||
| Go template rendering | [YES] | [YES] |
|
||||
| Theme/template/language switching | [YES] | [YES] |
|
||||
| Live reload on save | [NO] | [YES] |
|
||||
Open [http://127.0.0.1:3456](http://127.0.0.1:3456). The Go server watches theme files, the shared framework, the lock/cache and preview fixtures. Changes trigger a rebuild and browser refresh through server-sent events (SSE).
|
||||
|
||||
### Features
|
||||
|
||||
- Theme switcher — browse all available visual styles
|
||||
- Template switcher — mail types discovered from the official snapshot (currently 11)
|
||||
- Language switcher — all official locale files (28 in the v28.0.0 snapshot), loaded on demand
|
||||
- View mode — Modern (rendered preview), Source (raw HTML)
|
||||
- Viewport toggle — Desktop 1386×780 / Mobile 390×780
|
||||
- Parameter panel — mock data per email type
|
||||
- Keyboard shortcuts — `←→` tab between Theme/Template/Language/View, `↑↓` select within, `d`/`m` viewport
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
gitea-mail-templates/
|
||||
├── gitea.lock.json # Generated version/commit/checksums, no vendored upstream source
|
||||
├── framework/ # Reusable mail controls and structural layout presets
|
||||
├── themes/ # theme.json and theme.css per style; no mail logic
|
||||
├── build/upstream/ # Downloaded official inputs and license; ignored
|
||||
├── build/themes/ # Generated installable overrides; ignored
|
||||
│ └── <name>/mail/ # Generated files for each source theme
|
||||
├── preview/ # Live preview SPA
|
||||
│ ├── index.html # Theme/template/language/view/viewport switcher
|
||||
│ ├── rendered.js # Generated manifest; ignored
|
||||
│ └── rendered/ # Generated per-language JS bundles; ignored
|
||||
├── tools/ # Modular CLI tooling
|
||||
│ ├── tools.go # Main entry point
|
||||
│ ├── cli/ # CLI commands (upstream, build, preview, dev, list, create, delete)
|
||||
│ ├── config/ # Config types and templates_config.json loading
|
||||
│ ├── data/ # Preview metadata and mock contexts
|
||||
│ ├── upstream/ # Snapshot sync and offline verification
|
||||
│ ├── builder/ # Official-context alignment and framework/theme generation
|
||||
│ ├── preview/ # Rendering, locale adapter and dev server
|
||||
│ └── go.mod
|
||||
├── docs/ # Bilingual documentation (English + Simplified Chinese)
|
||||
├── AGENTS.md # AI agent guidance
|
||||
├── CONTRIBUTING.md
|
||||
├── LICENSE
|
||||
├── README.md
|
||||
└── .gitignore
|
||||
```
|
||||
|
||||
### Template Types
|
||||
|
||||
These are the official v28.0.0 entrypoints, not individually maintained theme sources. Framework-backed `framed` themes generate them using one alignment layer and shared controls. Optional `shared` mode overrides only the two base partials without adding controls.
|
||||
|
||||
| File | Email Trigger |
|
||||
| Control | Options or shortcut |
|
||||
|---|---|
|
||||
| `mail/user/auth/activate.tmpl` | Account activation |
|
||||
| `mail/user/auth/activate_email.tmpl` | Email address verification |
|
||||
| `mail/user/auth/register_notify.tmpl` | New registration notification |
|
||||
| `mail/user/auth/reset_passwd.tmpl` | Password reset |
|
||||
| `mail/org/team_invite.tmpl` | Team invitation |
|
||||
| `mail/repo/collaborator.tmpl` | Repository collaborator added |
|
||||
| `mail/repo/transfer.tmpl` | Repository ownership transfer |
|
||||
| `mail/repo/release.tmpl` | New release published |
|
||||
| `mail/repo/actions/workflow_run.tmpl` | Actions workflow run |
|
||||
| `mail/repo/issue/assigned.tmpl` | Issue / Pull Request assigned |
|
||||
| `mail/repo/issue/default.tmpl` | Issue / Pull Request updates |
|
||||
| Theme, template, language and view | `←` / `→` moves between selectors; `↑` / `↓` selects an option |
|
||||
| View | **Modern** for rendered HTML; **Source** for generated HTML text |
|
||||
| Viewport | **Desktop** (1386 × 780), **Mobile** (390 × 780); `d` / `m` |
|
||||
| Information panel | `p` toggles the panel |
|
||||
|
||||
---
|
||||
The preview renders templates using example data. Check your target mail clients separately; browser rendering does not reproduce their CSS support.
|
||||
|
||||
## Compatibility
|
||||
|
||||
@@ -206,45 +127,67 @@ These are the official v28.0.0 entrypoints, not individually maintained theme so
|
||||
<!-- RELEASE:SUMMARY -->
|
||||
- **Latest release:** [v28.0.0](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/releases/latest)
|
||||
<!-- /RELEASE:SUMMARY -->
|
||||
- For other Gitea versions, check the [per-version compatibility matrix](COMPATIBILITY.md#compatibility-matrix) before choosing an archive; [PENDING] rows have no verified recommendation. The matching v1.27.2 tag has a known push-notification defect.
|
||||
<!-- TRACKER:UPSTREAM -->
|
||||
- **Upstream Gitea 28.1.0:** [PENDING]
|
||||
<!-- /TRACKER:UPSTREAM -->
|
||||
- New source architecture targets Gitea 28+ and verifies the pinned snapshot offline; see [COMPATIBILITY.md](COMPATIBILITY.md) for source status and release-specific limitations
|
||||
- Uses only built-in Gitea template functions and official translation keys
|
||||
- No custom template functions or locale patches required
|
||||
|
||||
---
|
||||
The current source architecture targets Gitea 28 and later, with compatibility verified against the locked version. A newer upstream release remains pending until reviewed. Earlier Gitea versions require the packages listed in the [compatibility matrix](COMPATIBILITY.md#compatibility-matrix), which also records the incomplete push-notification fix in v1.27.2.
|
||||
|
||||
## Design Principles
|
||||
Generated templates use Gitea's built-in functions and official translation keys. Missing translations fall back to English. The locked v28.0.0 catalog has a known Polish invitation formatting defect; preview reports `[UPSTREAM-WARN]` and preserves the official output. See [known limitations](COMPATIBILITY.md#snapshot-driven-source-status).
|
||||
|
||||
1. **Official mail values** — Preserve notification data, conditions, subjects and functional link targets.
|
||||
2. **Shared controls, separate themes** — One framework owns content alignment and reusable controls; themes own CSS and retain original designs.
|
||||
3. **Responsive** — Current framed themes use 600px cards with 390px mobile previews; test target email clients before deployment.
|
||||
4. **Locale-aware** — Official catalogs supply all text; missing keys follow Gitea's English fallback.
|
||||
5. **Reproducible** — A lightweight lock pins immutable downloads; verified cached builds work offline and install files remain generated.
|
||||
## Directory Structure
|
||||
|
||||
Gitea v28.0.0 contains a known Polish invitation placeholder defect. Preview reports `[UPSTREAM-WARN]` and preserves official behavior. Details and validation commands are in [CONTRIBUTING.md](CONTRIBUTING.md#official-snapshot-updates).
|
||||
```text
|
||||
gitea.lock.json # Official tag, commit and file checksums
|
||||
framework/ # Shared mail controls and layout presets
|
||||
themes/<name>/ # Theme metadata (theme.json) and CSS (theme.css)
|
||||
tools/ # Go CLI, build tools and tests
|
||||
cli/ # Command definitions
|
||||
upstream/ # Snapshot downloads, verification and key discovery
|
||||
builder/ # Official template adaptation and theme generation
|
||||
preview/ # Mail rendering, locale adapter and development server
|
||||
config/, data/ # Preview metadata and example contexts
|
||||
integration/, qa/ # Optional Gitea and browser checks
|
||||
preview/ # Browser UI; generated manifest and language bundles
|
||||
docs/ # Simplified Chinese guides and gallery images
|
||||
.github/ # Workflows, release notes and packaging/tracking scripts
|
||||
build/upstream/ # Downloaded official inputs (ignored)
|
||||
build/themes/ # Generated installable templates (ignored)
|
||||
```
|
||||
|
||||
---
|
||||
Gitea's official templates define notification data, conditions, subjects and URLs. The shared framework arranges these into headers, action buttons, fallback links and footers. Themes define colors, typography and spacing. See [theme development](CONTRIBUTING.md#adding-a-theme) for the `framed` and `shared` modes.
|
||||
|
||||
## Documentation
|
||||
### Template Types
|
||||
|
||||
- [English](README.md)
|
||||
- [简体中文](docs/README.zh-CN.md)
|
||||
Mail types are discovered from the locked snapshot. The v28.0.0 entrypoints are:
|
||||
|
||||
---
|
||||
| File | Notification |
|
||||
|---|---|
|
||||
| `mail/user/auth/activate.tmpl` | Account activation |
|
||||
| `mail/user/auth/activate_email.tmpl` | Email address verification |
|
||||
| `mail/user/auth/register_notify.tmpl` | Registration notification |
|
||||
| `mail/user/auth/reset_passwd.tmpl` | Password reset |
|
||||
| `mail/org/team_invite.tmpl` | Team invitation |
|
||||
| `mail/repo/collaborator.tmpl` | Repository collaborator added |
|
||||
| `mail/repo/transfer.tmpl` | Repository ownership transfer |
|
||||
| `mail/repo/release.tmpl` | Release published |
|
||||
| `mail/repo/actions/workflow_run.tmpl` | Actions workflow run |
|
||||
| `mail/repo/issue/assigned.tmpl` | Issue or pull request assigned |
|
||||
| `mail/repo/issue/default.tmpl` | Issue or pull request activity |
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. A Simplified Chinese translation is available in [docs/](docs/).
|
||||
Contributions to themes, tooling, documentation and translations are welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md) for local setup, design guidelines, checks and release procedures.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [简体中文使用说明](docs/README.zh-CN.md)
|
||||
- [Contributor guide](CONTRIBUTING.md) · [简体中文贡献指南](docs/CONTRIBUTING.zh-CN.md)
|
||||
- [Compatibility and template reference](COMPATIBILITY.md)
|
||||
- [Gallery capture guide](docs/images/README.md)
|
||||
|
||||
## License
|
||||
|
||||
MIT — see [LICENSE](LICENSE) and [third-party notices](THIRD_PARTY_NOTICES.md). Generated archives retain the official Gitea license and snapshot provenance.
|
||||
This project is licensed under [MIT](LICENSE). Generated release archives retain Gitea's license and snapshot provenance; see [third-party notices](THIRD_PARTY_NOTICES.md).
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<sub>Not affiliated with the Gitea project. Gitea is a community-managed lightweight code hosting solution written in Go.</sub>
|
||||
</p>
|
||||
This project is not affiliated with Gitea.
|
||||
+14
-3
@@ -1,7 +1,18 @@
|
||||
# Third-Party Notices
|
||||
|
||||
Official mail templates, locale JSON catalogs, the preview favicon and reviewed implementation references originate from [Gitea](https://github.com/go-gitea/gitea). The tool downloads them to ignored `build/upstream/`; only the generated tag, commit and file SHA-256 lock (`gitea.lock.json`) is kept in source control.
|
||||
## Gitea
|
||||
|
||||
Gitea is licensed under MIT. Its unmodified license is downloaded as `build/upstream/LICENSE`. Release archives retain it as `GITEA-LICENSE` and include `upstream-lock.json` as provenance for generated templates and translated previews. Deployment mail logos reference the instance asset URL; only generated preview data embeds the official icon for offline display.
|
||||
The official mail templates, locale catalogs, preview favicon and implementation references used by the adapter come from [Gitea](https://github.com/go-gitea/gitea), which is licensed under MIT.
|
||||
|
||||
Theme presentation and tooling are covered by this repository's [MIT license](LICENSE). Go module dependencies and their versions are recorded in `tools/go.mod` and `tools/go.sum`.
|
||||
The build tools download these files into the ignored `build/upstream/` directory. The committed `gitea.lock.json` records their tag, commit and SHA-256 hashes. The upstream license is retained without modification at `build/upstream/LICENSE`.
|
||||
|
||||
Archives generated by the current packaging script include:
|
||||
|
||||
- `GITEA-LICENSE`: the upstream license.
|
||||
- `upstream-lock.json`: the provenance of the official inputs used to generate templates and translated previews.
|
||||
|
||||
Deployed email logos reference the Gitea instance's asset URL. Generated preview data embeds the official icon for offline display.
|
||||
|
||||
## Project and Dependencies
|
||||
|
||||
Theme presentation and tooling are covered by this repository's [MIT license](LICENSE). Go dependencies are recorded in `tools/go.mod` and `tools/go.sum`; optional browser QA dependencies are declared in `tools/qa/package.json`. Each dependency retains its own license.
|
||||
+164
-84
@@ -1,79 +1,130 @@
|
||||
# 贡献指南 — Gitea 邮件模板
|
||||
# 贡献指南
|
||||
|
||||
## 添加主题
|
||||
[English](../CONTRIBUTING.md) · [项目概览](README.zh-CN.md) · [兼容性](../COMPATIBILITY.md)
|
||||
|
||||
1. 执行 `cd tools && go run . create <名称>`,创建共享框架主题。
|
||||
2. 编辑 `themes/<名称>/theme.json` 和 `theme.css`。
|
||||
3. 在 `tools/` 中运行 `go run . upstream prepare`、`go test ./...` 和 `go run . preview all`。
|
||||
4. 检查英文、简体中文及另一种官方语言的桌面/移动端预览,随 PR 提交截图。
|
||||
欢迎改进主题、工具、测试、文档和翻译。本指南介绍当前源码架构的开发流程;安装和版本选择请参阅 [README](README.zh-CN.md#安装)。
|
||||
|
||||
主题名称以小写字母开头,可包含小写字母、数字和连字符。主题只包含 `theme.json` 与 `theme.css`。新主题默认使用 `framed` 模式及 `standard` 框架布局;`layout` 选择共享框架中的结构预设。可选的 `shared` 模式仅注入 CSS,不添加框架控件。
|
||||
## 本地开发
|
||||
|
||||
页头、操作按钮、失效提示/备用链接、侧栏和页脚统一由 `framework/mail/base/` 提供;结构预设位于 `framework/layouts/`,均属于框架,而非主题维护的邮件模板。`tools/builder/framework.go` 是唯一的官方操作值/翻译对齐层。通知分支、主题行、附件及上下文链接来自下载的官方模板,不得复制到各主题中。
|
||||
|
||||
## 设计规范
|
||||
|
||||
- 主题仅定义展示样式,共享框架使用官方邮件值与翻译组织可复用控件。
|
||||
- 主题使用兼容邮件客户端的 CSS,框架负责展示结构;主题 CSS 不加载外部资源、不生成文字、不隐藏官方内容。框架引用实例托管的 Logo 是有意保留的图片引用。
|
||||
- 片段校验允许展示性的 table、tr、td、div、span 等节点及展示属性,检查桌面及 390px 移动端布局。
|
||||
- 尽可能测试 Gmail、Outlook、Apple Mail;浏览器预览不能模拟所有客户端的 CSS 支持。
|
||||
- 忠于原主题的配色、字体、边框、页头、按钮/备用链接及布局,不使用通用卡片或新增装饰替代既有设计。
|
||||
- 画廊截图使用 PNG,单张最多 50 KiB,建议 10–20 KiB。截图须来自当前源码构建,并关闭浮动信息面板。
|
||||
|
||||
## 更新官方快照
|
||||
|
||||
源码仅保留工具生成的 `gitea.lock.json`,记录稳定 Gitea 28+ 标签、不可变提交及文件校验值。官方模板、语言 JSON、图标、许可证和适配参考实现均下载到被忽略的 `build/upstream/`,不在仓库中维护副本。
|
||||
|
||||
### 命令参考
|
||||
|
||||
以下命令均在 `tools/` 执行。三个子命令都支持 `--root <仓库根目录>`,默认值为相对当前工作目录的 `..`;参数放在子命令之后,含空格的路径须加引号。
|
||||
|
||||
```powershell
|
||||
# 在 tools/ 中显式指定仓库根目录:
|
||||
go run . upstream verify --root "D:\Work\Development\WebSites\GiteaMailTemplates"
|
||||
```
|
||||
|
||||
| 命令 | 用途 | 联网与写入行为 |
|
||||
|---|---|---|
|
||||
| `go run . upstream prepare` | 根据仓库锁文件准备精确匹配的输入 | 缓存不存在时按锁定提交下载,验证 SHA-256 后创建 `build/upstream/`;缓存存在时离线校验。不修改根锁文件。 |
|
||||
| `go run . upstream verify` | 对照根锁文件检查已有缓存 | 离线、只读,不下载;输出 `[PASS]` 及非英文缺键的 `[FALLBACK]` 列表。 |
|
||||
| `go run . upstream sync --tag vX.Y.Z` | 显式选择上游版本 | 通过 GitHub API 解析标签,按提交下载并校验快照,替换缓存并生成 `gitea.lock.json`。仅接受主版本不小于 28 的稳定 `vX.Y.Z` 标签。 |
|
||||
|
||||
这些命令不支持隐式 `latest`、读取本地 Gitea 克隆、令牌参数或认证环境变量。`sync` 使用 `api.github.com`,首次 `prepare` 与 `sync` 下载使用 `raw.githubusercontent.com`;网络错误与 API 限流会报错,不会自动换版本。即使快照检查离线,Go 工具链与模块仍可能需要单独联网下载。
|
||||
|
||||
### 已有克隆与离线使用
|
||||
使用 **Go 1.24 或更高版本**。从仓库根目录开始,准备依赖和锁定的官方文件,再运行检查并生成预览:
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
go mod download
|
||||
go run . upstream prepare
|
||||
go run . upstream verify
|
||||
go test ./...
|
||||
go run . preview all
|
||||
```
|
||||
|
||||
`build all`、`preview all` 和 `dev` 会自动准备输入,但仍要求根锁文件存在。缓存完整且 Go 工具链/依赖已安装后可离线构建。`verify` 检查官方输入、适配参考实现哈希和官方英文键;框架新增键与操作锚点由构建和渲染检查,因此单独通过 `verify` 不代表兼容性验证完成。
|
||||
在浏览器中打开 `preview/index.html`,或在 `tools/` 中运行 `go run . dev`,访问 [http://127.0.0.1:3456](http://127.0.0.1:3456) 使用实时预览。开发服务器监听主题、框架、锁文件与缓存、预览测试数据的变化。
|
||||
|
||||
CLI 使用 urfave/cli 和 x/net HTML 解析器。文档与打包检查使用 Python 3.11 或更高版本;只有浏览器检查需要 Node.js 和 `tools/qa` 中的依赖。
|
||||
|
||||
### 常用命令
|
||||
|
||||
以下命令均在 `tools/` 中执行。带有位置参数时,将选项放在位置参数之前。
|
||||
|
||||
| 命令 | 用途 |
|
||||
|---|---|
|
||||
| `go run . list` | 列出可用主题 |
|
||||
| `go run . create my-theme` | 创建主题元数据和 CSS |
|
||||
| `go run . build my-theme` | 生成指定主题的安装模板 |
|
||||
| `go run . build all` | 生成全部主题 |
|
||||
| `go run . preview all` | 构建全部主题并渲染所有官方语言 |
|
||||
| `go run . dev` | 在端口 3456 启动开发服务器 |
|
||||
| `go run . dev --port 3457` | 指定其他本地端口 |
|
||||
| `go run . delete my-theme` | 删除指定主题的源码目录 |
|
||||
|
||||
`build` 将模板写入 `build/themes/<名称>/mail/`,并在 `build.json` 中记录文件和源码哈希。`preview` 同时完成构建,随后写入 `preview/rendered.js` 和 `preview/rendered/<语言>.js`。这些生成文件和下载的官方文件均被 Git 忽略,无需随贡献提交。
|
||||
|
||||
## 添加主题
|
||||
|
||||
1. 在 `tools/` 中运行 `go run . create my-theme`。
|
||||
2. 编辑 `themes/my-theme/theme.json` 和 `theme.css`。
|
||||
3. 在 `tools/` 中运行 `go test ./...` 和 `go run . preview all`。
|
||||
4. 检查英文、简体中文及至少另一种官方语言的桌面与移动端布局,在拉取请求中附上截图。
|
||||
|
||||
主题名称以小写字母开头,可包含小写字母、数字和连字符。主题目录只包含 `theme.json` 和 `theme.css`。
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-theme",
|
||||
"description": "主题的简短说明",
|
||||
"mode": "framed",
|
||||
"layout": "standard"
|
||||
}
|
||||
```
|
||||
|
||||
| 模式 | 生成的展示结构 |
|
||||
|---|---|
|
||||
| `framed` | 使用共享控件和框架布局,由主题 CSS 定义样式。新主题默认使用此模式及 `standard` 布局。 |
|
||||
| `shared` | 在官方页头片段中加入 CSS,并保留官方页脚片段;不增加框架控件或各类邮件的覆盖模板。 |
|
||||
|
||||
### 共享框架
|
||||
|
||||
页头、操作按钮、备用链接、侧栏和页脚位于 `framework/mail/base/`。布局预设位于 `framework/layouts/`,`framed` 主题可通过可选的 `layout` 字段选择预设。配色、字体和间距由主题 CSS 定义。
|
||||
|
||||
`tools/builder/framework.go` 将官方操作值和翻译键适配到共享控件。通知条件、主题行、附件和上下文链接由官方模板定义。控件或布局结构的修改应放在框架中,使各主题使用同一套适配逻辑。
|
||||
|
||||
布局片段组合后必须形成标签配对完整的展示结构。`__HEADER__` 插入共享页头,`__MAIL_TYPE__` 展开为发现的邮件 ID,页脚片段中的 `__SIDEBAR__` 插入共享侧栏。部署模板的 Logo 使用 `{{AppUrl}}assets/img/favicon.png`;生成的预览数据嵌入下载的图标,供离线显示。
|
||||
|
||||
## 设计规范
|
||||
|
||||
- 使用兼容邮件客户端的 CSS。主题 CSS 不得加载外部资源、生成文字或隐藏官方内容。
|
||||
- 布局片段使用展示性标记。校验器接受 `table`、`tbody`、`tr`、`td`、`div`、`span` 及支持的展示属性。
|
||||
- 修改已有主题时,保留其配色、字体、边框、页头、按钮和布局特征。
|
||||
- 检查桌面和 390px 移动端预览,覆盖长文本和长 URL。条件允许时测试 Gmail、Outlook 和 Apple Mail;浏览器预览不能模拟邮件客户端。
|
||||
- 画廊图片使用 PNG,单张不超过 50 KiB,建议为 10–20 KiB。按[截图指南](images/README.md)保持截图一致。
|
||||
|
||||
## 更新官方快照
|
||||
|
||||
`gitea.lock.json` 记录稳定的 Gitea 28+ 标签、对应提交和每个文件的 SHA-256。官方邮件模板、语言文件、图标、许可证和已评审的适配参考源码下载到 `build/upstream/`。仓库仅提交生成的根锁文件,不维护官方文件副本。
|
||||
|
||||
### 命令参考
|
||||
|
||||
在 `tools/` 中执行。每个上游子命令均支持 `--root <仓库根目录>`,默认值为相对当前工作目录的 `..`。参数放在子命令之后,包含空格的路径需要加引号:
|
||||
|
||||
```powershell
|
||||
go run . upstream verify --root "C:\Projects\GiteaMailTemplates"
|
||||
```
|
||||
|
||||
| 命令 | 行为 |
|
||||
|---|---|
|
||||
| `go run . upstream prepare` | 读取根锁文件。缓存不存在时下载并校验对应文件;已有缓存则离线校验。不修改根锁文件。 |
|
||||
| `go run . upstream verify` | 对照根锁文件离线、只读检查已有缓存。输出 `[PASS]`,并以 `[FALLBACK]` 列出非英文语言缺少的键。 |
|
||||
| `go run . upstream sync --tag vX.Y.Z` | 通过 GitHub API 解析明确指定的稳定 Gitea 28+ 标签,下载并校验文件,然后替换缓存并生成根锁文件。 |
|
||||
|
||||
`sync` 使用 `api.github.com`,文件下载使用 `raw.githubusercontent.com`。这些命令不接受本地 Gitea 克隆、认证令牌或隐式的 `latest` 版本。网络错误和 API 限流会中止操作;Go 工具链或模块可能仍需单独联网下载。
|
||||
|
||||
### 已有克隆与离线使用
|
||||
|
||||
`build`、`preview` 和 `dev` 会自动准备输入,需要已提交的根锁文件,并在使用缓存前完成校验。缓存、Go 工具链和依赖齐备后,可以离线构建。
|
||||
|
||||
需要单独检查缓存时,使用 `upstream verify`。它校验官方文件哈希、已评审的适配参考源码,以及官方模板引用的英文翻译键。构建和渲染还会检查框架翻译键及主要操作链接的锚点,因此缓存校验只是兼容性测试的一部分。
|
||||
|
||||
### 锁文件缺失与显式更新版本
|
||||
|
||||
缺少 `gitea.lock.json` 时,`prepare`、`verify`、构建与预览均在读取锁文件时失败,即使 `build/upstream/lock.json` 仍在也不会代用。普通源码克隆应恢复受版本控制的根锁文件;有意首次初始化时,`sync` 不要求已有根锁文件:
|
||||
已有克隆缺少 `gitea.lock.json` 时,应恢复受版本控制的文件。`build/upstream/lock.json` 中的副本不能替代根锁文件。需要有意初始化锁文件时,执行:
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
# 当前源码基线;显式初始化,不是发布操作:
|
||||
go run . upstream sync --tag v28.0.0
|
||||
go run . upstream verify
|
||||
go test ./...
|
||||
go run . preview all
|
||||
```
|
||||
|
||||
评审其它版本时显式替换标签,例如此处仍为 [PENDING] 的 `v28.1.0`。检查生成的锁文件差异,对齐共享框架与测试数据,执行全部检查及同版本实例冒烟测试后,再更新兼容性文档。`sync` 不构建主题、不更新 Markdown、不创建 Git 标签、不提交、不推送,也不发布。仅缓存缺失时不应使用它。
|
||||
评审其他版本时,明确指定对应标签。检查锁文件差异,按需更新框架适配逻辑和测试数据,完成检查及同版本实例冒烟测试后,再更新兼容性记录。`sync` 只修改缓存和锁文件,文档更新与版本发布需单独完成。仅缺少缓存时使用 `prepare`。
|
||||
|
||||
翻译或邮件渲染参考实现哈希变化会阻止同步,须先复核 Go 适配逻辑;下载新版本并不等于确认兼容。官方英文须包含官方模板引用的键,构建另行检查框架键;其它语言缺键回退英文。缓存替换前的网络/校验失败不会修改原输入。缓存替换和根锁文件写入是两个操作:文件系统错误可能留下不一致状态,后续校验会失败,重试前先检查二者。
|
||||
已评审的翻译或邮件渲染参考源码发生变化时,须先评审适配逻辑,再更新参考哈希。官方英文必须包含所有引用的翻译键;其他语言缺少的翻译回退为英文。新增邮件类型需要补充框架适配和 `tools/data/templates_config.json` 中的测试数据,该文件提供预览元数据和示例上下文。JSON 测试数据中的整数应保持整数形式,以便 Go 正确格式化。
|
||||
|
||||
缓存替换前发生网络或校验错误时,原有文件保持不变。缓存替换和根锁文件写入是两个操作;文件系统错误中断操作后,重试前应检查二者是否一致。
|
||||
|
||||
### 缓存恢复
|
||||
|
||||
`prepare` 拒绝损坏、不完整或锁文件不匹配的缓存,不合并、不静默修复;`sync` 也拒绝替换非空的无效快照。检查错误后,将精确的生成缓存目录移到备份位置,再按已复核的根锁文件执行 `prepare`。例如在 **仓库根目录的 PowerShell** 中,选择尚不存在的备份名称:
|
||||
`prepare` 会报告损坏、不完整或与锁文件不匹配的缓存,不会自动修复。`sync` 同样拒绝替换非空的无效快照。检查错误后,将生成的缓存移至备份位置,再按已评审的根锁文件重新准备。
|
||||
|
||||
例如,在**仓库根目录的 PowerShell** 中,使用尚不存在的备份名称:
|
||||
|
||||
```powershell
|
||||
Move-Item -LiteralPath .\build\upstream -Destination .\build\upstream.backup
|
||||
@@ -82,58 +133,87 @@ go run . upstream prepare
|
||||
go run . upstream verify
|
||||
```
|
||||
|
||||
不要删除整个 `build/` 或修改缓存中的官方文件。显式同步后如需回退,恢复之前已复核的根锁文件,再按同样方式重建缓存。避免多个 `sync`/`prepare`/构建进程同时操作同一缓存;替换输入前先停止 `dev`。
|
||||
保留 `build/` 中的其他内容,不直接编辑缓存中的官方文件。需要回退快照时,恢复此前已评审的根锁文件,再按同样方式重建缓存。替换输入前先停止 `dev`,避免多个进程同时写入同一缓存。
|
||||
|
||||
邮件类型由快照发现,`tools/data/templates_config.json` 仅提供名称、描述和模拟上下文。新增官方邮件类型后,必须补充测试数据才能通过预览校验。
|
||||
### 已知上游格式问题
|
||||
|
||||
Gitea v28.0.0 的波兰语 `mail.team_invite.text_1` 存在已确认的占位符缺陷。预览保留官方行为并报告 `[UPSTREAM-WARN]`,例外严格匹配官方原文。其他格式错误会使渲染失败。不要直接修改语言快照来隐藏官方问题。
|
||||
|
||||
## 本地开发
|
||||
|
||||
使用 **Go 1.24+**。CLI 依赖 urfave/cli,HTML 校验使用 Go 的 x/net 解析器。先执行 `go mod download` 和 `upstream prepare` 下载依赖及锁定输入,之后可离线构建。
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
go run . list
|
||||
go run . build all
|
||||
go run . preview all
|
||||
go run . dev
|
||||
# http://127.0.0.1:3456
|
||||
```
|
||||
|
||||
`build` 将安装文件写入 `build/themes/<名称>/mail/`。`preview` 同时完成构建,生成小型清单和每种官方语言各自的 JS 数据包。直接打开 `preview/index.html` 即可静态预览,语言加载支持 `file://`。
|
||||
|
||||
回环开发服务器监听主题 CSS/元数据、共享框架、锁文件/缓存和测试数据,通过 SSE 刷新。安装模板的 Logo 引用 `{{AppUrl}}assets/img/favicon.png`;仅静态预览的生成数据嵌入下载的官方图标,以支持离线显示。
|
||||
Gitea v28.0.0 的波兰语 `mail.team_invite.text_1` 存在占位符缺陷。预览保留官方输出并报告 `[UPSTREAM-WARN]`。该例外仅匹配已评审的完整原文,其他格式错误会使渲染失败。发现上游问题时应报告问题,不修改缓存中的语言文件。
|
||||
|
||||
## 验证与发布
|
||||
|
||||
测试检查框架适配与生成的确定性、操作锚点变化时失败、官方翻译键及通知语义保留。渲染覆盖全部主题/语言及推送、评审、回复、工作流和附件分支。控件及品牌区域是明确的展示增补;按钮文字、备用链接目标和 Logo 引用单独校验。
|
||||
### 拉取请求检查
|
||||
|
||||
发布前,在与快照标签一致的隔离 Gitea 实例中触发真实的密码重置或通知邮件。管理后台的测试邮件按钮不会使用自定义模板。确认模板加载并捕获邮件,避免向真实用户发送测试内容。
|
||||
在 `tools/` 中运行 `go test ./...` 和 `go run . preview all`。测试覆盖生成结果的确定性、操作锚点变化、翻译键,以及全部主题和语言的通知主题行、正文与链接。测试数据包含推送、评审、回复、工作流和附件分支;共享控件与品牌展示作为附加内容单独处理。
|
||||
|
||||
可选的 `tools/integration` 测试使用临时 SQLite、用户、Git/SSH 路径及回环 SMTP 自动完成此流程。将 `GITEA_SMOKE_BINARY` 设为已校验官方 SHA-256、版本与快照一致的 Gitea 可执行文件,在 `tools/` 执行 `go test ./integration -v -count=1`。浏览器检查位于 `tools/qa`:生成预览后安装其可选依赖并运行 `npm test`;设置 `PREVIEW_DEV_URL` 可同时检查 HTTP 预览,`--update-gallery` 可更新截图。
|
||||
修改文档、追踪脚本或打包流程时,在仓库根目录执行:
|
||||
|
||||
发行标签须与快照中的 Gitea 版本一致,在 `.github/release-notes/vX.Y.Z.md` 添加已复核的说明。工作流校验快照和测试,打包生成主题、多语言预览、文档及官方许可证/来源信息,再更新发布标签区块。源码修改与已发布兼容矩阵保持区分;历史标签和附件不变。
|
||||
```bash
|
||||
python -B -m unittest discover -s .github/scripts -p 'test_*.py'
|
||||
```
|
||||
|
||||
手动打包时,先执行 `preview all`,再从仓库根目录运行 `python .github/scripts/package_release.py --version vX.Y.Z --output <新输出目录>`。发布工作流使用同一脚本;它校验源码/产物哈希和全部语言包,排除未声明的旧构建目录,并拒绝覆盖已有压缩包。
|
||||
调整通用说明时,同步更新英文和简体中文指南。拉取请求应说明改动内容及相关检查结果,涉及视觉变化时附上截图。
|
||||
|
||||
### 浏览器与 Gitea 实例检查
|
||||
|
||||
生成预览数据后,可运行浏览器检查:
|
||||
|
||||
```bash
|
||||
cd tools/qa
|
||||
npm install
|
||||
npx playwright install chromium
|
||||
npm test
|
||||
```
|
||||
|
||||
如需使用已安装的 Chrome 或 Edge,设置 `BROWSER_EXECUTABLE_PATH`,无需再安装 Chromium。设置 `PREVIEW_DEV_URL` 可同时检查运行中的 HTTP 预览。`npm test -- --update-gallery` 会一并更新画廊截图。
|
||||
|
||||
发布前,在与锁定版本一致的隔离 Gitea 实例中加载生成的模板,捕获真实的密码重置或通知邮件。管理后台的测试邮件按钮不使用自定义模板。
|
||||
|
||||
可选的 `tools/integration` 测试使用临时 SQLite 数据、用户、Git/SSH 路径和回环 SMTP。将 `GITEA_SMOKE_BINARY` 设为已校验官方校验值、版本与锁文件一致的 Gitea 可执行文件,再在 `tools/` 中运行 `go test ./integration -v -count=1`。邮件仅在本地捕获,不发送给真实用户。未设置该变量时会跳过此测试。发布工作流不会自动运行可选的浏览器和真实 Gitea 实例检查。
|
||||
|
||||
### 准备发行版
|
||||
|
||||
发行标签必须与锁定的 Gitea 版本一致。当前源码重构尚未发布,已有 v28.0.0 和历史版本的附件应保留。
|
||||
|
||||
1. 完成自动化检查、预览检查和同版本实例冒烟测试。
|
||||
2. 在 `.github/release-notes/vX.Y.Z.md` 添加已评审的发行说明,并按验证结果更新兼容性记录。
|
||||
3. 在 `tools/` 中运行 `go run . preview all`,生成全部主题和语言数据。
|
||||
4. 打包并检查发行包内容后再发布。
|
||||
|
||||
手动打包时,在仓库根目录执行:
|
||||
|
||||
```bash
|
||||
python .github/scripts/package_release.py --version vX.Y.Z --output <new-output-directory>
|
||||
```
|
||||
|
||||
将版本和输出目录占位符替换为已评审的标签及新的目录。脚本会检查源码与产物哈希,包含所有语言数据包,排除残留的旧主题构建,并拒绝覆盖已有压缩包。
|
||||
|
||||
发布工作流使用同一脚本打包模板、预览、文档、官方许可证和来源信息,并更新受管理的版本标记。依赖自动发布前,请确认所用 Gitea 主机的 Actions 支持和写入权限。Markdown 管理区块的说明见[版本追踪](../COMPATIBILITY.md#version-tracking)。
|
||||
|
||||
### Gitea 工作流配置
|
||||
|
||||
两个工作流均使用 `linux-amd64-docker-small` Runner 标签。任务镜像需要支持检出和工具链安装步骤使用的 Node.js Action,并提供 Git 和 POSIX Shell。Go 与 Python 由安装步骤准备。
|
||||
|
||||
PR 创建和发行附件上传通过 `.github/scripts/gitea_actions.py` 调用实例的 `/api/v1` API。工作流传入实例地址、仓库名称和内置 `GITEA_TOKEN`,仓库设置需要允许所请求的代码、发行版及拉取请求写入权限。可选的 `UPSTREAM_GITHUB_TOKEN` Secret 仅用于查询 GitHub 上的官方发行版;未配置时使用 GitHub 的匿名 API 限额。
|
||||
|
||||
追踪工作流会复用内容相同的已有分支及对应的未关闭 PR。分支内容不同时需要人工检查,工作流不会强制推送。发布流程拒绝修改任何已有发行版,包括草稿;新版本在两个压缩包上传成功后才从草稿转为发布状态。上传失败时,重试前先检查草稿;已发布版本及附件应保持不变。
|
||||
|
||||
## 报告问题
|
||||
|
||||
注明快照标签/提交、主题、邮件类型、预览语言和错误。先运行 `go run . upstream verify` 与 `go run . preview all`,附上截图或渲染诊断。
|
||||
请提供 Gitea 版本、模板发行版或源码提交、主题、邮件类型、语言和复现步骤。源码构建问题还应包含快照标签与提交,以及 `go run . upstream verify` 或 `go run . preview all` 的输出。显示问题请注明邮件客户端,并附上移除个人信息后的截图。
|
||||
|
||||
## 提交规范
|
||||
|
||||
- `style(<名称>):` — 主题展示样式
|
||||
- `preview:` — 浏览器预览
|
||||
- `tools:` — CLI、构建及快照工具
|
||||
- `docs:` — 文档和翻译
|
||||
- `fix:` — 修复
|
||||
- `refactor:` — 重构
|
||||
- `chore:` — 维护
|
||||
| 前缀 | 范围 |
|
||||
|---|---|
|
||||
| `style(<名称>):` | 主题展示样式 |
|
||||
| `preview:` | 浏览器预览 |
|
||||
| `tools:` | CLI、构建与快照工具 |
|
||||
| `docs:` | 文档和翻译 |
|
||||
| `fix:` | 问题修复 |
|
||||
| `project:` | 仓库配置和项目结构 |
|
||||
| `refactor:` | 代码重构 |
|
||||
| `chore:` | 日常维护 |
|
||||
|
||||
## 翻译与许可证
|
||||
|
||||
- [English CONTRIBUTING](../CONTRIBUTING.md)
|
||||
- 简体中文(本文)
|
||||
|
||||
贡献以 MIT 许可证授权,分发派生模板时须保留 Gitea 版权及官方许可证。
|
||||
[英文指南](../CONTRIBUTING.md)介绍相同的开发流程。贡献采用 MIT 许可证;分发派生模板时,请保留 Gitea 版权和官方许可证,详见[第三方声明](../THIRD_PARTY_NOTICES.md)。
|
||||
+113
-67
@@ -1,48 +1,47 @@
|
||||
# Gitea 邮件模板
|
||||
<!-- DOC-TAGS: {"TRACKER":["LATEST-TESTED","UPSTREAM"],"RELEASE":["HEADER","SUMMARY"]} -->
|
||||
|
||||
为自托管 [Gitea](https://about.gitea.com) 提供精心设计、可直接部署的多风格邮件模板。
|
||||
为自托管 [Gitea](https://about.gitea.com) 提供邮件主题、本地预览和自定义邮件模板构建工具。
|
||||
|
||||
[English](../README.md) · [安装](#安装) · [预览](#预览) · [兼容性](../COMPATIBILITY.md) · [贡献指南](CONTRIBUTING.zh-CN.md)
|
||||
|
||||
<!-- RELEASE:HEADER -->
|
||||
> 最新发布版:[v28.0.0](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/releases/latest)
|
||||
<!-- /RELEASE:HEADER -->
|
||||
|
||||
---
|
||||
仓库包含十种主题,覆盖账户、仓库、议题和工作流等邮件通知。通知内容和翻译由 Gitea 提供,主题负责展示样式。
|
||||
|
||||
## 设计理念
|
||||
|
||||
大多数自托管 Gitea 实例使用默认的纯文本邮件模板。本项目提供了**开箱即用、视觉精美的替代方案**——每种方案都针对特定社区或受众设计,您可以选择最适合您用户的风格。
|
||||
|
||||
`main` 分支使用锁定的官方输入及共享控件框架:Gitea 提供邮件值、通知逻辑与翻译,框架负责页头、按钮、备用链接和页脚,主题仅定义样式。官方文件在开发/CI 时下载,不在仓库中维护副本。该重构尚未发布,以 v28.0.0 为基线;源码克隆需先构建安装文件,发行包提供可直接复制的产物。使用已发布版本前,请查看[兼容性说明](../COMPATIBILITY.md)。
|
||||
|
||||
---
|
||||
`main` 分支的源码架构**尚未发布**,以 Gitea v28.0.0 为基线,通过锁定的官方文件和共享布局框架构建模板。已发布的压缩包保留原有内容和兼容范围。安装前,请根据 Gitea 版本查阅[兼容矩阵](../COMPATIBILITY.md#compatibility-matrix),选择对应的发行包。
|
||||
|
||||
## 风格画廊
|
||||
|
||||
下表展示仓库当前收录的主题;新增主题可作为独立目录放在 `themes/` 下,不受现有数量限制。
|
||||
| 预览 | 主题 | 样式特点 |
|
||||
|---|---|---|
|
||||
|  | **Horizon** | 蓝色强调色、灰色文字、居中白色卡片 |
|
||||
|  | **Terminal** | 深色背景、等宽字体、绿色强调色 |
|
||||
|  | **Ember** | 暖橙色调、衬线标题、圆角按钮 |
|
||||
|  | **Bloom** | 浅蓝色渐变、圆角卡片与按钮 |
|
||||
|  | **Heritage** | 藏蓝与金色、双线边框、衬线字体 |
|
||||
|  | **Neon** | 深色背景、粉红与青色、发光效果 |
|
||||
|  | **Mono** | 黑白配色、红色强调色、直角边框 |
|
||||
|  | **Terra** | 大地色调、陶土色按钮、衬线字体 |
|
||||
|  | **Ink** | 报刊式布局、侧栏、衬线字体与首字下沉 |
|
||||
|  | **Aurora** | 深紫色背景、青绿色强调色、柔和光晕 |
|
||||
|
||||
| 预览 | 风格 | 受众 | 特点 |
|
||||
|---|---|---|---|
|
||||
|  | **Horizon** | 企业/公司 | 蓝色强调色、石板灰排版、居中卡片 |
|
||||
|  | **Terminal** | 开发者/技术 | 暗色模式、等宽字体、绿色命令行风格 |
|
||||
|  | **Ember** | 社区/开源 | 暖琥珀色、圆角、人文主义、包容 |
|
||||
|  | **Bloom** | 创意/初创 | 蓝色玻璃卡片、柔和渐变、圆角按钮 |
|
||||
|  | **Heritage** | 教育/研究 | 纸质色调、海军蓝与金色、双线边框、衬线字体 |
|
||||
|  | **Neon** | 游戏/Web3/创意科技 | 赛博朋克霓虹、粉红与青色、合成波能量 |
|
||||
|  | **Mono** | 设计工作室/编辑 | 瑞士粗野主义、黑白红强调、零圆角 |
|
||||
|  | **Terra** | 可持续/健康 | 大地色、陶土色按钮、自然风格细节、柔和卡片 |
|
||||
|  | **Ink** | 出版/新闻/文学 | 报刊分栏、海军蓝与金色分隔线、衬线字体及首字下沉 |
|
||||
|  | **Aurora** | 高端SaaS/正念 | 空灵光效渐变、深紫与青绿、大气光晕 |
|
||||
|
||||
> 画廊展示共享框架的当前源码构建,并非历史发行包。保留原主题的配色、字体、页头及按钮/备用链接控件。查看[本地预览](../preview/index.html)及[截图说明](images/README.md)。
|
||||
|
||||
[**本地预览画廊**](../preview/index.html) — 先按下文生成预览数据,再在浏览器中打开。
|
||||
|
||||
---
|
||||
截图展示当前源码的构建结果。其他邮件类型和语言可通过[本地预览](#预览)查看;更新截图请参阅[截图指南](images/README.md)。
|
||||
|
||||
## 安装
|
||||
|
||||
源码克隆需按仓库提交的 `gitea.lock.json` 先构建(Go 1.24+,缓存不存在时首次构建下载锁定输入)。锁文件缺失会报错,不会自动选择最新版 Gitea:
|
||||
### 选择安装来源
|
||||
|
||||
运行 `gitea --version` 确认实例版本,再按[兼容矩阵](../COMPATIBILITY.md#compatibility-matrix)选择模板版本。
|
||||
|
||||
| 来源 | 邮件模板目录 | 准备步骤 |
|
||||
|---|---|---|
|
||||
| 发行压缩包 | `themes/<名称>/mail/` | 下载并解压推荐版本的发行包 |
|
||||
| 源码仓库 | `build/themes/<名称>/mail/` | 使用 Go 1.24 或更高版本构建 |
|
||||
|
||||
从源码构建时,在仓库根目录执行:
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
@@ -50,37 +49,45 @@ go run . build all
|
||||
cd ..
|
||||
```
|
||||
|
||||
选择一种风格,将生成的 `mail/` 目录复制到 Gitea 自定义模板路径。发行压缩包中的路径为 `themes/<名称>/mail/`,源码构建后的路径为 `build/themes/<名称>/mail/`:
|
||||
缓存不存在时,首次构建会下载 `gitea.lock.json` 锁定的官方文件;后续构建会先校验缓存。构建需要根目录的锁文件,文件缺失或缓存损坏的处理方式见[准备与恢复说明](CONTRIBUTING.zh-CN.md#更新官方快照)。
|
||||
|
||||
### 安装主题
|
||||
|
||||
将所选主题 `mail/` 目录中的内容复制到 `<GITEA_CUSTOM>/templates/mail/`,然后重启 Gitea。复制前请确认实例实际使用的自定义目录。以下是常见部署路径示例:
|
||||
|
||||
| 部署方式 | 自定义目录示例 |
|
||||
|---|---|
|
||||
| Linux 二进制部署 | `/var/lib/gitea/custom` |
|
||||
| Docker | `/data/gitea` |
|
||||
| Windows | `C:\gitea\custom` |
|
||||
|
||||
例如,在使用 systemd 管理 Gitea 的 Linux 主机上,从已解压的发行包目录执行:
|
||||
|
||||
```bash
|
||||
mkdir -p /var/lib/gitea/custom/templates/mail
|
||||
cp -r build/themes/horizon/mail/. /var/lib/gitea/custom/templates/mail/
|
||||
cp -r themes/horizon/mail/. /var/lib/gitea/custom/templates/mail/
|
||||
systemctl restart gitea
|
||||
```
|
||||
|
||||
切换前备份当前邮件覆盖文件,根据上一主题的 `build.json` 移除其安装文件,再复制新主题完整输出;保留其他自定义模板。从 `framed` 切换到 `shared` 时,遗留的正文覆盖文件仍会使用旧布局,因此不能仅覆盖两个共享片段。
|
||||
使用源码构建产物时,将复制来源改为 `build/themes/horizon/mail/.`。Docker 和 Windows 部署请使用相应的容器或服务管理方式重启。
|
||||
|
||||
请确认实例实际配置的自定义目录再安装;常见部署示例为 Linux 二进制部署的 `/var/lib/gitea/custom`、Docker 的 `/data/gitea`,以及 Windows 的 `C:\gitea\custom`,这些并非所有实例的统一默认路径。
|
||||
### 切换主题
|
||||
|
||||
先备份已有邮件模板,再移除上一主题安装的文件,复制新主题的完整产物。当前源码构建会在 `build.json` 中记录生成的文件;历史发行包可参照压缩包内容确认文件范围。保留其他自定义模板。
|
||||
|
||||
从 `framed` 切换到 `shared` 模式时,尤其需要清理旧主题文件,否则残留的覆盖模板可能继续使用原有布局。
|
||||
|
||||
### 确认生效
|
||||
|
||||
管理后台的测试邮件不会使用自定义模板。要验证模板是否生效,请触发一次真实的
|
||||
邮件通知。最快的方式是密码重置:退出登录,点击登录页的**"忘记密码"**,查看
|
||||
重置邮件即可——它将使用你的自定义样式渲染。
|
||||
|
||||
---
|
||||
使用测试账户触发密码重置等邮件通知,检查邮件样式和链接。管理后台的测试邮件按钮不使用自定义邮件模板。
|
||||
|
||||
## 预览
|
||||
|
||||
源码克隆需先生成被忽略的 `preview/rendered.js` 清单及逐语言数据包。后续发行包会包含全部官方语言的预览,现有 v28.0.0 及更早压缩包保持原内容。
|
||||
预览支持切换主题、邮件类型和语言,查看渲染结果或 HTML 源码,切换桌面与移动端视口,以及查看示例数据面板。v28.0.0 快照包含 11 种邮件类型和 28 种语言。
|
||||
|
||||
### 官方输入命令(`upstream`)
|
||||
### 静态预览
|
||||
|
||||
在 `tools/` 执行:`go run . upstream prepare` 根据已有锁文件下载尚不存在的缓存;`go run . upstream verify` 离线校验已有缓存;`go run . upstream sync --tag vX.Y.Z` 显式替换版本并生成锁文件。均支持子命令后的 `--root <仓库根目录>`,默认 `..`。
|
||||
|
||||
缺少根锁文件时,准备、校验、构建与预览都会失败。普通克隆应恢复受版本控制的锁文件;有意初始化可运行 `go run . upstream sync --tag v28.0.0`。同步须联网,仅接受稳定 Gitea 28+ 标签,不更新文档或发布版本。损坏/版本不匹配的缓存需要检查后恢复,而非自动修复,详见[完整命令与恢复指南](CONTRIBUTING.zh-CN.md#更新官方快照)。
|
||||
|
||||
**静态模式:**
|
||||
在源码仓库中生成预览数据:
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
@@ -88,56 +95,95 @@ go run . preview all
|
||||
cd ..
|
||||
```
|
||||
|
||||
然后在浏览器中打开 `preview/index.html`,无需启动服务器。
|
||||
在浏览器中打开 [preview/index.html](../preview/index.html)。语言数据按需加载,支持 `file://`,无需启动服务器。当前打包脚本生成的发行包包含这些数据;历史发行包保留其原有预览内容。
|
||||
|
||||
**开发服务器(实时重载):**
|
||||
### 开发服务器
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
go run . dev
|
||||
# 在浏览器中打开 http://127.0.0.1:3456
|
||||
```
|
||||
|
||||
| 功能 | 静态 | Dev |
|
||||
|-----------|--------|-----|
|
||||
| Go 模板渲染 | [YES] | [YES] |
|
||||
| 主题/模板/语言切换 | [YES] | [YES] |
|
||||
| 实时重载 | [NO] | [YES] |
|
||||
打开 [http://127.0.0.1:3456](http://127.0.0.1:3456)。Go 服务器监听主题文件、共享框架、锁文件与缓存、预览测试数据的变化,重新构建后通过服务器发送事件(SSE)刷新页面。
|
||||
|
||||
预览支持主题、邮件类型及全部官方语言切换(v28.0.0 快照含 28 种语言),以及 Modern/Source 视图、桌面/移动端尺寸和参数面板。语言数据按需加载,支持直接打开本地文件。`←→` 可切换选择框,`↑↓` 可切换选项,`d`/`m` 可切换视口。
|
||||
| 控件 | 选项或快捷键 |
|
||||
|---|---|
|
||||
| 主题、模板、语言和视图 | `←` / `→` 切换选择框,`↑` / `↓` 选择选项 |
|
||||
| 视图 | **Modern** 显示渲染结果,**Source** 显示生成的 HTML 文本 |
|
||||
| 视口 | **Desktop**(1386 × 780)、**Mobile**(390 × 780);快捷键 `d` / `m` |
|
||||
| 信息面板 | `p` 展开或收起面板 |
|
||||
|
||||
---
|
||||
预览使用示例数据渲染模板。浏览器与邮件客户端对 CSS 的支持不同,部署前还需在目标邮件客户端中检查效果。
|
||||
|
||||
## 兼容性
|
||||
|
||||
- **Gitea 28.0.0** — 使用模板发布版 v28.0.0;旧版 Gitea 请选用对应的旧版模板
|
||||
<!-- TRACKER:LATEST-TESTED -->
|
||||
- **最新测试:** Gitea 28.0.0
|
||||
<!-- /TRACKER:LATEST-TESTED -->
|
||||
<!-- RELEASE:SUMMARY -->
|
||||
- **最新发布版:** [v28.0.0](https://gitea.kenanzhu.com/KenanZhu/GiteaMailTemplates/releases/latest)
|
||||
<!-- /RELEASE:SUMMARY -->
|
||||
- 其它 Gitea 版本请先查看[逐版本兼容矩阵](../COMPATIBILITY.md#compatibility-matrix)再选择模板压缩包;标记为 [PENDING] 的版本尚无已验证的推荐包。版本号相符的 v1.27.2 存在已知的推送通知问题。
|
||||
<!-- TRACKER:UPSTREAM -->
|
||||
- **上游 Gitea 28.1.0:** [PENDING]
|
||||
<!-- /TRACKER:UPSTREAM -->
|
||||
- 新源码架构支持 Gitea 28+,离线校验官方快照;源码状态及历史发行版限制详见[兼容性说明](../COMPATIBILITY.md)。
|
||||
|
||||
## 模板类型
|
||||
当前源码架构面向 Gitea 28 及更高版本,兼容性按锁定版本验证。新的上游版本在完成评审前保持待验证状态。早期 Gitea 版本请使用[兼容矩阵](../COMPATIBILITY.md#compatibility-matrix)推荐的发行包;其中也记录了 v1.27.2 推送通知修复不完整的问题。
|
||||
|
||||
邮件类型由官方输入发现,当前为 11 种:账户激活、邮箱验证、注册通知、密码重置、团队邀请、仓库协作者、仓库转移、新版发布、Actions 工作流、议题/合并请求指派及议题/合并请求更新。具体路径参见[英文 README](../README.md#template-types)。`framed` 主题使用同一对齐层与共享控件生成安装文件;可选的 `shared` 模式仅覆盖两个基础片段,不添加框架控件。
|
||||
生成的模板使用 Gitea 内置函数和官方翻译键,缺少的翻译回退为英文。锁定的 v28.0.0 语言文件存在已知的波兰语邀请文案格式缺陷,预览会报告 `[UPSTREAM-WARN]` 并保留官方输出。详见[已知限制](../COMPATIBILITY.md#snapshot-driven-source-status)。
|
||||
|
||||
## 设计与翻译
|
||||
## 目录结构
|
||||
|
||||
主题仅维护 CSS 与元数据;共享框架使用官方邮件值及翻译组织可复用控件,保留通知条件、主题行和功能链接目标。官方模板及语言文件下载到忽略的 `build/upstream/`,仅提交工具生成的 `gitea.lock.json`。语言缺键按 Gitea 规则回退英文。v28.0.0 波兰语邀请文案存在官方占位符缺陷,预览报告 `[UPSTREAM-WARN]` 并保留官方行为,详见[贡献指南](CONTRIBUTING.zh-CN.md#更新官方快照)。
|
||||
```text
|
||||
gitea.lock.json # 官方标签、提交和文件校验值
|
||||
framework/ # 共享邮件控件和布局预设
|
||||
themes/<名称>/ # 主题元数据(theme.json)和样式(theme.css)
|
||||
tools/ # Go 命令行工具、构建工具和测试
|
||||
cli/ # 命令定义
|
||||
upstream/ # 快照下载、校验和翻译键发现
|
||||
builder/ # 官方模板适配与主题生成
|
||||
preview/ # 邮件渲染、语言适配和开发服务器
|
||||
config/, data/ # 预览元数据和示例上下文
|
||||
integration/, qa/ # 可选的 Gitea 实例与浏览器检查
|
||||
preview/ # 浏览器界面;生成的清单和语言数据包
|
||||
docs/ # 简体中文指南和画廊图片
|
||||
.github/ # 工作流、发行说明、打包与版本追踪脚本
|
||||
build/upstream/ # 下载的官方文件,不纳入版本控制
|
||||
build/themes/ # 生成的安装模板,不纳入版本控制
|
||||
```
|
||||
|
||||
## 文档与贡献
|
||||
官方模板定义通知数据、条件、主题行和 URL。共享框架将其组织为页头、操作按钮、备用链接和页脚,主题定义配色、字体与间距。`framed` 和 `shared` 模式的说明见[主题开发指南](CONTRIBUTING.zh-CN.md#添加主题)。
|
||||
|
||||
### 模板类型
|
||||
|
||||
邮件类型从锁定的快照中发现。v28.0.0 的邮件入口如下:
|
||||
|
||||
| 文件 | 通知类型 |
|
||||
|---|---|
|
||||
| `mail/user/auth/activate.tmpl` | 账户激活 |
|
||||
| `mail/user/auth/activate_email.tmpl` | 邮箱验证 |
|
||||
| `mail/user/auth/register_notify.tmpl` | 注册通知 |
|
||||
| `mail/user/auth/reset_passwd.tmpl` | 密码重置 |
|
||||
| `mail/org/team_invite.tmpl` | 团队邀请 |
|
||||
| `mail/repo/collaborator.tmpl` | 添加仓库协作者 |
|
||||
| `mail/repo/transfer.tmpl` | 仓库所有权转移 |
|
||||
| `mail/repo/release.tmpl` | 发布新版本 |
|
||||
| `mail/repo/actions/workflow_run.tmpl` | Actions 工作流运行 |
|
||||
| `mail/repo/issue/assigned.tmpl` | 议题或合并请求指派 |
|
||||
| `mail/repo/issue/default.tmpl` | 议题或合并请求动态 |
|
||||
|
||||
## 参与贡献
|
||||
|
||||
欢迎改进主题、工具、文档和翻译。[贡献指南](CONTRIBUTING.zh-CN.md)介绍了本地环境准备、设计规范、检查要求和发布流程。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [English README](../README.md)
|
||||
- [简体中文 README](README.zh-CN.md)
|
||||
- [English CONTRIBUTING](../CONTRIBUTING.md)
|
||||
- [简体中文贡献指南](CONTRIBUTING.zh-CN.md)
|
||||
- [简体中文贡献指南](CONTRIBUTING.zh-CN.md) · [English contributor guide](../CONTRIBUTING.md)
|
||||
- [兼容性与模板参考](../COMPATIBILITY.md)
|
||||
- [画廊截图指南](images/README.md)
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT — 详见 [LICENSE](../LICENSE) 和[第三方声明](../THIRD_PARTY_NOTICES.md)。发行包保留官方 Gitea 许可证和快照来源信息。
|
||||
本项目采用 [MIT 许可证](../LICENSE)。生成的发行包保留 Gitea 许可证和快照来源信息,详见[第三方声明](../THIRD_PARTY_NOTICES.md)。
|
||||
|
||||
本项目与 Gitea 官方无隶属关系。
|
||||
+34
-21
@@ -1,31 +1,44 @@
|
||||
# Style Preview Images
|
||||
# Gallery Images
|
||||
|
||||
> Images show the current snapshot-driven source build. Historical release archives retain their original templates and are not replaced by these screenshots.
|
||||
Gallery images show the current source build. Historical release archives retain their original templates.
|
||||
|
||||
Place theme style screenshots of **Desktop** in PNG format here, captured from the [local preview](../../preview/index.html).
|
||||
## Capture Settings
|
||||
|
||||
## Naming Convention
|
||||
Use the same settings for every theme so images remain comparable:
|
||||
|
||||
```
|
||||
horizon.png terminal.png ember.png bloom.png heritage.png
|
||||
neon.png mono.png terra.png ink.png aurora.png
|
||||
| Setting | Value |
|
||||
|---|---|
|
||||
| Template | **Register Notify** |
|
||||
| Language | **en-US** |
|
||||
| View | **Modern** |
|
||||
| Viewport | **Desktop** |
|
||||
| Information panel | Collapsed |
|
||||
| Output | PNG, 600px wide recommended |
|
||||
|
||||
Save images as `<theme-name>.png` in this directory, matching the directory name under `themes/`. Each file must be at most **50 KiB**; **10–20 KiB** is preferred. Optimize larger PNGs with tools such as `pngquant` or `optipng`.
|
||||
|
||||
## Automated Capture
|
||||
|
||||
Generate preview data from the repository root:
|
||||
|
||||
```bash
|
||||
cd tools
|
||||
go run . preview all
|
||||
cd qa
|
||||
npm install
|
||||
npx playwright install chromium
|
||||
npm test -- --update-gallery
|
||||
```
|
||||
|
||||
## Image Size Requirements
|
||||
To use installed Chrome or Edge, set `BROWSER_EXECUTABLE_PATH` instead of installing Chromium. The script checks language loading, controls and mobile overflow, saves captures in `build/screenshots/`, then copies them here after enforcing the size limit. Review the resulting images before committing.
|
||||
|
||||
To ensure screenshots can be displayed in the README, please follow these size requirements:
|
||||
Run `npm test` without `--update-gallery` to perform the checks and capture images without changing the committed gallery.
|
||||
|
||||
- **Maximum:** 50 KiB per image
|
||||
- **Recommended:** 10–20 KiB
|
||||
- **Format:** PNG, optimised — run through `pngquant` or `optipng` before committing
|
||||
## Manual Capture
|
||||
|
||||
## How to Capture
|
||||
1. Run `go run . dev` from `tools/` and open [http://127.0.0.1:3456](http://127.0.0.1:3456). Alternatively, run `go run . preview all` and open [preview/index.html](../../preview/index.html) directly.
|
||||
2. Select a theme and apply the capture settings above.
|
||||
3. Capture the rendered email, excluding the preview toolbar and information panel.
|
||||
4. Save the PNG as `<theme-name>.png`, check its size and repeat for the remaining themes.
|
||||
|
||||
1. Start the dev server: `cd tools && go run . dev` and open http://127.0.0.1:3456 in your browser
|
||||
2. For each style, select the **"Register Notify"** template and **"Modern"** view, **"en-US"** language and **"Desktop"** viewport; close the floating inspector
|
||||
3. Take a screenshot of the rendered email (600px width recommended)
|
||||
4. Save as `<style-name>.png` in this directory
|
||||
|
||||
> For a source clone, run `cd tools && go run . preview all`, return to the repository root, then open `preview/index.html` directly.
|
||||
|
||||
For automated capture, install the optional dependencies in `tools/qa` and run `node preview.cjs --update-gallery` there. Set `BROWSER_EXECUTABLE_PATH` when using an installed Chrome/Edge instead of Playwright's bundled Chromium.
|
||||
When adding a theme, update its gallery entry in both the [English README](../../README.md#style-gallery) and [Simplified Chinese README](../README.zh-CN.md#风格画廊).
|
||||
Reference in new issue
Block a user