|
12 | 12 | get_regression_status,
|
13 | 13 | PerGroupResult,
|
14 | 14 | )
|
| 15 | +from jinja2 import Template |
15 | 16 |
|
16 | 17 |
|
17 | 18 | logger = logging.getLogger()
|
| 19 | +REPORT_MD_TEMPLATE = """# Benchmark Report {{ id }} |
| 20 | +config_id: `{{ report_id }}` |
| 21 | +
|
| 22 | +We have detected **{{ status }}** in benchmark results for `{{ report_id }}` (id: `{{ id }}`). |
| 23 | +(HUD benchmark regression page coming soon...) |
| 24 | +
|
| 25 | +> **Status:** {{ status }} · **Frequency:** {{ frequency }} |
| 26 | +
|
| 27 | +## Summary |
| 28 | +| Metric | Value | |
| 29 | +| :-- | --: | |
| 30 | +| Total | {{ summary.total_count | default(0) }} | |
| 31 | +| Regressions | {{ summary.regression_count | default(0) }} | |
| 32 | +| Suspicious | {{ summary.suspicious_count | default(0) }} | |
| 33 | +| No Regression | {{ summary.no_regression_count | default(0) }} | |
| 34 | +| Insufficient Data | {{ summary.insufficient_data_count | default(0) }} | |
| 35 | +
|
| 36 | +## Data Windows |
| 37 | +Baseline is a single reference value (e.g., mean, max, min, latest) aggregated from the previous few days, |
| 38 | +used to detect regressions by comparing against metric values in the target window. |
| 39 | +
|
| 40 | +### Baseline window (used to calculate baseline value) |
| 41 | +- **Start:** `{{ baseline.start.timestamp | default('') }}` (commit: `{{ baseline.start.commit | default('') }}`) |
| 42 | +- **End:** `{{ baseline.end.timestamp | default('') }}` (commit: `{{ baseline.end.commit | default('') }}`) |
| 43 | +
|
| 44 | +### Target window (used to compare against baseline value) |
| 45 | +- **Start:** `{{ target.start.timestamp | default('') }}` (commit: `{{ target.start.commit | default('') }}`) |
| 46 | +- **End:** `{{ target.end.timestamp | default('') }}` (commit: `{{ target.end.commit | default('') }}`) |
| 47 | +
|
| 48 | +{% if regression_items and regression_items|length > 0 %} |
| 49 | +## Regression Glance |
| 50 | +{% if url %} |
| 51 | +Use items below in [HUD]({{ url }}) to see regression. |
| 52 | +{% endif %} |
| 53 | +
|
| 54 | +{% set items = regression_items if regression_items|length <= 10 else regression_items[:10] %} |
| 55 | +{% if regression_items|length > 10 %} |
| 56 | +… (showing first 10 only, total {{ regression_items|length }} regressions) |
| 57 | +{% endif %} |
| 58 | +{% for item in items %} |
| 59 | +{% set kv = item.group_info|dictsort %} |
| 60 | +{{ "" }}|{% for k, _ in kv %}{{ k }} |{% endfor %}{{ "\n" -}} |
| 61 | +|{% for _k, _ in kv %}---|{% endfor %}{{ "\n" -}} |
| 62 | +|{% for _k, v in kv %}{{ v }} |{% endfor %}{{ "\n\n" -}} |
| 63 | +{% if item.baseline_point -%} |
| 64 | +- **startTime**: {{ item.baseline_point.timestamp }}, **endTime**: {{ target.end.timestamp }} |
| 65 | +- **lcommit**: `{{ item.baseline_point.commit }}`, **rcommit**: `{{ target.end.commit }}` |
| 66 | +{{ "\n" }} |
| 67 | +{%- endif %} |
| 68 | +{% endfor %} |
| 69 | +{% endif %} |
| 70 | +""" |
18 | 71 |
|
19 | 72 |
|
20 | 73 | class ReportManager:
|
@@ -68,6 +121,57 @@ def run(
|
68 | 121 | except Exception as e:
|
69 | 122 | logger.error(f"failed to insert report to db, error: {e}")
|
70 | 123 | raise
|
| 124 | + self.notify_github_comment(github_token) |
| 125 | + |
| 126 | + def notify_github_comment(self, github_token: str): |
| 127 | + if self.status != "regression": |
| 128 | + logger.info( |
| 129 | + "[%s] no regression found, skip notification", |
| 130 | + self.config_id, |
| 131 | + ) |
| 132 | + return |
| 133 | + |
| 134 | + github_notification = self.config.policy.get_github_notification_config() |
| 135 | + if not github_notification: |
| 136 | + logger.info( |
| 137 | + "[%s] no github notification config found, skip notification", |
| 138 | + self.config_id, |
| 139 | + ) |
| 140 | + return |
| 141 | + logger.info("[%s] prepareing gitub comment content", self.config_id) |
| 142 | + content = self._to_markdoown() |
| 143 | + if self.is_dry_run: |
| 144 | + logger.info( |
| 145 | + "[%s]dry run, skip sending comment to github, report(%s)", |
| 146 | + self.config_id, |
| 147 | + self.id, |
| 148 | + ) |
| 149 | + logger.info("[dry run] printing comment content") |
| 150 | + print(json.dumps(content, indent=2, default=str)) |
| 151 | + logger.info("[dry run] Done! Finish printing comment content") |
| 152 | + return |
| 153 | + logger.info("[%s] create comment to github issue", self.config_id) |
| 154 | + github_notification.create_github_comment(content, github_token) |
| 155 | + logger.info("[%s] done. comment is sent to github", self.config_id) |
| 156 | + |
| 157 | + def _to_markdoown(self): |
| 158 | + self.regression_items = self._collect_regression_items() |
| 159 | + url = "" |
| 160 | + if self.config.hud_info: |
| 161 | + url = self.config.hud_info.get("url", "") |
| 162 | + |
| 163 | + md = Template(REPORT_MD_TEMPLATE, trim_blocks=True, lstrip_blocks=True).render( |
| 164 | + id=self.id, |
| 165 | + url=url, |
| 166 | + status=self.status, |
| 167 | + report_id=self.config_id, |
| 168 | + summary=self.report["summary"], |
| 169 | + baseline=self.baseline, |
| 170 | + target=self.target, |
| 171 | + frequency=self.config.policy.frequency.get_text(), |
| 172 | + regression_items=self.regression_items, |
| 173 | + ) |
| 174 | + return md |
71 | 175 |
|
72 | 176 | def _collect_regression_items(self) -> list[PerGroupResult]:
|
73 | 177 | items = []
|
@@ -120,11 +224,30 @@ def insert_to_db(
|
120 | 224 | "repo": self.repo,
|
121 | 225 | "report_json": report_json,
|
122 | 226 | }
|
| 227 | + |
| 228 | + if self.is_dry_run: |
| 229 | + logger.info( |
| 230 | + "[%s]dry run, skip inserting report to db, report(%s)", |
| 231 | + self.config_id, |
| 232 | + self.id, |
| 233 | + ) |
| 234 | + logger.info("[dry run] printing db params data") |
| 235 | + if self.is_dry_run: |
| 236 | + print(json.dumps(params, indent=2, default=str)) |
| 237 | + logger.info("[dry run] Done! Finish printing db params data") |
| 238 | + return |
123 | 239 | logger.info(
|
124 | 240 | "[%s]inserting benchmark regression report(%s)", self.config_id, self.id
|
125 | 241 | )
|
126 |
| - self._db_insert(cc, self.db_table_name, params) |
127 |
| - |
| 242 | + try: |
| 243 | + self._db_insert(cc, self.db_table_name, params) |
| 244 | + except Exception: |
| 245 | + logger.exception( |
| 246 | + "[%s] failed to insert report to target table %s", |
| 247 | + self.config_id, |
| 248 | + self.db_table_name, |
| 249 | + ) |
| 250 | + raise |
128 | 251 | logger.info(
|
129 | 252 | "[%s] Done. inserted benchmark regression report(%s)",
|
130 | 253 | self.config_id,
|
|
0 commit comments