F# Introduction III: Library Setup

Back to the index

F# Introduction III: Library Setup

This guide shows an example setup for a library. This is not the only way on how to do this, but merely a possibility. As always, this guide is meant as a starting point to be expanded upon. For example, unit tests and full buildchains with automatic releases can be added to this template. The installation of .NET 5.0 or dotnet SDK 3.1 LTS is required. It is also recommended to use GitHub when following this example.

Initializing the repository

  • An easy way to initialize a repository is by creating a new one using GitHub and cloning it.

    • You can automatically add a readme, a .gitignore with many entries for Visual Studio already added and a license of choice.

  • After you cloned the initialized repository, it should look like this:

Initializing the library

  • The stock library template is just fine (change framework if you know what you are doing): dotnet new classlib -lang F# -n "YourNameHere" --framework net5.0 -o src/YourNameHere
  • Add an entry for the 'pkg' folder to your .gitignore
  • Create a RELEASE_NOTES.md file in the project root, make sure to add at least one version header like this:
## 0.0.1 - 28/7/2021
  • Add a solution to your projekt with dotnet new sln --name YourNameHere
  • After you completed the previous steps your folder should look like this:

Initializing the buildchain with FAKE

  • Initialize a local tool manifest that will keep track of the usable local dotnet tools in this project.

    • In the project root: dotnet new tool-manifest

  • In the project root: Install the fake cli as local tool: dotnet tool install fake-cli

  • In the project root: Install paket as local tool: dotnet tool install paket

  • In the project root: Create a new empty build.fsx file

  • Your folder should now look like this:

  • Open the build.fsx file (intellisense will not work right after creating it) and add the following content.

First, lets reference the dependencies of the build script. In fake they are loaded via the paket manager:

#r "paket:
nuget BlackFox.Fake.BuildTask
nuget Fake.Core.Target
nuget Fake.Core.Process
nuget Fake.Core.ReleaseNotes
nuget Fake.IO.FileSystem
nuget Fake.DotNet.Cli
nuget Fake.DotNet.MSBuild
nuget Fake.DotNet.AssemblyInfoFile
nuget Fake.DotNet.Paket
nuget Fake.DotNet.FSFormatting
nuget Fake.DotNet.Fsi
nuget Fake.DotNet.NuGet
nuget Fake.Api.Github
nuget Fake.DotNet.Testing.Expecto 
nuget Fake.Tools.Git //"

Then, we open the dependencies. Note that for getting intellisense, you will have to run the script once with the fake runner (see here).

#if !FAKE
#load "./.fake/build.fsx/intellisense.fsx"
#r "netstandard" // Temp fix for https://github.com/dotnet/fsharp/issues/5216
#endif

open BlackFox.Fake
open System.IO
open Fake.Core
open Fake.DotNet
open Fake.IO
open Fake.IO.FileSystemOperators
open Fake.IO.Globbing.Operators
open Fake.Tools

[<AutoOpen>]
/// user interaction prompts for critical build tasks where you may want to interrupt when you see wrong inputs.
module MessagePrompts =

    let prompt (msg:string) =
        System.Console.Write(msg)
        System.Console.ReadLine().Trim()
        |> function | "" -> None | s -> Some s
        |> Option.map (fun s -> s.Replace ("\"","\\\""))

    let rec promptYesNo msg =
        match prompt (sprintf "%s [Yn]: " msg) with
        | Some "Y" | Some "y" -> true
        | Some "N" | Some "n" -> false
        | _ -> System.Console.WriteLine("Sorry, invalid answer"); promptYesNo msg

    let releaseMsg = """This will stage all uncommitted changes, push them to the origin and bump the release version to the latest number in the RELEASE_NOTES.md file. 
        Do you want to continue?"""

    let releaseDocsMsg = """This will push the docs to gh-pages. Remember building the docs prior to this. Do you want to continue?"""

