Skip to content

Commit 5759d4c

Browse files
authored
envoy.ci.report(0.0.3): Improve schema and cleanups (#2348)
Signed-off-by: Ryan Northey <[email protected]>
1 parent 6f02f6c commit 5759d4c

File tree

10 files changed

+236
-114
lines changed

10 files changed

+236
-114
lines changed

envoy.ci.report/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.0.3-dev
1+
0.0.3

envoy.ci.report/envoy/ci/report/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ toolshed_library(
1414
"exceptions.py",
1515
"interface.py",
1616
"runner.py",
17+
"typing.py",
1718
"abstract/__init__.py",
1819
"abstract/filters.py",
1920
"abstract/format.py",

envoy.ci.report/envoy/ci/report/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
from . import abstract, exceptions, interface
2+
from . import abstract, exceptions, interface, typing
33
from .ci import CIRuns
44
from .runner import (
55
CreationTimeFilter, JSONFormat, MarkdownFormat,
@@ -18,4 +18,5 @@
1818
"main",
1919
"MarkdownFormat",
2020
"ReportRunner",
21-
"StatusFilter")
21+
"StatusFilter",
22+
"typing")
Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
import json
3+
import textwrap
34
from datetime import datetime
45

56
import abstracts
@@ -28,36 +29,49 @@ def out(self, data: dict) -> None:
2829
class AMarkdownFormat(AFormat):
2930

3031
def out(self, data: dict) -> None:
31-
for commit, events in data.items():
32-
self._handle_commit(commit, events)
33-
34-
def _handle_commit(self, commit: str, events: list[dict]) -> None:
35-
outcome = (
36-
"failed"
37-
if any(event["workflow"]["conclusion"] == "failure"
38-
for event
39-
in events)
40-
else "succeeded")
41-
target_branch = events[0]["request"]["target-branch"]
32+
for commit, info in data.items():
33+
self._handle_commit(commit, info)
34+
35+
def _handle_commit(self, commit: str, info: dict) -> None:
36+
target_branch = info["head"]["target_branch"]
4237
commit_url = f"https://github.com/envoyproxy/envoy/commit/{commit}"
43-
print(f"[{target_branch}@{commit[:7]}]({commit_url}): {outcome}")
44-
for event in events:
45-
self._handle_event(event)
38+
print(f"### [{target_branch}@{commit[:7]}]({commit_url})")
39+
self._handle_commit_message(info['head']['message'])
40+
for request_id, request in info["requests"].items():
41+
self._handle_event(request_id, request)
42+
43+
def _handle_commit_message(self, message):
44+
lines = message.splitlines()
45+
if len(lines) == 1:
46+
print(message)
47+
return
48+
summary = lines[0]
49+
details = textwrap.indent(
50+
"\n".join(lines[1:]),
51+
" ",
52+
lambda line: True)
53+
print("<details>")
54+
print(f" <summary>{summary}</summary>")
55+
print(" <blockquote>")
56+
print(details)
57+
print(" </blockquote>")
58+
print("</details>")
59+
print()
4660

47-
def _handle_event(self, event: dict) -> None:
48-
event_type = event["event"]
61+
def _handle_event(self, request_id, request) -> None:
62+
event_type = request["event"]
4963
request_started = datetime.utcfromtimestamp(
50-
int(event["request"]["started"])).isoformat()
51-
workflow_name = event["workflow"]["name"]
52-
conclusion = event["workflow"]["conclusion"]
53-
workflow_id = event["workflow_id"]
54-
request_id = event["request_id"]
55-
workflow_url = (
56-
"https://github.com/envoyproxy/envoy/"
57-
f"actions/runs/{workflow_id}")
64+
int(request["started"])).isoformat()
5865
request_url = (
5966
"https://github.com/envoyproxy/envoy/"
6067
f"actions/runs/{request_id}")
61-
print(
62-
f" -> [[{event_type}@{request_started}]({request_url})]: "
63-
f"[{workflow_name} ({conclusion})]({workflow_url})")
68+
print(f"#### [{event_type}@{request_started}]({request_url}):")
69+
for workflow_id, workflow in request["workflows"].items():
70+
workflow_url = (
71+
"https://github.com/envoyproxy/envoy/"
72+
f"actions/runs/{workflow_id}")
73+
print(
74+
f"- [{workflow['name']} "
75+
f"({workflow['conclusion']})]({workflow_url})")
76+
print()
77+
print("----")

envoy.ci.report/envoy/ci/report/abstract/runner.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
import pathlib
66
from functools import cached_property
7-
from typing import Callable, Type
7+
from typing import Callable
88

99
import aiohttp
1010

@@ -94,7 +94,7 @@ def runs(self) -> interface.ICIRuns:
9494

9595
@property
9696
@abstracts.interfacemethod
97-
def runs_class(self) -> Type[interface.ICIRuns]:
97+
def runs_class(self) -> type[interface.ICIRuns]:
9898
raise NotImplementedError
9999

100100
@cached_property

envoy.ci.report/envoy/ci/report/abstract/runs.py

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from aio.core.functional import async_property
1414
from aio.core.tasks import concurrent
1515

16-
from envoy.ci.report import exceptions
16+
from envoy.ci.report import exceptions, typing
1717

1818
URL_GH_REPO_ACTION_ENV_ARTIFACT = "actions/runs/{wfid}/artifacts?name=env"
1919
URL_GH_REPO_ACTIONS = "actions/runs?per_page=100"
@@ -41,7 +41,7 @@ def __init__(
4141
else sort_ascending)
4242

