11namespace GitVersion . VersionCalculation
22{
3+ using System ;
34 using System . Linq ;
45 using System . Text . RegularExpressions ;
56 using BaseVersionCalculators ;
7+ using LibGit2Sharp ;
68
79 public class NextVersionCalculator
810 {
@@ -41,12 +43,19 @@ public SemanticVersion FindVersion(GitVersionContext context)
4143
4244 var baseVersion = baseVersionFinder . GetBaseVersion ( context ) ;
4345 var semver = baseVersion . SemanticVersion ;
44- var increment = IncrementStrategyFinder . DetermineIncrementedField ( context , baseVersion ) ;
45- if ( increment != null )
46+ if ( context . Configuration . VersioningMode == VersioningMode . Mainline )
4647 {
47- semver = semver . IncrementVersion ( increment . Value ) ;
48+ semver = FindMainlineModeVersion ( baseVersion , context ) ;
49+ }
50+ else
51+ {
52+ var increment = IncrementStrategyFinder . DetermineIncrementedField ( context , baseVersion ) ;
53+ if ( increment != null )
54+ {
55+ semver = semver . IncrementVersion ( increment . Value ) ;
56+ }
57+ else Logger . WriteInfo ( "Skipping version increment" ) ;
4858 }
49- else Logger . WriteInfo ( "Skipping version increment" ) ;
5059
5160 if ( ! semver . PreReleaseTag . HasTag ( ) && ! string . IsNullOrEmpty ( context . Configuration . Tag ) )
5261 {
@@ -64,6 +73,52 @@ public SemanticVersion FindVersion(GitVersionContext context)
6473 return taggedSemanticVersion ?? semver ;
6574 }
6675
76+ private SemanticVersion FindMainlineModeVersion ( BaseVersion baseVersion , GitVersionContext context )
77+ {
78+ if ( baseVersion . SemanticVersion . PreReleaseTag . HasTag ( ) )
79+ {
80+ throw new NotSupportedException ( "Mainline development mode doesn't yet support pre-release tags on master" ) ;
81+ }
82+ Logger . WriteInfo ( "Using mainline development mode to calculate current version" ) ;
83+ var commitLog = context . Repository . Commits . QueryBy ( new CommitFilter
84+ {
85+ IncludeReachableFrom = context . CurrentBranch ,
86+ ExcludeReachableFrom = baseVersion . BaseVersionSource ,
87+ SortBy = CommitSortStrategies . Reverse
88+ } ) . ToList ( ) ;
89+ var mergeCommits = commitLog
90+ . Where ( l => l . Parents . Count ( ) > 1 )
91+ . ToList ( ) ;
92+ return mergeCommits
93+ . Select ( mc =>
94+ {
95+ var mergedHead = GetMergedHead ( mc ) ;
96+ var findMergeBase = context . Repository . ObjectDatabase . FindMergeBase ( mc . Parents . First ( ) , mergedHead ) ;
97+ var filter = new CommitFilter
98+ {
99+ IncludeReachableFrom = mergedHead ,
100+ ExcludeReachableFrom = findMergeBase
101+ } ;
102+ var mergedCommits = context . Repository . Commits . QueryBy ( filter ) . ToList ( ) ;
103+ return new
104+ {
105+ MergeCommit = mc ,
106+ MergeHead = mergedHead ,
107+ MergeBase = findMergeBase ,
108+ Increment = IncrementStrategyFinder . GetIncrementForCommits ( context , mergedCommits )
109+ } ;
110+ } )
111+ . Aggregate ( baseVersion . SemanticVersion , ( v , i ) => v . IncrementVersion ( i . Increment ?? VersionField . Patch ) ) ;
112+ }
113+
114+ private Commit GetMergedHead ( Commit mergeCommit )
115+ {
116+ var parents = mergeCommit . Parents . Skip ( 1 ) . ToList ( ) ;
117+ if ( parents . Count > 1 )
118+ throw new NotSupportedException ( "Mainline development does not support more than one merge source in a single commit yet" ) ;
119+ return parents . Single ( ) ;
120+ }
121+
67122 void UpdatePreReleaseTag ( GitVersionContext context , SemanticVersion semanticVersion , string branchNameOverride )
68123 {
69124 var tagToUse = GetBranchSpecificTag ( context . Configuration , context . CurrentBranch . FriendlyName , branchNameOverride ) ;
@@ -78,7 +133,7 @@ void UpdatePreReleaseTag(GitVersionContext context, SemanticVersion semanticVers
78133 number = int . Parse ( numberGroup . Value ) ;
79134 }
80135 }
81-
136+
82137 var lastTag = context . CurrentBranch
83138 . GetVersionTagsOnBranch ( context . Repository , context . Configuration . GitTagPrefix )
84139 . FirstOrDefault ( v => v . PreReleaseTag . Name == tagToUse ) ;
0 commit comments