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

pantsbuild / pants / 18913303678

29 Oct 2025 03:29PM UTC coverage: 80.004% (-0.3%) from 80.283%
18913303678

push

github

web-flow
Updating 3rd party lockfiles for PBS script and MyPy (#22796)

Also small bumps to fastapi and starlette, which updated over the last few days. Starlette updated for features, and then a security vulnerability.

Fastapi bumped just for starlette.

88 of 93 new or added lines in 73 files covered. (94.62%)

221 existing lines in 15 files now uncovered.

77334 of 96663 relevant lines covered (80.0%)

5.2 hits per line

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

67.16
/src/python/pants/backend/helm/resolve/fetch.py
1
# Copyright 2022 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 logging
6✔
7
import os
6✔
8
from dataclasses import dataclass
6✔
9
from typing import Any
6✔
10

11
from pants.backend.helm.resolve import artifacts
6✔
12
from pants.backend.helm.resolve.artifacts import (
6✔
13
    HelmArtifact,
14
    ResolvedHelmArtifact,
15
    resolved_helm_artifact,
16
)
17
from pants.backend.helm.target_types import HelmArtifactFieldSet, HelmArtifactTarget
6✔
18
from pants.backend.helm.util_rules import tool
6✔
19
from pants.backend.helm.util_rules.tool import HelmProcess
6✔
20
from pants.engine.addresses import Address
6✔
21
from pants.engine.engine_aware import EngineAwareParameter, EngineAwareReturnType
6✔
22
from pants.engine.fs import (
6✔
23
    CreateDigest,
24
    DigestSubset,
25
    Directory,
26
    FileDigest,
27
    PathGlobs,
28
    RemovePrefix,
29
    Snapshot,
30
)
31
from pants.engine.intrinsics import (
6✔
32
    create_digest,
33
    digest_subset_to_digest,
34
    digest_to_snapshot,
35
    remove_prefix,
36
)
37
from pants.engine.process import execute_process_or_raise
6✔
38
from pants.engine.rules import collect_rules, concurrently, implicitly, rule
6✔
39
from pants.engine.target import Target
6✔
40
from pants.util.logging import LogLevel
6✔
41
from pants.util.strutil import softwrap
6✔
42

43
logger = logging.getLogger(__name__)
6✔
44

45

46
class InvalidHelmArtifactTarget(Exception):
6✔
47
    def __init__(self, target: Target) -> None:
6✔
48
        super().__init__(
×
49
            softwrap(
50
                f"""
51
                Can not fetch a Helm artifact for a `{target.alias}` target.
52

53
                Helm artifacts are defined using target `{HelmArtifactTarget.alias}`.
54
                """
55
            )
56
        )
57

58

59
@dataclass(frozen=True)
6✔
60
class FetchHelmArtifactRequest(EngineAwareParameter):
6✔
61
    field_set: HelmArtifactFieldSet
6✔
62
    description_of_origin: str
6✔
63

64
    @classmethod
6✔
65
    def from_target(cls, target: Target, *, description_of_origin: str) -> FetchHelmArtifactRequest:
6✔
UNCOV
66
        if not HelmArtifactFieldSet.is_applicable(target):
×
67
            raise InvalidHelmArtifactTarget(target)
×
68

UNCOV
69
        return cls(
×
70
            field_set=HelmArtifactFieldSet.create(target),
71
            description_of_origin=description_of_origin,
72
        )
73

74
    def debug_hint(self) -> str | None:
6✔
75
        return f"{self.field_set.address} from {self.description_of_origin}"
×
76

77
    def metadata(self) -> dict[str, Any] | None:
6✔
78
        return {
×
79
            "address": self.field_set.address.spec,
80
            "description_of_origin": self.description_of_origin,
81
        }
82

83

84
@dataclass(frozen=True)
6✔
85
class FetchedHelmArtifact(EngineAwareReturnType):
6✔
86
    artifact: ResolvedHelmArtifact
6✔
87
    snapshot: Snapshot
6✔
88

89
    @property
6✔
90
    def address(self) -> Address:
6✔
91
        return self.artifact.address
×
92

93
    def level(self) -> LogLevel | None:
6✔
94
        return LogLevel.DEBUG
×
95

96
    def message(self) -> str | None:
6✔
97
        return softwrap(
×
98
            f"""
99
            Fetched Helm artifact '{self.artifact.name}' with version {self.artifact.version}
100
            using URL: {self.artifact.chart_url}
101
            """
102
        )
103

104
    def metadata(self) -> dict[str, Any] | None:
6✔
105
        return {"artifact": self.artifact}
×
106

107
    def artifacts(self) -> dict[str, FileDigest | Snapshot] | None:
6✔
108
        return {"snapshot": self.snapshot}
×
109

110

111
def assemble_pull_target(resolved_artifact: ResolvedHelmArtifact) -> list[str]:
6✔
112
    """The target of `pull` need different args depending on whether it's an OCI Registry or a Helm
113
    Chart Repository."""
114
    is_oci = resolved_artifact.requirement.location.spec.startswith("oci://")
×
115
    if is_oci:
×
116
        return [f"{resolved_artifact.location_url}/{resolved_artifact.name}"]
×
117
    else:
118
        return [resolved_artifact.name, "--repo", resolved_artifact.location_url]
×
119

120

121
@rule(desc="Fetch Helm artifact", level=LogLevel.DEBUG)
6✔
122
async def fetch_helm_artifact(request: FetchHelmArtifactRequest) -> FetchedHelmArtifact:
6✔
123
    download_prefix = "__downloads"
×
124

125
    empty_download_digest, resolved_artifact = await concurrently(
×
126
        create_digest(CreateDigest([Directory(download_prefix)])),
127
        resolved_helm_artifact(
128
            **implicitly({HelmArtifact.from_field_set(request.field_set): HelmArtifact})
129
        ),
130
    )
131

132
    download_result = await execute_process_or_raise(
×
133
        **implicitly(
134
            HelmProcess(
135
                argv=[
136
                    "pull",
137
                    *assemble_pull_target(resolved_artifact),
138
                    "--version",
139
                    resolved_artifact.version,
140
                    "--destination",
141
                    download_prefix,
142
                    "--untar",
143
                ],
144
                input_digest=empty_download_digest,
145
                description=f"Pulling Helm Chart '{resolved_artifact.name}' with version {resolved_artifact.version}.",
146
                output_directories=(download_prefix,),
147
                level=LogLevel.DEBUG,
148
            )
149
        )
150
    )
151

152
    raw_output_digest = await remove_prefix(
×
153
        RemovePrefix(download_result.output_digest, download_prefix)
154
    )
155

156
    # The download result will come with a tarball alongside the unzipped sources, pick the chart sources only.
157
    artifact_sources_digest = await digest_subset_to_digest(
×
158
        DigestSubset(raw_output_digest, PathGlobs([os.path.join(resolved_artifact.name, "**")]))
159
    )
160
    artifact_snapshot = await digest_to_snapshot(
×
161
        **implicitly(RemovePrefix(artifact_sources_digest, resolved_artifact.name))
162
    )
163

164
    return FetchedHelmArtifact(artifact=resolved_artifact, snapshot=artifact_snapshot)
×
165

166

167
def rules():
6✔
168
    return [*collect_rules(), *artifacts.rules(), *tool.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

© 2025 Coveralls, Inc