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

pantsbuild / pants / 25443604553

06 May 2026 03:05PM UTC coverage: 92.879% (-0.04%) from 92.915%
25443604553

push

github

web-flow
[pants_ng] Scaffolding for a pants_ng mode. (#23319)

In this mode the command line is parsed as an
NG invocation, and dispatched appropriately.

Of course at the moment there are no
implementations to dispatch to. That will follow.

This does expose a new option, `pants_ng` to users. 
There is a big warning not to set it, but we're not trying
to hide that we're working on a new thing, so I am
comfortable with this.

25 of 76 new or added lines in 9 files covered. (32.89%)

1294 existing lines in 76 files now uncovered.

92234 of 99306 relevant lines covered (92.88%)

4.05 hits per line

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

100.0
/src/python/pants/backend/project_info/count_loc_test.py
1
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
import pytest
3✔
5

6
from pants.backend.project_info import count_loc
3✔
7
from pants.backend.project_info.count_loc import CountLinesOfCode
3✔
8
from pants.backend.python import target_types_rules
3✔
9
from pants.backend.python.target_types import PythonSourcesGeneratorTarget
3✔
10
from pants.core.util_rules import external_tool
3✔
11
from pants.engine.target import MultipleSourcesField, Target
3✔
12
from pants.testutil.rule_runner import GoalRuleResult, RuleRunner
3✔
13

14

15
class ElixirSources(MultipleSourcesField):
3✔
16
    default = ("*.ex",)
3✔
17

18

19
class ElixirTarget(Target):
3✔
20
    alias = "elixir"
3✔
21
    core_fields = (ElixirSources,)
3✔
22

23

24
@pytest.fixture
3✔
25
def rule_runner() -> RuleRunner:
3✔
26
    return RuleRunner(
3✔
27
        rules=[
28
            *count_loc.rules(),
29
            *external_tool.rules(),
30
            *target_types_rules.rules(),
31
        ],
32
        target_types=[PythonSourcesGeneratorTarget, ElixirTarget],
33
    )
34

35

36
def assert_counts(
3✔
37
    stdout: str, lang: str, *, num_files: int = 1, blank: int = 0, comment: int = 0, code: int = 0
38
) -> None:
39
    summary_line = next(
3✔
40
        (
41
            line
42
            for line in stdout.splitlines()
43
            if len(line.split()) in (6, 7) and line.split()[0] == lang
44
        ),
45
        None,
46
    )
47
    assert summary_line is not None, f"Found no output line for {lang} given stdout:\n {stdout}"
3✔
48
    fields = summary_line.split()
3✔
49
    assert num_files == int(fields[1])
3✔
50
    assert blank == int(fields[3])
3✔
51
    assert comment == int(fields[4])
3✔
52
    assert code == int(fields[5])
3✔
53

54

55
@pytest.mark.platform_specific_behavior
3✔
56
def test_count_loc(rule_runner: RuleRunner) -> None:
3✔
57
    py_dir = "src/py/foo"
3✔
58
    elixir_dir = "src/elixir/foo"
3✔
59
    rule_runner.write_files(
3✔
60
        {
61
            f"{py_dir}/foo.py": '# A comment.\n\nprint("some code")\n# Another comment.',
62
            f"{py_dir}/bar.py": '# A comment.\n\nprint("some more code")',
63
            f"{py_dir}/BUILD": "python_sources(name='lib')",
64
            f"{elixir_dir}/foo.ex": 'IO.puts("Some elixir")\n# A comment',
65
            f"{elixir_dir}/ignored.ex": "# We do not expect this file to appear in counts.",
66
            f"{elixir_dir}/BUILD": "elixir(name='lib', sources=['foo.ex'])",
67
        }
68
    )
69
    result = rule_runner.run_goal_rule(
3✔
70
        CountLinesOfCode, args=[f"{py_dir}:lib", f"{elixir_dir}:lib"]
71
    )
72
    assert result.exit_code == 0
3✔
73
    assert_counts(result.stdout, "Python", num_files=2, blank=2, comment=3, code=2)
3✔
74
    assert_counts(result.stdout, "Elixir", comment=1, code=1)
3✔
75

76

77
def test_passthrough_args(rule_runner: RuleRunner) -> None:
3✔
UNCOV
78
    rule_runner.write_files(
1✔
79
        {"foo.py": "print('hello world!')\n", "BUILD": "python_sources(name='foo')"}
80
    )
UNCOV
81
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=["//:foo", "--", "--no-cocomo"])
1✔
UNCOV
82
    assert result.exit_code == 0
1✔
UNCOV
83
    assert_counts(result.stdout, "Python", code=1)
1✔
UNCOV
84
    assert "Estimated Cost to Develop" not in result.stdout
1✔
85

86

87
def test_files_without_owners(rule_runner: RuleRunner) -> None:
3✔
88
    """cloc works on any readable file in the build root, regardless of whether it's declared in a
89
    BUILD file."""
UNCOV
90
    rule_runner.write_files(
1✔
91
        {
92
            "test/foo.ex": 'IO.puts("im a free thinker!")',
93
            "test/foo.hs": 'main = putStrLn "Whats Pants, precious?"',
94
        }
95
    )
UNCOV
96
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=["test/foo.*"])
1✔
UNCOV
97
    assert result.exit_code == 0
1✔
UNCOV
98
    assert_counts(result.stdout, "Elixir", code=1)
1✔
UNCOV
99
    assert_counts(result.stdout, "Haskell", code=1)
1✔
100

101

102
def test_no_sources_exits_gracefully(rule_runner: RuleRunner) -> None:
3✔
UNCOV
103
    py_dir = "src/py/foo"
1✔
UNCOV
104
    rule_runner.write_files({f"{py_dir}/BUILD": "python_sources(name='lib')"})
1✔
UNCOV
105
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=[f"{py_dir}:lib"])
1✔
UNCOV
106
    assert result == GoalRuleResult.noop()
1✔
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