Skip to content

Commit

Permalink
Merge branch 'devel'
Browse files Browse the repository at this point in the history
  • Loading branch information
kekyo committed Jul 2, 2023
2 parents f6ce263 + c133b7f commit e19a9a7
Show file tree
Hide file tree
Showing 25 changed files with 318 additions and 114 deletions.
39 changes: 39 additions & 0 deletions CenterCLR.RelaxVersioner.Core.Tests/AnalyzerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// RelaxVersioner - Git tag/branch based, full-automatic version information inserter.
// Copyright (c) Kouji Matsui (@kozy_kekyo, @kekyo@mastodon.cloud)
//
// Licensed under Apache-v2: https://opensource.org/licenses/Apache-2.0
//
////////////////////////////////////////////////////////////////////////////////////////

using GitReader;
using GitReader.Structures;
using NUnit.Framework;
using System.IO;
using System.Threading.Tasks;

namespace RelaxVersioner;

public sealed class AnalyzerTests
{
[TestCase("NothingAnyTags1", "0.0.4")]
[TestCase("NothingAnyTags2", "0.0.5")]
[TestCase("NothingAnyTags3", "0.0.5")]
[TestCase("NothingAnyTags4", "0.0.6")]
[TestCase("TagInTop", "0.15.2")]
[TestCase("TagInPrimary", "0.10.1")]
[TestCase("TagInSecondary", "0.20.1")]
[TestCase("TagInBoth", "0.10.5")]
[TestCase("MultiRoot1", "0.10.6")]
[TestCase("MultiRoot2", "0.10.22")]
public async Task LookupVersionLabel(string repositoryName, string expectedString)
{
using var repository = await Repository.Factory.OpenStructureAsync(
Path.Combine(TestsSetUp.BasePath, repositoryName));

var actual = await Analyzer.LookupVersionLabelAsync(repository.Head!, default);

Assert.AreEqual(expectedString, actual.ToString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Nullable>enable</Nullable>
<TargetFrameworks>net48;net5.0;net6.0;net7.0</TargetFrameworks>
<NoWarn>$(NoWarn);NU5104</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
<PackageReference Include="Verify.NUnit" Version="19.13.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CenterCLR.RelaxVersioner.Core\CenterCLR.RelaxVersioner.Core.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="artifacts\" />
</ItemGroup>

<ItemGroup>
<None Update="artifacts\*.zip">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
46 changes: 46 additions & 0 deletions CenterCLR.RelaxVersioner.Core.Tests/TestsSetUp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// RelaxVersioner - Git tag/branch based, full-automatic version information inserter.
// Copyright (c) Kouji Matsui (@kozy_kekyo, @kekyo@mastodon.cloud)
//
// Licensed under Apache-v2: https://opensource.org/licenses/Apache-2.0
//
////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.IO;
using System.IO.Compression;
using VerifyTests;

namespace RelaxVersioner;

public sealed class TestsSetUp
{
public static readonly string BasePath =
Path.Combine("tests", $"{DateTime.Now:yyyyMMdd_HHmmss}");

static TestsSetUp()
{
VerifierSettings.DontScrubDateTimes();

if (!Directory.Exists(BasePath))
{
foreach (var path in Directory.EnumerateFiles(
"artifacts", "*.zip", SearchOption.AllDirectories))
{
var fileName = Path.GetFileNameWithoutExtension(path);
var targetBasePath = Path.Combine(BasePath, fileName);

try
{
Directory.CreateDirectory(targetBasePath);
}
catch
{
}

ZipFile.ExtractToDirectory(path, targetBasePath);
}
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
172 changes: 108 additions & 64 deletions CenterCLR.RelaxVersioner.Core/Analyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#nullable enable

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -20,95 +19,140 @@ namespace RelaxVersioner;

internal static class Analyzer
{
private readonly struct TargetCommit
private readonly struct ScheduledCommit
{
public readonly int StartDepth;
public readonly Commit Commit;
public readonly Commit[] Parents;

public TargetCommit(int startDepth, Commit commit)
public ScheduledCommit(
Commit commit, Commit[] parents)
{
this.StartDepth = startDepth;
this.Commit = commit;
this.Parents = parents;
}

public override string ToString() =>
$"StartDepth={this.StartDepth}, {this.Commit}";
public void Deconstruct(
out Commit commit, out Commit[] parents)
{
commit = this.Commit;
parents = this.Parents;
}
}

public static async Task<Version> LookupVersionLabelAsync(
Branch targetBranch, CancellationToken ct)
private static Version IncrementLastVersionComponent(
Version version)
{
var topCommit = await targetBranch.GetHeadCommitAsync(ct);

var reached = new HashSet<Commit>();
var scheduled = new Stack<TargetCommit>();
scheduled.Push(new TargetCommit(0, topCommit));

var mainDepth = 0;
if (version.Revision.HasValue)
{
return new(
version.Major,
version.Minor!.Value,
version.Build!.Value,
version.Revision.Value + 1);
}
else if (version.Build.HasValue)
{
return new(
version.Major,
version.Minor!.Value,
version.Build.Value + 1);
}
else if (version.Minor.HasValue)
{
return new(
version.Major,
version.Minor.Value + 1);
}
else
{
return new(
version.Major + 1);
}
}

while (scheduled.Count >= 1)
private static async Task<Version> LookupVersionLabelAsync(
Commit commit, Dictionary<Commit, Version> reached, CancellationToken ct)
{
var scheduledStack = new Stack<ScheduledCommit>();
var version = Version.Default;

// Trace back to the parent commit repeatedly with the following conditions:
// * If the commit has already been reached, get its version.
// * If there is a recognizable version string in the tag, get its version.
// * If the parent commit does not exist, get the default version.
// * If other than the above, push the commit on the stack for later processing in reverse order.
while (true)
{
// Extract an analysis commit.
var entry = scheduled.Pop();

var currentCommit = entry.Commit;
var currentDepth = entry.StartDepth;
if (reached.TryGetValue(commit, out var v1))
{
version = v1;
break;
}

while (true)
var found = false;
foreach (var tag in commit.Tags)
{
// Rejoined parent branch.
if (!reached.Add(currentCommit))
if (Version.TryParse(tag.Name, out var v2))
{
version = v2;
reached.Add(commit, version);
found = true;
break;
}
}
if (found)
{
break;
}

// If found be applied tags at this commit:
if (currentCommit.Tags.Count >= 1)
{
var filteredTags = currentCommit.Tags.
Select(tag => Version.TryParse(tag.Name, out var version) ? (Version?)version : null).
Where(version => version.HasValue).
Select(version => Utilities.IncrementLastVersionComponent(version!.Value, currentDepth)).
ToArray();

// Found first valid tag.
if (filteredTags.Length >= 1)
{
return filteredTags[0];
}
}

// Found parents.
if (await currentCommit.GetParentCommitsAsync(ct) is { Length: >= 1 } parents)
{
// Dive parent commit.
currentDepth++;
var parents = await commit.GetParentCommitsAsync(ct);
if (parents.Length == 0)
{
reached.Add(commit, version);
break;
}

// Next commit is a primary parent.
currentCommit = parents[0];
scheduledStack.Push(new(commit, parents));
commit = parents[0];
}

// Enqueue analysis scheduling if it has multiple parents.
foreach (var parentCommit in parents.Skip(1))
{
scheduled.Push(new TargetCommit(currentDepth, parentCommit));
}
}
// Bottom of branch.
else
// As long as there are commits stacked on the stack,
// retrieve a commit from the stack, and if there is more than one parent commit for that commit:
// * Recursively get versions from parent commits other than the primary one.
// * Compare the versions obtained and store the largest version.
// * Increment the version and make it the version of the current commit.
while (scheduledStack.Count >= 1)
{
var (c, pcs) = scheduledStack.Pop();
if (pcs.Length >= 2)
{
for (var index = 1; index < pcs.Length; index++)
{
// Save depth if it's on boarding the main branch.
if (mainDepth == 0)
var v = await LookupVersionLabelAsync(pcs[index], reached, ct);
if (v.CompareTo(version) > 0)
{
mainDepth = currentDepth;
version = v;
}

// Goes to next scheduled commit.
break;
}
}

version = IncrementLastVersionComponent(version);
reached.Add(c, version);
}

// Finally got the main branch depth.
return Utilities.IncrementLastVersionComponent(Version.Default, mainDepth);
return version;
}

public static Task<Version> LookupVersionLabelAsync(
Commit commit, CancellationToken ct) =>
LookupVersionLabelAsync(commit, new(), ct);

public static async Task<Version> LookupVersionLabelAsync(
Branch branch, CancellationToken ct)
{
// Get the head commit for the branch.
var headCommit = await branch.GetHeadCommitAsync(ct);

return await LookupVersionLabelAsync(headCommit, new(), ct);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GitReader" Version="0.13.0" />
<PackageReference Include="GitReader" Version="1.1.0" />
<PackageReference Include="NamingFormatter" Version="2.2.0" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="All" />
<PackageReference Include="RelaxVersioner" Version="2.15.0" PrivateAssets="all" />
<PackageReference Include="RelaxVersioner" Version="2.16.0" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
7 changes: 2 additions & 5 deletions CenterCLR.RelaxVersioner.Core/Processor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;

using GitReader;
using GitReader.Structures;

using RelaxVersioner.Writers;
using System.Threading;

namespace RelaxVersioner;

Expand All @@ -40,9 +40,6 @@ public sealed class ProcessorContext

public sealed class Processor
{
private static readonly Branch[] emptyBranches = Array.Empty<Branch>();
private static readonly Tag[] emptyTags = Array.Empty<Tag>();

private readonly Logger logger;
private readonly Dictionary<string, WriterBase> writers;

Expand Down
12 changes: 12 additions & 0 deletions CenterCLR.RelaxVersioner.Core/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// RelaxVersioner - Git tag/branch based, full-automatic version information inserter.
// Copyright (c) Kouji Matsui (@kozy_kekyo, @kekyo@mastodon.cloud)
//
// Licensed under Apache-v2: https://opensource.org/licenses/Apache-2.0
//
////////////////////////////////////////////////////////////////////////////////////////

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("CenterCLR.RelaxVersioner.Core.Tests")]
Loading

0 comments on commit e19a9a7

Please sign in to comment.