Skip to content

Commit

Permalink
internal: direct user to latest major version in current package
Browse files Browse the repository at this point in the history
Currently, the pkgsite allows the user to click a link to be taken
to the latest major version for that module. When a user is in a sub
package, clicking this link transports them to the top of the
directory, rather than the latest major version for that package.

Changes the behaviour of the link by directing to the latest
major version of the currently viewed package. If the package
does not exist in the latest major version, it falls back to
the root of the module.

The direct proxy datasource implementation does not attempt to
perform this resolution and maintains the current behaviour.

Fixes golang/go#42292

Change-Id: I6c17978034f87ceddb0edeae3894ce2cd4913fd2
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/274413
Trust: Julie Qiu <julie@golang.org>
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
  • Loading branch information
Charlotte Brandhorst-Satzkorn authored and julieqiu committed Dec 8, 2020
1 parent 68d251e commit 69b3ffd
Show file tree
Hide file tree
Showing 12 changed files with 386 additions and 171 deletions.
2 changes: 1 addition & 1 deletion content/static/html/helpers/_unit_header.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<span class="UnitHeader-badge">{{.}}</span>
{{end}}
</div>
<div class="UnitHeader-versionBanner $$GODISCOVERY_LATESTMAJORCLASS$$">
<div class="UnitHeader-versionBanner $$GODISCOVERY_LATESTMAJORCLASS$$" data-test-id="UnitHeader-versionBanner">
<img height="19px" width="16px" class="UnitHeader-detailIcon" src="/static/img/pkg-icon-info_19x16.svg" alt="">
<span>
The highest tagged major version is <a href="/$$GODISCOVERY_LATESTMAJORVERSIONURL$$">$$GODISCOVERY_LATESTMAJORVERSION$$</a>.
Expand Down
10 changes: 8 additions & 2 deletions internal/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ type DataSource interface {
// See the internal/postgres package for further documentation of these
// methods, particularly as they pertain to the main postgres implementation.

// GetLatestMajorVersion returns the latest major version of a series path.
GetLatestMajorVersion(ctx context.Context, seriesPath string) (_ string, err error)
// GetLatestMajorVersion returns the latest module path and the full package path
// of the latest version found, given the fullPath and the modulePath.
// For example, in the module path "github.com/casbin/casbin", there
// is another module path with a greater major version "github.com/casbin/casbin/v3".
// This function will return "github.com/casbin/casbin/v3" or the input module path
// if no later module path was found. It also returns the full package path at the
// latest module version if it exists. If not, it returns the module path.
GetLatestMajorVersion(ctx context.Context, fullPath, modulePath string) (_ string, _ string, err error)
// GetNestedModules returns the latest major version of all nested modules
// given a modulePath path prefix.
GetNestedModules(ctx context.Context, modulePath string) ([]*ModuleInfo, error)
Expand Down
13 changes: 6 additions & 7 deletions internal/frontend/latest_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,18 @@ import (
"golang.org/x/pkgsite/internal/log"
)

// GetLatestMajorVersion returns the major version of a package or module.
// If a module isn't found from the series path or an error ocurs, an empty string is returned
// GetLatestMajorVersion returns the latest module path and the full package path
// of any major version found given the fullPath and the modulePath.
// It is intended to be used as an argument to middleware.LatestVersions.
func (s *Server) GetLatestMajorVersion(ctx context.Context, seriesPath string) string {
mv, err := s.getDataSource(ctx).GetLatestMajorVersion(ctx, seriesPath)
func (s *Server) GetLatestMajorVersion(ctx context.Context, fullPath, modulePath string) (_ string, _ string) {
latestModulePath, latestPackagePath, err := s.getDataSource(ctx).GetLatestMajorVersion(ctx, fullPath, modulePath)
if err != nil {
if !errors.Is(err, derrors.NotFound) {
log.Errorf(ctx, "GetLatestMajorVersion: %v", err)
}
return ""
return "", ""
}

return mv
return latestModulePath, latestPackagePath
}

// GetLatestMinorVersion returns the latest minor version of the package or module.
Expand Down
287 changes: 207 additions & 80 deletions internal/frontend/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,52 @@ var testModules = []testModule{
},
},
},
{
// A module with a greater major version available.
path: "github.com/v2major/module_name",
redistributable: true,
versions: []string{"v1.0.0"},
packages: []testPackage{
{
suffix: "bar",
doc: sample.DocumentationHTML.String(),
readmeContents: sample.ReadmeContents,
readmeFilePath: sample.ReadmeFilePath,
},
{
suffix: "bar/directory/hello",
doc: `<a href="/pkg/io#Writer">io.Writer</a>`,
},
{
suffix: "buz",
doc: sample.DocumentationHTML.String(),
readmeContents: sample.ReadmeContents,
readmeFilePath: sample.ReadmeFilePath,
},
{
suffix: "buz/directory/hello",
doc: `<a href="/pkg/io#Writer">io.Writer</a>`,
},
},
},
{
// A v2 of the previous module, with one version.
path: "github.com/v2major/module_name/v2",
redistributable: true,
versions: []string{"v2.0.0"},
packages: []testPackage{
{
suffix: "bar",
doc: sample.DocumentationHTML.String(),
readmeContents: sample.ReadmeContents,
readmeFilePath: sample.ReadmeFilePath,
},
{
suffix: "bar/directory/hello",
doc: `<a href="/pkg/io#Writer">io.Writer</a>`,
},
},
},
{
// A non-redistributable module.
path: "github.com/non_redistributable",
Expand Down Expand Up @@ -271,18 +317,59 @@ func serverTestCases() []serverTestCase {
)

pkgV100 := &pagecheck.Page{
Title: "foo",
ModulePath: sample.ModulePath,
Version: sample.VersionString,
FormattedVersion: sample.VersionString,
Suffix: sample.Suffix,
IsLatest: true,
LatestLink: "/" + sample.ModulePath + "@" + sample.VersionString + "/" + sample.Suffix,
LicenseType: sample.LicenseType,
LicenseFilePath: sample.LicenseFilePath,
PackageURLFormat: "/" + sample.ModulePath + "%s/" + sample.Suffix,
ModuleURL: "/" + sample.ModulePath,
Title: "foo",
ModulePath: sample.ModulePath,
Version: sample.VersionString,
FormattedVersion: sample.VersionString,
Suffix: sample.Suffix,
IsLatest: true,
LatestLink: "/" + sample.ModulePath + "@" + sample.VersionString + "/" + sample.Suffix,
LatestMajorVersionLink: "/" + sample.ModulePath + "/" + sample.Suffix,
LicenseType: sample.LicenseType,
LicenseFilePath: sample.LicenseFilePath,
PackageURLFormat: "/" + sample.ModulePath + "%s/" + sample.Suffix,
ModuleURL: "/" + sample.ModulePath,
}

v2pkgV100 := &pagecheck.Page{
Title: "bar",
ModulePath: "github.com/v2major/module_name",
Version: "v1.0.0",
FormattedVersion: "v1.0.0",
Suffix: "bar",
IsLatest: false,
LatestLink: "/github.com/v2major/module_name@v1.0.0/bar",
LatestMajorVersion: "v2",
LatestMajorVersionLink: "/github.com/v2major/module_name/v2/bar",
LicenseType: sample.LicenseType,
LicenseFilePath: sample.LicenseFilePath,
PackageURLFormat: "/github.com/v2major/module_name%s/bar",
ModuleURL: "/github.com/v2major/module_name",
}

v2pkgV1Buz := *v2pkgV100
v2pkgV1Buz.Title = "buz"
v2pkgV1Buz.Suffix = "buz"
v2pkgV1Buz.LatestLink = "/github.com/v2major/module_name@v1.0.0/buz"
v2pkgV1Buz.LatestMajorVersionLink = "/github.com/v2major/module_name/v2"
v2pkgV1Buz.PackageURLFormat = "/github.com/v2major/module_name%s/buz"

v2pkgV200 := &pagecheck.Page{
Title: "bar",
ModulePath: "github.com/v2major/module_name/v2",
Version: "v2.0.0",
FormattedVersion: "v2.0.0",
Suffix: "bar",
IsLatest: true,
LatestLink: "/github.com/v2major/module_name/v2@v2.0.0/bar",
LatestMajorVersion: "v2",
LatestMajorVersionLink: "/github.com/v2major/module_name/v2/bar",
LicenseType: sample.LicenseType,
LicenseFilePath: sample.LicenseFilePath,
PackageURLFormat: "/github.com/v2major/module_name/v2%s/bar",
ModuleURL: "/github.com/v2major/module_name/v2",
}

p9 := *pkgV100
p9.Version = "v0.9.0"
p9.FormattedVersion = "v0.9.0"
Expand All @@ -296,97 +383,104 @@ func serverTestCases() []serverTestCase {
pkgPseudo := &pp

pkgInc := &pagecheck.Page{
Title: "inc",
ModulePath: "github.com/incompatible",
Version: "v1.0.0+incompatible",
FormattedVersion: "v1.0.0+incompatible",
Suffix: "dir/inc",
IsLatest: true,
LatestLink: "/github.com/incompatible@v1.0.0+incompatible/dir/inc",
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
PackageURLFormat: "/github.com/incompatible%s/dir/inc",
ModuleURL: "/github.com/incompatible",
Title: "inc",
ModulePath: "github.com/incompatible",
Version: "v1.0.0+incompatible",
FormattedVersion: "v1.0.0+incompatible",
Suffix: "dir/inc",
IsLatest: true,
LatestLink: "/github.com/incompatible@v1.0.0+incompatible/dir/inc",
LatestMajorVersionLink: "/github.com/incompatible/dir/inc",
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
PackageURLFormat: "/github.com/incompatible%s/dir/inc",
ModuleURL: "/github.com/incompatible",
}

pkgNonRedist := &pagecheck.Page{
Title: "bar",
ModulePath: "github.com/non_redistributable",
Version: "v1.0.0",
FormattedVersion: "v1.0.0",
Suffix: "bar",
IsLatest: true,
LatestLink: "/github.com/non_redistributable@v1.0.0/bar",
LicenseType: "",
PackageURLFormat: "/github.com/non_redistributable%s/bar",
ModuleURL: "/github.com/non_redistributable",
Title: "bar",
ModulePath: "github.com/non_redistributable",
Version: "v1.0.0",
FormattedVersion: "v1.0.0",
Suffix: "bar",
IsLatest: true,
LatestLink: "/github.com/non_redistributable@v1.0.0/bar",
LatestMajorVersionLink: "/github.com/non_redistributable/bar",
LicenseType: "",
PackageURLFormat: "/github.com/non_redistributable%s/bar",
ModuleURL: "/github.com/non_redistributable",
}

dir := &pagecheck.Page{
Title: "directory/",
ModulePath: sample.ModulePath,
Version: "v1.0.0",
FormattedVersion: "v1.0.0",
Suffix: "foo/directory",
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
ModuleURL: "/" + sample.ModulePath,
PackageURLFormat: "/" + sample.ModulePath + "%s/foo/directory",
Title: "directory/",
ModulePath: sample.ModulePath,
Version: "v1.0.0",
FormattedVersion: "v1.0.0",
Suffix: "foo/directory",
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
ModuleURL: "/" + sample.ModulePath,
PackageURLFormat: "/" + sample.ModulePath + "%s/foo/directory",
LatestMajorVersionLink: "/github.com/valid/module_name/foo/directory",
}

mod := &pagecheck.Page{
ModulePath: sample.ModulePath,
Title: "module_name",
ModuleURL: "/" + sample.ModulePath,
Version: "v1.0.0",
FormattedVersion: "v1.0.0",
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
IsLatest: true,
LatestLink: "/" + sample.ModulePath + "@v1.0.0",
ModulePath: sample.ModulePath,
Title: "module_name",
ModuleURL: "/" + sample.ModulePath,
Version: "v1.0.0",
FormattedVersion: "v1.0.0",
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
IsLatest: true,
LatestLink: "/" + sample.ModulePath + "@v1.0.0",
LatestMajorVersionLink: "/" + sample.ModulePath,
}
mp := *mod
mp.Version = pseudoVersion
mp.FormattedVersion = "v0.0.0-...-1234567"
mp.IsLatest = false

dirPseudo := &pagecheck.Page{
ModulePath: "github.com/pseudo",
Title: "dir/",
ModuleURL: "/github.com/pseudo",
LatestLink: "/github.com/pseudo@" + pseudoVersion + "/dir",
Suffix: "dir",
Version: pseudoVersion,
FormattedVersion: mp.FormattedVersion,
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
IsLatest: true,
PackageURLFormat: "/github.com/pseudo%s/dir",
ModulePath: "github.com/pseudo",
Title: "dir/",
ModuleURL: "/github.com/pseudo",
LatestLink: "/github.com/pseudo@" + pseudoVersion + "/dir",
LatestMajorVersionLink: "/github.com/pseudo/dir",
Suffix: "dir",
Version: pseudoVersion,
FormattedVersion: mp.FormattedVersion,
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
IsLatest: true,
PackageURLFormat: "/github.com/pseudo%s/dir",
}

dirCmd := &pagecheck.Page{
Title: "cmd",
ModulePath: "std",
Version: "go1.13",
FormattedVersion: "go1.13",
Suffix: "cmd",
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
ModuleURL: "/std",
PackageURLFormat: "/cmd%s",
Title: "cmd",
ModulePath: "std",
Version: "go1.13",
FormattedVersion: "go1.13",
Suffix: "cmd",
LicenseType: "MIT",
LicenseFilePath: "LICENSE",
ModuleURL: "/std",
PackageURLFormat: "/cmd%s",
LatestMajorVersionLink: "/cmd",
}

netHttp := &pagecheck.Page{
Title: "http",
ModulePath: "http",
Version: "go1.13",
FormattedVersion: "go1.13",
LicenseType: sample.LicenseType,
LicenseFilePath: sample.LicenseFilePath,
ModuleURL: "/net/http",
PackageURLFormat: "/net/http%s",
IsLatest: true,
LatestLink: "/net/http@go1.13",
Title: "http",
ModulePath: "http",
Version: "go1.13",
FormattedVersion: "go1.13",
LicenseType: sample.LicenseType,
LicenseFilePath: sample.LicenseFilePath,
ModuleURL: "/net/http",
PackageURLFormat: "/net/http%s",
IsLatest: true,
LatestLink: "/net/http@go1.13",
LatestMajorVersionLink: "/net/http",
}

return []serverTestCase{
Expand Down Expand Up @@ -519,6 +613,39 @@ func serverTestCases() []serverTestCase {
in(".UnitDetails-content", hasText(`not displayed due to license restrictions`)),
),
},
{
name: "v2 package at v1",
urlPath: fmt.Sprintf("/%s@%s/%s", v2pkgV100.ModulePath, v2pkgV100.Version, v2pkgV100.Suffix),
wantStatusCode: http.StatusOK,
want: in("",
pagecheck.UnitHeader(v2pkgV100, versioned, isPackage),
pagecheck.UnitReadme(),
pagecheck.UnitDoc(),
pagecheck.UnitDirectories(fmt.Sprintf("/%s@%s/%s/directory/hello", v2pkgV100.ModulePath, v2pkgV100.Version, v2pkgV100.Suffix), "directory/hello"),
pagecheck.CanonicalURLPath("/github.com/v2major/module_name@v1.0.0/bar")),
},
{
name: "v2 module with v1 package that does not exist in v2",
urlPath: fmt.Sprintf("/%s@%s/%s", v2pkgV1Buz.ModulePath, v2pkgV1Buz.Version, v2pkgV1Buz.Suffix),
wantStatusCode: http.StatusOK,
want: in("",
pagecheck.UnitHeader(&v2pkgV1Buz, versioned, isPackage),
pagecheck.UnitReadme(),
pagecheck.UnitDoc(),
pagecheck.UnitDirectories(fmt.Sprintf("/%s@%s/%s/directory/hello", v2pkgV1Buz.ModulePath, v2pkgV1Buz.Version, v2pkgV1Buz.Suffix), "directory/hello"),
pagecheck.CanonicalURLPath("/github.com/v2major/module_name@v1.0.0/buz")),
},
{
name: "v2 package at v2",
urlPath: fmt.Sprintf("/%s@%s/%s", v2pkgV200.ModulePath, v2pkgV200.Version, v2pkgV200.Suffix),
wantStatusCode: http.StatusOK,
want: in("",
pagecheck.UnitHeader(v2pkgV200, versioned, isPackage),
pagecheck.UnitReadme(),
pagecheck.UnitDoc(),
pagecheck.UnitDirectories(fmt.Sprintf("/%s@%s/%s/directory/hello", v2pkgV200.ModulePath, v2pkgV200.Version, v2pkgV200.Suffix), "directory/hello"),
pagecheck.CanonicalURLPath("/github.com/v2major/module_name/v2@v2.0.0/bar")),
},
{
name: "package at version default",
urlPath: fmt.Sprintf("/%s@%s/%s", sample.ModulePath, sample.VersionString, sample.Suffix),
Expand Down
Loading

0 comments on commit 69b3ffd

Please sign in to comment.