Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
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
26 changes: 18 additions & 8 deletions src/GitVersion.App/ArgumentParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,8 @@ private static bool ParseSwitches(Arguments arguments, string? name, IReadOnlyLi
return true;
}

if (name.IsSwitch("diag"))
if (ParseBooleanArguments(arguments, name))
{
arguments.Diag = true;
return true;
}

Expand Down Expand Up @@ -297,6 +296,23 @@ private static bool ParseSwitches(Arguments arguments, string? name, IReadOnlyLi
return true;
}

if (!name.IsSwitch("verbosity"))
{
return false;
}

arguments.Verbosity = ParseVerbosity(value);
return true;
}

private static bool ParseBooleanArguments(Arguments arguments, string? name)
{
if (name.IsSwitch("diag"))
{
arguments.Diag = true;
return true;
}

if (name.IsSwitch("nofetch"))
{
arguments.NoFetch = true;
Expand All @@ -321,12 +337,6 @@ private static bool ParseSwitches(Arguments arguments, string? name, IReadOnlyLi
return true;
}

if (name.IsSwitch("verbosity"))
{
arguments.Verbosity = ParseVerbosity(value);
return true;
}

if (!name.IsSwitch("updatewixversionfile"))
{
return false;
Expand Down
74 changes: 41 additions & 33 deletions src/GitVersion.Core/Core/GitPreparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -395,21 +395,8 @@ public void EnsureLocalBranchExistsForCurrentBranch(IRemote remote, string? curr
return;
}

const string referencePrefix = "refs/";
var isLocalBranch = currentBranch.StartsWith(ReferenceName.LocalBranchPrefix);
string localCanonicalName;
if (!currentBranch.StartsWith(referencePrefix))
{
localCanonicalName = ReferenceName.LocalBranchPrefix + currentBranch;
}
else if (isLocalBranch)
{
localCanonicalName = currentBranch;
}
else
{
localCanonicalName = ReferenceName.LocalBranchPrefix + currentBranch[referencePrefix.Length..];
}
var localCanonicalName = ResolveLocalCanonicalName(currentBranch, isLocalBranch);

var repoTip = this.repository.Head.Tip;

Expand All @@ -425,28 +412,49 @@ public void EnsureLocalBranchExistsForCurrentBranch(IRemote remote, string? curr

if (repoTipId != null)
{
var referenceName = ReferenceName.Parse(localCanonicalName);
if (this.repository.Branches.All(b => !b.Name.Equals(referenceName)))
{
this.log.Info(isLocalBranch
? $"Creating local branch {referenceName}"
: $"Creating local branch {referenceName} pointing at {repoTipId}");
this.repository.References.Add(localCanonicalName, repoTipId.Sha);
}
else
{
this.log.Info(isLocalBranch
? $"Updating local branch {referenceName} to point at {repoTipId}"
: $"Updating local branch {referenceName} to match ref {currentBranch}");
var localRef = this.repository.References[localCanonicalName];
if (localRef != null)
{
this.retryAction.Execute(() => this.repository.References.UpdateTarget(localRef, repoTipId));
}
}
CreateOrUpdateLocalBranch(localCanonicalName, repoTipId, isLocalBranch, currentBranch);
}

Checkout(localCanonicalName);
}

private static string ResolveLocalCanonicalName(string currentBranch, bool isLocalBranch)
{
const string referencePrefix = "refs/";
if (!currentBranch.StartsWith(referencePrefix))
{
return ReferenceName.LocalBranchPrefix + currentBranch;
}

if (isLocalBranch)
{
return currentBranch;
}

return ReferenceName.LocalBranchPrefix + currentBranch[referencePrefix.Length..];
}

private void CreateOrUpdateLocalBranch(string localCanonicalName, IObjectId repoTipId, bool isLocalBranch, string currentBranch)
{
var referenceName = ReferenceName.Parse(localCanonicalName);
if (this.repository.Branches.All(b => !b.Name.Equals(referenceName)))
{
this.log.Info(isLocalBranch
? $"Creating local branch {referenceName}"
: $"Creating local branch {referenceName} pointing at {repoTipId}");
this.repository.References.Add(localCanonicalName, repoTipId.Sha);
return;
}

this.log.Info(isLocalBranch
? $"Updating local branch {referenceName} to point at {repoTipId}"
: $"Updating local branch {referenceName} to match ref {currentBranch}");
var localRef = this.repository.References[localCanonicalName];
if (localRef != null)
{
this.retryAction.Execute(() => this.repository.References.UpdateTarget(localRef, repoTipId));
}
}

private void Checkout(string commitOrBranchSpec) => this.retryAction.Execute(() => this.repository.Checkout(commitOrBranchSpec));
}
59 changes: 40 additions & 19 deletions src/GitVersion.Core/Core/RepositoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,21 @@ public IEnumerable<IBranch> GetSourceBranches(

var commitBranches = FindCommitBranchesBranchedFrom(branch, configuration, excludedBranches).ToHashSet();

var ignore = CollectIgnoredMergeCommitBranches(branch, commitBranches);

RemoveCommitBranchesFoundInOtherBranches(commitBranches, ignore);

foreach (var branchGrouping in commitBranches.GroupBy(element => element.Commit, element => element.Branch))
{
foreach (var item in GetSourceBranchesForGrouping(branchGrouping, referenceLookup, returnedBranches))
{
yield return item;
}
}
}

private static HashSet<BranchCommit> CollectIgnoredMergeCommitBranches(IBranch branch, HashSet<BranchCommit> commitBranches)
{
var ignore = new HashSet<BranchCommit>();
foreach (var commitBranch in commitBranches)
{
Expand All @@ -133,6 +148,11 @@ public IEnumerable<IBranch> GetSourceBranches(
}
}

return ignore;
}

private static void RemoveCommitBranchesFoundInOtherBranches(HashSet<BranchCommit> commitBranches, HashSet<BranchCommit> ignore)
{
foreach (var item in commitBranches.Skip(1).Reverse().Where(item => !ignore.Contains(item)))
{
foreach (var commitBranch in commitBranches)
Expand All @@ -148,31 +168,32 @@ public IEnumerable<IBranch> GetSourceBranches(
}
}
}
}

foreach (var branchGrouping in commitBranches.GroupBy(element => element.Commit, element => element.Branch))
{
var referenceMatchFound = false;
var referenceNames = referenceLookup[branchGrouping.Key.Sha].Select(element => element.Name).ToHashSet();
private static IEnumerable<IBranch> GetSourceBranchesForGrouping(
IGrouping<ICommit, IBranch> branchGrouping, ILookup<string, IReference> referenceLookup, HashSet<IBranch> returnedBranches)
{
var referenceMatchFound = false;
var referenceNames = referenceLookup[branchGrouping.Key.Sha].Select(element => element.Name).ToHashSet();

foreach (var item in branchGrouping.Where(item => referenceNames.Contains(item.Name)))
foreach (var item in branchGrouping.Where(item => referenceNames.Contains(item.Name)))
{
if (returnedBranches.Add(item))
{
if (returnedBranches.Add(item))
{
yield return item;
}

referenceMatchFound = true;
yield return item;
}

if (referenceMatchFound)
{
continue;
}
referenceMatchFound = true;
}

foreach (var item in branchGrouping.Where(returnedBranches.Add))
{
yield return item;
}
if (referenceMatchFound)
{
yield break;
}

foreach (var item in branchGrouping.Where(returnedBranches.Add))
{
yield return item;
}
}

Expand Down
123 changes: 49 additions & 74 deletions src/GitVersion.Core/SemVer/SemanticVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -362,76 +362,56 @@ public SemanticVersion Increment(
public SemanticVersion Increment(
VersionField increment, string? label, IncrementMode mode, params SemanticVersion?[] alternativeSemanticVersions)
{
var major = Major;
var minor = Minor;
var patch = Patch;
var preReleaseNumber = PreReleaseTag.Number;

var hasPreReleaseTag = PreReleaseTag.HasTag();

switch (increment)
{
case VersionField.None:
preReleaseNumber++;
break;
var (major, minor, patch, preReleaseNumber) = ApplyIncrement(increment, mode, hasPreReleaseTag);

case VersionField.Patch:
if (hasPreReleaseTag && (mode == IncrementMode.Standard
|| (mode == IncrementMode.EnsureIntegrity && patch != 0)))
{
preReleaseNumber++;
}
else
{
patch++;
if (preReleaseNumber.HasValue)
{
preReleaseNumber = 1;
}
}
break;
var (semanticVersion, foundAlternativeSemanticVersion) =
SelectAlternativeIfGreater(new SemanticVersion(major, minor, patch), alternativeSemanticVersions);
major = semanticVersion.Major;
minor = semanticVersion.Minor;
patch = semanticVersion.Patch;

case VersionField.Minor:
if (hasPreReleaseTag && (mode == IncrementMode.Standard
|| (mode == IncrementMode.EnsureIntegrity && minor != 0 && patch == 0)))
{
preReleaseNumber++;
}
else
{
minor++;
patch = 0;
if (preReleaseNumber.HasValue)
{
preReleaseNumber = 1;
}
}
break;
if (foundAlternativeSemanticVersion && increment == VersionField.None)
{
preReleaseNumber = 1;
}

case VersionField.Major:
if (hasPreReleaseTag && (mode == IncrementMode.Standard
|| (mode == IncrementMode.EnsureIntegrity && major != 0 && minor == 0 && patch == 0)))
{
preReleaseNumber++;
}
else
{
major++;
minor = 0;
patch = 0;
if (preReleaseNumber.HasValue)
{
preReleaseNumber = 1;
}
}
break;
return BuildIncrementedVersion(major, minor, patch, preReleaseNumber, hasPreReleaseTag, label);
}

default:
throw new ArgumentOutOfRangeException(nameof(increment));
private (long Major, long Minor, long Patch, long? PreReleaseNumber) ApplyIncrement(
VersionField increment, IncrementMode mode, bool hasPreReleaseTag)
{
var preReleaseNumber = PreReleaseTag.Number;
return increment switch
{
VersionField.None => (Major, Minor, Patch, preReleaseNumber + 1),
VersionField.Patch => IncrementField(mode, hasPreReleaseTag, Patch != 0, Major, Minor, Patch + 1, preReleaseNumber),
VersionField.Minor => IncrementField(mode, hasPreReleaseTag, Minor != 0 && Patch == 0, Major, Minor + 1, 0, preReleaseNumber),
VersionField.Major => IncrementField(mode, hasPreReleaseTag, Major != 0 && Minor == 0 && Patch == 0, Major + 1, 0, 0, preReleaseNumber),
_ => throw new ArgumentOutOfRangeException(nameof(increment))
};
}

private (long Major, long Minor, long Patch, long? PreReleaseNumber) IncrementField(
IncrementMode mode, bool hasPreReleaseTag, bool integrityCondition,
long bumpedMajor, long bumpedMinor, long bumpedPatch, long? preReleaseNumber)
{
if (ShouldIncrementPreReleaseNumber(mode, hasPreReleaseTag, integrityCondition))
{
return (Major, Minor, Patch, preReleaseNumber + 1);
}

SemanticVersion semanticVersion = new(major, minor, patch);
return (bumpedMajor, bumpedMinor, bumpedPatch, preReleaseNumber.HasValue ? 1 : preReleaseNumber);
}

private static bool ShouldIncrementPreReleaseNumber(IncrementMode mode, bool hasPreReleaseTag, bool integrityCondition)
=> hasPreReleaseTag && (mode == IncrementMode.Standard || (mode == IncrementMode.EnsureIntegrity && integrityCondition));

private static (SemanticVersion Version, bool Found) SelectAlternativeIfGreater(
SemanticVersion semanticVersion, SemanticVersion?[] alternativeSemanticVersions)
{
var foundAlternativeSemanticVersion = false;
foreach (var alternativeSemanticVersion in alternativeSemanticVersions)
{
Expand All @@ -444,15 +424,12 @@ public SemanticVersion Increment(
foundAlternativeSemanticVersion = true;
}

major = semanticVersion.Major;
minor = semanticVersion.Minor;
patch = semanticVersion.Patch;

if (foundAlternativeSemanticVersion && increment == VersionField.None)
{
preReleaseNumber = 1;
}
return (semanticVersion, foundAlternativeSemanticVersion);
}

private SemanticVersion BuildIncrementedVersion(
long major, long minor, long patch, long? preReleaseNumber, bool hasPreReleaseTag, string? label)
{
string preReleaseTagName;
if (hasPreReleaseTag)
{
Expand All @@ -464,14 +441,12 @@ public SemanticVersion Increment(
preReleaseTagName = string.Empty;
}

if (label is null || preReleaseTagName == label)
if (label is not null && preReleaseTagName != label)
{
return new SemanticVersion(this) { Major = major, Minor = minor, Patch = patch, PreReleaseTag = new SemanticVersionPreReleaseTag(preReleaseTagName, preReleaseNumber, true) };
preReleaseNumber = 1;
preReleaseTagName = label;
}

preReleaseNumber = 1;
preReleaseTagName = label;

return new SemanticVersion(this)
{
Major = major,
Expand Down
Loading
Loading