diff --git a/internal/git/infer_module_version.go b/internal/git/infer_module_version.go index cc2f312..4776ff2 100644 --- a/internal/git/infer_module_version.go +++ b/internal/git/infer_module_version.go @@ -8,7 +8,7 @@ import ( // InferModuleVersion returns the version of the module declared in the given // directory. This will be either the work tree commit's tag, or it will be the -// most recent tag with a short revhash appended to it. +// short revhash of the HEAD commit. func InferModuleVersion(dir string) (string, error) { version, err := command.Run(dir, "git", "tag", "-l", "--points-at", "HEAD") if err != nil { diff --git a/internal/loader/loader.go b/internal/loader/loader.go index 546b76c..10f2ec6 100644 --- a/internal/loader/loader.go +++ b/internal/loader/loader.go @@ -10,6 +10,8 @@ import ( "github.com/sourcegraph/scip-go/internal/newtypes" "github.com/sourcegraph/scip-go/internal/output" "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/mod/semver" "golang.org/x/tools/go/packages" ) @@ -219,6 +221,27 @@ func normalizePackage(opts *config.IndexOpts, pkg *packages.Package) *packages.P pkg.Module.Version = "." } + } else if module.IsPseudoVersion(pkg.Module.Version) { + // Unpublished versions of dependencies have pseudo-versions in go.mod. + // When the dependency itself is indexed, only the revision will be used. + // For correct cross-repo navigation to such dependencies, only use + // the revision from a pseudo-version. + rev, err := module.PseudoVersionRev(pkg.Module.Version) + if err != nil { + // Only panic when running in debug mode. + fmt.Println(handler.ErrOrPanic( + "Unable to find rev from pseudo-version: %s %s", + pkg.Module.Path, + pkg.Module.Version, + )) + } else { + pkg.Module.Version = rev + } + } else if build := semver.Build(pkg.Module.Version); build != "" { + // The revision can also have build metadata following a `+`. Drop that, + // similar to official Go tooling. (https://go.dev/ref/mod#versions) + // > The build metadata suffix is ignored for the purpose of comparing versions + pkg.Module.Version = strings.TrimSuffix(pkg.Module.Version, build) } return pkg diff --git a/internal/loader/loader_test.go b/internal/loader/loader_test.go index 6e1f4aa..9fc10b2 100644 --- a/internal/loader/loader_test.go +++ b/internal/loader/loader_test.go @@ -7,6 +7,8 @@ import ( "testing" "github.com/sourcegraph/scip-go/internal/config" + "github.com/stretchr/testify/require" + "golang.org/x/mod/module" "golang.org/x/tools/go/packages" ) @@ -39,6 +41,81 @@ func TestBuiltinFormat(t *testing.T) { } } +type normalizeTestCase struct { + Raw string + Normalized string +} + +func TestNormalizePackageModuleVersion(t *testing.T) { + cases := []normalizeTestCase{ + { + Raw: "v0.0.0-20180920160851-f15b22f93c73", + Normalized: "f15b22f93c73", + }, + { + Raw: "v0.3.1-0.20230414160720-beea233bdc0b", + Normalized: "beea233bdc0b", + }, + { + Raw: "v2.0.0-20180818164646-67afb5ed74ec", + Normalized: "67afb5ed74ec", + }, + { + Raw: "v1.1.1", + Normalized: "v1.1.1", + }, + { + Raw: "v1.0.0-beta.1", + Normalized: "v1.0.0-beta.1", + }, + { + Raw: "v0.0.0", + Normalized: "v0.0.0", + }, + { + Raw: "v2.0.0+incompatible", + Normalized: "v2.0.0", + }, + { + Raw: "", + Normalized: ".", + }, + } + + for _, testCase := range cases { + pkg := &packages.Package{ + PkgPath: "github.com/fake_name/fake_module/fake_package", + Module: &packages.Module{ + Path: "github.com/fake_name/fake_module", + Version: testCase.Raw, + }, + } + normalizePackage(&config.IndexOpts{}, pkg) + + require.Equal(t, testCase.Normalized, pkg.Module.Version) + } +} + +func TestPackagePseudoVersion(t *testing.T) { + wd, _ := os.Getwd() + root, _ := filepath.Abs(filepath.Join(wd, "../../")) + pkgConfig := getConfig(root, config.IndexOpts{}) + pkgConfig.Tests = false + + pkgs, err := packages.Load(pkgConfig, "github.com/efritz/pentimento") + require.Nil(t, err) + + require.Equal(t, 1, len(pkgs), "Too many packages") + + pkg := pkgs[0] + + require.True(t, module.IsPseudoVersion(pkg.Module.Version), "Package did not have a pseudo version: pre ensure") + + normalizePackage(&config.IndexOpts{}, pkg) + + require.Equal(t, "ade47d831101", pkg.Module.Version, "Package pseudo-version was not extracted into a sha: post ensure") +} + func TestPackageWithinModule(t *testing.T) { wd, _ := os.Getwd() root, _ := filepath.Abs(filepath.Join(wd, "../../")) diff --git a/internal/testdata/snapshots/output/generallyeric/new_operators.go b/internal/testdata/snapshots/output/generallyeric/new_operators.go index 3cf43b6..ddc964a 100755 --- a/internal/testdata/snapshots/output/generallyeric/new_operators.go +++ b/internal/testdata/snapshots/output/generallyeric/new_operators.go @@ -2,19 +2,19 @@ // ^^^^^^^^^^^^^ reference 0.1.test `sg/generallyeric`/ import "golang.org/x/exp/constraints" -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reference golang.org/x/exp v0.0.0-20221205204356-47842c84f3db `golang.org/x/exp/constraints`/ +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reference golang.org/x/exp 47842c84f3db `golang.org/x/exp/constraints`/ type Number interface { // ^^^^^^ definition 0.1.test `sg/generallyeric`/Number# // documentation ```go // documentation ```go constraints.Float | constraints.Integer | constraints.Complex -// ^^^^^^^^^^^ reference golang.org/x/exp v0.0.0-20221205204356-47842c84f3db `golang.org/x/exp/constraints`/ -// ^^^^^ reference golang.org/x/exp v0.0.0-20221205204356-47842c84f3db `golang.org/x/exp/constraints`/Float# -// ^^^^^^^^^^^ reference golang.org/x/exp v0.0.0-20221205204356-47842c84f3db `golang.org/x/exp/constraints`/ -// ^^^^^^^ reference golang.org/x/exp v0.0.0-20221205204356-47842c84f3db `golang.org/x/exp/constraints`/Integer# -// ^^^^^^^^^^^ reference golang.org/x/exp v0.0.0-20221205204356-47842c84f3db `golang.org/x/exp/constraints`/ -// ^^^^^^^ reference golang.org/x/exp v0.0.0-20221205204356-47842c84f3db `golang.org/x/exp/constraints`/Complex# +// ^^^^^^^^^^^ reference golang.org/x/exp 47842c84f3db `golang.org/x/exp/constraints`/ +// ^^^^^ reference golang.org/x/exp 47842c84f3db `golang.org/x/exp/constraints`/Float# +// ^^^^^^^^^^^ reference golang.org/x/exp 47842c84f3db `golang.org/x/exp/constraints`/ +// ^^^^^^^ reference golang.org/x/exp 47842c84f3db `golang.org/x/exp/constraints`/Integer# +// ^^^^^^^^^^^ reference golang.org/x/exp 47842c84f3db `golang.org/x/exp/constraints`/ +// ^^^^^^^ reference golang.org/x/exp 47842c84f3db `golang.org/x/exp/constraints`/Complex# } func Double[T Number](value T) T { diff --git a/internal/testdata/snapshots/output/replace-directives/replace_directives.go b/internal/testdata/snapshots/output/replace-directives/replace_directives.go index b4f462a..3df6f88 100755 --- a/internal/testdata/snapshots/output/replace-directives/replace_directives.go +++ b/internal/testdata/snapshots/output/replace-directives/replace_directives.go @@ -7,7 +7,7 @@ // ^^^ reference github.com/golang/go/src go1.22 fmt/ "github.com/dghubble/gologin" -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ reference github.com/sourcegraph/gologin v1.0.2-0.20181110030308-c6f1b62954d8 `github.com/dghubble/gologin`/ +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ reference github.com/sourcegraph/gologin c6f1b62954d8 `github.com/dghubble/gologin`/ ) func Something() { @@ -16,7 +16,7 @@ fmt.Println(gologin.DefaultCookieConfig) // ^^^ reference github.com/golang/go/src go1.22 fmt/ // ^^^^^^^ reference github.com/golang/go/src go1.22 fmt/Println(). -// ^^^^^^^ reference github.com/sourcegraph/gologin v1.0.2-0.20181110030308-c6f1b62954d8 `github.com/dghubble/gologin`/ -// ^^^^^^^^^^^^^^^^^^^ reference github.com/sourcegraph/gologin v1.0.2-0.20181110030308-c6f1b62954d8 `github.com/dghubble/gologin`/DefaultCookieConfig. +// ^^^^^^^ reference github.com/sourcegraph/gologin c6f1b62954d8 `github.com/dghubble/gologin`/ +// ^^^^^^^^^^^^^^^^^^^ reference github.com/sourcegraph/gologin c6f1b62954d8 `github.com/dghubble/gologin`/DefaultCookieConfig. }