Skip to content

Instantly share code, notes, and snippets.

@vbfox
Last active September 8, 2017 08:19
Show Gist options
  • Save vbfox/e3e22d9ffff9b9de7f51 to your computer and use it in GitHub Desktop.
Save vbfox/e3e22d9ffff9b9de7f51 to your computer and use it in GitHub Desktop.
Allow to define FAKE targets with a syntax similar to Gulp tasks
#r "packages/FAKE/tools/FakeLib.dll"
namespace BlackFox
/// Allow to define FAKE tasks with a syntax similar to Gulp tasks
[<AutoOpen>]
module TaskDefinitionHelper =
open Fake
open System
open System.Text.RegularExpressions
type Dependency =
| Direct of dependsOn : string
| Soft of dependsOn : string
let inline private (|RegExp|_|) pattern input =
let m = Regex.Match(input, pattern, RegexOptions.Compiled)
if m.Success && m.Groups.Count > 0 then
Some (m.Groups.[1].Value)
else
None
let inline private parseDependency str =
match str with
| RegExp @"^\?(.*)$" dep -> Soft dep
| dep -> Direct dep
let inline private parseDependencies dependencies =
[
for dependency in dependencies do
yield parseDependency dependency
]
type TaskMetadata = {
name: string
dependencies: Dependency list
}
let mutable private tasks : TaskMetadata list = []
let inline private registerTask meta body =
Target meta.name body
tasks <- meta::tasks
type TaskBuilder(meta: TaskMetadata) =
member __.TryFinally(f, compensation) =
try
f()
finally
compensation()
member __.TryWith(f, catchHandler) =
try
f()
with e -> catchHandler e
member __.Using(disposable: #IDisposable, f) =
try
f disposable
finally
match disposable with
| null -> ()
| disp -> disp.Dispose()
member __.For(sequence, f) =
for i in sequence do f i
member __.Combine(f1, f2) = f2(); f1
member __.Zero() = ()
member __.Delay f = f
member __.Run f =
registerTask meta (fun () -> f())
/// Define a task with it's dependencies
let Task name dependencies body =
registerTask { name = name; dependencies = parseDependencies dependencies } body
/// Define a task with it's dependencies
let inline task name dependencies =
TaskBuilder({ name = name; dependencies = parseDependencies dependencies })
/// Define a task without any body, only dependencies
let inline EmptyTask name dependencies =
registerTask { name = name; dependencies = parseDependencies dependencies } (fun () -> ())
/// Send all the defined inter task dependencies to FAKE
let ApplyTasksDependencies () =
for taskMetadata in tasks do
for dependency in taskMetadata.dependencies do
match dependency with
| Direct dep -> dep ==> taskMetadata.name |> ignore
| Soft dep -> dep ?=> taskMetadata.name |> ignore
tasks <- []
/// Run the task specified on the command line if there was one or the
/// default one otherwise.
let RunTaskOrDefault taskName =
ApplyTasksDependencies ()
RunTargetOrDefault taskName
// include Fake libs
#r @"packages/FAKE/tools/FakeLib.dll"
open Fake
open Fake.AssemblyInfoFile
// include tasks
#load "TaskDefinitionHelper.fsx"
open BlackFox.TaskDefinitionHelper
// Directories
let buildDir = "./build/"
let testDir = "./test/"
let deployDir = "./deploy/"
// tools
let fxCopRoot = "./Tools/FxCop/FxCopCmd.exe"
// Filesets
let appReferences =
!! "src/app/**/*.csproj"
++ "src/app/**/*.fsproj"
let testReferences = !! "src/test/**/*.csproj"
// version info
let version = "0.2" // or retrieve from CI server
// Targets
task "Clean" [] {
CleanDirs [buildDir; testDir; deployDir]
}
task "BuildApp" ["Clean"] {
CreateCSharpAssemblyInfo "./src/app/Calculator/Properties/AssemblyInfo.cs"
[Attribute.Title "Calculator Command line tool"
Attribute.Description "Sample project for FAKE - F# MAKE"
Attribute.Guid "A539B42C-CB9F-4a23-8E57-AF4E7CEE5BAA"
Attribute.Product "Calculator"
Attribute.Version version
Attribute.FileVersion version]
CreateCSharpAssemblyInfo "./src/app/CalculatorLib/Properties/AssemblyInfo.cs"
[Attribute.Title "Calculator library"
Attribute.Description "Sample project for FAKE - F# MAKE"
Attribute.Guid "EE5621DB-B86B-44eb-987F-9C94BCC98441"
Attribute.Product "Calculator"
Attribute.Version version
Attribute.FileVersion version]
// compile all projects below src/app/
MSBuildRelease buildDir "Build" appReferences
|> Log "AppBuild-Output: "
}
task "BuildTest" ["Clean"] {
MSBuildDebug testDir "Build" testReferences
|> Log "TestBuild-Output: "
}
task "NUnitTest" ["BuildApp"; "BuildTest"] {
!! (testDir + "/NUnit.Test.*.dll")
|> NUnit (fun p ->
{p with
DisableShadowCopy = true;
OutputFile = testDir + "TestResults.xml"})
}
task "xUnitTest" ["BuildApp"; "BuildTest"] {
!! (testDir + "/xUnit.Test.*.dll")
|> xUnit (fun p ->
{p with
ShadowCopy = false;
HtmlOutput = true;
XmlOutput = true;
OutputDir = testDir })
}
// only if FAKE was called with parameter xUnitTest
Task
"Tests"
("NUnitTest" :: if hasBuildParam "xUnitTest" then ["xUnitTest"] else [])
DoNothing
task "FxCop" ["BuildApp"] {
!! (buildDir + "/**/*.dll")
++ (buildDir + "/**/*.exe")
|> FxCop (fun p ->
{p with
ReportFileName = testDir + "FXCopResults.xml";
ToolPath = fxCopRoot})
}
task "Deploy" ["Tests"; "FxCop"] {
!! (buildDir + "/**/*.*")
-- "*.zip"
|> Zip buildDir (deployDir + "Calculator." + version + ".zip")
}
// start build
RunTaskOrDefault "Deploy"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment