DEV Community

Jeremy Abbott
Jeremy Abbott

Posted on

FAKE 5 Migration Cheat Sheet

FAKE 5 Migration Cheat Sheet

Happy holidays everyone!

Pikachu in a Santa hat

When you start migrating from FAKE 4 and FAKE 5, you'll find that a simply opening the FAKE namespace isn't enough. Also, if like me, deprecation warnings drive you mad, you'll want to get rid of them as quickly as possible. I made the following cheat sheet to expedite your FAKE migration (and to help me update the other scripts I still need to update.)

Function/Module changes

Below are the functions I've had to update more than once. Most of them at least require referencing a nuget package and/or opening a module that you didn't have to open before.

Each of the following headers is the name of a FAKE 4 function. The snippet that follows shows how it is used in FAKE 4 followed by how to accomplish the same task in FAKE 5.

Target

// =======================================
// Before
// =======================================

Target "Foo" (fun _ -> 
    printfn "Foo to the Bar"
)

// =======================================
// After
// =======================================

open Fake.Core // From the Fake.Core.Target nuget package

Target.create "Foo" (fun _ ->
    printfn "Foo to the Bar"
)

Enter fullscreen mode Exit fullscreen mode

Target Operators

All of the FAKE custom operators are in their own modules now.

open Fake.Core.TargetOperators // From the Fake.Core.Target nuget package
"Clean"
    ==> "Restore"
    ==> "Build"
Enter fullscreen mode Exit fullscreen mode

Important: FAKE 4 Target operators (from FakeLib) do not work with FAKE 5 targets (and vice versa). That means converting Targets to FAKE 5 means using the operators from FAKE 5.

FullName

// =======================================
// Before
// =======================================

let path = "./foo" |> FullName // Auto-opened from Fake.FileSystemHelper

// =======================================
// After
// =======================================

open Fake.IO 

let path = "./foo" |> Path.getFullName // From the Fake.IO.FileSystem the nuget package 
Enter fullscreen mode Exit fullscreen mode

getBuildParam

// =======================================
// Before
// =======================================

// In FAKE 4 getBuildParam implicitly called getBuildParamOrDefault with empty string as the default

let userName = getBuildParam "userName" // Auto-opened from Fake.EnvironmentHelper

// =======================================
// After
// =======================================

open Fake.Core

let userName = 
    // From nuget package Fake.Core.Environment
    Environment.environVarOrDefault "UserName" ""
Enter fullscreen mode Exit fullscreen mode

Some Extra Notes

Passing arguments to your FAKE script is a little different in FAKE 5. In FAKE 4 you may have had something like

./build.sh <targetName> <buildParam>=foo, you now have a couple of different options, depending on your use case:

# create an environment variable that's scoped to the current shell session.
export myKey="my value"
./build.sh build
Enter fullscreen mode Exit fullscreen mode
let myKey = Environment.environVarOrDefault "myKey" ""
Enter fullscreen mode Exit fullscreen mode

If you want to pass arguments on the command line, you have to pass them with the following syntax:

# using the FAKE dotnet CLI tool
fake run build.fsx -t build --arg
Enter fullscreen mode Exit fullscreen mode

And then in build.fsx:

Target.create "Foo" (fun p ->
    printfn "args: %A" p.Context.Arguments

    printfn "%A " p
)

Target.runOrDefaultWithArguments "Foo"
Enter fullscreen mode Exit fullscreen mode

You need to use Target.runOrDefaultWithArguments instead of Target.runOrDefault to access arguments this way. Additionally, the target function signature is now string -> TargetParameter -> unit -> unit. You have to use the TargetParameter (p in the example above) to get access to it. Context.Arguments is a string list. You can use the module Fake.Core.CommandLineParsing to parse the target arguments.

parseAllReleaseNotes

// =======================================
// Before
// =======================================
open Fake.ReleaseNotesHelper

let releaseNotes = File.ReadAllLines "RELEASE_NOTES.md"

let releaseNotesData =
     releaseNotes
     |> parseAllReleaseNotes

let release = List.head releaseNotesData

// =======================================
// After
// =======================================

open Fake.Core

let release = 
    // From Fake.Core.ReleaseNotes nuget package
    ReleaseNotes.load "RELEASE_NOTES.md"
