build(deps): bump github.com/onsi/ginkgo/v2 from 2.17.3 to 2.19.0

Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.17.3 to 2.19.0.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.17.3...v2.19.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2024-05-27 09:23:16 +02:00
committed by Ralf Haferkamp
parent 7b47d55837
commit 7999751890
27 changed files with 519 additions and 184 deletions
+2 -2
View File
@@ -68,7 +68,7 @@ require (
github.com/oklog/run v1.1.0
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.17.3
github.com/onsi/ginkgo/v2 v2.19.0
github.com/onsi/gomega v1.33.1
github.com/open-policy-agent/opa v0.64.1
github.com/orcaman/concurrent-map v1.0.0
@@ -342,7 +342,7 @@ require (
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.20.0 // indirect
golang.org/x/tools v0.21.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect
+4 -4
View File
@@ -1785,8 +1785,8 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU=
github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
@@ -2640,8 +2640,8 @@ golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+20
View File
@@ -1,3 +1,23 @@
## 2.19.0
### Features
[Label Sets](https://onsi.github.io/ginkgo/#label-sets) allow for more expressive and flexible label filtering.
## 2.18.0
### Features
- Add --slience-skips and --force-newlines [f010b65]
- fail when no tests were run and --fail-on-empty was set [d80eebe]
### Fixes
- Fix table entry context edge case [42013d6]
### Maintenance
- Bump golang.org/x/tools from 0.20.0 to 0.21.0 (#1406) [fcf1fd7]
- Bump github.com/onsi/gomega from 1.33.0 to 1.33.1 (#1399) [8bb14fd]
- Bump golang.org/x/net from 0.24.0 to 0.25.0 (#1407) [04bfad7]
## 2.17.3
### Fixes
+6 -4
View File
@@ -6,8 +6,10 @@ Your contributions to Ginkgo are essential for its long-term maintenance and imp
- Ensure adequate test coverage:
- When adding to the Ginkgo library, add unit and/or integration tests (under the `integration` folder).
- When adding to the Ginkgo CLI, note that there are very few unit tests. Please add an integration test.
- Make sure all the tests succeed via `ginkgo -r -p`
- Vet your changes via `go vet ./...`
- Update the documentation. Ginkgo uses `godoc` comments and documentation in `docs/index.md`. You can run `bundle exec jekyll serve` in the `docs` directory to preview your changes.
- Run `make` or:
- Install ginkgo locally via `go install ./...`
- Make sure all the tests succeed via `ginkgo -r -p`
- Vet your changes via `go vet ./...`
- Update the documentation. Ginkgo uses `godoc` comments and documentation in `docs/index.md`. You can run `bundle && bundle exec jekyll serve` in the `docs` directory to preview your changes.
Thanks for supporting Ginkgo!
Thanks for supporting Ginkgo!
+11
View File
@@ -0,0 +1,11 @@
# default task since it's first
.PHONY: all
all: vet test
.PHONY: test
test:
go run github.com/onsi/ginkgo/v2/ginkgo -r -p
.PHONY: vet
vet:
go vet ./...
+6 -1
View File
@@ -489,10 +489,15 @@ func (suite *Suite) runSpecs(description string, suiteLabels Labels, suitePath s
newGroup(suite).run(specs.AtIndices(groupedSpecIndices[groupedSpecIdx]))
}
if specs.HasAnySpecsMarkedPending() && suite.config.FailOnPending {
if suite.config.FailOnPending && specs.HasAnySpecsMarkedPending() {
suite.report.SpecialSuiteFailureReasons = append(suite.report.SpecialSuiteFailureReasons, "Detected pending specs and --fail-on-pending is set")
suite.report.SuiteSucceeded = false
}
if suite.config.FailOnEmpty && specs.CountWithoutSkip() == 0 {
suite.report.SpecialSuiteFailureReasons = append(suite.report.SpecialSuiteFailureReasons, "Detected no specs ran and --fail-on-empty is set")
suite.report.SuiteSucceeded = false
}
}
if ranBeforeSuite {
+9 -1
View File
@@ -202,6 +202,11 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) {
v := r.conf.Verbosity()
inParallel := report.RunningInParallel
//should we completely omit this spec?
if report.State.Is(types.SpecStateSkipped) && r.conf.SilenceSkips {
return
}
header := r.specDenoter
if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) {
header = fmt.Sprintf("[%s]", report.LeafNodeType)
@@ -278,9 +283,12 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) {
}
}
// If we have no content to show, jsut emit the header and return
// If we have no content to show, just emit the header and return
if !reportHasContent {
r.emit(r.f(highlightColor + header + "{{/}}"))
if r.conf.ForceNewlines {
r.emit("\n")
}
return
}
+1
View File
@@ -177,6 +177,7 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
{"FocusFiles", strings.Join(report.SuiteConfig.FocusFiles, ";")},
{"SkipFiles", strings.Join(report.SuiteConfig.SkipFiles, ";")},
{"FailOnPending", fmt.Sprintf("%t", report.SuiteConfig.FailOnPending)},
{"FailOnEmpty", fmt.Sprintf("%t", report.SuiteConfig.FailOnEmpty)},
{"FailFast", fmt.Sprintf("%t", report.SuiteConfig.FailFast)},
{"FlakeAttempts", fmt.Sprintf("%d", report.SuiteConfig.FlakeAttempts)},
{"DryRun", fmt.Sprintf("%t", report.SuiteConfig.DryRun)},
+6 -2
View File
@@ -269,11 +269,15 @@ func generateTable(description string, isSubtree bool, args ...interface{}) {
internalNodeArgs = append(internalNodeArgs, entry.decorations...)
hasContext := false
if internalBodyType.NumIn() > 0. {
if internalBodyType.NumIn() > 0 {
if internalBodyType.In(0).Implements(specContextType) {
hasContext = true
} else if internalBodyType.In(0).Implements(contextType) && (len(entry.parameters) == 0 || !reflect.TypeOf(entry.parameters[0]).Implements(contextType)) {
} else if internalBodyType.In(0).Implements(contextType) {
hasContext = true
if len(entry.parameters) > 0 && reflect.TypeOf(entry.parameters[0]) != nil && reflect.TypeOf(entry.parameters[0]).Implements(contextType) {
// we allow you to pass in a non-nil context
hasContext = false
}
}
}
+9
View File
@@ -25,6 +25,7 @@ type SuiteConfig struct {
SkipFiles []string
LabelFilter string
FailOnPending bool
FailOnEmpty bool
FailFast bool
FlakeAttempts int
MustPassRepeatedly int
@@ -90,6 +91,8 @@ type ReporterConfig struct {
FullTrace bool
ShowNodeEvents bool
GithubOutput bool
SilenceSkips bool
ForceNewlines bool
JSONReport string
JUnitReport string
@@ -275,6 +278,8 @@ var SuiteConfigFlags = GinkgoFlags{
Usage: "If set, ginkgo will stop running a test suite after a failure occurs."},
{KeyPath: "S.FlakeAttempts", Name: "flake-attempts", SectionKey: "failure", UsageDefaultValue: "0 - failed tests are not retried", DeprecatedName: "flakeAttempts", DeprecatedDocLink: "changed-command-line-flags",
Usage: "Make up to this many attempts to run each spec. If any of the attempts succeed, the suite will not be failed."},
{KeyPath: "S.FailOnEmpty", Name: "fail-on-empty", SectionKey: "failure",
Usage: "If set, ginkgo will mark the test suite as failed if no specs are run."},
{KeyPath: "S.DryRun", Name: "dry-run", SectionKey: "debug", DeprecatedName: "dryRun", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v."},
@@ -334,6 +339,10 @@ var ReporterConfigFlags = GinkgoFlags{
Usage: "If set, default reporter prints node > Enter and < Exit events when specs fail"},
{KeyPath: "R.GithubOutput", Name: "github-output", SectionKey: "output",
Usage: "If set, default reporter prints easier to manage output in Github Actions."},
{KeyPath: "R.SilenceSkips", Name: "silence-skips", SectionKey: "output",
Usage: "If set, default reporter will not print out skipped tests."},
{KeyPath: "R.ForceNewlines", Name: "force-newlines", SectionKey: "output",
Usage: "If set, default reporter will ensure a newline appears after each test."},
{KeyPath: "R.JSONReport", Name: "json-report", UsageArgument: "filename.json", SectionKey: "output",
Usage: "If set, Ginkgo will generate a JSON-formatted test report at the specified location."},
+227 -2
View File
@@ -45,6 +45,83 @@ func orAction(a, b LabelFilter) LabelFilter {
return func(labels []string) bool { return a(labels) || b(labels) }
}
func labelSetFor(key string, labels []string) map[string]bool {
key = strings.ToLower(strings.TrimSpace(key))
out := map[string]bool{}
for _, label := range labels {
components := strings.SplitN(label, ":", 2)
if len(components) < 2 {
continue
}
if key == strings.ToLower(strings.TrimSpace(components[0])) {
out[strings.ToLower(strings.TrimSpace(components[1]))] = true
}
}
return out
}
func isEmptyLabelSetAction(key string) LabelFilter {
return func(labels []string) bool {
return len(labelSetFor(key, labels)) == 0
}
}
func containsAnyLabelSetAction(key string, expectedValues []string) LabelFilter {
return func(labels []string) bool {
set := labelSetFor(key, labels)
for _, value := range expectedValues {
if set[value] {
return true
}
}
return false
}
}
func containsAllLabelSetAction(key string, expectedValues []string) LabelFilter {
return func(labels []string) bool {
set := labelSetFor(key, labels)
for _, value := range expectedValues {
if !set[value] {
return false
}
}
return true
}
}
func consistsOfLabelSetAction(key string, expectedValues []string) LabelFilter {
return func(labels []string) bool {
set := labelSetFor(key, labels)
if len(set) != len(expectedValues) {
return false
}
for _, value := range expectedValues {
if !set[value] {
return false
}
}
return true
}
}
func isSubsetOfLabelSetAction(key string, expectedValues []string) LabelFilter {
expectedSet := map[string]bool{}
for _, value := range expectedValues {
expectedSet[value] = true
}
return func(labels []string) bool {
set := labelSetFor(key, labels)
for value := range set {
if !expectedSet[value] {
return false
}
}
return true
}
}
type lfToken uint
const (
@@ -58,6 +135,9 @@ const (
lfTokenOr
lfTokenRegexp
lfTokenLabel
lfTokenSetKey
lfTokenSetOperation
lfTokenSetArgument
lfTokenEOF
)
@@ -71,6 +151,8 @@ func (l lfToken) Precedence() int {
return 2
case lfTokenNot:
return 3
case lfTokenSetOperation:
return 4
}
return -1
}
@@ -93,6 +175,12 @@ func (l lfToken) String() string {
return "/regexp/"
case lfTokenLabel:
return "label"
case lfTokenSetKey:
return "set_key"
case lfTokenSetOperation:
return "set_operation"
case lfTokenSetArgument:
return "set_argument"
case lfTokenEOF:
return "EOF"
}
@@ -148,6 +236,35 @@ func (tn *treeNode) constructLabelFilter(input string) (LabelFilter, error) {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("RegExp compilation error: %s", err))
}
return matchLabelRegexAction(re), nil
case lfTokenSetOperation:
tokenSetOperation := strings.ToLower(tn.value)
if tokenSetOperation == "isempty" {
return isEmptyLabelSetAction(tn.leftNode.value), nil
}
if tn.rightNode == nil {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("Set operation '%s' is missing an argument.", tn.value))
}
rawValues := strings.Split(tn.rightNode.value, ",")
values := make([]string, len(rawValues))
for i := range rawValues {
values[i] = strings.ToLower(strings.TrimSpace(rawValues[i]))
if strings.ContainsAny(values[i], "&|!,()/") {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.rightNode.location, fmt.Sprintf("Invalid label value '%s' in set operation argument.", values[i]))
} else if values[i] == "" {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.rightNode.location, "Empty label value in set operation argument.")
}
}
switch tokenSetOperation {
case "containsany":
return containsAnyLabelSetAction(tn.leftNode.value, values), nil
case "containsall":
return containsAllLabelSetAction(tn.leftNode.value, values), nil
case "consistsof":
return consistsOfLabelSetAction(tn.leftNode.value, values), nil
case "issubsetof":
return isSubsetOfLabelSetAction(tn.leftNode.value, values), nil
}
}
if tn.rightNode == nil {
@@ -203,7 +320,17 @@ func (tn *treeNode) toString(indent int) string {
return out
}
var validSetOperations = map[string]string{
"containsany": "containsAny",
"containsall": "containsAll",
"consistsof": "consistsOf",
"issubsetof": "isSubsetOf",
"isempty": "isEmpty",
}
func tokenize(input string) func() (*treeNode, error) {
lastToken := lfTokenInvalid
lastValue := ""
runes, i := []rune(input), 0
peekIs := func(r rune) bool {
@@ -233,6 +360,53 @@ func tokenize(input string) func() (*treeNode, error) {
}
node := &treeNode{location: i}
defer func() {
lastToken = node.token
lastValue = node.value
}()
if lastToken == lfTokenSetKey {
//we should get a valid set operation next
value, n := consumeUntil(" )")
if validSetOperations[strings.ToLower(value)] == "" {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, fmt.Sprintf("Invalid set operation '%s'.", value))
}
i += n
node.token, node.value = lfTokenSetOperation, value
return node, nil
}
if lastToken == lfTokenSetOperation {
//we should get an argument next, if we aren't isempty
var arg = ""
origI := i
if runes[i] == '{' {
i += 1
value, n := consumeUntil("}")
if i+n >= len(runes) {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i-1, "Missing closing '}' in set operation argument?")
}
i += n + 1
arg = value
} else {
value, n := consumeUntil("&|!,()/")
i += n
arg = strings.TrimSpace(value)
}
if strings.ToLower(lastValue) == "isempty" && arg != "" {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, origI, fmt.Sprintf("isEmpty does not take arguments, was passed '%s'.", arg))
}
if arg == "" && strings.ToLower(lastValue) != "isempty" {
if i < len(runes) && runes[i] == '/' {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, origI, "Set operations do not support regular expressions.")
} else {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, origI, fmt.Sprintf("Set operation '%s' requires an argument.", lastValue))
}
}
// note that we sent an empty SetArgument token if we are isempty
node.token, node.value = lfTokenSetArgument, arg
return node, nil
}
switch runes[i] {
case '&':
if !peekIs('&') {
@@ -264,8 +438,38 @@ func tokenize(input string) func() (*treeNode, error) {
i += n + 1
node.token, node.value = lfTokenRegexp, value
default:
value, n := consumeUntil("&|!,()/")
value, n := consumeUntil("&|!,()/:")
i += n
value = strings.TrimSpace(value)
//are we the beginning of a set operation?
if i < len(runes) && runes[i] == ':' {
if peekIs(' ') {
if value == "" {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Missing set key.")
}
i += 1
//we are the beginning of a set operation
node.token, node.value = lfTokenSetKey, value
return node, nil
}
additionalValue, n := consumeUntil("&|!,()/")
additionalValue = strings.TrimSpace(additionalValue)
if additionalValue == ":" {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Missing set operation.")
}
i += n
value += additionalValue
}
valueToCheckForSetOperation := strings.ToLower(value)
for setOperation := range validSetOperations {
idx := strings.Index(valueToCheckForSetOperation, " "+setOperation)
if idx > 0 {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i-n+idx+1, fmt.Sprintf("Looks like you are using the set operator '%s' but did not provide a set key. Did you forget the ':'?", validSetOperations[setOperation]))
}
}
node.token, node.value = lfTokenLabel, strings.TrimSpace(value)
}
return node, nil
@@ -307,7 +511,7 @@ LOOP:
switch node.token {
case lfTokenEOF:
break LOOP
case lfTokenLabel, lfTokenRegexp:
case lfTokenLabel, lfTokenRegexp, lfTokenSetKey:
if current.rightNode != nil {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, "Found two adjacent labels. You need an operator between them.")
}
@@ -326,6 +530,18 @@ LOOP:
node.setLeftNode(nodeToStealFrom.rightNode)
nodeToStealFrom.setRightNode(node)
current = node
case lfTokenSetOperation:
if current.rightNode == nil {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Set operation '%s' missing left hand operand.", node.value))
}
node.setLeftNode(current.rightNode)
current.setRightNode(node)
current = node
case lfTokenSetArgument:
if current.rightNode != nil {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Unexpected set argument '%s'.", node.token))
}
current.setRightNode(node)
case lfTokenCloseGroup:
firstUnmatchedOpenNode := current.firstUnmatchedOpenNode()
if firstUnmatchedOpenNode == nil {
@@ -354,5 +570,14 @@ func ValidateAndCleanupLabel(label string, cl CodeLocation) (string, error) {
if strings.ContainsAny(out, "&|!,()/") {
return "", GinkgoErrors.InvalidLabel(label, cl)
}
if out[0] == ':' {
return "", GinkgoErrors.InvalidLabel(label, cl)
}
if strings.Contains(out, ":") {
components := strings.SplitN(out, ":", 2)
if len(components) < 2 || components[1] == "" {
return "", GinkgoErrors.InvalidLabel(label, cl)
}
}
return out, nil
}
+1 -1
View File
@@ -1,3 +1,3 @@
package types
const VERSION = "2.17.3"
const VERSION = "2.19.0"
+29 -10
View File
@@ -129,9 +129,8 @@ type Config struct {
Mode LoadMode
// Context specifies the context for the load operation.
// If the context is cancelled, the loader may stop early
// and return an ErrCancelled error.
// If Context is nil, the load cannot be cancelled.
// Cancelling the context may cause [Load] to abort and
// return an error.
Context context.Context
// Logf is the logger for the config.
@@ -214,8 +213,8 @@ type Config struct {
// Config specifies loading options;
// nil behaves the same as an empty Config.
//
// Load returns an error if any of the patterns was invalid
// as defined by the underlying build system.
// If any of the patterns was invalid as defined by the
// underlying build system, Load returns an error.
// It may return an empty list of packages without an error,
// for instance for an empty expansion of a valid wildcard.
// Errors associated with a particular package are recorded in the
@@ -428,6 +427,10 @@ type Package struct {
// The NeedTypes LoadMode bit sets this field for packages matching the
// patterns; type information for dependencies may be missing or incomplete,
// unless NeedDeps and NeedImports are also set.
//
// Each call to [Load] returns a consistent set of type
// symbols, as defined by the comment at [types.Identical].
// Avoid mixing type information from two or more calls to [Load].
Types *types.Package
// Fset provides position information for Types, TypesInfo, and Syntax.
@@ -854,6 +857,12 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
wg.Wait()
}
// If the context is done, return its error and
// throw out [likely] incomplete packages.
if err := ld.Context.Err(); err != nil {
return nil, err
}
result := make([]*Package, len(initial))
for i, lpkg := range initial {
result[i] = lpkg.Package
@@ -949,6 +958,14 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
lpkg.Types = types.NewPackage(lpkg.PkgPath, lpkg.Name)
lpkg.Fset = ld.Fset
// Start shutting down if the context is done and do not load
// source or export data files.
// Packages that import this one will have ld.Context.Err() != nil.
// ld.Context.Err() will be returned later by refine.
if ld.Context.Err() != nil {
return
}
// Subtle: we populate all Types fields with an empty Package
// before loading export data so that export data processing
// never has to create a types.Package for an indirect dependency,
@@ -1068,6 +1085,13 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
return
}
// Start shutting down if the context is done and do not type check.
// Packages that import this one will have ld.Context.Err() != nil.
// ld.Context.Err() will be returned later by refine.
if ld.Context.Err() != nil {
return
}
lpkg.TypesInfo = &types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Defs: make(map[*ast.Ident]types.Object),
@@ -1245,11 +1269,6 @@ func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) {
parsed := make([]*ast.File, n)
errors := make([]error, n)
for i, file := range filenames {
if ld.Config.Context.Err() != nil {
parsed[i] = nil
errors[i] = ld.Config.Context.Err()
continue
}
wg.Add(1)
go func(i int, filename string) {
parsed[i], errors[i] = ld.parseFile(filename)
+8 -4
View File
@@ -16,10 +16,14 @@ import (
// NewAlias creates a new TypeName in Package pkg that
// is an alias for the type rhs.
//
// When GoVersion>=1.22 and GODEBUG=gotypesalias=1,
// the Type() of the return value is a *types.Alias.
func NewAlias(pos token.Pos, pkg *types.Package, name string, rhs types.Type) *types.TypeName {
if enabled() {
// The enabled parameter determines whether the resulting [TypeName]'s
// type is an [types.Alias]. Its value must be the result of a call to
// [Enabled], which computes the effective value of
// GODEBUG=gotypesalias=... by invoking the type checker. The Enabled
// function is expensive and should be called once per task (e.g.
// package import), not once per call to NewAlias.
func NewAlias(enabled bool, pos token.Pos, pkg *types.Package, name string, rhs types.Type) *types.TypeName {
if enabled {
tname := types.NewTypeName(pos, pkg, name, nil)
newAlias(tname, rhs)
return tname
+8 -7
View File
@@ -15,16 +15,17 @@ import (
// It will never be created by go/types.
type Alias struct{}
func (*Alias) String() string { panic("unreachable") }
func (*Alias) String() string { panic("unreachable") }
func (*Alias) Underlying() types.Type { panic("unreachable") }
func (*Alias) Obj() *types.TypeName { panic("unreachable") }
func (*Alias) Obj() *types.TypeName { panic("unreachable") }
func Rhs(alias *Alias) types.Type { panic("unreachable") }
// Unalias returns the type t for go <=1.21.
func Unalias(t types.Type) types.Type { return t }
// Always false for go <=1.21. Ignores GODEBUG.
func enabled() bool { return false }
func newAlias(name *types.TypeName, rhs types.Type) *Alias { panic("unreachable") }
// Enabled reports whether [NewAlias] should create [types.Alias] types.
//
// Before go1.22, this function always returns false.
func Enabled() bool { return false }
+30 -39
View File
@@ -12,14 +12,22 @@ import (
"go/parser"
"go/token"
"go/types"
"os"
"strings"
"sync"
)
// Alias is an alias of types.Alias.
type Alias = types.Alias
// Rhs returns the type on the right-hand side of the alias declaration.
func Rhs(alias *Alias) types.Type {
if alias, ok := any(alias).(interface{ Rhs() types.Type }); ok {
return alias.Rhs() // go1.23+
}
// go1.22's Alias didn't have the Rhs method,
// so Unalias is the best we can do.
return Unalias(alias)
}
// Unalias is a wrapper of types.Unalias.
func Unalias(t types.Type) types.Type { return types.Unalias(t) }
@@ -33,40 +41,23 @@ func newAlias(tname *types.TypeName, rhs types.Type) *Alias {
return a
}
// enabled returns true when types.Aliases are enabled.
func enabled() bool {
// Use the gotypesalias value in GODEBUG if set.
godebug := os.Getenv("GODEBUG")
value := -1 // last set value.
for _, f := range strings.Split(godebug, ",") {
switch f {
case "gotypesalias=1":
value = 1
case "gotypesalias=0":
value = 0
}
}
switch value {
case 0:
return false
case 1:
return true
default:
return aliasesDefault()
}
// Enabled reports whether [NewAlias] should create [types.Alias] types.
//
// This function is expensive! Call it sparingly.
func Enabled() bool {
// The only reliable way to compute the answer is to invoke go/types.
// We don't parse the GODEBUG environment variable, because
// (a) it's tricky to do so in a manner that is consistent
// with the godebug package; in particular, a simple
// substring check is not good enough. The value is a
// rightmost-wins list of options. But more importantly:
// (b) it is impossible to detect changes to the effective
// setting caused by os.Setenv("GODEBUG"), as happens in
// many tests. Therefore any attempt to cache the result
// is just incorrect.
fset := token.NewFileSet()
f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", 0)
pkg, _ := new(types.Config).Check("p", fset, []*ast.File{f}, nil)
_, enabled := pkg.Scope().Lookup("A").Type().(*types.Alias)
return enabled
}
// aliasesDefault reports if aliases are enabled by default.
func aliasesDefault() bool {
// Dynamically check if Aliases will be produced from go/types.
aliasesDefaultOnce.Do(func() {
fset := token.NewFileSet()
f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", 0)
pkg, _ := new(types.Config).Check("p", fset, []*ast.File{f}, nil)
_, gotypesaliasDefault = pkg.Scope().Lookup("A").Type().(*types.Alias)
})
return gotypesaliasDefault
}
var gotypesaliasDefault bool
var aliasesDefaultOnce sync.Once
-59
View File
@@ -1,59 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package tag provides the labels used for telemetry throughout gopls.
package tag
import (
"golang.org/x/tools/internal/event/keys"
)
var (
// create the label keys we use
Method = keys.NewString("method", "")
StatusCode = keys.NewString("status.code", "")
StatusMessage = keys.NewString("status.message", "")
RPCID = keys.NewString("id", "")
RPCDirection = keys.NewString("direction", "")
File = keys.NewString("file", "")
Directory = keys.New("directory", "")
URI = keys.New("URI", "")
Package = keys.NewString("package", "") // sorted comma-separated list of Package IDs
PackagePath = keys.NewString("package_path", "")
Query = keys.New("query", "")
Snapshot = keys.NewUInt64("snapshot", "")
Operation = keys.NewString("operation", "")
Position = keys.New("position", "")
Category = keys.NewString("category", "")
PackageCount = keys.NewInt("packages", "")
Files = keys.New("files", "")
Port = keys.NewInt("port", "")
Type = keys.New("type", "")
HoverKind = keys.NewString("hoverkind", "")
NewServer = keys.NewString("new_server", "A new server was added")
EndServer = keys.NewString("end_server", "A server was shut down")
ServerID = keys.NewString("server", "The server ID an event is related to")
Logfile = keys.NewString("logfile", "")
DebugAddress = keys.NewString("debug_address", "")
GoplsPath = keys.NewString("gopls_path", "")
ClientID = keys.NewString("client_id", "")
Level = keys.NewInt("level", "The logging level")
)
var (
// create the stats we measure
Started = keys.NewInt64("started", "Count of started RPCs.")
ReceivedBytes = keys.NewInt64("received_bytes", "Bytes received.") //, unit.Bytes)
SentBytes = keys.NewInt64("sent_bytes", "Bytes sent.") //, unit.Bytes)
Latency = keys.NewFloat64("latency_ms", "Elapsed time in milliseconds") //, unit.Milliseconds)
)
const (
Inbound = "in"
Outbound = "out"
)
+1 -18
View File
@@ -21,7 +21,6 @@ import (
"sort"
"strconv"
"strings"
"unsafe"
"golang.org/x/tools/go/types/objectpath"
"golang.org/x/tools/internal/aliases"
@@ -529,7 +528,7 @@ func (p *iexporter) doDecl(obj types.Object) {
if alias, ok := t.(*aliases.Alias); ok {
// Preserve materialized aliases,
// even of non-exported types.
t = aliasRHS(alias)
t = aliases.Rhs(alias)
}
w.typ(t, obj.Pkg())
break
@@ -1331,19 +1330,3 @@ func (e internalError) Error() string { return "gcimporter: " + string(e) }
func internalErrorf(format string, args ...interface{}) error {
return internalError(fmt.Sprintf(format, args...))
}
// aliasRHS removes exactly one Alias constructor.
func aliasRHS(alias *aliases.Alias) types.Type {
// TODO(adonovan): if proposal #66559 is accepted, this will
// become Alias.RHS(alias). In the meantime, we must punch
// through the drywall.
type go123Alias struct {
_ *types.TypeName
_ *types.TypeParamList
RHS types.Type
_ types.Type
}
var raw *go123Alias
*(**aliases.Alias)(unsafe.Pointer(&raw)) = alias
return raw.RHS
}
+3 -1
View File
@@ -210,6 +210,7 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte
p := iimporter{
version: int(version),
ipath: path,
aliases: aliases.Enabled(),
shallow: shallow,
reportf: reportf,
@@ -369,6 +370,7 @@ type iimporter struct {
version int
ipath string
aliases bool
shallow bool
reportf ReportFunc // if non-nil, used to report bugs
@@ -567,7 +569,7 @@ func (r *importReader) obj(name string) {
// tparams := r.tparamList()
// alias.SetTypeParams(tparams)
// }
r.declare(aliases.NewAlias(pos, r.currPkg, name, typ))
r.declare(aliases.NewAlias(r.p.aliases, pos, r.currPkg, name, typ))
case constTag:
typ, val := r.value()
+3 -1
View File
@@ -26,6 +26,7 @@ type pkgReader struct {
ctxt *types.Context
imports map[string]*types.Package // previously imported packages, indexed by path
aliases bool // create types.Alias nodes
// lazily initialized arrays corresponding to the unified IR
// PosBase, Pkg, and Type sections, respectively.
@@ -99,6 +100,7 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st
ctxt: ctxt,
imports: imports,
aliases: aliases.Enabled(),
posBases: make([]string, input.NumElems(pkgbits.RelocPosBase)),
pkgs: make([]*types.Package, input.NumElems(pkgbits.RelocPkg)),
@@ -524,7 +526,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
case pkgbits.ObjAlias:
pos := r.pos()
typ := r.typ()
declare(aliases.NewAlias(pos, objPkg, objName, typ))
declare(aliases.NewAlias(r.p.aliases, pos, objPkg, objName, typ))
case pkgbits.ObjConst:
pos := r.pos()
+6 -4
View File
@@ -25,7 +25,6 @@ import (
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/event/keys"
"golang.org/x/tools/internal/event/label"
"golang.org/x/tools/internal/event/tag"
)
// An Runner will run go command invocations and serialize
@@ -55,11 +54,14 @@ func (runner *Runner) initialize() {
// 1.14: go: updating go.mod: existing contents have changed since last read
var modConcurrencyError = regexp.MustCompile(`go:.*go.mod.*contents have changed`)
// verb is an event label for the go command verb.
var verb = keys.NewString("verb", "go command verb")
// event keys for go command invocations
var (
verb = keys.NewString("verb", "go command verb")
directory = keys.NewString("directory", "")
)
func invLabels(inv Invocation) []label.Label {
return []label.Label{verb.Of(inv.Verb), tag.Directory.Of(inv.WorkingDir)}
return []label.Label{verb.Of(inv.Verb), directory.Of(inv.WorkingDir)}
}
// Run is a convenience wrapper around RunRaw.
+54
View File
@@ -107,3 +107,57 @@ func getMainModuleAnd114(ctx context.Context, inv Invocation, r *Runner) (*Modul
}
return mod, lines[4] == "go1.14", nil
}
// WorkspaceVendorEnabled reports whether workspace vendoring is enabled. It takes a *Runner to execute Go commands
// with the supplied context.Context and Invocation. The Invocation can contain pre-defined fields,
// of which only Verb and Args are modified to run the appropriate Go command.
// Inspired by setDefaultBuildMod in modload/init.go
func WorkspaceVendorEnabled(ctx context.Context, inv Invocation, r *Runner) (bool, []*ModuleJSON, error) {
inv.Verb = "env"
inv.Args = []string{"GOWORK"}
stdout, err := r.Run(ctx, inv)
if err != nil {
return false, nil, err
}
goWork := string(bytes.TrimSpace(stdout.Bytes()))
if fi, err := os.Stat(filepath.Join(filepath.Dir(goWork), "vendor")); err == nil && fi.IsDir() {
mainMods, err := getWorkspaceMainModules(ctx, inv, r)
if err != nil {
return false, nil, err
}
return true, mainMods, nil
}
return false, nil, nil
}
// getWorkspaceMainModules gets the main modules' information.
// This is the information needed to figure out if vendoring should be enabled.
func getWorkspaceMainModules(ctx context.Context, inv Invocation, r *Runner) ([]*ModuleJSON, error) {
const format = `{{.Path}}
{{.Dir}}
{{.GoMod}}
{{.GoVersion}}
`
inv.Verb = "list"
inv.Args = []string{"-m", "-f", format}
stdout, err := r.Run(ctx, inv)
if err != nil {
return nil, err
}
lines := strings.Split(strings.TrimSuffix(stdout.String(), "\n"), "\n")
if len(lines) < 4 {
return nil, fmt.Errorf("unexpected stdout: %q", stdout.String())
}
mods := make([]*ModuleJSON, 0, len(lines)/4)
for i := 0; i < len(lines); i += 4 {
mods = append(mods, &ModuleJSON{
Path: lines[i],
Dir: lines[i+1],
GoMod: lines[i+2],
GoVersion: lines[i+3],
Main: true,
})
}
return mods, nil
}
+34 -4
View File
@@ -301,6 +301,20 @@ func (p *pass) loadPackageNames(imports []*ImportInfo) error {
return nil
}
// if there is a trailing major version, remove it
func withoutVersion(nm string) string {
if v := path.Base(nm); len(v) > 0 && v[0] == 'v' {
if _, err := strconv.Atoi(v[1:]); err == nil {
// this is, for instance, called with rand/v2 and returns rand
if len(v) < len(nm) {
xnm := nm[:len(nm)-len(v)-1]
return path.Base(xnm)
}
}
}
return nm
}
// importIdentifier returns the identifier that imp will introduce. It will
// guess if the package name has not been loaded, e.g. because the source
// is not available.
@@ -310,7 +324,7 @@ func (p *pass) importIdentifier(imp *ImportInfo) string {
}
known := p.knownPackages[imp.ImportPath]
if known != nil && known.name != "" {
return known.name
return withoutVersion(known.name)
}
return ImportPathToAssumedName(imp.ImportPath)
}
@@ -1059,6 +1073,18 @@ func addStdlibCandidates(pass *pass, refs references) error {
if err != nil {
return err
}
localbase := func(nm string) string {
ans := path.Base(nm)
if ans[0] == 'v' {
// this is called, for instance, with math/rand/v2 and returns rand/v2
if _, err := strconv.Atoi(ans[1:]); err == nil {
ix := strings.LastIndex(nm, ans)
more := path.Base(nm[:ix])
ans = path.Join(more, ans)
}
}
return ans
}
add := func(pkg string) {
// Prevent self-imports.
if path.Base(pkg) == pass.f.Name.Name && filepath.Join(goenv["GOROOT"], "src", pkg) == pass.srcDir {
@@ -1067,13 +1093,17 @@ func addStdlibCandidates(pass *pass, refs references) error {
exports := symbolNameSet(stdlib.PackageSymbols[pkg])
pass.addCandidate(
&ImportInfo{ImportPath: pkg},
&packageInfo{name: path.Base(pkg), exports: exports})
&packageInfo{name: localbase(pkg), exports: exports})
}
for left := range refs {
if left == "rand" {
// Make sure we try crypto/rand before math/rand.
// Make sure we try crypto/rand before any version of math/rand as both have Int()
// and our policy is to recommend crypto
add("crypto/rand")
add("math/rand")
// if the user's no later than go1.21, this should be "math/rand"
// but we have no way of figuring out what the user is using
// TODO: investigate using the toolchain version to disambiguate in the stdlib
add("math/rand/v2")
continue
}
for importPath := range stdlib.PackageSymbols {
+33 -15
View File
@@ -112,11 +112,11 @@ func newModuleResolver(e *ProcessEnv, moduleCacheCache *DirInfoCache) (*ModuleRe
}
vendorEnabled := false
var mainModVendor *gocommand.ModuleJSON
var mainModVendor *gocommand.ModuleJSON // for module vendoring
var mainModsVendor []*gocommand.ModuleJSON // for workspace vendoring
// Module vendor directories are ignored in workspace mode:
// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md
if len(r.env.Env["GOWORK"]) == 0 {
goWork := r.env.Env["GOWORK"]
if len(goWork) == 0 {
// TODO(rfindley): VendorEnabled runs the go command to get GOFLAGS, but
// they should be available from the ProcessEnv. Can we avoid the redundant
// invocation?
@@ -124,18 +124,35 @@ func newModuleResolver(e *ProcessEnv, moduleCacheCache *DirInfoCache) (*ModuleRe
if err != nil {
return nil, err
}
} else {
vendorEnabled, mainModsVendor, err = gocommand.WorkspaceVendorEnabled(context.Background(), inv, r.env.GocmdRunner)
if err != nil {
return nil, err
}
}
if mainModVendor != nil && vendorEnabled {
// Vendor mode is on, so all the non-Main modules are irrelevant,
// and we need to search /vendor for everything.
r.mains = []*gocommand.ModuleJSON{mainModVendor}
r.dummyVendorMod = &gocommand.ModuleJSON{
Path: "",
Dir: filepath.Join(mainModVendor.Dir, "vendor"),
if vendorEnabled {
if mainModVendor != nil {
// Module vendor mode is on, so all the non-Main modules are irrelevant,
// and we need to search /vendor for everything.
r.mains = []*gocommand.ModuleJSON{mainModVendor}
r.dummyVendorMod = &gocommand.ModuleJSON{
Path: "",
Dir: filepath.Join(mainModVendor.Dir, "vendor"),
}
r.modsByModPath = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod}
r.modsByDir = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod}
} else {
// Workspace vendor mode is on, so all the non-Main modules are irrelevant,
// and we need to search /vendor for everything.
r.mains = mainModsVendor
r.dummyVendorMod = &gocommand.ModuleJSON{
Path: "",
Dir: filepath.Join(filepath.Dir(goWork), "vendor"),
}
r.modsByModPath = append(append([]*gocommand.ModuleJSON{}, mainModsVendor...), r.dummyVendorMod)
r.modsByDir = append(append([]*gocommand.ModuleJSON{}, mainModsVendor...), r.dummyVendorMod)
}
r.modsByModPath = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod}
r.modsByDir = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod}
} else {
// Vendor mode is off, so run go list -m ... to find everything.
err := r.initAllMods()
@@ -166,8 +183,9 @@ func newModuleResolver(e *ProcessEnv, moduleCacheCache *DirInfoCache) (*ModuleRe
return count(j) < count(i) // descending order
})
r.roots = []gopathwalk.Root{
{Path: filepath.Join(goenv["GOROOT"], "/src"), Type: gopathwalk.RootGOROOT},
r.roots = []gopathwalk.Root{}
if goenv["GOROOT"] != "" { // "" happens in tests
r.roots = append(r.roots, gopathwalk.Root{Path: filepath.Join(goenv["GOROOT"], "/src"), Type: gopathwalk.RootGOROOT})
}
r.mainByDir = make(map[string]*gocommand.ModuleJSON)
for _, main := range r.mains {
+4
View File
@@ -23,6 +23,9 @@ type PkgDecoder struct {
// version is the file format version.
version uint32
// aliases determines whether types.Aliases should be created
aliases bool
// sync indicates whether the file uses sync markers.
sync bool
@@ -73,6 +76,7 @@ func (pr *PkgDecoder) SyncMarkers() bool { return pr.sync }
func NewPkgDecoder(pkgPath, input string) PkgDecoder {
pr := PkgDecoder{
pkgPath: pkgPath,
//aliases: aliases.Enabled(),
}
// TODO(mdempsky): Implement direct indexing of input string to
+2 -2
View File
@@ -1449,10 +1449,10 @@ const (
NotAGenericType
// WrongTypeArgCount occurs when a type or function is instantiated with an
// incorrent number of type arguments, including when a generic type or
// incorrect number of type arguments, including when a generic type or
// function is used without instantiation.
//
// Errors inolving failed type inference are assigned other error codes.
// Errors involving failed type inference are assigned other error codes.
//
// Example:
// type T[p any] int
+2 -3
View File
@@ -1477,7 +1477,7 @@ github.com/onsi/ginkgo/reporters/stenographer
github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable
github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty
github.com/onsi/ginkgo/types
# github.com/onsi/ginkgo/v2 v2.17.3
# github.com/onsi/ginkgo/v2 v2.19.0
## explicit; go 1.20
github.com/onsi/ginkgo/v2
github.com/onsi/ginkgo/v2/config
@@ -2168,7 +2168,7 @@ golang.org/x/text/width
# golang.org/x/time v0.5.0
## explicit; go 1.18
golang.org/x/time/rate
# golang.org/x/tools v0.20.0
# golang.org/x/tools v0.21.0
## explicit; go 1.19
golang.org/x/tools/cmd/stringer
golang.org/x/tools/cover
@@ -2184,7 +2184,6 @@ golang.org/x/tools/internal/event
golang.org/x/tools/internal/event/core
golang.org/x/tools/internal/event/keys
golang.org/x/tools/internal/event/label
golang.org/x/tools/internal/event/tag
golang.org/x/tools/internal/gcimporter
golang.org/x/tools/internal/gocommand
golang.org/x/tools/internal/gopathwalk