From 657e8c15b38cd2e1af6a18ff4f21e20cef6b4b9c Mon Sep 17 00:00:00 2001 From: jjaquish Date: Tue, 5 Mar 2024 08:19:29 -0500 Subject: [PATCH 1/8] Initial draft commit for importance widget component --- backend/ibutsu_server/constants.py | 36 ++++ .../controllers/widget_controller.py | 2 + backend/ibutsu_server/db/models.py | 7 + backend/ibutsu_server/db/util.py | 1 + .../widgets/importance_component.py | 177 ++++++++++++++++++ frontend/src/constants.js | 3 +- frontend/src/dashboard.js | 13 ++ frontend/src/widgets/importancecomponent.js | 123 ++++++++++++ frontend/src/widgets/index.js | 1 + 9 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 backend/ibutsu_server/widgets/importance_component.py create mode 100644 frontend/src/widgets/importancecomponent.js diff --git a/backend/ibutsu_server/constants.py b/backend/ibutsu_server/constants.py index 98438459..7c0bc0ae 100644 --- a/backend/ibutsu_server/constants.py +++ b/backend/ibutsu_server/constants.py @@ -229,6 +229,42 @@ ], "type": "widget", }, + "importance-component": { + "id": "importance-component", + "title": "Importance by component", + "description": "Test results filtered by component and broken down by importance", + "params": [ + { + "name": "job_name", + "description": "The name of the jenkins job to pull from", + "type": "string", + "required": True, + "default": "", + }, + { + "name": "group_field", + "description": "the field in a result to group by, typically 'component'", + "type": "string", + "required": True, + "default": "component", + }, + { + "name": "env", + "description": "The environment to filter by", + "type": "string", + "required": False, + "default": "", + }, + { + "name": "components", + "description": "The component(s) to filter by", + "type": "string", + "required": False, + "default": "", + }, + ], + "type": "widget", + }, "accessibility-dashboard-view": { "id": "accessibility-dashboard-view", "title": "Accessibility Dashboard View", diff --git a/backend/ibutsu_server/controllers/widget_controller.py b/backend/ibutsu_server/controllers/widget_controller.py index 49358216..0ef62184 100644 --- a/backend/ibutsu_server/controllers/widget_controller.py +++ b/backend/ibutsu_server/controllers/widget_controller.py @@ -6,6 +6,7 @@ from ibutsu_server.widgets.accessibility_dashboard_view import get_accessibility_dashboard_view from ibutsu_server.widgets.compare_runs_view import get_comparison_data from ibutsu_server.widgets.filter_heatmap import get_filter_heatmap +from ibutsu_server.widgets.importance_component import get_importance_component from ibutsu_server.widgets.jenkins_heatmap import get_jenkins_heatmap from ibutsu_server.widgets.jenkins_job_analysis import get_jenkins_analysis_data from ibutsu_server.widgets.jenkins_job_analysis import get_jenkins_bar_chart @@ -24,6 +25,7 @@ "jenkins-bar-chart": get_jenkins_bar_chart, "jenkins-heatmap": get_jenkins_heatmap, "filter-heatmap": get_filter_heatmap, + "importance-component": get_importance_component, "jenkins-job-view": get_jenkins_job_view, "jenkins-line-chart": get_jenkins_line_chart, "run-aggregator": get_recent_run_data, diff --git a/backend/ibutsu_server/db/models.py b/backend/ibutsu_server/db/models.py index bb08a0ed..14a803ad 100644 --- a/backend/ibutsu_server/db/models.py +++ b/backend/ibutsu_server/db/models.py @@ -244,6 +244,13 @@ def password(self, value): def check_password(self, plaintext): return bcrypt.check_password_hash(self.password, plaintext) + def set_password(self, value: str): + """ + The password setter breaks with an AttributeError, so this is a temporary work-around + until that can be resolved. + """ + self._password = bcrypt.generate_password_hash(value).decode("utf8") + def to_dict(self, with_projects=False): """An overridden method to include projects""" user_dict = super().to_dict() diff --git a/backend/ibutsu_server/db/util.py b/backend/ibutsu_server/db/util.py index 4d13b825..ee9e0b1c 100644 --- a/backend/ibutsu_server/db/util.py +++ b/backend/ibutsu_server/db/util.py @@ -61,6 +61,7 @@ def add_superadmin( ) user.password = password + user.set_password(password) session.add(user) session.commit() diff --git a/backend/ibutsu_server/widgets/importance_component.py b/backend/ibutsu_server/widgets/importance_component.py new file mode 100644 index 00000000..351501f8 --- /dev/null +++ b/backend/ibutsu_server/widgets/importance_component.py @@ -0,0 +1,177 @@ +#TODO: delete unneeded imports +# import yaml +from ibutsu_server.db.models import Run +from ibutsu_server.db.models import Result +from ibutsu_server.constants import BARCHART_MAX_BUILDS +# from ibutsu_server.constants import HEATMAP_MAX_BUILDS +from ibutsu_server.constants import JJV_RUN_LIMIT +from ibutsu_server.widgets.jenkins_job_view import get_jenkins_job_view +# from ibutsu_server.widgets.jenkins_job_view import get_jenkins_job_viewid +# from ibutsu_server.db.base import session +# from sqlalchemy import func +# from ibutsu_server.filters import apply_filters +from ibutsu_server.filters import string_to_column +# from ibutsu_server.db.base import Text + +#TODO: these were mocked methods, delete if unused +""" +def get_runs_from_job(job, additional_filters): + # Get a list of runs from the job, trim based on filters + # this can be imported/copied from the jenkins analysis view + pass + + +def get_results_from_runs(run_list): + # Get a list of results from a list of runs + # this can be specifially tailored to return one already + # sorted by component, can genericize later + pass +""" + + +def get_importance_component(env="prod", + group_field="component", + job_name="", + components=None, + project=None): + # tmp parameters + #TODO: decide if this should be an optional parameter or hard coded + builds = 5 + + # taken from get_jenkins_line_chart in jenkins_job_analysis.py + run_limit = int((JJV_RUN_LIMIT / BARCHART_MAX_BUILDS) * builds) + jobs = get_jenkins_job_view( + filter_=f"job_name={job_name}", + page_size=builds, + project=project, + run_limit=run_limit + ).get("jobs") + + # A list of job build numbers to filter our runs by + job_ids = [] + for job in jobs: + job_ids.append(job["build_number"]) + + # query for RUN ids + # metadata has to have a string to column to work + # because it is a sqlalchemy property otherwise (AFAIK) + bnumdat = string_to_column("metadata.jenkins.build_number", Run) + run_data = Run.query.filter( + bnumdat.in_(job_ids), + Run.component.in_(components.split(',')) + ).add_columns( + Run.id, + bnumdat.label("build_number") + ).all() + + # get a list of the job IDs + run_info = {} + for run in run_data: + run_info[run.id] = run.build_number + + mdat = string_to_column("metadata.importance", Result) + result_data = Result.query.filter( + Result.run_id.in_(run_info.keys()), + Result.component.in_( + components.split(','))).add_columns( + Result.run_id, + Result.component, + Result.id, + Result.result, + mdat.label("importance") + ).all() + + #TODO: remove this when no longer needed for reference + """ + sdatdict gonna look like + {"platfor_ui": + {"build451": + {"critical": + [results list], + "high": + [results list], + ... + }, + {"build452": + {"critical": + ... + } + }, + "rbac_frontend": + {... + } + } + """ + + """ + This starts a (probably) over complicated bit of data maniplation + to get sdatdict in a proper state to be broken down into + sdatret, which is the format we need for the widget. + """ + sdatdict = {} + bnums = set() + importances = ["critical", "high", "medium", "low"] + for datum in result_data: + # getting the components from the results + if datum.component not in sdatdict.keys(): + sdatdict[datum.component] = {} + + # getting the build numbers from the results + if run_info[datum.run_id] not in sdatdict[datum.component].keys(): + bnums.add(run_info[datum.run_id]) + sdatdict[datum.component][run_info[datum.run_id]] = {} + + # Adding all importances from our constant + if datum.importance not in sdatdict[datum.component][run_info[datum.run_id]].keys(): + sdatdict[datum.component][run_info[datum.run_id]][datum.importance] = [] + # adding the result value + sdatdict[datum.component][run_info[datum.run_id]][datum.importance].append({"result": datum.result, "result_id": datum.id}) + + # This adds the extra importance values that didn't appear in the results + for component in sdatdict.keys(): + for bnum in sdatdict[component].keys(): + for importance in importances: + if importance not in sdatdict[component][bnum].keys(): + sdatdict[component][bnum][importance] = [] + + # this is to change result values into numbers + #TODO: This doesn't handle xpassed, xfailed, skipped, etc. so figure that out + for component in sdatdict.keys(): + for bnum in sdatdict[component].keys(): + for importance in sdatdict[component][bnum].keys(): + total = 0 + passed = 0 + res_list = [] + for item in sdatdict[component][bnum][importance]: + total += 1 + res_list.append(item["result_id"]) + if item["result"] == "passed": + passed += 1 + + if total != 0: + sdatdict[component][bnum][importance] = {"percentage": round(passed / total, 2), "result_list": res_list} + else: + sdatdict[component][bnum][importance] = {"percentage": 0, "result_list": res_list} + + for bnum in bnums: + if bnum not in sdatdict[component].keys(): + sdatdict[component][bnum] = {} + for importance in importances: + sdatdict[component][bnum][importance] = {"percentage": "NA", "result_list": []} + + # Need this broken down more for the table + sdatret = [] + for key in sdatdict.keys(): + sdatret.append({"component": key, + "bnums": sorted(list(bnums)), + "importances": importances, + "data": sdatdict[key]}) + + # return data, for sanity + data = {"testa": group_field, + "testb": components, + "testc": project, + "sdatnew": sdatret, + #TODO: remove tmpdat here and in frontend, just used for troubleshooting + "tmpdat": sorted(["lol"])} + return data diff --git a/frontend/src/constants.js b/frontend/src/constants.js index 12505cca..4ce33470 100644 --- a/frontend/src/constants.js +++ b/frontend/src/constants.js @@ -9,7 +9,8 @@ export const KNOWN_WIDGETS = [ 'result-summary', 'result-aggregator', 'jenkins-bar-chart', - 'jenkins-line-chart' + 'jenkins-line-chart', + 'importance-component' ]; export const STRING_OPERATIONS = { 'eq': '=', diff --git a/frontend/src/dashboard.js b/frontend/src/dashboard.js index 72f6f21f..a3bdc4e6 100644 --- a/frontend/src/dashboard.js +++ b/frontend/src/dashboard.js @@ -35,6 +35,7 @@ import { GenericAreaWidget, GenericBarWidget, FilterHeatmapWidget, + ImportanceComponentWidget, ResultAggregatorWidget, ResultSummaryWidget } from './widgets'; @@ -411,6 +412,18 @@ export class Dashboard extends React.Component { onEditClick={() => this.onEditWidgetClick(widget.id)} /> } + {(widget.type === "widget" && widget.widget === "importance-component") && + this.onDeleteWidgetClick(widget.id)} + onEditClick={() => this.onEditWidgetClick(widget.id)} + /> + } ); } diff --git a/frontend/src/widgets/importancecomponent.js b/frontend/src/widgets/importancecomponent.js new file mode 100644 index 00000000..4deb434b --- /dev/null +++ b/frontend/src/widgets/importancecomponent.js @@ -0,0 +1,123 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { + Card, + CardBody, + Text +} from '@patternfly/react-core'; + +import { + Table, + Thead, + Th, + Tbody, + Tr, + Td +} from '@patternfly/react-table'; + +import { Link } from 'react-router-dom'; + +import { HttpClient } from '../services/http'; +import { Settings } from '../settings'; +import { WidgetHeader } from '../components/widget-components'; + +export class ImportanceComponentWidget extends React.Component { + static propTypes = { + title: PropTypes.string, + params: PropTypes.object, + onDeleteClick: PropTypes.func, + onEditClick: PropTypes.func + } + + constructor(props) { + super(props); + this.title = props.title || 'Importance Component Widget'; + this.params = props.params || {}; + this.state = { + data: { + testa: "", + testb: "", + testc: "", + sdatnew: [], + tmpdat: [] + }, + isLoading: true, + }; + } + + getData = () => { + this.setState({isLoading: true}) + HttpClient.get([Settings.serverUrl, 'widget', 'importance-component'], this.params) + .then(response => { + response = HttpClient.handleResponse(response, 'response'); + if (!response.ok) { + throw Error(response.statusText); + } + return response.json(); + }) + .then(data => this.setState({data: data, isLoading: false})) + .catch(error => { + this.setState({dataError: true}); + console.log(error); + }); + } + + componentDidMount() { + this.getData(); + } + + componentDidUpdate(prevProps) { + if (prevProps.params !== this.props.params) { + this.params = this.props.params; + this.getData(); + } + } + + render() { + + const Console = prop => (console[Object.keys(prop)[0]](...Object.values(prop)) + ,null // ➜ React components must return something + ) + return ( + + + + {(!this.state.dataError && this.state.isLoading) && + + Loading ... + + } + {(!this.state.dataError && !this.state.isLoading) && + + {this.state.data.sdatnew.map((sdat) => ( + <> + {sdat.component} + + + + {["-", ...sdat.bnums].map((bnum) => ( + + ))} + + + + {sdat.importances.map((importance) => ( + + {importance} + {sdat.bnums.map((bnum) => ( + + ))} + + ))} + +
{bnum}
{sdat.data[bnum][importance]["percentage"]}
+ + ))} + {/*{this.state.data.tmpdat}*/} +
+ } +
+ ); + } +} diff --git a/frontend/src/widgets/index.js b/frontend/src/widgets/index.js index d968b2c3..452db07a 100644 --- a/frontend/src/widgets/index.js +++ b/frontend/src/widgets/index.js @@ -3,3 +3,4 @@ export { GenericAreaWidget } from './genericarea'; export { GenericBarWidget } from './genericbar'; export { FilterHeatmapWidget } from './filterheatmap'; export { ResultAggregatorWidget } from './resultaggregator'; +export { ImportanceComponentWidget } from './importancecomponent'; From bbb292becba8342865bd37cb62ea99495a52b7db Mon Sep 17 00:00:00 2001 From: jjaquish Date: Mon, 11 Mar 2024 17:11:22 -0400 Subject: [PATCH 2/8] removed password setters --- backend/ibutsu_server/db/models.py | 7 ------- backend/ibutsu_server/db/util.py | 1 - 2 files changed, 8 deletions(-) diff --git a/backend/ibutsu_server/db/models.py b/backend/ibutsu_server/db/models.py index 14a803ad..bb08a0ed 100644 --- a/backend/ibutsu_server/db/models.py +++ b/backend/ibutsu_server/db/models.py @@ -244,13 +244,6 @@ def password(self, value): def check_password(self, plaintext): return bcrypt.check_password_hash(self.password, plaintext) - def set_password(self, value: str): - """ - The password setter breaks with an AttributeError, so this is a temporary work-around - until that can be resolved. - """ - self._password = bcrypt.generate_password_hash(value).decode("utf8") - def to_dict(self, with_projects=False): """An overridden method to include projects""" user_dict = super().to_dict() diff --git a/backend/ibutsu_server/db/util.py b/backend/ibutsu_server/db/util.py index ee9e0b1c..4d13b825 100644 --- a/backend/ibutsu_server/db/util.py +++ b/backend/ibutsu_server/db/util.py @@ -61,7 +61,6 @@ def add_superadmin( ) user.password = password - user.set_password(password) session.add(user) session.commit() From 34619a6ace6dcfc389c6523b49ddc006d16bf823 Mon Sep 17 00:00:00 2001 From: jjaquish Date: Mon, 11 Mar 2024 17:15:09 -0400 Subject: [PATCH 3/8] Cleaning up 1 --- backend/ibutsu_server/widgets/importance_component.py | 4 +--- frontend/src/widgets/importancecomponent.js | 9 +-------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/backend/ibutsu_server/widgets/importance_component.py b/backend/ibutsu_server/widgets/importance_component.py index 351501f8..78cba8df 100644 --- a/backend/ibutsu_server/widgets/importance_component.py +++ b/backend/ibutsu_server/widgets/importance_component.py @@ -171,7 +171,5 @@ def get_importance_component(env="prod", data = {"testa": group_field, "testb": components, "testc": project, - "sdatnew": sdatret, - #TODO: remove tmpdat here and in frontend, just used for troubleshooting - "tmpdat": sorted(["lol"])} + "sdatnew": sdatret} return data diff --git a/frontend/src/widgets/importancecomponent.js b/frontend/src/widgets/importancecomponent.js index 4deb434b..716057b5 100644 --- a/frontend/src/widgets/importancecomponent.js +++ b/frontend/src/widgets/importancecomponent.js @@ -39,8 +39,7 @@ export class ImportanceComponentWidget extends React.Component { testa: "", testb: "", testc: "", - sdatnew: [], - tmpdat: [] + sdatnew: [] }, isLoading: true, }; @@ -75,14 +74,9 @@ export class ImportanceComponentWidget extends React.Component { } render() { - - const Console = prop => (console[Object.keys(prop)[0]](...Object.values(prop)) - ,null // ➜ React components must return something - ) return ( - {(!this.state.dataError && this.state.isLoading) && Loading ... @@ -114,7 +108,6 @@ export class ImportanceComponentWidget extends React.Component { ))} - {/*{this.state.data.tmpdat}*/} } From 7b804230d177226b073b1bf5d7fa8dc83b4d212d Mon Sep 17 00:00:00 2001 From: jjaquish Date: Mon, 11 Mar 2024 17:27:17 -0400 Subject: [PATCH 4/8] cleaned up some more --- .../widgets/importance_component.py | 8 +++----- frontend/src/widgets/importancecomponent.js | 19 ++++++++----------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/backend/ibutsu_server/widgets/importance_component.py b/backend/ibutsu_server/widgets/importance_component.py index 78cba8df..5f7b04e1 100644 --- a/backend/ibutsu_server/widgets/importance_component.py +++ b/backend/ibutsu_server/widgets/importance_component.py @@ -161,15 +161,13 @@ def get_importance_component(env="prod", # Need this broken down more for the table sdatret = [] + table_data = [] for key in sdatdict.keys(): - sdatret.append({"component": key, + table_data.append({"component": key, "bnums": sorted(list(bnums)), "importances": importances, "data": sdatdict[key]}) # return data, for sanity - data = {"testa": group_field, - "testb": components, - "testc": project, - "sdatnew": sdatret} + data = {"table_data": table_data} return data diff --git a/frontend/src/widgets/importancecomponent.js b/frontend/src/widgets/importancecomponent.js index 716057b5..14c003ef 100644 --- a/frontend/src/widgets/importancecomponent.js +++ b/frontend/src/widgets/importancecomponent.js @@ -36,10 +36,7 @@ export class ImportanceComponentWidget extends React.Component { this.params = props.params || {}; this.state = { data: { - testa: "", - testb: "", - testc: "", - sdatnew: [] + table_data: [] }, isLoading: true, }; @@ -84,23 +81,23 @@ export class ImportanceComponentWidget extends React.Component { } {(!this.state.dataError && !this.state.isLoading) && - {this.state.data.sdatnew.map((sdat) => ( + {this.state.data.table_data.map((tdat) => ( <> - {sdat.component} + {tdat.component} - {["-", ...sdat.bnums].map((bnum) => ( - + {["-", ...tdat.bnums].map((buildnum) => ( + ))} - {sdat.importances.map((importance) => ( + {tdat.importances.map((importance) => ( {importance} - {sdat.bnums.map((bnum) => ( - + {tdat.bnums.map((buildnum) => ( + ))} ))} From 17e4931b23d227b3126f06982c4da782fcd18505 Mon Sep 17 00:00:00 2001 From: jjaquish Date: Tue, 12 Mar 2024 10:29:47 -0400 Subject: [PATCH 5/8] Cleaning up for linter --- backend/ibutsu_server/widgets/importance_component.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/ibutsu_server/widgets/importance_component.py b/backend/ibutsu_server/widgets/importance_component.py index 5f7b04e1..7053e6ba 100644 --- a/backend/ibutsu_server/widgets/importance_component.py +++ b/backend/ibutsu_server/widgets/importance_component.py @@ -160,7 +160,6 @@ def get_importance_component(env="prod", sdatdict[component][bnum][importance] = {"percentage": "NA", "result_list": []} # Need this broken down more for the table - sdatret = [] table_data = [] for key in sdatdict.keys(): table_data.append({"component": key, From c9eb15a4740e13c12636485989689946f8cb97b7 Mon Sep 17 00:00:00 2001 From: jjaquish Date: Wed, 13 Mar 2024 16:09:50 -0400 Subject: [PATCH 6/8] Cleaned up some more --- backend/ibutsu_server/constants.py | 7 + .../widgets/importance_component.py | 127 ++++++------------ frontend/src/widgets/importancecomponent.js | 4 +- 3 files changed, 50 insertions(+), 88 deletions(-) diff --git a/backend/ibutsu_server/constants.py b/backend/ibutsu_server/constants.py index 7c0bc0ae..655ce6f2 100644 --- a/backend/ibutsu_server/constants.py +++ b/backend/ibutsu_server/constants.py @@ -262,6 +262,13 @@ "required": False, "default": "", }, + { + "name": "builds", + "description": "The number of Jenkins builds to analyze.", + "type": "integer", + "default": 5, + "required": False, + }, ], "type": "widget", }, diff --git a/backend/ibutsu_server/widgets/importance_component.py b/backend/ibutsu_server/widgets/importance_component.py index 7053e6ba..5dc63be7 100644 --- a/backend/ibutsu_server/widgets/importance_component.py +++ b/backend/ibutsu_server/widgets/importance_component.py @@ -1,50 +1,18 @@ -#TODO: delete unneeded imports -# import yaml -from ibutsu_server.db.models import Run -from ibutsu_server.db.models import Result from ibutsu_server.constants import BARCHART_MAX_BUILDS -# from ibutsu_server.constants import HEATMAP_MAX_BUILDS from ibutsu_server.constants import JJV_RUN_LIMIT -from ibutsu_server.widgets.jenkins_job_view import get_jenkins_job_view -# from ibutsu_server.widgets.jenkins_job_view import get_jenkins_job_viewid -# from ibutsu_server.db.base import session -# from sqlalchemy import func -# from ibutsu_server.filters import apply_filters +from ibutsu_server.db.models import Result +from ibutsu_server.db.models import Run from ibutsu_server.filters import string_to_column -# from ibutsu_server.db.base import Text - -#TODO: these were mocked methods, delete if unused -""" -def get_runs_from_job(job, additional_filters): - # Get a list of runs from the job, trim based on filters - # this can be imported/copied from the jenkins analysis view - pass - - -def get_results_from_runs(run_list): - # Get a list of results from a list of runs - # this can be specifially tailored to return one already - # sorted by component, can genericize later - pass -""" - +from ibutsu_server.widgets.jenkins_job_view import get_jenkins_job_view -def get_importance_component(env="prod", - group_field="component", - job_name="", - components=None, - project=None): - # tmp parameters - #TODO: decide if this should be an optional parameter or hard coded - builds = 5 +def get_importance_component( + env="prod", group_field="component", job_name="", builds=5, components=None, project=None +): # taken from get_jenkins_line_chart in jenkins_job_analysis.py run_limit = int((JJV_RUN_LIMIT / BARCHART_MAX_BUILDS) * builds) jobs = get_jenkins_job_view( - filter_=f"job_name={job_name}", - page_size=builds, - project=project, - run_limit=run_limit + filter_=f"job_name={job_name}", page_size=builds, project=project, run_limit=run_limit ).get("jobs") # A list of job build numbers to filter our runs by @@ -56,13 +24,11 @@ def get_importance_component(env="prod", # metadata has to have a string to column to work # because it is a sqlalchemy property otherwise (AFAIK) bnumdat = string_to_column("metadata.jenkins.build_number", Run) - run_data = Run.query.filter( - bnumdat.in_(job_ids), - Run.component.in_(components.split(',')) - ).add_columns( - Run.id, - bnumdat.label("build_number") - ).all() + run_data = ( + Run.query.filter(bnumdat.in_(job_ids), Run.component.in_(components.split(","))) + .add_columns(Run.id, bnumdat.label("build_number")) + .all() + ) # get a list of the job IDs run_info = {} @@ -70,38 +36,15 @@ def get_importance_component(env="prod", run_info[run.id] = run.build_number mdat = string_to_column("metadata.importance", Result) - result_data = Result.query.filter( - Result.run_id.in_(run_info.keys()), - Result.component.in_( - components.split(','))).add_columns( - Result.run_id, - Result.component, - Result.id, - Result.result, - mdat.label("importance") - ).all() - - #TODO: remove this when no longer needed for reference - """ - sdatdict gonna look like - {"platfor_ui": - {"build451": - {"critical": - [results list], - "high": - [results list], - ... - }, - {"build452": - {"critical": - ... - } - }, - "rbac_frontend": - {... - } - } - """ + result_data = ( + Result.query.filter( + Result.run_id.in_(run_info.keys()), Result.component.in_(components.split(",")) + ) + .add_columns( + Result.run_id, Result.component, Result.id, Result.result, mdat.label("importance") + ) + .all() + ) """ This starts a (probably) over complicated bit of data maniplation @@ -125,7 +68,9 @@ def get_importance_component(env="prod", if datum.importance not in sdatdict[datum.component][run_info[datum.run_id]].keys(): sdatdict[datum.component][run_info[datum.run_id]][datum.importance] = [] # adding the result value - sdatdict[datum.component][run_info[datum.run_id]][datum.importance].append({"result": datum.result, "result_id": datum.id}) + sdatdict[datum.component][run_info[datum.run_id]][datum.importance].append( + {"result": datum.result, "result_id": datum.id} + ) # This adds the extra importance values that didn't appear in the results for component in sdatdict.keys(): @@ -135,7 +80,7 @@ def get_importance_component(env="prod", sdatdict[component][bnum][importance] = [] # this is to change result values into numbers - #TODO: This doesn't handle xpassed, xfailed, skipped, etc. so figure that out + # TODO: This doesn't handle xpassed, xfailed, skipped, etc. so figure that out for component in sdatdict.keys(): for bnum in sdatdict[component].keys(): for importance in sdatdict[component][bnum].keys(): @@ -149,9 +94,15 @@ def get_importance_component(env="prod", passed += 1 if total != 0: - sdatdict[component][bnum][importance] = {"percentage": round(passed / total, 2), "result_list": res_list} + sdatdict[component][bnum][importance] = { + "percentage": round(passed / total, 2), + "result_list": res_list, + } else: - sdatdict[component][bnum][importance] = {"percentage": 0, "result_list": res_list} + sdatdict[component][bnum][importance] = { + "percentage": 0, + "result_list": res_list, + } for bnum in bnums: if bnum not in sdatdict[component].keys(): @@ -162,10 +113,14 @@ def get_importance_component(env="prod", # Need this broken down more for the table table_data = [] for key in sdatdict.keys(): - table_data.append({"component": key, - "bnums": sorted(list(bnums)), - "importances": importances, - "data": sdatdict[key]}) + table_data.append( + { + "component": key, + "bnums": sorted(list(bnums)), + "importances": importances, + "data": sdatdict[key], + } + ) # return data, for sanity data = {"table_data": table_data} diff --git a/frontend/src/widgets/importancecomponent.js b/frontend/src/widgets/importancecomponent.js index 14c003ef..9289bacf 100644 --- a/frontend/src/widgets/importancecomponent.js +++ b/frontend/src/widgets/importancecomponent.js @@ -84,7 +84,7 @@ export class ImportanceComponentWidget extends React.Component { {this.state.data.table_data.map((tdat) => ( <> {tdat.component} -
{bnum}{buildnum}
{sdat.data[bnum][importance]["percentage"]}{tdat.data[buildnum][importance]["percentage"]}
+
{["-", ...tdat.bnums].map((buildnum) => ( @@ -98,7 +98,7 @@ export class ImportanceComponentWidget extends React.Component { {importance} {tdat.bnums.map((buildnum) => ( - ))} + ))} ))} From 295fee72806f48efd65b6084a92ebc420d27882d Mon Sep 17 00:00:00 2001 From: jjaquish Date: Tue, 19 Mar 2024 15:11:36 -0400 Subject: [PATCH 7/8] Set components default --- backend/ibutsu_server/widgets/importance_component.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ibutsu_server/widgets/importance_component.py b/backend/ibutsu_server/widgets/importance_component.py index 5dc63be7..6f7c03b3 100644 --- a/backend/ibutsu_server/widgets/importance_component.py +++ b/backend/ibutsu_server/widgets/importance_component.py @@ -7,7 +7,7 @@ def get_importance_component( - env="prod", group_field="component", job_name="", builds=5, components=None, project=None + env="prod", group_field="component", job_name="", builds=5, components="", project=None ): # taken from get_jenkins_line_chart in jenkins_job_analysis.py run_limit = int((JJV_RUN_LIMIT / BARCHART_MAX_BUILDS) * builds) From 8d17feaf5f8b62134026ba28f4801af2d5176b50 Mon Sep 17 00:00:00 2001 From: jjaquish Date: Tue, 2 Apr 2024 08:37:54 -0400 Subject: [PATCH 8/8] Made components required for importance by component --- backend/ibutsu_server/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ibutsu_server/constants.py b/backend/ibutsu_server/constants.py index 655ce6f2..a10d6e63 100644 --- a/backend/ibutsu_server/constants.py +++ b/backend/ibutsu_server/constants.py @@ -259,7 +259,7 @@ "name": "components", "description": "The component(s) to filter by", "type": "string", - "required": False, + "required": True, "default": "", }, {
{tdat.data[buildnum][importance]["percentage"]}