My Take on FAKE in 2020

I’ve been using FAKE since roughly 2009 when Steffen Forkmann first introduced it. I’ve used it for OSS and work projects, builds and deployments, and even committed features to it. I think FAKE is a fantastic tool, and I loved the changes that came in FAKE 5.

However, I’ve been reconsidering my use of FAKE as a default build scripting tool in smaller projects and wanted to write up my reasons for switching to dotnet CLI builds for new projects and migrating some OSS projects to do the same.

Build Script

I have always thought FAKE was quite easy to set up for a project, as you can see from the Getting Started page. With the addition of installation as a dotnet local tool, it’s really easier than ever. However, compare that with the following:

dotnet restore
dotnet build --no-restore -c Release
dotnet test --no-restore --no-build -c Release
dotnet pack --no-restore --no-build -c Release -o bin --include-symbols

I can run that from the command line or put it into a script or .yml file for use in a CI/CD tool. It’s simple, consistent, and portable without trying hard. It’s certainly simpler than even a simple FAKE script.

Versioning

I have used several methods for managing version is my FAKE scripts in the past. I generally copied the same set of functions from project to project. Note: that’s functions, plural. In the past, this required setting up things for modifying AssemblyInfo, but with the introduction of VersionPrefix, Version, and VersionSuffix in the .*proj formats, managing this with a Directory.Build.props and a little bit of PowerShell, which is also cross-platform, is even simpler. Here’s an example from the FSharp.Control.Reactive project:

[xml]$doc = Get-Content .\src\Directory.Build.props
$version = $doc.Project.PropertyGroup.VersionPrefix # the version under development, update after a release
$versionSuffix = '-build.0' # manually incremented for local builds

function isVersionTag($tag){
    $v = New-Object Version
    [Version]::TryParse($tag, [ref]$v)
}

if ($env:appveyor){
    $versionSuffix = '-build.' + $env:appveyor_build_number
    if ($env:appveyor_repo_tag -eq 'true' -and (isVersionTag($env:appveyor_repo_tag_name))){
        $version = $env:appveyor_repo_tag_name
        $versionSuffix = ''
    }
    Update-AppveyorBuild -Version "$version$versionSuffix"
}

dotnet tool restore
dotnet build -c Release /p:Version=$version$versionSuffix
dotnet test --no-build -c Release tests
dotnet pack --no-restore -c Release /p:Version=$version$versionSuffix -o $psscriptroot/bin

Feel free to disagree. I don’t love PowerShell like I love F#, but this is a worthwhile tradeoff for me.

Release Notes

The one thing that kept me with FAKE the longest was its excellent support for managing versions and release notes with its RELEASE_NOTES.md support. I recently stumbled across a post describing how to manage release notes outside of a .*proj file. While I don’t love using MSBuild tasks, this is another one where the benefits outweigh the cost. The nice thing here is that I’m able to include this once in my Directory.Build.props file and have it apply to all of the packaged .nupkgs. Here’s the relevant snippet from the FSharp.Control.Reactive project:

  <Target Name="PreparePackageReleaseNotesFromFile" BeforeTargets="GenerateNuspec">
    <ReadLinesFromFile File="..\..\RELEASE_NOTES.md">
      <Output TaskParameter="Lines" ItemName="ReleaseNoteLines" />
    </ReadLinesFromFile>
    <PropertyGroup>
      <PackageReleaseNotes>@(ReleaseNoteLines, '%0a')</PackageReleaseNotes>
    </PropertyGroup>
  </Target>

This will put the full contents of the RELEASE_NOTES.md file into my FSharp.Control.Reactive.*.nupkg package. I still need to do a little work to take only the relevant lines for the current version, I don’t mind the simplicity.

What’s Left for FAKE?

With all of the above, you may wonder whether there is anything for which I would still use FAKE. I certainly continue to use FAKE for many other purposes. Here’s a list of things for which I continue to use FAKE:

FAKE is a really good tool, and I still highly recommend it. I think the team working on it is doing a great job, and if the things I describe above are not trade-offs you are willing to make, then by all means stick with FAKE.

What do you think? Agree or disagree with any of the directions I’ve taken above? I’m open to changing my mind on these things, and I would love to hear your opinions. Leave a comment!

One thought on “My Take on FAKE in 2020

Comments are closed.