Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
module Git =
open System
open System.Diagnostics
let private runCommand cmd args =
let startInfo = new ProcessStartInfo()
startInfo.FileName <- cmd
startInfo.Arguments <- args
startInfo.UseShellExecute <- false
startInfo.RedirectStandardOutput <- true
let proc = Process.Start(startInfo)
use stream = proc.StandardOutput
stream.ReadToEnd()
let log branch args =
let args = sprintf "log %s %s" branch (String.concat " " args)
runCommand "git" args
[<AutoOpen>]
module Types =
open System
type Id = Id of string
type Message = Message of string
type Author = {
Name:string
Email:string }
type Commit = {
Id:Id
Author:Author
Date:DateTimeOffset
Message:Message }
#r @"packages/fparsec/lib/net40-client/fparseccs.dll"
#r @"packages/fparsec/lib/net40-client/fparsec.dll"
module GitLogParser =
open System
open FParsec
let private parser =
let str_ws s = pstring s .>> spaces
let char_ws c = pchar c .>> spaces
let ws_char c = spaces >>. pchar c
let anyCharsTill pEnd = manyCharsTill anyChar pEnd
let line = anyCharsTill newline
let restOfLineAfter str = str_ws str >>. line
let id = restOfLineAfter "commit"
let date = restOfLineAfter "Date:"
let merge = restOfLineAfter "Merge:"
let email = ws_char '<' >>. anyCharsTill (char_ws '>')
let name = anyCharsTill (lookAhead email)
let author = str_ws "Author:" >>. name .>>. email
let msgLine = spaces >>. line
let msg = manyTill msgLine (lookAhead (newline >>. id) |>> ignore <|> eof)
let commitId = (spaces >>. id .>> optional merge)
let createCommit id (name, email) date msg = {
Id = Id id
Author = { Name = name; Email = email }
Date = DateTimeOffset.Parse(date)
Message = Types.Message (String.concat Environment.NewLine msg) }
let commit = pipe4 commitId author date msg createCommit
many commit .>> eof
let parseLog log =
match log |> run parser with
| Success(v,_,_) -> v
| Failure(msg,_,_) -> failwith msg
open System
let run branch =
let averageMsgLength = List.map (fun c -> c.Message) >> List.averageBy (fun (Message m) -> float m.Length)
let partitionCommitsByPartOfDay = List.countBy (fun c ->
let within start stop (ts:TimeSpan) = ts.Hours >= start && ts.Hours < stop
let morning = within 6 10
let daytime = within 10 17
let evening = within 17 22
if morning c.Date.TimeOfDay then "Morning"
else if daytime c.Date.TimeOfDay then "Daytime"
else if evening c.Date.TimeOfDay then "Evening"
else "Overnight" )
let print (name, count, length, stats) =
do printfn "%s" name
do printfn "\tTotal commits: %d" count
do printfn "\tCommits by part of day:%s%s" Environment.NewLine
(stats
|> List.sortBy snd
|> List.rev
|> List.map (fun (key, n) -> sprintf "\t\t%s: %.0f %%" key (float n / float count * 100.0))
|> String.concat Environment.NewLine)
do printfn "\tAverage commit message size: %.0f" length
let commits =
Git.log branch ["--date iso"]
|> GitLogParser.parseLog
commits
|> List.groupBy (fun c -> c.Author.Name)
|> List.map (fun (key, xs) -> key, xs.Length, averageMsgLength xs, partitionCommitsByPartOfDay xs)
|> List.sortBy (fun (_,commits,_,_) -> commits)
|> List.rev
|> List.take 5
|> List.iter print
run "master"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.