/// Executes a dotnet command in the given working directory
let runDotNet cmd workingDir =
    let result =
        DotNet.exec (DotNet.Options.withWorkingDirectory workingDir) cmd ""
    if result.ExitCode <> 0 then failwithf "'dotnet %s' failed in %s" cmd workingDir

Note: This build.fsx will be gradually epxanded

  • Add the ProjectInfo module to the build.fsx file, which will contain all relevant metadata for the buildchain except nuget package metadata (more on that later).
  • Replace all strings with the correct ones for your project.
/// Metadata about the project
module ProjectInfo = 

    let project = "LibraryExample"

    let summary = "An example Library"

    let configuration = "Release"

    // Git configuration (used for publishing documentation in gh-pages branch)
    // The profile where the project is posted
    let gitOwner = "YourGitProfile"
    let gitName = "YourNameHere"

    let gitHome = sprintf "%s/%s" "https://github.com" gitOwner

    let projectRepo = sprintf "%s/%s/%s" "https://github.com" gitOwner gitName

    let website = "/YourNameHere"

    let pkgDir = "pkg"

    let release = ReleaseNotes.load "RELEASE_NOTES.md"

    let stableVersion = SemVer.parse release.NugetVersion

    let stableVersionTag = (sprintf "%i.%i.%i" stableVersion.Major stableVersion.Minor stableVersion.Patch )

    let mutable prereleaseSuffix = ""

    let mutable prereleaseTag = ""

    let mutable isPrerelease = false
  • Add the BasicTasks module to the build.fsx file, which will contain the minimal build chain.
/// Barebones, minimal build tasks
module BasicTasks = 

    open ProjectInfo

    let setPrereleaseTag = BuildTask.create "SetPrereleaseTag" [] {
        printfn "Please enter pre-release package suffix"
        let suffix = System.Console.ReadLine()
        prereleaseSuffix <- suffix
        prereleaseTag <- (sprintf "%s-%s" release.NugetVersion suffix)
        isPrerelease <- true
    }

    let clean = BuildTask.create "Clean" [] {
        !! "src/**/bin"
        ++ "src/**/obj"
        ++ "pkg"
        ++ "bin"
        |> Shell.cleanDirs 
    }

    let build = BuildTask.create "Build" [clean] {
        !! "src/**/*.*proj"
        |> Seq.iter (DotNet.build id)
    }

    let copyBinaries = BuildTask.create "CopyBinaries" [clean; build] {
        let targets = 
            !! "src/**/*.??proj"
            -- "src/**/*.shproj"
            |>  Seq.map (fun f -> ((Path.getDirectory f) </> "bin" </> configuration, "bin" </> (Path.GetFileNameWithoutExtension f)))
        for i in targets do printfn "%A" i
        targets
        |>  Seq.iter (fun (fromDir, toDir) -> Shell.copyDir toDir fromDir (fun _ -> true))
    }
  • At the bottom of the build.fsx file, add the following lines:
open BasicTasks
BuildTask.runOrDefault copyBinaries
  • Create a build.cmd or build.sh file (or both) with the following lines:

build.cmd

dotnet tool restore
dotnet fake build %*

build.sh

#!/usr/bin/env bash

set -eu
set -o pipefail

dotnet tool restore
dotnet fake build "[email protected]"

Running the build script

  • You can now run your build via calling either build.cmd or build.sh.
    • Optionally, you can pass the -t argument with it to execute a specific build task, e.g ./build.cmd -t clean to execute the clean target.
    • The first time you run the build.cmd will also enable intellisense for the fake build script
  • After building for the first time your folder will look like this:

Packing a nuget package

  • Add nuget package metadata to the project file (src/LibraryExample/LibraryExample.fsproj) and adapt accordingly:
