Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
cacd5ab
Add `CreativeCoders.GitTool` project and implement versioning utilities
darthsharp Feb 14, 2026
60a4ac3
Add unit tests for `VersionBuilder` and integrate `CreativeCoders.Git…
darthsharp Feb 14, 2026
bed66d1
- Migrate to `CreativeCoders` 6.6.0 across all projects and refactor …
darthsharp Feb 14, 2026
9ec380f
Refactor versioning logic and add `ListVersionsCommand`
darthsharp Feb 14, 2026
d624b4c
Refactor `VersionComparer` to use `switch` expression for null checks…
darthsharp Feb 14, 2026
084d082
Add confirmation prompt for auto-incremented version in `CreateReleas…
darthsharp Feb 14, 2026
dbab44b
Enhance `CreateReleaseCommand` console output with markup and success…
darthsharp Feb 14, 2026
b466bb2
Refine `CreateReleaseCommand` console messages for improved clarity a…
darthsharp Feb 14, 2026
99dda6e
Add support for resetting lower version parts during version auto-inc…
darthsharp Feb 14, 2026
a2614dd
Refactor `CreateReleaseCommand` to use `ConfirmationPrompt` for user …
darthsharp Feb 14, 2026
73224f2
Add comprehensive unit tests for versioning utilities and enhance `Ve…
darthsharp Feb 14, 2026
7fbdfee
Rename auto-increment confirmation option for improved clarity in `Cr…
darthsharp Feb 14, 2026
46069cb
Fix test name in `VersionBuilderTests` to reflect correct behavior of…
darthsharp Feb 14, 2026
6388bfc
Refactor `CreateReleaseCommand` to simplify code by removing unused `…
darthsharp Feb 15, 2026
f368913
Rename `RemoveTrailingVersionPrefix` to `RemoveLeadingVersionPrefix` …
darthsharp Feb 15, 2026
b4f7b19
Ensure mutual exclusivity between `Version` and `VersionIncrement` in…
darthsharp Feb 15, 2026
ca794b0
Update `VersionFormatException` message for clearer description of va…
darthsharp Feb 15, 2026
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
7 changes: 7 additions & 0 deletions GitTools.sln
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreativeCoders.GitTool.Cli.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreativeCoders.GitTool.Cli.Commands", "source\GitTool\CreativeCoders.GitTool.Cli.Commands\CreativeCoders.GitTool.Cli.Commands.csproj", "{80C7112B-7D72-4585-BDFA-101289319B2C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreativeCoders.GitTool.Tests", "tests\CreativeCoders.GitTool.Tests\CreativeCoders.GitTool.Tests.csproj", "{EB39081F-6139-40B2-BEE7-E024DE6118CD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -136,6 +138,10 @@ Global
{80C7112B-7D72-4585-BDFA-101289319B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{80C7112B-7D72-4585-BDFA-101289319B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80C7112B-7D72-4585-BDFA-101289319B2C}.Release|Any CPU.Build.0 = Release|Any CPU
{EB39081F-6139-40B2-BEE7-E024DE6118CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB39081F-6139-40B2-BEE7-E024DE6118CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB39081F-6139-40B2-BEE7-E024DE6118CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB39081F-6139-40B2-BEE7-E024DE6118CD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -159,6 +165,7 @@ Global
{D65676E3-6820-464B-8493-597E3E1DCD98} = {90C87656-57A8-4AE9-8619-DA08AA137D6A}
{46156AAB-B9F6-4C99-AD0A-9F370DB87679} = {D65676E3-6820-464B-8493-597E3E1DCD98}
{80C7112B-7D72-4585-BDFA-101289319B2C} = {D65676E3-6820-464B-8493-597E3E1DCD98}
{EB39081F-6139-40B2-BEE7-E024DE6118CD} = {B7558045-D005-49D4-9205-55A32B6C99DE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D38E5978-8FB3-474B-BDCB-18853E21A429}
Expand Down
2 changes: 1 addition & 1 deletion build/Build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CreativeCoders.CakeBuild" Version="6.5.0"/>
<PackageReference Include="CreativeCoders.CakeBuild" Version="6.6.0"/>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CreativeCoders.Core" Version="6.5.0"/>
<PackageReference Include="CreativeCoders.Core" Version="6.6.0"/>
<PackageReference Include="JetBrains.Annotations" Version="2025.2.4"/>

</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Devlooped.CredentialManager" Version="2.6.1.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.2" />
<PackageReference Include="Devlooped.CredentialManager" Version="2.6.1.1"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.3"/>
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions source/Git/CreativeCoders.Git/CreativeCoders.Git.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CreativeCoders.Core" Version="6.5.0"/>
<PackageReference Include="CreativeCoders.Core" Version="6.6.0"/>
<PackageReference Include="LibGit2Sharp" Version="0.31.0"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.2"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.3"/>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.2"/>
<PackageReference Include="CreativeCoders.Core" Version="6.5.0"/>
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.2"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.3"/>
<PackageReference Include="CreativeCoders.Core" Version="6.6.0"/>
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.3"/>
<PackageReference Include="Spectre.Console" Version="0.54.0"/>
</ItemGroup>

Expand Down
4 changes: 4 additions & 0 deletions source/GitTool/CreativeCoders.GitTool.Base/ReturnCodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ public static class ReturnCodes
public const int FeatureBranchAlreadyExistsLocal = -7;

public const int FeatureBranchAlreadyExistsRemote = -8;

public const int LocalTagNotFound = -9;

public const int ReleaseCreationAborted = -10;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Collections.Generic;
using CreativeCoders.Git.Abstractions;

namespace CreativeCoders.GitTool.Base.Versioning;

public static class GitRepositoryExtensions
{
public static IEnumerable<VersionTag> GetVersionTags(this IGitRepository gitRepository)
{
foreach (var tag in gitRepository.Tags)
{
if (VersionUtils.IsValidVersion(tag.Name.Friendly, out var version))
{
yield return new VersionTag(version, tag);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace CreativeCoders.GitTool.Base.Versioning;

public class VersionBuilder
{
public const int MajorPartIndex = 0;
public const int MinorPartIndex = 1;
public const int PatchPartIndex = 2;

private readonly VersionFormatKind _formatKind;

private readonly List<string> _versionParts = [];

public VersionBuilder(string version, VersionFormatKind formatKind = VersionFormatKind.Strict)
{
_formatKind = formatKind;
_versionParts.AddRange(SplitVersionParts(version));
}

private List<string> SplitVersionParts(string version)
{
var versionParts = version.Split('.').ToList();

if (versionParts.Count > 3)
{
throw new VersionFormatException(version);
}

for (var i = 0; i < versionParts.Count; i++)
{
var versionPart = versionParts[i];

if (versionPart.Trim() != versionPart && _formatKind == VersionFormatKind.Strict)
{
throw new VersionFormatException(version,
$"The version part '{versionPart}' contains leading or trailing whitespace.");
}

if (!int.TryParse(versionPart.Trim(), out var versionPartInt))
{
throw new VersionFormatException(version, $"The version part '{versionPart}' is not a valid integer.");
}

versionParts[i] = versionPartInt.ToString();
}

while (versionParts.Count < 3)
{
versionParts.Add("0");
}

return versionParts;
}

private static string BuildVersion(IEnumerable<string> versionParts)
{
return string.Join(".", versionParts);
}

public VersionBuilder IncrementPatch(int incrementBy = 1)
{
return IncrementPart(PatchPartIndex, incrementBy);
}

public VersionBuilder IncrementMinor(int incrementBy = 1, bool resetPatch = true)
{
IncrementPart(MinorPartIndex, incrementBy);

if (resetPatch)
{
Patch = 0;
}

return this;
}

public VersionBuilder IncrementMajor(int incrementBy = 1, bool resetMinorAndPatch = true)
{
IncrementPart(MajorPartIndex, incrementBy);

if (resetMinorAndPatch)
{
Minor = 0;
Patch = 0;
}

return this;
}

private VersionBuilder IncrementPart(int partIndex, int incrementBy)
{
if (!int.TryParse(_versionParts[partIndex], out var versionPartNumber))
{
throw new InvalidOperationException();
}

_versionParts[partIndex] = (versionPartNumber + incrementBy).ToString();

return this;
}

public string Build()
{
return BuildVersion(_versionParts);
}

public int GetVersionPart(int partIndex)
{
return partIndex is < 0 or > 2
? throw new ArgumentOutOfRangeException(nameof(partIndex))
: int.Parse(_versionParts[partIndex]);
}

public int Major
{
get => GetVersionPart(MajorPartIndex);
set => _versionParts[MajorPartIndex] = value.ToString();
}

public int Minor
{
get => GetVersionPart(MinorPartIndex);
set => _versionParts[MinorPartIndex] = value.ToString();
}

public int Patch
{
get => GetVersionPart(PatchPartIndex);
set => _versionParts[PatchPartIndex] = value.ToString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Collections.Generic;

namespace CreativeCoders.GitTool.Base.Versioning;

public class VersionComparer : IComparer<string>
{
public int Compare(string? x, string? y)
{
switch (x)
{
case null when y == null:
return 0;
case null:
return -1;
}

if (y == null)
{
return 1;
}

var versionBuilderX = new VersionBuilder(x);
var versionBuilderY = new VersionBuilder(y);

for (var i = 0; i < 3; i++)
{
var versionPartX = versionBuilderX.GetVersionPart(i);
var versionPartY = versionBuilderY.GetVersionPart(i);

var versionPartComparison = versionPartX.CompareTo(versionPartY);

if (versionPartComparison != 0)
{
return versionPartComparison;
}
}

return 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using JetBrains.Annotations;

namespace CreativeCoders.GitTool.Base.Versioning;

[PublicAPI]
public class VersionFormatException(string? version, string? message = null) : Exception(message ??
$"The version '{version}' has an invalid format. The version must consist of 1 to 3 numeric parts separated by dots (e.g. '1.0.0').")
{
public string? Version { get; } = version;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace CreativeCoders.GitTool.Base.Versioning;

public enum VersionFormatKind
{
Strict,
Loose
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Diagnostics.CodeAnalysis;
using CreativeCoders.Core;
using CreativeCoders.Git.Abstractions.Tags;

namespace CreativeCoders.GitTool.Base.Versioning;

[ExcludeFromCodeCoverage]
public class VersionTag(string version, IGitTag tag)
{
public string Version { get; } = Ensure.NotNull(version);

public IGitTag Tag { get; } = Ensure.NotNull(tag);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Linq;

namespace CreativeCoders.GitTool.Base.Versioning;

public static class VersionUtils
{
public static bool IsValidVersion(string version, out string normalizedVersion,
bool ignoreLeadingVersionPrefix = true)
{
if (ignoreLeadingVersionPrefix)
{
version = RemoveLeadingVersionPrefix(version);
}

var versionParts = version.Split('.');

var isValidVersion = versionParts.All(x => int.TryParse(x, out _));

normalizedVersion = isValidVersion ? string.Join(".", versionParts) : string.Empty;

return isValidVersion;
}

public static string RemoveLeadingVersionPrefix(string version)
{
if (string.IsNullOrEmpty(version))
{
return string.Empty;
}

string[] versionPrefixes = ["version", "v"];

var versionPrefix =
versionPrefixes.FirstOrDefault(x => version.StartsWith(x, StringComparison.OrdinalIgnoreCase));

return string.IsNullOrWhiteSpace(versionPrefix)
? version
: version[versionPrefix.Length..];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CreativeCoders.Cli.Hosting" Version="6.5.0"/>
<PackageReference Include="CreativeCoders.SysConsole.Core" Version="6.5.0"/>
<PackageReference Include="CreativeCoders.Cli.Hosting" Version="6.6.0"/>
<PackageReference Include="CreativeCoders.SysConsole.Core" Version="6.6.0"/>
</ItemGroup>

<ItemGroup>
Expand Down
Loading