1

I'm writing a FAKE script which will basically do the following: -

1. Clean build outputs
2. Modify a configuration file with a specific value.
3. Perform a build.
4. Upload the outputs somewhere.

I've written all the individual tasks. What I now need to do is to set up a set of FAKE build steps to essentially repeat the above steps, once for each configuration value e.g. let's assume the configuration file had an attribute "colour". I want to repeat the above four build steps, and in step 2 use one of the values [ "black"; "blue"; "red"; "white" ].

What's the best way of achieving this? Should I just make one big build task that does all of this in one e.g. for loop (seems wrong)? Or create multiple build steps e.g. "Set Config to Blue" and "Set Config to Red" etc. and repeat the whole build flow for each colour (again, seems wrong)?

Isaac Abraham
  • 3,422
  • 2
  • 23
  • 26

5 Answers5

2

It's not very good documented, but you can create targets programmatically via TargetTemplateWithDependecies

I will add some docs.

forki23
  • 2,784
  • 1
  • 28
  • 42
  • +1 - I noticed these but couldn't find docs on them. Currently what I'm doing is programmatically creating one target for each config setting and then manually wiring them up. But each target does "everything" inside it e.g. Clean, Config, Upload etc. – Isaac Abraham Mar 09 '15 at 11:18
  • OK - I'll have a play around with this. And get back to you :-) – Isaac Abraham Mar 09 '15 at 12:01
  • OK. One problem I have with the linked example is that the dependencies only run once (at the start). I would want them to run once for each chain. Is that possible to achieve? – Isaac Abraham Mar 09 '15 at 21:11
  • No you would also have to duplicate these targets. – forki23 Mar 10 '15 at 08:55
1

You can do it like this

#r "tools/FAKE/tools/FakeLib.dll"
open Fake 


Target "Clean" (fun _ ->
    trace "Cleaning stuff..."
)

let config color = ignore()

Target "ConfigBlack" (fun _ ->
    config "black"
)

Target "ConfigRed" (fun _ ->
    config "red"
)

Target "Build" (fun _ ->
    trace "Build solution"
)

Target "Upload" (fun _ ->
    trace "Upload artifacts"
)


"Clean"
   =?> ("ConfigBlack",hasBuildParam "black")
   =?> ("ConfigRed",hasBuildParam "red")
   ==> "Build"
   ==> "Upload"

Run "Upload"

After that you will be able to call in like this build Upload black or build Upload red

Sergey Tihon
  • 12,071
  • 4
  • 23
  • 29
  • This isn't quite what I would want - in this case I would have to call ```build``` multiple times, once for each colour. I'd prefer all build steps to be in a single chain. – Isaac Abraham Mar 08 '15 at 22:36
1

The script below works but uses ExecutedTargets which I don't think you should use.

#I "tools/FAKE/tools"
#r "FakeLib.dll"

open Fake

let mutable value = "Foo"

Target "Clean" (fun _ ->
    trace "clean target"
)

Target "Modify config file" (fun _ ->
    trace (sprintf "===========> Modify config file: '%s'" value)
)

Target "Perform build" (fun _ ->
    trace "Perform build"
)

Target "Default" (fun _ -> ())

"Clean"
    ==> "Modify config file"
    ==> "Perform build"
    ==> "Default"

["black"; "blue"; "red"; "white"]
|> List.iter(fun v ->
    value <- v
    Run <| getBuildParamOrDefault "target" "Default"
    ExecutedTargets.Clear()
)
Lazydev
  • 459
  • 2
  • 4
  • OK, this is something like what I've tried so far, except I didn't know about ```ExecutedTargets.Clear()```. I imagine that in the final build report I wouldn't see everything that's happened tho? – Isaac Abraham Mar 08 '15 at 22:35
  • Yes, it's all there, but you will get 4 build time reports (at least in the console). – Lazydev Mar 09 '15 at 11:27
0

Can you use various configurations? For example:

BlueBuild:

[configsection] 
  [Color]Blue[/Color]
[/configsection]

RedBuild:

[configsection] 
  [Color]Red[/Color]
[/configsection]

See the following Articles: How to select different app.config for several build configurations

http://www.hanselman.com/blog/managingmultipleconfigurationfileenvironmentswithprebuildevents.aspx

Community
  • 1
  • 1
David Crook
  • 2,722
  • 3
  • 23
  • 49
  • The word configuration probably not the best choice. What I meant was just some arbitrary mechanism that will alter the build process of Fake. It's not so much to do with app.config etc. really. – Isaac Abraham Mar 08 '15 at 17:32
0

The way I've done this is to basically write a helper function which generates targets - much like the template dependency does - but also generates multiple instances of the "common" targets; each one differs based on the name of the variable element e.g.

let targets = 
  [ "Blue: Clean"
    "Blue: Modify Config"
    "Blue: Perform Build"
    "Blue: Upload outputs"
    "Red: Clean"
    "Red: Modify Config"
    "Red: Perform Build"
    "Red: Upload outputs"
    "Yellow: Clean"
    "Yellow: Modify Config"
    "Yellow: Perform Build"
    "Yellow: Upload outputs" ]

You can then easily build then into a sequential chain of dependencies with e.g.

targets |> List.reduce (==>)

Whilst this is not exactly what I had hoped for, it works well enough for me and lets me see through Fake where things are.

Isaac Abraham
  • 3,422
  • 2
  • 23
  • 26