Skip to content

Commit

Permalink
Cherry pick commits from branch fix643 up to commit 3d0d77b.
Browse files Browse the repository at this point in the history
  • Loading branch information
tg73 committed Sep 27, 2021
1 parent fa7c948 commit 2e74568
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/NerdBank.GitVersioning/GitContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ public static GitContext Create(string path, string? committish = null, bool wri
/// <returns>A string that is at least <paramref name="minLength"/> in length but may be more as required to uniquely identify the git object identified by <see cref="GitCommitId"/>.</returns>
public abstract string GetShortUniqueCommitId(int minLength);

internal abstract int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion);
internal abstract (int height, string? nearestRelevantCommit) CalculateVersionHeightAndNearestRelevantCommit(VersionOptions? committedVersion, VersionOptions? workingVersion);

internal abstract Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight);

Expand Down
6 changes: 5 additions & 1 deletion src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ public override bool TrySelectCommit(string committish)
/// <inheritdoc/>
public override string GetShortUniqueCommitId(int minLength) => this.Repository.ObjectDatabase.ShortenObjectId(this.Commit, minLength);

internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion)
internal override (int height, string? nearestRelevantCommit) CalculateVersionHeightAndNearestRelevantCommit(VersionOptions? committedVersion, VersionOptions? workingVersion)
{
throw new NotImplementedException("nearestRelevantCommit for libgit2");

#if false
var headCommitVersion = committedVersion?.Version ?? SemVer0;

if (IsVersionFileChangedInWorkingTree(committedVersion, workingVersion))
Expand All @@ -99,6 +102,7 @@ internal override int CalculateVersionHeight(VersionOptions? committedVersion, V
}

return LibGit2GitExtensions.GetVersionHeight(this);
#endif
}

internal override System.Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight)
Expand Down
7 changes: 4 additions & 3 deletions src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public static ManagedGitContext Create(string path, string? committish = null)
};
}

internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion)
internal override (int height, string? nearestRelevantCommit) CalculateVersionHeightAndNearestRelevantCommit(VersionOptions? committedVersion, VersionOptions? workingVersion)
{
var headCommitVersion = committedVersion?.Version ?? SemVer0;

Expand All @@ -98,11 +98,12 @@ internal override int CalculateVersionHeight(VersionOptions? committedVersion, V
{
// The working copy has changed the major.minor version.
// So by definition the version height is 0, since no commit represents it yet.
return 0;
return (0, null);
}
}

return GitExtensions.GetVersionHeight(this);
var (height, nearestRelevantCommit) = GitExtensions.GetVersionHeight(this);
return (height, nearestRelevantCommit?.Sha.ToString());
}

internal override Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight)
Expand Down
37 changes: 26 additions & 11 deletions src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,40 @@ internal static class GitExtensions
/// <summary>
/// Gets the number of commits in the longest single path between
/// the specified commit and the most distant ancestor (inclusive)
/// that set the version to the value at <paramref name="context"/>.
/// that set the version to the value at <paramref name="context"/>,
/// and the nearest commit that is part of that path, taking into
/// account path filters.
/// </summary>
/// <param name="context">The git context for which to calculate the height.</param>
/// <param name="baseVersion">Optional base version to calculate the height. If not specified, the base version will be calculated by scanning the repository.</param>
/// <returns>The height of the commit. Always a positive integer.</returns>
internal static int GetVersionHeight(ManagedGitContext context, Version? baseVersion = null)
/// <returns>The height of the commit (always a positive integer), and a <see cref="GitContext"/> representing the nearest relevant commit, or <see langword="null"/> if there is no relevant commit.</returns>
internal static (int height, GitCommit? nearestRelevantCommit) GetVersionHeight(ManagedGitContext context, Version? baseVersion = null)
{
if (context.Commit is null)
{
return 0;
return (0, null);
}

var tracker = new GitWalkTracker(context);

var versionOptions = tracker.GetVersion(context.Commit.Value);
if (versionOptions == null)
{
return 0;
return (0, null);
}

var baseSemVer =
baseVersion != null ? SemanticVersion.Parse(baseVersion.ToString()) :
versionOptions.Version ?? SemVer0;

// TODO: What if versionHeightPosition is not set, but we still want to know the nearest relevant commit id?
var versionHeightPosition = versionOptions.VersionHeightPosition;
if (versionHeightPosition.HasValue)
{
int height = GetHeight(context, c => CommitMatchesVersion(c, baseSemVer, versionHeightPosition.Value, tracker));
return height;
return GetHeight(context, c => CommitMatchesVersion(c, baseSemVer, versionHeightPosition.Value, tracker));
}

return 0;
return (0, null);
}

