168 lines
6.0 KiB
Python
168 lines
6.0 KiB
Python
from __future__ import annotations
|
|
|
|
from io import BytesIO
|
|
import importlib.util
|
|
import json
|
|
from pathlib import Path
|
|
import sys
|
|
import tarfile
|
|
import tempfile
|
|
import tomllib
|
|
import unittest
|
|
import zipfile
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def _load(name: str, path: Path):
|
|
spec = importlib.util.spec_from_file_location(name, path)
|
|
assert spec is not None and spec.loader is not None
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[name] = module
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
PACKAGE_SET = _load(
|
|
"generate_release_package_set",
|
|
ROOT / "tools/release/generate-release-package-set.py",
|
|
)
|
|
ARTIFACTS = _load(
|
|
"resolve_package_artifacts",
|
|
ROOT / "tools/release/resolve-package-artifacts.py",
|
|
)
|
|
|
|
|
|
class PackageRegistryReleaseTests(unittest.TestCase):
|
|
def test_current_release_sources_form_a_hash_bound_package_set(self) -> None:
|
|
core_version = tomllib.loads(
|
|
(ROOT.parent / "govoplan-core/pyproject.toml").read_text(encoding="utf-8")
|
|
)["project"]["version"]
|
|
payload = PACKAGE_SET.generate_package_set(
|
|
core_version=core_version,
|
|
requirements=ROOT / "requirements-release.txt",
|
|
workspace=ROOT.parent,
|
|
)
|
|
|
|
self.assertEqual("1", payload["schema_version"])
|
|
self.assertEqual("govoplan-core", payload["python"][0]["name"])
|
|
self.assertIn(
|
|
"@govoplan/core-webui",
|
|
{item["name"] for item in payload["webui"]},
|
|
)
|
|
unsigned = dict(payload)
|
|
digest = unsigned.pop("package_set_sha256")
|
|
self.assertEqual(ARTIFACTS._canonical_sha256(unsigned), digest)
|
|
|
|
def test_wheel_and_webui_artifacts_are_verified_by_embedded_identity(self) -> None:
|
|
with tempfile.TemporaryDirectory(prefix="govoplan-package-artifacts-") as value:
|
|
root = Path(value)
|
|
wheels = root / "wheels"
|
|
webui = root / "webui"
|
|
wheels.mkdir()
|
|
webui.mkdir()
|
|
wheel = wheels / "govoplan_demo-1.2.3-py3-none-any.whl"
|
|
with zipfile.ZipFile(wheel, "w") as archive:
|
|
archive.writestr(
|
|
"govoplan_demo-1.2.3.dist-info/METADATA",
|
|
"Metadata-Version: 2.1\nName: govoplan-demo\nVersion: 1.2.3\n",
|
|
)
|
|
package_json = json.dumps(
|
|
{"name": "@govoplan/demo-webui", "version": "1.2.3"}
|
|
).encode("utf-8")
|
|
npm = webui / "govoplan-demo-webui-1.2.3.tgz"
|
|
with tarfile.open(npm, "w:gz") as archive:
|
|
member = tarfile.TarInfo("package/package.json")
|
|
member.size = len(package_json)
|
|
archive.addfile(member, BytesIO(package_json))
|
|
source = {
|
|
"version": "1.2.3",
|
|
"repository": "govoplan-demo",
|
|
"tag": "v1.2.3",
|
|
"commit": "1" * 40,
|
|
}
|
|
|
|
python_rows = ARTIFACTS._verify_wheels(
|
|
({"name": "govoplan-demo", "extras": ["server"], **source},), wheels
|
|
)
|
|
webui_rows = ARTIFACTS._verify_webui(
|
|
({"name": "@govoplan/demo-webui", **source},), webui
|
|
)
|
|
|
|
self.assertEqual("govoplan-demo", python_rows[0]["name"])
|
|
self.assertEqual(["server"], python_rows[0]["extras"])
|
|
self.assertEqual("@govoplan/demo-webui", webui_rows[0]["name"])
|
|
self.assertTrue(str(webui_rows[0]["integrity"]).startswith("sha512-"))
|
|
|
|
def test_package_set_rejects_argument_shaped_package_names(self) -> None:
|
|
payload = {
|
|
"schema_version": "1",
|
|
"release_version": "1.2.3",
|
|
"registries": {
|
|
"python": "https://packages.example.test/pypi/simple",
|
|
"npm": "https://packages.example.test/npm/",
|
|
},
|
|
"python": [
|
|
{
|
|
"name": "--index-url",
|
|
"version": "1.2.3",
|
|
"repository": "govoplan-demo",
|
|
"extras": [],
|
|
"tag": "v1.2.3",
|
|
"commit": "1" * 40,
|
|
}
|
|
],
|
|
"webui": [
|
|
{
|
|
"name": "@govoplan/demo-webui",
|
|
"version": "1.2.3",
|
|
"repository": "govoplan-demo",
|
|
"tag": "v1.2.3",
|
|
"commit": "1" * 40,
|
|
}
|
|
],
|
|
}
|
|
payload["package_set_sha256"] = ARTIFACTS._canonical_sha256(payload)
|
|
with tempfile.TemporaryDirectory() as value:
|
|
path = Path(value) / "packages.json"
|
|
path.write_text(json.dumps(payload), encoding="utf-8")
|
|
with self.assertRaisesRegex(
|
|
ARTIFACTS.PackageArtifactError, "invalid identity"
|
|
):
|
|
ARTIFACTS._load_package_set(path)
|
|
|
|
def test_runtime_workflow_consumes_registry_artifacts_and_publishes_lock(self) -> None:
|
|
workflow = (ROOT / ".gitea/workflows/runtime-distribution.yml").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
|
|
self.assertIn("resolve-package-artifacts.py", workflow)
|
|
self.assertIn("package-artifacts.lock.json", workflow)
|
|
self.assertIn(
|
|
"--package-lock runtime-output/package-artifacts.lock.json",
|
|
workflow,
|
|
)
|
|
self.assertNotIn(
|
|
"pip wheel --no-deps --wheel-dir runtime-output/local-wheels",
|
|
workflow,
|
|
)
|
|
|
|
def test_developer_meta_package_matches_workspace_versions(self) -> None:
|
|
script = _load(
|
|
"generate_developer_meta_package",
|
|
ROOT / "tools/release/generate-developer-meta-package.py",
|
|
)
|
|
expected = script.render(
|
|
workspace=ROOT.parent,
|
|
requirements=ROOT / "requirements-release.txt",
|
|
)
|
|
actual = (ROOT / "packages/govoplan-meta/pyproject.toml").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
self.assertEqual(expected, actual)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|