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

pantsbuild / pants / 19015773527

02 Nov 2025 05:33PM UTC coverage: 17.872% (-62.4%) from 80.3%
19015773527

Pull #22816

github

web-flow
Merge a12d75757 into 6c024e162
Pull Request #22816: Update Pants internal Python to 3.14

4 of 5 new or added lines in 3 files covered. (80.0%)

28452 existing lines in 683 files now uncovered.

9831 of 55007 relevant lines covered (17.87%)

0.18 hits per line

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

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

UNCOV
4
from __future__ import annotations
×
5

UNCOV
6
import logging
×
UNCOV
7
from dataclasses import dataclass
×
8

UNCOV
9
from pants.backend.helm.resolve.remotes import ALL_DEFAULT_HELM_REGISTRIES
×
UNCOV
10
from pants.base.glob_match_error_behavior import GlobMatchErrorBehavior
×
UNCOV
11
from pants.core.goals.package import OutputPathField
×
UNCOV
12
from pants.core.goals.test import TestTimeoutField
×
UNCOV
13
from pants.engine.internals.native_engine import AddressInput
×
UNCOV
14
from pants.engine.rules import collect_rules, rule
×
UNCOV
15
from pants.engine.target import (
×
16
    COMMON_TARGET_FIELDS,
17
    AllTargets,
18
    AsyncFieldMixin,
19
    BoolField,
20
    Dependencies,
21
    DescriptionField,
22
    DictStringToStringField,
23
    FieldSet,
24
    IntField,
25
    MultipleSourcesField,
26
    OverridesField,
27
    SingleSourceField,
28
    SpecialCasedDependencies,
29
    StringField,
30
    StringSequenceField,
31
    Target,
32
    TargetFilesGenerator,
33
    Targets,
34
    TriBoolField,
35
    ValidNumbers,
36
    generate_file_based_overrides_field_help_message,
37
    generate_multiple_sources_field_help_message,
38
)
UNCOV
39
from pants.util.docutil import bin_name
×
UNCOV
40
from pants.util.strutil import help_text
×
41

UNCOV
42
logger = logging.getLogger(__name__)
×
43

44
# -----------------------------------------------------------------------------------------------
45
# Generic commonly used fields
46
# -----------------------------------------------------------------------------------------------
47

48

UNCOV
49
class HelmRegistriesField(StringSequenceField):
×
UNCOV
50
    alias = "registries"
×
UNCOV
51
    default = (ALL_DEFAULT_HELM_REGISTRIES,)
×
UNCOV
52
    help = help_text(
×
53
        """
54
        List of addresses or configured aliases to any OCI registries to use for the
55
        built chart.
56

57
        The address is an `oci://` prefixed domain name with optional port for your registry, and any registry
58
        aliases are prefixed with `@` for addresses in the `[helm].registries` configuration
59
        section.
60

61
        By default, all configured registries with `default = true` are used.
62

63
        Example:
64

65
            # pants.toml
66
            [helm.registries.my-registry-alias]
67
            address = "oci://myregistrydomain:port"
68
            default = false  # optional
69

70
            # example/BUILD
71
            helm_chart(
72
                registries = [
73
                    "@my-registry-alias",
74
                    "oci://myregistrydomain:port",
75
                ],
76
            )
77

78
        The above example shows two valid `registry` options: using an alias to a configured
79
        registry and the address to a registry verbatim in the BUILD file.
80
        """
81
    )
82

83

UNCOV
84
class HelmSkipLintField(BoolField):
×
UNCOV
85
    alias = "skip_lint"
×
UNCOV
86
    default = False
×
UNCOV
87
    help = help_text(
×
88
        f"""
89
        If set to true, do not run any linting in this Helm chart when running `{bin_name()}
90
        lint`.
91
        """
92
    )
93

94

UNCOV
95
class HelmSkipPushField(BoolField):
×
UNCOV
96
    alias = "skip_push"
×
UNCOV
97
    default = False
