mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
feat(update): leave an image pin to the version source it declares
A pin that names its own upstream in an update: block was still collected by the image updater, which raises it to the newest tag of its registry. For a component of a release bundle that tag is not the bundle's, so the two updaters would propose different versions for the same line and such a pin had to carry nocheck: docker-version. The image updater now skips a version that declares a source for itself. The source resolver alone bumps it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
759a1aa4d0
commit
75460b95cd
4 files changed
+81
-2
No files matched your search
@@ -21,7 +21,9 @@ stalwart:
|
||||
```
|
||||
|
||||
`key` names the pinned key and defaults to `version`; an entity with several
|
||||
pins declares a list of such blocks. Types:
|
||||
pins declares a list of such blocks. An `image` + `version` pin that declares a
|
||||
source for `version` is bumped from that source alone, the Docker updater skips
|
||||
it. Types:
|
||||
|
||||
| `type` | Fields | Reads |
|
||||
| --------------- | --------------------- | -------------------------------------- |
|
||||
|
||||
@@ -5,7 +5,33 @@ import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from utils.cache.files import read_text
|
||||
from utils.update.docker import _registry_cursor, update_config_versions
|
||||
from utils.roles.mapping import ROLE_FILE_META_SERVICES
|
||||
from utils.update.docker import (
|
||||
_registry_cursor,
|
||||
collect_entries,
|
||||
sourced_services,
|
||||
update_config_versions,
|
||||
)
|
||||
|
||||
SOURCED = """bundled:
|
||||
image: example/app
|
||||
version: v1.0.0
|
||||
update:
|
||||
type: http_regex
|
||||
url: https://example.invalid/bundle
|
||||
pattern: "app:(v[0-9.]+)"
|
||||
tracked:
|
||||
image: example/side
|
||||
version: v2.0.0
|
||||
other_version: v3.0.0
|
||||
update:
|
||||
- key: other_version
|
||||
type: git_tags
|
||||
repository: https://example.invalid/side.git
|
||||
plain:
|
||||
image: example/plain
|
||||
version: v4.0.0
|
||||
"""
|
||||
|
||||
|
||||
class TestRegistryCursor(unittest.TestCase):
|
||||
@@ -16,6 +42,20 @@ class TestRegistryCursor(unittest.TestCase):
|
||||
self.assertIsNone(_registry_cursor("19.1.1"))
|
||||
|
||||
|
||||
class TestDeclaredSource(unittest.TestCase):
|
||||
def test_a_version_with_its_own_source_is_left_to_that_source(self) -> None:
|
||||
root = Path(tempfile.mkdtemp())
|
||||
config = root / "roles" / "web-app-example" / ROLE_FILE_META_SERVICES
|
||||
config.parent.mkdir(parents=True)
|
||||
config.write_text(SOURCED, encoding="utf-8")
|
||||
|
||||
self.assertEqual(sourced_services(config), {"bundled"})
|
||||
self.assertEqual(
|
||||
sorted(entry.service for entry in collect_entries(root)),
|
||||
["plain", "tracked"],
|
||||
)
|
||||
|
||||
|
||||
class TestUpdateDocker(unittest.TestCase):
|
||||
def test_update_config_versions_updates_only_target_services(self) -> None:
|
||||
original = """moodle:
|
||||
|
||||
@@ -105,3 +105,19 @@ def is_maintained(roles_root: Path, role: str) -> bool:
|
||||
"""
|
||||
lifecycle = get_role_lifecycle(roles_root / role, role_name=role)
|
||||
return lifecycle not in UNMAINTAINED_LIFECYCLES
|
||||
|
||||
|
||||
def declares_source(config: object, key: str) -> bool:
|
||||
"""Report whether a services entity names its own upstream for a pin.
|
||||
|
||||
Args:
|
||||
config: one entity of ``meta/services.yml``.
|
||||
key: the pinned key; an ``update:`` block without ``key`` names
|
||||
``version``.
|
||||
"""
|
||||
declared = config.get("update") if isinstance(config, dict) else None
|
||||
sources = declared if isinstance(declared, list) else [declared]
|
||||
return any(
|
||||
isinstance(source, dict) and source.get("key", "version") == key
|
||||
for source in sources
|
||||
)
|
||||
@@ -8,6 +8,9 @@ walker that rewrites the matching ``version:`` line.
|
||||
|
||||
Suppress a check by placing ``# nocheck: docker-version`` on the line
|
||||
directly above the ``version:`` key.
|
||||
|
||||
A ``version`` that names its own upstream in an ``update:`` block belongs to
|
||||
:mod:`utils.update.source` and is not collected here.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -28,6 +31,7 @@ import yaml
|
||||
|
||||
from utils.annotations.suppress import is_suppressed_at
|
||||
from utils.cache.files import read_text
|
||||
from utils.cache.yaml import load_yaml
|
||||
from utils.docker.image.discovery import iter_role_images
|
||||
from utils.docker.image.ref import (
|
||||
DOCKER_HUB_REGISTRIES,
|
||||
@@ -38,6 +42,7 @@ from utils.docker.image.ref import (
|
||||
from utils.docker.registry import fetch_registry_tags
|
||||
from utils.roles.mapping import ROLE_FILE_META_SERVICES
|
||||
from utils.update.base import (
|
||||
declares_source,
|
||||
is_maintained,
|
||||
is_semver,
|
||||
latest_semver,
|
||||
@@ -265,6 +270,20 @@ def suppressed_services(config_path: Path) -> set[str]:
|
||||
return names
|
||||
|
||||
|
||||
def sourced_services(config_path: Path) -> set[str]:
|
||||
"""Return service names whose ``version`` declares its own upstream.
|
||||
|
||||
Args:
|
||||
config_path: a role's ``meta/services.yml``.
|
||||
"""
|
||||
services = load_yaml(str(config_path)) or {}
|
||||
return {
|
||||
str(service)
|
||||
for service, config in services.items()
|
||||
if declares_source(config, "version")
|
||||
}
|
||||
|
||||
|
||||
def collect_entries(repo_root: Path) -> list[DockerImageVersionEntry]:
|
||||
roles_root = repo_root / "roles"
|
||||
entries: list[DockerImageVersionEntry] = []
|
||||
@@ -280,6 +299,8 @@ def collect_entries(repo_root: Path) -> list[DockerImageVersionEntry]:
|
||||
config_path = roles_root / ref.role / ROLE_FILE_META_SERVICES
|
||||
if ref.service in suppressed_services(config_path):
|
||||
continue
|
||||
if ref.service in sourced_services(config_path):
|
||||
continue
|
||||
|
||||
if ref.registry == "docker.io":
|
||||
image = ref.name
|
||||
|
||||
Reference in new issue
Block a user