Last active
August 15, 2016 19:15
Star
You must be signed in to star a gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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