Coverage for jaypore_ci/reporters/markdown.py: 97%
46 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-30 09:04 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-30 09:04 +0000
1from jaypore_ci.interfaces import Reporter, Status
4def __node_mod__(nodes):
5 mod = 1
6 if len(nodes) > 5:
7 mod = 2
8 if len(nodes) > 10: 8 ↛ 9line 8 didn't jump to line 9, because the condition on line 8 was never true
9 mod = 3
10 return mod
13class Markdown(Reporter):
14 def __init__(self, *, graph_direction: str = "TD", **kwargs):
15 super().__init__(**kwargs)
16 self.graph_direction = graph_direction
18 def render(self, pipeline):
19 """
20 Returns a markdown report for a given pipeline.
22 It will include a mermaid graph and a collapsible list of logs for each
23 job.
24 """
25 return f"""
26<details>
27 <summary>JayporeCi: {pipeline.get_status_dot()} {pipeline.remote.sha[:10]}</summary>
29{self.__render_graph__(pipeline)}
31</details>"""
33 def __render_graph__(self, pipeline) -> str: # pylint: disable=too-many-locals
34 """
35 Render a mermaid graph given the jobs in the pipeline.
36 """
37 st_map = {
38 Status.PENDING: "pending",
39 Status.RUNNING: "running",
40 Status.FAILED: "failed",
41 Status.PASSED: "passed",
42 Status.TIMEOUT: "timeout",
43 Status.SKIPPED: "skipped",
44 }
45 mermaid = f"""
46```mermaid
47flowchart {self.graph_direction}
48"""
49 for stage in pipeline.stages:
50 nodes, edges = set(), set()
51 for job in pipeline.jobs.values():
52 if job.stage != stage:
53 continue
54 nodes.add(job.name)
55 edges |= {(p, job.name) for p in job.parents}
56 mermaid += f"""
57 subgraph {stage}
58 direction {self.graph_direction}
59 """
60 ref = {n: f"{stage}_{i}" for i, n in enumerate(nodes)}
61 # If there are too many nodes, scatter them with different length arrows
62 mod = __node_mod__([n for n in nodes if not pipeline.jobs[n].parents])
63 for i, n in enumerate(nodes):
64 n = pipeline.jobs[n]
65 if n.parents:
66 continue
67 arrow = "." * ((i % mod) + 1)
68 arrow = f"-{arrow}->"
69 mermaid += f"""
70 s_{stage}(( )) {arrow} {ref[n.name]}({n.name}):::{st_map[n.status]}"""
71 mod = __node_mod__([n for n in nodes if pipeline.jobs[n].parents])
72 for i, (a, b) in enumerate(edges):
73 a, b = pipeline.jobs[a], pipeline.jobs[b]
74 arrow = "." * ((i % mod) + 1)
75 arrow = f"-{arrow}->"
76 mermaid += "\n"
77 mermaid += (
78 " "
79 "{ref[a.name]}({a.name}):::{st_map[a.status]}"
80 "{arrow}"
81 "{ref[b.name]}({b.name}):::{st_map[b.status]}"
82 )
83 mermaid += """
84 end
85 """
86 for s1, s2 in zip(pipeline.stages, pipeline.stages[1:]):
87 mermaid += f"""
88 {s1} ---> {s2}
89 """
90 mermaid += """
92 classDef pending fill:#aaa, color:black, stroke:black,stroke-width:2px,stroke-dasharray: 5 5;
93 classDef skipped fill:#aaa, color:black, stroke:black,stroke-width:2px;
94 classDef assigned fill:#ddd, color:black, stroke:black,stroke-width:2px;
95 classDef running fill:#bae1ff,color:black,stroke:black,stroke-width:2px,stroke-dasharray: 5 5;
96 classDef passed fill:#88d8b0, color:black, stroke:black;
97 classDef failed fill:#ff6f69, color:black, stroke:black;
98 classDef timeout fill:#ffda9e, color:black, stroke:black;
99``` """
100 return mermaid