Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions GitFlowVersion/BranchClassifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static bool IsFeature(this Branch branch)

public static bool IsPullRequest(this Branch branch)
{
return branch.CanonicalName.Contains("/pull/") || TeamCity.IsBuildingAPullRequest();
return branch.CanonicalName.Contains("/pull/");
}
}
}
}
2 changes: 1 addition & 1 deletion GitFlowVersion/BranchFinders/DevelopVersionFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ SemanticVersion GetSemanticVersion()
};
var versionFromMaster = versionOnMasterFinder.Execute();

var developBranch = Repository.GetBranch("develop");
var developBranch = Repository.Branches["develop"];
var preReleasePartOne = developBranch.Commits
.SkipWhile(x => x != Commit)
.TakeWhile(x => x.When() >= versionFromMaster.Timestamp)
Expand Down
38 changes: 35 additions & 3 deletions GitFlowVersion/BranchFinders/FeatureVersionFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ public FeatureVersionFinder()

public VersionAndBranch FindVersion()
{
var ancestor = FindCommonAncestorWithDevelop();

var firstCommitOnBranch = FindFirstCommitOnBranchFunc();

if (firstCommitOnBranch == Commit.Id) //no commits on branch. use develop approach
if (firstCommitOnBranch == null) //no commits on branch. use develop approach
{
var developVersionFinder = new DevelopVersionFinder
{
Expand Down Expand Up @@ -52,15 +54,45 @@ public VersionAndBranch FindVersion()
Patch = 0,
Stability = Stability.Unstable,
PreReleasePartOne = 0,
Suffix = firstCommitOnBranch.Prefix()
Suffix = ancestor.Prefix()
}
};
}

private Commit FindCommonAncestorWithDevelop()
{
var ancestor = Repository.Commits.FindCommonAncestor(
Repository.Branches["develop"].Tip,
FeatureBranch.Tip);

if (ancestor != null)
{
return ancestor;
}

throw new ErrorException(
"A feature branch is expected to branch off of 'develop'. "
+ string.Format("However, branch 'develop' and '{0}' do not share a common ancestor."
, FeatureBranch.Name));
}


public ObjectId FindFirstCommitOnBranch()
{
return Repository.Refs.Log(FeatureBranch.CanonicalName).Last().To;
var filter = new CommitFilter
{
Since = FeatureBranch,
Until = Repository.Branches["develop"]
};

var commits = Repository.Commits.QueryBy(filter).ToList();

if (commits.Count == 0)
{
return null;
}

return commits.Last().Id;
}
}

Expand Down
21 changes: 20 additions & 1 deletion GitFlowVersion/BranchFinders/HotfixVersionFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class HotfixVersionFinder

public VersionAndBranch FindVersion()
{
EnsureHotfixBranchShareACommonAncestorWithMaster();

var versionString = HotfixBranch.GetHotfixSuffix();

int patch;
Expand Down Expand Up @@ -63,5 +65,22 @@ public VersionAndBranch FindVersion()
throw new Exception(message);

}

private void EnsureHotfixBranchShareACommonAncestorWithMaster()
{
var ancestor = Repository.Commits.FindCommonAncestor(
Repository.Branches["master"].Tip,
HotfixBranch.Tip);

if (ancestor != null)
{
return;
}

throw new ErrorException(
"A hotfix branch is expected to branch off of 'master'. "
+ string.Format("However, branch 'master' and '{0}' do not share a common ancestor."
, HotfixBranch.Name));
}
}
}
}
72 changes: 61 additions & 11 deletions GitFlowVersion/BranchFinders/PullVersionFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class PullVersionFinder

public VersionAndBranch FindVersion()
{
EnsurePullBranchShareACommonAncestorWithDevelop();

var versionOnMasterFinder = new VersionOnMasterFinder
{
Repository = Repository,
Expand All @@ -18,16 +20,7 @@ public VersionAndBranch FindVersion()
var versionFromMaster = versionOnMasterFinder
.Execute();

string suffix;
if (TeamCity.IsBuildingAPullRequest())
{
suffix = TeamCity.CurrentPullRequestNo().ToString();
}
else
{
suffix = PullBranch.CanonicalName.Substring(PullBranch.CanonicalName.IndexOf("/pull/") + 6);
}

var suffix = ExtractIssueNumber();

return new VersionAndBranch
{
Expand All @@ -45,5 +38,62 @@ public VersionAndBranch FindVersion()
}
};
}