/// <summary>
Expand Down Expand Up @@ -94,11 +96,11 @@ private static bool CommitMatchesVersion(GitCommit commit, SemanticVersion expec
/// May be null to count the height to the original commit.
/// </param>
/// <returns>The height of the commit. Always a positive integer.</returns>
public static int GetHeight(ManagedGitContext context, Func<GitCommit, bool>? continueStepping = null)
public static (int height, GitCommit? nearestRelevantCommit) GetHeight(ManagedGitContext context, Func<GitCommit, bool>? continueStepping = null)
{
Verify.Operation(context.Commit.HasValue, "No commit is selected.");
var tracker = new GitWalkTracker(context);
return GetCommitHeight(context.Repository, context.Commit.Value, tracker, continueStepping);
return (GetCommitHeight(context.Repository, context.Commit.Value, tracker, continueStepping), tracker.NearestCommit);
}

/// <summary>
Expand Down Expand Up @@ -306,14 +308,27 @@ private class GitWalkTracker
private readonly Dictionary<GitObjectId, int> heights = new Dictionary<GitObjectId, int>();
private readonly ManagedGitContext context;

private int nearestCommitHeight = -1;

internal GitCommit? NearestCommit { get; private set; }

internal GitWalkTracker(ManagedGitContext context)
{
this.context = context;
}

internal bool TryGetVersionHeight(GitCommit commit, out int height) => this.heights.TryGetValue(commit.Sha, out height);

internal void RecordHeight(GitCommit commit, int height) => this.heights.Add(commit.Sha, height);
internal void RecordHeight(GitCommit commit, int height)
{
if ( height > this.nearestCommitHeight)
{
this.NearestCommit = commit;
this.nearestCommitHeight = height;
}

this.heights.Add(commit.Sha, height);
}

internal VersionOptions? GetVersion(GitCommit commit)
{
Expand Down
3 changes: 3 additions & 0 deletions src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ public static GitObjectId ParseHex(ReadOnlySpan<byte> value)

bytes[i >> 1] = (byte)(c1 + c2);
}

// Clear any cached sha. This can happen when debugging, and is very confusing.
objectId.sha = null;

return objectId;
}
Expand Down
2 changes: 1 addition & 1 deletion src/NerdBank.GitVersioning/NoGit/NoGitContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public NoGitContext(string workingTreePath)
public override void Stage(string path) => throw new InvalidOperationException(NotAGitRepoMessage);
public override string GetShortUniqueCommitId(int minLength) => throw new InvalidOperationException(NotAGitRepoMessage);
public override bool TrySelectCommit(string committish) => throw new InvalidOperationException(NotAGitRepoMessage);
internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion) => 0;
internal override (int height, string? nearestRelevantCommit) CalculateVersionHeightAndNearestRelevantCommit(VersionOptions? committedVersion, VersionOptions? workingVersion) => (0, null);
internal override Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight) => throw new NotImplementedException();
}
}
13 changes: 12 additions & 1 deletion src/NerdBank.GitVersioning/VersionOracle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ public VersionOracle(GitContext context, ICloudBuild? cloudBuild = null, int? ov
}

this.BuildingRef = cloudBuild?.BuildingTag ?? cloudBuild?.BuildingBranch ?? context.HeadCanonicalName;
string? nearestRelevantCommit = null;
try
{
this.VersionHeight = context.CalculateVersionHeight(this.CommittedVersion, this.WorkingVersion);
(this.VersionHeight, nearestRelevantCommit) = context.CalculateVersionHeightAndNearestRelevantCommit(this.CommittedVersion, this.WorkingVersion);
}
catch (GitException ex) when (context.IsShallow && ex.ErrorCode == GitException.ErrorCodes.ObjectNotFound)
{
Expand All @@ -73,6 +74,7 @@ public VersionOracle(GitContext context, ICloudBuild? cloudBuild = null, int? ov

static Exception ThrowShallowClone(Exception inner) => throw new GitException("Shallow clone lacks the objects required to calculate version height. Use full clones or clones with a history at least as deep as the last version height resetting change.", inner) { iSShallowClone = true, ErrorCode = GitException.ErrorCodes.ObjectNotFound };


this.VersionOptions = this.CommittedVersion ?? this.WorkingVersion;
this.Version = this.VersionOptions?.Version?.Version ?? Version0;

Expand All @@ -84,6 +86,15 @@ public VersionOracle(GitContext context, ICloudBuild? cloudBuild = null, int? ov

this.CloudBuildNumberOptions = this.VersionOptions?.CloudBuild?.BuildNumberOrDefault ?? VersionOptions.CloudBuildNumberOptions.DefaultInstance;

if (!string.IsNullOrEmpty(nearestRelevantCommit) && context.GitCommitId != nearestRelevantCommit)
{
if (!context.TrySelectCommit(nearestRelevantCommit!))
{
// This would be very unexpected, given that the context itself provided the commit id we're selecting.
throw new GitException("Failed to select the nearest relevant commit.");
}
}

// get the commit id abbreviation only if the commit id is set
if (!string.IsNullOrEmpty(this.GitCommitId))
{
Expand Down

0 comments on commit 2e74568

Please sign in to comment.