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

pantsbuild / pants / 25441711719

06 May 2026 02:31PM UTC coverage: 92.915%. Remained the same
25441711719

push

github

web-flow
use sha pin (with comment) format for generated actions (#23312)

Per the GitHub Action best practices we recently enabled at #23249, we
should pin each action to a SHA so that the reference is actually
immutable.

This will -- I hope -- knock out a large chunk of the 421 alerts we
currently get from zizmor. The next followup would then be upgrades and
harmonizing the generated and none-generated pins.

Notice: This idea was suggested by Claude while going over pinact output
and I was surprised to see that post processing the yaml wasn't too
gross.

92206 of 99237 relevant lines covered (92.91%)

4.04 hits per line

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

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

4
from __future__ import annotations
10✔
5

6
import os
10✔
7
import re
10✔
8
from abc import ABC, abstractmethod
10✔
9
from collections.abc import Callable, Iterator
10✔
10
from dataclasses import dataclass
10✔
11
from enum import Enum
10✔
12
from typing import ClassVar, cast, final
10✔
13

14
from pants.backend.docker.registries import ALL_DEFAULT_REGISTRIES
10✔
15
from pants.backend.docker.subsystems.docker_options import DockerOptions
10✔
16
from pants.base.build_environment import get_buildroot
10✔
17
from pants.core.goals.package import OutputPathField
10✔
18
from pants.core.goals.run import RestartableField
10✔
19
from pants.engine.addresses import Address
10✔
20
from pants.engine.collection import Collection
10✔
21
from pants.engine.environment import EnvironmentName
10✔
22
from pants.engine.fs import GlobExpansionConjunction, GlobMatchErrorBehavior
10✔
23
from pants.engine.rules import collect_rules, rule
10✔
24
from pants.engine.target import (
10✔
25
    COMMON_TARGET_FIELDS,
26
    AllTargets,
27
    AsyncFieldMixin,
28
    BoolField,
29
    Dependencies,
30
    DictStringToStringField,
31
    Field,
32
    InvalidFieldException,
33
    ListOfDictStringToStringField,
34
    OptionalSingleSourceField,
35
    StringField,
36
    StringSequenceField,
37
    Target,
38
    Targets,
39
)
40
from pants.engine.unions import union
10✔
41
from pants.util.docutil import bin_name, doc_url
10✔
42
from pants.util.frozendict import FrozenDict
10✔
43
from pants.util.strutil import help_text, softwrap
10✔
44

45
# Common help text to be applied to each field that supports value interpolation.
46
_interpolation_help = (
10✔
47
    "{kind} may use placeholders in curly braces to be interpolated. The placeholders are derived "
48
    "from various sources, such as the Dockerfile instructions and build args."
49
)
50

51

52
class DockerImageBuildArgsField(StringSequenceField):
10✔
53
    alias = "extra_build_args"
10✔
54
    default = ()
10✔
55
    help = help_text(
10✔
56
        """
57
        Build arguments (`--build-arg`) to use when building this image.
58
        Entries are either strings in the form `ARG_NAME=value` to set an explicit value;
59
        or just `ARG_NAME` to copy the value from Pants's own environment.
60

61
        Use `[docker].build_args` to set default build args for all images.
62
        """
63
    )
64

65

66
class DockerImageContextRootField(StringField):
10✔
67
    alias = "context_root"
10✔
68
    help = help_text(
10✔
69
        """
70
        Specify which directory to use as the Docker build context root. This affects the file
71
        paths to use for the `COPY` and `ADD` instructions. For example, whether
72
        `COPY files/f.txt` should look for the file relative to the build root:
73
        `<build root>/files/f.txt` vs relative to the BUILD file:
74
        `<build root>/path_to_build_file/files/f.txt`.
75

76
        Specify the `context_root` path as `files` for relative to build root, or as `./files`
77
        for relative to the BUILD file.
78

79
        If `context_root` is not specified, it defaults to `[docker].default_context_root`.
80
        """
81
    )
82

83
    @classmethod
10✔
84
    def compute_value(cls, raw_value: str | None, address: Address) -> str | None:
10✔
85
        value_or_default = super().compute_value(raw_value, address=address)
9✔
86
        if isinstance(value_or_default, str) and value_or_default.startswith("/"):
9✔
87
            val = value_or_default.strip("/")
1✔
88
            raise InvalidFieldException(
1✔
89
                softwrap(
90
                    f"""
91
                    The `{cls.alias}` field in target {address} must be a relative path, but was
92
                    {value_or_default!r}. Use {val!r} for a path relative to the build root, or
93
                    {"./" + val!r} for a path relative to the BUILD file
94
                    (i.e. {os.path.join(address.spec_path, val)!r}).
95
                    """
96
                )
97
            )
98
        return value_or_default
9✔
99

100

101
class DockerImageSourceField(OptionalSingleSourceField):
10✔
102
    none_is_valid_value = True
10✔
103
    default = "Dockerfile"
10✔
104

105
    # When the default glob value is in effect, we don't want the normal glob match error behavior
106
    # to kick in for a missing Dockerfile, in case there are `instructions` provided, in which case
107
    # we generate the Dockerfile instead. If there are no `instructions`, or there are both
108
    # `instructions` and a Dockerfile hydrated from the `source` glob, we error out with a message
109
    # to the user.
110
    default_glob_match_error_behavior = GlobMatchErrorBehavior.ignore
10✔
111

112
    help = help_text(
10✔
113
        """
114
        The Dockerfile to use when building the Docker image.
115

116
        Use the `instructions` field instead if you prefer not having the Dockerfile in your
117
        source tree.
118
        """
119
    )
120

121

122
class DockerImageInstructionsField(StringSequenceField):
10✔
123
    alias = "instructions"
10✔
124
    required = False
10✔
125
    help = help_text(
10✔
126
        """
127
        The `Dockerfile` content, typically one instruction per list item.
128

129
        Use the `source` field instead if you prefer having the Dockerfile in your source tree.
130

131
        Example:
132

133
            # example/BUILD
134
            docker_image(
135
              instructions=[
136
                "FROM base/image:1.0",
137
                "RUN echo example",
138
              ],
139
            )
140
        """
141
    )
142

143

144
class DockerImageTagsField(StringSequenceField):
10✔
145
    alias = "image_tags"
10✔
146
    default = ("latest",)
10✔
147
    help = help_text(
10✔
148
        f"""
149

150
        Any tags to apply to the Docker image name (the version is usually applied as a tag).
151

152
        {_interpolation_help.format(kind="tag")}
153

154
        See {doc_url("docs/docker/tagging-docker-images")}.
155
        """
156
    )
157

158

159
class DockerImageTargetStageField(StringField):
10✔
160
    alias = "target_stage"
10✔
161
    help = help_text(
10✔
162
        """
163
        Specify target build stage, rather than building the entire `Dockerfile`.
164

165
        When using multi-stage build, you may name your stages, and can target them when building
166
        to only selectively build a certain stage. See also the `--docker-build-target-stage`
167
        option.
168

169
        Read more about [multi-stage Docker builds](https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage)
170
        """
171
    )
172

173

174
class DockerImageDependenciesField(Dependencies):
10✔
175
    supports_transitive_excludes = True
10✔
176

177

178
class DockerImageRegistriesField(StringSequenceField):
10✔
179
    alias = "registries"
10✔
180
    default = (ALL_DEFAULT_REGISTRIES,)
10✔
181
    help = help_text(
10✔
182
        """
183
        List of addresses or configured aliases to any Docker registries to use for the
184
        built image.
185

186
        The address is a domain name with optional port for your registry, and any registry
187
        aliases are prefixed with `@` for addresses in the `[docker].registries` configuration
188
        section.
189

190
        By default, all configured registries with `default = true` are used.
191

192
        Example:
193

194
            # pants.toml
195
            [docker.registries.my-registry-alias]
196
            address = "myregistrydomain:port"
197
            default = false # optional
198

199
            # example/BUILD
200
            docker_image(
201
                registries = [
202
                    "@my-registry-alias",
203
                    "myregistrydomain:port",
204
                ],
205
            )
206

207
        The above example shows two valid `registry` options: using an alias to a configured
208
        registry and the address to a registry verbatim in the BUILD file.
209
        """
210
    )
211

212

213
class DockerImageRepositoryField(StringField):
10✔
214
    alias = "repository"
10✔
215
    help = help_text(
10✔
216
        f"""
217
        The repository name for the Docker image. e.g. `"<repository>/<name>"`.
218

219
        It uses the `[docker].default_repository` by default.
220

221
        {_interpolation_help.format(kind="Repository")}
222

223
        Additional placeholders for the repository field are: `name`, `directory`,
224
        `parent_directory`, and `default_repository`.
225

226
        Registries may also configure the repository value for specific registries.
227

228
        See the documentation for `[docker].default_repository` for more information.
229
        """
230
    )
231

232

233
class DockerImageSkipPushField(BoolField):
10✔
234
    alias = "skip_push"
10✔
235
    default = False
10✔
236
    help = f"If true, do not push this image to registries when running `{bin_name()} publish`."
10✔
237

238

239
OptionValueFormatter = Callable[[str], str]
10✔
240

241

242
class DockerBuildOptionFieldMixin(ABC):
10✔
243
    """Inherit this mixin class to provide options to `docker build`."""
244

245
    docker_build_option: ClassVar[str]
10✔
246

247
    @abstractmethod
10✔
248
    def option_values(
10✔
249
        self, *, value_formatter: OptionValueFormatter, global_build_hosts_options: dict
250
    ) -> Iterator[str]:
251
        """Subclasses must implement this, to turn their `self.value` into none, one or more option
252
        values."""
253

254
    @final
10✔
255
    def options(
10✔
256
        self, value_formatter: OptionValueFormatter, global_build_hosts_options
257
    ) -> Iterator[str]:
258
        for value in self.option_values(
4✔
259
            value_formatter=value_formatter, global_build_hosts_options=global_build_hosts_options
260
        ):
261
            yield from (self.docker_build_option, value)
1✔
262

263

264
class DockerImageBuildImageLabelsOptionField(DockerBuildOptionFieldMixin, DictStringToStringField):
10✔
265
    alias = "image_labels"
10✔
266
    help = help_text(
10✔
267
        f"""
268
        Provide image metadata.
269

270
        {_interpolation_help.format(kind="Label value")}
271

272
        See [Docker labels](https://docs.docker.com/config/labels-custom-metadata/#manage-labels-on-objects)
273
        for more information.
274
        """
275
    )
276
    docker_build_option = "--label"
10✔
277

278
    def option_values(self, value_formatter: OptionValueFormatter, **kwargs) -> Iterator[str]:
10✔
279
        for label, value in (self.value or {}).items():
4✔
280
            yield f"{label}={value_formatter(value)}"
1✔
281

282

283
class DockerImageBuildImageExtraHostsField(DockerBuildOptionFieldMixin, DictStringToStringField):
10✔
284
    alias = "extra_build_hosts"
10✔
285
    help = help_text(
10✔
286
        """
287
        Extra hosts entries to be added to a container's `/etc/hosts` file.
288

289
        Use `[docker].build_hosts` to set default host entries for all images.
290
        """
291
    )
292
    docker_build_option = "--add-host"
10✔
293

294
    def option_values(
10✔
295
        self, value_formatter: OptionValueFormatter, global_build_hosts_options: dict = {}
296
    ) -> Iterator[str]:
297
        if self.value:
4✔
298
            merged_values = {**global_build_hosts_options, **self.value}
1✔
299
            for label, value in merged_values.items():
1✔
300
                yield f"{label}:{value_formatter(value)}"
1✔
301

302

303
class DockerBuildOptionFieldMultiValueDictMixin(DictStringToStringField):
10✔
304
    """Inherit this mixin class to provide options in the form of `--flag=key1=value1,key2=value2`
305
    to `docker build`."""
306

307
    docker_build_option: ClassVar[str]
10✔
308

309
    @final
10✔
310
    def options(self, value_formatter: OptionValueFormatter, **kwargs) -> Iterator[str]:
10✔
311
        if self.value:
1✔
312
            yield f"{self.docker_build_option}=" + ",".join(
1✔
313
                f"{key}={value_formatter(value)}" for key, value in self.value.items()
314
            )
315

316

317
class DockerBuildOptionFieldListOfMultiValueDictMixin(ListOfDictStringToStringField):
10✔
318
    """Inherit this mixin class to provide multiple key-value options to docker build:
319

320
    `--flag=key1=value1,key2=value2 --flag=key3=value3,key4=value4`
321
    """
322

323
    docker_build_option: ClassVar[str]
10✔
324

325
    @final
10✔
326
    def options(self, value_formatter: OptionValueFormatter, **kwargs) -> Iterator[str]:
10✔
327
        if self.value:
1✔
328
            for item in self.value:
1✔
329
                yield f"{self.docker_build_option}=" + ",".join(
1✔
330
                    f"{key}={value_formatter(value)}" for key, value in item.items()
331
                )
332

333

334
class DockerBuildKitOptionField:
10✔
335
    """Mixin to indicate a BuildKit-specific option."""
336

337
    @abstractmethod
338
    def options(self, value_formatter: OptionValueFormatter) -> Iterator[str]: ...
339

340
    required_help = "This option requires BuildKit to be enabled via the Docker subsystem options."
10✔
341

342

343
class DockerImageBuildImageCacheToField(
10✔
344
    DockerBuildOptionFieldMultiValueDictMixin, DictStringToStringField, DockerBuildKitOptionField
345
):
346
    alias = "cache_to"
10✔
347
    help = help_text(
10✔
348
        f"""
349
        Export image build cache to an external cache destination.
350

351
        Note that Docker [supports](https://docs.docker.com/build/cache/backends/#multiple-caches)
352
        multiple cache sources - Pants will pass these as multiple `--cache_from` arguments to the
353
        Docker CLI. Docker will only use the first cache hit (i.e. the image exists) in the build.
354

355
        {DockerBuildKitOptionField.required_help}
356

357
        Example:
358

359
            docker_image(
360
                name="example-local-cache-backend",
361
                cache_to={{
362
                    "type": "local",
363
                    "dest": "/tmp/docker-cache/example"
364
                }},
365
                cache_from=[{{
366
                    "type": "local",
367
                    "src": "/tmp/docker-cache/example"
368
                }}]
369
            )
370

371
        {_interpolation_help.format(kind="Values")}
372
        """
373
    )
374
    docker_build_option = "--cache-to"
10✔
375

376

377
class DockerImageBuildImageCacheFromField(
10✔
378
    DockerBuildOptionFieldListOfMultiValueDictMixin,
379
    ListOfDictStringToStringField,
380
    DockerBuildKitOptionField,
381
):
382
    alias = "cache_from"
10✔
383
    help = help_text(
10✔
384
        f"""
385
        Use external cache sources when building the image.
386

387
        {DockerBuildKitOptionField.required_help}
388

389
        Example:
390

391
            docker_image(
392
                name="example-local-cache-backend",
393
                cache_to={{
394
                    "type": "local",
395
                    "dest": "/tmp/docker-cache/primary"
396
                }},
397
                cache_from=[
398
                    {{
399
                        "type": "local",
400
                        "src": "/tmp/docker-cache/primary"
401
                    }},
402
                    {{
403
                        "type": "local",
404
                        "src": "/tmp/docker-cache/secondary"
405
                    }}
406
                ]
407
            )
408

409
        {_interpolation_help.format(kind="Values")}
410
        """
411
    )
412
    docker_build_option = "--cache-from"
10✔
413

414

415
class DockerImageBuildImageOutputField(
10✔
416
    DockerBuildOptionFieldMultiValueDictMixin, DictStringToStringField, DockerBuildKitOptionField
417
):
418
    alias = "output"
10✔
419
    default = FrozenDict({"type": "docker"})
10✔
420
    help = help_text(
10✔
421
        f"""
422
        Sets the export action for the build result.
423

424
        {DockerBuildKitOptionField.required_help}
425

426
        When using `pants publish` to publish Docker images to a registry, the output type
427
        must be 'docker', as `publish` expects that the built images exist in the local
428
        image store.
429

430
        {_interpolation_help.format(kind="Values")}
431
        """
432
    )
433
    docker_build_option = "--output"
10✔
434

435

436
class DockerImageOutputFilesField(StringSequenceField):
10✔
437
    alias = "output_files"
10✔
438
    default = ()
10✔
439
    help = help_text(
10✔
440
        """
441
        Files to capture from a BuildKit local output export, relative to the build root.
442

443
        When this field or `output_directories` is set, Pants overrides the default Docker build
444
        output with `--output=type=local,dest=.` and captures only the requested files and
445
        directories as the package digest.
446

447
        Use `target_stage` to capture output from a specific Dockerfile stage.
448
        """
449
    )
450

451

452
class DockerImageOutputDirectoriesField(StringSequenceField):
10✔
453
    alias = "output_directories"
10✔
454
    default = ()
10✔
455
    help = help_text(
10✔
456
        """
457
        Directories to capture from a BuildKit local output export, relative to the build root.
458

459
        When this field or `output_files` is set, Pants overrides the default Docker build output
460
        with `--output=type=local,dest=.` and captures only the requested files and directories as
461
        the package digest.
462

463
        Use `target_stage` to capture output from a specific Dockerfile stage.
464
        """
465
    )
466

467

468
class DockerImageOutputsMatchModeValue(Enum):
10✔
469
    ALL = "all"
10✔
470
    ALL_WARN = "all_warn"
10✔
471
    AT_LEAST_ONE = "at_least_one"
10✔
472
    AT_LEAST_ONE_WARN = "at_least_one_warn"
10✔
473
    ALLOW_EMPTY = "allow_empty"
10✔
474

475
    @property
10✔
476
    def glob_match_error_behavior(self) -> GlobMatchErrorBehavior:
10✔
477
        if self in (
1✔
478
            DockerImageOutputsMatchModeValue.ALL,
479
            DockerImageOutputsMatchModeValue.AT_LEAST_ONE,
480
        ):
481
            return GlobMatchErrorBehavior.error
1✔
482
        return GlobMatchErrorBehavior.warn
1✔
483

484
    @property
10✔
485
    def glob_expansion_conjunction(self) -> GlobExpansionConjunction | None:
10✔
486
        if self in (
1✔
487
            DockerImageOutputsMatchModeValue.ALL,
488
            DockerImageOutputsMatchModeValue.ALL_WARN,
489
        ):
490
            return GlobExpansionConjunction.all_match
1✔
491
        if self in (
1✔
492
            DockerImageOutputsMatchModeValue.AT_LEAST_ONE,
493
            DockerImageOutputsMatchModeValue.AT_LEAST_ONE_WARN,
494
        ):
495
            return GlobExpansionConjunction.any_match
×
496
        return None
1✔
497

498

499
class DockerImageOutputsMatchModeField(StringField):
10✔
500
    alias = "outputs_match_mode"
10✔
501
    default = DockerImageOutputsMatchModeValue.ALL_WARN.value
10✔
502
    help = help_text(
10✔
503
        """
504
        Configure whether all, or some, of the values in the `output_files` and
505
        `output_directories` fields must actually match outputs from the Docker build.
506

507
        Valid values are:
508

509
        - `all_warn`: Log a warning if any glob fails to match an output. (In other words, all
510
        globs must match to avoid a warning.) This is the default value.
511

512
        - `all`: Ensure all globs match an output or else raise an error.
513

514
        - `at_least_one_warn`: Log a warning if none of the globs match an output.
515

516
        - `at_least_one`: Ensure at least one glob matches an output or else raise an error.
517

518
        - `allow_empty`: Allow empty digests (which means nothing was captured). This disables
519
        checking that globs match outputs.
520
        """
521
    )
522
    valid_choices = DockerImageOutputsMatchModeValue
10✔
523

524
    @property
10✔
525
    def enum_value(self) -> DockerImageOutputsMatchModeValue:
10✔
526
        return DockerImageOutputsMatchModeValue(self.value)
1✔
527

528

529
class DockerImageBuildSecretsOptionField(
10✔
530
    AsyncFieldMixin, DockerBuildOptionFieldMixin, DictStringToStringField
531
):
532
    alias = "secrets"
10✔
533
    help = help_text(
10✔
534
        """
535
        Secret files to expose to the build (only if BuildKit enabled).
536

537
        Secrets may use absolute paths, or paths relative to your build root, or the BUILD file
538
        if prefixed with `./`. Paths to your home directory will be automatically expanded.
539
        The id should be valid as used by the Docker build `--secret` option.
540
        See [Docker secrets](https://docs.docker.com/engine/swarm/secrets/) for more
541
        information.
542

543
        Example:
544

545
            docker_image(
546
                secrets={
547
                    "mysecret": "/var/secrets/some-secret",
548
                    "repo-secret": "src/proj/secrets/some-secret",
549
                    "home-dir-secret": "~/.config/some-secret",
550
                    "target-secret": "./secrets/some-secret",
551
                }
552
            )
553
        """
554
    )
555

556
    docker_build_option = "--secret"
10✔
557

558
    def option_values(self, **kwargs) -> Iterator[str]:
10✔
559
        # os.path.join() discards preceding parts if encountering an abs path, e.g. if the secret
560
        # `path` is an absolute path, the `buildroot` and `spec_path` will not be considered.  Also,
561
        # an empty path part is ignored.
562
        for secret, path in (self.value or {}).items():
5✔
563
            full_path = os.path.join(
2✔
564
                get_buildroot(),
565
                self.address.spec_path if re.match(r"\.{1,2}/", path) else "",
566
                os.path.expanduser(path),
567
            )
568

569
            yield f"id={secret},src={os.path.normpath(full_path)}"
2✔
570

571

572
class DockerImageBuildSSHOptionField(DockerBuildOptionFieldMixin, StringSequenceField):
10✔
573
    alias = "ssh"
10✔
574
    default = ()
10✔
575
    help = help_text(
10✔
576
        """
577
        SSH agent socket or keys to expose to the build (only if BuildKit enabled)
578
        (format: `default|<id>[=<socket>|<key>[,<key>]]`)
579

580
        The exposed agent and/or keys can then be used in your `Dockerfile` by mounting them in
581
        your `RUN` instructions:
582

583
            RUN --mount=type=ssh ...
584

585
        See [Docker documentation](https://docs.docker.com/develop/develop-images/build_enhancements/#using-ssh-to-access-private-data-in-builds)
586
        for more information.
587
        """
588
    )
589

590
    docker_build_option = "--ssh"
10✔
591

592
    def option_values(self, **kwargs) -> Iterator[str]:
10✔
593
        yield from cast("tuple[str]", self.value)
4✔
594

595

596
class DockerBuildOptionFieldValueMixin(Field):
10✔
597
    """Inherit this mixin class to provide unary options (i.e. option in the form of `--flag=value`)
598
    to `docker build`."""
599

600
    docker_build_option: ClassVar[str]
10✔
601

602
    @final
10✔
603
    def options(self, *args, **kwargs) -> Iterator[str]:
10✔
604
        if self.value is not None:
4✔
605
            yield f"{self.docker_build_option}={self.value}"
4✔
606

607

608
class DockerBuildOptionFieldMultiValueMixin(StringSequenceField):
10✔
609
    """Inherit this mixin class to provide options in the form of `--flag=value1,value2` to `docker
610
    build`."""
611

612
    docker_build_option: ClassVar[str]
10✔
613

614
    @final
10✔
615
    def options(self, *args, **kwargs) -> Iterator[str]:
10✔
616
        if self.value:
4✔
617
            yield f"{self.docker_build_option}={','.join(list(self.value))}"
1✔
618

619

620
class DockerImageBuildPullOptionField(DockerBuildOptionFieldValueMixin, BoolField):
10✔
621
    alias = "pull"
10✔
622
    default = False
10✔
623
    help = help_text(
10✔
624
        """
625
        If true, then docker will always attempt to pull a newer version of the image.
626

627
        NOTE: This option cannot be used on images that build off of "transitive" base images
628
        referenced by address (i.e. `FROM path/to/your/base/Dockerfile`).
629
        """
630
    )
631
    docker_build_option = "--pull"
10✔
632

633

634
class DockerBuildOptionFlagFieldMixin(BoolField, ABC):
10✔
635
    """Inherit this mixin class to provide optional flags (i.e. add `--flag` only when the value is
636
    `True`) to `docker build`."""
637

638
    docker_build_option: ClassVar[str]
10✔
639

640
    @final
10✔
641
    def options(self, *args, **kwargs) -> Iterator[str]:
10✔
642
        if self.value:
4✔
643
            yield f"{self.docker_build_option}"
1✔
644

645

646
class DockerImageBuildSquashOptionField(DockerBuildOptionFlagFieldMixin):
10✔
647
    alias = "squash"
10✔
648
    default = False
10✔
649
    help = help_text(
10✔
650
        """
651
        If true, then docker will squash newly built layers into a single new layer.
652

653
        Note that this option is only supported on a Docker daemon with experimental features enabled.
654
        """
655
    )
656
    docker_build_option = "--squash"
10✔
657

658

659
class DockerImageBuildNetworkOptionField(DockerBuildOptionFieldValueMixin, StringField):
10✔
660
    alias = "build_network"
10✔
661
    default = None
10✔
662
    help = help_text(
10✔
663
        """
664
        Sets the networking mode for the run commands during build.
665
        Supported standard values are: bridge, host, none, and container:<name|id>.
666
        Any other value is taken as a custom network's name to which the container should connect to.
667
        """
668
    )
669
    docker_build_option = "--network"
10✔
670

671

672
class DockerImageBuildPlatformOptionField(
10✔
673
    DockerBuildOptionFieldMultiValueMixin, StringSequenceField
674
):
675
    alias = "build_platform"
10✔
676
    default = None
10✔
677
    help = help_text(
10✔
678
        """
679
        Set the target platform(s) for the build.
680
        """
681
    )
682
    docker_build_option = "--platform"
10✔
683

684

685
class DockerImageRunExtraArgsField(StringSequenceField):
10✔
686
    alias: ClassVar[str] = "extra_run_args"
10✔
687
    default = ()
10✔
688
    help = help_text(
10✔
689
        lambda: f"Extra arguments to pass into the invocation of `docker run`. These are in addition to those at the `[{DockerOptions.options_scope}].run_args`"
690
    )
691

692

693
class DockerImageTarget(Target):
10✔
694
    alias = "docker_image"
10✔
695
    core_fields = (
10✔
696
        *COMMON_TARGET_FIELDS,
697
        DockerImageBuildArgsField,
698
        DockerImageDependenciesField,
699
        DockerImageSourceField,
700
        DockerImageInstructionsField,
701
        DockerImageContextRootField,
702
        DockerImageTagsField,
703
        DockerImageRegistriesField,
704
        DockerImageRepositoryField,
705
        DockerImageBuildImageLabelsOptionField,
706
        DockerImageBuildImageExtraHostsField,
707
        DockerImageBuildSecretsOptionField,
708
        DockerImageBuildSSHOptionField,
709
        DockerImageSkipPushField,
710
        DockerImageTargetStageField,
711
        DockerImageBuildPullOptionField,
712
        DockerImageBuildSquashOptionField,
713
        DockerImageBuildNetworkOptionField,
714
        DockerImageBuildPlatformOptionField,
715
        DockerImageBuildImageCacheToField,
716
        DockerImageBuildImageCacheFromField,
717
        DockerImageBuildImageOutputField,
718
        DockerImageOutputFilesField,
719
        DockerImageOutputDirectoriesField,
720
        DockerImageOutputsMatchModeField,
721
        DockerImageRunExtraArgsField,
722
        OutputPathField,
723
        RestartableField,
724
    )
725
    help = help_text(
726
        """
727
        The `docker_image` target describes how to build and tag a Docker image.
728

729
        Any dependencies, as inferred or explicitly specified, will be included in the Docker
730
        build context, after being packaged if applicable.
731

732
        By default, it will use a Dockerfile from the same directory as the BUILD file this target
733
        is defined in. Point at another file with the `source` field, or use the `instructions`
734
        field to have the Dockerfile contents verbatim directly in the BUILD file.
735

736
        Dependencies on upstream/base images defined by another `docker_image` are inferred if
737
        referenced by a build argument with a default value of the target address.
738

739
        Example:
740

741
            # src/docker/downstream/Dockerfile
742
            ARG BASE=src/docker/upstream:image
743
            FROM $BASE
744
            ...
745

746
        """
747
    )
748

749

750
@union(in_scope_types=[EnvironmentName])
10✔
751
@dataclass(frozen=True)
10✔
752
class DockerImageTagsRequest:
10✔
753
    """A request to provide additional image tags."""
754

755
    target: Target
10✔
756

757
    @classmethod
10✔
758
    def is_applicable(cls, target: Target) -> bool:
10✔
759
        """Whether to provide additional tags for this target or not."""
760
        return True
1✔
761

762

763
class DockerImageTags(Collection[str]):
10✔
764
    """Additional image tags to apply to built Docker images."""
765

766

767
@rule(polymorphic=True)
10✔
768
async def get_docker_image_tags(
10✔
769
    req: DockerImageTagsRequest, env_name: EnvironmentName
770
) -> DockerImageTags:
771
    raise NotImplementedError()
×
772

773

774
class AllDockerImageTargets(Targets):
10✔
775
    pass
10✔
776

777

778
@rule
10✔
779
async def all_docker_targets(all_targets: AllTargets) -> AllDockerImageTargets:
10✔
780
    return AllDockerImageTargets(
6✔
781
        [tgt for tgt in all_targets if tgt.has_field(DockerImageSourceField)]
782
    )
783

784

785
def rules():
10✔
786
    return collect_rules()
6✔
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