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

1from jaypore_ci.interfaces import Reporter, Status 

2 

3 

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 

11 

12 

13class Markdown(Reporter): 

14 def __init__(self, *, graph_direction: str = "TD", **kwargs): 

15 super().__init__(**kwargs) 

16 self.graph_direction = graph_direction 

17 

18 def render(self, pipeline): 

19 """ 

20 Returns a markdown report for a given pipeline. 

21 

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> 

28 

29{self.__render_graph__(pipeline)} 

30 

31</details>""" 

32 

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 += """ 

91 

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