Last active
August 14, 2019 10:35
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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