Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
adamralph committed Aug 14, 2019
1 parent 21add10 commit f784054
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 57 deletions.
41 changes: 41 additions & 0 deletions MinVer.Lib/Command.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
namespace MinVer.Lib
{
using System.Diagnostics;
using System.Threading.Tasks;

internal static class Command
{
public static string Read(string name, string args, string workingDirectory)
{
using (var process = new Process())
{
process.StartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = name,
Arguments = args,
WorkingDirectory = workingDirectory,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
};

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

var readOutput = process.StandardOutput.ReadToEndAsync();

Task.WaitAll(runProcess, readOutput);

if (process.ExitCode != 0)
{
throw new NonZeroExitCodeException();
}

return readOutput.Result;
}
}
}
}
13 changes: 13 additions & 0 deletions MinVer.Lib/Commit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace MinVer.Lib
{
using System.Collections.Generic;

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

public string Sha { get; }

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;
}
}
}
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
15 changes: 15 additions & 0 deletions MinVer.Lib/NonZeroExitCodeException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace MinVer.Lib
{
using System;

#pragma warning disable CA1032 // Implement standard exception constructors
#pragma warning disable CA1064 // Exceptions should be public
internal class NonZeroExitCodeException : Exception
#pragma warning restore CA1064 // Exceptions should be public
#pragma warning restore CA1032 // Implement standard exception constructors
{
public NonZeroExitCodeException() : base()
{
}
}
}
84 changes: 84 additions & 0 deletions MinVer.Lib/Repository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
namespace MinVer.Lib
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using static Command;

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

public Commit Head { get; }

public IEnumerable<Tag> Tags { get; }

public static bool TryCreateRepo(string repoOrWorkDir, out Repository repository)
{
repository = default;

var commitCount = 0;

while (true)
{
try
{
commitCount = int.Parse(Read("git", "rev-list --all --count", repoOrWorkDir).Trim());
break;
}
catch (NonZeroExitCodeException)
{
repoOrWorkDir = Directory.GetParent(repoOrWorkDir)?.FullName;
if (repoOrWorkDir == default)
{
return false;
}
}
}

var commitLines = commitCount == 0 ? "" : Read("git", "log --pretty=format:\"%H %P\"", repoOrWorkDir);

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

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

var tags = GetTags(repoOrWorkDir);

repository = new Repository(commits.Values.FirstOrDefault(), tags);

return true;
}

private static List<Tag> GetTags(string repoOrWorkDir)
{
if (Read("git", "log --oneline --tags", repoOrWorkDir).Trim() == "")
{
return new List<Tag>();
}

var tagLines = Read("git", "show-ref --tags", repoOrWorkDir);

var tags = new List<Tag>();
foreach (var tokens in tagLines
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Select(line => line.Split(new[] { ' ' }, 2)))
{
tags.Add(new Tag(tokens[1].Substring(10), tokens[0]));
}

return tags;
}
}
}
28 changes: 0 additions & 28 deletions MinVer.Lib/RepositoryEx.cs

This file was deleted.

