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

pantsbuild / pants / 18822648545

26 Oct 2025 07:24PM UTC coverage: 79.831% (-0.4%) from 80.28%
18822648545

Pull #22809

github

web-flow
Merge 9401c4830 into 170094e99
Pull Request #22809: golang: fix Go SDK version check for coverage experiment

0 of 1 new or added line in 1 file covered. (0.0%)

439 existing lines in 25 files now uncovered.

77436 of 97000 relevant lines covered (79.83%)

3.35 hits per line

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

76.39
/src/python/pants/backend/go/target_type_rules_test.py
1
# Copyright 2021 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 textwrap import dedent
1✔
7

8
import pytest
1✔
9

10
from pants.backend.go import target_type_rules
1✔
11
from pants.backend.go.target_types import (
1✔
12
    GoBinaryMainPackageField,
13
    GoBinaryTarget,
14
    GoImportPathField,
15
    GoModTarget,
16
    GoPackageSourcesField,
17
    GoPackageTarget,
18
    GoThirdPartyPackageTarget,
19
)
20
from pants.backend.go.testutil import gen_module_gomodproxy
1✔
21
from pants.backend.go.util_rules import (
1✔
22
    assembly,
23
    build_pkg,
24
    first_party_pkg,
25
    go_mod,
26
    link,
27
    sdk,
28
    third_party_pkg,
29
)
30
from pants.backend.go.util_rules.binary import (
1✔
31
    GoBinaryMainDependencyInferenceFieldSet,
32
    GoBinaryMainPackage,
33
    GoBinaryMainPackageRequest,
34
    InferGoBinaryMainDependencyRequest,
35
)
36
from pants.build_graph.address import Address, ResolveError
1✔
37
from pants.core.target_types import (
1✔
38
    GenericTarget,
39
    TargetGeneratorSourcesHelperSourcesField,
40
    TargetGeneratorSourcesHelperTarget,
41
)
42
from pants.engine.addresses import Addresses
1✔
43
from pants.engine.internals.graph import _TargetParametrizations, _TargetParametrizationsRequest
1✔
44
from pants.engine.rules import QueryRule
1✔
45
from pants.engine.target import (
1✔
46
    Dependencies,
47
    DependenciesRequest,
48
    InferredDependencies,
49
    InvalidFieldException,
50
    InvalidTargetException,
51
)
52
from pants.testutil.rule_runner import RuleRunner, engine_error
1✔
53

54
# -----------------------------------------------------------------------------------------------
55
# Dependency inference
56
# -----------------------------------------------------------------------------------------------
57

58

59
@pytest.fixture
1✔
60
def rule_runner() -> RuleRunner:
1✔
61
    rule_runner = RuleRunner(
1✔
62
        rules=[
63
            *go_mod.rules(),
64
            *first_party_pkg.rules(),
65
            *third_party_pkg.rules(),
66
            *sdk.rules(),
67
            *target_type_rules.rules(),
68
            *build_pkg.rules(),
69
            *link.rules(),
70
            *assembly.rules(),
71
            QueryRule(_TargetParametrizations, [_TargetParametrizationsRequest]),
72
            QueryRule(Addresses, [DependenciesRequest]),
73
            QueryRule(GoBinaryMainPackage, [GoBinaryMainPackageRequest]),
74
            QueryRule(InferredDependencies, [InferGoBinaryMainDependencyRequest]),
75
        ],
76
        target_types=[
77
            GoModTarget,
78
            GoPackageTarget,
79
            GoBinaryTarget,
80
            GenericTarget,
81
        ],
82
    )
83
    rule_runner.set_options([], env_inherit={"PATH"})
1✔
84
    return rule_runner
1✔
85

86

87
def test_go_package_dependency_inference(rule_runner: RuleRunner) -> None:
1✔
88
    # TODO(#12761): Add tests for ambiguous dependencies.
89
    rule_runner.write_files(
1✔
90
        {
91
            "foo/BUILD": "go_mod()",
92
            "foo/go.mod": dedent(
93
                """\
94
                    module go.example.com/foo
95
                    go 1.17
96

97
                    require (
98
                        rsc.io/quote v1.5.2
99
                        golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
100
                        rsc.io/sampler v1.3.0 // indirect
101
                    )
102
                    """
103
            ),
104
            "foo/go.sum": dedent(
105
                """\
106
                golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
107
                golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
108
                rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y=
109
                rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
110
                rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
111
                rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
112
                """
113
            ),
114
            "foo/pkg/foo.go": dedent(
115
                """\
116
                    package pkg
117
                    import "rsc.io/quote"
118
                    """
119
            ),
120
            "foo/pkg/BUILD": "go_package()",
121
            "foo/cmd/main.go": dedent(
122
                """\
123
                    package main
124
                    import (
125
                        "fmt"
126
                        "go.example.com/foo/pkg"
127
                    )
128
                    """
129
            ),
130
            "foo/cmd/BUILD": "go_package()",
131
            "foo/bad/f.go": "invalid!!!",
132
            "foo/bad/BUILD": "go_package()",
133
        }
134
    )
