Skip to content

Instantly share code, notes, and snippets.

@arthurrump
Last active August 14, 2019 10:35
Show Gist options
  • Save arthurrump/5cc9005e4d817f7d36c2c4ad736fd894 to your computer and use it in GitHub Desktop.
Save arthurrump/5cc9005e4d817f7d36c2c4ad736fd894 to your computer and use it in GitHub Desktop.
How to use FAKE to automatically set version numbers based on your Git history. https://www.arthurrump.com/2019/07/19/git-based-versioning-using-fake
#r "paket:
nuget Fake.Core.SemVer
nuget Fake.Core.Target
nuget Fake.DotNet.Cli
nuget Fake.Tools.Git //"
#load "./.fake/build.fsx/intellisense.fsx"
open Fake.Core
open Fake.DotNet
open Fake.Tools
let [<Literal>] repo = "."
let [<Literal>] versionFile = "version"
let [<Literal>] versionPreFile = "version-pre"
let [<Literal>] project = "Project.fsproj"
module GitHelpers =
let isTagged () =
Git.CommandHelper.directRunGitCommand repo "describe --exact-match HEAD"
let previousChangeCommit file =
Git.CommandHelper.runSimpleGitCommand repo ("log --format=%H -1 -- " + file)
let fileChanged file =
Git.FileStatus.getChangedFilesInWorkingCopy repo "HEAD"
|> Seq.exists (fun (_, f) -> f = file)
module AzureDevOps =
let tryGetSourceBranch () =
System.Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCHNAME")
|> Option.ofObj
let updateBuildNumber version =
sprintf "\n##vso[build.updatebuildnumber]%O" version
|> System.Console.WriteLine
module Version =
let withPatch patch version =
{ version with Patch = patch; Original = None }
let appendPrerelease suffix version =
let pre =
match suffix, version.PreRelease with
| Some s, Some p -> PreRelease.TryParse (sprintf "%O-%s" p s)
| Some s, None -> PreRelease.TryParse s
| None, p -> p
{ version with PreRelease = pre; Original = None }
let getCleanVersion () =
Trace.trace "Determining version based on Git history"
let version = File.readAsString versionFile |> SemVer.parse
let height =
if GitHelpers.fileChanged versionFile then
0
else
let previousVersionChange = GitHelpers.previousChangeCommit versionFile
let height = Git.Branches.revisionsBetween repo previousVersionChange "HEAD"
if Git.Information.isCleanWorkingCopy repo then height else height + 1
let pre =
if File.exists versionPreFile
then Some (File.readAsString versionPreFile)
else None
version |> withPatch (uint32 height) |> appendPrerelease pre
let getVersionWithPrerelease () =
let pre =
let branch =
match Git.Information.getBranchName repo with
| "NoBranch" -> AzureDevOps.tryGetSourceBranch ()
| branch -> Some branch
let isClean = Git.Information.isCleanWorkingCopy repo
if isClean && (branch = Some "master" || GitHelpers.isTagged ()) then
None
else
let commit = Git.Information.getCurrentSHA1 repo |> fun s -> s.Substring(0, 7)
let dirty = if isClean then None else Some "dirty"
[ branch; Some commit; dirty ] |> List.choose id |> String.concat "-" |> Some
getCleanVersion () |> appendPrerelease pre
[<AutoOpen>]
module MSBuildParamHelpers =
let withVersion version (param : MSBuild.CliArguments) =
{ param with Properties = ("Version", string version)::param.Properties }
let withNoWarn warnings (param : MSBuild.CliArguments) =
{ param with
NoWarn =
param.NoWarn
|> Option.defaultValue []
|> List.append warnings
|> Some }
let withDefaults version =
withVersion version >> withNoWarn [ "FS2003" ]
Target.create "Build" <| fun _ ->
let version = Version.getVersionWithPrerelease ()
AzureDevOps.updateBuildNumber version
DotNet.build
(fun o -> { o with MSBuildParams = o.MSBuildParams |> withDefaults version })
project
Target.runOrDefault "Build"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment