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

Tag prefixes #49

Merged
merged 5 commits into from
Oct 29, 2018
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
3 changes: 2 additions & 1 deletion MinVer.Cli/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace MinVer.Cli
{
using System;
using System.Linq;

class Program
{
Expand All @@ -11,7 +12,7 @@ static void Main(string[] args)
throw new ArgumentException("Path not specified.");
}

Console.WriteLine(Versioner.GetVersion(args[0]));
Console.WriteLine(Versioner.GetVersion(args[0], args.ElementAtOrDefault(1)));
}
}
}
3 changes: 2 additions & 1 deletion MinVer/MinVer.targets
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
<GetPackageVersionDependsOn>$(GetPackageVersionDependsOn);MinVer</GetPackageVersionDependsOn>
<MinVerVersion Condition=" '$(MinVerVersion)' == '' ">$(MINVER_VERSION)</MinVerVersion>
<MinVerBuildMetadata Condition=" '$(MinVerBuildMetadata)' == '' ">$(MINVER_BUILD_METADATA)</MinVerBuildMetadata>
<MinVerTagPrefix Condition=" '$(MinVerTagPrefix)' == '' ">$(MINVER_TAG_PREFIX)</MinVerTagPrefix>
</PropertyGroup>

<Target Name="MinVer_GetVersion" Condition=" '$(MinVerVersion)' == '' ">
<Exec Command="dotnet &quot;$(MSBuildThisFileDirectory)MinVer.Cli.dll&quot; &quot;$(MSBuildProjectDirectory)&quot;" ConsoleToMSBuild="true">
<Exec Command="dotnet &quot;$(MSBuildThisFileDirectory)MinVer.Cli.dll&quot; &quot;$(MSBuildProjectDirectory)&quot; &quot;$(MinVerTagPrefix)&quot;" ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" ItemName="MinVerConsoleOutputItems" />
</Exec>
<ItemGroup>
Expand Down
5 changes: 3 additions & 2 deletions MinVer/Version.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public Version AddHeight(int height) =>
? new Version(this.major, this.minor, this.patch + 1, new[] { "alpha", "0", height.ToString(CultureInfo.InvariantCulture) })
: new Version(this.major, this.minor, this.patch, this.preReleaseIdentifiers.Concat(new[] { height.ToString(CultureInfo.InvariantCulture) }));

