mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 18:11:48 +00:00
codeintel: Fix test database at revision for oobmigrations (#46141)
This commit is contained in:
parent
eb315f680b
commit
b0b5822b55
@ -7,7 +7,7 @@ client/browser/build
|
||||
**/coverage
|
||||
internal/database/schema*.md
|
||||
internal/database/schema*.json
|
||||
internal/database/migration/shared/upgradedata/stitched-migration-graph.json
|
||||
internal/database/migration/shared/data/**/*.json
|
||||
cmd/xlang-python/python-langserver/
|
||||
package-lock.json
|
||||
package.json
|
||||
|
||||
@ -314,7 +314,7 @@ Note that it is not advised to set the deprecated version to the minor release o
|
||||
|
||||
#### Step 6: Deprecation
|
||||
|
||||
Despite an out of band migration being marked deprecated, it may still need to be executed by multi-version upgrades in a later version. For this reason it is not safe to delete any code from the out of band migrations until _after_ the deprecation version falls out of the [supported multi-version upgrade window](https://sourcegraph.com/github.com/sourcegraph/sourcegraph@39996f3159a0466624bc3a57689560c6bdebb60c/-/blob/internal/database/migration/shared/upgradedata/cmd/generator/consts.go?L24).
|
||||
Despite an out of band migration being marked deprecated, it may still need to be executed by multi-version upgrades in a later version. For this reason it is not safe to delete any code from the out of band migrations until _after_ the deprecation version falls out of the [supported multi-version upgrade window](https://sourcegraph.com/github.com/sourcegraph/sourcegraph@39996f3159a0466624bc3a57689560c6bdebb60c/-/blob/internal/database/migration/shared/data/cmd/generator/consts.go?L24).
|
||||
|
||||
As an alternative to deleting the code, the out of band migration can be isolated from any dependencies outside of the out of band migration. For example copying any types, functions, and other code that is used to execute the migration. Once isolated, the migration can be considered frozen and effectively ignored. To see an example, [see the Code Insights settings migration](https://sourcegraph.com/github.com/sourcegraph/sourcegraph@39996f3159a0466624bc3a57689560c6bdebb60c/-/tree/enterprise/internal/oobmigration/migrations/insights)
|
||||
|
||||
|
||||
@ -21,7 +21,9 @@ func init() {
|
||||
|
||||
func TestSCIPMigrator(t *testing.T) {
|
||||
logger := logtest.Scoped(t)
|
||||
// TODO - use the AtRev constructor after this has been deprecated
|
||||
rawDB := dbtest.NewDB(logger, t)
|
||||
// rawDB := dbtest.NewDBAtRev(logger, t, "4.3.0")
|
||||
db := database.NewDB(logger, rawDB)
|
||||
codeIntelDB := stores.NewCodeIntelDB(logger, rawDB)
|
||||
store := basestore.NewWithHandle(db.Handle())
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
crand "crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
@ -60,49 +61,67 @@ var rng = rand.New(rand.NewSource(func() int64 {
|
||||
}()))
|
||||
var rngLock sync.Mutex
|
||||
|
||||
var dbTemplateOnce sync.Once
|
||||
|
||||
// NewDB returns a connection to a clean, new temporary testing database with
|
||||
// the same schema as Sourcegraph's production Postgres database.
|
||||
func NewDB(logger log.Logger, t testing.TB) *sql.DB {
|
||||
if testing.Short() {
|
||||
t.Skip("DB tests disabled since go test -short is specified")
|
||||
}
|
||||
|
||||
dbTemplateOnce.Do(func() {
|
||||
initTemplateDB(logger, t, "migrated", []*schemas.Schema{schemas.Frontend, schemas.CodeIntel})
|
||||
})
|
||||
|
||||
return newFromDSN(logger, t, "migrated")
|
||||
return newDB(logger, t, "migrated", schemas.Frontend, schemas.CodeIntel)
|
||||
}
|
||||
|
||||
var insightsTemplateOnce sync.Once
|
||||
// NewDBAtRev returns a connection to a clean, new temporary testing database with
|
||||
// the same schema as Sourcegraph's production Postgres database at the given revision.
|
||||
func NewDBAtRev(logger log.Logger, t testing.TB, rev string) *sql.DB {
|
||||
return newDB(
|
||||
logger,
|
||||
t,
|
||||
fmt.Sprintf("migrated-%s", rev),
|
||||
getSchemaAtRev(t, "frontend", rev),
|
||||
getSchemaAtRev(t, "codeintel", rev),
|
||||
)
|
||||
}
|
||||
|
||||
func getSchemaAtRev(t testing.TB, name, rev string) *schemas.Schema {
|
||||
schema, err := schemas.ResolveSchemaAtRev(name, rev)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to resolve %q schema: %s", name, err)
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
// NewInsightsDB returns a connection to a clean, new temporary testing database with
|
||||
// the same schema as Sourcegraph's CodeInsights production Postgres database.
|
||||
func NewInsightsDB(logger log.Logger, t testing.TB) *sql.DB {
|
||||
if testing.Short() {
|
||||
t.Skip("DB tests disabled since go test -short is specified")
|
||||
}
|
||||
|
||||
insightsTemplateOnce.Do(func() {
|
||||
initTemplateDB(logger, t, "insights", []*schemas.Schema{schemas.CodeInsights})
|
||||
})
|
||||
return newFromDSN(logger, t, "insights")
|
||||
return newDB(logger, t, "insights", schemas.CodeInsights)
|
||||
}
|
||||
|
||||
var rawTemplateOnce sync.Once
|
||||
|
||||
// NewRawDB returns a connection to a clean, new temporary testing database.
|
||||
func NewRawDB(logger log.Logger, t testing.TB) *sql.DB {
|
||||
return newDB(logger, t, "raw")
|
||||
}
|
||||
|
||||
func newDB(logger log.Logger, t testing.TB, name string, schemas ...*schemas.Schema) *sql.DB {
|
||||
if testing.Short() {
|
||||
t.Skip("DB tests disabled since go test -short is specified")
|
||||
}
|
||||
|
||||
rawTemplateOnce.Do(func() {
|
||||
initTemplateDB(logger, t, "raw", nil)
|
||||
})
|
||||
return newFromDSN(logger, t, "raw")
|
||||
onceByName(name).Do(func() { initTemplateDB(logger, t, name, schemas) })
|
||||
return newFromDSN(logger, t, name)
|
||||
}
|
||||
|
||||
var onceByNameMap = map[string]*sync.Once{}
|
||||
var onceByNameMutex sync.Mutex
|
||||
|
||||
func onceByName(name string) *sync.Once {
|
||||
onceByNameMutex.Lock()
|
||||
defer onceByNameMutex.Unlock()
|
||||
|
||||
if once, ok := onceByNameMap[name]; ok {
|
||||
return once
|
||||
}
|
||||
|
||||
once := new(sync.Once)
|
||||
onceByNameMap[name] = once
|
||||
return once
|
||||
}
|
||||
|
||||
func newFromDSN(logger log.Logger, t testing.TB, templateNamespace string) *sql.DB {
|
||||
|
||||
@ -35,7 +35,6 @@ func makeTestSchema(t *testing.T, name string) *schemas.Schema {
|
||||
return &schemas.Schema{
|
||||
Name: name,
|
||||
MigrationsTableName: fmt.Sprintf("%s_migrations_table", name),
|
||||
FS: fs,
|
||||
Definitions: definitions,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
package schemas
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/internal/database/migration/definition"
|
||||
)
|
||||
|
||||
@ -14,9 +12,6 @@ type Schema struct {
|
||||
// MigrationsTableName is the name of the table that tracks the schema version.
|
||||
MigrationsTableName string
|
||||
|
||||
// FS describes the raw migration assets of the schema.
|
||||
FS fs.FS
|
||||
|
||||
// Definitions describes the parsed migration assets of the schema.
|
||||
Definitions *definition.Definitions
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/internal/database/migration/definition"
|
||||
"github.com/sourcegraph/sourcegraph/internal/database/migration/shared"
|
||||
"github.com/sourcegraph/sourcegraph/lib/errors"
|
||||
"github.com/sourcegraph/sourcegraph/migrations"
|
||||
)
|
||||
@ -46,7 +47,19 @@ func ResolveSchema(fs fs.FS, name string) (*Schema, error) {
|
||||
return &Schema{
|
||||
Name: name,
|
||||
MigrationsTableName: MigrationsTableName(name),
|
||||
FS: fs,
|
||||
Definitions: definitions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ResolveSchemaAtRev(name, rev string) (*Schema, error) {
|
||||
definitions, err := shared.GetFrozenDefinitions(name, rev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Schema{
|
||||
Name: name,
|
||||
MigrationsTableName: MigrationsTableName(name),
|
||||
Definitions: definitions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -6,9 +6,8 @@ import (
|
||||
"github.com/sourcegraph/sourcegraph/internal/oobmigration"
|
||||
)
|
||||
|
||||
// NOTE: This should be kept up-to-date with cmd/migrator/build.sh
|
||||
// so that we "bake in" fallback schemas everything we support migrating
|
||||
// to.
|
||||
// NOTE: This should be kept up-to-date with cmd/migrator/build.sh so that we "bake in"
|
||||
// fallback schemas everything we support migrating to.
|
||||
const maxVersionString = "4.3.0"
|
||||
|
||||
// MaxVersion is the highest known released version at the time the migrator was built.
|
||||
@ -20,5 +19,13 @@ var MaxVersion = func() oobmigration.Version {
|
||||
panic(fmt.Sprintf("malformed maxVersionString %q", maxVersionString))
|
||||
}()
|
||||
|
||||
// MinVersion is the minimum version a migrator can support upgrading to a newer version of Sourcegraph.
|
||||
// MinVersion is the minimum version a migrator can support upgrading to a newer version of
|
||||
// Sourcegraph.
|
||||
var MinVersion = oobmigration.NewVersion(3, 20)
|
||||
|
||||
// FrozenRevisions are schemas at a point-in-time for which out-of-band migration unit tests
|
||||
// can continue to run on their last pre-deprecation version. This code is still ran by the
|
||||
// migrator, but only on a schema shape that existed in the past.
|
||||
var FrozenRevisions = []string{
|
||||
"4.3.0",
|
||||
}
|
||||
@ -19,26 +19,41 @@ func main() {
|
||||
}
|
||||
|
||||
func mainErr() error {
|
||||
// This script is invoked via a go:generate directive in
|
||||
// internal/database/migration/shared (embed.go)
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This script is invoked via a go:generate directive in internal/database/migration/shared (embed.go)
|
||||
repoRoot := filepath.Join(wd, "..", "..", "..", "..")
|
||||
filepath := filepath.Join(wd, "upgradedata", "stitched-migration-graph.json")
|
||||
|
||||
//
|
||||
// Write stitched migrations
|
||||
|
||||
versions, err := oobmigration.UpgradeRange(MinVersion, MaxVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
versionTags := make([]string, 0, len(versions))
|
||||
for _, version := range versions {
|
||||
versionTags = append(versionTags, version.GitTag())
|
||||
}
|
||||
if err := stitchAndWrite(repoRoot, filepath.Join(wd, "data", "stitched-migration-graph.json"), versionTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//
|
||||
// Write frozen migrations
|
||||
|
||||
for _, rev := range FrozenRevisions {
|
||||
if err := stitchAndWrite(repoRoot, filepath.Join(wd, "data", "frozen", fmt.Sprintf("%s.json", rev)), []string{rev}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func stitchAndWrite(repoRoot, filepath string, versionTags []string) error {
|
||||
stitchedMigrationBySchemaName := map[string]shared.StitchedMigration{}
|
||||
for _, schemaName := range schemas.SchemaNames {
|
||||
stitched, err := stitch.StitchDefinitions(schemaName, repoRoot, versionTags)
|
||||
2089
internal/database/migration/shared/data/frozen/3.34.2.json
Executable file
2089
internal/database/migration/shared/data/frozen/3.34.2.json
Executable file
File diff suppressed because one or more lines are too long
2540
internal/database/migration/shared/data/frozen/4.3.0.json
Executable file
2540
internal/database/migration/shared/data/frozen/4.3.0.json
Executable file
File diff suppressed because one or more lines are too long
@ -1,23 +1,66 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/internal/database/migration/definition"
|
||||
"github.com/sourcegraph/sourcegraph/lib/errors"
|
||||
)
|
||||
|
||||
//go:generate go run ./upgradedata/cmd/generator
|
||||
// Ensure upgradedata/stitched-migration-graph.json is generated
|
||||
//go:generate go run ./data/cmd/generator
|
||||
// Ensure data/* files are generated
|
||||
|
||||
//go:embed upgradedata/stitched-migration-graph.json
|
||||
var upgradeDataPayloadContents string
|
||||
var (
|
||||
root = "internal/database/migration/shared/data"
|
||||
stitchfile = filepath.Join(root, "stitched-migration-graph.json")
|
||||
constfile = filepath.Join(root, "cmd/generator/consts.go")
|
||||
)
|
||||
|
||||
//go:embed data/stitched-migration-graph.json
|
||||
var stitchedPayloadContents string
|
||||
|
||||
// StitchedMigationsBySchemaName is a map from schema name to migration upgrade metadata.
|
||||
// The data backing the map is updated by `go generating` this package.
|
||||
var StitchedMigationsBySchemaName = map[string]StitchedMigration{}
|
||||
|
||||
func init() {
|
||||
if err := json.Unmarshal([]byte(upgradeDataPayloadContents), &StitchedMigationsBySchemaName); err != nil {
|
||||
panic(fmt.Sprintf("failed to load upgrade data (check the contents of internal/database/migration/shared/upgradedata/stitched-migration-graph.json): %s", err))
|
||||
if err := json.Unmarshal([]byte(stitchedPayloadContents), &StitchedMigationsBySchemaName); err != nil {
|
||||
panic(fmt.Sprintf("failed to load upgrade data (check the contents of %s): %s", stitchfile, err))
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed data/frozen/*
|
||||
var frozenDataDir embed.FS
|
||||
|
||||
// GetFrozenDefinitions returns the schema definitions frozen at a given revision. This
|
||||
// function returns an error if the given schema has not been generated into data/frozen.
|
||||
func GetFrozenDefinitions(schemaName, rev string) (*definition.Definitions, error) {
|
||||
f, err := frozenDataDir.Open(fmt.Sprintf("data/frozen/%s.json", rev))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, errors.Newf("failed to load schema at revision %q (check the versions listed in %s)", rev, constfile)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
content, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var definitionBySchema map[string]struct {
|
||||
Definitions *definition.Definitions
|
||||
}
|
||||
if err := json.Unmarshal(content, &definitionBySchema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return definitionBySchema[schemaName].Definitions, nil
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user