<PropertyGroup>
    <Authors>YourName</Authors>
    <Description>Your description here</Description>
    <Summary>Your summary here</Summary>
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
    <PackageProjectUrl>https://fslab.org/projectName/</PackageProjectUrl>
    <PackageIconUrl>https://fslab.org/projectName/img/logo.png</PackageIconUrl>
    <PackageTags>documentation fsharp csharp dotnet</PackageTags>
    <RepositoryUrl>https://github.com/fslaborg/projectName</RepositoryUrl>
    <RepositoryType>git</RepositoryType>
    <FsDocsLicenseLink>https://github.com/fslaborg/projectName/blob/master/LICENSE</FsDocsLicenseLink>
    <FsDocsReleaseNotesLink>https://github.com/fslaborg/projectName/blob/master/RELEASE_NOTES.md</FsDocsReleaseNotesLink>
</PropertyGroup>
  • Add the PackageTasks module to the build.fsx file, which will take care of building nuget packages for both stable and prerelease packages:
/// Package creation
module PackageTasks = 

    open ProjectInfo

    open BasicTasks

    let pack = BuildTask.create "Pack" [clean; build; copyBinaries] {
        if promptYesNo (sprintf "creating stable package with version %s OK?" stableVersionTag ) 
            then
                !! "src/**/*.*proj"
                |> Seq.iter (Fake.DotNet.DotNet.pack (fun p ->
                    let msBuildParams =
                        {p.MSBuildParams with 
                            Properties = ([
                                "Version",stableVersionTag
                                "PackageReleaseNotes",  (release.Notes |> String.concat "\r\n")
                            ] @ p.MSBuildParams.Properties)
                        }
                    {
                        p with 
                            MSBuildParams = msBuildParams
                            OutputPath = Some pkgDir
                    }
                ))
        else failwith "aborted"
    }

    let packPrerelease = BuildTask.create "PackPrerelease" [setPrereleaseTag; clean; build; copyBinaries] {
        if promptYesNo (sprintf "package tag will be %s OK?" prereleaseTag )
            then 
                !! "src/**/*.*proj"
                //-- "src/**/Plotly.NET.Interactive.fsproj"
                |> Seq.iter (Fake.DotNet.DotNet.pack (fun p ->
                            let msBuildParams =
                                {p.MSBuildParams with 
                                    Properties = ([
                                        "Version", prereleaseTag
                                        "PackageReleaseNotes",  (release.Notes |> String.toLines )
                                    ] @ p.MSBuildParams.Properties)
                                }
                            {
                                p with 
                                    VersionSuffix = Some prereleaseSuffix
                                    OutputPath = Some pkgDir
                                    MSBuildParams = msBuildParams
                            }
                ))
        else
            failwith "aborted"
    }
  • You can test both targets with ./build.cmd -t Pack or ./build.cmd -t PackPrerelease respectively.
  • The packages can be found in the pkg folder in the project root. Since you do not want to host your nuget packages on github, do also remove this folder from source control by adding /pkg to your .gitignore file.
  • If you want users of your nuget package to have a pleasant debugging experience you can make use of sourcelink.
    • To install this package, navigate to the folder of your project, e.g. src/LibraryExample and call: dotnet add package Microsoft.SourceLink.GitHub --version 1.0.0

Documentation

  • In the project root: Install fsdocs as local tool: dotnet tool install FSharp.Formatting.CommandTool
  • In the project root: Install the fslab documentation template: dotnet new -i FsLab.DocumentationTemplate::*
  • Initialize the fslab documentation template: dotnet new fslab-docs
  • Add the DocumentationTasks module to the build.fsx file, which will take care initializing documentation files and developing them:
