internal/middleware: remove latest-minor-class substitution

Remove the $$ substitution for the latest-minor CSS class.
Instead, determine the class on the normal serving path.

This is possible because the worker invalidates the cache when
processing a new latest version, so pages will not be stale
even though they are cached.

For golang/go#44210

Change-Id: Ide18e8257369810cd98f0b7d4fb41b75af961b83
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/292492
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
This commit is contained in:
Jonathan Amsterdam 2021-02-16 11:36:52 -05:00
Родитель 0b4f745b48
Коммит 9fad5fb2a4
5 изменённых файлов: 32 добавлений и 186 удалений

Просмотреть файл

@ -4,6 +4,8 @@
license that can be found in the LICENSE file.
-->
{{/* . is internal/frontend.UnitPage */}}
{{define "unit_fixed_header"}}
<div class="UnitFixedHeader js-fixedHeader" aria-hidden="true">
<div class="UnitFixedHeader-container">
@ -37,8 +39,9 @@
<img height="16px" width="16px" src="/static/img/pkg-icon-arrowBranch_16x16.svg" alt="">
<a href="?tab=versions" tabindex="-1">Version {{.DisplayVersion}}</a>
<!-- Do not reformat the data attributes of the following div: the server uses a regexp to extract them. -->
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
data-version="{{.LinkVersion}}" data-mpath="{{.Unit.ModulePath}}" data-ppath="{{.Unit.Path}}" data-pagetype="{{.PageType}}">
<div class="DetailsHeader-badge {{.LatestMinorClass}}"
data-version="{{.LinkVersion}}" data-mpath="{{.Unit.ModulePath}}" data-ppath="{{.Unit.Path}}" data-pagetype="{{.PageType}}">
<span>Latest</span>
<a href="{{.LatestURL}}">Go to latest</a>
</div>

Просмотреть файл

@ -57,7 +57,7 @@
<img class="UnitHeader-detailItemLarge" height="16px" width="16px" src="/static/img/pkg-icon-arrowBranch_16x16.svg" alt="">
<a href="?tab=versions">Version {{.DisplayVersion}}</a>
<!-- Do not reformat the data attributes of the following div: the server uses a regexp to extract them. -->
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
<div class="DetailsHeader-badge {{.LatestMinorClass}}"
data-test-id="UnitHeader-minorVersionBanner"
data-version="{{.LinkVersion}}"
data-mpath="{{.Unit.ModulePath}}"
@ -119,7 +119,7 @@
<div class="UnitHeader-detail">
<span class="UnitHeader-detailItem">
<!-- Do not reformat the data attributes of the following div: the server uses a regexp to extract them. -->
<div style="display: none;" class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
<div style="display: none;" class="DetailsHeader-badge {{.LatestMinorClass}}"
data-version="{{.LinkVersion}}" data-mpath="{{.Unit.ModulePath}}" data-ppath="{{.Unit.Path}}" data-pagetype="{{.PageType}}">
</div>
<a class="UnitHeader-backLink" href="{{.URLPath}}">

Просмотреть файл

