3 people like it.

Compute CC.Net build statistics

Written against CruiseControl.NET v1.5. Queries a CruiseControl.NET server for a project list and then computes min, max, average, and standard deviation of the build durations based on the statistics.csv CC.NET maintains.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
open System
open System.Collections.Generic
open System.IO

open ThoughtWorks.CruiseControl.Remote

type Result = { Name : string; Count : Int32; Average : float; StdDev : float; Min : float; Max : float; }
              member x.Print() = printfn "%s,%d,%.2f,%.2f,%.2f,%.6f" x.Name x.Count x.Min x.Max x.Average x.StdDev

let ReadLines (fileName : string) = seq {
    use reader = new StreamReader(fileName)
    while not reader.EndOfStream do yield reader.ReadLine() }

let ComputeResults name values =
    let count = values |> Seq.length
    let average = values |> Seq.average    
    let variance = (values |> Seq.map (fun n -> (n - average) * (n - average)) |> Seq.sum) / float count
    let stdDev = Math.Sqrt(variance)
    { Name = name; Count = count; Average = average; StdDev = stdDev; Min = Seq.min values; Max = Seq.max values }
            
let GetStatistics serverName projectName =
    let fileName = String.Format(@"\\{0}\ccnet\{1}\ArtifactDirectory\statistics.csv", serverName, projectName)
    ReadLines(fileName)
    |> Seq.map (fun s -> s.Split(','))      
    |> Seq.map (fun v -> TimeSpan.TryParse(v.[1]))
    |> Seq.filter (fun (r, span) -> r && span <> TimeSpan.Zero)
    |> Seq.map (fun (r, span) -> span.TotalMinutes)
    |> ComputeResults projectName

let client = new CruiseServerHttpClient("http://cruisecontrol")  

printfn "Project,Count,Minimum,Maximum,Average,StdDev"
client.GetProjectStatus()
|> Seq.map (fun (p : ProjectStatus) -> GetStatistics p.ServerName p.Name)
|> Seq.sortBy (fun result -> result.Name)
|> Seq.iter (fun result -> result.Print())
namespace System
namespace System.Collections
namespace System.Collections.Generic
namespace System.IO
type Result =
  {Name: string;
   Count: Int32;
   Average: float;
   StdDev: float;
   Min: float;
   Max: float;}
  member Print : unit -> unit

Full name: Script.Result
Result.Name: string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
Result.Count: Int32
type Int32 =
  struct
    member CompareTo : value:obj -> int + 1 overload
    member Equals : obj:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member GetTypeCode : unit -> TypeCode
    member ToString : unit -> string + 3 overloads
    static val MaxValue : int
    static val MinValue : int
    static member Parse : s:string -> int + 3 overloads
    static member TryParse : s:string * result:int -> bool + 1 overload
  end

Full name: System.Int32
Result.Average: float
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
Result.StdDev: float
Result.Min: float
Result.Max: float
val x : Result
member Result.Print : unit -> unit

Full name: Script.Result.Print
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val ReadLines : fileName:string -> seq<string>

Full name: Script.ReadLines
val fileName : string
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val reader : StreamReader
Multiple items
type StreamReader =
  inherit TextReader
  new : stream:Stream -> StreamReader + 9 overloads
  member BaseStream : Stream
  member Close : unit -> unit
  member CurrentEncoding : Encoding
  member DiscardBufferedData : unit -> unit
  member EndOfStream : bool
  member Peek : unit -> int
  member Read : unit -> int + 1 overload
  member ReadLine : unit -> string
  member ReadToEnd : unit -> string
  ...

Full name: System.IO.StreamReader

