• 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

97.5
/src/python/pants/backend/debian/rules.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
1✔
5

6
from collections.abc import Iterable
1✔
7
from dataclasses import dataclass
1✔
8
from pathlib import PurePath
1✔
9

10
from pants.backend.debian.target_types import (
1✔
11
    DebianInstallPrefix,
12
    DebianPackageDependencies,
13
    DebianSources,
14
)
15
from pants.core.goals.package import (
1✔
16
    BuiltPackage,
17
    BuiltPackageArtifact,
18
    OutputPathField,
19
    PackageFieldSet,
20
)
21
from pants.core.util_rules.system_binaries import BinaryPathRequest, TarBinary, find_binary
1✔
22
from pants.engine.fs import CreateDigest, FileEntry
1✔
23
from pants.engine.internals.graph import hydrate_sources
1✔
24
from pants.engine.intrinsics import create_digest, get_digest_entries
1✔
25
from pants.engine.process import Process, execute_process_or_raise
1✔
26
from pants.engine.rules import Rule, collect_rules, implicitly, rule
1✔
27
from pants.engine.target import HydrateSourcesRequest
1✔
28
from pants.engine.unions import UnionRule
1✔
29
from pants.util.logging import LogLevel
1✔
30

31

32
@dataclass(frozen=True)
1✔
33
class DebianPackageFieldSet(PackageFieldSet):
1✔
34
    required_fields = (DebianSources, DebianInstallPrefix, DebianPackageDependencies)
1✔
35

36
    sources_dir: DebianSources
1✔
37
    install_prefix: DebianInstallPrefix
1✔
38
    packages: DebianPackageDependencies
1✔
39
    output_path: OutputPathField
1✔
40

41

42
@rule(level=LogLevel.INFO)
1✔
43
async def package_debian_package(
1✔
44
    field_set: DebianPackageFieldSet, tar_binary_path: TarBinary
45
) -> BuiltPackage:
46
    dpkg_deb_path = await find_binary(
1✔
47
        BinaryPathRequest(
48
            binary_name="dpkg-deb",
49
            search_path=["/usr/bin"],
50
        ),
51
        **implicitly(),
52
    )
53
    if not dpkg_deb_path.first_path:
1✔
54
        raise OSError(f"Could not find the `{dpkg_deb_path.binary_name}` program in `/usr/bin`.")
×
55

56
    hydrated_sources = await hydrate_sources(
1✔
57
        HydrateSourcesRequest(field_set.sources_dir), **implicitly()
58
    )
59

60
    # Since all the sources are coming only from a single directory, it is
61
    # safe to pick an arbitrary file and get its root directory name.
62
    # Validation of the resolved files has been called on the target, so it is known that
63
    # snapshot.files isn't empty.
64
    sources_directory_name = PurePath(hydrated_sources.snapshot.files[0]).parts[0]
1✔
65

66
    result = await execute_process_or_raise(
1✔
67
        **implicitly(
68
            Process(
69
                argv=(
70
                    dpkg_deb_path.first_path.path,
71
                    "--build",
72
                    sources_directory_name,
73
                ),
74
                description="Create a Debian package from the produced packages.",
75
                input_digest=hydrated_sources.snapshot.digest,
76
                # dpkg-deb produces a file with the same name as the input directory
77
                output_files=(f"{sources_directory_name}.deb",),
78
                env={"PATH": str(PurePath(tar_binary_path.path).parent)},
79
            )
80
        )
81
    )
82
    # The output Debian package file needs to be renamed to match the output_path field.
83
    output_filename = field_set.output_path.value_or_default(
1✔
84
        file_ending="deb",
85
    )
86
    digest_entries = await get_digest_entries(result.output_digest)
1✔
87
    assert len(digest_entries) == 1
1✔
88
    result_file_entry = digest_entries[0]
1✔
89
    assert isinstance(result_file_entry, FileEntry)
1✔
90
    new_file = FileEntry(output_filename, result_file_entry.file_digest)
1✔
91

92
    final_result = await create_digest(CreateDigest([new_file]))
1✔
93
    return BuiltPackage(final_result, artifacts=(BuiltPackageArtifact(output_filename),))
1✔
94

95

96
def rules() -> Iterable[Rule | UnionRule]:
1✔
97
    return (
1✔
98
        *collect_rules(),
99
        UnionRule(PackageFieldSet, DebianPackageFieldSet),
100
    )
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