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

pantsbuild / pants / 18517631058

15 Oct 2025 04:18AM UTC coverage: 69.207% (-11.1%) from 80.267%
18517631058

Pull #22745

github

web-flow
Merge 642a76ca1 into 99919310e
Pull Request #22745: [windows] Add windows support in the stdio crate.

53815 of 77759 relevant lines covered (69.21%)

2.42 hits per line

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

87.31
/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
6✔
5

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

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

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

50

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

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

64

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

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

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

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

99

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

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

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

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

120

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

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

130
        Example:
131

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

142

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

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

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

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

157

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

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

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

172

173
class DockerImageDependenciesField(Dependencies):
6✔
174
    supports_transitive_excludes = True
6✔
175

176

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

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

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

191
        Example:
192

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

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

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

211

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

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

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

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

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

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

231

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

237

238
OptionValueFormatter = Callable[[str], str]
6✔
239

240

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

244
    docker_build_option: ClassVar[str]
6✔
245

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

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

262

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

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

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

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

281

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

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

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

301

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

306
    docker_build_option: ClassVar[str]
6✔
307

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

315

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

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

322
    docker_build_option: ClassVar[str]
6✔
323

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

332

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

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

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

341

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

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

354
        {DockerBuildKitOptionField.required_help}
355

356
        Example:
357

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

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

375

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

386
        {DockerBuildKitOptionField.required_help}
387

388
        Example:
389

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

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

413

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

423
        {DockerBuildKitOptionField.required_help}
424

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

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

434

435
class DockerImageBuildSecretsOptionField(
6✔
436
    AsyncFieldMixin, DockerBuildOptionFieldMixin, DictStringToStringField
437
):
438
    alias = "secrets"
6✔
439
    help = help_text(
6✔
440
        """
441
        Secret files to expose to the build (only if BuildKit enabled).
442

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

449
        Example:
450

451
            docker_image(
452
                secrets={
453
                    "mysecret": "/var/secrets/some-secret",
454
                    "repo-secret": "src/proj/secrets/some-secret",
455
                    "home-dir-secret": "~/.config/some-secret",
456
                    "target-secret": "./secrets/some-secret",
457
                }
458
            )
459
        """
460
    )
461

462
    docker_build_option = "--secret"
6✔
463

464
    def option_values(self, **kwargs) -> Iterator[str]:
6✔
465
        # os.path.join() discards preceding parts if encountering an abs path, e.g. if the secret
466
        # `path` is an absolute path, the `buildroot` and `spec_path` will not be considered.  Also,
467
        # an empty path part is ignored.
468
        for secret, path in (self.value or {}).items():
1✔
469
            full_path = os.path.join(
1✔
470
                get_buildroot(),
471
                self.address.spec_path if re.match(r"\.{1,2}/", path) else "",
472
                os.path.expanduser(path),
473
            )
474

475
            yield f"id={secret},src={os.path.normpath(full_path)}"
1✔
476

477

478
class DockerImageBuildSSHOptionField(DockerBuildOptionFieldMixin, StringSequenceField):
6✔
479
    alias = "ssh"
6✔
480
    default = ()
6✔
481
    help = help_text(
6✔
482
        """
483
        SSH agent socket or keys to expose to the build (only if BuildKit enabled)
484
        (format: `default|<id>[=<socket>|<key>[,<key>]]`)
485

486
        The exposed agent and/or keys can then be used in your `Dockerfile` by mounting them in
487
        your `RUN` instructions:
488

489
            RUN --mount=type=ssh ...
490

491
        See [Docker documentation](https://docs.docker.com/develop/develop-images/build_enhancements/#using-ssh-to-access-private-data-in-builds)
492
        for more information.
493
        """
494
    )
495

496
    docker_build_option = "--ssh"
6✔
497

498
    def option_values(self, **kwargs) -> Iterator[str]:
6✔
499
        yield from cast("tuple[str]", self.value)
×
500

501

502
class DockerBuildOptionFieldValueMixin(Field):
6✔
503
    """Inherit this mixin class to provide unary options (i.e. option in the form of `--flag=value`)
504
    to `docker build`."""
505

506
    docker_build_option: ClassVar[str]
6✔
507

508
    @final
6✔
509
    def options(self, *args, **kwargs) -> Iterator[str]:
6✔
510
        if self.value is not None:
×
511
            yield f"{self.docker_build_option}={self.value}"
×
512

513

514
class DockerBuildOptionFieldMultiValueMixin(StringSequenceField):
6✔
515
    """Inherit this mixin class to provide options in the form of `--flag=value1,value2` to `docker
516
    build`."""
517

518
    docker_build_option: ClassVar[str]
6✔
519

520
    @final
6✔
521
    def options(self, *args, **kwargs) -> Iterator[str]:
6✔
522
        if self.value:
×
523
            yield f"{self.docker_build_option}={','.join(list(self.value))}"
×
524

525

526
class DockerImageBuildPullOptionField(DockerBuildOptionFieldValueMixin, BoolField):
6✔
527
    alias = "pull"
6✔
528
    default = False
6✔
529
    help = help_text(
6✔
530
        """
531
        If true, then docker will always attempt to pull a newer version of the image.
532

533
        NOTE: This option cannot be used on images that build off of "transitive" base images
534
        referenced by address (i.e. `FROM path/to/your/base/Dockerfile`).
535
        """
536
    )
