diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py index 60caa101..d006ad47 100644 --- a/pre_commit/languages/docker_image.py +++ b/pre_commit/languages/docker_image.py @@ -23,9 +23,18 @@ def run_hook( require_serial: bool, color: bool, ) -> tuple[int, bytes]: # pragma: win32 no cover - cmd = docker_cmd(color=color) + lang_base.hook_cmd(entry, args) + cmd = lang_base.hook_cmd(entry, args) + + # To prevent duplicate simultaneous image pull attempts in `run_xargs`, we + # try to precache the Docker image by pulling it here first + try: + image_name = cmd[2 if cmd[0] == '--entrypoint' else 0] + lang_base.setup_cmd(prefix, ('docker', 'pull', image_name)) + except Exception: + pass + return lang_base.run_xargs( - cmd, + docker_cmd(color=color) + cmd, file_args, require_serial=require_serial, color=color, diff --git a/tests/languages/docker_image_test.py b/tests/languages/docker_image_test.py index 4f720600..0a0c49f1 100644 --- a/tests/languages/docker_image_test.py +++ b/tests/languages/docker_image_test.py @@ -1,5 +1,7 @@ from __future__ import annotations +from unittest.mock import patch + import pytest from pre_commit.languages import docker_image @@ -57,3 +59,35 @@ def test_docker_image_no_color_no_tty(tmp_path): color=False, ) assert ret == (0, b'root:x:0:\n') + + +@xfailif_windows # pragma: win32 no cover +@patch('pre_commit.lang_base.setup_cmd') +def test_docker_image_pre_pull_regular_entry(mock_setup, tmp_path): + ret = run_language( + tmp_path, + docker_image, + 'ubuntu:22.04 echo', + args=('hello hello world',), + ) + mock_setup.assert_called_once_with( + mock_setup.call_args[0][0], + ('docker', 'pull', 'ubuntu:22.04'), + ) + assert ret == (0, b'hello hello world\n') + + +@xfailif_windows # pragma: win32 no cover +@patch('pre_commit.lang_base.setup_cmd') +def test_docker_image_pre_pull_entrypoint_entry(mock_setup, tmp_path): + ret = run_language( + tmp_path, + docker_image, + '--entrypoint echo ubuntu:22.04', + args=('hello hello world',), + ) + mock_setup.assert_called_once_with( + mock_setup.call_args[0][0], + ('docker', 'pull', 'ubuntu:22.04'), + ) + assert ret == (0, b'hello hello world\n')