• 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/javascript/install_node_package.py
1
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
UNCOV
3
from __future__ import annotations
×
4

UNCOV
5
import os.path
×
UNCOV
6
from collections.abc import Iterable
×
UNCOV
7
from dataclasses import dataclass
×
8

UNCOV
9
from pants.backend.javascript import nodejs_project_environment
×
UNCOV
10
from pants.backend.javascript.dependency_inference.rules import rules as dependency_inference_rules
×
UNCOV
11
from pants.backend.javascript.nodejs_project_environment import (
×
12
    NodeJsProjectEnvironment,
13
    NodeJsProjectEnvironmentProcess,
14
    NodeJSProjectEnvironmentRequest,
15
    get_nodejs_environment,
16
)
UNCOV
17
from pants.backend.javascript.package_json import (
×
18
    NodePackageNameField,
19
    NodePackageVersionField,
20
    PackageJsonSourceField,
21
)
UNCOV
22
from pants.backend.javascript.package_manager import PackageManager
×
UNCOV
23
from pants.backend.javascript.subsystems import nodejs
×
UNCOV
24
from pants.backend.javascript.target_types import JSRuntimeSourceField
×
UNCOV
25
from pants.build_graph.address import Address
×
UNCOV
26
from pants.core.target_types import FileSourceField, ResourceSourceField
×
UNCOV
27
from pants.core.util_rules.source_files import (
×
28
    SourceFiles,
29
    SourceFilesRequest,
30
    determine_source_files,
31
)
UNCOV
32
from pants.engine.internals.graph import transitive_targets
×
UNCOV
33
from pants.engine.internals.native_engine import AddPrefix, Digest, MergeDigests
×
UNCOV
34
from pants.engine.intrinsics import add_prefix, merge_digests
×
UNCOV
35
from pants.engine.process import fallible_to_exec_result_or_raise
×
UNCOV
36
from pants.engine.rules import Rule, collect_rules, implicitly, rule
×
UNCOV
37
from pants.engine.target import SourcesField, Target, TransitiveTargetsRequest
×
UNCOV
38
from pants.engine.unions import UnionMembership, UnionRule
×
39

40

UNCOV
41
@dataclass(frozen=True)
×
UNCOV
42
class InstalledNodePackageRequest:
×
UNCOV
43
    address: Address
×
44

45

UNCOV
46
@dataclass(frozen=True)
×
UNCOV
47
class InstalledNodePackage:
×
UNCOV
48
    project_env: NodeJsProjectEnvironment
×
UNCOV
49
    digest: Digest
×
50

UNCOV
51
    @property
×
UNCOV
52
    def project_dir(self) -> str:
×
53
        return self.project_env.root_dir
×
54

UNCOV
55
    def join_relative_workspace_directory(self, path: str) -> str:
×
56
        return os.path.join(self.project_env.relative_workspace_directory(), path)
×
57

UNCOV
58
    @property
×
UNCOV
59
    def target(self) -> Target:
×
60
        return self.project_env.ensure_target()
×
61

UNCOV
62
    @property
×
UNCOV
63
    def package_manager(self) -> PackageManager:
×
64
        return self.project_env.project.package_manager
×
65

66

UNCOV
67
@dataclass(frozen=True)
×
UNCOV
68
class InstalledNodePackageWithSource(InstalledNodePackage):
×
UNCOV
69
    pass
×
70

71

UNCOV
72
async def _get_relevant_source_files(
×
73
    sources: Iterable[SourcesField], with_js: bool = False
74
) -> SourceFiles:
75
    return await determine_source_files(
×
76
        SourceFilesRequest(
77
            sources,
78
            for_sources_types=(PackageJsonSourceField, FileSourceField)
79
            + ((ResourceSourceField, JSRuntimeSourceField) if with_js else ()),
80
            enable_codegen=True,
81
        )
82
    )
83

84

UNCOV
85
@rule
×
UNCOV
86
async def install_node_packages_for_address(
×
87
    req: InstalledNodePackageRequest,
88
    union_membership: UnionMembership,
89
    nodejs: nodejs.NodeJS,
90
) -> InstalledNodePackage:
91
    project_env = await get_nodejs_environment(NodeJSProjectEnvironmentRequest(req.address))
×
92
    target = project_env.ensure_target()
×
93
    transitive_tgts = await transitive_targets(
×
94
        TransitiveTargetsRequest([target.address]), **implicitly()
95
    )
96

97
    source_files = await _get_relevant_source_files(
×
98
        (tgt[SourcesField] for tgt in transitive_tgts.closure if tgt.has_field(SourcesField)),
99
        with_js=False,
100
    )
101
    package_digest = source_files.snapshot.digest
×
102

103
    install_result = await fallible_to_exec_result_or_raise(
×
104
        **implicitly(
105
            NodeJsProjectEnvironmentProcess(
106
                project_env,
107
                project_env.project.immutable_install_args,
108
                description=f"Installing {target[NodePackageNameField].value}@{target[NodePackageVersionField].value}.",
109
                input_digest=package_digest,
110
                output_directories=tuple(project_env.node_modules_directories),
111
            )
112
        )
113
    )
114
    node_modules = await add_prefix(AddPrefix(install_result.output_digest, project_env.root_dir))
×
115

116
    return InstalledNodePackage(
×
117
        project_env,
118
        digest=await merge_digests(
119
            MergeDigests(
120
                [
121
                    package_digest,
122
                    node_modules,
123
                ]
124
            )
125
        ),
126
    )
127

128

UNCOV
129
@rule
×
UNCOV
130
async def add_sources_to_installed_node_package(
×
131
    req: InstalledNodePackageRequest,
132
) -> InstalledNodePackageWithSource:
133
    installation = await install_node_packages_for_address(req, **implicitly())
×
134
    transitive_tgts = await transitive_targets(
×
135
        TransitiveTargetsRequest([installation.target.address]), **implicitly()
136
    )
137

138
    source_files = await _get_relevant_source_files(
×
139
        (tgt[SourcesField] for tgt in transitive_tgts.dependencies if tgt.has_field(SourcesField)),
140
        with_js=True,
141
    )
142
    digest = await merge_digests(MergeDigests((installation.digest, source_files.snapshot.digest)))
×
143
    return InstalledNodePackageWithSource(installation.project_env, digest=digest)
×
144

145

UNCOV
146
def rules() -> Iterable[Rule | UnionRule]:
×
UNCOV
147
    return [
×
148
        *nodejs.rules(),
149
        *nodejs_project_environment.rules(),
150
        *dependency_inference_rules(),
151
        *collect_rules(),
152
    ]
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