×
UNCOV
98
    help = help_text(
×
99
        f"""
100
        If set to true, do not push this Helm chart to registries when running `{bin_name()}
101
        publish`.
102
        """
103
    )
104

105

106
# -----------------------------------------------------------------------------------------------
107
# `helm_chart` target
108
# -----------------------------------------------------------------------------------------------
109

110

UNCOV
111
class HelmChartMetaSourceField(SingleSourceField):
×
UNCOV
112
    alias = "chart"
×
UNCOV
113
    default = "Chart.yaml"
×
UNCOV
114
    expected_file_extensions = (
×
115
        ".yaml",
116
        ".yml",
117
    )
UNCOV
118
    required = False
×
UNCOV
119
    help = "The chart definition file."
×
120

121

UNCOV
122
class HelmChartSourcesField(MultipleSourcesField):
×
UNCOV
123
    default = (
×
124
        ".helmignore",
125
        "README.md",
126
        "LICENSE",
127
        "values.yaml",
128
        "values.yml",
129
        "values.schema.json",
130
        "templates/**/*.yaml",
131
        "templates/**/*.yml",
132
        "templates/**/*.tpl",
133
        "templates/NOTES.txt",
134
        "crds/*.yaml",
135
        "crds/*.yml",
136
    )
UNCOV
137
    expected_file_extensions = (".helmignore", ".yaml", ".yml", ".tpl", ".json", ".md", ".txt", "")
×
UNCOV
138
    help = generate_multiple_sources_field_help_message(
×
139
        "Example: `sources=['values.yaml', 'templates/*.yaml', '!values_ignore.yaml']`"
140
    )
141

142

UNCOV
143
class HelmChartDependenciesField(Dependencies):
×
UNCOV
144
    pass
×
145

146

UNCOV
147
class HelmChartOutputPathField(OutputPathField):
×
UNCOV
148
    help = help_text(
×
149
        f"""
150
        Where the built directory tree should be located.
151

152
        If undefined, this will use the path to the BUILD file,
153
        For example, `src/charts/mychart:tgt_name` would be
154
        `src.charts.mychart/tgt_name/`.
155

156
        Regardless of whether you use the default or set this field, the path will end with
157
        Helms's file format of `<chart_name>-<chart_version>.tgz`, where
158
        `chart_name` and `chart_version` are the values extracted from the Chart.yaml file.
159
        So, using the default for this field, the target
160
        `src/charts/mychart:tgt_name` might have a final path like
161
        `src.charts.mychart/tgt_name/mychart-0.1.0.tgz`.
162

163
        When running `{bin_name()} package`, this path will be prefixed by `--distdir` (e.g. `dist/`).
164

165
        Warning: setting this value risks naming collisions with other package targets you may
166
        have.
167
        """
168
    )
169

170

UNCOV
171
class HelmChartLintStrictField(TriBoolField):
×
UNCOV
172
    alias = "lint_strict"
×
UNCOV
173
    help = "If set to true, enables strict linting of this Helm chart."
×
174

175

UNCOV
176
class HelmChartLintQuietField(TriBoolField):
×
UNCOV
177
    alias = "lint_quiet"
×
UNCOV
178
    help = "If set to true, print only warnings and errors."
×
179

180

UNCOV
181
class HelmChartRepositoryField(StringField):
×
UNCOV
182
    alias = "repository"
×
UNCOV
183
    help = help_text(
×
184
        """
185
        Repository to use in the Helm registry where this chart is going to be published.
186

187
        If no value is given and `[helm].default-registry-repository` is undefined too, then the chart
188
        will be pushed to the root of the OCI registry.
189
        """
190
    )
191

192

UNCOV
193
class HelmChartVersionField(StringField):
×
UNCOV
194
    alias = "version"
×
UNCOV
195
    help = help_text(
×
196
        """
197
        Version number for the given Helm chart.
198

199
        When specified, the version provided in the source Chart.yaml file will be overriden by the value
200
        given to this field.
201
        """
202
    )
