• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 22893710013

10 Mar 2026 08:29AM UTC coverage: 91.148% (-1.8%) from 92.932%
22893710013

Pull #23032

github

web-flow
Merge c09ecdff4 into 2804a4673
Pull Request #23032: Bugfix: Add support for pull option in podman

87 of 93 new or added lines in 4 files covered. (93.55%)

1432 existing lines in 69 files now uncovered.

84014 of 92173 relevant lines covered (91.15%)

3.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.21
/src/python/pants/backend/docker/goals/package_image_podman_pull_test.py
1
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
"""Integration tests for Podman-specific pull policy behavior in DockerImageBuildPullOptionField."""
5

6
from __future__ import annotations
1✔
7

8
import pytest
1✔
9

10
from pants.backend.docker.goals.package_image import (
1✔
11
    DockerImageBuildProcess,
12
    DockerImageRefs,
13
    DockerPackageFieldSet,
14
    ImageRefRegistry,
15
    ImageRefTag,
16
    get_docker_image_build_process,
17
    rules,
18
)
19
from pants.backend.docker.subsystems.docker_options import DockerOptions
1✔
20
from pants.backend.docker.target_types import DockerImageTarget
1✔
21
from pants.backend.docker.util_rules.docker_binary import DockerBinary
1✔
22
from pants.backend.docker.util_rules.docker_build_args import rules as build_args_rules
1✔
23
from pants.backend.docker.util_rules.docker_build_env import rules as build_env_rules
1✔
24
from pants.engine.addresses import Address
1✔
25
from pants.engine.env_vars import EnvironmentVars
1✔
26
from pants.engine.fs import EMPTY_DIGEST
1✔
27
from pants.engine.target import InvalidFieldException, WrappedTarget
1✔
28
from pants.engine.unions import UnionMembership
1✔
29
from pants.testutil.option_util import create_subsystem
1✔
30
from pants.testutil.rule_runner import QueryRule, RuleRunner, run_rule_with_mocks
1✔
31
from pants.backend.docker.util_rules.docker_build_args import DockerBuildArgs
1✔
32
from pants.backend.docker.util_rules.docker_build_context import DockerBuildContext
1✔
33
from pants.backend.docker.util_rules.docker_build_env import DockerBuildEnvironment
1✔
34
from pants.util.value_interpolation import InterpolationContext, InterpolationValue
1✔
35

36

37
@pytest.fixture
1✔
38
def rule_runner() -> RuleRunner:
1✔
39
    return RuleRunner(
1✔
40
        rules=[
41
            *rules(),
42
            *build_args_rules(),
43
            *build_env_rules(),
44
            QueryRule(DockerOptions, []),
45
        ],
46
        target_types=[DockerImageTarget],
47
    )
48

49

50
def _make_image_refs(address: Address) -> DockerImageRefs:
1✔
51
    repository = address.target_name
1✔
52
    return DockerImageRefs(
1✔
53
        [
54
            ImageRefRegistry(
55
                registry=None,
56
                repository=repository,
57
                tags=(
58
                    ImageRefTag(
59
                        template="latest",
60
                        formatted="latest",
61
                        full_name=f"{repository}:latest",
62
                        uses_local_alias=False,
63
                    ),
64
                ),
65
            )
66
        ]
67
    )
68

69

70
def create_test_context(rule_runner: RuleRunner, pull_value=None):
1✔
71
    """Helper to create a mock build context and target with specific pull value."""
72
    # Create BUILD file with optional pull value
73
    # Python booleans need to be capitalized (True/False) in BUILD files
74
    build_content = "docker_image(name='test'"
1✔
75
    if pull_value is not None:
1✔
76
        if isinstance(pull_value, str):
1✔
77
            build_content += f", pull='{pull_value}'"
1✔
78
        else:
79
            # Convert bool to string with proper capitalization
NEW
80
            build_content += f", pull={str(pull_value)}"
×
81
    build_content += ")"
1✔
82

83
    rule_runner.write_files(
1✔
84
        {
85
            "test/BUILD": build_content,
86
            "test/Dockerfile": "FROM alpine:3.16\n",
87
        }
88
    )
89

90
    tgt = rule_runner.get_target(Address("test"))
1✔
91

92
    # Mock build context