135

136
    def get_deps(addr: Address) -> set[Address]:
1✔
137
        tgt = rule_runner.get_target(addr)
1✔
138
        return set(
1✔
139
            rule_runner.request(
140
                Addresses,
141
                [DependenciesRequest(tgt[Dependencies])],
142
            )
143
        )
144

145
    go_mod_file_tgts = {Address("foo", relative_file_path=fp) for fp in ("go.mod", "go.sum")}
1✔
146

147
    assert get_deps(Address("foo/cmd")) == {
1✔
148
        Address("foo/pkg"),
149
    }
UNCOV
150
    assert get_deps(Address("foo/pkg")) == {Address("foo", generated_name="rsc.io/quote")}
×
UNCOV
151
    assert get_deps(Address("foo", generated_name="rsc.io/quote")) == {
×
152
        Address("foo", generated_name="rsc.io/sampler"),
153
        *go_mod_file_tgts,
154
    }
UNCOV
155
    assert get_deps(Address("foo", generated_name="rsc.io/sampler")) == {
×
156
        Address("foo", generated_name="golang.org/x/text/language"),
157
        *go_mod_file_tgts,
158
    }
UNCOV
159
    assert get_deps(Address("foo", generated_name="golang.org/x/text")) == go_mod_file_tgts
×
160
    # Compilation failures should not blow up Pants.
UNCOV
161
    assert not get_deps(Address("foo/bad"))
×
162

163

164
# -----------------------------------------------------------------------------------------------
165
# `go_package` validation
166
# -----------------------------------------------------------------------------------------------
167

168

169
def test_go_package_sources_field_validation() -> None:
1✔
170
    with pytest.raises(InvalidTargetException):
1✔
171
        GoPackageTarget({GoPackageSourcesField.alias: ()}, Address("pkg"))
1✔
172
    with pytest.raises(InvalidTargetException):
1✔
173
        GoPackageTarget({GoPackageSourcesField.alias: ("**.go",)}, Address("pkg"))
1✔
174
    with pytest.raises(InvalidTargetException):
1✔
175
        GoPackageTarget({GoPackageSourcesField.alias: ("subdir/f.go",)}, Address("pkg"))
1✔
176

177

178
# -----------------------------------------------------------------------------------------------
179
# Generate package targets from `go_mod`
180
# -----------------------------------------------------------------------------------------------
181

182

183
def test_generate_package_targets(rule_runner: RuleRunner) -> None:
1✔
184
    rule_runner.write_files(
1✔
185
        {
186
            "src/go/BUILD": "go_mod()\n",
187
            "src/go/go.mod": dedent(
188
                """\
189
                module example.com/src/go
190
                go 1.17
191

192
                require (
193
                    github.com/google/go-cmp v0.4.0
194
                    github.com/google/uuid v1.2.0
195
                    golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
196
                )
197
                """
198
            ),
199
            "src/go/go.sum": dedent(
200
                """\
201
                github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
202
                github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
203
                github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
204
                github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
205
                golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
206
                golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
207
                """
208
            ),
209
            "src/go/hello.go": "",
210
            "src/go/subdir/f.go": "",
211
            "src/go/subdir/f2.go": "",
212
            "src/go/another_dir/subdir/f.go": "",
213
        }
214
    )
215
    generated = rule_runner.request(
1✔
216
        _TargetParametrizations,
217
        [_TargetParametrizationsRequest(Address("src/go"), description_of_origin="tests")],
218
    ).parametrizations
219

UNCOV
220
    file_tgts = [
×
221
        TargetGeneratorSourcesHelperTarget(
222
            {TargetGeneratorSourcesHelperSourcesField.alias: fp},
223
            Address("src/go", relative_file_path=fp),
224
        )
225
        for fp in ("go.mod", "go.sum")
226
    ]
227

UNCOV
228
    def gen_third_party_tgt(import_path: str) -> GoThirdPartyPackageTarget:
×
UNCOV
229
        return GoThirdPartyPackageTarget(
×
230
            {
231
                GoImportPathField.alias: import_path,
232
                Dependencies.alias: [t.address.spec for t in file_tgts],
233
            },
234
            Address("src/go", generated_name=import_path),
235
        )
236

UNCOV
237
    all_third_party = {
×
238
        gen_third_party_tgt(pkg)
239
        for pkg in (
240
            "github.com/google/uuid",
241
            "github.com/google/go-cmp/cmp",
242
            "github.com/google/go-cmp/cmp/cmpopts",
243
            "github.com/google/go-cmp/cmp/internal/diff",
244
            "github.com/google/go-cmp/cmp/internal/flags",
245
            "github.com/google/go-cmp/cmp/internal/function",
246
            "github.com/google/go-cmp/cmp/internal/testprotos",
247
            "github.com/google/go-cmp/cmp/internal/teststructs",
248
            "github.com/google/go-cmp/cmp/internal/value",
249
            "golang.org/x/xerrors",
250
            "golang.org/x/xerrors/internal",
251
        )
252
    }