537
    docker_build_option = "--pull"
6✔
538

539

540
class DockerBuildOptionFlagFieldMixin(BoolField, ABC):
6✔
541
    """Inherit this mixin class to provide optional flags (i.e. add `--flag` only when the value is
542
    `True`) to `docker build`."""
543

544
    docker_build_option: ClassVar[str]
6✔
545

546
    @final
6✔
547
    def options(self, *args, **kwargs) -> Iterator[str]:
6✔
548
        if self.value:
×
549
            yield f"{self.docker_build_option}"
×
550

551

552
class DockerImageBuildSquashOptionField(DockerBuildOptionFlagFieldMixin):
6✔
553
    alias = "squash"
6✔
554
    default = False
6✔
555
    help = help_text(
6✔
556
        """
557
        If true, then docker will squash newly built layers into a single new layer.
558

559
        Note that this option is only supported on a Docker daemon with experimental features enabled.
560
        """
561
    )
562
    docker_build_option = "--squash"
6✔
563

564

565
class DockerImageBuildNetworkOptionField(DockerBuildOptionFieldValueMixin, StringField):
6✔
566
    alias = "build_network"
6✔
567
    default = None
6✔
568
    help = help_text(
6✔
569
        """
570
        Sets the networking mode for the run commands during build.
571
        Supported standard values are: bridge, host, none, and container:<name|id>.
572
        Any other value is taken as a custom network's name to which the container should connect to.
573
        """
574
    )
575
    docker_build_option = "--network"
6✔
576

577

578
class DockerImageBuildPlatformOptionField(
6✔
579
    DockerBuildOptionFieldMultiValueMixin, StringSequenceField
580
):
581
    alias = "build_platform"
6✔
582
    default = None
6✔
583
    help = help_text(
6✔
584
        """
585
        Set the target platform(s) for the build.
586
        """
587
    )
588
    docker_build_option = "--platform"
6✔
589

590

591
class DockerImageRunExtraArgsField(StringSequenceField):
6✔
592
    alias: ClassVar[str] = "extra_run_args"
6✔
593
    default = ()
6✔
594
    help = help_text(
6✔
595
        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`"
596
    )
597

598

599
class DockerImageTarget(Target):
6✔
600
    alias = "docker_image"
6✔
601
    core_fields = (
6✔
602
        *COMMON_TARGET_FIELDS,
603
        DockerImageBuildArgsField,
604
        DockerImageDependenciesField,
605
        DockerImageSourceField,
606
        DockerImageInstructionsField,
607
        DockerImageContextRootField,
608
        DockerImageTagsField,
609
        DockerImageRegistriesField,
610
        DockerImageRepositoryField,
611
        DockerImageBuildImageLabelsOptionField,
612
        DockerImageBuildImageExtraHostsField,
613
        DockerImageBuildSecretsOptionField,
614
        DockerImageBuildSSHOptionField,
615
        DockerImageSkipPushField,
616
        DockerImageTargetStageField,
617
        DockerImageBuildPullOptionField,
618
        DockerImageBuildSquashOptionField,
619
        DockerImageBuildNetworkOptionField,
620
        DockerImageBuildPlatformOptionField,
621
        DockerImageBuildImageCacheToField,
622
        DockerImageBuildImageCacheFromField,
623
        DockerImageBuildImageOutputField,
624
        DockerImageRunExtraArgsField,
625
        OutputPathField,
626
        RestartableField,
627
    )
628
    help = help_text(
629
        """
630
        The `docker_image` target describes how to build and tag a Docker image.
631

632
        Any dependencies, as inferred or explicitly specified, will be included in the Docker
633
        build context, after being packaged if applicable.
634

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

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

642
        Example:
643

644
            # src/docker/downstream/Dockerfile
645
            ARG BASE=src/docker/upstream:image
646
            FROM $BASE
647
            ...
648

649
        """
650
    )
651

652

653
@union(in_scope_types=[EnvironmentName])
6✔
654
@dataclass(frozen=True)
6✔
655
class DockerImageTagsRequest:
6✔
656
    """A request to provide additional image tags."""
657

658
    target: Target
6✔
659

660
    @classmethod
6✔
661
    def is_applicable(cls, target: Target) -> bool:
6✔
662
        """Whether to provide additional tags for this target or not."""
663
        return True
×
664

665

666
class DockerImageTags(Collection[str]):
6✔
667
    """Additional image tags to apply to built Docker images."""
668

669

670
@rule(polymorphic=True)
6✔
671
async def get_docker_image_tags(
6✔
672
    req: DockerImageTagsRequest, env_name: EnvironmentName
673
) -> DockerImageTags:
674
    raise NotImplementedError()
×
675

676

677
class AllDockerImageTargets(Targets):
6✔
678
    pass
6✔
679

680

681
@rule
6✔
682
async def all_docker_targets(all_targets: AllTargets) -> AllDockerImageTargets:
6✔
683
    return AllDockerImageTargets(
×
684
        [tgt for tgt in all_targets if tgt.has_field(DockerImageSourceField)]
685
    )
686

687

688
def rules():
6✔
689
    return collect_rules()
4✔
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

© 2025 Coveralls, Inc