FAKE (F# Make) dotCover coverage in TeamCity - f#

I have a FAKE build script that contains a DotCover coverage step using using the DotCoverNUnit3 extension:
let filters = ""
!! (buildDir ## "/*.UnitTests.dll")
|> DotCoverNUnit3 (fun p ->
{ p with
Output = artifactsDir ## "NUnitDotCover.snapshot"
Filters = filters }) nunitOptions
The snapshot generates correctly, but the coverage overview doesn't appear in the TeamCity build.
I then tried calling DotCoverReport after building the snapshot:
DotCoverReport (fun p ->
{ p with
Source = artifactsDir ## "NUnitDotCover.snapshot"
Output = artifactsDir ## "NUnitDotCover.xml"
ReportType = DotCoverReportType.Xml }) true
This generates the expected XML report, but again, the coverage overview doesn't appear in the build overview page.
As a side note - I'm not sure what the boolean parameter on the end of the DotCoverReport method is, can't find a reference to it on the FAKE docs. I tried switching the value, but it didn't make a difference.
Does anyone know how I can get TeamCity to pickup the DotCover report?

Found a solution.
After drilling down through many layers of TeamCity documentation, I found this page: https://confluence.jetbrains.com/display/TCD9/Manually+Configuring+Reporting+Coverage
Which describes using service messages to point TeamCity in the direction of the snapshot.
So, in the end I didn't need the DotCoverReport, just the snapshot:
For dotCover you should send paths to the snapshot file that is generated by the dotCover.exe cover command.
This is my resulting Target:
let artifactsDir = environVarOrDefault "ARTIFACT_DIR" (currentDirectory ## "artifacts")
let nunitOptions nUnit3Defaults =
{ NUnit3Defaults with
TimeOut = TimeSpan.MaxValue
WorkingDir = artifactsDir }
Target "TestCoverage" (fun _ ->
let filters = ""
!! (buildDir ## "/*.UnitTests.dll")
|> DotCoverNUnit3 (fun p ->
{ p with
Output = artifactsDir ## "NUnitDotCover.snapshot"
Filters = filters }) nunitOptions
tracefn "##teamcity[importData type='dotNetCoverage' tool='dotcover' path='%s']" (artifactsDir ## "NUnitDotCover.snapshot")
)

Related

DotCover not working

I am using DotCoverNUnit in FAKE for code coverage .
It is giving some error
`Starting Target: TestCoverage (==> BuildUnitTest)
./Buildtools/dotCover/dotCover.exe "cover" "/TargetExecutable=./Libs/NUnit.Runners.2.6.3/tools/nunit-console.exe" "/TargetArguments="-nologo" "-labels" "D:\Project\build\project.UnitTest.dll" "-xml:D:\Project\TestResult.xml"" "/Output=./test/NUnitDotCover.xml"
./Buildtools/dotCover/dotCover.exe "cover" "/TargetExecutable=./Libs/NUnit.Runners.2.6.3/tools/nunit-console.exe" "/TargetArguments="-nologo" "-labels" "D:\Project\build\Project.UnitTest.dll" "-xml:D:\Project\TestResult.xml"" "/Output=./test/NUnitDotCover.xml"
JetBrains dotCover Console Runner v2.6.608.684. Copyright (c) 2009–2017 JetBrains s.r.o. All rights reserved.
**Command 'cover' doesn't support 4 unnamed arguments**
Type 'dotCover help' for usage.
Running build failed.
Error:
System.Exception: Error running ./Buildtools/dotCover/dotCover.exe with exitcode -1
at Fake.DotCover.buildParamsAndExecute#124-6.Invoke(String message)
at Fake.DotCover.buildParamsAndExecute[a](a parameters, FSharpFunc2 buildArguments,String toolPath, String workingDir, Boolean failBuild)
at Fake.DotCover.DotCoverNUnit(FSharpFunc 2 setDotCoverParams, FSharpFunc2 setNUnitParams, IEnumerable 1 assemblies)
at FSI_0005.Build.clo#98-8.Invoke(Unit _arg6) in D:\ICIS API develop\icis-api\build.fsx:line 99`
I am not able to figure out the problem out there in this code , I was able to run this code earlier but right now it is not wroking .
Here is the code that I am using for DotCover :
Target "TestCoverage" (fun _ ->
!! (buildDir ## "/Project.UnitTest.dll")
|> DotCoverNUnit
(fun p -> { p with TargetExecutable ="nunit-console.exe"
Output ="NUnitDotCover.xml"
ToolPath = "dotCover.exe"
ErrorLevel = DontFailBuild
Filters = filters })
(fun nunitOptions ->
{ nunitOptions with DisableShadowCopy = true })
tracefn "##teamcity[importData type='dotNetCoverage' tool='dotcover' path='%s']" (testDir ## "NUnitDotCover.xml")
)

Code coverage using dotCover - FAKE F#MAKE

I am trying to use dotCover in FAKE .I am getting an error i.e. DotCoverNUnit is not defined .I think this is the problem with the package .
Here is my Code for DotCover in FAKE :
let filters = ""
Target "TestCoverage" (fun _ ->
!! ("D:/Test/Project/Project1/UnitTests/UnitTest.dll")
|> DotCoverNUnit (fun p ->
{ p with
Output = testDir ## "NUnitDotCover.snapshot"
Filters = filters }) nunitOptions
)
Please tell me how to install DotCover in Fake or how to use this . This would be very helpful .
The Fake.DotCover module is not auto-opened, so its functions aren't available until you do open Fake.DotCover near the top of your script.
Unfortunately, the FAKE API documentation currently isn't very good at telling you which modules are auto-opened and which ones need open (modulename) in order to expose their functions.
Update: The way you should be calling DotCoverNUnit is as follows:
let filters = ""
Target "TestCoverage" (fun _ ->
!! ("D:/Test/Project/Project1/UnitTests/UnitTest.dll")
|> DotCoverNUnit
(fun p -> { p with Output = testDir ## "NUnitDotCover.snapshot"
Filters = filters })
(fun nunitOptions -> nunitOptions)
)
Or, if you want to change some of the NUnit options:
let filters = ""
Target "TestCoverage" (fun _ ->
!! ("D:/Test/Project/Project1/UnitTests/UnitTest.dll")
|> DotCoverNUnit
(fun dotCoverOptions ->
{ dotCoverOptions with Output = testDir ## "NUnitDotCover.snapshot"
Filters = filters })
(fun nunitOptions ->
{ nunitOptions with ExcludeCategory = "Manual,LongRunning"
DisableShadowCopy = true })
)
See http://fsharp.github.io/FAKE/apidocs/fake-nunitcommon-nunitparams.html for the complete list of what NUnit options are available from inside FAKE.

Websharper compiler can't translate other assemblies

my goal is to simply output a javascript file containing my translated F# library. Nothing more.
I have an empty solution to which I added two F# projects. One is a library called WSLib with a single file:
namespace WSLib
[<ReflectedDefinition>]
type Class1() =
member this.X = "F#"
[<ReflectedDefinition>]
module Foo =
let bar = 34
The other project is a console app and references the WebSharper and WebSharper.Compiler NuGet packages. It has a single file. I copied the first half of the code from http://www.fssnip.net/snippet/rP.
module Program
open Microsoft.FSharp.Quotations
open WebSharper
type AR = IntelliFactory.Core.AssemblyResolution.AssemblyResolver
module FE = WebSharper.Compiler.FrontEnd
let compile (expr: Expr) : string option =
let loader = FE.Loader.Create (AR.Create()) (eprintfn "%O")
let options =
{ FE.Options.Default with
References =
List.map loader.LoadFile [
// These contain the JavaScript implementation for most of the standard library
"WebSharper.Main.dll"
"WebSharper.Collections.dll"
"WebSharper.Control.dll"
"WSLib.dll"
// Add any other assemblies used in the quotation...
] }
let compiler = FE.Prepare options (sprintf "%A" >> System.Diagnostics.Debug.WriteLine)
compiler.Compile expr
|> Option.map (fun e -> e.ReadableJavaScript)
[<JavaScript>]
let main() =
let a = WSLib.Class1().X
let b = WSLib.Foo.bar
(a,b)
let code =
match (compile <# main() #>) with
|None -> failwith "parse failed"
|Some x -> x
open System.IO
let filePath = Path.Combine(System.Environment.CurrentDirectory, "index.js")
File.WriteAllText(filePath, code)
I get a couple of errors:
{Location = {ReadableLocation = "main";
SourceLocation = null;};
Priority = Error;
Text = "Failed to translate property access: X [WSLib.Class1].";}
{Location = {ReadableLocation = "main";
SourceLocation = null;};
Priority = Error;
Text = "Failed to translate property access: bar [WSLib.Foo].";}
What do I need to do to get the websharper compiler working with different projects? I get the same error if I include the WebSharper package on WSLib and replace ReflectedDefinition with JavaScript.
What happens here is that adding WSLib.dll to the compiler references will only make it look for WebSharper metadata in that assembly, if there is any; but WSLib needs to be WebSharper-compiled already. For this to happen, you need to reference WebSharper in WSLib (as you did) and add the following property to the project file:
<WebSharperProject>Library</WebSharperProject>
to instruct WebSharper that it does have to compile this assembly.

FAKE specify NUnit Namespace/Fixture when running tests

In my Powershell script (PSAKE), I have the ability to specify the Namespace/Fixture to run when I execute the NUnit test runner.
task UnitTest -Depends Compile -Description "Runs only Unit Tests" {
Invoke-Nunit "$buildOutputDir\$testAssembly.dll" "$testAssembly.Unit" $buildArtifactsDir
}
task IntegrationTest -Depends Compile -Description "Runs only Integration Tests" {
Invoke-Nunit "$buildOutputDir\$testAssembly.dll" "$testAssembly.Integration" $buildArtifactsDir
}
task FunctionalTest -Depends Compile -Description "Runs only Functional Tests" {
Invoke-Nunit "$buildOutputDir\$testAssembly.dll" "$testAssembly.Functional" $buildArtifactsDir
}
This allows me to have three outputs
Unit-TestResults.xml
Integration-TestResults.xml
Functional-TestResults.xml
I'm in the process of switching over to FAKE because it's just so much cleaner to maintain, however I can't figure out how to specify the Fixture for my test.
IE: right now I have
// Run Tests
Target "Tests" (fun _ ->
testDlls
|> NUnit (fun p ->
{p with
DisableShadowCopy = true;
OutputFile = artifactDir + "/TestResults.xml"
})
)
But this runs ALL the tests and drops it into a single output. I'd really like to specify the Fixture, and be able to split it all up. Is there a way to do this?
Newest version of FAKE added support for Fixture parameter. You should be able to do:
Target "Tests" (fun _ ->
testDlls
|> NUnit (fun p ->
{p with
Fixture ="Namespace.Unit"
DisableShadowCopy = true;
OutputFile = artifactDir + "/Unit-TestResults.xml"
})
testDlls
|> NUnit (fun p ->
{p with
Fixture ="Namespace.Integration"
DisableShadowCopy = true;
OutputFile = artifactDir + "/Integration-TestResults.xml"
})
testDlls
|> NUnit (fun p ->
{p with
Fixture ="Namespace.Functional"
DisableShadowCopy = true;
OutputFile = artifactDir + "/Functional-TestResults.xml"
})
)

Need help regarding Async and fsi

I'd like to write some code that runs a sequence of F# scripts (.fsx). The thing is that I could have literally hundreds of scripts and if I do that:
let shellExecute program args =
let startInfo = new ProcessStartInfo()
do startInfo.FileName <- program
do startInfo.Arguments <- args
do startInfo.UseShellExecute <- true
do startInfo.WindowStyle <- ProcessWindowStyle.Hidden
//do printfn "%s" startInfo.Arguments
let proc = Process.Start(startInfo)
()
scripts
|> Seq.iter (shellExecute "fsi")
it could stress too much my 2GB system. Anyway, I'd like to run scripts by batch of n, which seems also a good exercise for learning Async (I guess it's the way to go).
I have started to write some code for that but unfortunately it doesn't work:
open System.Diagnostics
let p = shellExecute "fsi" #"C:\Users\Stringer\foo.fsx"
async {
let! exit = Async.AwaitEvent p.Exited
do printfn "process has exited"
}
|> Async.StartImmediate
foo.fsx is just a hello world script.
What would be the most idiomatic way of solving this problem?
I'd like also to figure out if it's doable to retrieve a return code for each executing script and if not, find another way. Thanks!
EDIT:
Thanks a lot for your insights and links! I've learned a lot.
I just want to add some code for running batchs in parallel using Async.Parallel as Tomas suggested it. Please comment if there is a better implementation for my cut function.
module Seq =
/// Returns a sequence of sequences of N elements from the source sequence.
/// If the length of the source sequence is not a multiple
/// of N, last element of the returned sequence will have a length
/// included between 1 and N-1.
let cut (count : int) (source : seq<´T>) =
let rec aux s length = seq {
if (length < count) then yield s
else
yield Seq.take count s
if (length <> count) then
yield! aux (Seq.skip count s) (length - count)
}
aux source (Seq.length source)
let batchCount = 2
let filesPerBatch =
let q = (scripts.Length / batchCount)
q + if scripts.Length % batchCount = 0 then 0 else 1
let batchs =
scripts
|> Seq.cut filesPerBatch
|> Seq.map Seq.toList
|> Seq.map loop
Async.RunSynchronously (Async.Parallel batchs) |> ignore
EDIT2:
So I had some troubles to get Tomas's guard code working. I guess the f function had to be called in AddHandler method, otherwise we loose the event for ever... Here's the code:
module Event =
let guard f (e:IEvent<´Del, ´Args>) =
let e = Event.map id e
{ new IEvent<´Args> with
member this.AddHandler(d) = e.AddHandler(d); f() //must call f here!
member this.RemoveHandler(d) = e.RemoveHandler(d); f()
member this.Subscribe(observer) =
let rm = e.Subscribe(observer) in f(); rm }
The interesting thing (as mentioned by Tomas) is that it looks like the Exited event is stored somewhere when the process terminates, even though the process has not started with EnableRaisingEvents set to true.
When this property is finally set to true, the event is fired up.
Since I'm not sure that this is the official specification (and also a bit paranoid), I found another solution that consists in starting the process in the guard function, so we ensure that the code will work on whichever situation:
let createStartInfo program args =
new ProcessStartInfo
(FileName = program, Arguments = args, UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Normal,
RedirectStandardOutput = true)
let createProcess info =
let p = new Process()
do p.StartInfo <- info
do p.EnableRaisingEvents <- true
p
let rec loop scripts = async {
match scripts with
| [] -> printfn "FINISHED"
| script::scripts ->
let args = sprintf "\"%s\"" script
let p = createStartInfo "notepad" args |> createProcess
let! exit =
p.Exited
|> Event.guard (fun () -> p.Start() |> ignore)
|> Async.AwaitEvent
let output = p.StandardOutput.ReadToEnd()
do printfn "\nPROCESSED: %s, CODE: %d, OUTPUT: %A"script p.ExitCode output
return! loop scripts
}
Notice I've replaced fsi.exe by notepad.exe so I can replay different scenarios step by step in the debugger and control explicitly the exit of the process myself.
I did some experiments and here is one way to deal with the problem discussed in the comments below my post and in the answer from Joel (which I think doesn't work currently, but could be fixed).
I think the specification of Process is that it can trigger the Exited event after we set the EnableRaisingEvents property to true (and will trigger the event even if the process has already completed before we set the property). To handle this case correctly, we need to enable raising of events after we attach handler to the Exited event.
This is a problme, because if we use AwaitEvent it will block the workflow until the event fires. We cannot do anything after calling AwaitEvent from the workflow (and if we set the property before calling AwaitEvent, then we get a race....). Vladimir's approach is correct, but I think there is a simpler way to deal with this.
I'll create a function Event.guard taking an event and returning an event, which allows us to specify some function that will be executed after a handler is attached to the event. This means that if we do some operation (which in turn triggers the event) inside this function, the event will be handled.
To use it for the problem discussed here, we need to change my original solution as follows. Firstly, the shellExecute function must not set the EnableRaisingEvents property (otherwise, we could lose the event!). Secondly, the waiting code should look like this:
let rec loop scripts = async {
match scripts with
| [] -> printf "FINISHED"
| script::scripts ->
let p = shellExecute fsi script
let! exit =
p.Exited
|> Event.guard (fun () -> p.EnableRaisingEvents <- true)
|> Async.AwaitEvent
let output = p.StandardOutput.ReadToEnd()
return! loop scripts }
Note the use of the Event.guard function. Roughly, it says that after the workflow attaches handler to the p.Exited event, the provided lambda function will run (and will enable raising of events). However, we already attached the handler to the event, so if this causes the event immediately, we're fine!
The implementation (for both Event and Observable) looks like this:
module Event =
let guard f (e:IEvent<'Del, 'Args>) =
let e = Event.map id e
{ new IEvent<'Args> with
member x.AddHandler(d) = e.AddHandler(d)
member x.RemoveHandler(d) = e.RemoveHandler(d); f()
member x.Subscribe(observer) =
let rm = e.Subscribe(observer) in f(); rm }
module Observable =
let guard f (e:IObservable<'Args>) =
{ new IObservable<'Args> with
member x.Subscribe(observer) =
let rm = e.Subscribe(observer) in f(); rm }
Nice thing is that this code is very straightforward.
Your approach looks great to me, I really like the idea of embedding process execution into asynchronous workflows using AwaitEvent!
The likely reason why it didn't work is that you need to set EnableRisingEvents property of the Process to true if you want it to ever trigger the Exited event (don't ask my why you have to do that, it sounds pretty silly to me!) Anyway, I did a couple of other changes to your code when testing it, so here is a version that worked for me:
open System
open System.Diagnostics
let shellExecute program args =
// Configure process to redirect output (so that we can read it)
let startInfo =
new ProcessStartInfo
(FileName = program, Arguments = args, UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardOutput = true)
// Start the process
// Note: We must enable rising events explicitly here!
Process.Start(startInfo, EnableRaisingEvents = true)
Most importantly, the code now sets EnableRaisingEvents to true. I also changed the code to use a syntax where you specify properties of an object when constructing it (to make the code a bit more succinct) and I changed a few properties, so that I can read the output (RedirectStandardOutput).
Now, we can use the AwaitEvent method to wait until a process completes. I'll assume that fsi contains the path to fsi.exe and that scripts is a list of FSX scripts. If you want to run them sequentially, you could use a loop implemented using recursion:
let rec loop scripts = async {
match scripts with
| [] -> printf "FINISHED"
| script::scripts ->
// Start the proces in background
let p = shellExecute fsi script
// Wait until the process completes
let! exit = Async.AwaitEvent p.Exited
// Read the output produced by the process, the exit code
// is available in the `ExitCode` property of `Process`
let output = p.StandardOutput.ReadToEnd()
printfn "\nPROCESSED: %s, CODE: %d\n%A" script p.ExitCode output
// Process the rest of the scripts
return! loop scripts }
// This starts the workflow on background thread, so that we can
// do other things in the meantime. You need to add `ReadLine`, so that
// the console application doesn't quit immedeiately
loop scripts |> Async.Start
Console.ReadLine() |> ignore
Of course, you could also run the processes in parallel (or for example run 2 groups of them in parallel etc.) To do that you would use Async.Parallel (in the usual way).
Anyway, this is a really nice example of using asynchronous workflows in an area where I haven't seen them used so far. Very interesting :-)
In response to Tomas's answer, would this be a workable solution to the race condition involved in starting the process, and then subscribing to its Exited event?
type Process with
static member AsyncStart psi =
let proc = new Process(StartInfo = psi, EnableRaisingEvents = true)
let asyncExit = Async.AwaitEvent proc.Exited
async {
proc.Start() |> ignore
let! args = asyncExit
return proc
}
Unless I'm mistaken, this would subscribe to the event prior to starting the process, and package it all up as an Async<Process> result.
This would allow you to rewrite the rest of the code like this:
let shellExecute program args =
// Configure process to redirect output (so that we can read it)
let startInfo =
new ProcessStartInfo(FileName = program, Arguments = args,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardOutput = true)
// Start the process
Process.AsyncStart(startInfo)
let fsi = "PATH TO FSI.EXE"
let rec loop scripts = async {
match scripts with
| [] -> printf "FINISHED"
| script::scripts ->
// Start the proces in background
use! p = shellExecute fsi script
// Read the output produced by the process, the exit code
// is available in the `ExitCode` property of `Process`
let output = p.StandardOutput.ReadToEnd()
printfn "\nPROCESSED: %s, CODE: %d\n%A" script p.ExitCode output
// Process the rest of the scripts
return! loop scripts
}
If that does the job, it's certainly a lot less code to worry about than Vladimir's Async.GetSubject.
What about a mailboxprocessor?
It is possible to simplify version of Subject from blogpost. instead of returning imitation of event, getSubject can return workflow.
Result workflow itself is state machine with two states
1. Event wasn't triggered yet: all pending listeners should be registered
2. Value is already set, listener is served immediately
In code it will appear like this:
type SubjectState<'T> = Listen of ('T -> unit) list | Value of 'T
getSubject implementation is trivial
let getSubject (e : IEvent<_, _>) =
let state = ref (Listen [])
let switchState v =
let listeners =
lock state (fun () ->
match !state with
| Listen ls ->
state := Value v
ls
| _ -> failwith "Value is set twice"
)
for l in listeners do l v
Async.StartWithContinuations(
Async.AwaitEvent e,
switchState,
ignore,
ignore
)
Async.FromContinuations(fun (cont, _, _) ->
let ok, v = lock state (fun () ->
match !state with
| Listen ls ->
state := Listen (cont::ls)
false, Unchecked.defaultof<_>
| Value v ->
true, v
)
if ok then cont v
)

Resources