--------------------
StreamReader(stream: Stream) : unit
StreamReader(path: string) : unit
StreamReader(stream: Stream, detectEncodingFromByteOrderMarks: bool) : unit
StreamReader(stream: Stream, encoding: Text.Encoding) : unit
StreamReader(path: string, detectEncodingFromByteOrderMarks: bool) : unit
StreamReader(path: string, encoding: Text.Encoding) : unit
StreamReader(stream: Stream, encoding: Text.Encoding, detectEncodingFromByteOrderMarks: bool) : unit
StreamReader(path: string, encoding: Text.Encoding, detectEncodingFromByteOrderMarks: bool) : unit
StreamReader(stream: Stream, encoding: Text.Encoding, detectEncodingFromByteOrderMarks: bool, bufferSize: int) : unit
StreamReader(path: string, encoding: Text.Encoding, detectEncodingFromByteOrderMarks: bool, bufferSize: int) : unit
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
property StreamReader.EndOfStream: bool
StreamReader.ReadLine() : string
val ComputeResults : name:string -> values:seq<float> -> Result

Full name: Script.ComputeResults
val name : string
val values : seq<float>
val count : int
module Seq

from Microsoft.FSharp.Collections
val length : source:seq<'T> -> int

Full name: Microsoft.FSharp.Collections.Seq.length
val average : float
val average : source:seq<'T> -> 'T (requires member ( + ) and member DivideByInt and member get_Zero)

Full name: Microsoft.FSharp.Collections.Seq.average
val variance : float
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val n : float
val sum : source:seq<'T> -> 'T (requires member ( + ) and member get_Zero)

Full name: Microsoft.FSharp.Collections.Seq.sum
val stdDev : float
type Math =
  static val PI : float
  static val E : float
  static member Abs : value:sbyte -> sbyte + 6 overloads
  static member Acos : d:float -> float
  static member Asin : d:float -> float
  static member Atan : d:float -> float
  static member Atan2 : y:float * x:float -> float
  static member BigMul : a:int * b:int -> int64
  static member Ceiling : d:decimal -> decimal + 1 overload
  static member Cos : d:float -> float
  ...

Full name: System.Math
Math.Sqrt(d: float) : float
val min : source:seq<'T> -> 'T (requires comparison)

Full name: Microsoft.FSharp.Collections.Seq.min
val max : source:seq<'T> -> 'T (requires comparison)

Full name: Microsoft.FSharp.Collections.Seq.max
val GetStatistics : serverName:'a -> projectName:string -> Result

Full name: Script.GetStatistics
val serverName : 'a
val projectName : string
Multiple items
type String =
  new : value:char -> string + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

Full name: System.String

--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
String.Format(format: string, [<ParamArray>] args: obj []) : string
String.Format(format: string, arg0: obj) : string
String.Format(provider: IFormatProvider, format: string, [<ParamArray>] args: obj []) : string
String.Format(format: string, arg0: obj, arg1: obj) : string
String.Format(format: string, arg0: obj, arg1: obj, arg2: obj) : string
val s : string
String.Split([<ParamArray>] separator: char []) : string []
String.Split(separator: string [], options: StringSplitOptions) : string []
String.Split(separator: char [], options: StringSplitOptions) : string []
String.Split(separator: char [], count: int) : string []
String.Split(separator: string [], count: int, options: StringSplitOptions) : string []
String.Split(separator: char [], count: int, options: StringSplitOptions) : string []
val v : string []
Multiple items
type TimeSpan =
  struct
    new : ticks:int64 -> TimeSpan + 3 overloads
    member Add : ts:TimeSpan -> TimeSpan
    member CompareTo : value:obj -> int + 1 overload
    member Days : int
    member Duration : unit -> TimeSpan
    member Equals : value:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member Hours : int
    member Milliseconds : int
    member Minutes : int
    ...
  end

Full name: System.TimeSpan

--------------------
TimeSpan()
TimeSpan(ticks: int64) : unit
TimeSpan(hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : unit
TimeSpan.TryParse(s: string, result: byref<TimeSpan>) : bool
TimeSpan.TryParse(input: string, formatProvider: IFormatProvider, result: byref<TimeSpan>) : bool
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
val r : bool
val span : TimeSpan
field TimeSpan.Zero
property TimeSpan.TotalMinutes: float
val client : obj

Full name: Script.client
val p : Result
val sortBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Seq.sortBy
val result : Result
val iter : action:('T -> unit) -> source:seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iter
member Result.Print : unit -> unit
Raw view Test code New version

More information

Link:http://fssnip.net/8J
Posted:12 years ago
Author:Matt Wilson
Tags: cruisecontrol , io , build , cc.net , math