203

204

UNCOV
205
class HelmChartTarget(Target):
×
UNCOV
206
    alias = "helm_chart"
×
UNCOV
207
    core_fields = (
×
208
        *COMMON_TARGET_FIELDS,
209
        HelmChartMetaSourceField,
210
        HelmChartSourcesField,
211
        HelmChartDependenciesField,
212
        HelmChartOutputPathField,
213
        HelmChartLintStrictField,
214
        HelmChartLintQuietField,
215
        HelmChartRepositoryField,
216
        HelmChartVersionField,
217
        HelmRegistriesField,
218
        HelmSkipPushField,
219
        HelmSkipLintField,
220
    )
UNCOV
221
    help = "A Helm chart."
×
222

223

UNCOV
224
@dataclass(frozen=True)
×
UNCOV
225
class HelmChartFieldSet(FieldSet):
×
UNCOV
226
    required_fields = (
×
227
        HelmChartMetaSourceField,
228
        HelmChartSourcesField,
229
    )
230

UNCOV
231
    chart: HelmChartMetaSourceField
×
UNCOV
232
    sources: HelmChartSourcesField
×
UNCOV
233
    dependencies: HelmChartDependenciesField
×
UNCOV
234
    description: DescriptionField
×
UNCOV
235
    version: HelmChartVersionField
×
236

237

UNCOV
238
class AllHelmChartTargets(Targets):
×
UNCOV
239
    pass
×
240

241

UNCOV
242
@rule
×
UNCOV
243
async def all_helm_chart_targets(all_targets: AllTargets) -> AllHelmChartTargets:
×
244
    return AllHelmChartTargets([tgt for tgt in all_targets if HelmChartFieldSet.is_applicable(tgt)])
×
245

246

247
# -----------------------------------------------------------------------------------------------
248
# `helm_unittest_test` target
249
# -----------------------------------------------------------------------------------------------
250

251

UNCOV
252
class HelmUnitTestDependenciesField(Dependencies):
×
UNCOV
253
    pass
×
254

255

UNCOV
256
class HelmUnitTestTimeoutField(TestTimeoutField):
×
UNCOV
257
    pass
×
258

259

UNCOV
260
class HelmUnitTestSourceField(SingleSourceField):
×
UNCOV
261
    expected_file_extensions = (
×
262
        ".yaml",
263
        ".yml",
264
    )
265

266

UNCOV
267
class HelmUnitTestStrictField(TriBoolField):
×
UNCOV
268
    alias = "strict"
×
UNCOV
269
    help = "If set to true, parses the UnitTest suite files strictly."
×
270

271

UNCOV
272
class HelmUnitTestTestTarget(Target):
×
UNCOV
273
    alias = "helm_unittest_test"
×
UNCOV
274
    core_fields = (
×
275
        *COMMON_TARGET_FIELDS,
276
        HelmUnitTestSourceField,
277
        HelmUnitTestDependenciesField,
278
        HelmUnitTestStrictField,
279
        HelmUnitTestTimeoutField,
280
    )
UNCOV
281
    help = "A single helm-unittest suite file."
×
282

283

UNCOV
284
class AllHelmUnitTestTestTargets(Targets):
×
UNCOV
285
    pass
×
286

287

UNCOV
288
@rule
×
UNCOV
289
async def all_helm_unittest_test_targets(all_targets: AllTargets) -> AllHelmUnitTestTestTargets:
×
290
    return AllHelmUnitTestTestTargets(
×
291
        [tgt for tgt in all_targets if tgt.has_field(HelmUnitTestSourceField)]
292
    )
293

294

295
# -----------------------------------------------------------------------------------------------
296
# `helm_unittest_tests` target generator
297
# -----------------------------------------------------------------------------------------------
298

299

UNCOV
300
class HelmUnitTestGeneratingSourcesField(MultipleSourcesField):
×
UNCOV
301
    default = ("*_test.yaml", "*_test.yml")
