Skip to content

Commit bdc3fe8

Browse files
mstaebleclaude
andcommitted
Move release metadata from BigQuery to PostgreSQL
Create a release_definitions table to store release metadata (GA dates, development start dates, previous release, capabilities, etc.) that was previously only available in BigQuery. During the data load cycle, releases fetched from BQ are converted directly from ReleaseRow to ReleaseDefinition and synced to PostgreSQL. All release data consumers now read from PostgreSQL via GetReleasesFromDB and GetReleaseDatesFromDB. The BigQuery release functions (GetReleasesFromBigQuery, GetReleases, QueryReleaseDates) are removed, along with the hardcoded releaseMetadata map from the PostgreSQL data provider and the QueryReleases/QueryReleaseDates methods from the DataProvider interface. Internally, all consumers use models.ReleaseDefinition directly instead of converting through the v1.Release intermediary. Capability constants are defined in pkg/db/models alongside the ReleaseDefinition type. Ref: TRT-2734 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent dd64c4f commit bdc3fe8

39 files changed

Lines changed: 354 additions & 442 deletions

cmd/sippy/automatejira.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,12 @@ func NewAutomateJiraCommand() *cobra.Command {
152152
if err != nil {
153153
log.WithError(err).Fatal("unable to load views")
154154
}
155-
releases, err := api.GetReleases(context.Background(), bigQueryClient, false)
155+
156+
dbc, err := f.PostgresFlags.GetDBClient()
157+
if err != nil {
158+
log.WithError(err).Fatal("unable to connect to postgres")
159+
}
160+
releases, err := api.GetReleasesFromDB(ctx, dbc)
156161
if err != nil {
157162
log.WithError(err).Fatal("error querying releases")
158163
}
@@ -178,10 +183,6 @@ func NewAutomateJiraCommand() *cobra.Command {
178183
return errors.WithMessage(err, "error validating options")
179184
}
180185

181-
dbc, err := f.PostgresFlags.GetDBClient()
182-
if err != nil {
183-
log.WithError(err).Fatal("unable to connect to postgres")
184-
}
185186
j, err := jiraautomator.NewJiraAutomator(
186187
jiraClient, bigQueryClient, provider, dbc, cacheOpts,
187188
views.ComponentReadiness, releases, f.SippyURL, f.JiraAccount,

cmd/sippy/load.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"cloud.google.com/go/bigquery"
1212
"github.com/openshift/sippy/pkg/api"
1313
"github.com/openshift/sippy/pkg/api/componentreadiness"
14-
sippyv1 "github.com/openshift/sippy/pkg/apis/sippy/v1"
1514
"github.com/openshift/sippy/pkg/dataloader/regressioncacheloader"
1615
"github.com/pkg/errors"
1716
"github.com/prometheus/client_golang/prometheus"
@@ -40,6 +39,7 @@ import (
4039
"github.com/openshift/sippy/pkg/dataloader/releaseloader"
4140
"github.com/openshift/sippy/pkg/dataloader/testownershiploader"
4241
"github.com/openshift/sippy/pkg/db"
42+
"github.com/openshift/sippy/pkg/db/models"
4343
"github.com/openshift/sippy/pkg/flags"
4444
"github.com/openshift/sippy/pkg/github/commenter"
4545
)
@@ -151,7 +151,7 @@ func NewLoadCommand() *cobra.Command {
151151
cacheClient = nil // error hygiene, since we pass this down to quite a few functions
152152
}
153153

154-
releaseConfigs := []sippyv1.Release{}
154+
var releaseDefs []models.ReleaseDefinition
155155

156156
// initializing a bigquery client different from the normal one
157157
opCtx, ctx := bqcachedclient.OpCtxForCronEnv(ctx, "load")
@@ -163,15 +163,27 @@ func NewLoadCommand() *cobra.Command {
163163
if f.CacheFlags.EnablePersistentCaching {
164164
bqc = f.CacheFlags.DecorateBiqQueryClientWithPersistentCache(bqc)
165165
}
166-
releaseConfigs, err = api.GetReleasesFromBigQuery(context.Background(), bqc)
166+
releaseRows, err := api.GetReleaseRowsFromBigQuery(context.Background(), bqc)
167167
if err != nil {
168168
return errors.Wrapf(err, "error querying releases from bq")
169169
}
170+
releaseDefs = make([]models.ReleaseDefinition, 0, len(releaseRows))
171+
for _, row := range releaseRows {
172+
releaseDefs = append(releaseDefs, releaseloader.ReleaseRowToDefinition(row))
173+
}
174+
175+
// Sync release definitions from BQ to PostgreSQL so the serving
176+
// path can read them without a BigQuery dependency.
177+
if dbErr == nil && len(releaseDefs) > 0 {
178+
if syncErr := releaseloader.SyncReleaseDefinitions(dbc, releaseDefs); syncErr != nil {
179+
log.WithError(syncErr).Warning("failed to sync release definitions to postgres")
180+
}
181+
}
170182
}
171183

172184
// Ensure partitions exist for all releases (only when InitDatabase is true)
173185
if f.InitDatabase && dbErr == nil {
174-
err = ensurePartitionsForReleases(dbc, releaseConfigs)
186+
err = ensurePartitionsForReleases(dbc, releaseDefs)
175187
if err != nil {
176188
return errors.Wrapf(err, "error ensuring partitions")
177189
}
@@ -236,7 +248,7 @@ func NewLoadCommand() *cobra.Command {
236248
regressionStore := componentreadiness.NewPostgresRegressionStore(dbc, jiraClient)
237249

238250
rcl, err := regressioncacheloader.New(
239-
dbc, bqc, config, views.ComponentReadiness, releaseConfigs,
251+
dbc, bqc, config, views.ComponentReadiness, releaseDefs,
240252
f.ComponentReadinessFlags.CRTimeRoundingFactor,
241253
f.ComponentReadinessFlags.CRTimeRoundingOffset,
242254
regressionStore,
@@ -251,7 +263,7 @@ func NewLoadCommand() *cobra.Command {
251263
if dbErr != nil {
252264
return dbErr
253265
}
254-
loaders = append(loaders, releaseloader.New(ctx, dbc, bqc, f.Releases, f.Architectures, releaseConfigs))
266+
loaders = append(loaders, releaseloader.New(ctx, dbc, bqc, f.Releases, f.Architectures, releaseDefs))
255267
}
256268

257269
// Prow Loader
@@ -260,7 +272,7 @@ func NewLoadCommand() *cobra.Command {
260272
if dbErr != nil {
261273
return dbErr
262274
}
263-
prowLoader, err := f.prowLoader(ctx, dbc, config, releaseConfigs, promPusher)
275+
prowLoader, err := f.prowLoader(ctx, dbc, config, releaseDefs, promPusher)
264276
if err != nil {
265277
return err
266278
}
@@ -330,7 +342,7 @@ func NewLoadCommand() *cobra.Command {
330342
// Feature gates
331343
if l == "feature-gates" {
332344
refreshMatviews = true
333-
fgLoader := featuregateloader.New(dbc, releaseConfigs)
345+
fgLoader := featuregateloader.New(dbc, releaseDefs)
334346
loaders = append(loaders, fgLoader)
335347
}
336348

@@ -417,7 +429,7 @@ func (f *LoadFlags) jobVariantsLoader(ctx context.Context) (dataloader.DataLoade
417429

418430
}
419431

420-
func (f *LoadFlags) prowLoader(ctx context.Context, dbc *db.DB, sippyConfig *v1.SippyConfig, releaseConfigs []sippyv1.Release, promPusher *push.Pusher) (dataloader.DataLoader, error) {
432+
func (f *LoadFlags) prowLoader(ctx context.Context, dbc *db.DB, sippyConfig *v1.SippyConfig, releaseDefs []models.ReleaseDefinition, promPusher *push.Pusher) (dataloader.DataLoader, error) {
421433
gcsClient, err := gcs.NewGCSClient(ctx,
422434
f.GoogleCloudFlags.ServiceAccountCredentialFile,
423435
f.GoogleCloudFlags.OAuthClientCredentialFile,
@@ -452,8 +464,8 @@ func (f *LoadFlags) prowLoader(ctx context.Context, dbc *db.DB, sippyConfig *v1.
452464

453465
releases := f.Releases
454466
if len(releases) == 0 { // if not specified, use those defined in the Releases table
455-
for _, config := range releaseConfigs {
456-
releases = append(releases, config.Release) // could filter by capability if needed
467+
for _, def := range releaseDefs {
468+
releases = append(releases, def.Release) // could filter by capability if needed
457469
}
458470
}
459471

@@ -503,10 +515,9 @@ func parseProwLoadSince(val string) (time.Time, error) {
503515
// ensurePartitionsForReleases creates partitions for all configured releases.
504516
// It uses a 7 day lookback window plus 2 days forward from today.
505517
// Errors are logged but ignored to prevent blocking the load process.
506-
func ensurePartitionsForReleases(dbc *db.DB, releaseConfigs []sippyv1.Release) error {
507-
// Extract release names from release configs
508-
releases := make([]string, 0, len(releaseConfigs))
509-
for _, r := range releaseConfigs {
518+
func ensurePartitionsForReleases(dbc *db.DB, releaseDefs []models.ReleaseDefinition) error {
519+
releases := make([]string, 0, len(releaseDefs))
520+
for _, r := range releaseDefs {
510521
releases = append(releases, r.Release)
511522
}
512523

cmd/sippy/seed_data.go

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/spf13/pflag"
1717
"gopkg.in/yaml.v3"
1818

19+
"github.com/openshift/sippy/pkg/api"
1920
componentreadiness "github.com/openshift/sippy/pkg/api/componentreadiness"
2021
pgprovider "github.com/openshift/sippy/pkg/api/componentreadiness/dataprovider/postgres"
2122
"github.com/openshift/sippy/pkg/api/componentreadiness/utils"
@@ -410,6 +411,11 @@ func seedSyntheticData(dbc *db.DB) error {
410411
return nil
411412
}
412413

414+
if err := seedReleaseDefinitions(dbc); err != nil {
415+
return errors.WithMessage(err, "failed to seed release definitions")
416+
}
417+
log.Info("Seeded release definitions")
418+
413419
if err := createTestSuite(dbc, "synthetic"); err != nil {
414420
return errors.WithMessage(err, "failed to create test suite")
415421
}
@@ -445,6 +451,53 @@ func seedSyntheticData(dbc *db.DB) error {
445451
return nil
446452
}
447453

454+
func seedReleaseDefinitions(dbc *db.DB) error {
455+
now := time.Now().UTC()
456+
allCaps := pq.StringArray{"componentReadiness", "featureGates", "metrics", "payloadTags", "sippyClassic"}
457+
458+
type relMeta struct {
459+
previous string
460+
gaDays int // negative = days before now; 0 = no GA (in development)
461+
}
462+
meta := map[string]relMeta{
463+
"4.19": {previous: "4.18", gaDays: -289},
464+
"4.20": {previous: "4.19", gaDays: -163},
465+
"4.21": {previous: "4.20", gaDays: -58},
466+
"4.22": {previous: "4.21"},
467+
}
468+
469+
for _, release := range syntheticReleases {
470+
m := meta[release]
471+
parts := strings.Split(release, ".")
472+
major, minor := 0, 0
473+
if len(parts) >= 2 {
474+
fmt.Sscanf(parts[0], "%d", &major)
475+
fmt.Sscanf(parts[1], "%d", &minor)
476+
}
477+
478+
develStart := now.AddDate(0, 0, m.gaDays-180)
479+
def := models.ReleaseDefinition{
480+
Release: release,
481+
Major: major,
482+
Minor: minor,
483+
PreviousRelease: m.previous,
484+
DevelopmentStartDate: &develStart,
485+
Product: "OCP",
486+
Status: "Full Support",
487+
Capabilities: allCaps,
488+
}
489+
if m.gaDays != 0 {
490+
ga := now.AddDate(0, 0, m.gaDays)
491+
def.GADate = &ga
492+
}
493+
494+
if err := dbc.DB.Where("release = ?", release).FirstOrCreate(&def).Error; err != nil {
495+
return fmt.Errorf("failed to create release definition %s: %w", release, err)
496+
}
497+
}
498+
return nil
499+
}
500+
448501
func seedProwJobs(dbc *db.DB) error {
449502
for _, release := range syntheticReleases {
450503
for _, job := range syntheticJobs {
@@ -692,7 +745,7 @@ func syncRegressions(dbc *db.DB) error {
692745
provider := pgprovider.NewPostgresProvider(dbc, nil)
693746
ctx := context.Background()
694747

695-
releases, err := provider.QueryReleases(ctx)
748+
releases, err := api.GetReleasesFromDB(ctx, dbc)
696749
if err != nil {
697750
return fmt.Errorf("querying releases: %w", err)
698751
}

pkg/api/componentreadiness/component_report.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ import (
3131
"github.com/openshift/sippy/pkg/api/componentreadiness/utils"
3232
crtype "github.com/openshift/sippy/pkg/apis/api/componentreport"
3333
"github.com/openshift/sippy/pkg/apis/cache"
34-
v1 "github.com/openshift/sippy/pkg/apis/sippy/v1"
3534
"github.com/openshift/sippy/pkg/db"
35+
"github.com/openshift/sippy/pkg/db/models"
3636
"github.com/openshift/sippy/pkg/util/sets"
3737
)
3838

@@ -82,7 +82,7 @@ func GetComponentReport(
8282
reqOptions reqopts.RequestOptions,
8383
baseURL string,
8484
) (report crtype.ComponentReport, errs []error) {
85-
releaseConfigs, err := provider.QueryReleases(ctx)
85+
releaseConfigs, err := api.GetReleasesFromDB(ctx, dbc)
8686
if err != nil {
8787
return report, []error{err}
8888
}
@@ -151,7 +151,7 @@ func (c *ComponentReportGenerator) PostAnalysis(report *crtype.ComponentReport)
151151
return nil
152152
}
153153

154-
func NewComponentReportGenerator(provider dataprovider.DataProvider, reqOptions reqopts.RequestOptions, dbc *db.DB, releaseConfigs []v1.Release, baseURL string) ComponentReportGenerator {
154+
func NewComponentReportGenerator(provider dataprovider.DataProvider, reqOptions reqopts.RequestOptions, dbc *db.DB, releaseConfigs []models.ReleaseDefinition, baseURL string) ComponentReportGenerator {
155155
slices.Sort(reqOptions.Capabilities) // normalize ordering so cache keys match
156156
generator := ComponentReportGenerator{
157157
dataProvider: provider,
@@ -175,7 +175,7 @@ type ComponentReportGenerator struct {
175175
dbc *db.DB
176176
ReqOptions reqopts.RequestOptions
177177
middlewares middleware.List
178-
releaseConfigs []v1.Release
178+
releaseConfigs []models.ReleaseDefinition
179179
baseURL string
180180
}
181181

@@ -278,7 +278,7 @@ func (c *ComponentReportGenerator) initializeMiddleware() {
278278
c.middlewares = middleware.List{}
279279
// Initialize all our middleware applicable to this request.
280280
if c.ReqOptions.AdvancedOption.IncludeMultiReleaseAnalysis && c.ReqOptions.SampleRelease.PullRequestOptions == nil {
281-
c.middlewares = append(c.middlewares, releasefallback.NewReleaseFallbackMiddleware(c.dataProvider, c.ReqOptions, c.releaseConfigs))
281+
c.middlewares = append(c.middlewares, releasefallback.NewReleaseFallbackMiddleware(c.dataProvider, c.dbc, c.ReqOptions, c.releaseConfigs))
282282
}
283283
if c.dbc != nil {
284284
c.middlewares = append(c.middlewares, regressiontracker.NewRegressionTrackerMiddleware(c.dbc, c.ReqOptions))

pkg/api/componentreadiness/dataprovider/bigquery/provider.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"github.com/openshift/sippy/pkg/apis/api/componentreport/crtest"
1919
"github.com/openshift/sippy/pkg/apis/api/componentreport/reqopts"
2020
apiCache "github.com/openshift/sippy/pkg/apis/cache"
21-
v1 "github.com/openshift/sippy/pkg/apis/sippy/v1"
2221
bqcachedclient "github.com/openshift/sippy/pkg/bigquery"
2322
"github.com/openshift/sippy/pkg/bigquery/bqlabel"
2423
"github.com/openshift/sippy/pkg/util/param"
@@ -170,14 +169,6 @@ func (p *BigQueryProvider) QueryJobVariants(ctx context.Context) (crtest.JobVari
170169
return variants, nil
171170
}
172171

173-
func (p *BigQueryProvider) QueryReleaseDates(ctx context.Context, reqOptions reqopts.RequestOptions) ([]crtest.ReleaseTimeRange, []error) {
174-
return GetReleaseDatesFromBigQuery(ctx, p.client, reqOptions)
175-
}
176-
177-
func (p *BigQueryProvider) QueryReleases(ctx context.Context) ([]v1.Release, error) {
178-
return apiPkg.GetReleasesFromBigQuery(ctx, p.client)
179-
}
180-
181172
func (p *BigQueryProvider) QueryUniqueVariantValues(ctx context.Context, field string, nested bool) ([]string, error) {
182173
unnest := ""
183174
if nested {

pkg/api/componentreadiness/dataprovider/bigquery/releasedates.go

Lines changed: 0 additions & 44 deletions
This file was deleted.

pkg/api/componentreadiness/dataprovider/interface.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"github.com/openshift/sippy/pkg/apis/api/componentreport/crtest"
99
"github.com/openshift/sippy/pkg/apis/api/componentreport/reqopts"
1010
"github.com/openshift/sippy/pkg/apis/cache"
11-
v1 "github.com/openshift/sippy/pkg/apis/sippy/v1"
1211
)
1312

1413
// TestStatusQuerier fetches aggregated test pass/fail counts.
@@ -40,12 +39,6 @@ type MetadataQuerier interface {
4039
// QueryJobVariants returns all variant names and their possible values.
4140
QueryJobVariants(ctx context.Context) (crtest.JobVariants, []error)
4241

43-
// QueryReleaseDates returns the time ranges for each known release.
44-
QueryReleaseDates(ctx context.Context, reqOptions reqopts.RequestOptions) ([]crtest.ReleaseTimeRange, []error)
45-
46-
// QueryReleases returns known release configurations.
47-
QueryReleases(ctx context.Context) ([]v1.Release, error)
48-
4942
// QueryUniqueVariantValues returns distinct values for a variant column
5043
// from the past 60 days.
5144
QueryUniqueVariantValues(ctx context.Context, field string, nested bool) ([]string, error)

0 commit comments

Comments
 (0)