From f2a0c0100ec9e3cad9a12ef5387488cf32f5a927 Mon Sep 17 00:00:00 2001 From: itsrez <35066771+whiteov3rflow@users.noreply.github.com> Date: Sun, 23 Aug 2026 22:51:12 +0200 Subject: [PATCH] fix: set image platform for builds on ARM64 --- nihil/cli/controller.py | 4 +++ tests/test_cli_controller.py | 68 ++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/nihil/cli/controller.py b/nihil/cli/controller.py index ff2db7c..4354a20 100644 --- a/nihil/cli/controller.py +++ b/nihil/cli/controller.py @@ -1223,6 +1223,10 @@ def _cmd_build(self, args) -> int: "--build-arg", "VERSION=local", "--build-arg", f"BUILD_DATE={build_date}", ] + from nihil.utils import get_image_platform + image_platform = get_image_platform() + if image_platform: + cmd.extend(["--platform", image_platform]) if getattr(args, "no_cache", False): cmd.append("--no-cache") cmd.append(str(source)) diff --git a/tests/test_cli_controller.py b/tests/test_cli_controller.py index 565a9fd..84bb843 100644 --- a/tests/test_cli_controller.py +++ b/tests/test_cli_controller.py @@ -70,3 +70,71 @@ def test_force_removes_running_container_then_image(self, mock_formatter): manager.remove_container.assert_called_once_with(ad_container, force=True) # L'image est ensuite supprimée avec force=True. manager.remove_image.assert_called_once_with(image_ref, force=True) + + +class TestBuildPlatform: + """Tests pour la plateforme passée à `docker build`.""" + + @staticmethod + def _make_controller(source): + from nihil.cli.controller import NihilController + + controller = NihilController.__new__(NihilController) + controller.config = SimpleNamespace(images_path=str(source)) + controller.formatter = MagicMock() + controller.formatter.info.side_effect = lambda message: message + controller.formatter.success.side_effect = lambda message: message + controller.formatter.error.side_effect = lambda message: message + return controller + + @staticmethod + def _run_build(controller, variant, tag=None): + args = SimpleNamespace( + variant=variant, + source=None, + tag=tag, + no_cache=False, + log=None, + ) + process = MagicMock() + process.stdout.read1.return_value = b"" + process.returncode = 0 + + with patch("subprocess.Popen", return_value=process) as popen: + assert controller._cmd_build(args) == 0 + + return popen.call_args.args[0] + + @pytest.mark.parametrize( + ("variant", "dockerfile"), + [ + ("full", "Dockerfile"), + ("blueteam", "Dockerfile.blueteam"), + ("test", "Dockerfile.test"), + ], + ) + def test_arm64_build_sets_amd64_platform(self, tmp_path, variant, dockerfile): + """Les variantes principales ciblent linux/amd64 sur ARM64.""" + (tmp_path / dockerfile).touch() + controller = self._make_controller(tmp_path) + + with patch("nihil.utils.get_image_platform", return_value="linux/amd64"): + command = self._run_build(controller, variant) + + assert command[:2] == ["docker", "build"] + assert command[command.index("--file") + 1] == str(tmp_path / dockerfile) + assert command[command.index("--tag") + 1] == f"nihil/{variant}:local" + assert command[command.index("--platform") + 1] == "linux/amd64" + assert command[-1] == str(tmp_path) + + def test_amd64_build_keeps_custom_tag_without_platform(self, tmp_path): + """Un build amd64 conserve le tag demandé sans forcer de plateforme.""" + (tmp_path / "Dockerfile").touch() + controller = self._make_controller(tmp_path) + + with patch("nihil.utils.get_image_platform", return_value=None): + command = self._run_build(controller, "full", tag="example/nihil:dev") + + assert "--platform" not in command + assert command[command.index("--tag") + 1] == "example/nihil:dev" + assert command[-1] == str(tmp_path)