Local NuGet source + creating packages with FAKE - f#

I've been trying to configure my local NuGet source so as to put there my own packages. So I created a folder and set up the path in Visual Studio - this works fine.
Currently I've got a problem with creating a package with FAKE. The nupkg file gets successfully created, but when I try to add a reference to it from another project, nothing happens (i.e. VS says the package was successfully added, but I can't see it under the "References").
My example project has the following structure:
-- root
-- MyProject (project type: F# library)
-- MyProject.Test (Xunit)
build.bat
build.fsx
MyProject.nuspec
MyProject.sln
And I'd like my NuGet package to contain functions defined in MyProject (It doesn't have any additional dependenties, apart from the "traditional" ones as FSharp.Core).
The content of .nuspec file is as follows:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<id>#project#</id>
<version>#build.number#</version>
<authors>#authors#</authors>
<owners>#authors#</owners>
<summary>#summary#</summary>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>#description#</description>
<releaseNotes>#releaseNotes#</releaseNotes>
#dependencies#
#references#
</metadata>
<files>
<file src="**\*.*" exclude="**\*.pdb;**\*.xml" />
</files>
</package>
The build.fsx file is quite long, so I'll paste only piece of it, that is responsible for creating a package (shout if more content is needed):
let buildDir = #".\build\"
let testDir = #".\test\"
let deployDir = #".\deploy\"
let nugetDir = #".\nuget\"
Target "CreateNuget" (fun _ ->
XCopy buildDir nugetDir
"MyProject.nuspec"
|> NuGet (fun p ->
{p with
Authors = authors
Project = projectName
Description = projectDescription
Version = version
NoPackageAnalysis = true
OutputPath = nugetDir
})
)
Target "Publish" (fun _ ->
!! (nugetDir + "*.nupkg")
|> Copy deployDir

Because your files aren't put into the correct target folder in the nuget package, nuget doesn't know you want to reference them.
You need to change your files so that they put the dlls you want to reference into a lib folder in your nuget package for example:
<files>
<file src="directory\MyProject.dll" target="lib" />
</files>
or from FAKE itself:
Nuget(
{ p with
Files = [#"directory\MyProject.dll", Some #"lib", None] })
(but if you want to do it from FAKE you'll have to replace the files config section in your nuspec file with ##files##.

Related

Where does Ionide + Fake put the output executable?

I am trying to use .NET Core + Ionide + VS Code + Fake + Paket on macOS High Sierra.
Using the project generator, I have created a Suave application called Test. Ionide seems to have generated the appropriate files. After tweaking the TargetFramework to .NET Core, I can build successfully:
$ ./build.sh
...
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:03.72
Finished Target: Build
---------------------------------------------------------------------
Build Time Report
---------------------------------------------------------------------
Target Duration
------ --------
Clean 00:00:00.0026904
InstallDotNetCLI 00:00:01.2292511
Restore 00:00:04.2731055
Build 00:00:07.1234434
Total: 00:00:12.7035334
---------------------------------------------------------------------
Status: Ok
---------------------------------------------------------------------
There are now some files in Test/bin, but none of them are .exe, which is what I would expect as output from fsharpc.
Where does Ionide + Fake put the output executable?
My project has OutputType executable:
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Test.fs" />
</ItemGroup>
<Import Project="..\.paket\Paket.Restore.targets" />
</Project>
.Net Core compiles all projects (even executable applications) to .dll not .exe that can be run with dotnet PATH_TO_DLL. In the bin folder, in the subfolder for given framework target there should be file YOUR_PROJECT_NAME.dll that can be run with dotnet CLI.
To generate an exe you need to supply a run-time identifier. You can include this in the fsproj with
<PropertyGroup>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
</PropertyGroup>
but you don't need to do that. You can use VSCode's tasks.json file to set up a build task.
My suggestion is just to run the dotnet CLI:
dotnet build -c Release -r win10-x64
This will create an exe in the bin\release\netcoreapp2.0\win10-x64 folder. You can also dotnet publish if you want a self-contained directory to deploy (this can get large). The id for OSX will be something like osx-x64.
By default ionide generates an fsproj file that is targetting net461, and you might also need Fake 5 for dotnetcore. I also suggest you use paket in magic-mode, and commit the .exe to github (if you use git).

F# How to setup FAKE project that can use FsUnit

I'm trying to setup a basic FAKE F# project that can run FsUnit but I cannot figure out how to solve the Method not found: 'Void FsUnit.TopLevelOperators.should(Microsoft.FSharp.Core.FSharpFunc`2<!!0,!!1>, !!0, System.Object)' errors.
I have read the following posts that seem to be related, but I'm apparently still not grokking it:
Main github issue
FSharp.Core packaging guidelines
FsUnit unable to test portable library (SO)
Another github issue
I have created a JunkTest library project with the following setup:
paket.dependencies
source https://www.nuget.org/api/v2
nuget FAKE
nuget FSharp.Core
nuget FsUnit
nuget NUnit
nuget NUnit.Console
paket.references
FSharp.Core
FsUnit
NUnit
JunkTest.fs
module JunkTest
open FsUnit
open NUnit.Framework
[<Test>]
let ``Example Test`` () =
1 |> should equal 1 // this does not work
//Assert.That(1, Is.EqualTo(1)) // this works (NUnit)
build.fsx (relevant part)
Target "Test" (fun _ ->
!! (buildDir + "JunkTest.dll")
|> NUnit3 (fun p ->
{p with OutputDir = "TestResults" }
)
)
Output
I see that FSharp.Core.dll is being copied from the local packages directory: Copying file from "c:\Users\dangets\code\exercism\fsharp\dgt\packages\FSharp.Core\lib\net40\FSharp.Core.dll" to "c:\Users\dangets\code\exercism\fsharp\dgt\build\FSharp.Core.dll".
And the nunit3-console execution: c:\Users\dangets\code\exercism\fsharp\dgt\packages\NUnit.ConsoleRunner\tools\nunit3-console.exe "--noheader" "--output=TestResults" "c:\Users\dangets\code\exercism\fsharp\dgt\build\JunkTest.dll"
I have tried to add a app.config file with the in the test project root directory with the following but it doesn't seem to solve the issue (NOTE I am not using Visual Studio - do I need to do anything special for the project to include the app.config file?):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.3.1.0" newVersion="4.3.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Any and all help is appreciated.
EDIT: The solution was that I was not properly setting up the App.config file to get included in the build. All of the answers that said "just add this to your App.config file" didn't help me because VSCode doesn't add this to the fsproj file automatically.
The part that I added is:
<None Include="App.config" />
In the ItemGroup that contains the other <Compile Include=Foo.fs> lines.
This happens because of FSharp.Core version mismatch. See, your application references one version of FSharp.Core and FsUnit references another version. This means that the FSharpFunc<_,_> type is going to be different (coming from different assemblies) for you and FsUnit, which in turn means that the should function exported by FsUnit is not the same function that your code is looking for, because it has a parameter of a different type.
This is where the bindingRedirect comes in. You're absolutely correctly added it to app.config, but from your question about whether you're doing it correctly, I get a suspicion that you might not. The thing with app.config is, it's not actually the program configuration. Rather, it's the source code for program configuration. At compile time, this file gets copied to bin\Debug\Your.Project.dll.config, and only then it will get picked up at runtime. If you didn't add this file to the fsproj project file (which, I suspect, might be the case), then it's not getting copied to the right place during build, and thus isn't getting picked up at runtime.
Another reason for it still not working may be that you've specified an incorrect version of FSharp.Core in your app.config file. Which brings me to the next point.
Crafting that file by hand is a bit fragile: when you upgrade FSharp.Core to a new version (or Paket does it for you), you may forget to fix it in app.config and even if you don't, it's a bit of a hassle. But Paket can help you with that: if you add the redirects: on options to your paket.dependencies file, Paket will add the bindingRedirect cruft to your app.config automatically:
source https://www.nuget.org/api/v2
nuget FAKE
nuget FSharp.Core redirects: on
nuget FsUnit
nuget NUnit
nuget NUnit.Console
This sounds like an FSharp.Core version mismatch.
The NuGet package you're using ships with FSharp.Core 4.4 (not 4.3.1). I recommend modifying your binding redirect to use 4.4:
<bindingRedirect oldVersion="0.0.0.0-4.3.1.0" newVersion="4.4.0.0" />

Getting an error during the deploying webapplication "Could not open Source file: Could not find a part of the path"

I got an error during the deploying my web-application.
The title of error is Could not open Source file: Could not find a part of the path
'Could not open Source file: Could not find a part of the path
'E:\ARCHIVES\Projects\Main\Jahan.Handicraft\Jahan.Handicraft.Web.Mvc.UmbracoCms.App\obj\Release\AspnetCompileMerge\TempBuildDir\App_Plugins\UmbracoForms\Data\Web.config;\App_Plugins\UmbracoForms\Data\Web.config'.'.
I've used Umbraco 7.4.3 und ASP.NET MVC in my project.
I'd like deploy it on localhost.
How can I solve this problem?
This is a failed attempt at transforming connection strings in sublevel configurations files.
To disable this transformation, edit the publish profile under Properties\PublishProfiles and set the value of the AutoParameterizationWebConfigConnectionStrings element to false. Add the element if missing.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!--
...
Other settings
...
-->
<AutoParameterizationWebConfigConnectionStrings>false</AutoParameterizationWebConfigConnectionStrings>
</PropertyGroup>
</Project>
I got it from this blog (which is not mine): http://blog.aabech.no/archive/web-deploy-says-could-not-open-source-file-some-webconfig-when-you-publish-an-umbraco-site/
Post installation
You should note that the Umbraco nuget package adds a build step to always include the Umbraco folders when you deploy using Web One-Click Publish with Visual Studio.
You can see these folders in packages/UmbracoCms x.y.z/build/UmbracoCms.targets
Should you need to exclude any of these folders or content, you can add a target to your .pubxml files in the properties/Publish folder. For instance if you need to exclude json data a plugin generates during production.
<Target Name="StopUmbracoFromPublishingAppPlugins" AfterTargets="AddUmbracoFilesToOutput">
<ItemGroup>
<FilesForPackagingFromProject Remove=".\App_Plugins\UmbracoForms\Data\**\*.*"/>
</ItemGroup>
</Target>
Reference: https://our.umbraco.org/documentation/Getting-Started/Setup/Install/install-umbraco-with-nuget#post-installation

F#'s Scaffold and FsUnit/FsCheck

I'm struggling to get started with F# on Linux using ProjectScaffold.
Specifically: I can't get a project to work with FsUnit/FsCheck/xunit. I
have F# 3.1 and mono 3.12.1 and I'm on Linux (Ubuntu) x64.
I start "MyProject" with:
$ git clone --depth=1 git#github.com:fsprojects/ProjectScaffold.git
$ cd ProjectScaffold && ./build.sh
Then I add a bit of code to "src/MyProject/Library.fs":
module MyProject.X
let four = 4
And then two tests to "tests/MyProject.Tests/Tests.fs":
module MyProject.Tests.X
open Xunit
open FsUnit.Xunit
open FsCheck
open FsCheck.Xunit
open MyProject.X
[<Fact>]
let ``Two plus two is four.`` () =
2 + 2 |> should equal four
[<Property>]
let ``Sorting a sorted list is idempotent.`` (l: int list) =
let s = List.sort l
s = List.sort s
This code works on Visual Studio where I manually added FsCheck, FsUnit, anx xunit 1.9.2 (it fails with later version
for some reason). My test project on Windows/Visual Studio has this config file:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FsCheck" version="1.0.4" targetFramework="net45" />
<package id="FsCheck.Xunit" version="1.0.4" targetFramework="net45" />
<package id="FsUnit.xUnit" version="1.3.0.1" targetFramework="net45" />
<package id="xunit" version="1.9.2" targetFramework="net45" />
<package id="xunit.runner.visualstudio" version="2.0.0" targetFramework="net45" />
</packages>
So I edit paket.dependencies to add these packages and remove Nunit:
source https://nuget.org/api/v2
nuget FSharp.Formatting 2.8.0
nuget FSharpVSPowerTools.Core 1.7.0
nuget FAKE
nuget FsCheck 1.0.4
nuget FsCheck.Xunit 1.0.4
nuget FsUnit.xUnit 1.3.0.1
nuget xunit 1.9.2
nuget SourceLink.Fake
github fsharp/FAKE modules/Octokit/Octokit.fsx
Then:
$ mono .paket/paket.exe install
...and it fails because NUnit is referenced somewhere, so I delete the references in tests/MyProject.Tests/paket.references and
$ mono .paket/paket.exe install
works, but
$ ./build.sh
fails, at it cannot find references to FsCheck et al. So I assume that I need to add the references manually, so tests/MyProject.Tests/paket.references is now:
FsCheck
FsCheck.Xunit
FsUnit.xUnit
xunit
...built build.sh fails again: it cannot find FsCheck. I could not find in the paket doc how to add a local dependency (MyProject.Tests should reference MyProject), it might be done automatically.
I had this problem and it took a while for me to figure out a fix. For the project file in the Tests directory, I had to change this:
<Reference Include="FsUnit.NUnit">
<HintPath>..\..\packages\FsUnit.1.3.0.1\Lib\Net40\FsUnit.NUnit.dll</HintPath>
<Private>True</Private>
</Reference>
To this:
<Reference Include="FsUnit.NUnit">
<HintPath>..\..\packages\FsUnit\Lib\Net40\FsUnit.NUnit.dll</HintPath>
<Private>True</Private>
</Reference>
Similarly, for NUnit:
<Reference Include="nunit.framework">
<HintPath>..\..\packages\NUnit.2.6.3\lib\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
To:
<Reference Include="nunit.framework">
<HintPath>..\..\packages\NUnit\lib\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
The issue is that on mono, the packages don't have the version in the path but under Visual Studio they do. Once I found this fix, I created two .fsproj files for the tests and I modified the build.sh script to swap the mono-compatible one in when under mono via:
#!/bin/bash
if test "$OS" = "Windows_NT"
then
# no changes in here
else
# fix test fsproj file
mv tests/ProjectName.Tests/ProjectName.Tests.fsproj tests/ProjectName.Tests/ProjectName.Tests.fsproj.vs
mv tests/ProjectName.Tests/ProjectName.Tests.fsproj.mono tests/ProjectName.Tests/ProjectName.Tests.fsproj
# leave the script logic for mono in place
# put project files back to avoid git noticing the swap
mv tests/ProjectName.Tests/ProjectName.Tests.fsproj tests/ProjectName.Tests/ProjectName.Tests.fsproj.mono
mv tests/ProjectName.Tests/ProjectName.Tests.fsproj.vs tests/ProjectName.Tests/ProjectName.Tests.fsproj
fi
Once I made these changes the project works fine under both Visual Studio as well as mono.
I am not quite sure, I understand you: Do you have two fsproj files, one for the production code and one for the unit tests? And are you referencing FsCheck in the fsproj?
Plus, I remember an issue, where if you compile against an older version of .net and reference an assembly compiled against a newer version of .net, it will behave as though there was no reference.

Adding files to the bin directory at Build and Publish

I have two license files that I would like to include in my \bin directory both when I build and publish.
Both files are in the App_Data directory (their initial location doesn't matter, they just need to end up in the \bin) and have the following properties set:
Build Action = Content
Copy to Output Directory = Copy Always
They are in not the \bin when I build or publish.
What is wrong with my setup: the settings, the folders, the files, something else...?
UPDATE
I moved the files out of the App_Data directory and placed them in the project root and now they are copied to the \bin on build.
I've done this in a few projects by expanding my .csproject file slightly. The following code should be put directly beneath the Project node in your WebProject.csproj.
The AfterBuild target simply copies a set of files ("unreferenced DLLs" in this case) to the bin-folder when building normally from Visual Studio. The CustomCollectFiles basically do the same thing when deploying.
<PropertyGroup>
<UnreferencedDlls>..\lib\Unreferenced\**\*.dll</UnreferencedDlls>
</PropertyGroup>
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="AfterBuild">
<Message Text="Copying unreferenced DLLs to bin" Importance="High" />
<CreateItem Include="$(UnreferencedDlls)">
<Output TaskParameter="Include" ItemName="_UnReferencedDLLs" />
</CreateItem>
<Copy SourceFiles="#(_UnReferencedDLLs)" DestinationFolder="bin\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>
<Target Name="CustomCollectFiles">
<Message Text="Publishing unreferenced DLLs" Importance="High" />
<ItemGroup>
<_CustomFiles Include="$(UnreferencedDlls)" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>bin\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
The part you need to modify is basically the UnreferencedDlls node to match your folder structure. The **\*.dll part simply means "every DLL file at any level beneath here".
If you're using Visual Studio:
Show your file properties (Click on your file or Right-click on it then choose Properties)
At the Copy to Output Directory property choose Copy always or Copy if newer.
At build time, the file is going to be copied at the bin directory: Debug or Release...
not necessarily a direct answer, but I highly suggest not using the baked in "publish" mechanism, but rather wire up a build script (probably in powershell) that will do everything you need. It's really easy to hook into MSBuild as well as nUnit and also copy files and move them around.
POWERSHELL (rough) example.
# Get Directory Location
$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
# Build the application using MSBuild
cmd /c C:\Windows\Microsoft.NET\Framework\$v4_net_version\msbuild.exe "$directorypath\MyProject.sln" /p:Configuration=Release
# Run the tests using nUnit
cmd /c $directorypath\build\nunit\nunit-console.exe $solutionPath\MyProject.Tests\bin\debug\MyProject.Tests.dll
# Copy the license to the appropriate directory
Copy-Item -LiteralPath "$directorypath\mylicensefile.txt" "$directorypath\bin\release" -Force
# NOTE: You are going to have to adjust this to match your solution and projects.
In this post on Microsoft Connect the answer is much simpler:
Referenced assemblies in Unit Test are not copied in TestResults/Out
So what I did was the following:
[TestClass]
[DeploymentItem("Some.dll")]
public class SomeTests
{
...
}
It works fine for me.
Hope it help.

Resources