private string ExtractIssueNumber()
{
const string prefix = "/pull/";
int start = PullBranch.CanonicalName.IndexOf(prefix, System.StringComparison.Ordinal);
int end = PullBranch.CanonicalName.LastIndexOf("/merge", PullBranch.CanonicalName.Length - 1,
System.StringComparison.Ordinal);

string issueNumber = null;

if (start != -1 && end != -1 && start + prefix.Length <= end)
{
start += prefix.Length;
issueNumber = PullBranch.CanonicalName.Substring(start, end - start);
}

if (!LooksLikeAValidPullRequestNumber(issueNumber))
{
throw new ErrorException(string.Format("Unable to extract pull request number from '{0}'.",
PullBranch.CanonicalName));
}

return issueNumber;
}

private bool LooksLikeAValidPullRequestNumber(string issueNumber)
{
if (string.IsNullOrEmpty(issueNumber))
{
return false;
}

uint res;
if (!uint.TryParse(issueNumber, out res))
{
return false;
}

return true;
}

private void EnsurePullBranchShareACommonAncestorWithDevelop()
{
var ancestor = Repository.Commits.FindCommonAncestor(
Repository.Branches["develop"].Tip,
PullBranch.Tip);

if (ancestor != null)
{
return;
}

throw new ErrorException(
"A pull request branch is expected to branch off of 'develop'. "
+ string.Format("However, branch 'develop' and '{0}' do not share a common ancestor."
, PullBranch.Name));
}
}
}
}
35 changes: 34 additions & 1 deletion GitFlowVersion/GitFlowVersionFinder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace GitFlowVersion
{
using System;
using LibGit2Sharp;

public class GitFlowVersionFinder
Expand All @@ -10,6 +11,8 @@ public class GitFlowVersionFinder

public VersionAndBranch FindVersion()
{
EnsureMainTopologyConstraints();

if (Branch.IsMaster())
{
return new MasterVersionFinder
Expand Down Expand Up @@ -73,5 +76,35 @@ public VersionAndBranch FindVersion()
FeatureBranch = Branch
}.FindVersion();
}

private void EnsureMainTopologyConstraints()
{
EnsureLocalBranchExists("master");
EnsureLocalBranchExists("develop");
EnsureHeadIsNotDetached();
}

private void EnsureHeadIsNotDetached()
{
if (!Branch.CanonicalName.Equals("(no branch)", StringComparison.OrdinalIgnoreCase))
{
return;
}

throw new ErrorException(
string.Format("It looks like the branch being examined is a detached Head pointing to commit '{0}'. "
+ "Without a proper branch name GITFlowVersion cannot determine the build version."
, Branch.Tip.Id.ToString(7)));
}

private void EnsureLocalBranchExists(string branchName)
{
if (Repository.Branches[branchName] != null)
{
return;
}

throw new ErrorException(string.Format("This repository doesn't contain a branch named '{0}'. Please create one.", branchName));
}
}
}
}
46 changes: 0 additions & 46 deletions GitFlowVersion/LibGitExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,51 +55,5 @@ public static IEnumerable<Commit> CommitsPriorToThan(this Branch branch, DateTim
{
return branch.Commits.SkipWhile(c => c.When() > olderThan);
}

public static Branch GetBranch(this IRepository repository, string name)
{
var branch = repository.Branches.FirstOrDefault(b => b.Name == name);

if (branch == null)
{

if (!repository.Network.Remotes.Any())
{
Logger.WriteInfo("No remotes found");
}
else
{
var remote = repository.Network.Remotes.First();

Logger.WriteInfo(string.Format("No local branch with name {0} found, going to try on the remote {1}({2})", name, remote.Name, remote.Url));
try
{
repository.Network.Fetch(remote);
}
catch (LibGit2SharpException exception)
{
if (exception.Message.Contains("This transport isn't implemented"))
{
var message = string.Format("Could not fetch from '{0}' since LibGit2 does not support the transport. You have most likely cloned using SSH. If there is a remote branch named '{1}' then fetch it manually, otherwise please create a local branch named '{1}'.", remote.Url, name);
throw new MissingBranchException(message, exception);
}
throw;
}

branch = repository.Branches.FirstOrDefault(b => b.Name.EndsWith("/" + name));
}
}

if (branch == null)
{
var branchNames = string.Join(";", repository.Branches);
var message = string.Format("Could not find branch '{0}' in the repository, please create one. Existing branches:{1}", name, branchNames);
throw new Exception(message);
}

return branch;
}


}
}
Loading