×
UNCOV
302
    expected_file_extensions = (
×
303
        ".yaml",
304
        ".yml",
305
    )
UNCOV
306
    help = generate_multiple_sources_field_help_message(
×
307
        "Example: `sources=['*_test.yaml', '!ignore_test.yaml']`"
308
    )
309

310

UNCOV
311
class HelmUnitTestOverridesField(OverridesField):
×
UNCOV
312
    help = generate_file_based_overrides_field_help_message(
×
313
        HelmUnitTestTestTarget.alias,
314
        """
315
        overrides={
316
            "configmap_test.yaml": {"timeout": 120},
317
            ("deployment_test.yaml", "pod_test.yaml"): {"tags": ["slow_tests"]},
318
        }
319
        """,
320
    )
321

322

UNCOV
323
class HelmUnitTestTestsGeneratorTarget(TargetFilesGenerator):
×
UNCOV
324
    alias = "helm_unittest_tests"
×
UNCOV
325
    core_fields = (
×
326
        *COMMON_TARGET_FIELDS,
327
        HelmUnitTestGeneratingSourcesField,
328
        HelmUnitTestDependenciesField,
329
        HelmUnitTestOverridesField,
330
    )
UNCOV
331
    generated_target_cls = HelmUnitTestTestTarget
×
UNCOV
332
    copied_fields = COMMON_TARGET_FIELDS
×
UNCOV
333
    moved_fields = (
×
334
        HelmUnitTestStrictField,
335
        HelmUnitTestTimeoutField,
336
    )
UNCOV
337
    help = f"Generates a `{HelmUnitTestTestTarget.alias}` target per each file in the `{HelmUnitTestGeneratingSourcesField.alias}` field."
×
338

339

340
# -----------------------------------------------------------------------------------------------
341
# `helm_artifact` target
342
# -----------------------------------------------------------------------------------------------
343

344

UNCOV
345
class HelmArtifactRegistryField(StringField):
×
UNCOV
346
    alias = "registry"
×
UNCOV
347
    help = help_text(
×
348
        """
349
        Either registry alias (prefixed by `@`) configured in `[helm.registries]` for the
350
        Helm artifact or the full OCI registry URL.
351
        """
352
    )
353

354

UNCOV
355
class HelmArtifactRepositoryField(StringField):
×
UNCOV
356
    alias = "repository"
×
UNCOV
357
    help = help_text(
×
358
        f"""
359
        Either a HTTP(S) URL to a classic repository, or a path inside an OCI registry (when
360
        `{HelmArtifactRegistryField.alias}` is provided).
361
        """
362
    )
363

364

UNCOV
365
class HelmArtifactArtifactField(StringField):
×
UNCOV
366
    alias = "artifact"
×
UNCOV
367
    required = True
×
UNCOV
368
    help = "Artifact name of the chart, without version number."
×
369

370

UNCOV
371
class HelmArtifactVersionField(StringField):
×
UNCOV
372
    alias = "version"
×
UNCOV
373
    required = True
×
UNCOV
374
    help = "The `version` part of a third party Helm chart."
×
375

376

UNCOV
377
class HelmArtifactTarget(Target):
×
UNCOV
378
    alias = "helm_artifact"
×
UNCOV
379
    core_fields = (
×
380
        *COMMON_TARGET_FIELDS,
381
        HelmArtifactRegistryField,
382
        HelmArtifactRepositoryField,
383
        HelmArtifactArtifactField,
384
        HelmArtifactVersionField,
385
    )
UNCOV
386
    help = "A third party Helm artifact."
×
387

388

UNCOV
389
@dataclass(frozen=True)
×
UNCOV
390
class HelmArtifactFieldSet(FieldSet):
×
UNCOV
391
    required_fields = (HelmArtifactArtifactField, HelmArtifactVersionField)
×
392

UNCOV
393
    registry: HelmArtifactRegistryField
