@@ -9,6 +9,9 @@ namespace CodeCoverageSummary
9
9
{
10
10
internal static class Program
11
11
{
12
+ private static double lowerThreshold = 0.5 ;
13
+ private static double upperThreshold = 0.75 ;
14
+
12
15
private static int Main ( string [ ] args )
13
16
{
14
17
return Parser . Default . ParseArguments < CommandLineOptions > ( args )
@@ -32,6 +35,10 @@ private static int Main(string[] args)
32
35
}
33
36
else
34
37
{
38
+ // set health badge thresholds
39
+ if ( ! string . IsNullOrWhiteSpace ( o . Thresholds ) )
40
+ SetThresholds ( o . Thresholds ) ;
41
+
35
42
// generate badge
36
43
string badgeUrl = o . Badge ? GenerateBadge ( summary ) : null ;
37
44
@@ -41,12 +48,16 @@ private static int Main(string[] args)
41
48
if ( o . Format . Equals ( "text" , StringComparison . OrdinalIgnoreCase ) )
42
49
{
43
50
fileExt = "txt" ;
44
- output = GenerateTextOutput ( summary , badgeUrl ) ;
51
+ output = GenerateTextOutput ( summary , badgeUrl , o . Indicators ) ;
52
+ if ( o . FailBelowThreshold )
53
+ output += $ "Minimum allowed line rate is { lowerThreshold * 100 : N0} %{ Environment . NewLine } ";
45
54
}
46
55
else if ( o . Format . Equals ( "md" , StringComparison . OrdinalIgnoreCase ) || o . Format . Equals ( "markdown" , StringComparison . OrdinalIgnoreCase ) )
47
56
{
48
57
fileExt = "md" ;
49
- output = GenerateMarkdownOutput ( summary , badgeUrl ) ;
58
+ output = GenerateMarkdownOutput ( summary , badgeUrl , o . Indicators ) ;
59
+ if ( o . FailBelowThreshold )
60
+ output += $ "{ Environment . NewLine } _Minimum allowed line rate is `{ lowerThreshold * 100 : N0} %`_{ Environment . NewLine } ";
50
61
}
51
62
else
52
63
{
@@ -74,6 +85,12 @@ private static int Main(string[] args)
74
85
return - 2 ; // error
75
86
}
76
87
88
+ if ( o . FailBelowThreshold && summary . LineRate < lowerThreshold )
89
+ {
90
+ Console . WriteLine ( $ "FAIL: Overall line rate below minimum threshold of { lowerThreshold * 100 : N0} %.") ;
91
+ return - 2 ;
92
+ }
93
+
77
94
return 0 ; // success
78
95
}
79
96
}
@@ -158,14 +175,49 @@ private static CodeSummary ParseTestResults(string filename)
158
175
}
159
176
}
160
177
178
+ private static void SetThresholds ( string thresholds )
179
+ {
180
+ int lowerPercentage ;
181
+ int upperPercentage = ( int ) ( upperThreshold * 100 ) ;
182
+ int s = thresholds . IndexOf ( " " ) ;
183
+ if ( s == 0 )
184
+ {
185
+ throw new ArgumentException ( "Threshold parameter set incorrectly." ) ;
186
+ }
187
+ else if ( s < 0 )
188
+ {
189
+ if ( ! int . TryParse ( thresholds , out lowerPercentage ) )
190
+ throw new ArgumentException ( "Threshold parameter set incorrectly." ) ;
191
+ }
192
+ else
193
+ {
194
+ if ( ! int . TryParse ( thresholds . Substring ( 0 , s ) , out lowerPercentage ) )
195
+ throw new ArgumentException ( "Threshold parameter set incorrectly." ) ;
196
+
197
+ if ( ! int . TryParse ( thresholds . Substring ( s + 1 ) , out upperPercentage ) )
198
+ throw new ArgumentException ( "Threshold parameter set incorrectly." ) ;
199
+ }
200
+ lowerThreshold = lowerPercentage / 100.0 ;
201
+ upperThreshold = upperPercentage / 100.0 ;
202
+
203
+ if ( lowerThreshold > 1.0 )
204
+ lowerThreshold = 1.0 ;
205
+
206
+ if ( lowerThreshold > upperThreshold )
207
+ upperThreshold = lowerThreshold + 0.1 ;
208
+
209
+ if ( upperThreshold > 1.0 )
210
+ upperThreshold = 1.0 ;
211
+ }
212
+
161
213
private static string GenerateBadge ( CodeSummary summary )
162
214
{
163
215
string colour ;
164
- if ( summary . LineRate < 0.5 )
216
+ if ( summary . LineRate < lowerThreshold )
165
217
{
166
218
colour = "critical" ;
167
219
}
168
- else if ( summary . LineRate < 0.75 )
220
+ else if ( summary . LineRate < upperThreshold )
169
221
{
170
222
colour = "yellow" ;
171
223
}
@@ -176,78 +228,75 @@ private static string GenerateBadge(CodeSummary summary)
176
228
return $ "https://img.shields.io/badge/Code%20Coverage-{ summary . LineRate * 100 : N0} %25-{ colour } ?style=flat";
177
229
}
178
230
179
- private static string GenerateTextOutput ( CodeSummary summary , string badgeUrl )
231
+ private static string GenerateHealthIndicator ( double rate )
180
232
{
181
- StringBuilder textOutput = new ( ) ;
182
-
183
- if ( ! string . IsNullOrWhiteSpace ( badgeUrl ) )
233
+ if ( rate < lowerThreshold )
184
234
{
185
- textOutput . AppendLine ( badgeUrl ) ;
235
+ return "❌" ;
186
236
}
187
-
188
- textOutput . AppendLine ( $ "Line Rate = { summary . LineRate * 100 : N0} %, Lines Covered = { summary . LinesCovered } / { summary . LinesValid } ")
189
- . AppendLine ( $ "Branch Rate = { summary . BranchRate * 100 : N0} %, Branches Covered = { summary . BranchesCovered } / { summary . BranchesValid } ") ;
190
-
191
- if ( summary . Complexity % 1 == 0 )
237
+ else if ( rate < upperThreshold )
192
238
{
193
- textOutput . AppendLine ( $ "Complexity = { summary . Complexity } " ) ;
239
+ return "➖" ;
194
240
}
195
241
else
196
242
{
197
- textOutput . AppendLine ( $ "Complexity = { summary . Complexity : N4} ") ;
243
+ return "✔" ;
244
+ }
245
+ }
246
+
247
+ private static string GenerateTextOutput ( CodeSummary summary , string badgeUrl , bool indicators )
248
+ {
249
+ StringBuilder textOutput = new ( ) ;
250
+
251
+ if ( ! string . IsNullOrWhiteSpace ( badgeUrl ) )
252
+ {
253
+ textOutput . AppendLine ( badgeUrl )
254
+ . AppendLine ( ) ;
198
255
}
199
256
200
257
foreach ( CodeCoverage package in summary . Packages )
201
258
{
202
- if ( package . Complexity % 1 == 0 )
203
- {
204
- textOutput . AppendLine ( $ "{ package . Name } : Line Rate = { package . LineRate * 100 : N0} %, Branch Rate = { package . BranchRate * 100 : N0} %, Complexity = { package . Complexity } ") ;
205
- }
206
- else
207
- {
208
- textOutput . AppendLine ( $ "{ package . Name } : Line Rate = { package . LineRate * 100 : N0} %, Branch Rate = { package . BranchRate * 100 : N0} %, Complexity = { package . Complexity : N4} ") ;
209
- }
259
+ textOutput . Append ( $ "{ package . Name } : Line Rate = { package . LineRate * 100 : N0} %")
260
+ . Append ( $ ", Branch Rate = { package . BranchRate * 100 : N0} %")
261
+ . Append ( ( package . Complexity % 1 == 0 ) ? $ ", Complexity = { package . Complexity } " : $ ", Complexity = { package . Complexity : N4} ")
262
+ . AppendLine ( indicators ? $ ", { GenerateHealthIndicator ( package . LineRate ) } " : string . Empty ) ;
210
263
}
211
264
265
+ textOutput . Append ( $ "Summary: Line Rate = { summary . LineRate * 100 : N0} % ({ summary . LinesCovered } / { summary . LinesValid } )")
266
+ . Append ( $ ", Branch Rate = { summary . BranchRate * 100 : N0} % ({ summary . BranchesCovered } / { summary . BranchesValid } )")
267
+ . Append ( ( summary . Complexity % 1 == 0 ) ? $ ", Complexity = { summary . Complexity } " : $ ", Complexity = { summary . Complexity : N4} ")
268
+ . AppendLine ( indicators ? $ ", { GenerateHealthIndicator ( summary . LineRate ) } " : string . Empty ) ;
269
+
212
270
return textOutput . ToString ( ) ;
213
271
}
214
272
215
- private static string GenerateMarkdownOutput ( CodeSummary summary , string badgeUrl )
273
+ private static string GenerateMarkdownOutput ( CodeSummary summary , string badgeUrl , bool indicators )
216
274
{
217
275
StringBuilder markdownOutput = new ( ) ;
218
276
219
277
if ( ! string . IsNullOrWhiteSpace ( badgeUrl ) )
220
278
{
221
- markdownOutput . AppendLine ( $ "") ;
222
- markdownOutput . AppendLine ( "" ) ;
279
+ markdownOutput . AppendLine ( $ "")
280
+ . AppendLine ( ) ;
223
281
}
224
282
225
- markdownOutput . AppendLine ( "Package | Line Rate | Branch Rate | Complexity" )
226
- . AppendLine ( "-------- | --------- | ----------- | ----------" ) ;
283
+ markdownOutput . Append ( "Package | Line Rate | Branch Rate | Complexity" )
284
+ . AppendLine ( indicators ? " | Health" : string . Empty )
285
+ . Append ( "-------- | --------- | ----------- | ----------" )
286
+ . AppendLine ( indicators ? " | ------" : string . Empty ) ;
227
287
228
288
foreach ( CodeCoverage package in summary . Packages )
229
289
{
230
- if ( package . Complexity % 1 == 0 )
231
- {
232
- markdownOutput . AppendLine ( $ "{ package . Name } | { package . LineRate * 100 : N0} % | { package . BranchRate * 100 : N0} % | { package . Complexity } ") ;
233
- }
234
- else
235
- {
236
- markdownOutput . AppendLine ( $ "{ package . Name } | { package . LineRate * 100 : N0} % | { package . BranchRate * 100 : N0} % | { package . Complexity : N4} ") ;
237
- }
290
+ markdownOutput . Append ( $ "{ package . Name } | { package . LineRate * 100 : N0} %")
291
+ . Append ( $ " | { package . BranchRate * 100 : N0} %")
292
+ . Append ( ( package . Complexity % 1 == 0 ) ? $ " | { package . Complexity } " : $ " | { package . Complexity : N4} " )
293
+ . AppendLine ( indicators ? $ " | { GenerateHealthIndicator ( package . LineRate ) } " : string . Empty ) ;
238
294
}
239
295
240
- markdownOutput . Append ( $ "**Summary** | **{ summary . LineRate * 100 : N0} %** ({ summary . LinesCovered } / { summary . LinesValid } ) | ")
241
- . Append ( $ "**{ summary . BranchRate * 100 : N0} %** ({ summary . BranchesCovered } / { summary . BranchesValid } ) | ") ;
242
-
243
- if ( summary . Complexity % 1 == 0 )
244
- {
245
- markdownOutput . AppendLine ( summary . Complexity . ToString ( ) ) ;
246
- }
247
- else
248
- {
249
- markdownOutput . AppendLine ( summary . Complexity . ToString ( "N4" ) ) ;
250
- }
296
+ markdownOutput . Append ( $ "**Summary** | **{ summary . LineRate * 100 : N0} %** ({ summary . LinesCovered } / { summary . LinesValid } )")
297
+ . Append ( $ " | **{ summary . BranchRate * 100 : N0} %** ({ summary . BranchesCovered } / { summary . BranchesValid } )")
298
+ . Append ( ( summary . Complexity % 1 == 0 ) ? $ " | { summary . Complexity } " : $ " | { summary . Complexity : N4} ")
299
+ . AppendLine ( indicators ? $ " | { GenerateHealthIndicator ( summary . LineRate ) } " : string . Empty ) ;
251
300
252
301
return markdownOutput . ToString ( ) ;
253
302
}
0 commit comments