/// Build tasks for documentation setup and development
module DocumentationTasks =

    open ProjectInfo

    open BasicTasks

    let buildDocs = BuildTask.create "BuildDocs" [build; copyBinaries] {
        printfn "building docs with stable version %s" stableVersionTag
        runDotNet 
            (sprintf "fsdocs build --eval --clean --property Configuration=Release --parameters fsdocs-package-version %s" stableVersionTag)
            "./"
    }

    let buildDocsPrerelease = BuildTask.create "BuildDocsPrerelease" [setPrereleaseTag; build; copyBinaries] {
        printfn "building docs with prerelease version %s" prereleaseTag
        runDotNet 
            (sprintf "fsdocs build --eval --clean --property Configuration=Release --parameters fsdocs-package-version %s" prereleaseTag)
            "./"
    }

    let watchDocs = BuildTask.create "WatchDocs" [build; copyBinaries] {
        printfn "watching docs with stable version %s" stableVersionTag
        runDotNet 
            (sprintf "fsdocs watch --eval --clean --property Configuration=Release --parameters fsdocs-package-version %s" stableVersionTag)
            "./"
    }

    let watchDocsPrerelease = BuildTask.create "WatchDocsPrerelease" [setPrereleaseTag; build; copyBinaries] {
        printfn "watching docs with prerelease version %s" prereleaseTag
        runDotNet 
            (sprintf "fsdocs watch --eval --clean --property Configuration=Release --parameters fsdocs-package-version %s" prereleaseTag)
            "./"
    }
  • To create a new documentation file, run ./build.cmd -t InitDocsPage
  • Add tmp/ to .gitignore
  • To run fsdocs in watchmode (hot reaload local hosting of your docs for live development), run dotnet fsdocs watch
  • Your repository should now look like this:

Adding nuget packages

  • Navigate to your project folder (i. e. src/LibraryExample)
  • If you want to specify a package source other than nuget.com (e.g. a local package) you can specify other sources after adding a nuget.config file to your project root:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
</configuration>
  • The following example would add the local lib folder as a new nuget source to your local nuget.config file: dotnet nuget add source ./lib --configfile nuget.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="Package source 1" value="./lib" />
  </packageSources>
</configuration>
  • Calling dotnet add package PackageName --version PackageVersion will still start to search for the package on nuget.com, but if this call is unsuccesful, Package source 1 will be used as a fallback. For a more complete view on how to use nuget.config files please visit the offical documentation or have a look at this blog post.
namespace BlackFox
namespace BlackFox.Fake
namespace System
namespace System.IO
namespace Fake
namespace Fake.Core
namespace Fake.DotNet
namespace Fake.IO
module FileSystemOperators from Fake.IO
namespace Fake.IO.Globbing
module Operators from Fake.IO.Globbing
<summary> Contains operators to find and process files. This module is part of the `Fake.IO.FileSystem` package ### Simple glob using as list #r "paket: nuget Fake.IO.FileSystem //" open Fake.IO.Globbing.Operators let csProjectFiles = !! "src/*.csproj" for projectFile in csProjectFiles do printf "F# ProjectFile: %s" projectFile ### Combine globs #r "paket: nuget Fake.IO.FileSystem //" open Fake.IO.Globbing.Operators let projectFiles = !! "src/*/*.*proj" ++ "src/*/*.target" -- "src/*/*.vbproj" for projectFile in projectFiles do printf "ProjectFile: %s" projectFile ### Forward globs to tasks #r "paket: nuget Fake.Core.Target nuget Fake.IO.FileSystem //" open Fake.Core open Fake.IO open Fake.IO.Globbing.Operators Target.create "Clean" (fun _ -&gt; !! "src/*/*/obj/**/*.nuspec" |&gt; File.deleteAll ) </summary>
namespace Fake.Tools
Multiple items
type AutoOpenAttribute = inherit Attribute new : unit -> AutoOpenAttribute + 1 overload member Path : string
<summary>Indicates a construct is automatically opened when brought into scope through an assembly reference or then opening of the containing namespace or module.</summary>
<remarks>When applied to an assembly, this attribute must be given a string argument, and this indicates a valid module or namespace in that assembly. Source code files compiled with a reference to this assembly are processed in an environment where the given path is automatically opened. When applied to a type or module within an assembly, then the attribute must not be given any arguments, and the type or module is implicitly opened when its enclosing namespace or module is opened. </remarks>
<category>Attributes</category>


