Skip to content

Commit b011083

Browse files
committed
Improve extrapolation calculations
1 parent e780ff1 commit b011083

9 files changed

Lines changed: 659 additions & 198 deletions

File tree

cmd/prcost/main.go

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func main() {
3131
org := flag.String("org", "", "GitHub organization to analyze (optionally with --repo for single repo)")
3232
repo := flag.String("repo", "", "GitHub repository to analyze (requires --org)")
3333
samples := flag.Int("samples", 25, "Number of PRs to sample for extrapolation (25=fast/±20%, 50=slower/±14%)")
34-
days := flag.Int("days", 90, "Number of days to look back for PR modifications")
34+
days := flag.Int("days", 60, "Number of days to look back for PR modifications")
3535

3636
flag.Usage = func() {
3737
fmt.Fprintf(os.Stderr, "Usage: %s [options] <PR_URL>\n", os.Args[0])
@@ -439,31 +439,48 @@ func formatWithCommas(amount float64) string {
439439
func efficiencyGrade(efficiencyPct float64) (string, string) {
440440
switch {
441441
case efficiencyPct >= 97:
442-
return "A+", "Outstanding!"
442+
return "A+", "Impeccable"
443443
case efficiencyPct >= 93:
444-
return "A", "Excellent!"
444+
return "A", "Excellent"
445445
case efficiencyPct >= 90:
446-
return "A-", "Great work!"
446+
return "A-", "Nearly excellent"
447447
case efficiencyPct >= 87:
448-
return "B+", "Pretty good!"
448+
return "B+", "Acceptable+"
449449
case efficiencyPct >= 83:
450-
return "B", "Minor inefficiency detected."
450+
return "B", "Acceptable"
451451
case efficiencyPct >= 80:
452-
return "B-", "Minor inefficiency detected."
453-
case efficiencyPct >= 77:
454-
return "C+", "Some inefficiency detected."
455-
case efficiencyPct >= 73:
456-
return "C", "Moderate inefficiency detected."
452+
return "B-", "Nearly acceptable"
457453
case efficiencyPct >= 70:
458-
return "C-", "Moderate inefficiency detected."
459-
case efficiencyPct >= 67:
460-
return "D+", "Noticeable inefficiency detected."
461-
case efficiencyPct >= 63:
462-
return "D", "Significant inefficiency detected."
454+
return "C", "Average"
463455
case efficiencyPct >= 60:
464-
return "D-", "Severe inefficiency detected."
456+
return "D", "Not good my friend."
465457
default:
466-
return "F", "Critical inefficiency detected."
458+
return "F", "Failing"
459+
}
460+
}
461+
462+
// mergeVelocityGrade returns a grade based on average PR open time in days.
463+
// A: 1 day or less, B: 2.5 days or less, C: 2.5-4 days, D: 4-5 days, F: 5+ days.
464+
func mergeVelocityGrade(avgOpenDays float64) (string, string) {
465+
switch {
466+
case avgOpenDays <= 0.1875: // 4.5 hours
467+
return "A+", "Impeccable"
468+
case avgOpenDays <= 1.0:
469+
return "A", "Excellent"
470+
case avgOpenDays <= 1.5:
471+
return "A-", "Nearly excellent"
472+
case avgOpenDays <= 2.0:
473+
return "B+", "Acceptable+"
474+
case avgOpenDays <= 2.5:
475+
return "B", "Acceptable"
476+
case avgOpenDays <= 3.0:
477+
return "B-", "Nearly acceptable"
478+
case avgOpenDays <= 4.0:
479+
return "C", "Average"
480+
case avgOpenDays <= 5.0:
481+
return "D", "Not good my friend."
482+
default:
483+
return "F", "Failing"
467484
}
468485
}
469486

@@ -493,14 +510,28 @@ func printEfficiency(breakdown *cost.Breakdown, formatCurrency func(float64) str
493510

494511
grade, message := efficiencyGrade(efficiencyPct)
495512

513+
// Calculate merge velocity grade based on PR duration
514+
prDurationDays := breakdown.PRDuration / 24.0
515+
velocityGrade, velocityMessage := mergeVelocityGrade(prDurationDays)
516+
496517
fmt.Println(" ┌─────────────────────────────────────────────────────────────┐")
497-
headerText := fmt.Sprintf("WORKFLOW EFFICIENCY: %s (%.1f%%) - %s", grade, efficiencyPct, message)
518+
headerText := fmt.Sprintf("DEVELOPMENT EFFICIENCY: %s (%.1f%%) - %s", grade, efficiencyPct, message)
498519
padding := 60 - len(headerText)
499520
if padding < 0 {
500521
padding = 0
501522
}
502523
fmt.Printf(" │ %s%*s│\n", headerText, padding, "")
503524
fmt.Println(" └─────────────────────────────────────────────────────────────┘")
525+
526+
fmt.Println(" ┌─────────────────────────────────────────────────────────────┐")
527+
velocityHeader := fmt.Sprintf("MERGE VELOCITY: %s (%s) - %s", velocityGrade, formatTimeUnit(breakdown.PRDuration), velocityMessage)
528+
velPadding := 60 - len(velocityHeader)
529+
if velPadding < 0 {
530+
velPadding = 0
531+
}
532+
fmt.Printf(" │ %s%*s│\n", velocityHeader, velPadding, "")
533+
fmt.Println(" └─────────────────────────────────────────────────────────────┘")
534+
504535
fmt.Printf(" Preventable Waste: $%12s %s\n",
505536
formatWithCommas(preventableCost), formatTimeUnit(preventableHours))
506537
fmt.Println()

0 commit comments

Comments
 (0)