• 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

95.45
/src/python/pants/backend/codegen/export_codegen_goal.py
1
# Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
import logging
7✔
5

6
from pants.core.util_rules.distdir import DistDir
7✔
7
from pants.engine.fs import MergeDigests, Workspace
7✔
8
from pants.engine.goal import Goal, GoalSubsystem
7✔
9
from pants.engine.internals.graph import hydrate_sources
7✔
10
from pants.engine.intrinsics import merge_digests
7✔
11
from pants.engine.rules import collect_rules, concurrently, goal_rule, implicitly
7✔
12
from pants.engine.target import (
7✔
13
    FilteredTargets,
14
    GenerateSourcesRequest,
15
    HydrateSourcesRequest,
16
    RegisteredTargetTypes,
17
    SourcesField,
18
)
19
from pants.engine.unions import UnionMembership
7✔
20
from pants.util.strutil import softwrap
7✔
21

22
logger = logging.getLogger(__name__)
7✔
23

24

25
class ExportCodegenSubsystem(GoalSubsystem):
7✔
26
    name = "export-codegen"
7✔
27
    help = "Write generated files to `dist/codegen` for use outside of Pants."
7✔
28

29
    @classmethod
7✔
30
    def activated(cls, union_membership: UnionMembership) -> bool:
7✔
31
        return GenerateSourcesRequest in union_membership
×
32

33

34
class ExportCodegen(Goal):
7✔
35
    subsystem_cls = ExportCodegenSubsystem
7✔
36
    environment_behavior = Goal.EnvironmentBehavior.LOCAL_ONLY  # TODO(#17129) — Migrate this.
7✔
37

38

39
@goal_rule
7✔
40
async def export_codegen(
7✔
41
    targets: FilteredTargets,
42
    union_membership: UnionMembership,
43
    workspace: Workspace,
44
    dist_dir: DistDir,
45
    registered_target_types: RegisteredTargetTypes,
46
) -> ExportCodegen:
47
    # We run all possible code generators. Running codegen requires specifying the expected
48
    # output_type, so we must inspect what is possible to generate.
49
    all_generate_request_types = union_membership.get(GenerateSourcesRequest)
1✔
50
    inputs_to_outputs = [
1✔
51
        (req.input, req.output) for req in all_generate_request_types if req.exportable
52
    ]
53
    codegen_sources_fields_with_output = []
1✔
54
    for tgt in targets:
1✔
55
        if not tgt.has_field(SourcesField):
1✔
56
            continue
×
57
        sources = tgt[SourcesField]
1✔
58
        for input_type, output_type in inputs_to_outputs:
1✔
59
            if isinstance(sources, input_type):
1✔
60
                codegen_sources_fields_with_output.append((sources, output_type))
1✔
61

62
    if not codegen_sources_fields_with_output:
1✔
63
        codegen_targets = sorted(
1✔
64
            {
65
                tgt_type.alias
66
                for tgt_type in registered_target_types.types
67
                for input_source in {input_source for input_source, _ in inputs_to_outputs}
68
                if tgt_type.class_has_field(input_source, union_membership=union_membership)
69
            }
70
        )
71
        logger.warning(
1✔
72
            softwrap(
73
                f"""
74
                No codegen files/targets matched. All codegen target types:
75
                {", ".join(codegen_targets)}
76
                """
77
            )
78
        )
79
        return ExportCodegen(exit_code=0)
1✔
80

81
    all_hydrated_sources = await concurrently(
1✔
82
        hydrate_sources(
83
            HydrateSourcesRequest(
84
                sources,
85
                for_sources_types=(output_type,),
86
                enable_codegen=True,
87
            ),
88
            **implicitly(),
89
        )
90
        for sources, output_type in codegen_sources_fields_with_output
91
    )
92

93
    merged_digest = await merge_digests(
1✔
94
        MergeDigests(hydrated_sources.snapshot.digest for hydrated_sources in all_hydrated_sources)
95
    )
96

97
    dest = str(dist_dir.relpath / "codegen")
1✔
98
    logger.info(f"Writing generated files to {dest}")
1✔
99
    workspace.write_digest(merged_digest, path_prefix=dest)
1✔
100
    return ExportCodegen(exit_code=0)
1✔
101

102

103
def rules():
7✔
104
    return collect_rules()
7✔
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