Skip to content

Commit 1d1dc81

Browse files
committed
Merge pull request #32 from nulltoken/ntk/fix/detached_head
Resolving Pull Requests in TeamCity context
2 parents 95626b2 + d13c760 commit 1d1dc81

File tree

111 files changed

+1604
-629
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+1604
-629
lines changed

GitFlowVersion/BranchClassifier.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public static bool IsFeature(this Branch branch)
4242

4343
public static bool IsPullRequest(this Branch branch)
4444
{
45-
return branch.CanonicalName.Contains("/pull/") || TeamCity.IsBuildingAPullRequest();
45+
return branch.CanonicalName.Contains("/pull/");
4646
}
4747
}
48-
}
48+
}

GitFlowVersion/BranchFinders/DevelopVersionFinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ SemanticVersion GetSemanticVersion()
3535
};
3636
var versionFromMaster = versionOnMasterFinder.Execute();
3737

38-
var developBranch = Repository.GetBranch("develop");
38+
var developBranch = Repository.Branches["develop"];
3939
var preReleasePartOne = developBranch.Commits
4040
.SkipWhile(x => x != Commit)
4141
.TakeWhile(x => x.When() >= versionFromMaster.Timestamp)

GitFlowVersion/BranchFinders/FeatureVersionFinder.cs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ public FeatureVersionFinder()
1818

1919
public VersionAndBranch FindVersion()
2020
{
21+
var ancestor = FindCommonAncestorWithDevelop();
22+
2123
var firstCommitOnBranch = FindFirstCommitOnBranchFunc();
2224

23-
if (firstCommitOnBranch == Commit.Id) //no commits on branch. use develop approach
25+
if (firstCommitOnBranch == null) //no commits on branch. use develop approach
2426
{
2527
var developVersionFinder = new DevelopVersionFinder
2628
{
@@ -52,15 +54,45 @@ public VersionAndBranch FindVersion()
5254
Patch = 0,
5355
Stability = Stability.Unstable,
5456
PreReleasePartOne = 0,
55-
Suffix = firstCommitOnBranch.Prefix()
57+
Suffix = ancestor.Prefix()
5658
}
5759
};
5860
}
5961

62+
private Commit FindCommonAncestorWithDevelop()
63+
{
64+
var ancestor = Repository.Commits.FindCommonAncestor(
65+
Repository.Branches["develop"].Tip,
66+
FeatureBranch.Tip);
67+
68+
if (ancestor != null)
69+
{
70+
return ancestor;
71+
}
72+
73+
throw new ErrorException(
74+
"A feature branch is expected to branch off of 'develop'. "
75+
+ string.Format("However, branch 'develop' and '{0}' do not share a common ancestor."
76+
, FeatureBranch.Name));
77+
}
78+
6079

6180
public ObjectId FindFirstCommitOnBranch()
6281
{
63-
return Repository.Refs.Log(FeatureBranch.CanonicalName).Last().To;
82+
var filter = new CommitFilter
83+
{
84+
Since = FeatureBranch,
85+
Until = Repository.Branches["develop"]
86+
};
87+
88+
var commits = Repository.Commits.QueryBy(filter).ToList();
89+
90+
if (commits.Count == 0)
91+
{
92+
return null;
93+
}
94+
95+
return commits.Last().Id;
6496
}
6597
}
6698

GitFlowVersion/BranchFinders/HotfixVersionFinder.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ class HotfixVersionFinder
1212

1313
public VersionAndBranch FindVersion()
1414
{
15+
EnsureHotfixBranchShareACommonAncestorWithMaster();
16+
1517
var versionString = HotfixBranch.GetHotfixSuffix();
1618

1719
int patch;
@@ -63,5 +65,22 @@ public VersionAndBranch FindVersion()
6365
throw new Exception(message);
6466

6567
}
68+
69+
private void EnsureHotfixBranchShareACommonAncestorWithMaster()
70+
{
71+
var ancestor = Repository.Commits.FindCommonAncestor(
72+
Repository.Branches["master"].Tip,
73+
HotfixBranch.Tip);
74+
75+
if (ancestor != null)
76+
{
77+
return;
78+
}
79+
80+
throw new ErrorException(
81+
"A hotfix branch is expected to branch off of 'master'. "
82+
+ string.Format("However, branch 'master' and '{0}' do not share a common ancestor."
83+
, HotfixBranch.Name));
84+
}
6685
}
67-
}
86+
}

GitFlowVersion/BranchFinders/PullVersionFinder.cs

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class PullVersionFinder
1010

