Files
MooTool/scripts/test_manage_releases.py
2026-07-18 07:51:36 +08:00

181 lines
8.4 KiB
Python

from __future__ import annotations
import json
import tempfile
import unittest
from pathlib import Path
from scripts.manage_releases import (
ELECTRON_TARGETS,
compare_semver,
electron_release_info,
java_release_info,
release_outputs,
stage_electron_assets,
update_electron_manifest,
)
class ManageReleasesTests(unittest.TestCase):
def test_semver_comparison_handles_prereleases(self) -> None:
self.assertLess(compare_semver("2.0.0-beta.2", "2.0.0"), 0)
self.assertGreater(compare_semver("2.0.0-beta.10", "2.0.0-beta.2"), 0)
self.assertGreater(compare_semver("1.10.0", "1.9.9"), 0)
with self.assertRaisesRegex(ValueError, "Invalid semantic version"):
compare_semver("2.0.0-beta.01", "2.0.0-beta.1")
def test_electron_release_requires_package_tag_and_notes_to_match(self) -> None:
with tempfile.TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
self.write_electron_project(root, "1.2.0-beta.1")
info = electron_release_info(root, "next-electron-v1.2.0-beta.1")
self.assertEqual(info.title, "MooTool Next Electron 1.2.0-beta.1")
self.assertTrue(info.prerelease)
self.assertEqual(release_outputs(info)["notes_path"], "next/release-notes/1.2.0-beta.1.md")
with self.assertRaisesRegex(ValueError, "Electron tag must be"):
electron_release_info(root, "v1.2.0-beta.1")
def test_staging_mac_only_publishes_the_dmg(self) -> None:
with tempfile.TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
source = root / "dist"
output = root / "release"
source.mkdir()
version = "1.0.0"
target = ELECTRON_TARGETS["mac-apple-silicon"]
for template in target.asset_templates:
(source / template.format(version=version)).write_text("asset", encoding="utf-8")
staged = stage_electron_assets(source, output, "mac-apple-silicon", version)
self.assertEqual(staged, [output / "MooTool-Next-Electron-1.0.0-mac-arm64.dmg"])
self.assertEqual([path.name for path in output.iterdir()], ["MooTool-Next-Electron-1.0.0-mac-arm64.dmg"])
def test_manifest_update_preserves_products_and_replaces_same_version(self) -> None:
with tempfile.TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
self.write_electron_project(root, "1.0.0")
assets = root / "assets"
assets.mkdir()
self.write_complete_electron_assets(assets, "1.0.0")
manifest_path = root / "update-manifest.json"
manifest_path.write_text(json.dumps({
"schemaVersion": 1,
"products": {
"java": {"displayName": "Java", "status": "legacy"},
"next-electron": {
"displayName": "Electron",
"status": "active",
"releases": [{"version": "1.0.0", "notes": "old"}],
},
},
}), encoding="utf-8")
release = update_electron_manifest(
root,
manifest_path,
assets,
"next-electron-v1.0.0",
)
updated = json.loads(manifest_path.read_text(encoding="utf-8"))
self.assertFalse(release["prerelease"])
mac_assets = [asset for asset in release["assets"] if asset["platform"] == "darwin"]
self.assertEqual(len(mac_assets), 2)
self.assertTrue(all(asset["packageType"] == "dmg" for asset in mac_assets))
self.assertTrue(all(asset["priority"] == 10 for asset in mac_assets))
self.assertTrue(all(len(asset["sha512"]) == 88 for asset in mac_assets))
self.assertTrue(all(asset["size"] == 5 for asset in mac_assets))
self.assertEqual(updated["products"]["java"]["status"], "legacy")
self.assertEqual(len(updated["products"]["next-electron"]["releases"]), 1)
self.assertIn("独立更新", updated["products"]["next-electron"]["releases"][0]["notes"])
def test_manifest_update_rejects_malformed_existing_release(self) -> None:
with tempfile.TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
self.write_electron_project(root, "1.0.0")
assets = root / "assets"
assets.mkdir()
self.write_complete_electron_assets(assets, "1.0.0")
manifest_path = root / "update-manifest.json"
manifest_path.write_text(json.dumps({
"schemaVersion": 1,
"products": {
"next-electron": {
"displayName": "Electron",
"status": "active",
"releases": [{"notes": "missing version"}],
},
},
}), encoding="utf-8")
with self.assertRaisesRegex(ValueError, "string version"):
update_electron_manifest(root, manifest_path, assets, "next-electron-v1.0.0")
def test_java_release_uses_all_three_version_sources_and_renders_notes(self) -> None:
with tempfile.TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
self.write_java_project(root, "1.10.0")
info = java_release_info(root, "v1.10.0")
self.assertEqual(info.title, "MooTool Java 1.10.0")
self.assertIn("- 修复版本比较", info.notes)
self.assertIn("## English", info.notes)
self.assertIn("- Fix version comparison", info.notes)
self.assertIn("## 日本語", info.notes)
self.assertIn("- バージョン比較を修正", info.notes)
with self.assertRaisesRegex(ValueError, "Java tag must be"):
java_release_info(root, "v1.9.0")
@staticmethod
def write_electron_project(root: Path, version: str) -> None:
(root / "next/release-notes").mkdir(parents=True)
(root / "next/package.json").write_text(json.dumps({"version": version}), encoding="utf-8")
title = f"MooTool Next Electron {version}"
(root / f"next/release-notes/{version}.md").write_text(
f"# {title}\n\n## English\n\n- Independent updates.\n\n"
"## 中文\n\n- 独立更新。\n\n## 日本語\n\n- 独立して更新します。\n",
encoding="utf-8",
)
@staticmethod
def write_complete_electron_assets(root: Path, version: str) -> None:
for target in ELECTRON_TARGETS.values():
for template in target.asset_templates:
(root / template.format(version=version)).write_text("asset", encoding="utf-8")
if target.metadata_destination and target.metadata_payload_template:
payload = target.metadata_payload_template.format(version=version)
(root / target.metadata_destination).write_text(
f"version: {version}\nfiles:\n - url: {payload}\n sha512: checksum\n",
encoding="utf-8",
)
@staticmethod
def write_java_project(root: Path, version: str) -> None:
(root / "src/main/java/com/luoboduner/moo/tool/ui").mkdir(parents=True)
(root / "src/main/resources").mkdir(parents=True)
(root / "pom.xml").write_text(
"<?xml version=\"1.0\"?><project xmlns=\"http://maven.apache.org/POM/4.0.0\">"
f"<modelVersion>4.0.0</modelVersion><version>{version}</version></project>",
encoding="utf-8",
)
tag = f"v{version}"
(root / "src/main/java/com/luoboduner/moo/tool/ui/UiConsts.java").write_text(
f'public class UiConsts {{ public static final String APP_VERSION = "{tag}"; }}',
encoding="utf-8",
)
(root / "src/main/resources/version_summary.json").write_text(json.dumps({
"currentVersion": tag,
"versionIndex": {tag: "1"},
"versionDetailList": [{
"version": tag,
"title": "维护版本",
"log": "● 修复版本比较\n● 更新发布说明\n",
"titleEn": "Maintenance release",
"logEn": "● Fix version comparison\n● Update release notes\n",
"titleJa": "メンテナンスリリース",
"logJa": "● バージョン比較を修正\n● リリースノートを更新\n",
}],
}), encoding="utf-8")
if __name__ == "__main__":
unittest.main()