Skip to content

TRT-2768: Import /payload job results from PRs into postgres#3728

Open
dgoodwin wants to merge 17 commits into
openshift:mainfrom
dgoodwin:import-pr-payload-jobs
Open

TRT-2768: Import /payload job results from PRs into postgres#3728
dgoodwin wants to merge 17 commits into
openshift:mainfrom
dgoodwin:import-pr-payload-jobs

Conversation

@dgoodwin

@dgoodwin dgoodwin commented Jul 2, 2026

Copy link
Copy Markdown
Contributor
  • Core change here is to begin importing jobs run in a PR via /payload commands as if they were presubmit data.
  • Involves a small hack to normalize the prow job name openshift-origin-31301-ci-5.0-upgrade-from-stable-4.22-e2e-gcp-ovn-rt-upgrade by removing the PR number, so any /payload job run of this job gets the same job name: openshift-origin-ci-5.0-upgrade-from-stable-4.22-e2e-gcp-ovn-rt-upgrade
  • Ports the api endpoint for test_results for a PR to now use postgresql instead of BQ.
  • This positions the endpoint as cost effective to roll out a risk analysis agent across many repositories, which will examine PR test results for anything suspicious and related to the code change, without worrying about bigquery costs.
    • In my testing, the response for a 2 week query of presubmit data for one PR in the prod db is now very fast with the sharding.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Expanded synthetic seeding to include Presubmits test data.
    • Added end-to-end coverage for /api/pull_requests/test_results.
    • Added support for a limit query parameter.
  • Bug Fixes

    • Improved /payload sub-job handling for more reliable presubmit-style job/variant matching.
    • TestGrid links are no longer generated for payload presubmit jobs where they don’t apply.
  • API Updates

    • /api/pull_requests/test_results now always uses PostgreSQL and returns job-run–scoped results, with failures-only-by-default plus optional successes (include_successes) and latest_sha_only.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: automatic mode

@dgoodwin dgoodwin changed the title Import /payload job results from PRs TRT-2768: Import /payload job results from PRs into postgres Jul 2, 2026
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 2, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 2, 2026

Copy link
Copy Markdown

@dgoodwin: This pull request references TRT-2768 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR normalizes payload Prow jobs as presubmits, adds synthetic presubmit data, and moves pull request test-result retrieval from BigQuery to PostgreSQL with updated endpoint handling and e2e coverage.

Changes

Payload presubmit classification and normalization

Layer / File(s) Summary
Payload presubmit classification and normalization
pkg/dataloader/prowloader/bigqueryjobs.go, pkg/dataloader/prowloader/prow.go, pkg/variantregistry/ocp.go, pkg/db/models/releases.go, pkg/api/job_runs.go
Payload jobs are detected from annotations and PR refs, assigned normalized names and presubmit types, routed to the Presubmits release, and handled consistently by variant and risk-analysis logic.

PostgreSQL PR test results endpoint

Layer / File(s) Summary
PostgreSQL PR test results endpoint
pkg/api/prtestresults.go, pkg/sippyserver/server.go, pkg/db/models/prow.go, pkg/util/param/param.go
PR test results are queried from PostgreSQL with job-run metadata, optional success filtering, latest-SHA selection, date defaults, and limits; the server endpoint uses the local database and validates limit.

Synthetic presubmit data and endpoint validation

Layer / File(s) Summary
Synthetic presubmit data and endpoint validation
cmd/sippy/seed_data.go, test/e2e/pull_requests_test.go
Synthetic presubmit releases, pull requests, runs, tests, outputs, and release definitions are seeded, with e2e coverage for filtering, SHA selection, defaults, validation errors, and empty results.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested labels: lgtm, ready-for-human-review

Suggested reviewers: petr-muller, neisw, stbenjam