×
UNCOV
394
    repository: HelmArtifactRepositoryField
×
UNCOV
395
    artifact: HelmArtifactArtifactField
×
UNCOV
396
    version: HelmArtifactVersionField
×
397

398

UNCOV
399
class AllHelmArtifactTargets(Targets):
×
UNCOV
400
    pass
×
401

402

UNCOV
403
@rule
×
UNCOV
404
async def all_helm_artifact_targets(all_targets: AllTargets) -> AllHelmArtifactTargets:
×
405
    return AllHelmArtifactTargets(
×
406
        [tgt for tgt in all_targets if HelmArtifactFieldSet.is_applicable(tgt)]
407
    )
408

409

410
# -----------------------------------------------------------------------------------------------
411
# `helm_deployment` target
412
# -----------------------------------------------------------------------------------------------
413

414

UNCOV
415
class HelmDeploymentChartField(StringField, AsyncFieldMixin):
×
UNCOV
416
    alias = "chart"
×
UNCOV
417
    required = True
×
UNCOV
418
    value: str
×
UNCOV
419
    help = help_text(
×
420
        f"""
421
        The address of the `{HelmChartTarget.alias}` or `{HelmArtifactTarget.alias}`
422
        that will be used for this deployment.
423
        """
424
    )
425

UNCOV
426
    def to_address_input(self) -> AddressInput:
×
427
        return AddressInput.parse(
×
428
            self.value,
429
            relative_to=self.address.spec_path,
430
            description_of_origin=f"the `{self.alias}` field in the `{HelmDeploymentTarget.alias}` target {self.address}",
431
        )
432

433

UNCOV
434
class HelmDeploymentReleaseNameField(StringField):
×
UNCOV
435
    alias = "release_name"
×
UNCOV
436
    help = "Name of the release used in the deployment. If not set, the target name will be used instead."
×
437

438

UNCOV
439
class HelmDeploymentNamespaceField(StringField):
×
UNCOV
440
    alias = "namespace"
×
UNCOV
441
    help = help_text("""Kubernetes namespace for the given deployment.""")
×
442

443

UNCOV
444
class HelmDeploymentDependenciesField(Dependencies):
×
UNCOV
445
    pass
×
446

447

UNCOV
448
class HelmDeploymentSkipCrdsField(BoolField):
×
UNCOV
449
    alias = "skip_crds"
×
UNCOV
450
    default = False
×
UNCOV
451
    help = "If true, then does not deploy the Custom Resource Definitions that are defined in the chart."
×
452

453

UNCOV
454
class HelmDeploymentSourcesField(MultipleSourcesField):
×
UNCOV
455
    default = ("*.yaml", "*.yml")
×
UNCOV
456
    expected_file_extensions = (".yaml", ".yml")
×
UNCOV
457
    default_glob_match_error_behavior = GlobMatchErrorBehavior.ignore
×
UNCOV
458
    help = "Helm configuration files for a given deployment."
×
459

460

UNCOV
461
class HelmDeploymentValuesField(DictStringToStringField, AsyncFieldMixin):
×
UNCOV
462
    alias = "values"
×
UNCOV
463
    required = False
×
UNCOV
464
    help = help_text(
×
465
        """
466
        Individual values to use when rendering a given deployment.
467

468
        Value names should be defined using dot-syntax as in the following example:
469

470
            helm_deployment(
471
                values={
472
                    "nameOverride": "my_custom_name",
473
                    "image.pullPolicy": "Always",
474
                },
475
            )
476

477
        Values can be dynamically calculated using interpolation as shown in the following example:
478

479
            helm_deployment(
480
                values={
481
                    "configmap.deployedAt": f"{env('DEPLOY_TIME')}",
482
                },
483
            )
484

485
        Check the Helm backend documentation on what are the options available and its caveats when making
486
        usage of dynamic values in your deployments.
487
        """
488
    )
489

490

UNCOV
491
class HelmDeploymentNoHooksField(BoolField):
×
UNCOV
492
    alias = "no_hooks"
