From 14b5e59a444fca83342fac5b880d56fb580dbec3 Mon Sep 17 00:00:00 2001 From: Stephen Goeddel Date: Tue, 10 Feb 2026 10:07:01 -0500 Subject: [PATCH 1/2] normalize job names during variant generation for openshift/release --- pkg/variantregistry/ocp.go | 18 +++++++++++++-- pkg/variantregistry/ocp_test.go | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/pkg/variantregistry/ocp.go b/pkg/variantregistry/ocp.go index fd2db2049..574488bf3 100644 --- a/pkg/variantregistry/ocp.go +++ b/pkg/variantregistry/ocp.go @@ -234,11 +234,15 @@ ORDER BY j.prowjob_job_name; jLog.WithField("gcs_bucket", jlr.GCSBucket).WithField("url", jlr.URL.StringVal).Error("job had no gcs bucket or prow job url, proceeding without") } - variants := v.CalculateVariantsForJob(jLog, jlr.JobName, clusterData) + normalizedJobName := normalizeJobNameForVariants(jlr.JobName) + variants := v.CalculateVariantsForJob(jLog, normalizedJobName, clusterData) variantsByJobMu.Lock() - variantsByJob[jlr.JobName] = variants + variantsByJob[normalizedJobName] = variants variantsByJobMu.Unlock() count.Add(1) + if normalizedJobName != jlr.JobName { + jLog.WithField("original_name", jlr.JobName).WithField("normalized_name", normalizedJobName).Info("normalized job name") + } jLog.WithField("variants", variants).WithField("count", count.Load()).Info("calculated variants") } } @@ -252,6 +256,16 @@ ORDER BY j.prowjob_job_name; return variantsByJob, nil } +// normalizeJobNameForVariants normalizes job names to handle transitions like master -> main. +// This ensures that jobs renamed from master to main are treated as the same job in the variant registry. +// Currently only applies to openshift/release jobs. +func normalizeJobNameForVariants(jobName string) string { + if strings.Contains(jobName, "openshift-release") { + return strings.ReplaceAll(jobName, "-master-", "-main-") + } + return jobName +} + // fileVariantsToIgnore are values in the cluster-data.json that vary by run, and are not consistent for the job itself. // These are unsuited for variants. var fileVariantsToIgnore = map[string]bool{ diff --git a/pkg/variantregistry/ocp_test.go b/pkg/variantregistry/ocp_test.go index 51737ed03..dc68eb0d8 100644 --- a/pkg/variantregistry/ocp_test.go +++ b/pkg/variantregistry/ocp_test.go @@ -1790,3 +1790,44 @@ func TestVariantsSnapshot(t *testing.T) { t.Logf("\n****** Run `make update-variants` to update the snapshot and accept these changes.") } } + +func TestNormalizeJobNameForVariants(t *testing.T) { + tests := []struct { + name string + jobName string + expected string + }{ + { + name: "openshift-release master to main", + jobName: "periodic-ci-openshift-release-master-nightly-4.16-e2e-aws-ovn", + expected: "periodic-ci-openshift-release-main-nightly-4.16-e2e-aws-ovn", + }, + { + name: "openshift-release ci master to main", + jobName: "periodic-ci-openshift-release-master-ci-4.16-e2e-azure-ovn-upgrade", + expected: "periodic-ci-openshift-release-main-ci-4.16-e2e-azure-ovn-upgrade", + }, + { + name: "non-openshift-release master unchanged", + jobName: "periodic-ci-openshift-multiarch-master-nightly-4.17-ocp-e2e-aws-ovn", + expected: "periodic-ci-openshift-multiarch-master-nightly-4.17-ocp-e2e-aws-ovn", + }, + { + name: "already main stays main", + jobName: "periodic-ci-openshift-release-main-nightly-4.16-e2e-aws-ovn", + expected: "periodic-ci-openshift-release-main-nightly-4.16-e2e-aws-ovn", + }, + { + name: "other repos with master unchanged", + jobName: "periodic-ci-openshift-hive-master-e2e-aws", + expected: "periodic-ci-openshift-hive-master-e2e-aws", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := normalizeJobNameForVariants(tt.jobName) + assert.Equal(t, tt.expected, result, "normalization failed for %s", tt.jobName) + }) + } +} From f31daf1f54fb33e30c69d1115e35bc6011cba0b2 Mon Sep 17 00:00:00 2001 From: Stephen Goeddel Date: Tue, 10 Feb 2026 10:38:54 -0500 Subject: [PATCH 2/2] handle temporary collisions by prefering main to master --- pkg/variantregistry/ocp.go | 44 ++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/pkg/variantregistry/ocp.go b/pkg/variantregistry/ocp.go index 574488bf3..ba4649acd 100644 --- a/pkg/variantregistry/ocp.go +++ b/pkg/variantregistry/ocp.go @@ -161,12 +161,13 @@ ORDER BY j.prowjob_job_name; } var ( - wg sync.WaitGroup - parallelism = 20 - jobCh = make(chan *prowJobLastRun) - count atomic.Int64 - variantsByJobMu sync.Mutex - variantsByJob = make(map[string]map[string]string) + wg sync.WaitGroup + parallelism = 20 + jobCh = make(chan *prowJobLastRun) + count atomic.Int64 + variantsByJobMu sync.Mutex + variantsByJob = make(map[string]map[string]string) + variantsByJobSource = make(map[string]string) // tracks which original job name was used ) // Producer @@ -236,9 +237,33 @@ ORDER BY j.prowjob_job_name; normalizedJobName := normalizeJobNameForVariants(jlr.JobName) variants := v.CalculateVariantsForJob(jLog, normalizedJobName, clusterData) + + // Handle collision resolution when multiple job names normalize to the same key. + // This is temporary transition logic for the openshift-release master->main rename. + // TODO(sgoeddel): Remove this collision handling logic after confirming no master jobs exist + // in query results (master jobs fully aged out). variantsByJobMu.Lock() - variantsByJob[normalizedJobName] = variants + existingSource := variantsByJobSource[normalizedJobName] + shouldUpdate := false + + if existingSource == "" { + // No existing entry, always insert + shouldUpdate = true + } else if strings.Contains(existingSource, "-master-") && strings.Contains(jlr.JobName, "-main-") { + // Prefer main over master for deterministic collision resolution + shouldUpdate = true + jLog.WithField("existing_source", existingSource).WithField("new_source", jlr.JobName).Info("replacing master variant with main variant") + } else { + // Keep existing entry (either main already exists, or both are master/main, first wins) + jLog.WithField("existing_source", existingSource).WithField("new_source", jlr.JobName).Debug("keeping existing variant, skipping duplicate") + } + + if shouldUpdate { + variantsByJob[normalizedJobName] = variants + variantsByJobSource[normalizedJobName] = jlr.JobName + } variantsByJobMu.Unlock() + count.Add(1) if normalizedJobName != jlr.JobName { jLog.WithField("original_name", jlr.JobName).WithField("normalized_name", normalizedJobName).Info("normalized job name") @@ -260,8 +285,9 @@ ORDER BY j.prowjob_job_name; // This ensures that jobs renamed from master to main are treated as the same job in the variant registry. // Currently only applies to openshift/release jobs. func normalizeJobNameForVariants(jobName string) string { - if strings.Contains(jobName, "openshift-release") { - return strings.ReplaceAll(jobName, "-master-", "-main-") + // Only normalize openshift-release jobs, using Replace (not ReplaceAll) to change only the first occurrence + if strings.Contains(jobName, "openshift-release-master") { + return strings.Replace(jobName, "-master-", "-main-", 1) } return jobName }