93
    build_context = DockerBuildContext(
1✔
94
        build_args=DockerBuildArgs(),
95
        digest=EMPTY_DIGEST,
96
        dockerfile="test/Dockerfile",
97
        build_env=DockerBuildEnvironment(environment=EnvironmentVars()),
98
        interpolation_context=InterpolationContext.from_dict(
99
            {
100
                "tags": InterpolationValue({}),
101
            }
102
        ),
103
        copy_source_vs_context_source=(("test/Dockerfile", ""),),
104
        stages=(),
105
        upstream_image_ids=(),
106
    )
107

108
    return tgt, build_context
1✔
109

110

111
@pytest.mark.parametrize(
1✔
112
    "policy",
113
    ["always", "missing", "never", "newer"],
114
)
115
def test_podman_pull_string_policies(rule_runner: RuleRunner, policy: str) -> None:
1✔
116
    """Test that Podman accepts all valid string pull policies."""
117
    tgt, build_context = create_test_context(rule_runner, pull_value=policy)
1✔
118

119
    docker_options = create_subsystem(
1✔
120
        DockerOptions,
121
        registries={},
122
        default_repository="{name}",
123
        default_context_root="",
124
        build_args=[],
125
        build_target_stage=None,
126
        build_hosts=None,
127
        build_verbose=False,
128
        build_no_cache=False,
129
        use_buildx=False,
130
        env_vars=[],
131
    )
132

133
    # Use Podman binary
134
    podman_binary = DockerBinary(
1✔
135
        path="/bin/podman",
136
        fingerprint="test",
137
        extra_env={},
138
        extra_input_digests=None,
139
        is_podman=True,
140
    )
141

142
    address = Address("test")
1✔
143
    image_refs = _make_image_refs(address)
1✔
144

145
    result: DockerImageBuildProcess = run_rule_with_mocks(
1✔
146
        get_docker_image_build_process,
147
        rule_args=[
148
            DockerPackageFieldSet.create(tgt),
149
            docker_options,
150
            podman_binary,
151
        ],
152
        mock_calls={
153
            "pants.backend.docker.util_rules.docker_build_context.create_docker_build_context": lambda _req: build_context,
154
            "pants.engine.internals.graph.resolve_target": lambda _: WrappedTarget(tgt),
155
            "pants.backend.docker.goals.package_image.get_image_refs": lambda _: image_refs,
156
        },
157
        union_membership=UnionMembership.from_rules([]),
158
        show_warnings=False,
159
    )
160

161
    # Verify that the correct policy was used
162
    argv = result.process.argv
1✔
163
    expected_flag = f"--pull={policy}"
1✔
164
    assert expected_flag in argv, f"Expected '{expected_flag}' in {argv}"
1✔
165

166

167
def test_docker_pull_string_raises_error(rule_runner: RuleRunner) -> None:
1✔
168
    """Test that Docker backend raises error when given a string pull policy."""
169
    tgt, build_context = create_test_context(rule_runner, pull_value="always")
1✔
170

171
    docker_options = create_subsystem(
1✔
172
        DockerOptions,
173
        registries={},
174
        default_repository="{name}",
175
        default_context_root="",
176
        build_args=[],
177
        build_target_stage=None,
178
        build_hosts=None,
179
        build_verbose=False,
180
        build_no_cache=False,
181
        use_buildx=False,
182
        env_vars=[],
183
    )
184

185
    # Use Docker binary (not Podman)
186
    docker_binary = DockerBinary(
1✔
187
        path="/bin/docker",
188
        fingerprint="test",
189
        extra_env={},
190
        extra_input_digests=None,
191
        is_podman=False,
192
    )
193

194
    address = Address("test")
1✔
195
    image_refs = _make_image_refs(address)
1✔
196

197
    # Should raise InvalidFieldException
198
    with pytest.raises(InvalidFieldException) as exc_info:
1✔
199
        run_rule_with_mocks(
1✔
200
            get_docker_image_build_process,
201
            rule_args=[
202
                DockerPackageFieldSet.create(tgt),
203
                docker_options,
204
                docker_binary,
205
            ],
206
            mock_calls={
207
                "pants.backend.docker.util_rules.docker_build_context.create_docker_build_context": lambda _req: build_context,
208
                "pants.engine.internals.graph.resolve_target": lambda _: WrappedTarget(tgt),
209
                "pants.backend.docker.goals.package_image.get_image_refs": lambda _: image_refs,
210
            },
211
            union_membership=UnionMembership.from_rules([]),
212
            show_warnings=False,
213
        )
214

215
    assert "string pull policies are only supported by Podman" in str(exc_info.value)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc