Skip to content

Commit d1130ec

Browse files
committed
Update (base update)
[ghstack-poisoned]
1 parent a0a53db commit d1130ec

2 files changed

Lines changed: 232 additions & 184 deletions

File tree

aws/lambda/benchmark_regression_summary_report/common/config_model.py

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
import json
44
from dataclasses import dataclass, field
55
from datetime import timedelta
6-
from typing import Any, Dict, Literal, Optional
6+
from typing import Any, ClassVar, Dict, Literal, Optional
77

8+
import requests
89
from jinja2 import Environment, meta, Template
910

1011

@@ -35,6 +36,9 @@ def to_timedelta(self) -> timedelta:
3536
else:
3637
raise ValueError(f"Unsupported unit: {self.unit}")
3738

39+
def to_timedelta_s(self) -> int:
40+
return int(self.to_timedelta().total_seconds())
41+
3842
def get_text(self):
3943
return f"{self.value}_{self.unit}"
4044

@@ -96,12 +100,23 @@ class RangeConfig:
96100
def total_timedelta(self) -> timedelta:
97101
return timedelta(days=self.baseline.value + self.comparison.value)
98102

103+
def total_timedelta_s(self) -> int:
104+
return int(
105+
timedelta(days=self.baseline.value + self.comparison.value).total_seconds()
106+
)
107+
99108
def comparison_timedelta(self) -> timedelta:
100109
return timedelta(days=self.comparison.value)
101110

111+
def comparison_timedelta_s(self) -> int:
112+
return int(self.comparison_timedelta().total_seconds())
113+
102114
def baseline_timedelta(self) -> timedelta:
103115
return timedelta(days=self.baseline.value)
104116

117+
def baseline_timedelta_s(self) -> int:
118+
return int(self.baseline_timedelta().total_seconds())
119+
105120

106121
# -------- Policy: metrics --------
107122
@dataclass
@@ -121,9 +136,7 @@ class RegressionPolicy:
121136
"greater_than", "less_than", "equal_to", "greater_equal", "less_equal"
122137
]
123138
threshold: float
124-
baseline_aggregation: Literal[
125-
"avg", "max", "min", "p50", "p90", "p95", "latest", "earliest"
126-
] = "max"
139+
baseline_aggregation: Literal["max", "min", "latest", "earliest"] = "max"
127140
rel_tol: float = 1e-3 # used only for "equal_to"
128141

129142
def is_violation(self, value: float, baseline: float) -> bool:
@@ -154,13 +167,60 @@ def is_violation(self, value: float, baseline: float) -> bool:
154167

155168

156169
@dataclass
157-
class Policy:
158-
frequency: Frequency
159-
range: RangeConfig
160-
metrics: Dict[str, RegressionPolicy]
170+
class BaseNotificationConfig:
171+
# subclasses override this
172+
type_tag: ClassVar[str] = ""
173+
174+
@classmethod
175+
def matches(cls, d: Dict[str, Any]) -> bool:
176+
return d.get("type") == cls.type_tag
161177

162-
# TODO(elainewy): add notification config
163-
notification_config: Optional[Dict[str, Any]] = None
178+
179+
@dataclass
180+
class GitHubNotificationConfig(BaseNotificationConfig):
181+
type_tag: ClassVar[str] = "github"
182+
183+
# actual fields
184+
type: str = "github"
185+
repo: str = "" # e.g. "owner/repo"
186+
issue_number: str = "" # store as str for simplicity
187+
188+
@classmethod
189+
def from_dict(cls, d: Dict[str, Any]) -> "GitHubNotificationConfig":
190+
# support 'issue' alias
191+
issue = d.get("issue_number") or d.get("issue") or ""
192+
return cls(
193+
type="github",
194+
repo=d.get("repo", ""),
195+
issue_number=str(issue),
196+
)
197+
198+
def create_github_comment(self, body: str, github_token: str) -> Dict[str, Any]:
199+
url = f"https://api.github.com/repos/{self.repo}/issues/{self.issue_number}/comments"
200+
headers = {
201+
"Authorization": f"token {github_token}",
202+
"Accept": "application/vnd.github+json",
203+
"User-Agent": "bench-reporter/1.0",
204+
}
205+
resp = requests.post(url, headers=headers, json={"body": body})
206+
resp.raise_for_status()
207+
return resp.json()
208+
209+
210+
@dataclass
211+
class Policy:
212+
frequency: "Frequency"
213+
range: "RangeConfig"
214+
metrics: Dict[str, "RegressionPolicy"]
215+
216+
notification_config: Optional[dict[str, Any]] = None
217+
218+
def get_github_notification_config(self) -> Optional[GitHubNotificationConfig]:
219+
if not self.notification_config:
220+
return None
221+
if self.notification_config.get("type") != "github":
222+
return None
223+
return GitHubNotificationConfig.from_dict(self.notification_config)
164224

165225

166226
# -------- Top-level benchmark regression config --------

0 commit comments

Comments
 (0)