Coverage for src/pytribeam/cicd/report_dashboard.py: 96%

24 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2026-07-23 00:29 +0000

1#!/usr/bin/env python3 

2""" 

3Generates the root index.html Project Dashboard for GitHub Pages. 

4""" 

5 

6import argparse 

7import os 

8 

9from pytribeam.cicd.utilities import ( 

10 ReportMetadata, 

11 add_common_args, 

12 extend_timestamp, 

13 report_metadata_creation, 

14) 

15 

16 

17def generate_dashboard_html(metadata: ReportMetadata) -> str: 

18 """ 

19 Generate the HTML content for the Project Dashboard using a two-column layout. 

20 

21 Args: 

22 metadata: CI/CD metadata 

23 

24 Returns: 

25 HTML string 

26 """ 

27 timestamp_ext = extend_timestamp(metadata.timestamp) 

28 

29 # Pre-calculate GitHub URLs to stay under line length limits 

30 github_url = f"https://github.com/{metadata.github_repo}" 

31 run_url = f"{github_url}/actions/runs/{metadata.run_id}" 

32 branch_url = f"{github_url}/tree/{metadata.ref_name}" 

33 commit_url = f"{github_url}/commit/{metadata.github_sha}" 

34 

35 return f"""<!DOCTYPE html> 

36<html lang="en"> 

37<head> 

38 <meta charset="UTF-8"> 

39 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 

40 <title>pyTriBeam | Project Dashboard</title> 

41 <script src="https://cdn.tailwindcss.com"></script> 

42 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" 

43 rel="stylesheet"> 

44 <style> 

45 body {{ font-family: 'Inter', sans-serif; }} 

46 .hover-card:hover {{ transform: translateY(-2px); transition: all 0.2s ease; }} 

47 </style> 

48 </head> 

49 <body class="bg-[#DCDCDC] text-slate-800 antialiased min-h-screen"> 

50<nav class="bg-[#F5F5F5] border-b border-slate-200 sticky top-0 z-50"> 

51 <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex justify-between items-center"> 

52 <div class="flex items-center gap-2"> 

53 <span class="text-xl font-bold tracking-tight text-blue-600">pyTriBeam</span> 

54 </div> 

55 

56 <a href="{github_url}" 

57 class="text-sm font-medium hover:text-blue-600 transition">GitHub Repository</a> 

58 </div> 

59 </nav> 

60 

61 <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> 

62 <header class="mb-12 text-center"> 

63 <h1 class="text-4xl font-extrabold tracking-tight text-slate-900 mb-4"> 

64 <b>Project Dashboard</b></h1> 

65 <p class="text-lg text-slate-600 max-w-2xl mx-auto"> 

66 Documentation and quality reports for pyTriBeam. 

67 </p> 

68 </header> 

69 

70 <div class="grid grid-cols-1 md:grid-cols-2 gap-8"> 

71 

72 <section class="space-y-6"> 

73 <div class="flex items-center justify-between border-b-2 border-blue-200 pb-2"> 

74 <h2 class="text-2xl font-bold flex items-center gap-2"> 

75 🚀 Released 

76 </h2> 

77 <a href="{github_url}/tree/main" 

78 class="text-xs font-semibold bg-blue-100 text-blue-700 

79 px-2 py-1 rounded hover:bg-slate-300">main branch</a> 

80 </div> 

81 

82 <div class="space-y-4"> 

83 <a href="main/docs/userguide/book/index.html" 

84 class="hover-card block p-5 bg-[#F5F5F5] rounded-xl shadow-sm border 

85 border-slate-200 hover:border-blue-600 group"> 

86 <div class="flex justify-between items-start"> 

87 <div> 

88 <h3 class="font-bold text-lg group-hover:text-blue-600"> 

89 User's Manual</h3> 

90 <p class="text-sm text-slate-500 mt-1"> 

91 Stable documentation for end-users.</p> 

92 </div> 

93 <span class="text-xs font-bold uppercase tracking-wider 

94 bg-blue-100 text-blue-700 px-2 py-1 rounded"> 

95 Stable</span> 

96 </div> 

97 </a> 

98 

99 <a href="main/docs/api/index.html" 

100 class="hover-card block p-5 bg-[#F5F5F5] rounded-xl shadow-sm border 

101 border-slate-200 hover:border-blue-600 group"> 

102 <div class="flex justify-between items-start"> 

103 <div> 

104 <h3 class="font-bold text-lg group-hover:text-blue-600"> 

105 API Reference</h3> 

106 <p class="text-sm text-slate-500 mt-1"> 

107 Technical API documentation.</p> 

108 </div> 

109 <span class="text-xs font-bold uppercase tracking-wider 

110 bg-blue-100 text-blue-700 px-2 py-1 rounded"> 

111 Stable</span> 

112 </div> 

113 </a> 

114 

115 <div class="grid grid-cols-2 gap-4"> 

116 <a href="main/reports/lint/index.html" 

117 class="hover-card p-4 bg-[#F5F5F5] rounded-xl shadow-sm border 

118 border-slate-200 hover:border-blue-600"> 

119 <span class="block text-xs font-bold text-slate-400 

120 uppercase mb-2">Code Quality</span> 

121 <img src="main/badges/lint.svg" alt="Lint Score" class="h-5"> 

122 </a> 

123 <a href="main/reports/coverage/index.html" 

124 class="hover-card p-4 bg-[#F5F5F5] rounded-xl shadow-sm border 

125 border-slate-200 hover:border-blue-600"> 

126 <span class="block text-xs font-bold text-slate-400 

127 uppercase mb-2">Test Coverage</span> 

128 <img src="main/badges/coverage.svg" alt="Coverage" class="h-5"> 

129 </a> 

130 </div> 

131 </div> 

132 </section> 

133 

134 <section class="space-y-6"> 

135 <div class="flex items-center justify-between border-b-2 border-orange-200 pb-2"> 

136 <h2 class="text-2xl font-bold flex items-center gap-2"> 

137 🛠️ Development 

138 </h2> 

139 <a href="{github_url}/tree/dev" 

140 class="text-xs font-semibold bg-orange-100 text-orange-700 

141 px-2 py-1 rounded hover:bg-orange-200">dev branch</a> 

142 </div> 

143 

144 <div class="space-y-4"> 

145 <a href="dev/docs/userguide/book/index.html" 

146 class="hover-card block p-5 bg-[#F5F5F5] rounded-xl shadow-sm border 

147 border-slate-200 hover:border-orange-500 group"> 

148 <div class="flex justify-between items-start"> 

149 <div> 

150 <h3 class="font-bold text-lg group-hover:text-orange-600"> 

151 User's Manual</h3> 

152 <p class="text-sm text-slate-500 mt-1"> 

153 Development documentation.</p> 

154 </div> 

155 <span class="text-xs font-bold uppercase tracking-wider 

156 bg-orange-100 text-orange-700 px-2 py-1 rounded"> 

157 Latest</span> 

158 </div> 

159 </a> 

160 

161 <a href="dev/docs/api/index.html" 

162 class="hover-card block p-5 bg-[#F5F5F5] rounded-xl shadow-sm border 

163 border-slate-200 hover:border-orange-500 group"> 

164 <div class="flex justify-between items-start"> 

165 <div> 

166 <h3 class="font-bold text-lg group-hover:text-orange-600"> 

167 API Reference</h3> 

168 <p class="text-sm text-slate-500 mt-1"> 

169 Technical API documentation.</p> 

170 </div> 

171 <span class="text-xs font-bold uppercase tracking-wider 

172 bg-orange-100 text-orange-700 px-2 py-1 rounded"> 

173 Latest</span> 

174 </div> 

175 </a> 

176 

177 <div class="grid grid-cols-2 gap-4"> 

178 <a href="dev/reports/lint/index.html" 

179 class="hover-card p-4 bg-[#F5F5F5] rounded-xl shadow-sm border 

180 border-slate-200 hover:border-orange-500"> 

181 <span class="block text-xs font-bold text-slate-400 

182 uppercase mb-2">Code Quality</span> 

183 <img src="dev/badges/lint.svg" alt="Lint Score" class="h-5"> 

184 </a> 

185 <a href="dev/reports/coverage/index.html" 

186 class="hover-card p-4 bg-[#F5F5F5] rounded-xl shadow-sm border 

187 border-slate-200 hover:border-orange-500"> 

188 <span class="block text-xs font-bold text-slate-400 

189 uppercase mb-2">Test Coverage</span> 

190 <img src="dev/badges/coverage.svg" alt="Coverage" class="h-5"> 

191 </a> 

192 </div> 

193 </div> 

194 </section> 

195 

196 </div> 

197 

198 <section class="mt-16 bg-[#F5F5F5] p-8 rounded-xl shadow-sm border border-slate-200"> 

199 <h2 class="text-xl font-bold mb-4 border-b pb-2">Build Metadata</h2> 

200 <div class="flex flex-col gap-0 text-sm leading-tight text-slate-600"> 

201 <div> 

202 <span class="font-semibold">Generated:</span> {timestamp_ext} 

203 </div> 

204 <div> 

205 <span class="font-semibold">Run ID:</span> 

206 <a href="{run_url}" class="text-blue-600 hover:underline">{metadata.run_id}</a> 

207 </div> 

208 <div> 

209 <span class="font-semibold">Branch:</span> 

210 <a href="{branch_url}" class="text-blue-600 hover:underline">{metadata.ref_name}</a> 

211 </div> 

212 <div> 

213 <span class="font-semibold">Commit:</span> 

214 <a href="{commit_url}" class="text-blue-600 hover:underline">{metadata.github_sha[:7]}</a> 

215 </div> 

216 <div> 

217 <span class="font-semibold">Repository:</span> 

218 <a href="{github_url}" class="text-blue-600 hover:underline">{metadata.github_repo}</a> 

219 </div> 

220 </div> 

221 </section> 

222 </main> 

223 

224 <footer class="mt-20 py-10 border-t border-slate-200 bg-[#F5F5F5]"> 

225 <div class="max-w-7xl mx-auto px-4 text-center"> 

226 <p class="text-sm text-slate-400"> 

227 &copy; 2026 Sandia National Laboratories | Released under <a href="{github_url}/blob/main/LICENSE" class="text-blue-600 hover:underline">MIT License</a> 

228 </p> 

229 </div> 

230 </footer> 

231 

232</body> 

233</html>""" 

234 

235 

236def main(): 

237 """Main entry point.""" 

238 parser = argparse.ArgumentParser( 

239 description="Generate Project Dashboard index.html" 

240 ) 

241 parser.add_argument("--output_file", required=True, help="Output HTML file path") 

242 

243 add_common_args(parser) 

244 

245 args = parser.parse_args() 

246 

247 metadata = report_metadata_creation(args) 

248 

249 html = generate_dashboard_html(metadata) 

250 

251 output_dir = os.path.dirname(args.output_file) 

252 if output_dir: 252 ↛ 255line 252 didn't jump to line 255, because the condition on line 252 was always true

253 os.makedirs(output_dir, exist_ok=True) 

254 

255 with open(args.output_file, "w", encoding="utf-8") as f: 

256 f.write(html) 

257 

258 print(f"[OK] Project Dashboard generated: {args.output_file}") 

259 

260 

261if __name__ == "__main__": 

262 main()