4343
@async_property
44-
async def as_dict(self) -> dict:
44+
async def as_dict(self) -> typing.CIRunsDict:
4545
return self._sorted(await self._to_dict())
4646

4747
@async_property(cache=True)
@@ -57,7 +57,7 @@ async def check_runs(self) -> dict:
5757
return result
5858

5959
@async_property(cache=True)
60-
async def envs(self) -> dict:
60+
async def envs(self) -> typing.CIRequestEnvsDict:
6161
artifacts: dict = {}
6262
async for result in concurrent(self._env_fetches):
6363
if not result:
@@ -214,40 +214,57 @@ async def _resolve_env_artifact_url(self, wfid: int) -> str | None:
214214
except IndexError:
215215
log.warning(f"Unable to find request artifact: {wfid}")
216216

217-
def _sorted(self, runs: dict) -> dict:
217+
def _sorted(self, runs: typing.CIRunsDict) -> typing.CIRunsDict:
218218
max_or_min = (
219219
min
220220
if self.sort_ascending
221221
else max)
222222
return dict(
223223
sorted(
224-
((k,
225-
sorted(
226-
v,
227-
key=lambda event: event["request"]["started"],
228-
reverse=not self.sort_ascending))
229-
for k, v in runs.items()),
224+
runs.items(),
230225
key=lambda item: max_or_min(
231-
x["request"]["started"]
232-
for x in item[1]),
226+
request["started"]
227+
for request
228+
in item[1]["requests"].values()),
233229
reverse=not self.sort_ascending))
234230

235-
async def _to_dict(self) -> dict:
236-
return {
237-
commit: requests
238-
for commit, request in (await self.workflow_requests).items()
239-
if (requests := await self._to_list_request(commit, request))}
231+
async def _to_dict(self) -> typing.CIRunsDict:
232+
wf_requests = await self.workflow_requests
233+
result: dict = {}
234+
for commit, _requests in wf_requests.items():
235+
requests = await self._to_list_request(commit, _requests)
236+
if not requests:
237+
continue
238+
result[commit] = {}
239+
result[commit]["head"] = dict(
240+
message=requests[0]["request"]["message"],
241+
target_branch=requests[0]["request"]["target-branch"])
242+
result[commit]["requests"] = {}
243+
for request in requests:
244+
result[commit]["requests"][request["request_id"]] = result[
245+
commit]["requests"].get(
246+
request["request_id"],
247+
dict(event=request["event"],
248+
started=request["request"]["started"],
249+
workflows={}))
250+
result[commit]["requests"][
251+
request["request_id"]]["workflows"][
252+
request["workflow_id"]] = request["workflow"]
253+
return result
240254

241255
async def _to_list_request(self, commit: str, request: dict) -> list[dict]:
242-
return [
243-
{"event": event,
244-
"request": (await self.envs)[commit][event][req]["request"],
245-
"request_id": req,
246-
"check_name": check_run["name"],
247-
"workflow_id": check_run["external_id"],
248-
"workflow": (await self.workflows)[int(check_run["external_id"])]}
249-
for event, requests in request.items()
250-
for check_run in (
251-
await self.check_runs).get(
252-
commit, {}).get(event, [])
253-
for req in requests]
256+
return sorted(
257+
[{"event": event,
258+
"request": (await self.envs)[commit][event][req]["request"],
259+
"request_id": req,
260+
"check_name": check_run["name"],
261+
"workflow_id": check_run["external_id"],
262+
"workflow": (await self.workflows)[
263+
int(check_run["external_id"])]}
264+
for event, requests in request.items()
265+
for check_run in (
266+
await self.check_runs).get(
267+
commit, {}).get(event, [])
268+
for req in requests],
269+
key=lambda item: item["request"]["started"],
270+
reverse=not self.sort_ascending)

envoy.ci.report/envoy/ci/report/cmd.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11

22
import sys
3-
from typing import Optional
43

54
from .runner import ReportRunner
65

76

8-
def main(*args: str) -> Optional[int]:
7+
def main(*args: str) -> int | None:
98
return ReportRunner(*args)()
109

1110

envoy.ci.report/envoy/ci/report/runner.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11

22
from functools import cached_property
3-
from typing import Type
43

54
import abstracts
65

@@ -29,7 +28,7 @@ class ReportRunner(abstract.AReportRunner):
2928
about Envoy's CI."""
3029

3130
@property
32-
def runs_class(self) -> Type[interface.ICIRuns]:
31+
def runs_class(self) -> type[interface.ICIRuns]:
3332
return ci.CIRuns
3433

3534
@cached_property
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
from typing import TypedDict
3+
4+
5+
class CIWorkflowDict(TypedDict):
6+
name: str
7+
status: str
8+
event: str
9+
conclusion: str
10+
11+
12+
class CICommitHeadDict(TypedDict):
13+
message: str
14+
target_branch: str
15+
16+
17+
class CIRequestDict(TypedDict):
18+
event: str
19+
started: float
20+
workflows: list[dict[str, CIWorkflowDict]]
21+
22+
23+
class CIRunsCommitDict(TypedDict):
24+
head: CICommitHeadDict
25+
requests: dict[int, CIRequestDict]
26+
27+
28+
class CIRequestWorkflowDict(TypedDict):
29+
checks: dict
30+
request: dict
31+
32+
33+
CIRunsDict = dict[str, CIRunsCommitDict]
34+
CIRequestWorkflowsDict = dict[int, list[CIRequestWorkflowDict]]
35+
CIRequestEventDict = dict[str, CIRequestWorkflowsDict]
36+
CIRequestEnvsDict = dict[str, CIRequestEventDict]

0 commit comments

Comments
 (0)