Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

switch from LibGit2Sharp to Git #256

Merged
merged 1 commit into from
Sep 14, 2019
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
runs-on: [macOS-10.14, ubuntu-18.04, windows-2019]
runs-on: [macOS-10.14, ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019]
name: ${{ matrix.runs-on }}
runs-on: ${{ matrix.runs-on }}
steps:
Expand Down
15 changes: 15 additions & 0 deletions MinVer.Lib/Commit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace MinVer.Lib
{
using System.Collections.Generic;

internal class Commit
{
public Commit(string sha) => this.Sha = sha;

public string Sha { get; }

public string ShortSha => this.Sha.Substring(0, 7);

public List<Commit> Parents { get; } = new List<Commit>();
}
}
18 changes: 18 additions & 0 deletions MinVer.Lib/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace MinVer.Lib
{
using System;
using System.Collections.Generic;

internal static class DictionaryExtensions
{
public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, Func<TValue> valueFactory)
{
if (!dictionary.TryGetValue(key, out var value))
{
dictionary.Add(key, value = valueFactory());
}

return value;
}
}
}
42 changes: 42 additions & 0 deletions MinVer.Lib/Git.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace MinVer.Lib
{
using System;
using System.Collections.Generic;
using System.Linq;

internal static class Git
{
public static bool IsWorkingDirectory(string directory, ILogger log) => GitCommand.TryRun("status --short", directory, log, out _);

public static Commit GetHeadOrDefault(string directory, ILogger log)
{
if (!GitCommand.TryRun("log --pretty=format:\"%H %P\"", directory, log, out var output))
{
return null;
}

var commits = new Dictionary<string, Commit>();

foreach (var shas in output
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Select(line => line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)))
{
commits.GetOrAdd(shas[0], () => new Commit(shas[0]))
.Parents.AddRange(shas.Skip(1).Select(parentSha => commits.GetOrAdd(parentSha, () => new Commit(parentSha))));
}

return commits.Values.FirstOrDefault();
}

public static IEnumerable<Tag> GetTagsOrEmpty(string directory, ILogger log) =>
GitCommand.TryRun("show-ref --tags --dereference", directory, log, out var output)
? output
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Select(line => line.Split(new[] { ' ' }, 2))
.Select(tokens => new Tag(tokens[1].Substring(10).RemoveFromEnd("^{}"), tokens[0]))
: Enumerable.Empty<Tag>();

private static string RemoveFromEnd(this string text, string value) =>
text.EndsWith(value) ? text.Substring(0, text.Length - value.Length) : text;
}
}
57 changes: 57 additions & 0 deletions MinVer.Lib/GitCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
namespace MinVer.Lib
{
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading.Tasks;

internal static class GitCommand
{
public static bool TryRun(string args, string workingDirectory, ILogger log, out string output)
{
using (var process = new Process())
{
process.StartInfo = new ProcessStartInfo
{
FileName = "git",
Arguments = args,
WorkingDirectory = workingDirectory,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
};

var tcs = new TaskCompletionSource<object>();
process.Exited += (s, e) => tcs.SetResult(default);
process.EnableRaisingEvents = true;

log.Trace($"Running Git: {process.StartInfo.FileName} {process.StartInfo.Arguments}");

try
{
process.Start();
}
catch (Win32Exception ex)
{
throw new Exception("Failed to run Git. Git may not be installed on the system.", ex);
}

var runProcess = tcs.Task;
var readOutput = process.StandardOutput.ReadToEndAsync();
var readError = process.StandardError.ReadToEndAsync();

Task.WaitAll(runProcess, readOutput, readError);

var exitCode = process.ExitCode;
output = readOutput.Result;
var error = readError.Result;

log.Trace($"Git exit code: {exitCode}");
log.Trace($"Git stdout:{Environment.NewLine}{output}");
log.Trace($"Git stderr:{Environment.NewLine}{error}");

return exitCode == 0;
}
}
}
}
1 change: 0 additions & 1 deletion MinVer.Lib/MinVer.Lib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="LibGit2Sharp" Version="0.26.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeQuality.Analyzers" Version="2.9.4" PrivateAssets="All" />
</ItemGroup>
Expand Down
65 changes: 44 additions & 21 deletions MinVer.Lib/RepositoryExtensions.cs → MinVer.Lib/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,38 @@ namespace MinVer.Lib
{
using System.Collections.Generic;
using System.Linq;
using LibGit2Sharp;

internal static class RepositoryExtensions
internal class Repository
{
public static Version GetVersion(this Repository repo, string tagPrefix, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log)
private readonly Commit head;
private readonly IEnumerable<Tag> tags;

private Repository(Commit head, IEnumerable<Tag> tags)
{
this.head = head;
this.tags = tags;
}

public static bool TryCreateRepo(string workDir, out Repository repository, ILogger log)
{
repository = null;

if (!Git.IsWorkingDirectory(workDir, log))
{
return false;
}

var head = Git.GetHeadOrDefault(workDir, log);
var tags = head != null ? Git.GetTagsOrEmpty(workDir, log) : Enumerable.Empty<Tag>();

repository = new Repository(head, tags);

return true;
}

public Version GetVersion(string tagPrefix, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log)
{
var commit = repo.Commits.FirstOrDefault();
var commit = this.head;

if (commit == null)
{
Expand All @@ -19,10 +44,10 @@ public static Version GetVersion(this Repository repo, string tagPrefix, Version
return version;
}

var tagsAndVersions = repo.Tags
.Select(tag => (tag, Version.ParseOrDefault(tag.FriendlyName, tagPrefix)))
var tagsAndVersions = this.tags
.Select(tag => (tag, Version.ParseOrDefault(tag.Name, tagPrefix)))
.OrderBy(tagAndVersion => tagAndVersion.Item2)
.ThenBy(tagsAndVersion => tagsAndVersion.tag.FriendlyName)
.ThenBy(tagsAndVersion => tagsAndVersion.tag.Name)
.ToList();

var commitsChecked = new HashSet<string>();
Expand All @@ -34,7 +59,7 @@ public static Version GetVersion(this Repository repo, string tagPrefix, Version

if (log.IsTraceEnabled)
{
log.Trace($"Starting at commit {commit.ShortSha()} (height {height})...");
log.Trace($"Starting at commit {commit.ShortSha} (height {height})...");
}

while (true)
Expand All @@ -45,12 +70,12 @@ public static Version GetVersion(this Repository repo, string tagPrefix, Version
{
++count;

var commitTagsAndVersions = tagsAndVersions.Where(tagAndVersion => tagAndVersion.tag.Target.Sha == commit.Sha).ToList();
var commitTagsAndVersions = tagsAndVersions.Where(tagAndVersion => tagAndVersion.tag.Sha == commit.Sha).ToList();
var foundVersion = false;

foreach (var (tag, commitVersion) in commitTagsAndVersions)
{
var candidate = new Candidate { Commit = commit, Height = height, Tag = tag.FriendlyName, Version = commitVersion, };
var candidate = new Candidate { Commit = commit, Height = height, Tag = tag.Name, Version = commitVersion, };

foundVersion = foundVersion || candidate.Version != null;

Expand All @@ -77,11 +102,11 @@ public static Version GetVersion(this Repository repo, string tagPrefix, Version
firstParent = parent;
break;
case 1:
log.Trace($"History diverges from {commit.ShortSha()} (height {height}) to:");
log.Trace($"- {firstParent.ShortSha()} (height {height + 1})");
log.Trace($"History diverges from {commit.ShortSha} (height {height}) to:");
log.Trace($"- {firstParent.ShortSha} (height {height + 1})");
goto default;
default:
log.Trace($"- {parent.ShortSha()} (height {height + 1})");
log.Trace($"- {parent.ShortSha} (height {height + 1})");
break;
}

Expand All @@ -90,7 +115,7 @@ public static Version GetVersion(this Repository repo, string tagPrefix, Version
}
}

foreach (var parent in commit.Parents.Reverse())
foreach (var parent in ((IEnumerable<Commit>)commit.Parents).Reverse())
{
commitsToCheck.Push((parent, height + 1, commit));
}
Expand All @@ -112,7 +137,7 @@ public static Version GetVersion(this Repository repo, string tagPrefix, Version
{
if (log.IsTraceEnabled)
{
log.Trace($"History converges from {previousCommit.ShortSha()} (height {height - 1}) back to previously seen commit {commit.ShortSha()} (height {height}). Abandoning path.");
log.Trace($"History converges from {previousCommit.ShortSha} (height {height - 1}) back to previously seen commit {commit.ShortSha} (height {height}). Abandoning path.");
}
}

Expand All @@ -134,17 +159,17 @@ public static Version GetVersion(this Repository repo, string tagPrefix, Version
{
if (parentCount > 1)
{
log.Trace($"Following path from {child.ShortSha()} (height {height - 1}) through first parent {commit.ShortSha()} (height {height})...");
log.Trace($"Following path from {child.ShortSha} (height {height - 1}) through first parent {commit.ShortSha} (height {height})...");
}
else if (height <= oldHeight)
{
if (commitsToCheck.Any() && commitsToCheck.Peek().Item2 == height)
{
log.Trace($"Backtracking to {child.ShortSha()} (height {height - 1}) and following path through next parent {commit.ShortSha()} (height {height})...");
log.Trace($"Backtracking to {child.ShortSha} (height {height - 1}) and following path through next parent {commit.ShortSha} (height {height})...");
}
else
{
log.Trace($"Backtracking to {child.ShortSha()} (height {height - 1}) and following path through last parent {commit.ShortSha()} (height {height})...");
log.Trace($"Backtracking to {child.ShortSha} (height {height - 1}) and following path through last parent {commit.ShortSha} (height {height})...");
}
}
}
Expand Down Expand Up @@ -178,8 +203,6 @@ public static Version GetVersion(this Repository repo, string tagPrefix, Version
return selectedCandidate.Version.WithHeight(selectedCandidate.Height, autoIncrement, defaultPreReleasePhase);
}

private static string ShortSha(this Commit commit) => commit.Sha.Substring(0, 7);

private class Candidate
{
public Commit Commit { get; set; }
Expand All @@ -193,7 +216,7 @@ private class Candidate
public override string ToString() => this.ToString(0, 0, 0);

public string ToString(int tagWidth, int versionWidth, int heightWidth) =>
$"{{ {nameof(this.Commit)}: {this.Commit.ShortSha()}, {nameof(this.Tag)}: {$"{(this.Tag == null ? "null" : $"'{this.Tag}'")},".PadRight(tagWidth + 3)} {nameof(this.Version)}: {$"{this.Version?.ToString() ?? "null"},".PadRight(versionWidth + 1)} {nameof(this.Height)}: {this.Height.ToString().PadLeft(heightWidth)} }}";
$"{{ {nameof(this.Commit)}: {this.Commit.ShortSha}, {nameof(this.Tag)}: {$"{(this.Tag == null ? "null" : $"'{this.Tag}'")},".PadRight(tagWidth + 3)} {nameof(this.Version)}: {$"{this.Version?.ToString() ?? "null"},".PadRight(versionWidth + 1)} {nameof(this.Height)}: {this.Height.ToString().PadLeft(heightWidth)} }}";
}
}
}
28 changes: 0 additions & 28 deletions MinVer.Lib/RepositoryEx.cs

This file was deleted.

15 changes: 15 additions & 0 deletions MinVer.Lib/Tag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace MinVer.Lib
{
internal class Tag
{
public Tag(string name, string sha)
{
this.Name = name;
this.Sha = sha;
}

public string Name { get; }

public string Sha { get; }
}
}
18 changes: 7 additions & 11 deletions MinVer.Lib/Versioner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ namespace MinVer.Lib
{
public static class Versioner
{
public static Version GetVersion(string repoOrWorkDir, string tagPrefix, MajorMinor minMajorMinor, string buildMeta, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log)
public static Version GetVersion(string workDir, string tagPrefix, MajorMinor minMajorMinor, string buildMeta, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log)
{
log = log ?? new NullLogger();

defaultPreReleasePhase = string.IsNullOrEmpty(defaultPreReleasePhase)
? "alpha"
: defaultPreReleasePhase;

var version = GetVersion(repoOrWorkDir, tagPrefix, autoIncrement, defaultPreReleasePhase, log).AddBuildMetadata(buildMeta);
var version = GetVersion(workDir, tagPrefix, autoIncrement, defaultPreReleasePhase, log).AddBuildMetadata(buildMeta);

var calculatedVersion = version.Satisfying(minMajorMinor, defaultPreReleasePhase);

Expand All @@ -31,23 +31,19 @@ public static Version GetVersion(string repoOrWorkDir, string tagPrefix, MajorMi
return calculatedVersion;
}

private static Version GetVersion(string repoOrWorkDir, string tagPrefix, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log)
private static Version GetVersion(string workDir, string tagPrefix, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log)
{
#pragma warning disable IDE0068 // Use recommended dispose pattern
if (!RepositoryEx.TryCreateRepo(repoOrWorkDir, out var repo))
#pragma warning restore IDE0068 // Use recommended dispose pattern
if (!Repository.TryCreateRepo(workDir, out var repo, log))

{
var version = new Version(defaultPreReleasePhase);

log.Warn(1001, $"'{repoOrWorkDir}' is not a valid repository or working directory. Using default version {version}.");
log.Warn(1001, $"'{workDir}' is not a valid working directory. Using default version {version}.");

return version;
}

using (repo)
{
return repo.GetVersion(tagPrefix, autoIncrement, defaultPreReleasePhase, log);
}
return repo.GetVersion(tagPrefix, autoIncrement, defaultPreReleasePhase, log);
}
}
}
Loading