🚥 Pre-merge checks | ✅ 18 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Go Error Handling ⚠️ Warning The new limit parsing in PrintPRTestResultsJSON ignores strconv.Atoi errors and silently falls back to the default instead of handling them. Use param.ReadUint or return a 400/error with context when limit parsing fails; don’t swallow the parse error.
Test Coverage For New Features ⚠️ Warning New functionality has only e2e coverage; no unit tests exist for matchRelease/isPayloadPresubmit, prtestresults, param limit parsing, or seedPresubmitData. Add unit tests for the new payload-release logic, PR test-results query/handler, limit validation, and seedPresubmitData; split out pure logic if needed.
✅ Passed checks (18 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: importing /payload PR job results into PostgreSQL.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Sql Injection Prevention ✅ Passed The new PostgreSQL query binds all user inputs with placeholders; include_successes is passed as a LIKE parameter, not concatenated into SQL.
Excessive Css In React Should Use Styles ✅ Passed No React components or inline CSS changes are present in the PR’s changed files, so this styling check is not applicable.
Single Responsibility And Clear Naming ✅ Passed New helpers and names stay domain-specific; no generic manager/util types or obviously over-broad structs/methods were introduced.
Feature Documentation ✅ Passed docs/features only has job-analysis-symptoms.md, which covers symptoms/labels and not PR test_results or /payload ingestion; no feature doc change was needed.
Stable And Deterministic Test Names ✅ Passed All added test titles are static string literals (Test.../t.Run names); no dynamic identifiers, timestamps, or generated names appear.
Test Structure And Quality ✅ Passed PASS: The new tests are plain testing/testify HTTP checks, create no resources or waits, and include meaningful assertion messages consistent with existing e2e style.
Microshift Test Compatibility ✅ Passed PASS: The new e2e tests only call the local Sippy HTTP API and inspect JSON; they use no OpenShift APIs, special namespaces, or MicroShift-unsupported features.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The added e2e tests only call the PR test_results HTTP API and assert response fields; they don’t count nodes, schedule pods, or require multi-node topology.
Topology-Aware Scheduling Compatibility ✅ Passed Touched files are data/API/test code only; no anti-affinity, nodeSelector, topology spread, replicas, or PDB changes were introduced.
Ote Binary Stdout Contract ✅ Passed No new process-level stdout writes were added; touched entrypoints use logrus, and there’s no fmt/klog stdout in main/setup code.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The new e2e tests only call the local Sippy API via util.SippyGet, which uses net.JoinHostPort, and contain no IPv4 literals or public internet deps.
No-Weak-Crypto ✅ Passed The PR only adds job/result ingestion and API/seed logic; touched files contain no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret/token comparisons.
Container-Privileges ✅ Passed No changed files are container/K8s manifests, and the PR diff shows no privileged/root/host settings.
No-Sensitive-Data-In-Logs ✅ Passed New/changed logs only emit public job/PR metadata and counts; no secrets, PII, tokens, hostnames, or customer data were logged.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@openshift-ci
openshift-ci Bot requested review from neisw and petr-muller July 2, 2026 14:18
@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: dgoodwin

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 2, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/dataloader/prowloader/prow.go (1)

1002-1035: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep payload TestGridURL suppressed on updates too.

New payload jobs skip TestGridURL, but the existing-job path later backfills it whenever the field is empty. That makes the payload-specific behavior disappear after a subsequent import.

Proposed fix
-		if len(dbProwJob.TestGridURL) == 0 {
+		if isPayloadPresubmit && dbProwJob.TestGridURL != "" {
+			dbProwJob.TestGridURL = ""
+			saveDB = true
+		} else if !isPayloadPresubmit && len(dbProwJob.TestGridURL) == 0 {
 			dbProwJob.TestGridURL = pl.generateTestGridURL(release, pj.Spec.Job).String()
 			if len(dbProwJob.TestGridURL) > 0 {
 				saveDB = true
 			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dataloader/prowloader/prow.go` around lines 1002 - 1035, The existing-job
update path in the prow loader is backfilling TestGridURL even for payload jobs,
which breaks the payload-specific suppression. Update the logic in the prow job
import flow around pl.generateTestGridURL and dbProwJob handling so TestGridURL
is only populated for non-payload jobs, both on insert and on subsequent
updates, and leave empty values untouched for payload imports.
🧹 Nitpick comments (2)
pkg/dataloader/prowloader/prow.go (1)

975-1020: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Add regression tests for payload variant and persistence behavior.

Please cover releaseJobName-based variant identification, release variant rewriting to Presubmits, create-vs-update behavior, and TestGridURL suppression. As per coding guidelines, modified Go functionality should include test coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dataloader/prowloader/prow.go` around lines 975 - 1020, Add regression
tests around prow job persistence in the prow loader to cover the new payload
handling in identifyVariants and the dbProwJob create/update path. Verify that
when pj.Annotations["releaseJobName"] is present and pj.Spec.Refs is non-nil,
the variant name comes from releaseJobName, any release variant is rewritten to
Presubmits, and TestGridURL is left empty; also cover the non-payload case where
generateTestGridURL is used. Include both the new ProwJob creation path and the
existing cache/update path in the prowJobCache logic so the behavior stays
covered.

Source: Coding guidelines

pkg/dataloader/prowloader/bigqueryjobs.go (1)

132-176: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Add regression coverage for the payload transformation contract.

This new branch rewrites identity, type, annotations, and PR refs. Please add tests for stable-name stripping, fallback naming, aggregator skipping, and comma-normalized releaseJobName values. As per coding guidelines, new or modified functionality should include test coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dataloader/prowloader/bigqueryjobs.go` around lines 132 - 176, Add
regression tests for the payload sub-job transformation in the bigquery job
ingestion path, covering the branch that rewrites `jobName` and `jobType` when
`releaseJobName` is present. Exercise stable-name stripping from `bqjr.JobName`,
the `payload-pr-` fallback when the PR prefix cannot be removed, skipping jobs
whose names start with `aggregator-`, and normalization of comma-separated
`releaseJobName` values. Add assertions around the resulting `prow.ProwJob`
fields produced by the `prowJobs` population logic so the identity and type
contract stays covered.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/dataloader/prowloader/bigqueryjobs.go`:
- Around line 139-156: The fallback path in bigqueryjobs.go uses the raw
releaseJobName annotation, which can include comma-delimited suffixes and lead
to incorrect canonical job names. Normalize releaseJobName the same way the
BigQuery query-generator does by trimming everything after the first comma
before building stableName or any downstream variant identifiers. Apply this in
the releaseJobName handling block near the stableName fallback so all consumers
see the normalized value.

---

Outside diff comments:
In `@pkg/dataloader/prowloader/prow.go`:
- Around line 1002-1035: The existing-job update path in the prow loader is
backfilling TestGridURL even for payload jobs, which breaks the payload-specific
suppression. Update the logic in the prow job import flow around
pl.generateTestGridURL and dbProwJob handling so TestGridURL is only populated
for non-payload jobs, both on insert and on subsequent updates, and leave empty
values untouched for payload imports.

---

Nitpick comments:
In `@pkg/dataloader/prowloader/bigqueryjobs.go`:
- Around line 132-176: Add regression tests for the payload sub-job
transformation in the bigquery job ingestion path, covering the branch that
rewrites `jobName` and `jobType` when `releaseJobName` is present. Exercise
stable-name stripping from `bqjr.JobName`, the `payload-pr-` fallback when the
PR prefix cannot be removed, skipping jobs whose names start with `aggregator-`,
and normalization of comma-separated `releaseJobName` values. Add assertions
around the resulting `prow.ProwJob` fields produced by the `prowJobs` population
logic so the identity and type contract stays covered.

In `@pkg/dataloader/prowloader/prow.go`:
- Around line 975-1020: Add regression tests around prow job persistence in the
prow loader to cover the new payload handling in identifyVariants and the
dbProwJob create/update path. Verify that when pj.Annotations["releaseJobName"]
is present and pj.Spec.Refs is non-nil, the variant name comes from
releaseJobName, any release variant is rewritten to Presubmits, and TestGridURL
is left empty; also cover the non-payload case where generateTestGridURL is
used. Include both the new ProwJob creation path and the existing cache/update
path in the prowJobCache logic so the behavior stays covered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: c6a2fb07-147f-4982-809e-c476b82a5c71

📥 Commits

Reviewing files that changed from the base of the PR and between c4d96fa and ce37c2e.

📒 Files selected for processing (2)
  • pkg/dataloader/prowloader/bigqueryjobs.go
  • pkg/dataloader/prowloader/prow.go

Comment thread pkg/dataloader/prowloader/bigqueryjobs.go
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/api/prtestresults.go (1)

42-124: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add test coverage for GetPRTestResults and PrintPRTestResultsJSON functions.

Per coding guidelines, new functionality requires unit tests. The PostgreSQL query in GetPRTestResults (lines 42–124) contains complex JOIN logic, conditional filtering, and date bounds that should be covered by tests. The HTTP handler PrintPRTestResultsJSON (lines 126–220) should also be tested. Add tests covering: default failure-only results, include_successes pattern matching, output joins, date boundary filtering, and invalid input handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/api/prtestresults.go` around lines 42 - 124, Add unit tests for
GetPRTestResults and PrintPRTestResultsJSON to cover the new query and handler
behavior. Focus on GetPRTestResults’s JOIN/filter logic by testing default
failure-only results, includeSuccesses pattern matching, output join population,
and start/end date boundary handling using the function name and its
query-building flow to locate the code. Also add handler tests for
PrintPRTestResultsJSON to verify valid responses and invalid input handling,
ensuring the JSON endpoint exercises the same PR test result path.

Source: Coding guidelines

🧹 Nitpick comments (1)
cmd/sippy/seed_data.go (1)

903-963: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use status constants and align the comments with the seeded tests.

The seed rows use raw status integers and two comments describe different tests than the TestID actually assigned. This makes the API fixture easy to misread.

Proposed cleanup
-		// Failure result for install test
+		// Seed an install failure so the default PR test-results view has data.
 		failResult := models.ProwJobRunTest{
@@
-			Status:              12,
+			Status:              int(v1.TestStatusFailure),
@@
-		// Success result for install test (same test, different run aspect)
+		// Seed a network success so include_successes exercises non-failure statuses.
 		successResult := models.ProwJobRunTest{
@@
-			Status:              1,
+			Status:              int(v1.TestStatusSuccess),
@@
-		// Flake result for network test on a different test
+		// Seed an install flake so include_successes exercises flakes.
 		flakeResult := models.ProwJobRunTest{
@@
-			Status:              13,
+			Status:              int(v1.TestStatusFlake),

As per coding guidelines, “Follow idiomatic Go practices” and keep comments minimal/helpful.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/sippy/seed_data.go` around lines 903 - 963, The seeded ProwJobRunTest
rows are hard to read because they use raw status integers and the comments
don’t match the actual TestID being set. Update the seeding logic to use the
existing status constants instead of literal values, and revise or remove the
comments so they accurately describe each result created via failResult,
successResult, and flakeResult with installTestID/networkTestID. Keep the
fixture idiomatic and minimal so the test data is self-explanatory.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/api/prtestresults.go`:
- Around line 81-85: Normalize and validate include_successes before
constructing the query in the prtestresults filtering logic, since the current
loop in the query builder can produce unrestricted LIKE matches. In the code
around the conditions assembly, trim out empty entries, enforce a reasonable
maximum count and per-item length, and escape SQL LIKE wildcard characters
before passing patterns into the Or("t.name LIKE ?", ...) clauses. Apply the
same hardening to the related include_successes handling referenced by the
second occurrence so the endpoint only accepts safe, bounded values.
- Around line 210-215: The error handling in the PR test results path is leaking
backend error details to clients. Update the error branch in the PR test results
handler to keep the detailed failure only in the `log.WithError(err).Error(...)`
call and return a generic HTTP 500 JSON body from `RespondWithJSON` without
embedding `err` in the `message` field.

---

Outside diff comments:
In `@pkg/api/prtestresults.go`:
- Around line 42-124: Add unit tests for GetPRTestResults and
PrintPRTestResultsJSON to cover the new query and handler behavior. Focus on
GetPRTestResults’s JOIN/filter logic by testing default failure-only results,
includeSuccesses pattern matching, output join population, and start/end date
boundary handling using the function name and its query-building flow to locate
the code. Also add handler tests for PrintPRTestResultsJSON to verify valid
responses and invalid input handling, ensuring the JSON endpoint exercises the
same PR test result path.

---

Nitpick comments:
In `@cmd/sippy/seed_data.go`:
- Around line 903-963: The seeded ProwJobRunTest rows are hard to read because
they use raw status integers and the comments don’t match the actual TestID
being set. Update the seeding logic to use the existing status constants instead
of literal values, and revise or remove the comments so they accurately describe
each result created via failResult, successResult, and flakeResult with
installTestID/networkTestID. Keep the fixture idiomatic and minimal so the test
data is self-explanatory.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: ad4774e2-3201-48f9-a252-0e2a78f221d5

📥 Commits

Reviewing files that changed from the base of the PR and between ce37c2e and cc2b47b.

📒 Files selected for processing (5)
  • cmd/sippy/seed_data.go
  • pkg/api/prtestresults.go
  • pkg/dataloader/prowloader/bigqueryjobs.go
  • pkg/dataloader/prowloader/prow.go
  • pkg/sippyserver/server.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/dataloader/prowloader/bigqueryjobs.go
  • pkg/dataloader/prowloader/prow.go

Comment thread pkg/api/prtestresults.go
Comment on lines +81 to +85
conditions := dbc.DB.Where("pjrt.status = ?", int(sippyprocessingv1.TestStatusFailure))
for _, pattern := range includeSuccesses {
conditions = conditions.Or("t.name LIKE ?", "%"+pattern+"%")
}
whereClause += `
)
)`
}
whereClause += `
)`

queryString := fmt.Sprintf(`
WITH deduped_testcases AS (
SELECT
junit.*,
ROW_NUMBER() OVER(PARTITION BY prowjob_build_id, file_path, test_name, testsuite ORDER BY
CASE
WHEN flake_count > 0 THEN 0
WHEN success_val > 0 THEN 1
ELSE 2
END) AS row_num,
CASE
WHEN flake_count > 0 THEN 0
ELSE success_val
END AS adjusted_success_val,
CASE
WHEN flake_count > 0 THEN 1
ELSE 0
END AS adjusted_flake_count
FROM
%s.%s AS junit
WHERE
junit.modified_time >= DATETIME(@StartDate)
AND junit.modified_time < DATETIME(@EndDate)
AND junit.skipped = false
)
SELECT
jobs.prowjob_build_id,
jobs.prowjob_job_name AS prowjob_name,
jobs.prowjob_url,
jobs.pr_sha,
jobs.prowjob_start,
deduped.test_name,
deduped.testsuite,
CASE
WHEN deduped.adjusted_flake_count > 0 THEN TRUE
ELSE FALSE
END AS flaked,
CASE
WHEN deduped.adjusted_flake_count > 0 THEN TRUE
WHEN deduped.adjusted_success_val > 0 THEN TRUE
ELSE FALSE
END AS success,
deduped.failure_content
FROM
%s.jobs AS jobs
INNER JOIN
deduped_testcases AS deduped
ON
jobs.prowjob_build_id = deduped.prowjob_build_id
AND deduped.row_num = 1
WHERE
jobs.org = @Org
AND jobs.repo = @Repo
AND jobs.pr_number = @PRNumber
AND jobs.prowjob_start >= DATETIME(@StartDate)
AND jobs.prowjob_start < DATETIME(@EndDate)%s
ORDER BY
jobs.prowjob_start DESC,
deduped.test_name ASC
`, bqc.Dataset, junitTable, bqc.Dataset, whereClause)

query := bqc.BQ.Query(queryString)
query.Parameters = []bigquery.QueryParameter{
{
Name: "Org",
Value: org,
},
{
Name: "Repo",
Value: repo,
},
{
Name: "PRNumber",
Value: strconv.Itoa(prNumber),
},
{
Name: "StartDate",
Value: startDate,
},
{
Name: "EndDate",
Value: endDate,
},
}

// Add parameters for includeSuccesses LIKE clauses
for i, testName := range includeSuccesses {
query.Parameters = append(query.Parameters, bigquery.QueryParameter{
Name: fmt.Sprintf("IncludeSuccess%d", i),
Value: "%" + testName + "%", // Wrap in % for SQL LIKE partial matching
query = query.Where(conditions)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Normalize include_successes before building LIKE clauses.

?include_successes= produces LIKE '%%', and % / _ values can intentionally match every test name. Since the endpoint no longer uses param.SafeRead for this list parameter, trim empty values, cap count/length, and escape LIKE wildcards before querying.

Proposed hardening
+func escapeLikePattern(pattern string) string {
+	replacer := strings.NewReplacer(`\`, `\\`, `%`, `\%`, `_`, `\_`)
+	return replacer.Replace(pattern)
+}
+
@@
 	} else {
 		conditions := dbc.DB.Where("pjrt.status = ?", int(sippyprocessingv1.TestStatusFailure))
 		for _, pattern := range includeSuccesses {
-			conditions = conditions.Or("t.name LIKE ?", "%"+pattern+"%")
+			conditions = conditions.Or("t.name LIKE ? ESCAPE '\\'", "%"+escapeLikePattern(pattern)+"%")
 		}
 		query = query.Where(conditions)
 	}
@@
-	includeSuccesses := req.URL.Query()["include_successes"]
+	includeSuccesses := make([]string, 0, len(req.URL.Query()["include_successes"]))
+	for _, pattern := range req.URL.Query()["include_successes"] {
+		pattern = strings.TrimSpace(pattern)
+		if pattern != "" {
+			includeSuccesses = append(includeSuccesses, pattern)
+		}
+	}

As per path instructions, “Validate at trust boundaries with allow-lists, not deny-lists.”

Also applies to: 207-209

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/api/prtestresults.go` around lines 81 - 85, Normalize and validate
include_successes before constructing the query in the prtestresults filtering
logic, since the current loop in the query builder can produce unrestricted LIKE
matches. In the code around the conditions assembly, trim out empty entries,
enforce a reasonable maximum count and per-item length, and escape SQL LIKE
wildcard characters before passing patterns into the Or("t.name LIKE ?", ...)
clauses. Apply the same hardening to the related include_successes handling
referenced by the second occurrence so the endpoint only accepts safe, bounded
values.

Source: Path instructions

Comment thread pkg/api/prtestresults.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
pkg/api/prtestresults.go (1)

208-213: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Keep backend error details out of 500 responses.

Line 212 still echoes the wrapped DB error to clients. Keep the detailed error in log.WithError(err) and return a generic message body.

Proposed fix
 		RespondWithJSON(http.StatusInternalServerError, w, map[string]any{
 			"code":    http.StatusInternalServerError,
-			"message": fmt.Sprintf("error fetching test results: %v", err),
+			"message": "error fetching test results",
 		})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/api/prtestresults.go` around lines 208 - 213, The PR test results error
path in the handler should not leak backend details in the HTTP 500 response
body. In the same block that logs with log.WithError(err) inside the PR test
results handler, change the RespondWithJSON payload to return a generic message
only, while keeping the full wrapped error detail in the log for debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/api/prtestresults.go`:
- Around line 165-193: The date range handling in prtestresults should validate
the normalized window before querying, since explicit start_date and end_date
can now create arbitrarily large ranges or an empty half-open interval after
end_date is made inclusive. In the request-handling logic around param.SafeRead,
the time.Parse blocks, and the prow_job_run_tests query setup, reintroduce the
previous/documented maximum span cap and reject requests where the normalized
endDate is not after startDate before continuing. Keep the existing inclusive
end-date behavior, but ensure the final normalized bounds are checked as a valid
allow-listed window before any query is executed.

---

Duplicate comments:
In `@pkg/api/prtestresults.go`:
- Around line 208-213: The PR test results error path in the handler should not
leak backend details in the HTTP 500 response body. In the same block that logs
with log.WithError(err) inside the PR test results handler, change the
RespondWithJSON payload to return a generic message only, while keeping the full
wrapped error detail in the log for debugging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 88ca46e1-07a1-41b0-b785-829de19913ab

📥 Commits

Reviewing files that changed from the base of the PR and between cc2b47b and 966df4b.

📒 Files selected for processing (2)
  • pkg/api/prtestresults.go
  • test/e2e/pull_requests_test.go

Comment thread pkg/api/prtestresults.go
@dgoodwin

dgoodwin commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

/test lint

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e

@dgoodwin

dgoodwin commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

/test e2e

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e

@mstaeble mstaeble left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an in-flight PR that's relevant here: #3679 (TRT-2734) adds a release_definitions table in PostgreSQL with a Capabilities field and constants like CapPullRequests. It provides the infrastructure to formally define what each release supports.

This PR introduces "Presubmits" as a pseudo-release with the name hardcoded throughout (prow loader routing, PG query filters, seed data, variant overrides). If both PRs land independently, "Presubmits" would exist in prow_jobs.release but not in release_definitions, which could cause issues as the server starts relying on release_definitions to enumerate releases or gate features.

A few things worth considering:

  1. "Presubmits" should probably get a ReleaseDefinition row (with CapPullRequests at minimum) so it's a first-class release rather than a magic string that only exists implicitly.
  2. The CapPullRequests constant in #3679 is currently unused. This endpoint would be a natural consumer for capability-based gating.
  3. The seed data here should eventually seed a "Presubmits" ReleaseDefinition alongside the presubmit jobs/runs.

Not necessarily something to solve in this PR, but wanted to flag the overlap so we can coordinate on how "Presubmits" gets defined as a release. Happy to discuss sequencing.

Comment thread cmd/sippy/seed_data.go Outdated
}
}

