This is an automated email from the ASF dual-hosted git repository. potiuk pushed a commit to branch pin-os-deps-image-layer in repository https://gitbox.apache.org/repos/asf/airflow.git
commit c70b19ad35d0b300879ec4816fb51f8d3b4982ef Author: Jarek Potiuk <[email protected]> AuthorDate: Sun Nov 1 14:02:22 2026 +0100 Hash the database client scripts and keys into the OS-dependencies image tag install_os_dependencies.sh now runs the database client scripts, so a change to only one of them, or to a repository key, must produce a new OS-dependencies image. Otherwise the daily build sees the image as already built while every CI and PROD build's marker misses, and each reinstalls from the live repositories until the base image happens to change. Generated-by: Claude Opus 5 --- .../airflow_breeze/commands/release_management_commands.py | 14 +++++++++++++- dev/breeze/tests/test_os_deps_images.py | 10 ++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/dev/breeze/src/airflow_breeze/commands/release_management_commands.py b/dev/breeze/src/airflow_breeze/commands/release_management_commands.py index 8213d049c7f..7c8a5fa021c 100644 --- a/dev/breeze/src/airflow_breeze/commands/release_management_commands.py +++ b/dev/breeze/src/airflow_breeze/commands/release_management_commands.py @@ -5444,10 +5444,22 @@ def get_os_deps_image_build_args( return build_args +OS_DEPS_DATABASE_CLIENT_SCRIPTS = ("common.sh", "install_mysql.sh", "install_mssql.sh", "install_postgres.sh") + + def compute_os_deps_image_inputs_hash(image_type: OsDepsImageType, build_args: dict[str, str]) -> str: """Hash what an OS-dependencies image is built from apart from its base image, whose tag it gets.""" inputs = hashlib.sha256() - inputs.update(INSTALL_OS_DEPENDENCIES_SCRIPT_PATH.read_bytes()) + scripts_dir = INSTALL_OS_DEPENDENCIES_SCRIPT_PATH.parent + # The same files the marker in install_os_dependencies.sh hashes: a change to any of them must + # produce a new image, not only a reinstall on top of the pinned one. + for path in [ + INSTALL_OS_DEPENDENCIES_SCRIPT_PATH, + *(scripts_dir / name for name in OS_DEPS_DATABASE_CLIENT_SCRIPTS), + *sorted((scripts_dir / "keys").glob("*")), + ]: + inputs.update(f"{path.relative_to(scripts_dir)}\n".encode()) + inputs.update(path.read_bytes()) dockerfile_content = (AIRFLOW_ROOT_PATH / image_type.dockerfile).read_text() inputs.update(extract_dockerfile_stage(dockerfile_content, image_type.target).encode()) for name, value in sorted(build_args.items()): diff --git a/dev/breeze/tests/test_os_deps_images.py b/dev/breeze/tests/test_os_deps_images.py index 95cb8d5daea..fd6b05302c1 100644 --- a/dev/breeze/tests/test_os_deps_images.py +++ b/dev/breeze/tests/test_os_deps_images.py @@ -237,6 +237,8 @@ def test_os_deps_images_install_what_the_default_image_builds_pass(image_type, p "change", [ pytest.param("script", id="script"), + pytest.param("client-script", id="client-script"), + pytest.param("key", id="key"), pytest.param("stage", id="stage"), pytest.param("build-arg", id="build-arg"), ], @@ -247,6 +249,10 @@ def test_os_deps_image_inputs_hash_changes_with_its_inputs(change, tmp_path): ) script = tmp_path / "install_os_dependencies.sh" script.write_text("echo install\n") + for name in ("common.sh", "install_mysql.sh", "install_mssql.sh", "install_postgres.sh"): + (tmp_path / name).write_text(f"echo {name}\n") + (tmp_path / "keys").mkdir() + (tmp_path / "keys" / "repo.asc").write_text("key\n") build_args = {"BASE_IMAGE": "base@sha256:1", "AIRFLOW_PYTHON_VERSION": "3.12.1"} with ( mock.patch(f"{PATCH_PREFIX}.AIRFLOW_ROOT_PATH", tmp_path), @@ -258,6 +264,10 @@ def test_os_deps_image_inputs_hash_changes_with_its_inputs(change, tmp_path): ) if change == "script": script.write_text("echo install more\n") + elif change == "client-script": + (tmp_path / "install_mysql.sh").write_text("echo install_mysql.sh 8.4\n") + elif change == "key": + (tmp_path / "keys" / "repo.asc").write_text("rotated key\n") elif change == "stage": (tmp_path / "Dockerfile.ci").write_text( "FROM ${CI_OS_DEPS_IMAGE} as ci-os-deps\nRUN false\nFROM x as main\n"
