PMM-15308 Trim whitespace from dashboard titles - #5767
Conversation
Panel and dashboard titles carried leading or trailing whitespace in 14 dashboards (39 titles), including the reported "InnoDB Buffer Pool Data " in MySQL_InnoDB_Details. Nothing validated titles: the dashboards.yml check job already runs cleanup-dash.py --check-only, but its CLEANUPERS list only normalised editable/time/timezone/refresh/id, so untrimmed titles always passed. Add a trim_titles cleanuper and report title differences in --check-only so that gate catches regressions. The reporter hardcodes per-field comparisons, so without the new title case CI would exit 1 without printing a reason. Titles are trimmed in place rather than by running cleanup-dash.py in write mode, which re-serialises with sort_keys/indent=4 and would reformat 6 unrelated dashboards wholesale. Also add stdlib unittest coverage for the script and wire it into the check job. Signed-off-by: theTibi <tkorocz@gmail.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5767 +/- ##
==========================================
+ Coverage 43.59% 45.69% +2.10%
==========================================
Files 415 547 +132
Lines 43134 46048 +2914
Branches 0 581 +581
==========================================
+ Hits 18804 21042 +2238
- Misses 22454 22953 +499
- Partials 1876 2053 +177 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (1)
🔗 Linked repositories identifiedCodeRabbit considers these linked repositories for cross-repo context during reviews:
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review. WalkthroughThe cleanup script now recursively trims dashboard titles and reports title changes. Dashboard JSON titles were normalized. Unit, CLI, repository, and workflow checks validate the cleanup behavior. CI also detects workflow and tooling changes before running the whole-tree test suite. Contributor guidance documents the required test command, and Python cache files are ignored. Merge Risk: ⚪ Minimal · up to Dashboard titles are normalized and the cleanup tooling adds checks to prevent future whitespace regressions. No current merge-blocking risk is identified. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Full details: Description checkExplanation The description includes the ticket number, feature build, detailed summary, related work, and a complete test plan. The API documentation checkbox is not required because this PR does not alter API endpoints. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
mattiasimonato
left a comment
There was a problem hiding this comment.
One comment below on the repo-wide test. Not blocking, but I'd like it sorted before merge.
Review follow-up. The repo-wide test in test_cleanup_dash.py gated every PR touching dashboards/** on the state of all 76 dashboards, and reported a failure as a bare list of paths with no reason and no remediation. - dashboards.yml runs the cleanup-script suite only when the PR changes a dashboard JSON, cleanup-dash.py or its tests, or this workflow itself, so a pmm-app or lockfile change is no longer gated on the whole tree. It runs after the per-dashboard check, so a whole-tree failure cannot hide the step summary and file annotations for the PR's own dashboards. - The whole-tree test keeps the tool's own per-file report and splits the three failure kinds, each with its own remedy: needs cleanup (with the cleanuper command and its reformatting caveat), exited without naming a field, and could not be checked at all. Capped at 10 per bucket. - The changed-files step no longer swallows a failed git diff (|| true returned sort's status) and fails on an empty diff instead of reporting success with no dashboard checked. - Parse errors in the in-process whole-tree tests now name the file. - AGENTS.md and dashboards/dashboards/AGENTS.md document the suite command and the whole-tree caveat. Signed-off-by: theTibi <tkorocz@gmail.com>
Ticket number: PMM-15308
Feature build: Percona-Lab/pmm-submodules#4525
Summary
"InnoDB Buffer Pool Data ", plus 38 more across 14 dashboards (e.g.Nodes_Overview.jsonhas 8 leading-space titles like" Top Disk Latency").Dashboards → Checkjob already runscleanup-dash.py --check-only, but itsCLEANUPERSlist only normalisededitable/time/timezone/refresh/id, so untrimmed titles always passed.trim_titlescleanuper so the existing CI gate catches regressions — the trim-on-publish the reporter asked for.Notes for reviewers
1. The
--check-onlyreporter needed atitle:case too. It hardcodes per-field comparisons, so addingtrim_titlesalone would have made CI exit 1 while printing no reason.walk_titlesis shared by the cleanuper and the reporter so the two cannot drift.2. Titles were trimmed in place, not via
cleanup-dash.pywrite mode.--check-onlycompares parsed objects, while write mode re-serialises withsort_keys/indent=4. Running it over the tree would reformat 6 unrelated dashboards wholesale (~26k lines of indentation churn):MongoDB_Cluster_Summary,MongoDB_Collections_Overview,MongoDB_ReplSet_Summary,PMM_Health,PostgreSQL_Instance_Summary,PostgreSQL_Top_Queries. That drift is pre-existing and left alone here — worth its own ticket, since the CI error message points devs at exactly that command.3. One behaviour-visible change.
MySQL_User_Details.jsonpanels[0]is atextspacer whose title is literally" "; it becomes"". Confirmed as intended.4. First Python tests in the repo.
test_cleanup_dash.pyis stdlibunittest— no new dependency. Happy to drop it and the CI step if you'd rather not set the precedent.5. The whole-tree gate, and how it is scoped.
TestRepoDashboardsruns--check-onlyover all 76 dashboards, so a dirty dashboard fails the job no matter which file the PR touched. That breadth is deliberate — it is what forces a whole-tree fix when a cleanuper is added, exactly as this PR had to do — but the workflow triggers onpaths: dashboards/**, so left unscoped it would gate unrelated PRs (apmm-appchange, ayarn.lockbump) on every dashboard in the tree. TheTest the cleanup scriptstep therefore runs only when the PR changes a dashboard JSON file,cleanup-dash.py/test_cleanup_dash.py, ordashboards.ymlitself — whoever edits the gate should see it run, and that is the one place the widened scope is deliberate. It runs after the per-dashboard check so a whole-tree failure never hides the step summary and::error file=annotations for the PR's own dashboards. On failure it prints the tool's own per-file report — every dirty field as"raw" -> "cleaned"— and sorts failures into three buckets with different remedies: needs cleanup (run the cleanuper), failed without naming a field (a cleanuper has no case in the--check-onlyreporter; write mode still fixes the file), and could not be checked at all (the tool crashed; the cleanuper hits the same error). Each bucket is capped at 10 entries so a systemic fault does not bury the explanation. The trigger matches anydashboards/misc/test_*.py, so a PR adding a test module actually runs it.AGENTS.mdanddashboards/dashboards/AGENTS.mddocument the new command.6. Drive-by: the
checkjob was fail-open.git diff … | sort -u > changed_dashboards.txt || truereturnssort's exit status, so an unresolvable base SHA yielded an empty file and the job reported success with no dashboard checked at all. It now fails with an annotation. Pre-existing, fixed here because note 5 doubled the blast radius (two skipped checks instead of one). The workflow also now triggers on changes to itself — before this, a PR fixing onlydashboards.ymlmerged without ever running it.Test plan
cleanup-dash.py --check-onlyfails on exactly 14 dashboards before the trim, passes on all 76 after"title":ubuntu:24.04/ Python 3.12.3 container (mirrors CI runner), no pip installs; also green on Python 3.9.6 / 3.13.7 / 3.14.3, so the suite is not tied to the runner's minor versiontime, malformed JSON, non-dict root), cleanuper with no reporter case incl. unrelated stderr noise, missing dashboard tree, mixed dirty+broken, and the printed remediation command actually runs and makes the gate pass: 19/19 assertions, plus a second harness of 24 covering the three-bucket split, exit-code reporting, output capping and per-field reporter coverage (positive and negative probes)checkjob's changed-files step executed verbatim against a real / bogus / empty base SHA → 0 / 1 / 1, each failure carrying a::error::annotation; thetoolingoutput resolves to 1 for a dashboard /cleanup-dash.py/test_*.py/dashboards.ymlchange and 0 for apmm-app-only or lockfile-only changeplugin.json's 68 dashboard paths all resolveRelated
cleanup-dash.py <file>is safe to run as CI suggests.