UNCOV
253
    assert set(generated.values()) == {*file_tgts, *all_third_party}
×
254

255

256
def test_third_party_package_targets_cannot_be_manually_created() -> None:
1✔
257
    with pytest.raises(InvalidTargetException):
1✔
258
        GoThirdPartyPackageTarget(
1✔
259
            {GoImportPathField.alias: "foo"},
260
            Address("foo"),
261
        )
262

263

264
# -----------------------------------------------------------------------------------------------
265
# The `main` field for `go_binary`
266
# -----------------------------------------------------------------------------------------------
267

268

269
def test_determine_main_pkg_for_go_binary(rule_runner: RuleRunner) -> None:
1✔
270
    import_path = "pantsbuild.org/go-sample-for-test"
1✔
271
    version = "v0.0.1"
1✔
272

273
    fake_gomod = gen_module_gomodproxy(
1✔
274
        version,
275
        import_path,
276
        (
277
            (
278
                "pkg/hello/hello.go",
279
                dedent(
280
                    """\
281
        package hello
282
        import "fmt"
283

284

285
        func Hello() {
286
            fmt.Println("Hello world!")
287
        }
288
        """
289
                ),
290
            ),
291
            (
292
                "cmd/hello/main.go",
293
                dedent(
294
                    f"""\
295
        package main
296
        import "{import_path}/pkg/hello"
297

298

299
        func main() {{
300
            hello.Hello()
301
        }}
302
        """
303
                ),
304
            ),
305
        ),
306
    )
307

308
    # mypy gets sad if update is reversed or ** is used here
309
    fake_gomod.update(
1✔
310
        {
311
            "go.mod": dedent(
312
                f"""\
313
                module example.com/foo
314
                go 1.16
315

316
                require (
317
                \t{import_path} {version}
318
                )
319
                """
320
            ),
321
            "BUILD": "go_mod(name='mod')",
322
            "explicit/f.go": "",
323
            "explicit/BUILD": "go_binary(main=':pkg')\ngo_package(name='pkg')",
324
            "inferred/f.go": "",
325
            "inferred/BUILD": "go_binary()\ngo_package(name='pkg')",
326
            "ambiguous/f.go": "",
327
            "ambiguous/BUILD": "go_binary()\ngo_package(name='pkg1')\ngo_package(name='pkg2')",
328
            "external/BUILD": f"go_binary(main='//:mod#{import_path}/cmd/hello')",
329
            # Note there are no `.go` files in this dir.
330
            "missing/BUILD": "go_binary()",
331
            "explicit_wrong_type/BUILD": dedent(
332
                """\
333
                target(name='dep')
334
                go_binary(main=':dep')
335
                """
336
            ),
337
        }
338
    )
339

340
    rule_runner.write_files(fake_gomod)
1✔
341

342
    rule_runner.set_options(
1✔
343
        [
344
            "--go-test-args=-v -bench=.",
345
            f"--golang-subprocess-env-vars=GOPROXY=file://{rule_runner.build_root}/go-mod-proxy",
346
            "--golang-subprocess-env-vars=GOSUMDB=off",
347
        ],
348
        env_inherit={"PATH"},
349
    )
350

351
    def get_main(addr: Address) -> Address:
1✔
352
        tgt = rule_runner.get_target(addr)
1✔
353
        main_addr = rule_runner.request(
1✔
354
            GoBinaryMainPackage, [GoBinaryMainPackageRequest(tgt[GoBinaryMainPackageField])]
355
        ).address
356
        inferred_addresses = rule_runner.request(
1✔
357
            InferredDependencies,
358
            [
359
                InferGoBinaryMainDependencyRequest(
360
                    GoBinaryMainDependencyInferenceFieldSet.create(tgt)
361
                )
362
            ],
363
        )
364
        assert inferred_addresses == InferredDependencies([main_addr])
1✔
365
        return main_addr
1✔
366

367
    assert get_main(Address("explicit")) == Address("explicit", target_name="pkg")
1✔
368
    assert get_main(Address("inferred")) == Address("inferred", target_name="pkg")
1✔
UNCOV
369
    assert get_main(Address("external")) == Address(
×
370
        "",
371
        target_name="mod",
372
        generated_name="pantsbuild.org/go-sample-for-test/cmd/hello",
373
    )
374

UNCOV
375
    with engine_error(ResolveError, contains="none were found"):
×
UNCOV
376
        get_main(Address("missing"))
×
UNCOV
377
    with engine_error(ResolveError, contains="There are multiple `go_package` targets"):
×
UNCOV
378
        get_main(Address("ambiguous"))
×
UNCOV
379
    with engine_error(
×
380
        InvalidFieldException, contains="a `go_package` or `go_third_party_package` target"
381
    ):
UNCOV
382
        get_main(Address("explicit_wrong_type"))
×
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