Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ COPY dfupdate.py /dfupdate.py

COPY docker-entrypoint.sh /docker-entrypoint.sh

ENV DFUPDATE_VERSION 2.2.1
ENV DFUPDATE_VERSION 2.2.2
ENV REQUESTS_VERSION 2.32.5
ENV TENACITY_VERSION 9.1.2
ENV DOCKERFILE_PARSE_VERSION 2.0.1
Expand Down
33 changes: 31 additions & 2 deletions dfupdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,30 @@ def _update_env_value(self, env_name: str, new_value: str) -> bool:
)
return changed

def _substitute_version_tokens(
self, text: str | None, sw: str, new_ver: str, current_example: str
) -> str:
"""
Replace common version placeholders with the new version.
Supports ${SW_VERSION}, $SW_VERSION, and the literal current version string.
"""
if not text:
return ""
sw_upper = sw.upper()
sw_lower = sw.lower()
placeholders = [
f"${{{sw_upper}_VERSION}}",
f"${sw_upper}_VERSION",
f"${{{sw_lower}_VERSION}}",
f"${sw_lower}_VERSION",
]
result = text
for placeholder in placeholders:
result = result.replace(placeholder, new_ver)
if current_example:
result = result.replace(current_example, new_ver)
return result

def _get_env_value(
self, env_name: str, stage_index: int | None = None
) -> str | None:
Expand Down Expand Up @@ -492,8 +516,13 @@ def update_software(self, sw: str, new_ver: str, current_versions: set[str]):
df_sha = self._get_env_value(f"{sw}_SHA256", stage_hint)
if df_url and df_filename and df_sha:
logger.info("Found remote URL, fetching and calculating new shasum")
full_url = df_url + "/" + df_filename
full_url = full_url.replace(current_example, new_ver)
url_template = self._substitute_version_tokens(
df_url, sw, new_ver, current_example
)
filename_template = self._substitute_version_tokens(
df_filename, sw, new_ver, current_example
)
full_url = url_template.rstrip("/") + "/" + filename_template.lstrip("/")
logger.info("Retrieving new SHA256 for %s from %s", sw, full_url)
new_sha = get_remote_sha(full_url)
if new_sha:
Expand Down
36 changes: 33 additions & 3 deletions test_dfupdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def test_update_base_multi_stage(self):
self.assertIn("FROM python:3.11 AS builder", content)
self.assertIn("FROM alpine:3.19", content)

@mock.patch("dfupdate.get_remote_sha", return_value="deadbeef")
@mock.patch("dfupdate.get_remote_sha", return_value="jytncge6")
def test_check_software_updates_across_stages(self, _msha):
self._write_dockerfile(
"FROM python:3.10 AS builder\n"
Expand All @@ -148,8 +148,38 @@ def test_check_software_updates_across_stages(self, _msha):
with open(self.dockerfile_path, "r", encoding="utf8") as fh:
content = fh.read()
self.assertEqual(content.count("FOO_VERSION=2.0"), 2)
self.assertIn("FOO_SHA256=deadbeef", content)
self.assertIn("FOO_SHA256 deadbeef", content)
self.assertIn("FOO_SHA256=jytncge6", content)
self.assertIn("FOO_SHA256 jytncge6", content)

@mock.patch("dfupdate.get_remote_sha", return_value="jytncge6")
def test_update_replaces_version_placeholders_in_url_and_filename(self, msha):
self._write_dockerfile(
"FROM alpine\n"
"ENV UV_VERSION=0.9.15\n"
"ENV UV_URL=https://github.com/astral-sh/uv/releases/download/${UV_VERSION}\n"
"ENV UV_FILENAME=uv-$UV_VERSION.tar.gz\n"
"ENV UV_SHA256=old\n"
)
with open(self.nvchecker_path, "w", encoding="utf8") as fh:
json.dump({"UV": {"version": "0.9.17"}}, fh)
self.updater.update()
used_url = msha.call_args.args[0]
self.assertNotIn("${UV_VERSION}", used_url)
self.assertNotIn("$UV_VERSION", used_url)
self.assertIn("0.9.17", used_url)
with open(self.dockerfile_path, "r", encoding="utf8") as fh:
content = fh.read()
self.assertIn("UV_VERSION=0.9.17", content)
self.assertIn("UV_SHA256=jytncge6", content)

def test_update_detects_newer_version_and_writes(self):
self._write_dockerfile("FROM alpine\nENV UV_VERSION=0.9.15\n")
with open(self.nvchecker_path, "w", encoding="utf8") as fh:
json.dump({"UV": {"version": "0.9.17"}}, fh)
self.updater.update()
with open(self.dockerfile_path, "r", encoding="utf8") as fh:
content = fh.read()
self.assertIn("UV_VERSION=0.9.17", content)


class TestParseArgs(unittest.TestCase):
Expand Down