--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
val prompt : msg:string -> string option
val msg : string
Multiple items
val string : value:'T -> string
<summary>Converts the argument to a string using <c>ToString</c>.</summary>
<remarks>For standard integer and floating point values the and any type that implements <c>IFormattable</c><c>ToString</c> conversion uses <c>CultureInfo.InvariantCulture</c>. </remarks>
<param name="value">The input value.</param>
<returns>The converted string.</returns>


--------------------
type string = System.String
<summary>An abbreviation for the CLI type <see cref="T:System.String" />.</summary>
<category>Basic Types</category>
type Console = static member Beep : unit -> unit + 1 overload static member Clear : unit -> unit static member GetCursorPosition : unit -> struct (int * int) static member MoveBufferArea : sourceLeft: int * sourceTop: int * sourceWidth: int * sourceHeight: int * targetLeft: int * targetTop: int -> unit + 1 overload static member OpenStandardError : unit -> Stream + 1 overload static member OpenStandardInput : unit -> Stream + 1 overload static member OpenStandardOutput : unit -> Stream + 1 overload static member Read : unit -> int static member ReadKey : unit -> ConsoleKeyInfo + 1 overload static member ReadLine : unit -> string ...
<summary>Represents the standard input, output, and error streams for console applications. This class cannot be inherited.</summary>
System.Console.Write(value: uint64) : unit
   (+0 other overloads)
System.Console.Write(value: uint32) : unit
   (+0 other overloads)
System.Console.Write(value: string) : unit
   (+0 other overloads)
System.Console.Write(value: float32) : unit
   (+0 other overloads)
System.Console.Write(value: obj) : unit
   (+0 other overloads)
System.Console.Write(value: int64) : unit
   (+0 other overloads)
System.Console.Write(value: int) : unit
   (+0 other overloads)
System.Console.Write(value: float) : unit
   (+0 other overloads)
System.Console.Write(value: decimal) : unit
   (+0 other overloads)
System.Console.Write(buffer: char []) : unit
   (+0 other overloads)
System.Console.ReadLine() : string
union case Option.None: Option<'T>
<summary>The representation of "No value"</summary>
val s : string
union case Option.Some: Value: 'T -> Option<'T>
<summary>The representation of "Value of type 'T"</summary>
<param name="Value">The input value.</param>
<returns>An option representing the value.</returns>
module Option from Microsoft.FSharp.Core
<summary>Contains operations for working with options.</summary>
<category>Options</category>
val map : mapping:('T -> 'U) -> option:'T option -> 'U option
<summary><c>map f inp</c> evaluates to <c>match inp with None -&gt; None | Some x -&gt; Some (f x)</c>.</summary>
<param name="mapping">A function to apply to the option value.</param>
<param name="option">The input option.</param>
<example><code> None |&gt; Option.map (fun x -&gt; x * 2) // evaluates to None Some 42 |&gt; Option.map (fun x -&gt; x * 2) // evaluates to Some 84 </code></example>
<returns>An option of the input value after applying the mapping function, or None if the input is None.</returns>
System.String.Replace(oldValue: string, newValue: string) : string
System.String.Replace(oldChar: char, newChar: char) : string
System.String.Replace(oldValue: string, newValue: string, comparisonType: System.StringComparison) : string
System.String.Replace(oldValue: string, newValue: string, ignoreCase: bool, culture: System.Globalization.CultureInfo) : string
val promptYesNo : msg:string -> bool
val sprintf : format:Printf.StringFormat<'T> -> 'T
<summary>Print to a string using the given format.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
System.Console.WriteLine() : unit
   (+0 other overloads)
System.Console.WriteLine(value: uint64) : unit
   (+0 other overloads)
System.Console.WriteLine(value: uint32) : unit
   (+0 other overloads)
System.Console.WriteLine(value: string) : unit
   (+0 other overloads)
System.Console.WriteLine(value: float32) : unit
   (+0 other overloads)
System.Console.WriteLine(value: obj) : unit
   (+0 other overloads)
