-
Notifications
You must be signed in to change notification settings - Fork 131
TRT-2273: Show Regressions for Test Analysis #3775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
068156f
a992a14
f466df8
5bf82bd
53f4c81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,7 @@ var paramRegexp = map[string]*regexp.Regexp{ | |
| "job": nameRegexp, | ||
| "job_name": nameRegexp, | ||
| "test": regexp.MustCompile(`^.+$`), // tests can be anything, so always parameterize in sql | ||
| "test_name": regexp.MustCompile(`^.+$`), // test names can be anything, always parameterize in sql | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can't we use "test" here for this? how is that any different? what would "test" be if not a test name?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. Switched to using the existing |
||
| "test_id": regexp.MustCompile(`^[\w:. -]+$`), // test IDs like "openshift-tests-upgrade:af8a62c596e5c2b5448a5d308f4989a6" or "cluster install:0cb1bb27e418491b1ffdacab58c5c8c0" | ||
| "prow_job_run_id": uintRegexp, | ||
| "prow_job_run_ids": regexp.MustCompile(`^\d+(,\d+)*$`), // comma-separated integers | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,184 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||
| Chip, | ||||||||||||||||||||||||||||||||||||||||||||||||
| Paper, | ||||||||||||||||||||||||||||||||||||||||||||||||
| Table, | ||||||||||||||||||||||||||||||||||||||||||||||||
| TableBody, | ||||||||||||||||||||||||||||||||||||||||||||||||
| TableCell, | ||||||||||||||||||||||||||||||||||||||||||||||||
| TableContainer, | ||||||||||||||||||||||||||||||||||||||||||||||||
| TableHead, | ||||||||||||||||||||||||||||||||||||||||||||||||
| TableRow, | ||||||||||||||||||||||||||||||||||||||||||||||||
| Tooltip, | ||||||||||||||||||||||||||||||||||||||||||||||||
| Typography, | ||||||||||||||||||||||||||||||||||||||||||||||||
| } from '@mui/material' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { Link } from 'react-router-dom' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { relativeTime, safeEncodeURIComponent } from '../helpers' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import Alert from '@mui/material/Alert' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import PropTypes from 'prop-types' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import React, { useEffect, useMemo } from 'react' | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| export default function TestRegressionsTable({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| release, | ||||||||||||||||||||||||||||||||||||||||||||||||
| testName, | ||||||||||||||||||||||||||||||||||||||||||||||||
| filterModel, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const [isLoaded, setLoaded] = React.useState(false) | ||||||||||||||||||||||||||||||||||||||||||||||||
| const [regressions, setRegressions] = React.useState([]) | ||||||||||||||||||||||||||||||||||||||||||||||||
| const [fetchError, setFetchError] = React.useState('') | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!testName || !release) return | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const url = `${ | ||||||||||||||||||||||||||||||||||||||||||||||||
| process.env.REACT_APP_API_URL | ||||||||||||||||||||||||||||||||||||||||||||||||
| }/api/component_readiness/regressions?release=${safeEncodeURIComponent( | ||||||||||||||||||||||||||||||||||||||||||||||||
| release | ||||||||||||||||||||||||||||||||||||||||||||||||
| )}&test_name=${safeEncodeURIComponent(testName)}` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| fetch(url) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .then((res) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (res.status !== 200) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error('server returned ' + res.status) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| return res.json() | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .then((data) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| setRegressions(data || []) | ||||||||||||||||||||||||||||||||||||||||||||||||
| setLoaded(true) | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .catch((error) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| setFetchError('Could not retrieve regression data: ' + error) | ||||||||||||||||||||||||||||||||||||||||||||||||
| setLoaded(true) | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, [release, testName]) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const variantFilters = useMemo(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!filterModel || !filterModel.items) return [] | ||||||||||||||||||||||||||||||||||||||||||||||||
| return filterModel.items.filter((f) => f.columnField === 'variants') | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, [filterModel]) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const filteredRegressions = useMemo(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| let filtered = regressions.filter((r) => !r.closed || !r.closed.Valid) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (variantFilters.length === 0) return filtered | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return filtered.filter((regression) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const variantValues = (regression.variants || []).map((v) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const parts = v.split(':') | ||||||||||||||||||||||||||||||||||||||||||||||||
| return parts.length > 1 ? parts.slice(1).join(':') : v | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Use Both locations manually split variant strings to strip prefixes, which duplicates logic and violates path instructions. As per path instructions, when dealing with variant strings that may include a prefix, use
♻️ Proposed refactor for both sitesUpdate the import at the top of the file: -import { relativeTime, safeEncodeURIComponent } from '../helpers'
+import { relativeTime, safeEncodeURIComponent, parseVariantName } from '../helpers'Update the first site (lines 64-67): - const variantValues = (regression.variants || []).map((v) => {
- const parts = v.split(':')
- return parts.length > 1 ? parts.slice(1).join(':') : v
- })
+ const variantValues = (regression.variants || []).map(
+ (v) => parseVariantName(v).variant
+ )Update the second site (lines 104-108): - const variantValues = (regression.variants || [])
- .map((v) => {
- const parts = v.split(':')
- return parts.length > 1 ? parts.slice(1).join(':') : v
- })
+ const variantValues = (regression.variants || [])
+ .map((v) => parseVariantName(v).variant)📝 Committable suggestion
Suggested change
📍 Affects 1 file
🤖 Prompt for AI AgentsSource: Path instructions
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 53f4c81. Replaced manual string splitting with
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return variantFilters.every((filter) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const hasMatch = variantValues.some( | ||||||||||||||||||||||||||||||||||||||||||||||||
| (v) => v.toLowerCase() === filter.value.toLowerCase() | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (filter.not) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return !hasMatch | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| return hasMatch | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, [regressions, variantFilters]) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isLoaded) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return <p>Loading...</p> | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (fetchError !== '') { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return <Alert severity="error">{fetchError}</Alert> | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (filteredRegressions.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return <Typography>No active regressions found</Typography> | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableContainer component={Paper} style={{ marginTop: 20 }}> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <Table size="small" aria-label="regressions-table"> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableHead> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableRow> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell>ID</TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell>Variants</TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell>Regressed Since</TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell>Last Failure</TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell>Triage</TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| </TableRow> | ||||||||||||||||||||||||||||||||||||||||||||||||
| </TableHead> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableBody> | ||||||||||||||||||||||||||||||||||||||||||||||||
| {filteredRegressions.map((regression) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const variantValues = (regression.variants || []) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .map((v) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const parts = v.split(':') | ||||||||||||||||||||||||||||||||||||||||||||||||
| return parts.length > 1 ? parts.slice(1).join(':') : v | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .filter((val) => !['default', 'none', 'unknown'].includes(val)) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const tooltipLines = (regression.variants || []).sort().join('\n') | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const triaged = regression.triages && regression.triages.length > 0 | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableRow key={regression.id}> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <Link | ||||||||||||||||||||||||||||||||||||||||||||||||
| to={`/sippy-ng/component_readiness/regressions/${regression.id}`} | ||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||
| {regression.id} | ||||||||||||||||||||||||||||||||||||||||||||||||
| </Link> | ||||||||||||||||||||||||||||||||||||||||||||||||
| </TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <Tooltip | ||||||||||||||||||||||||||||||||||||||||||||||||
| title={ | ||||||||||||||||||||||||||||||||||||||||||||||||
| <span style={{ whiteSpace: 'pre-line' }}> | ||||||||||||||||||||||||||||||||||||||||||||||||
| {tooltipLines} | ||||||||||||||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||
| <span>{variantValues.join(', ')}</span> | ||||||||||||||||||||||||||||||||||||||||||||||||
| </Tooltip> | ||||||||||||||||||||||||||||||||||||||||||||||||
| </TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| {regression.opened | ||||||||||||||||||||||||||||||||||||||||||||||||
| ? relativeTime(new Date(regression.opened), new Date()) | ||||||||||||||||||||||||||||||||||||||||||||||||
| : ''} | ||||||||||||||||||||||||||||||||||||||||||||||||
| </TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| {regression.last_failure && regression.last_failure.Valid | ||||||||||||||||||||||||||||||||||||||||||||||||
| ? relativeTime( | ||||||||||||||||||||||||||||||||||||||||||||||||
| new Date(regression.last_failure.Time), | ||||||||||||||||||||||||||||||||||||||||||||||||
| new Date() | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||
| : ''} | ||||||||||||||||||||||||||||||||||||||||||||||||
| </TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
| {triaged ? ( | ||||||||||||||||||||||||||||||||||||||||||||||||
| regression.triages.map((t) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||
| <Chip | ||||||||||||||||||||||||||||||||||||||||||||||||
| key={t.id} | ||||||||||||||||||||||||||||||||||||||||||||||||
| label={ | ||||||||||||||||||||||||||||||||||||||||||||||||
| t.url ? t.url.split('/').pop() : `Triage #${t.id}` | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| component={Link} | ||||||||||||||||||||||||||||||||||||||||||||||||
| to={`/sippy-ng/component_readiness/triages/${t.id}`} | ||||||||||||||||||||||||||||||||||||||||||||||||
| clickable | ||||||||||||||||||||||||||||||||||||||||||||||||
| size="small" | ||||||||||||||||||||||||||||||||||||||||||||||||
| color="primary" | ||||||||||||||||||||||||||||||||||||||||||||||||
| variant="outlined" | ||||||||||||||||||||||||||||||||||||||||||||||||
| sx={{ marginRight: 0.5 }} | ||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||
| )) | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||||||||||||||
| <Chip label="Untriaged" size="small" color="warning" /> | ||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||
| </TableCell> | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Multiple Triages can exist for a single regression. I don't think we should surface triages here at all as it just makes things too complex.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. Removed the Triage column entirely from the table. |
||||||||||||||||||||||||||||||||||||||||||||||||
| </TableRow> | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||
| })} | ||||||||||||||||||||||||||||||||||||||||||||||||
| </TableBody> | ||||||||||||||||||||||||||||||||||||||||||||||||
| </Table> | ||||||||||||||||||||||||||||||||||||||||||||||||
| </TableContainer> | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| TestRegressionsTable.propTypes = { | ||||||||||||||||||||||||||||||||||||||||||||||||
| release: PropTypes.string.isRequired, | ||||||||||||||||||||||||||||||||||||||||||||||||
| testName: PropTypes.string.isRequired, | ||||||||||||||||||||||||||||||||||||||||||||||||
| filterModel: PropTypes.object, | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather not see this reused in this manner. We would be better off with a GetRegressionForTest function that was only (currently) used for this purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created a dedicated
GetRegressionsForTestfunction in bothtriage_queries.goandtriage.go, and revertedListRegressionsback to its original signature. The handler inserver.gonow dispatches toGetRegressionsForTestwhen thetestparameter is provided, and toListRegressionsotherwise.