13 changes: 6 additions & 7 deletions MinVer.Lib/RepositoryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ namespace MinVer.Lib
{
using System.Collections.Generic;
using System.Linq;
using LibGit2Sharp;

internal static class RepositoryExtensions
{
public static Version GetVersion(this Repository repo, string tagPrefix, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log)
{
var commit = repo.Commits.FirstOrDefault();
var commit = repo.Head;

if (commit == default)
{
Expand All @@ -20,9 +19,9 @@ public static Version GetVersion(this Repository repo, string tagPrefix, Version
}

var tagsAndVersions = repo.Tags
.Select(tag => (tag, Version.ParseOrDefault(tag.FriendlyName, tagPrefix)))
.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 @@ -45,12 +44,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 != default;

Expand Down Expand Up @@ -90,7 +89,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 Down
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
{
public class Tag
{
public Tag(string name, string sha)
{
this.Name = name;
this.Sha = sha;
}

public string Name { get; }

public string Sha { get; }
}
}
11 changes: 2 additions & 9 deletions MinVer.Lib/Versioner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public static Version GetVersion(string repoOrWorkDir, string tagPrefix, MajorMi

private static Version GetVersion(string repoOrWorkDir, string tagPrefix, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log)
{
if (!RepositoryEx.TryCreateRepo(repoOrWorkDir, out var repo))
if (!Repository.TryCreateRepo(repoOrWorkDir, out var repo))
{
var version = new Version(defaultPreReleasePhase);

Expand All @@ -45,14 +45,7 @@ private static Version GetVersion(string repoOrWorkDir, string tagPrefix, Versio
return version;
}

try
{
return repo.GetVersion(tagPrefix, autoIncrement, defaultPreReleasePhase, log);
}
finally
{
repo.Dispose();
}
return repo.GetVersion(tagPrefix, autoIncrement, defaultPreReleasePhase, log);
}
}
}
14 changes: 2 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Also available as a [command line tool](#can-i-use-minver-to-version-software-wh
## Prerequisites

- [.NET Core SDK 2.1.300 or a later 2.x version.](https://www.microsoft.com/net/download)
- [Git](https://git-scm.com/)

## Quick start

Expand Down Expand Up @@ -102,7 +103,6 @@ _(With TL;DR answers inline.)_
- [Can I use MinVer to version software which is not built using a .NET SDK style project?](#can-i-use-minver-to-version-software-which-is-not-built-using-a-net-sdk-style-project) _(yes)_
- [What if the history diverges, and more than one tag is found?](#what-if-the-history-diverges-and-more-than-one-tag-is-found) _(nothing bad)_
- [What if the history diverges, and then converges again, before the latest tag (or root commit) is found?](#what-if-the-history-diverges-and-then-converges-again-before-the-latest-tag-or-root-commit-is-found) _(nothing bad)_
- [Why does MinVer fail with `LibGit2Sharp.NotFoundException`?](#why-does-minver-fail-with-libgit2sharpnotfoundexception) _(easy to fix)_

### Why not use GitVersion, Nerdbank.GitVersioning, or some other tool?

Expand Down Expand Up @@ -256,7 +256,7 @@ Yes! You can do this by using a specific tag prefix for each project. For exampl

Yes! [`MinVerVerbosity`](#options) can be set to `quiet`, `minimal` (default), `normal`, `detailed`, or `diagnostic`. These verbosity levels match those in MSBuild and therefore `dotnet build`, `dotnet pack`, etc. The default is `minimal`, which matches the default in MSBuild. At the `quiet` and `minimal` levels, you will see only warnings and errors. At the `normal` level you will see which commit is being used to calculate the version, and the calculated version. At the `detailed` level you will see how many commits were examined, which version tags were found but ignored, which version was calculated, etc. At the `diagnostic` level you will see how MinVer walks the commit history, in excruciating detail.

In a future version of MinVer, the verbosity level may be inherited from MSBuild, in which case `MinVerVerbosity` will be deprecated. Currently this is not possible due to technical restrictions related to [libgit2](https:/libgit2/libgit2).
In a future version of MinVer, the verbosity level may be inherited from MSBuild, in which case `MinVerVerbosity` will be deprecated.

### Can I use MinVer to version software which is not built using a .NET SDK style project?

Expand All @@ -272,16 +272,6 @@ The tag with the higher version is used.

MinVer will use the height on the first path followed where the history diverges. The paths are followed in the same order that the parents of the commit are stored in git. The first parent is the commit on the branch that was the current branch when the merge was performed. The remaining parents are stored in the order that their branches were specified in the merge command.

### Why does MinVer fail with `LibGit2Sharp.NotFoundException`?

You may see an exception of this form:

> Unhandled Exception: LibGit2Sharp.NotFoundException: object not found - no match for id (...)

This is because you are using a [shallow clone](https://www.git-scm.com/docs/git-clone#git-clone---depthltdepthgt). MinVer uses [libgit2](https:/libgit2/libgit2) to interrogate the repo and [libgit2 does not support shallow clones](https:/libgit2/libgit2/issues/3058). To resolve this problem, use a regular (deep) clone.

**Important:** By default, [Travis CI](https://travis-ci.org/) uses shallow clones with a depth of 50 commits. To build on Travis CI, [remove the `--depth` flag](https://docs.travis-ci.com/user/customizing-the-build#git-clone-depth).

---

<sub>[Tag](https://thenounproject.com/term/tag/938952) by [Ananth](https://thenounproject.com/ananthshas/) from [the Noun Project](https://thenounproject.com/).</sub>

0 comments on commit f784054

Please sign in to comment.