System.Console.WriteLine(value: int64) : unit
   (+0 other overloads)
System.Console.WriteLine(value: int) : unit
   (+0 other overloads)
System.Console.WriteLine(value: float) : unit
   (+0 other overloads)
System.Console.WriteLine(value: decimal) : unit
   (+0 other overloads)
val releaseMsg : string
val releaseDocsMsg : string
val runDotNet : cmd:string -> workingDir:string -> unit
 Executes a dotnet command in the given working directory
val cmd : string
val workingDir : string
val result : ProcessResult
module DotNet from Fake.DotNet
val exec : buildOptions:(DotNet.Options -> DotNet.Options) -> command:string -> args:string -> ProcessResult
<summary> Execute raw dotnet cli command ## Parameters - 'buildOptions' - build common execution options - 'command' - the sdk command to execute 'test', 'new', 'build', ... - 'args' - command arguments </summary>
Multiple items
module Options from Fake.DotNet.DotNet

--------------------
type Options = { DotNetCliPath: string Version: string option WorkingDirectory: string Timeout: TimeSpan option CustomParams: string option Verbosity: Verbosity option Diagnostics: bool RedirectOutput: bool PrintRedirectedOutput: bool Environment: Map<string,string> } member WithCommon : f:(Options -> 'a0) -> 'a0 member WithEnvironment : map:Map<string,string> -> Options member WithPrintRedirectedOutput : shouldPrint:bool -> Options member WithRedirectOutput : shouldRedirect:bool -> Options static member Create : unit -> Options
<summary> dotnet cli command execution options </summary>
val withWorkingDirectory : wd:string -> x:'a -> 'a (requires member WithCommon)
ProcessResult.ExitCode: int
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T
<summary>Print to a string buffer and raise an exception with the given result. Helper printers must return strings.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
val project : string
val summary : string
val configuration : string
val gitOwner : string
val gitName : string
val gitHome : string
val projectRepo : string
val website : string
val pkgDir : string
val release : ReleaseNotes.ReleaseNotes
module ReleaseNotes from Fake.Core
<summary> Contains helpers which allow to parse Release Notes text files. Either "simple" or "complex" format is accepted. ## Formats ### Simple format * 1.1.10 - Support for heterogeneous XML attributes. Make CsvFile re-entrant. * 1.1.9 - Infer booleans for ints that only manifest 0 and 1. ### Complex format ### New in 1.1.10 (Released 2013/09/12) * Support for heterogeneous XML attributes. * Make CsvFile re-entrant. * Support for compressed HTTP responses. * Fix JSON conversion of 0 and 1 to booleans. ### New in 1.1.9 (Released 2013/07/21) * Infer booleans for ints that only manifest 0 and 1. * Support for partially overriding the Schema in CsvProvider. * PreferOptionals and SafeMode parameters for CsvProvider. ## Sample #r "paket: nuget Fake.Core.ReleaseNotes //" let release = ReleaseNotes.load "RELEASE_NOTES.md" Target "AssemblyInfo" (fun _ -&gt; CreateFSharpAssemblyInfo "src/Common/AssemblyInfo.fs" [ Attribute.Title project Attribute.Product project Attribute.Description summary Attribute.Version release.AssemblyVersion Attribute.FileVersion release.AssemblyVersion] ) </summary>
val load : fileName:string -> ReleaseNotes.ReleaseNotes
<summary> Parses a Release Notes text file and returns the lastest release notes. ## Parameters - `fileName` - Release notes text file name </summary>
val stableVersion : SemVerInfo
module SemVer from Fake.Core
<summary> Parser which allows to deal with [Semantic Versioning](http://semver.org/) (SemVer). Make sure to read the documentation in the [SemVerInfo](fake-core-semverinfo.html) record as well if you manually create versions. </summary>
val parse : version:string -> SemVerInfo
<summary> Parses the given version string into a SemVerInfo which can be printed using ToString() or compared according to the rules described in the [SemVer docs](http://semver.org/). ## Sample parse "1.0.0-rc.1" &lt; parse "1.0.0" // true parse "1.2.3-alpha" &gt; parse "1.2.2" // true parse "1.2.3-alpha2" &gt; parse "1.2.3-alpha" // true parse "1.2.3-alpha002" &gt; parse "1.2.3-alpha1" // false parse "1.5.0-beta.2" &gt; parse "1.5.0-rc.1" // false </summary>
ReleaseNotes.ReleaseNotes.NugetVersion: string
<summary> The nuget package version. </summary>
val stableVersionTag : string
SemVerInfo.Major: uint32
<summary> MAJOR version when you make incompatible API changes. </summary>
SemVerInfo.Minor: uint32
<summary> MINOR version when you add functionality in a backwards-compatible manner. </summary>
SemVerInfo.Patch: uint32
<summary> PATCH version when you make backwards-compatible bug fixes. </summary>
val mutable prereleaseSuffix : string
val mutable prereleaseTag : string
val mutable isPrerelease : bool
module ProjectInfo from IntroductionIII
 Metadata about the project
val setPrereleaseTag : BuildTask.TaskInfo
module BuildTask from BlackFox.Fake
<summary> Allow to define FAKE tasks with a syntax similar to Gulp tasks </summary>
val create : name:string -> dependencies:BuildTask.TaskInfo list -> BuildTask.TaskBuilder
<summary> Define a Task with it's dependencies </summary>
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
<summary>Print to <c>stdout</c> using the given format, and add a newline.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
val suffix : string
val clean : BuildTask.TaskInfo
Multiple items
module Shell from Fake.IO

--------------------
type Shell = private new : unit -> Shell static member AsyncExec : cmd:string * ?args:string * ?dir:string -> Async<int> static member Exec : cmd:string * ?args:string * ?dir:string -> int static member private GetParams : cmd:string * ?args:string * ?dir:string -> ExecParams
<summary> Allows to exec shell operations synchronously and asynchronously. </summary>
val cleanDirs : dirs:seq<string> -> unit
<summary> Cleans multiple directories </summary>
val build : BuildTask.TaskInfo
module Seq from Microsoft.FSharp.Collections
<summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Collections.seq`1" />.</summary>
val iter : action:('T -> unit) -> source:seq<'T> -> unit
<summary>Applies the given function to each element of the collection.</summary>
<param name="action">A function to apply to each element of the sequence.</param>
<param name="source">The input sequence.</param>
<exception cref="T:System.ArgumentNullException">Thrown when the input sequence is null.</exception>
val build : setParams:(DotNet.BuildOptions -> DotNet.BuildOptions) -> project:string -> unit
<summary> Execute dotnet build command ## Parameters - 'setParams' - set compile command parameters - 'project' - project to compile </summary>
val id : x:'T -> 'T
<summary>The identity function</summary>
<param name="x">The input value.</param>
<returns>The same value.</returns>
val copyBinaries : BuildTask.TaskInfo
val targets : seq<string * string>
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>
<summary>Builds a new collection whose elements are the results of applying the given function to each of the elements of the collection. The given function will be applied as elements are demanded using the <c>MoveNext</c> method on enumerators retrieved from the object.</summary>
<remarks>The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently.</remarks>
<param name="mapping">A function to transform items from the input sequence.</param>
<param name="source">The input sequence.</param>
<returns>The result sequence.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when the input sequence is null.</exception>
val f : string
type Path = static member ChangeExtension : path: string * extension: string -> string static member Combine : path1: string * path2: string -> string + 3 overloads static member EndsInDirectorySeparator : path: ReadOnlySpan<char> -> bool + 1 overload static member GetDirectoryName : path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetExtension : path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFileName : path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFileNameWithoutExtension : path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFullPath : path: string -> string + 1 overload static member GetInvalidFileNameChars : unit -> char [] static member GetInvalidPathChars : unit -> char [] ...
<summary>Performs operations on <see cref="T:System.String" /> instances that contain file or directory path information. These operations are performed in a cross-platform manner.</summary>
val getDirectory : path:string -> string
<summary> Get the directory of the specified path ## Parameters - 'path' - The path from which the directory is retrieved. </summary>
Path.GetFileNameWithoutExtension(path: string) : string
Path.GetFileNameWithoutExtension(path: System.ReadOnlySpan<char>) : System.ReadOnlySpan<char>
val i : string * string
val fromDir : string
val toDir : string
val copyDir : target:string -> source:string -> filterFile:(string -> bool) -> unit
<summary> Copies a directory recursivly. If the target directory does not exist, it will be created. ## Parameters - `target` - The target directory. - `source` - The source directory. - `filterFile` - A file filter predicate. </summary>
module BasicTasks from IntroductionIII
 Barebones, minimal build tasks
val runOrDefault : defaultTask:BuildTask.TaskInfo -> unit
<summary> Run the task specified on the command line if there was one or the default one otherwise. </summary>
val pack : BuildTask.TaskInfo
val pack : setParams:(DotNet.PackOptions -> DotNet.PackOptions) -> project:string -> unit
<summary> Execute dotnet pack command ## Parameters - 'setParams' - set pack command parameters - 'project' - project to pack ## Sample let packConfiguration (defaults:DotNet.PackOptions) = { defaults with Configuration = DotNet.Debug OutputPath = Some "./packages" IncludeSymbols = true } DotNet.pack packConfiguration "./MyProject.csproj" </summary>
val p : DotNet.PackOptions
val msBuildParams : MSBuild.CliArguments
DotNet.PackOptions.MSBuildParams: MSBuild.CliArguments
<summary> Other msbuild specific parameters </summary>
ReleaseNotes.ReleaseNotes.Notes: string list
Multiple items
module String from Fake.Core
<summary> Contains basic functions for string manipulation. </summary>

--------------------
module String from Microsoft.FSharp.Core
<summary>Functional programming operators for string processing. Further string operations are available via the member functions on strings and other functionality in <a href="http://msdn2.microsoft.com/en-us/library/system.string.aspx">System.String</a> and <a href="http://msdn2.microsoft.com/library/system.text.regularexpressions.aspx">System.Text.RegularExpressions</a> types. </summary>
<category>Strings and Text</category>
val concat : sep:string -> strings:seq<string> -> string
<summary>Returns a new string made by concatenating the given strings with separator <c>sep</c>, that is <c>a1 + sep + ... + sep + aN</c>.</summary>
<param name="sep">The separator string to be inserted between the strings of the input sequence.</param>
<param name="strings">The sequence of strings to be concatenated.</param>
<returns>A new string consisting of the concatenated strings separated by the separation string.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when <c>strings</c> is null.</exception>
MSBuild.CliArguments.Properties: (string * string) list
type MSBuildParams = { ToolPath: string WorkingDirectory: string Targets: string list Properties: (string * string) list MaxCpuCount: int option option DoRestore: bool NoLogo: bool NodeReuse: bool RestorePackagesFlag: bool ToolsVersion: string option ... } member WithEnvironment : map:Map<string,string> -> MSBuildParams static member Create : unit -> MSBuildParams
<summary> A type for MSBuild task parameters </summary>
val failwith : message:string -> 'T
<summary>Throw a <see cref="T:System.Exception" /> exception.</summary>
<param name="message">The exception message.</param>
<returns>The result value.</returns>
val packPrerelease : BuildTask.TaskInfo
val toLines : text:seq<string> -> string
<summary> Converts a sequence of strings into a string separated with line ends </summary>
module DocumentationTasks from IntroductionIII
 Build tasks for documentation setup and development
val buildDocs : BuildTask.TaskInfo
val buildDocsPrerelease : BuildTask.TaskInfo
val watchDocs : BuildTask.TaskInfo
val watchDocsPrerelease : BuildTask.TaskInfo