Enter fullscreen mode Exit fullscreen mode

SemVerHelper.parse

// =======================================
// Before
// =======================================

let packageVersion = SemVerHelper.parse release.NugetVersion // From Fake.SemVerHelper

// =======================================
// After
// =======================================

open Fake.Core
let semVer =
    // From Fake.Core.SemVer nuget package
    SemVer.parse release.NugetVersion
printfn "semver.Parse: %s" <| semVer.ToString()


Enter fullscreen mode Exit fullscreen mode

isUnix

// =======================================
// Before
// =======================================

let pathSep = if isUnix then """\""" else "/" // From Fake.EnvironmentHelper

// =======================================
// After
// =======================================
open Fake.Core

let pathSep = 
    // From the nuget package Fake.Core.Environment
    if Environment.isUnix then """\""" else "/"
Enter fullscreen mode Exit fullscreen mode

ProcessHelper.tryFindFileOnPath

// =======================================
// Before
// =======================================

let fooExe = ProcessHelper.tryFindFileOnPath "foo"

// =======================================
// After
// =======================================

open Fake.Core

let fooExe =
    // From the nuget package Fake.Core.Process
    ProcessUtils.tryFindFileOnPath "foo" 
Enter fullscreen mode Exit fullscreen mode

DotNetCli.GetDotNetSDKVersionFromGlobalJson()

// =======================================
// Before
// =======================================

let dotnetcliVersion = DotNetCli.GetDotNetSDKVersionFromGlobalJson()

// =======================================
// After
// =======================================

open Fake.DotNet

// After
// From the nuget package Fake.DotNet.Cli
// In the namespace Fake.DotNet and module DotNet
let dotnetcliVersion = DotNet.CliVersion.GlobalJson
Enter fullscreen mode Exit fullscreen mode

CleanDirs

// =======================================
// Before
// =======================================

// Auto-opened from Fake.FileHelper
CleanDirs [exampleDir]

// =======================================
// After
// =======================================

open Fake.IO

//From the nuget package Fake.IO.FileSystem
Shell.cleanDirs [deployDir] 
Enter fullscreen mode Exit fullscreen mode

ExecProcess / Shell.Exec

// =======================================
// Before
// =======================================

let result = Shell.Exec("foo", "--version")
if result <> 0 failwith "boom"

// =======================================
// After
// =======================================

open Fake.Core

let result =
    // From the NuGet Package Fake.Core.Process
    CreateProcess.fromRawCommand "dotnet" ["--info"]
    |> Proc.run
if result.ExitCode <> 0 then failwith "boom"

Enter fullscreen mode Exit fullscreen mode

build

// =======================================
// Before
// =======================================
open Fake

Target "MSBuild" (fun _ ->
    let setMsBuildParams defaultParams =
        { defaultParams with
            Targets=["Build"]
            Properties = ["Configuration", "Debug"]
        }
    // Auto-opened from Fake.MSBuildHelper
    build setMsBuildParams "Foo.sln"
)

// =======================================
// After
// =======================================

open Fake.DotNet

Target.create "MSBuild" (fun _ ->
    let setMsBuildParams defaultParams =
        { defaultParams with
            Targets=["Build"]
            Properties = ["Configuration", "Debug"]
        }
    MSBuild.build setMsBuildParams "Foo.sln"
)
Enter fullscreen mode Exit fullscreen mode

Discussion (3)

Collapse
thorium profile image
Tuomas Hietanen

Thanks great article. The only minor typo was in wrong pathSep, but you can get the correct one from Path.DirectorySeparatorChar (off-topic anyway). Is Fake5 focused for .NET Core, or should you consider migrating an old .NET Framework full application also?

Collapse
jeremyabbott profile image
Jeremy Abbott Author

Thank you for the feedback! I didn't know about Path.DirectorySeparatorChar

I would consider migrating regardless of which flavor of .NET you're using. FAKE 5 includes MSBuild and NuGet APIs. The FAKE runner is a dotnet SDK global tool, but that doesn't mean it can't be used with scripts written for .NET Framework applications.

Collapse
patriba profile image
Patricia dos Santos Pastorelli

Thanks, great article... It saved me hundreds of hours searching for the right migration

Patricia