// Success result for install test (same test, different run aspect)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment accurate? Is says it is for the same install test, but the TestID used is "networkTestID".

Comment thread cmd/sippy/seed_data.go Outdated
ProwJobRunTimestamp: ri.run.Timestamp,
TestID: installTestID,
SuiteID: &suite.ID,
Status: 12,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread pkg/api/prtestresults.go Outdated
COALESCE(s.name, '') AS test_suite,
pjrt.status,
COALESCE(pjrto.output, '') AS output`).
Joins("JOIN prow_job_run_prow_pull_requests jrpr ON jrpr.prow_pull_request_id = pp.id").

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two performance concerns with this join:

Missing index: The primary key on prow_job_run_prow_pull_requests is (prow_job_run_id, prow_pull_request_id). Since prow_pull_request_id is the second column, PostgreSQL can't use the PK index for this jrpr.prow_pull_request_id = pp.id lookup and must sequentially scan the join table. This table grows by one row per job-run-to-PR association. A single-column index on prow_pull_request_id would fix this.

Missing release/timestamp filter on join table: Every other query in the codebase that uses this table filters on its denormalized prow_job_run_release and prow_job_run_timestamp columns (see pull_request_queries.go:32, repository_queries.go:30, functions.go:89-90). There's a composite index idx_prow_job_run_prow_pull_requests_release_timestamp specifically for this. Adding these conditions to the join would let the planner use it:

Joins("JOIN prow_job_run_prow_pull_requests jrpr ON
   jrpr.prow_pull_request_id = pp.id AND
   jrpr.prow_job_run_release = 'Presubmits' AND
   jrpr.prow_job_run_timestamp >= ? AND
   jrpr.prow_job_run_timestamp < ?",
  startDate, endDate)

Comment thread pkg/api/prtestresults.go
// Start from the PR side and use partition keys (release, timestamp) on
// prow_job_run_tests to allow PostgreSQL to prune partitions and avoid
// locking every partition in the table.
query := dbc.DB.Table("prow_pull_requests pp").

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using dbc.DB.Table(...) with a raw table name bypasses GORM's automatic WHERE deleted_at IS NULL injection. ProwPullRequest, ProwJobRun, and ProwJob all have soft-delete support, so soft-deleted records could leak into results. Other queries in the codebase (e.g., recent_test_failures.go:38-41) add explicit deleted_at IS NULL conditions on each table when using raw table names. Consider adding:

Where("pp.deleted_at IS NULL AND pjr.deleted_at IS NULL AND pj.deleted_at IS NULL")

Comment thread pkg/api/prtestresults.go
Joins("JOIN tests t ON t.id = pjrt.test_id").
Joins("LEFT JOIN suites s ON s.id = pjrt.suite_id").
Joins("LEFT JOIN prow_job_run_test_outputs pjrto ON pjrto.prow_job_run_test_id = pjrt.id AND pjrto.prow_job_run_test_timestamp = pjrt.prow_job_run_timestamp AND pjrto.prow_job_run_test_release = pjrt.prow_job_run_release").
Where("pp.org = ? AND pp.repo = ? AND pp.number = ?", org, repo, prNumber).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no index on prow_pull_requests(org, repo, number). The model only has a unique index on (sha, link). This filter is the primary selectivity driver for the entire query (a specific PR typically has 1-5 rows), but without an index PostgreSQL must sequentially scan the table. As the table grows with each unique (PR, SHA) combination, this will get progressively slower.

Consider adding a composite index to the model:

Org    string `json:"org" gorm:"index:idx_prow_pull_requests_org_repo_number"`
Repo   string `json:"repo" gorm:"index:idx_prow_pull_requests_org_repo_number"`
Number int    `json:"number" gorm:"index:idx_prow_pull_requests_org_repo_number"`

Comment thread pkg/api/prtestresults.go Outdated
query = query.Where(conditions)
}

query = query.Order("pjr.timestamp DESC, t.name ASC")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no result limit or pagination. The default date range is 14 days, and a PR tested many times with many tests could return thousands of rows. The old BigQuery version had a 30-day cap as a safeguard. Consider adding a configurable limit, or at minimum a reasonable ceiling to protect against unexpectedly large result sets.

Comment thread pkg/api/prtestresults.go Outdated
} else {
conditions := dbc.DB.Where("pjrt.status = ?", int(sippyprocessingv1.TestStatusFailure))
for _, pattern := range includeSuccesses {
conditions = conditions.Or("t.name LIKE ?", "%"+pattern+"%")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: the OR t.name LIKE '%pattern%' matches regardless of status, so it returns successes, flakes, and failures for matching test names. The old BigQuery version only included successes for matching names (explicitly excluded flakes via adjusted_flake_count = 0). The e2e test confirms this is intentional (statuses["success"]+statuses["flake"] > 0), but it's a behavior change worth noting in the PR description for anyone consuming this API.

dgoodwin and others added 12 commits July 13, 2026 14:45
…kfill

Normalize releaseJobName by stripping comma-delimited suffixes to match
the BigQuery query generator behavior. Also prevent the TestGridURL
update path from backfilling a URL on payload presubmit jobs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
start_date and end_date are now optional (default to last 14 days).
Added sha query param to filter results to a specific commit.
Updated e2e tests accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The sha param caused a server crash because it was not registered in the
param.SafeRead registry (which calls log.Fatal for unknown params).
Instead, use a latest_sha_only boolean param that filters results to
the SHA from the most recent prow job run, removing the burden from
the caller to know the exact SHA.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
#	pkg/api/job_runs.go
#	pkg/dataloader/prowloader/prow.go
The comment said "install test" but the code uses networkTestID.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace raw int status values (1, 12, 13) with the named constants
from sippyprocessingv1 (TestStatusSuccess, TestStatusFailure,
TestStatusFlake).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address review feedback:
- Add release/timestamp filters to the prow_job_run_prow_pull_requests
  join so PostgreSQL can use the composite index
  idx_prow_job_run_prow_pull_requests_release_timestamp.
- Add explicit deleted_at IS NULL conditions for soft-delete safety
  since raw table names bypass GORM's automatic injection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PR test results query filters primarily on org/repo/number but
had no supporting index, requiring a sequential scan as the table
grows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dgoodwin and others added 3 commits July 17, 2026 14:50
Default to 10000 rows max, configurable via a limit query parameter.
Prevents unexpectedly large result sets from PRs with many test runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous implementation returned all statuses (including flakes)
for test names matching include_successes patterns. The old BigQuery
version only included successes. Restrict the OR clause to
status=success for matching test names.

Also add an install success result to the presubmit seed data so the
e2e test can verify the behavior, and update the e2e assertion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dgoodwin
dgoodwin force-pushed the import-pr-payload-jobs branch from d5763a0 to 5662a6b Compare July 17, 2026 18:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pkg/variantregistry/ocp.go (1)

763-768: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Cover both -iso-no-registry classifications.

Add table cases asserting its capability, candidate tier, and metal platform; these separate ordered match tables can otherwise drift unnoticed.

As per coding guidelines, “New or modified functionality should include test coverage.”

Also applies to: 1139-1141

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/variantregistry/ocp.go` around lines 763 - 768, Extend the tests for the
component capability pattern tables to cover both `-iso-no-registry`
classifications, asserting the expected capability, `candidate` tier, and
`metal` platform for each ordered match table. Locate the relevant table-driven
tests near the existing `-iso-no-registry` entry and add cases for both
classifications.