public static Version ParseOrDefault(string text)
public static Version ParseOrDefault(string text, string tagPrefix)
{
if (text == default)
{
Expand All @@ -111,7 +111,8 @@ public static Version ParseOrDefault(string text)

return
numbers.Length == 3 &&
int.TryParse(numbers[0], out var major) &&
numbers[0].StartsWith(tagPrefix ?? "") &&
int.TryParse(numbers[0].Substring(tagPrefix?.Length ?? 0), out var major) &&
int.TryParse(numbers[1], out var minor) &&
int.TryParse(numbers[2], out var patch)
? new Version(major, minor, patch, numbersAndPreRelease.Length == 2 ? numbersAndPreRelease[1].Split('.') : null)
Expand Down
29 changes: 15 additions & 14 deletions MinVer/Versioner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace MinVer

public static class Versioner
{
public static Version GetVersion(string path)
public static Version GetVersion(string path, string tagPrefix)
{
// Repository.ctor(string) throws RepositoryNotFoundException in this case
if (!Directory.Exists(path))
Expand All @@ -24,7 +24,7 @@ public static Version GetVersion(string path)
{
using (var repo = new Repository(testPath))
{
return GetVersion(repo.Commits.FirstOrDefault(), repo.Tags.ToList());
return GetVersion(repo, tagPrefix);
}
}
catch (RepositoryNotFoundException)
Expand All @@ -38,36 +38,44 @@ public static Version GetVersion(string path)
return new Version();
}

private static Version GetVersion(Commit commit, List<Tag> tags)
private static Version GetVersion(Repository repo, string tagPrefix)
{
var commit = repo.Commits.FirstOrDefault();

if (commit == default)
{
return new Version();
}

var tagsAndVersions = repo.Tags
.Select(tag => (tag, Version.ParseOrDefault(tag.FriendlyName, tagPrefix)))
.Where(tagAndVersion => tagAndVersion.Item2 != null)
.OrderByDescending(tagAndVersion => tagAndVersion.Item2)
.ToList();

var commitsChecked = new HashSet<string>();
var count = 0;
var height = 0;
var candidates = new List<Candidate>();
var commitsToCheck = new Stack<Tuple<Commit, int>>();
var commitsToCheck = new Stack<(Commit, int)>();

while (true)
{
if (commitsChecked.Add(commit.Sha))
{
++count;

var (tag, commitVersion) = GetVersionOrDefault(tags, commit);
var (tag, commitVersion) = tagsAndVersions.FirstOrDefault(tagAndVersion => tagAndVersion.tag.Target.Sha == commit.Sha);

if (commitVersion != default)
{
candidates.Add(new Candidate { Sha = commit.Sha, Height = height, Tag = tag, Version = commitVersion, });
candidates.Add(new Candidate { Sha = commit.Sha, Height = height, Tag = tag.FriendlyName, Version = commitVersion, });
}
else
{
foreach (var parent in commit.Parents.Reverse())
{
commitsToCheck.Push(Tuple.Create(parent, height + 1));
commitsToCheck.Push((parent, height + 1));
}

if (commitsToCheck.Count == 0 || commitsToCheck.Peek().Item2 <= height)
Expand Down Expand Up @@ -121,12 +129,5 @@ public string ToString(int heightWidth, int tagWidth) =>
}

private static void Log(string message) => Console.Error.WriteLine($"MinVer: {message}");

private static (string, Version) GetVersionOrDefault(List<Tag> tags, Commit commit) => tags
.Where(tag => tag.Target.Sha == commit.Sha)
.Select(tag => (tag.FriendlyName, Version.ParseOrDefault(tag.FriendlyName)))
.Where(tuple => tuple.Item2 != default)
.OrderByDescending(tuple => tuple.Item2)
.FirstOrDefault();
}
}
8 changes: 4 additions & 4 deletions MinVerTests/Infra/Git.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ public static async Task EnsureRepositoryWithACommit(string path)
{
await EnsureEmptyRepository(path);

await RunAsync("git", @"config user.email 'johndoe @tempuri.org'", path);
await RunAsync("git", @"config user.name 'John Doe'", path);
await RunAsync("git", @"config commit.gpgsign false", path);
await RunAsync("git", @"commit --allow-empty -m '.'", path);
await RunAsync("git", "config user.email 'johndoe @tempuri.org'", path);
await RunAsync("git", "config user.name 'John Doe'", path);
await RunAsync("git", "config commit.gpgsign false", path);
await RunAsync("git", "commit --allow-empty -m '.'", path);
}

public static async Task EnsureEmptyRepository(string path)
Expand Down
14 changes: 7 additions & 7 deletions MinVerTests/MSBuildIntegration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ public static void Subdirectory(string path, Version version)
$"Given a git repository with a commit in '{path = GetScenarioDirectory("msbuild-integration-subdirectory")}'"
.x(async () => await EnsureRepositoryWithACommit(path));

"And the git repository has a subdirectory"
.x(() => EnsureEmptyDirectory(path = Path.Combine(path, "subdirectory")));
"And the commit is tagged 2.0.0"
.x(async () => await RunAsync("git", "tag 2.0.0", path));

"And the current commit is tagged 1.0.0"
.x(async () => await RunAsync("git", @"tag 1.0.0", path));
"And the repository has a subdirectory"
.x(() => EnsureEmptyDirectory(path = Path.Combine(path, "subdirectory")));

"When the version is determined using the subdirectory"
.x(() => version = Versioner.GetVersion(path));
.x(() => version = Versioner.GetVersion(path, null));

"Then the version is 1.0.0"
.x(() => Assert.Equal("1.0.0", version.ToString()));
"Then the version is 2.0.0"
.x(() => Assert.Equal("2.0.0", version.ToString()));
}
}
}
32 changes: 32 additions & 0 deletions MinVerTests/TagPrefixes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace MinVerTests
{
using MinVer;
using Xbehave;
using Xunit;
using static MinVerTests.Infra.Git;
using static MinVerTests.Infra.FileSystem;
using static SimpleExec.Command;

public static class TagPrefixes
{
[Scenario]
[Example("1.2.3", null, "1.2.3")]
[Example("2.3.4", "", "2.3.4")]
[Example("v3.4.5", "v", "3.4.5")]
[Example("version5.6.7", "version", "5.6.7")]
public static void TagPrefix(string tag, string prefix, string expectedVersion, string path, Version actualVersion)
{
$"Given a git repository with a commit in '{path = GetScenarioDirectory($"tag-prefixes-{tag}")}'"
.x(async () => await EnsureRepositoryWithACommit(path));

$"And the commit is tagged '{tag}'"
.x(async () => await RunAsync("git", $"tag {tag}", path));

$"When the version is determined using the tag prefix '{prefix}'"
.x(() => actualVersion = Versioner.GetVersion(path, prefix));

$"Then the version is '{expectedVersion}'"
.x(() => Assert.Equal(expectedVersion, actualVersion.ToString()));
}
}
}
8 changes: 4 additions & 4 deletions MinVerTests/Versioning.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public static void RepoWithHistory(string name, string path)
{
Commands.Checkout(repo, commit);

var version = Versioner.GetVersion(path);
var version = Versioner.GetVersion(path, null);
var versionString = version.ToString();
var tagName = $"v/{versionString}";

Expand Down Expand Up @@ -128,7 +128,7 @@ public static void EmptyRepo(string path, MinVer.Version version)
.x(async () => await EnsureEmptyRepository(path));

"When the version is determined"
.x(() => version = Versioner.GetVersion(path));
.x(() => version = Versioner.GetVersion(path, null));

"Then the version is 0.0.0-alpha.0"
.x(() => Assert.Equal("0.0.0-alpha.0", version.ToString()));
Expand All @@ -141,7 +141,7 @@ public static void NoRepo(string path, MinVer.Version version)
.x(() => EnsureEmptyDirectory(path));

"When the version is determined"
.x(() => version = Versioner.GetVersion(path));
.x(() => version = Versioner.GetVersion(path, null));

"Then the version is 0.0.0-alpha.0"
.x(() => Assert.Equal("0.0.0-alpha.0", version.ToString()));
Expand All @@ -154,7 +154,7 @@ public static void NoDirectory(string path, Exception ex)
.x(() => path = Guid.NewGuid().ToString());

"When the version is determined"
.x(() => ex = Record.Exception(() => Versioner.GetVersion(path)));
.x(() => ex = Record.Exception(() => Versioner.GetVersion(path, null)));

"Then an exception is thrown"
.x(() => Assert.NotNull(ex));
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ Your project will be versioned according to the latest tag found in the commit h

## FAQ

### Can I prefix my tag names?

Yes! You can specify a prefix in an environment variable or MSBuild property named `MINVER_TAG_PREFIX` or `MinVerTagPrefix`.

For example, if you prefix your tag names with "v", e.g. `v1.2.3`:

```xml
<PropertyGroup>
<MinVerTagPrefix>v</MinVerTagPrefix>
</PropertyGroup>
```

### Does MinVer work with my chosen branching strategy?

Yes! MinVer doesn't care about branches. It's all about the tags!
Expand Down
5 changes: 4 additions & 1 deletion targets/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,17 @@ public static Task Main(string[] args)
var path = FileSystem.GetScenarioDirectory("package");
await Git.EnsureRepositoryWithACommit(path);

await RunAsync("git", "tag v1.2.3", path);
Environment.SetEnvironmentVariable("MINVER_TAG_PREFIX", "v", EnvironmentVariableTarget.Process);

await RunAsync("dotnet", "new classlib", path);
await RunAsync("dotnet", $"add package MinVer --version {version} --source {source} --package-directory packages", path);
await RunAsync("dotnet", $"restore --source {source} --packages packages", path);
await RunAsync("dotnet", "build --no-restore", path);
await RunAsync("dotnet", "pack --no-build", path);

var package = Directory.EnumerateFiles(path, "*.nupkg", new EnumerationOptions { RecurseSubdirectories = true }).First();
var expected = "0.0.0-alpha.0";
var expected = "1.2.3";
if (!package.Contains(expected))
{
throw new Exception($"'{package}' does not contain '{expected}'.");
Expand Down