chore: refresh docs and adapt workflows for Gitea
Release / Validate Templates (push) Successful in 3m1s
Release / Package & Release (push) Skipped
Release / Update Latest Release Documentation (push) Skipped

This commit is contained in:
KenanZhu committed 2026-10-09 22:02:33 +08:00
1 parent fec3ace600
commit f4d96de79e
14 files changed
+986 -505

No files matched your search

+160
View File
@@ -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()