×
UNCOV
493
    default = False
×
UNCOV
494
    help = "If true, none of the lifecycle hooks of the given chart will be included in the deployment."
×
495

496

UNCOV
497
class HelmDeploymentTimeoutField(IntField):
×
UNCOV
498
    alias = "timeout"
×
UNCOV
499
    required = False
×
UNCOV
500
    help = "Timeout in seconds when running a Helm deployment."
×
UNCOV
501
    valid_numbers = ValidNumbers.positive_only
×
502

503

UNCOV
504
class HelmDeploymentPostRenderersField(SpecialCasedDependencies):
×
UNCOV
505
    alias = "post_renderers"
×
UNCOV
506
    help = help_text(
×
507
        """
508
        List of runnable targets to be used to post-process the helm chart after being rendered by Helm.
509

510
        This is equivalent to the same post-renderer feature already available in Helm with the difference
511
        that this supports a list of executables instead of a single one.
512

513
        When more than one post-renderer is given, they will be combined into a single one in which the
514
        input of each of them would be output of the previous one.
515
        """
516
    )
517

518

UNCOV
519
class HelmDeploymentEnableDNSField(BoolField):
×
UNCOV
520
    alias = "enable_dns"
×
UNCOV
521
    default = False
×
UNCOV
522
    help = "Enables DNS lookups when using the `getHostByName` template function."
×
523

524

UNCOV
525
class HelmDeploymentTarget(Target):
×
UNCOV
526
    alias = "helm_deployment"
×
UNCOV
527
    core_fields = (
×
528
        *COMMON_TARGET_FIELDS,
529
        HelmDeploymentChartField,
530
        HelmDeploymentReleaseNameField,
531
        HelmDeploymentDependenciesField,
532
        HelmDeploymentSourcesField,
533
        HelmDeploymentNamespaceField,
534
        HelmDeploymentSkipCrdsField,
535
        HelmDeploymentValuesField,
536
        HelmDeploymentNoHooksField,
537
        HelmDeploymentTimeoutField,
538
        HelmDeploymentPostRenderersField,
539
        HelmDeploymentEnableDNSField,
540
    )
UNCOV
541
    help = "A Helm chart deployment."
×
542

543

UNCOV
544
@dataclass(frozen=True)
×
UNCOV
545
class HelmDeploymentFieldSet(FieldSet):
×
UNCOV
546
    required_fields = (
×
547
        HelmDeploymentDependenciesField,
548
        HelmDeploymentSourcesField,
549
    )
550

UNCOV
551
    chart: HelmDeploymentChartField
×
UNCOV
552
    description: DescriptionField
×
UNCOV
553
    release_name: HelmDeploymentReleaseNameField
×
UNCOV
554
    namespace: HelmDeploymentNamespaceField
×
UNCOV
555
    sources: HelmDeploymentSourcesField
×
UNCOV
556
    skip_crds: HelmDeploymentSkipCrdsField
×
UNCOV
557
    no_hooks: HelmDeploymentNoHooksField
×
UNCOV
558
    dependencies: HelmDeploymentDependenciesField
×
UNCOV
559
    values: HelmDeploymentValuesField
×
UNCOV
560
    post_renderers: HelmDeploymentPostRenderersField
×
UNCOV
561
    enable_dns: HelmDeploymentEnableDNSField
×
562

563

UNCOV
564
class AllHelmDeploymentTargets(Targets):
×
UNCOV
565
    pass
×
566

567

UNCOV
568
@rule
×
UNCOV
569
async def all_helm_deployment_targets(targets: AllTargets) -> AllHelmDeploymentTargets:
×
570
    return AllHelmDeploymentTargets(
×
571
        [tgt for tgt in targets if HelmDeploymentFieldSet.is_applicable(tgt)]
572
    )
573

574

UNCOV
575
def rules():
×
UNCOV
576
    return collect_rules()
×
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