mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-09 12:17:13 +00:00
Add registry.gitlab.com to the mirrorable registries so discovery yields the GitLab CNG images to the version updater and mirror sync. Seed the generic v2 tag scan with the OCI last cursor for v-prefixed pins and raise the page size to 1000: CNG repos carry tens of thousands of commit-sha tags that sort before the release tags, so an unseeded scan exhausted the page cap without reaching any semver tag. Pin every gitlab service version in meta/services.yml and drop the GITLAB_VERSION template override so services.yml is the single source for per-service versions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
161 lines
5.6 KiB
Python
161 lines
5.6 KiB
Python
from __future__ import annotations
|
|
|
|
import textwrap
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
from utils.cache.yaml import load_yaml_str
|
|
from utils.docker.image.discovery import iter_role_images
|
|
from utils.roles.mapping import ROLE_FILE_META_SERVICES
|
|
|
|
|
|
def _make_fs(files: dict[str, str]) -> dict[Path, str]:
|
|
return {Path(k): textwrap.dedent(v) for k, v in files.items()}
|
|
|
|
|
|
class TestIterRoleImagesMetaServices(unittest.TestCase):
|
|
"""iter_role_images reads meta/services.yml → services (any registry)."""
|
|
|
|
def _run(self, fs: dict[str, str]) -> list:
|
|
real_fs = _make_fs(fs)
|
|
|
|
def fake_glob(self, pattern: str):
|
|
return [p for p in real_fs if p.match(pattern)]
|
|
|
|
def fake_load(path: Path) -> dict:
|
|
|
|
content = real_fs.get(path, "")
|
|
return load_yaml_str(content) or {}
|
|
|
|
with (
|
|
patch.object(Path, "glob", fake_glob),
|
|
patch("utils.docker.image.discovery.load_yaml", side_effect=fake_load),
|
|
):
|
|
return list(iter_role_images(Path("/repo")))
|
|
|
|
def test_mcr_playwright_image(self):
|
|
refs = self._run(
|
|
{
|
|
f"roles/test-e2e-playwright/{ROLE_FILE_META_SERVICES}": """
|
|
playwright:
|
|
image: mcr.microsoft.com/playwright
|
|
version: v1.58.2-noble
|
|
""",
|
|
}
|
|
)
|
|
self.assertEqual(len(refs), 1)
|
|
ref = refs[0]
|
|
self.assertEqual(ref.role, "test-e2e-playwright")
|
|
self.assertEqual(ref.service, "playwright")
|
|
self.assertEqual(ref.name, "playwright")
|
|
self.assertEqual(ref.version, "v1.58.2-noble")
|
|
self.assertEqual(ref.registry, "mcr.microsoft.com")
|
|
self.assertEqual(ref.source, "mcr.microsoft.com/playwright:v1.58.2-noble")
|
|
self.assertEqual(ref.source_file, ROLE_FILE_META_SERVICES)
|
|
|
|
def test_ghcr_image_strips_registry_from_name(self):
|
|
refs = self._run(
|
|
{
|
|
f"roles/web-app-matrix/{ROLE_FILE_META_SERVICES}": """
|
|
matrix-chatgpt-bot:
|
|
image: ghcr.io/matrixgpt/matrix-chatgpt-bot
|
|
version: latest
|
|
""",
|
|
}
|
|
)
|
|
self.assertEqual(len(refs), 1)
|
|
ref = refs[0]
|
|
self.assertEqual(ref.name, "matrixgpt/matrix-chatgpt-bot")
|
|
self.assertEqual(ref.registry, "ghcr.io")
|
|
self.assertEqual(ref.source, "ghcr.io/matrixgpt/matrix-chatgpt-bot:latest")
|
|
self.assertEqual(ref.source_file, ROLE_FILE_META_SERVICES)
|
|
|
|
def test_missing_image_or_version_is_skipped(self):
|
|
refs = self._run(
|
|
{
|
|
f"roles/some-role/{ROLE_FILE_META_SERVICES}": """
|
|
no-version:
|
|
image: ghcr.io/foo/bar
|
|
no-image:
|
|
version: "1.0"
|
|
""",
|
|
}
|
|
)
|
|
self.assertEqual(refs, [])
|
|
|
|
def test_no_image_keys_yields_nothing(self):
|
|
refs = self._run(
|
|
{
|
|
f"roles/some-role/{ROLE_FILE_META_SERVICES}": """
|
|
some-svc:
|
|
lifecycle: beta
|
|
""",
|
|
}
|
|
)
|
|
self.assertEqual(refs, [])
|
|
|
|
def test_meta_services_ghcr_image(self):
|
|
refs = self._run(
|
|
{
|
|
f"roles/web-app-matrix/{ROLE_FILE_META_SERVICES}": """
|
|
matrix-chatgpt-bot:
|
|
image: ghcr.io/matrixgpt/matrix-chatgpt-bot
|
|
version: latest
|
|
""",
|
|
}
|
|
)
|
|
self.assertEqual(len(refs), 1)
|
|
ref = refs[0]
|
|
self.assertEqual(ref.role, "web-app-matrix")
|
|
self.assertEqual(ref.service, "matrix-chatgpt-bot")
|
|
self.assertEqual(ref.name, "matrixgpt/matrix-chatgpt-bot")
|
|
self.assertEqual(ref.registry, "ghcr.io")
|
|
self.assertEqual(ref.source, "ghcr.io/matrixgpt/matrix-chatgpt-bot:latest")
|
|
self.assertEqual(ref.source_file, ROLE_FILE_META_SERVICES)
|
|
|
|
def test_gitlab_registry_image_strips_registry_from_name(self):
|
|
refs = self._run(
|
|
{
|
|
f"roles/web-app-gitlab/{ROLE_FILE_META_SERVICES}": """
|
|
webservice:
|
|
image: registry.gitlab.com/gitlab-org/build/cng/gitlab-webservice-ce
|
|
version: v19.1.1
|
|
""",
|
|
}
|
|
)
|
|
self.assertEqual(len(refs), 1)
|
|
ref = refs[0]
|
|
self.assertEqual(ref.role, "web-app-gitlab")
|
|
self.assertEqual(ref.service, "webservice")
|
|
self.assertEqual(ref.name, "gitlab-org/build/cng/gitlab-webservice-ce")
|
|
self.assertEqual(ref.registry, "registry.gitlab.com")
|
|
self.assertEqual(
|
|
ref.source,
|
|
"registry.gitlab.com/gitlab-org/build/cng/gitlab-webservice-ce:v19.1.1",
|
|
)
|
|
self.assertEqual(ref.source_file, ROLE_FILE_META_SERVICES)
|
|
|
|
def test_opencode_gitlab_image_strips_registry_from_name(self):
|
|
refs = self._run(
|
|
{
|
|
f"roles/web-app-opentalk/{ROLE_FILE_META_SERVICES}": """
|
|
controller:
|
|
image: registry.opencode.de/opentalk/controller
|
|
version: v0.33.2
|
|
""",
|
|
}
|
|
)
|
|
self.assertEqual(len(refs), 1)
|
|
ref = refs[0]
|
|
self.assertEqual(ref.role, "web-app-opentalk")
|
|
self.assertEqual(ref.service, "controller")
|
|
self.assertEqual(ref.name, "opentalk/controller")
|
|
self.assertEqual(ref.registry, "registry.opencode.de")
|
|
self.assertEqual(ref.source, "registry.opencode.de/opentalk/controller:v0.33.2")
|
|
self.assertEqual(ref.source_file, ROLE_FILE_META_SERVICES)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|