1111
public VersionAndBranch FindVersion()
1212
{
13+
EnsurePullBranchShareACommonAncestorWithDevelop();
14+
1315
var versionOnMasterFinder = new VersionOnMasterFinder
1416
{
1517
Repository = Repository,
@@ -18,16 +20,7 @@ public VersionAndBranch FindVersion()
1820
var versionFromMaster = versionOnMasterFinder
1921
.Execute();
2022

21-
string suffix;
22-
if (TeamCity.IsBuildingAPullRequest())
23-
{
24-
suffix = TeamCity.CurrentPullRequestNo().ToString();
25-
}
26-
else
27-
{
28-
suffix = PullBranch.CanonicalName.Substring(PullBranch.CanonicalName.IndexOf("/pull/") + 6);
29-
}
30-
23+
var suffix = ExtractIssueNumber();
3124

3225
return new VersionAndBranch
3326
{
@@ -45,5 +38,62 @@ public VersionAndBranch FindVersion()
4538
}
4639
};
4740
}
41+
42+
private string ExtractIssueNumber()
43+
{
44+
const string prefix = "/pull/";
45+
int start = PullBranch.CanonicalName.IndexOf(prefix, System.StringComparison.Ordinal);
46+
int end = PullBranch.CanonicalName.LastIndexOf("/merge", PullBranch.CanonicalName.Length - 1,
47+
System.StringComparison.Ordinal);
48+
49+
string issueNumber = null;
50+
51+
if (start != -1 && end != -1 && start + prefix.Length <= end)
52+
{
53+
start += prefix.Length;
54+
issueNumber = PullBranch.CanonicalName.Substring(start, end - start);
55+
}
56+
57+
if (!LooksLikeAValidPullRequestNumber(issueNumber))
58+
{
59+
throw new ErrorException(string.Format("Unable to extract pull request number from '{0}'.",
60+
PullBranch.CanonicalName));
61+
}
62+
63+
return issueNumber;
64+
}
65+
66+
private bool LooksLikeAValidPullRequestNumber(string issueNumber)
67+
{
68+
if (string.IsNullOrEmpty(issueNumber))
69+
{
70+
return false;
71+
}
72+
73+
uint res;
74+
if (!uint.TryParse(issueNumber, out res))
75+
{
76+
return false;
77+
}
78+
79+
return true;
80+
}
81+
82+
private void EnsurePullBranchShareACommonAncestorWithDevelop()
83+
{
84+
var ancestor = Repository.Commits.FindCommonAncestor(
85+
Repository.Branches["develop"].Tip,
86+
PullBranch.Tip);
87+
88+
if (ancestor != null)
89+
{
90+
return;
91+
}
92+
93+
throw new ErrorException(
94+
"A pull request branch is expected to branch off of 'develop'. "
95+
+ string.Format("However, branch 'develop' and '{0}' do not share a common ancestor."
96+
, PullBranch.Name));
97+
}
4898
}
49-
}
99+
}

GitFlowVersion/GitFlowVersionFinder.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace GitFlowVersion
22
{
3+
using System;
34
using LibGit2Sharp;
45

56
public class GitFlowVersionFinder
@@ -10,6 +11,8 @@ public class GitFlowVersionFinder
1011

1112
public VersionAndBranch FindVersion()
1213
{
14+
EnsureMainTopologyConstraints();
15+
1316
if (Branch.IsMaster())
1417
{
1518
return new MasterVersionFinder
@@ -73,5 +76,35 @@ public VersionAndBranch FindVersion()
7376
FeatureBranch = Branch
7477
}.FindVersion();
7578
}
79+
80+
private void EnsureMainTopologyConstraints()
81+
{
82+
EnsureLocalBranchExists("master");
83+
EnsureLocalBranchExists("develop");
84+
EnsureHeadIsNotDetached();
85+
}
86+
87+
private void EnsureHeadIsNotDetached()
88+
{
89+
if (!Branch.CanonicalName.Equals("(no branch)", StringComparison.OrdinalIgnoreCase))
90+
{
91+
return;
92+
}
93+
94+
throw new ErrorException(
95+
string.Format("It looks like the branch being examined is a detached Head pointing to commit '{0}'. "
96+
+ "Without a proper branch name GITFlowVersion cannot determine the build version."
97+
, Branch.Tip.Id.ToString(7)));
98+
}
99+
100+
private void EnsureLocalBranchExists(string branchName)
101+
{
102+
if (Repository.Branches[branchName] != null)
103+
{
104+
return;
105+
}
106+
107+
throw new ErrorException(string.Format("This repository doesn't contain a branch named '{0}'. Please create one.", branchName));
108+
}
76109
}
77-
}
110+
}

GitFlowVersion/LibGitExtensions.cs

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -55,51 +55,5 @@ public static IEnumerable<Commit> CommitsPriorToThan(this Branch branch, DateTim
5555
{
5656
return branch.Commits.SkipWhile(c => c.When() > olderThan);
5757
}
58-
59-
public static Branch GetBranch(this IRepository repository, string name)
60-
{
61-
var branch = repository.Branches.FirstOrDefault(b => b.Name == name);
62-
63-
if (branch == null)
64-
{
65-
66-
if (!repository.Network.Remotes.Any())
67-
{
68-
Logger.WriteInfo("No remotes found");
69-
}
70-
else
71-
{
72-
var remote = repository.Network.Remotes.First();
73-
74-
Logger.WriteInfo(string.Format("No local branch with name {0} found, going to try on the remote {1}({2})", name, remote.Name, remote.Url));
75-
try
76-
{
77-
repository.Network.Fetch(remote);
78-
}
79-
catch (LibGit2SharpException exception)
80-
{
81-
if (exception.Message.Contains("This transport isn't implemented"))
82-
{
83-
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);
84-
throw new MissingBranchException(message, exception);
85-
}
86-
throw;
87-
}
88-
89-
branch = repository.Branches.FirstOrDefault(b => b.Name.EndsWith("/" + name));
90-
}
91-
}
92-
93-
if (branch == null)
94-
{
95-
var branchNames = string.Join(";", repository.Branches);
96-
var message = string.Format("Could not find branch '{0}' in the repository, please create one. Existing branches:{1}", name, branchNames);
97-
throw new Exception(message);
98-
}
99-
100-
return branch;
101-
}
102-
103-
10458
}
10559
}

0 commit comments

Comments
 (0)