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