Script

Extensions can provide actions to help performing a specific step. An extension can be implemented using an F# script:

PROJECT
extension say {
  script = "say.fsx"
}

target build {
  sayHello { who: "world" }
}
say.fsx
#if !TERRABUILD_SCRIPT
#r "<path-to>/Terrabuild.Extensibility.dll"
#endif

open Terrabuild.Extensibility

let sayHello (context: ActionContext) (who: string) =
    let ops = [ shellOp "echo" $"Hello {who}" ]
    execRequest Cacheability.Always ops

In this example, who argument is used to invoke the sayHello action (that’s just the name of the function).

ℹ️

When the script is runned in Terrabuild, TERRABUILD_SCRIPT is defined as well a reference to Terrabuild.Extensibility.dll assembly. Script is always compiled with this dependency.

If TERRABUILD_SCRIPT is not defined, you have to reference the assembly. This can also be used to test script without running in Terrabuild.

Arguments

Functions accept arguments. Supported types are:

  • string and string option
  • bool and bool option
  • List<string> and List<string> option
  • Map<string, string> and Map<string, string> option
  • ActionContext for action functions (must be named context)
  • InitContext for action function (must be named context)

Dispatch

If you want to let the user define the verb, you can use the special function name __dispatch__. If this function is defined, Terrabuild will used it to dispatch the command if the named one is not found. An action function must return an ActionExecutionRequest record.

PROJECT
extension hello {
  script = "hello.fsx"
}

target build {
  hello { who = "world" }
}
hello.fsx
#if !TERRABUILD_SCRIPT
#r "<path-to>/Terrabuild.Extensibility.dll"
#endif

open Terrabuild.Extensibility

let __dispatch__ (context: ActionContext) (who: string) =
    let ops = [ shellOp "echo" $"{context.Command} {who}" ]
    execRequest Cacheability.Always ops
ℹ️
context argument name is required to pass the ActionContext.

Defaults

An extension can also provide a default configuration for a project by implementing __defaults__ function. This function must return a ProjectInfo instance.

Here is a sample extension extracting projects from an sln project file (Visual Studio Solution file):

PROJECT
extension  {
  script = "sln.fsx"
}
sln.fsx
#if !TERRABUILD_SCRIPT
#r "<path-to>/Terrabuild.Extensibility.dll"
#endif

open Terrabuild.Extensibility
open System.IO
open System.Text.RegularExpressions

let private (|Regex|_|) pattern input =
    let m = Regex.Match(input, pattern)
    if m.Success then
        List.tail [ for g in m.Groups -> g.Value ] |> Some
    else
        None

let private findProject = function
    | Regex "^Project\(.*\) = \".*\", \"(.*)\", .*$" [projectFile] ->
        Some projectFile
    | _ ->
        None

let __defaults__ (context: InitContext) =
    let dependencies =
        Directory.EnumerateFiles(context.Directory, "*.sln") |> Seq.head
        |> File.ReadLines
        |> Seq.choose findProject

    { ProjectInfo.Default
      with Ignores = Set.empty
           Outputs = Set.empty
           Dependencies = Set dependencies }
ℹ️
context argument name is required to pass the InitContext.
Last updated on