Source: Coding guidelines

pkg/api/job_runs.go (1)

374-383: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Exclude Presubmits from the comparison baseline.

GetReleasesFromDB orders development_start_date DESC, where PostgreSQL places nulls first. Since the Presubmits definition has no development start date, ar[0] can be Presubmits, leaving the comparison release unchanged. Select the first non-presubmit release or query with NULLS LAST while excluding the pseudo-release.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/api/job_runs.go` around lines 374 - 383, Update the compareRelease
handling in the ReleasePresubmits branch to exclude the Presubmits
pseudo-release when selecting the baseline from GetReleasesFromDB. Choose the
first non-presubmit release, preserve the existing no-releases error when none
exists, and assign that release to compareRelease.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/sippy/seed_data.go`:
- Around line 969-1035: Update the seed data around the ProwJobRun creation and
join-table linking so PR 99001’s runs use competing SHAs: assign older runs an
older SHA and the newest run the current SHA, while preserving PR 99002’s
existing behavior. Ensure the seeded relationships support the latest_sha_only
e2e assertion that only the newest SHA is returned.

In `@pkg/dataloader/prowloader/prow.go`:
- Around line 687-701: Update the payload variant rewrite in the isPayload
branch after IdentifyVariants: parse each variant’s key:value form, compare the
value portion with pl.config.Releases, and preserve the key when replacing the
value. Rewrite matching entries as Release:Presubmits rather than a bare
Presubmits string.
- Around line 604-645: Add unit tests for matchRelease and isPayloadPresubmit
covering all annotation/refs combinations, including annotated jobs with and
without refs and unannotated jobs with and without refs. Verify payload
presubmits resolve to models.ReleasePresubmits only when that release is
enabled, and return no match when Presubmits is disabled.

