FAKE 5 Migration Cheat Sheet
Happy holidays everyone!
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" )
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"
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
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" ""
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
let myKey = Environment.environVarOrDefault "myKey" ""
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
And then in build.fsx:
Target.create "Foo" (fun p -> printfn "args: %A" p.Context.Arguments printfn "%A " p ) Target.runOrDefaultWithArguments "Foo"
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"
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()
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 "/"
ProcessHelper.tryFindFileOnPath
// ======================================= // Before // ======================================= let fooExe = ProcessHelper.tryFindFileOnPath "foo" // ======================================= // After // ======================================= open Fake.Core let fooExe = // From the nuget package Fake.Core.Process ProcessUtils.tryFindFileOnPath "foo"
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
CleanDirs
// ======================================= // Before // ======================================= // Auto-opened from Fake.FileHelper CleanDirs [exampleDir] // ======================================= // After // ======================================= open Fake.IO //From the nuget package Fake.IO.FileSystem Shell.cleanDirs [deployDir]
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"
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" )
Top comments (3)
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?
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.
Thanks, great article... It saved me hundreds of hours searching for the right migration
Patricia