In my build script, when I run it on my local machine (Win 8.1 x64) the whole script works perfectly fine.
When I run it on my build server (Jenkins, Server 2012 r2 x64), the FxCop task fails, because it cannot resolve any of the System.* assembly references which are required by some of the 3rd party libs I'm using.
I know full well that the version of FxCop (10.0) being used is the same, because it is checked into the project's git repo.
I don't understand why it works ok on my local machine, and not on the build server, but as I understand it from the results of my googling, I should be able to pass the /gac switch to FxCop in order to tell it that it should look there to resolve references it needs when scanning assemblies.
I just can't work out how to pass that switch to FxCop, using FAKE.
The target is as follows, but it's honestly essentially the same as the FxCop tutorial on the FAKE website, I've just removed the names of some dlls and exes.
Target "FxCop" (fun _ ->
!! (build ## "**/*.dll")
++ (build ## "**/*.exe")
|> FxCop (fun p ->
{p with
ReportFileName = testResults + "FXCopResults.xml";
ToolPath = "./tools/FxCop/FxCopCmd.exe" })
)
I've had a look at the source of the FxCopHelper, but my F# isn't that great, and there doesn't appear (to me) to be a way of passing extra command line options other than the ones already specified.
Does anyone have any suggestions?
The parameter you are looking for is UseGACSwitch and it is a boolean.
https://github.com/fsharp/FAKE/blob/master/src/app/FakeLib/FXCopHelper.fs#L77
To update your example:
Target "FxCop" (fun _ ->
!! (build ## "**/*.dll")
++ (build ## "**/*.exe")
|> FxCop (fun p ->
{p with
ReportFileName = testResults + "FXCopResults.xml";
UseGACSwitch = true;
ToolPath = "./tools/FxCop/FxCopCmd.exe" })
)
That should get you what you need for your build server to be happy. You may have already found this out or something else, but it is good that everyone knows there are options. Thank you. Good day.
Related
I'm learning Fake 5 (F# Make) and I'm going through the Getting Started tutorial. When I run the following code I receive an error message : tryscript.fsx (6,7)-(6,54): Error FS0001: The type 'Fake.IO.IGlobbingPattern' is not compatible with the type 'seq<'a>'
#r "paket: nuget Fake.IO.FileSystem //"
open Fake.IO.Globbing.Operators
let csProjectFiles = !! "src/app/**/*.csproj"
csProjectFiles
|> Seq.iter (fun x -> printfn "ProjectFile: %s" x)
// for projectFile in csProjectFiles do
// printfn "F# ProjectFile: %s" projectFile
But if I comment out two lines starting at csProjectFiles |> ... and uncomment the last two lines I will get the expected output of file names.
According to documentation and Ionide tooltips the !! should return a sequence of file names. Can someone advise me what I might be doing wrong?
P.S. I'm using Fake 5.3.1 installed using dotnet tool install fake-cli -g
UPD. I don't have any solution for this issue. It resolved itself after Windows 10 got an update and I removed Nuget package caches in %HOMEPATH\.nuget, %HOMEPATH%\AppData\Local\Nuget, and deleted .fake folder and lock file in the same folder as FAKE script and then reran script again.
If you are still facing similar issue developers ask for extended log fake -vv run <yourScriptName>.fsx after you clear all the caches, and archived contents of %HOMEPATH%\.nuget\packages\netstandard.library after this run.
Just for completeness sake, the reported issue can be found here: https://github.com/fsharp/FAKE/issues/2062
If anyone encounters this issue please open a new issue (and link the old one) and provide the following information:
Can you clean everything and send the output of fake -vv run tryscript.fsx and attach the logfile? Something is indeed fishy with the NetStandard.Library package
Can you also compress and attach the folder C:\Users\.nuget\packages\netstandard.library and then try to delete it (and again create a logfile for that)?
I'd assume this was either a caching issue or an F# compiler bug or both.
I have a situation where in a Fake script I am trying to grab all the unit test dll's from a path using the Glob (!!) operator.
The issue is that on my machine the glob expansion doesn't work, on other similar Windows 10 machines at work, its fine and finds the dlls.
Below is an example:
let path = [function to generate path]
trace path [would look something like "c:\git\project\src\**\*UnitTest*"]
!! path.ToLower()
|> Seq.iter (fun file -> trace file ) [this would not output anything]
I've tried numerous things:
uninstalling older versions of F#
reinstalling the lastest version
ensuring F# is in my Path
The versions of software I am using are:
Fake v4.63.2
Windows 10
F#4.1
No errors or exceptions are thrown.
Whats the best way to trouble shoot if its an F# or a Fake issue?
How could I work out what version of F# Fake is using?
Update
I've reinstalled F# 4.1 and performed a test using fsi.exe with the following command:
Microsoft (R) F# Interactive version 4.1
<snip>
#r #"packages/FAKE/tools/FakeLib.dll";;
open Fake;;
!! "**\*UnitTests.dll" |> Seq.iter (fun x -> trace x);;
C:\git\project1\bin\Debug\project1.UnitTests.dll
C:\git\project2\bin\Debug\project2.UnitTests.dll
!! "**\*UnitTests.dll".ToLower() |> Seq.iter (fun x -> trace x);;
C:\git\project1\bin\Debug\project1.UnitTests.dll
C:\git\project2\bin\Debug\project2.UnitTests.dll
All the test dlls were found, both with and without the call to ToLower().
When I remove the ToLower() from the script, it now works on my machine.
However, on other peoples machines removing ToLower() on the path causes them not to find any files.
So, is Fake using a different version of the fsi.exe?
I've opened a github issue to see if that sheds any light on it: https://github.com/fsharp/FAKE/issues/1772
In F# as in all .NET languages, the backslash is used for escape sequences in strings.
You need to escape the backslash or use a verbatim string, eg :
let path = "c:\\git\\project\\src\\**\\*UnitTest*"
or
let path = #"c:\git\project\src\**\*UnitTest*"
Fake can work with forward slashes as well :
let path = "c:/git/project/src/**/*UnitTest*"
You'll have to use forward slashes anyway if you want your build script to run on Linux.
An even better option is to use relative paths. Your build script most likely is stored in your project folder. You can write
let path = "src/**/*UnitTest*"
Using the following script, I was able to reproduce the issue and work out that the issue was due to how Windows 10 handles the original casing of the company name, in the path.
I confirmed this by changing company name to ** in the file path expression, the operator worked and found all the dlls.
I remember changing the capitalisation of the company name, from all caps to lower case. If I remove the ToLower() on the path, then the script works fine and finds all the dlls.
This hidden issue, combined with how FAKE does a case sensitive search, doesn't help either.
Powershell
packages\FAKE\tools\FAKE.exe glob.test.fsx
glob.test.fsx
#r #"packages/FAKE/tools/FakeLib.dll"
open Fake
let thePath = """C:\git\company/projectname/**/bin/Debug/*UnitTests.dll"""
sprintf "the path is %s" thePath |> trace
!! thePath.ToLower() |> Seq.iter (fun f -> trace f)
I had a look at the process executing in ProcMon and did not see the original casing of the directory. The NTFS file system is still see this directory as its original casing (see comments below).
I re-image my machine every few months, so this will disappear soon but it was good to understand what was going on.
Thanks to all those that helped narrow the issue down.
I am using FxCop in FAKE but it is giving an error
i.e.
Analysis was not performed; at least one valid rules assembly and one valid target file must be specified.
* 1 total analysis engine exceptions.
While all targets are successfully build.
here is my code :
Target "FxCop" (fun _ ->
!! (buildDir + "/**/*.dll")
++ (buildDir + "/**/*.exe")
|> FxCop (fun p ->
{p with
//Override default parameters
ReportFileName = testDir + "FXCopResults.xml";
ToolPath = "D:/Fake/FAKE-Calculator/tools/FxCop/FxCopCmd.exe"})
)
It also shows : Project error : No targets were selected .
The FAKE documentation doesn't make it clear enough, but apparently you need to explicitly specify one of two things:
Which FxCop rules you want to run, or
The path to an "FxCop project file" (a file with the .FxCop extension).
I can't tell you how to write an FxCop project file since I've never done so myself, but maybe the programmer who set up the MsBuild system you've working with already did so. If he did, then you just need to add the following parameter to your FxCop call in your FAKE build script:
ProjectFile = buildDir </> "filename.FxCop"
where filename, of course, should be replaced by a real file name.
If you don't have an FxCop project file, then apparently you have to explicitly specify a list of FxCop rules in the RuleLibraries parameter. First, you need to find out which FxCop rules are available. To do that, look in your FxCop installation directory (on my system, where I have an older version of FxCop installed, it was C:\Program Files (x86)\Microsoft FxCop 1.36, but it may be different for you) for a Rules folder. That folder should contain several DLLs; for example, on my system, the Rules folder contained:
DesignRules.dll
GlobalizationRules.dll
InteroperabilityRules.dll
... and several other DLLs that I'm not going to bother typing out. Now you just make that list of filenames into an F# list:
RulesLibraries = ["DesignRules.dll"; "GlobalizationRules.dll"] // and so on
There should be sensible defaults for that, but currently it looks like you have to specify that list of rules by hand. So try writing your target to look something like this:
Target "FxCop" (fun _ ->
!! (buildDir + "/**/*.dll")
++ (buildDir + "/**/*.exe")
|> FxCop (fun p ->
{p with
//Override default parameters
ReportFileName = testDir + "FXCopResults.xml";
RulesLibraries = ["DesignRules.dll"; "GlobalizationRules.dll"] // etc.
ToolPath = "D:/Fake/FAKE-Calculator/tools/FxCop/FxCopCmd.exe"})
)
Remember to separate your list items with ; (semicolon): in F#, the , (comma) character is ONLY for tuples. And don't just copy my example verbatim, but actually look in your FxCop installation directory to see what rule DLLs are available, and include those. (As many, or as few, as your project actually needs).
Also, I don't know if you actually have to specify the .dll extension; you might be able to use ["DesignRules"; "GlobalizationRules"] (and so on). But it's probably just as simple to use the .dll extension and just copy and paste from the filenames.
I haven't tested this myself, so I hope this works for you. If it doesn't, let me know.
I created a standalone console application using the yo fsharp generator. The github repo concerning this particular question is here: https://github.com/KurtRMueller/PascalsTriangleKata.
I'd like to build and run some basic FsCheck.Xunit tests. I'm aware that I need to add some targets to FAKE's build.fsx, but as I'm quite new to .net and the C#/F# ecosystem, I don't know how to do that.
The example from the FAKE example page is as follows:
// define test dlls
let testDlls = !! (testDir + "/Test.*.dll")
Target "xUnitTest" (fun _ ->
testDlls
|> xUnit (fun p ->
{p with
ShadowCopy = false;
HtmlOutput = true;
XmlOutput = true;
OutputDir = testDir })
)
I'm not quite sure how to build the these Test dlls.
Any help is appreciated. Thanks.
I'm trying to create FAKE(F# Make) build target that will update AssemblyInfo files in my project after sucsess build. Version info files are stored in TFS CVS, so I need to checkin updated files to TFS from FAKE build task.
Using TFS 2010, call FAKE from custom activity.
My flow is:
- ... cleanup, call build target
- Update AssemblyInfo files
- Check-in files to TFS
Faced with check-in to TFS issues...
Is there any way to check-in to TFS from FAKE (F# Make) target?
Yes, but this will come in two parts. Also, this is working for TFS 2015 new Build Definitions and TFS Git repository. You can modify this as necessary to fit your particular situation. These two targets can be called as you wish.
Part I - Update the AssemblyInfo files
let AssemblyInfoFiles = !! #"src\**\AssemblyInfo.cs";
Target "SetVersions" (fun _ ->
AssemblyInfoFiles
|> Seq.iter (fun a ->
if tfBuildNumber <> null then
if isLocalBuild = false then
UpdateAttributes a [ Attribute.FileVersion tfBuildNumber]
)
)
Part II - Check in the modified AssemblyInfo file(s)
let CheckInMessage = "Files related to versioning where checked in. ***NO_CI***"
let tfBuildSourceBranchName = environVar "BUILD_SOURCEBRANCHNAME"
let tfBuilderRepositoryProvider = environVar "BUILD_REPOSITORY_PROVIDER"
Target "CheckinFiles" (fun _ ->
AssemblyInfoFiles
|> Seq.iter (fun a ->
//This is for GIT REPOSITORY in TFS 2015 Build Definition
if isLocalBuild = false && tfBuilderRepositoryProvider = "TfsGit" then
checkoutBranch solutionDir tfBuildSourceBranchName
trace ("File to stage: " + a)
StageFile solutionDir a |> ignore
Commit solutionDir CheckInMessage
pull solutionDir "origin" tfBuildSourceBranchName
push solutionDir
)
)
The problem with Part II is that it does a commit for EACH AssemblyInfo, whereas I would like to batch these in one single commit. I can do that, I'm just lazy to fix it.