@ -17,6 +17,7 @@ import (
"github.com/google/safehtml/uncheckedconversions"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/experiment"
"golang.org/x/pkgsite/internal/log"
"golang.org/x/pkgsite/internal/stdlib"
)
@ -54,6 +55,10 @@ type UnitPage struct {
// LatestURL is a url pointing to the latest version of a unit.
LatestURL string
// LatestMinorClass is the CSS class that describes the current unit's minor
// version in relationship to the latest version of the unit.
LatestMinorClass string
// PageType is the type of page (pkg, cmd, dir, std, or mod).
PageType string
@ -122,10 +127,13 @@ func (s *Server) serveUnitPage(ctx context.Context, w http.ResponseWriter, r *ht
http.Redirect(w, r, r.URL.Path, http.StatusFound)
return nil
}
latestInfo := s.GetLatestInfo(r.Context(), um.Path, um.ModulePath)
tabSettings := unitTabLookup[tab]
title := pageTitle(um)
basePage := s.newBasePage(r, title)
basePage.AllowWideContent = true
lv := linkVersion(um.Version, um.ModulePath)
page := UnitPage{
basePage: basePage,
Unit: um,
@ -135,8 +143,9 @@ func (s *Server) serveUnitPage(ctx context.Context, w http.ResponseWriter, r *ht
URLPath: constructUnitURL(um.Path, um.ModulePath, info.requestedVersion),
CanonicalURLPath: canonicalURLPath(um),
DisplayVersion: displayVersion(um.Version, um.ModulePath),
LinkVersion: linkVersion(um.Version, um.ModulePath),
LinkVersion: lv,
LatestURL: constructUnitURL(um.Path, um.ModulePath, internal.LatestVersion),
LatestMinorClass: latestMinorClass(r.Context(), lv, latestInfo),
PageLabels: pageLabels(um),
PageType: pageType(um),
}
@ -160,6 +169,21 @@ func (s *Server) serveUnitPage(ctx context.Context, w http.ResponseWriter, r *ht
return nil
}
func latestMinorClass(ctx context.Context, version string, latest internal.LatestInfo) string {
c := "DetailsHeader-badge"
switch {
case latest.MinorVersion == "":
c += "--unknown"
case latest.MinorVersion == version && !latest.UnitExistsAtMinor && experiment.IsActive(ctx, internal.ExperimentNotAtLatest):
c += "--notAtLatest"
case latest.MinorVersion == version:
c += "--latest"
default:
c += "--goToLatest"
}
return c
}
// metaDescription uses a safehtml escape hatch to build HTML used
// to render the <meta name="Description"> for unit pages as a
// workaround for https://github.com/google/safehtml/issues/6.

Просмотреть файл

@ -9,16 +9,13 @@ import (
"context"
"net/http"
"regexp"
"strings"
"golang.org/x/mod/module"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/experiment"
"golang.org/x/pkgsite/internal/log"
)
const (
latestMinorClassPlaceholder = "$$GODISCOVERY_LATESTMINORCLASS$$"
latestMajorClassPlaceholder = "$$GODISCOVERY_LATESTMAJORCLASS$$"
LatestMajorVersionPlaceholder = "$$GODISCOVERY_LATESTMAJORVERSION$$"
LatestMajorVersionURL = "$$GODISCOVERY_LATESTMAJORVERSIONURL$$"
@ -40,25 +37,10 @@ func LatestVersions(getLatest latestFunc) Middleware {
body := crw.bytes()
matches := latestInfoRegexp.FindSubmatch(body)
if matches != nil {
version := string(matches[1])
// The template package converts '+' to its HTML entity.
version = strings.Replace(version, "&#43;", "+", -1)
modulePath := string(matches[2])
_, majorVersion, _ := module.SplitPathVersion(modulePath)
unitPath := string(matches[3])
latest := getLatest(r.Context(), unitPath, modulePath)
latestMinorClass := "DetailsHeader-badge"
switch {
case latest.MinorVersion == "":
latestMinorClass += "--unknown"
case latest.MinorVersion == version && !latest.UnitExistsAtMinor && experiment.IsActive(r.Context(), internal.ExperimentNotAtLatest):
latestMinorClass += "--notAtLatest"
case latest.MinorVersion == version:
latestMinorClass += "--latest"
default:
latestMinorClass += "--goToLatest"
}
_, latestMajorVersion, ok := module.SplitPathVersion(latest.MajorModulePath)
var latestMajorVersionText string
if ok && len(latestMajorVersion) > 0 {
@ -72,7 +54,6 @@ func LatestVersions(getLatest latestFunc) Middleware {
if majorVersion == latestMajorVersion || latestMajorVersion == "" {
latestMajorClass += " DetailsHeader-banner--latest"
}
body = bytes.ReplaceAll(body, []byte(latestMinorClassPlaceholder), []byte(latestMinorClass))
body = bytes.ReplaceAll(body, []byte(latestMajorClassPlaceholder), []byte(latestMajorClass))
body = bytes.ReplaceAll(body, []byte(LatestMajorVersionPlaceholder), []byte(latestMajorVersionText))
body = bytes.ReplaceAll(body, []byte(LatestMajorVersionURL), []byte(latest.MajorUnitPath))

Просмотреть файл

@ -13,170 +13,8 @@ import (
"testing"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/experiment"
)
func TestLatestMinorVersion(t *testing.T) {
for _, test := range []struct {
name string
latest internal.LatestInfo
in string
want string
}{
{
name: "package version is not latest",
latest: internal.LatestInfo{MinorVersion: "v1.2.3"},
in: `
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
data-version="v1.0.0" data-mpath="p1/p2" data-ppath="p1/p2/p3" data-pagetype="pkg">
<span>Latest</span>
<a href="p1/p2@v1.2.3/p3">Go to latest</a>
</div>`,
want: `
<div class="DetailsHeader-badge DetailsHeader-badge--goToLatest"
data-version="v1.0.0" data-mpath="p1/p2" data-ppath="p1/p2/p3" data-pagetype="pkg">
<span>Latest</span>
<a href="p1/p2@v1.2.3/p3">Go to latest</a>
</div>`,
},
{
name: "package version is latest",
latest: internal.LatestInfo{MinorVersion: "v1.2.3", UnitExistsAtMinor: true},
in: `
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
data-version="v1.2.3" data-mpath="p1/p2" data-ppath="p1/p2/p3" data-pagetype="pkg">
<span>Latest</span>
<a href="p1/p2@v1.2.3/p3">Go to latest</a>
</div>`,
want: `
<div class="DetailsHeader-badge DetailsHeader-badge--latest"
data-version="v1.2.3" data-mpath="p1/p2" data-ppath="p1/p2/p3" data-pagetype="pkg">
<span>Latest</span>
<a href="p1/p2@v1.2.3/p3">Go to latest</a>
</div>`,
},
{
name: "package version with build is latest",
latest: internal.LatestInfo{MinorVersion: "v1.2.3+build", UnitExistsAtMinor: true},
in: `
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
data-version="v1.2.3&#43;build" data-mpath="p1/p2" data-ppath="p1/p2/p3" data-pagetype="pkg">
<span>Latest</span>
<a href="p1/p2@v1.2.3+build/p3">Go to latest</a>
</div>`,
want: `
<div class="DetailsHeader-badge DetailsHeader-badge--latest"
data-version="v1.2.3&#43;build" data-mpath="p1/p2" data-ppath="p1/p2/p3" data-pagetype="pkg">
<span>Latest</span>
<a href="p1/p2@v1.2.3+build/p3">Go to latest</a>
</div>`,
},
{
name: "module version is not latest",
latest: internal.LatestInfo{MinorVersion: "v1.2.3"},
in: `
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
data-version="v1.0.0" data-mpath="p1/p2" data-ppath="" data-pagetype="pkg">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
want: `
<div class="DetailsHeader-badge DetailsHeader-badge--goToLatest"
data-version="v1.0.0" data-mpath="p1/p2" data-ppath="" data-pagetype="pkg">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
},
{
name: "module version is latest",
latest: internal.LatestInfo{MinorVersion: "v1.2.3", UnitExistsAtMinor: true},
in: `
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
data-version="v1.2.3" data-mpath="p1/p2" data-ppath="" data-pagetype="pkg">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
want: `
<div class="DetailsHeader-badge DetailsHeader-badge--latest"
data-version="v1.2.3" data-mpath="p1/p2" data-ppath="" data-pagetype="pkg">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
},
{
name: "package not in module latest",
latest: internal.LatestInfo{MinorVersion: "v1.2.3", UnitExistsAtMinor: false},
in: `
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
data-version="v1.2.3" data-mpath="p1/p2" data-ppath="" data-pagetype="pkg">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
want: `
<div class="DetailsHeader-badge DetailsHeader-badge--notAtLatest"
data-version="v1.2.3" data-mpath="p1/p2" data-ppath="" data-pagetype="pkg">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
},
{
name: "latest func returns empty string",
latest: internal.LatestInfo{},
in: `
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$"
data-version="v1.2.3" data-mpath="p1/p2" data-ppath="" data-pagetype="pkg">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
want: `
<div class="DetailsHeader-badge DetailsHeader-badge--unknown"
data-version="v1.2.3" data-mpath="p1/p2" data-ppath="" data-pagetype="pkg">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
},
{
name: "no regexp match",
latest: internal.LatestInfo{MinorVersion: "v1.2.3"},
in: `
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
want: `
<div class="DetailsHeader-badge $$GODISCOVERY_LATESTMINORCLASS$$">
<span>Latest</span>
<a href="mod/p1/p2@v1.2.3">Go to latest</a>
</div>`,
},
} {
t.Run(test.name, func(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, test.in)
})
lfunc := func(context.Context, string, string) internal.LatestInfo { return test.latest }
lv := LatestVersions(lfunc)(handler)
addExp := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
lv.ServeHTTP(w, r.WithContext(experiment.NewContext(r.Context(), internal.ExperimentNotAtLatest)))
})
ts := httptest.NewServer(addExp)
defer ts.Close()
resp, err := ts.Client().Get(ts.URL)
if err != nil {
t.Fatal(err)
}
got, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
_ = resp.Body.Close()
if string(got) != test.want {
t.Errorf("\ngot %s\nwant %s", got, test.want)
}
})
}
}
func TestLatestMajorVersion(t *testing.T) {
for _, test := range []struct {
name string