diff --git a/GitVersionCore/GitFlow/BranchFinders/DevelopBasedVersionFinderBase.cs b/GitVersionCore/GitFlow/BranchFinders/DevelopBasedVersionFinderBase.cs index 2f915d8052..c0a9e76165 100644 --- a/GitVersionCore/GitFlow/BranchFinders/DevelopBasedVersionFinderBase.cs +++ b/GitVersionCore/GitFlow/BranchFinders/DevelopBasedVersionFinderBase.cs @@ -37,6 +37,8 @@ protected SemanticVersion FindVersion( context.CurrentBranch.Name, releaseDate) }; + semanticVersion.OverrideVersionManuallyIfNeeded(context.Repository); + return semanticVersion; } diff --git a/GitVersionCore/GitFlow/BranchFinders/DevelopVersionFinder.cs b/GitVersionCore/GitFlow/BranchFinders/DevelopVersionFinder.cs index 90f8bd6e7c..f6e60196a8 100644 --- a/GitVersionCore/GitFlow/BranchFinders/DevelopVersionFinder.cs +++ b/GitVersionCore/GitFlow/BranchFinders/DevelopVersionFinder.cs @@ -30,6 +30,9 @@ public SemanticVersion FindVersion(GitVersionContext context) PreReleaseTag = "unstable" + numberOfCommitsSinceRelease, BuildMetaData = new SemanticVersionBuildMetaData(numberOfCommitsSinceRelease, context.CurrentBranch.Name, releaseDate), }; + + semanticVersion.OverrideVersionManuallyIfNeeded(context.Repository); + return semanticVersion; } } diff --git a/GitVersionCore/GitFlow/BranchFinders/MasterVersionFinder.cs b/GitVersionCore/GitFlow/BranchFinders/MasterVersionFinder.cs index 4eb976ed33..8e160f71bf 100644 --- a/GitVersionCore/GitFlow/BranchFinders/MasterVersionFinder.cs +++ b/GitVersionCore/GitFlow/BranchFinders/MasterVersionFinder.cs @@ -17,16 +17,23 @@ public SemanticVersion FindVersion(IRepository repository, Commit tip) } } + var semanticVersion = new SemanticVersion(); + string versionString; if (MergeMessageParser.TryParse(tip, out versionString)) { if (ShortVersionParser.TryParse(versionString, out major, out minor, out patch)) { - return BuildVersion(repository, tip, major, minor, patch); + semanticVersion = BuildVersion(repository, tip, major, minor, patch); } } - throw new WarningException("The head of master should always be a merge commit if you follow gitflow. Please create one or work around this by tagging the commit with SemVer compatible Id."); + if (semanticVersion == null || semanticVersion.IsEmpty()) + { + throw new WarningException("The head of master should always be a merge commit if you follow gitflow. Please create one or work around this by tagging the commit with SemVer compatible Id."); + } + + return semanticVersion; } SemanticVersion BuildVersion(IRepository repository, Commit tip, int major, int minor, int patch) diff --git a/GitVersionCore/GitFlow/BranchFinders/SupportVersionFinder.cs b/GitVersionCore/GitFlow/BranchFinders/SupportVersionFinder.cs index 318aa086df..f96535be91 100644 --- a/GitVersionCore/GitFlow/BranchFinders/SupportVersionFinder.cs +++ b/GitVersionCore/GitFlow/BranchFinders/SupportVersionFinder.cs @@ -17,16 +17,25 @@ public SemanticVersion FindVersion(IRepository repository, Commit tip) } } + var semanticVersion = new SemanticVersion(); + string versionString; if (MergeMessageParser.TryParse(tip, out versionString)) { if (ShortVersionParser.TryParse(versionString, out major, out minor, out patch)) { - return BuildVersion(repository, tip, major, minor, patch); + semanticVersion = BuildVersion(repository, tip, major, minor, patch); } } - throw new WarningException("The head of a support branch should always be a merge commit if you follow gitflow. Please create one or work around this by tagging the commit with SemVer compatible Id."); + semanticVersion.OverrideVersionManuallyIfNeeded(repository); + + if (semanticVersion == null || semanticVersion.IsEmpty()) + { + throw new WarningException("The head of a support branch should always be a merge commit if you follow gitflow. Please create one or work around this by tagging the commit with SemVer compatible Id."); + } + + return semanticVersion; } SemanticVersion BuildVersion(IRepository repository, Commit tip, int major, int minor, int patch) diff --git a/GitVersionCore/GitHubFlow/NextVersionTxtFileFinder.cs b/GitVersionCore/GitHubFlow/NextVersionTxtFileFinder.cs index fb45b92360..7c9e8bb23a 100644 --- a/GitVersionCore/GitHubFlow/NextVersionTxtFileFinder.cs +++ b/GitVersionCore/GitHubFlow/NextVersionTxtFileFinder.cs @@ -19,14 +19,18 @@ public SemanticVersion GetNextVersion() { return new SemanticVersion(); } - var version = File.ReadAllText(filePath); + var version = File.ReadAllText(filePath); if (string.IsNullOrEmpty(version)) + { return new SemanticVersion(); + } SemanticVersion semanticVersion; if (!SemanticVersion.TryParse(version, out semanticVersion)) + { throw new ArgumentException("Make sure you have a valid semantic version in NextVersion.txt"); + } return semanticVersion; } diff --git a/GitVersionCore/GitVersionCore.csproj b/GitVersionCore/GitVersionCore.csproj index 0f11721778..4f1680a25b 100644 --- a/GitVersionCore/GitVersionCore.csproj +++ b/GitVersionCore/GitVersionCore.csproj @@ -7,7 +7,7 @@ {F9741A0D-B9D7-4557-9A1C-A7252C1071F5} Library Properties - GitVersionCore + GitVersion GitVersionCore v4.0 512 @@ -66,6 +66,7 @@ + diff --git a/GitVersionCore/LibGitExtensions.cs b/GitVersionCore/LibGitExtensions.cs index bd12998c17..2ffe323ca7 100644 --- a/GitVersionCore/LibGitExtensions.cs +++ b/GitVersionCore/LibGitExtensions.cs @@ -2,6 +2,7 @@ namespace GitVersion { using System; using System.Collections.Generic; + using System.IO; using System.Linq; using LibGit2Sharp; @@ -73,5 +74,59 @@ public static bool IsDetachedHead(this Branch branch) { return branch.CanonicalName.Equals("(no branch)", StringComparison.OrdinalIgnoreCase); } + + public static string GetRepositoryDirectory(this IRepository repository) + { + var gitDirectory = repository.Info.Path; + + gitDirectory = gitDirectory.TrimEnd('\\'); + + if (gitDirectory.EndsWith(".git")) + { + gitDirectory = gitDirectory.Substring(0, gitDirectory.Length - ".git".Length); + } + + return gitDirectory; + } + + public static void CheckoutFilesIfExist(this IRepository repository, params string[] fileNames) + { + if (fileNames == null || fileNames.Length == 0) + { + return; + } + + Logger.WriteInfo(string.Format("Checking out files that might be needed later in dynamic repository")); + + foreach (var fileName in fileNames) + { + try + { + Logger.WriteInfo(string.Format(" Trying to check out '{0}'", fileName)); + + var headBranch = repository.Head; + var tip = headBranch.Tip; + + var treeEntry = tip[fileName]; + if (treeEntry == null) + { + continue; + } + + var fullPath = Path.Combine(repository.GetRepositoryDirectory(), fileName); + using (var stream = ((Blob) treeEntry.Target).GetContentStream()) + { + using (var streamReader = new BinaryReader(stream)) + { + File.WriteAllBytes(fullPath, streamReader.ReadBytes((int)stream.Length)); + } + } + } + catch (Exception ex) + { + Logger.WriteWarning(string.Format(" An error occurred while checking out '{0}': '{1}'", fileName, ex.Message)); + } + } + } } } \ No newline at end of file diff --git a/GitVersionCore/SemanticVersion.cs b/GitVersionCore/SemanticVersion.cs index a1f1bd83f6..578f672ae5 100644 --- a/GitVersionCore/SemanticVersion.cs +++ b/GitVersionCore/SemanticVersion.cs @@ -5,6 +5,8 @@ namespace GitVersion public class SemanticVersion : IFormattable, IComparable { + public static SemanticVersion Empty = new SemanticVersion(); + static Regex ParseSemVer = new Regex( @"[vV]?(?(?\d+)(\.(?\d+))?(\.(?\d+))?)(\.(?\d+))?(-(?[^\+]*))?(\+(?.*))?", RegexOptions.Compiled); @@ -34,6 +36,11 @@ public bool Equals(SemanticVersion obj) BuildMetaData == obj.BuildMetaData; } + public bool IsEmpty() + { + return Equals(Empty); + } + public static bool operator ==(SemanticVersion v1, SemanticVersion v2) { if (ReferenceEquals(v1, null)) diff --git a/GitVersionCore/SemanticVersionExtensions.cs b/GitVersionCore/SemanticVersionExtensions.cs new file mode 100644 index 0000000000..002ffddfbb --- /dev/null +++ b/GitVersionCore/SemanticVersionExtensions.cs @@ -0,0 +1,22 @@ +namespace GitVersion +{ + using LibGit2Sharp; + + public static class SemanticVersionExtensions + { + public static void OverrideVersionManuallyIfNeeded(this SemanticVersion version, IRepository repository) + { + var nextVersionTxtFileFinder = new NextVersionTxtFileFinder(repository.GetRepositoryDirectory()); + var manualNextVersion = nextVersionTxtFileFinder.GetNextVersion(); + if (!manualNextVersion.IsEmpty()) + { + if (manualNextVersion > version) + { + version.Major = manualNextVersion.Major; + version.Minor = manualNextVersion.Minor; + version.Patch = manualNextVersion.Patch; + } + } + } + } +} \ No newline at end of file diff --git a/GitVersionExe/GitPreparer.cs b/GitVersionExe/GitPreparer.cs index d47fb672ef..fa1ea63394 100644 --- a/GitVersionExe/GitPreparer.cs +++ b/GitVersionExe/GitPreparer.cs @@ -73,6 +73,8 @@ string GetGitInfoFromUrl() repository.Refs.UpdateTarget("HEAD", targetBranchName); } + + repository.CheckoutFilesIfExist("NextVersion.txt"); } } diff --git a/Tests/SemanticVersionTests.cs b/Tests/SemanticVersionTests.cs index 8bcd519543..1be429565e 100644 --- a/Tests/SemanticVersionTests.cs +++ b/Tests/SemanticVersionTests.cs @@ -61,5 +61,12 @@ public void LegacySemVerTest() new SemanticVersionPreReleaseTag("AReallyReallyReallyLongBranchName", 1).ToString("lp").ShouldBe("AReallyReallyRea0001"); } + [Test] + public void EmptyVersion() + { + Assert.IsTrue(SemanticVersion.Empty.IsEmpty()); + var emptyVersion = new SemanticVersion(); + Assert.IsTrue(emptyVersion.IsEmpty()); + } } \ No newline at end of file