In `@pkg/util/param/param.go`:
- Around line 79-80: Update the pull request test results limit handling in
SafeRead to use ReadUint with defaultPRTestResultsLimit, and propagate its
validation error so malformed, zero, or over-limit values return 400 instead of
being converted to empty or reset to 10,000.

---

Outside diff comments:
In `@pkg/api/job_runs.go`:
- Around line 374-383: Update the compareRelease handling in the
ReleasePresubmits branch to exclude the Presubmits pseudo-release when selecting
the baseline from GetReleasesFromDB. Choose the first non-presubmit release,
preserve the existing no-releases error when none exists, and assign that
release to compareRelease.

In `@pkg/variantregistry/ocp.go`:
- Around line 763-768: Extend the tests for the component capability pattern
tables to cover both `-iso-no-registry` classifications, asserting the expected
capability, `candidate` tier, and `metal` platform for each ordered match table.
Locate the relevant table-driven tests near the existing `-iso-no-registry`
entry and add cases for both classifications.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: e7de0aa6-5cfd-4160-bb34-595ff76243cc

📥 Commits

Reviewing files that changed from the base of the PR and between d5763a0 and 5662a6b.

📒 Files selected for processing (11)
  • cmd/sippy/seed_data.go
  • pkg/api/job_runs.go
  • pkg/api/prtestresults.go
  • pkg/dataloader/prowloader/bigqueryjobs.go
  • pkg/dataloader/prowloader/prow.go
  • pkg/db/models/prow.go
  • pkg/db/models/releases.go
  • pkg/sippyserver/server.go
  • pkg/util/param/param.go
  • pkg/variantregistry/ocp.go
  • test/e2e/pull_requests_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • pkg/dataloader/prowloader/bigqueryjobs.go
  • pkg/sippyserver/server.go
  • test/e2e/pull_requests_test.go
  • pkg/api/prtestresults.go

Comment thread cmd/sippy/seed_data.go
Comment on lines +969 to +1035
// Create ProwPullRequests
prs := []models.ProwPullRequest{
{
Org: "openshift",
Repo: "origin",
Number: 99001,
Author: "test-author-1",
Title: "Test PR 99001",
SHA: "abc123def456",
Link: "https://github.com/openshift/origin/pull/99001",
},
{
Org: "openshift",
Repo: "origin",
Number: 99002,
Author: "test-author-2",
Title: "Test PR 99002",
SHA: "789abc012def",
Link: "https://github.com/openshift/origin/pull/99002",
},
}

for i, pr := range prs {
if err := dbc.DB.Create(&pr).Error; err != nil {
return fmt.Errorf("failed to create ProwPullRequest %d: %w", pr.Number, err)
}
prs[i] = pr
}

// Create runs: 3 runs per job, PR 99001 gets job[0] runs, PR 99002 gets job[1] runs
type runInfo struct {
run models.ProwJobRun
prIdx int
}
var runs []runInfo

for jobIdx, pj := range presubmitJobs {
for i := 0; i < 3; i++ {
timestamp := now.Add(-time.Duration(3-i) * 20 * time.Hour)
run := models.ProwJobRun{
ProwJobID: pj.ID,
ProwJobRelease: models.ReleasePresubmits,
Cluster: "build01",
Timestamp: timestamp,
Duration: 2 * time.Hour,
OverallResult: v1.JobTestFailure,
Failed: true,
}
if err := dbc.DB.Create(&run).Error; err != nil {
return fmt.Errorf("failed to create ProwJobRun: %w", err)
}
runs = append(runs, runInfo{run: run, prIdx: jobIdx})
}
}

// Link runs to PRs via join table
for _, ri := range runs {
jrpr := models.ProwJobRunProwPullRequest{
ProwJobRunID: ri.run.ID,
ProwPullRequestID: prs[ri.prIdx].ID,
ProwJobRunRelease: models.ReleasePresubmits,
ProwJobRunTimestamp: ri.run.Timestamp,
}
if err := dbc.DB.Create(&jrpr).Error; err != nil {
return fmt.Errorf("failed to create ProwJobRunProwPullRequest: %w", err)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Seed competing SHAs for PR 99001.

Every run currently links to the same SHA, so the latest_sha_only e2e test passes even if that filter is a no-op. Link older runs to an older SHA and assert that only the newest SHA is returned.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/sippy/seed_data.go` around lines 969 - 1035, Update the seed data around
the ProwJobRun creation and join-table linking so PR 99001’s runs use competing
SHAs: assign older runs an older SHA and the newest run the current SHA, while
preserving PR 99002’s existing behavior. Ensure the seeded relationships support
the latest_sha_only e2e assertion that only the newest SHA is returned.

Comment on lines 604 to +645
@@ -628,6 +638,12 @@ func (pl *ProwLoader) matchRelease(jobName string) string {
return ""
}

// isPayloadPresubmit returns true if the prow job is a /payload sub-job.
func isPayloadPresubmit(pj *prow.ProwJob) bool {
_, hasAnnotation := pj.Annotations["releaseJobName"]
return hasAnnotation && pj.Spec.Refs != nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add unit coverage for payload-presubmit detection.

The endpoint e2e seed writes presubmit rows directly, so it does not exercise matchRelease or isPayloadPresubmit. Cover annotation/refs combinations and behavior when Presubmits is disabled.

As per coding guidelines, “New Go functions and methods need unit tests.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dataloader/prowloader/prow.go` around lines 604 - 645, Add unit tests for
matchRelease and isPayloadPresubmit covering all annotation/refs combinations,
including annotated jobs with and without refs and unannotated jobs with and
without refs. Verify payload presubmits resolve to models.ReleasePresubmits only
when that release is enabled, and return no match when Presubmits is disabled.

Source: Coding guidelines

Comment on lines +687 to +701
variantJobName := pj.Spec.Job
isPayload := isPayloadPresubmit(pj)
if isPayload {
variantJobName = pj.Annotations["releaseJobName"]
}

variants := pl.variantManager.IdentifyVariants(variantJobName)
if isPayload {
for vi, v := range variants {
if _, isRel := pl.config.Releases[v]; isRel {
variants[vi] = models.ReleasePresubmits
break
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve the serialized Release: variant key.

ProwJob.Variants entries use key:value form, but Line 696 compares the complete entry such as Release:4.22 against the config key 4.22; Line 697 would also replace it with bare Presubmits. Consequently, payload jobs retain the versioned release variant or receive a malformed one. Parse the entry and rewrite it as Release:Presubmits.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dataloader/prowloader/prow.go` around lines 687 - 701, Update the payload
variant rewrite in the isPayload branch after IdentifyVariants: parse each
variant’s key:value form, compare the value portion with pl.config.Releases, and
preserve the key when replacing the value. Rewrite matching entries as
Release:Presubmits rather than a bare Presubmits string.

Comment thread pkg/util/param/param.go
Comment on lines +79 to +80
// pull request test results params
"limit": uintRegexp,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Return 400 for invalid or excessive limits.

SafeRead silently converts malformed input to empty, while 0 or values above 10,000 are later reset to 10,000. Use ReadUint(req, "limit", defaultPRTestResultsLimit) and propagate its validation error instead of unexpectedly requesting the maximum result set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/util/param/param.go` around lines 79 - 80, Update the pull request test
results limit handling in SafeRead to use ReadUint with
defaultPRTestResultsLimit, and propagate its validation error so malformed,
zero, or over-limit values return 400 instead of being converted to empty or
reset to 10,000.

dgoodwin and others added 2 commits July 17, 2026 15:55
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PK is (prow_job_run_id, prow_pull_request_id) so PostgreSQL cannot
use it for lookups starting from the pull request side. Add a
single-column index so the PR test results query can efficiently join
from prow_pull_requests into the association table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e

@openshift-ci

openshift-ci Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

@dgoodwin: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants