зеркало из https://github.com/golang/pkgsite.git
internal: remove unit-meta-with-latest experiment
For golang/go#43265 Change-Id: I1d056a893fdff60744ff328ab9f4a1b6665b3e32 Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/309709 Trust: Jonathan Amsterdam <jba@google.com> Run-TryBot: Jonathan Amsterdam <jba@google.com> TryBot-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: Julie Qiu <julie@golang.org>
This commit is contained in:
Родитель
58432cb4a0
Коммит
103f9ede54
|
@ -9,7 +9,6 @@ const (
|
||||||
ExperimentInsertSymbols = "insert-symbols"
|
ExperimentInsertSymbols = "insert-symbols"
|
||||||
ExperimentSymbolHistoryVersionsPage = "symbol-history-versions-page"
|
ExperimentSymbolHistoryVersionsPage = "symbol-history-versions-page"
|
||||||
ExperimentSymbolHistoryMainPage = "symbol-history-main-page"
|
ExperimentSymbolHistoryMainPage = "symbol-history-main-page"
|
||||||
ExperimentUnitMetaWithLatest = "unit-meta-with-latest"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Experiments represents all of the active experiments in the codebase and
|
// Experiments represents all of the active experiments in the codebase and
|
||||||
|
@ -18,7 +17,6 @@ var Experiments = map[string]string{
|
||||||
ExperimentInsertSymbols: "Insert data into symbols, package_symbols, and documentation_symbols.",
|
ExperimentInsertSymbols: "Insert data into symbols, package_symbols, and documentation_symbols.",
|
||||||
ExperimentSymbolHistoryVersionsPage: "Show package API history on the versions page.",
|
ExperimentSymbolHistoryVersionsPage: "Show package API history on the versions page.",
|
||||||
ExperimentSymbolHistoryMainPage: "Show package API history on the main unit page.",
|
ExperimentSymbolHistoryMainPage: "Show package API history on the main unit page.",
|
||||||
ExperimentUnitMetaWithLatest: "Use latest-version information for GetUnitMeta.",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Experiment holds data associated with an experimental feature for frontend
|
// Experiment holds data associated with an experimental feature for frontend
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"golang.org/x/pkgsite/internal"
|
"golang.org/x/pkgsite/internal"
|
||||||
"golang.org/x/pkgsite/internal/database"
|
"golang.org/x/pkgsite/internal/database"
|
||||||
"golang.org/x/pkgsite/internal/derrors"
|
"golang.org/x/pkgsite/internal/derrors"
|
||||||
"golang.org/x/pkgsite/internal/experiment"
|
|
||||||
"golang.org/x/pkgsite/internal/middleware"
|
"golang.org/x/pkgsite/internal/middleware"
|
||||||
"golang.org/x/pkgsite/internal/stdlib"
|
"golang.org/x/pkgsite/internal/stdlib"
|
||||||
"golang.org/x/pkgsite/internal/version"
|
"golang.org/x/pkgsite/internal/version"
|
||||||
|
@ -39,19 +38,16 @@ func (db *DB) GetUnitMeta(ctx context.Context, fullPath, requestedModulePath, re
|
||||||
defer derrors.WrapStack(&err, "DB.GetUnitMeta(ctx, %q, %q, %q)", fullPath, requestedModulePath, requestedVersion)
|
defer derrors.WrapStack(&err, "DB.GetUnitMeta(ctx, %q, %q, %q)", fullPath, requestedModulePath, requestedVersion)
|
||||||
defer middleware.ElapsedStat(ctx, "GetUnitMeta")()
|
defer middleware.ElapsedStat(ctx, "GetUnitMeta")()
|
||||||
|
|
||||||
if experiment.IsActive(ctx, internal.ExperimentUnitMetaWithLatest) {
|
modulePath := requestedModulePath
|
||||||
modulePath := requestedModulePath
|
version := requestedVersion
|
||||||
version := requestedVersion
|
var lmv *internal.LatestModuleVersions
|
||||||
var lmv *internal.LatestModuleVersions
|
if requestedVersion == internal.LatestVersion {
|
||||||
if requestedVersion == internal.LatestVersion {
|
modulePath, version, lmv, err = db.getLatestUnitVersion(ctx, fullPath, requestedModulePath)
|
||||||
modulePath, version, lmv, err = db.getLatestUnitVersion(ctx, fullPath, requestedModulePath)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return db.getUnitMetaWithKnownLatestVersion(ctx, fullPath, modulePath, version, lmv)
|
|
||||||
}
|
}
|
||||||
return db.legacyGetUnitMeta(ctx, fullPath, requestedModulePath, requestedVersion)
|
return db.getUnitMetaWithKnownLatestVersion(ctx, fullPath, modulePath, version, lmv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) getUnitMetaWithKnownLatestVersion(ctx context.Context, fullPath, modulePath, version string, lmv *internal.LatestModuleVersions) (_ *internal.UnitMeta, err error) {
|
func (db *DB) getUnitMetaWithKnownLatestVersion(ctx context.Context, fullPath, modulePath, version string, lmv *internal.LatestModuleVersions) (_ *internal.UnitMeta, err error) {
|
||||||
|
@ -225,131 +221,6 @@ func (db *DB) getLatestUnitVersion(ctx context.Context, fullPath, requestedModul
|
||||||
return modulePath, latestVersion, nil, nil
|
return modulePath, latestVersion, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) legacyGetUnitMeta(ctx context.Context, fullPath, requestedModulePath, requestedVersion string) (_ *internal.UnitMeta, err error) {
|
|
||||||
defer derrors.WrapStack(&err, "DB.legacyGetUnitMeta(ctx, %q, %q, %q)", fullPath, requestedModulePath, requestedVersion)
|
|
||||||
|
|
||||||
var (
|
|
||||||
q string
|
|
||||||
args []interface{}
|
|
||||||
)
|
|
||||||
q, args, err = getUnitMetaQuery(fullPath, requestedModulePath, requestedVersion).PlaceholderFormat(squirrel.Dollar).ToSql()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("squirrel.ToSql: %v", err)
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
licenseTypes []string
|
|
||||||
licensePaths []string
|
|
||||||
um = internal.UnitMeta{Path: fullPath}
|
|
||||||
)
|
|
||||||
err = db.db.QueryRow(ctx, q, args...).Scan(
|
|
||||||
&um.ModulePath,
|
|
||||||
&um.Version,
|
|
||||||
&um.CommitTime,
|
|
||||||
jsonbScanner{&um.SourceInfo},
|
|
||||||
&um.HasGoMod,
|
|
||||||
&um.ModuleInfo.IsRedistributable,
|
|
||||||
&um.Name,
|
|
||||||
&um.IsRedistributable,
|
|
||||||
pq.Array(&licenseTypes),
|
|
||||||
pq.Array(&licensePaths))
|
|
||||||
switch err {
|
|
||||||
case sql.ErrNoRows:
|
|
||||||
return nil, derrors.NotFound
|
|
||||||
case nil:
|
|
||||||
lics, err := zipLicenseMetadata(licenseTypes, licensePaths)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if db.bypassLicenseCheck {
|
|
||||||
um.IsRedistributable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
um.Licenses = lics
|
|
||||||
if err := populateLatestInfo(ctx, db, &um.ModuleInfo); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &um, nil
|
|
||||||
default:
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUnitMetaQuery(fullPath, requestedModulePath, requestedVersion string) squirrel.SelectBuilder {
|
|
||||||
query := squirrel.Select(
|
|
||||||
"m.module_path",
|
|
||||||
"m.version",
|
|
||||||
"m.commit_time",
|
|
||||||
"m.source_info",
|
|
||||||
"m.has_go_mod",
|
|
||||||
"m.redistributable",
|
|
||||||
"u.name",
|
|
||||||
"u.redistributable",
|
|
||||||
"u.license_types",
|
|
||||||
"u.license_paths",
|
|
||||||
)
|
|
||||||
if requestedVersion != internal.LatestVersion {
|
|
||||||
query = query.From("modules m").
|
|
||||||
Join("units u on u.module_id = m.id").
|
|
||||||
Join("paths p ON p.id = u.path_id").Where(squirrel.Eq{"p.path": fullPath})
|
|
||||||
if requestedModulePath != internal.UnknownModulePath {
|
|
||||||
query = query.Where(squirrel.Eq{"m.module_path": requestedModulePath})
|
|
||||||
}
|
|
||||||
if internal.DefaultBranches[requestedVersion] {
|
|
||||||
query = query.Join("version_map vm ON m.id = vm.module_id").Where("vm.requested_version = ? ", requestedVersion)
|
|
||||||
} else if requestedVersion != internal.LatestVersion {
|
|
||||||
query = query.Where(squirrel.Eq{"version": requestedVersion})
|
|
||||||
}
|
|
||||||
return orderByLatest(query).Limit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use a nested select to fetch the latest version of the unit, then JOIN
|
|
||||||
// on units to fetch other relevant information. This allows us to use the
|
|
||||||
// index on units.id and paths.path to get the latest path. We can then
|
|
||||||
// look up only the relevant information from the units table.
|
|
||||||
nestedSelect := orderByLatest(squirrel.Select(
|
|
||||||
"m.id",
|
|
||||||
"m.module_path",
|
|
||||||
"m.version",
|
|
||||||
"m.commit_time",
|
|
||||||
"m.source_info",
|
|
||||||
"m.has_go_mod",
|
|
||||||
"m.redistributable",
|
|
||||||
"u.id AS unit_id",
|
|
||||||
).From("modules m").
|
|
||||||
Join("units u ON u.module_id = m.id").
|
|
||||||
Join("paths p ON p.id = u.path_id").
|
|
||||||
Where(squirrel.Eq{"p.path": fullPath}))
|
|
||||||
if requestedModulePath != internal.UnknownModulePath {
|
|
||||||
nestedSelect = nestedSelect.Where(squirrel.Eq{"m.module_path": requestedModulePath})
|
|
||||||
}
|
|
||||||
nestedSelect = nestedSelect.Limit(1)
|
|
||||||
return query.From("units u").JoinClause(nestedSelect.Prefix("JOIN (").Suffix(") m ON u.id = m.unit_id"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// orderByLatest orders paths according to the go command.
|
|
||||||
// Versions are ordered by:
|
|
||||||
// (1) release (non-incompatible)
|
|
||||||
// (2) prerelease (non-incompatible)
|
|
||||||
// (3) release, incompatible
|
|
||||||
// (4) prerelease, incompatible
|
|
||||||
// (5) pseudo
|
|
||||||
// They are then sorted based on semver, then decreasing module path length (so
|
|
||||||
// that nested modules are preferred).
|
|
||||||
func orderByLatest(q squirrel.SelectBuilder) squirrel.SelectBuilder {
|
|
||||||
return q.OrderBy(
|
|
||||||
`CASE
|
|
||||||
WHEN m.version_type = 'release' AND NOT m.incompatible THEN 1
|
|
||||||
WHEN m.version_type = 'prerelease' AND NOT m.incompatible THEN 2
|
|
||||||
WHEN m.version_type = 'release' THEN 3
|
|
||||||
WHEN m.version_type = 'prerelease' THEN 4
|
|
||||||
ELSE 5
|
|
||||||
END`,
|
|
||||||
"m.series_path DESC",
|
|
||||||
"m.sort_version DESC",
|
|
||||||
).PlaceholderFormat(squirrel.Dollar)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUnit returns a unit from the database, along with all of the data
|
// GetUnit returns a unit from the database, along with all of the data
|
||||||
// associated with that unit.
|
// associated with that unit.
|
||||||
func (db *DB) GetUnit(ctx context.Context, um *internal.UnitMeta, fields internal.FieldSet) (_ *internal.Unit, err error) {
|
func (db *DB) GetUnit(ctx context.Context, um *internal.UnitMeta, fields internal.FieldSet) (_ *internal.Unit, err error) {
|
||||||
|
|
|
@ -26,12 +26,7 @@ func TestGetUnitMeta(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), testTimeout*2)
|
ctx, cancel := context.WithTimeout(context.Background(), testTimeout*2)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
t.Run("legacy", func(t *testing.T) {
|
testGetUnitMeta(t, ctx)
|
||||||
testGetUnitMeta(t, ctx)
|
|
||||||
})
|
|
||||||
t.Run("latest", func(t *testing.T) {
|
|
||||||
testGetUnitMeta(t, experiment.NewContext(ctx, internal.ExperimentUnitMetaWithLatest))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetUnitMeta(t *testing.T, ctx context.Context) {
|
func testGetUnitMeta(t *testing.T, ctx context.Context) {
|
||||||
|
@ -207,104 +202,6 @@ func testGetUnitMeta(t *testing.T, ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetUnitMetaDiffs(t *testing.T) {
|
|
||||||
// Demonstrate differences between legacy and latest-version GetUnitMeta
|
|
||||||
// implementations.
|
|
||||||
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
type latest struct { // latest-version info
|
|
||||||
module string
|
|
||||||
version string // latest raw and cooked version
|
|
||||||
goMod string // go.mod file contents after "module" line
|
|
||||||
}
|
|
||||||
|
|
||||||
modver := func(u *internal.UnitMeta) string { return u.ModulePath + "@" + u.Version }
|
|
||||||
|
|
||||||
for _, test := range []struct {
|
|
||||||
name string
|
|
||||||
packages []string // mod@ver/pkg
|
|
||||||
latests []latest
|
|
||||||
path string
|
|
||||||
wantLatest, wantLegacy string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "incompatible",
|
|
||||||
// When there are incompatible versions and no go.mod at the latest
|
|
||||||
// compatible version, the go command selects the highest
|
|
||||||
// incompatible version, but legacy GetUnitMeta selects the highest
|
|
||||||
// compatible version.
|
|
||||||
packages: []string{
|
|
||||||
"m.com@v1.0.0/a",
|
|
||||||
"m.com@v2.0.0+incompatible/a",
|
|
||||||
},
|
|
||||||
latests: []latest{{"m.com", "v2.0.0+incompatible", ""}},
|
|
||||||
path: "m.com/a",
|
|
||||||
wantLatest: "m.com@v2.0.0+incompatible",
|
|
||||||
wantLegacy: "m.com@v1.0.0",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "shorter",
|
|
||||||
// The go command prefers the longer path if both have latest-version information,
|
|
||||||
// but legacy GetUnitMeta prefers the shorter path if it has a release version.
|
|
||||||
packages: []string{
|
|
||||||
"m.com@v1.0.0/a/b", // shorter path, release version
|
|
||||||
"m.com/a@v1.0.0-pre/b", // longer path, pre-release version
|
|
||||||
},
|
|
||||||
latests: []latest{{"m.com", "v1.0.0", ""}, {"m.com/a", "v1.0.0-pre", ""}},
|
|
||||||
path: "m.com/a/b",
|
|
||||||
wantLatest: "m.com/a@v1.0.0-pre",
|
|
||||||
wantLegacy: "m.com@v1.0.0",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "retraction",
|
|
||||||
// Legacy GetUnitMeta ignores retractions when picking the latest version.
|
|
||||||
packages: []string{
|
|
||||||
"m.com@v1.0.0/a",
|
|
||||||
"m.com@v1.1.0/a", // latest, also retracted
|
|
||||||
},
|
|
||||||
latests: []latest{{"m.com", "v1.1.0", "retract v1.1.0"}},
|
|
||||||
path: "m.com/a",
|
|
||||||
wantLatest: "m.com@v1.0.0",
|
|
||||||
wantLegacy: "m.com@v1.1.0",
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
t.Run(test.name, func(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
testDB, release := acquire(t)
|
|
||||||
defer release()
|
|
||||||
|
|
||||||
for _, p := range test.packages {
|
|
||||||
mod, ver, pkg := parseModuleVersionPackage(p)
|
|
||||||
m := sample.Module(mod, ver, pkg)
|
|
||||||
goMod := "module " + mod
|
|
||||||
for _, l := range test.latests {
|
|
||||||
if l.module == mod && l.version == ver {
|
|
||||||
goMod += "\n" + l.goMod
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MustInsertModuleGoMod(ctx, t, testDB, m, goMod)
|
|
||||||
}
|
|
||||||
gotLegacy, err := testDB.GetUnitMeta(ctx, test.path, internal.UnknownModulePath, internal.LatestVersion)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if got := modver(gotLegacy); got != test.wantLegacy {
|
|
||||||
t.Errorf("legacy: got %s, want %s", got, test.wantLegacy)
|
|
||||||
}
|
|
||||||
gotLatest, err := testDB.GetUnitMeta(experiment.NewContext(ctx, internal.ExperimentUnitMetaWithLatest),
|
|
||||||
test.path, internal.UnknownModulePath, internal.LatestVersion)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if got := modver(gotLatest); got != test.wantLatest {
|
|
||||||
t.Errorf("latest: got %s, want %s", got, test.wantLatest)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetUnitMetaBypass(t *testing.T) {
|
func TestGetUnitMetaBypass(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
testDB, release := acquire(t)
|
testDB, release := acquire(t)
|
||||||
|
@ -318,13 +215,13 @@ func TestGetUnitMetaBypass(t *testing.T) {
|
||||||
module, version, packageSuffix string
|
module, version, packageSuffix string
|
||||||
isMaster bool
|
isMaster bool
|
||||||
}{
|
}{
|
||||||
|
{"m.com", "v2.0.0+incompatible", "a", false},
|
||||||
|
{"m.com/b", "v2.0.0+incompatible", "a", true},
|
||||||
{"m.com", "v1.0.0", "a", false},
|
{"m.com", "v1.0.0", "a", false},
|
||||||
{"m.com", "v1.0.1", "dir/a", false},
|
{"m.com", "v1.0.1", "dir/a", false},
|
||||||
{"m.com", "v1.1.0", "a/b", false},
|
{"m.com", "v1.1.0", "a/b", false},
|
||||||
{"m.com", "v1.2.0-pre", "a", true},
|
{"m.com", "v1.2.0-pre", "a", true},
|
||||||
{"m.com", "v2.0.0+incompatible", "a", false},
|
|
||||||
{"m.com/a", "v1.1.0", "b", false},
|
{"m.com/a", "v1.1.0", "b", false},
|
||||||
{"m.com/b", "v2.0.0+incompatible", "a", true},
|
|
||||||
} {
|
} {
|
||||||
m := sample.Module(testModule.module, testModule.version, testModule.packageSuffix)
|
m := sample.Module(testModule.module, testModule.version, testModule.packageSuffix)
|
||||||
makeModuleNonRedistributable(m)
|
makeModuleNonRedistributable(m)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче