From 295540ca47dabc087e42b7fe4bc7211e367347ea Mon Sep 17 00:00:00 2001 From: darthsharp <48331467+darthsharp@users.noreply.github.com> Date: Sun, 8 Feb 2026 16:25:11 +0100 Subject: [PATCH 1/8] Add commands for listing and managing Git tags (#25) - Introduce `TagCommandGroup` as a command group for tag-related commands. - Implement `ListTagsCommand` with options to display tags in simple or detailed views. - Add support for `TargetCommit` property in `IGitTag` and `GitTag` to enable sorting and extended tag details. - Create `BoolExtensions` helper class for streamlined boolean condition handling in commands. --- .../Tags/IGitTag.cs | 4 +- source/Git/CreativeCoders.Git/Tags/GitTag.cs | 7 ++ .../Shared/BoolExtensions.cs | 42 ++++++++++++ .../TagGroup/List/ListTagsCommand.cs | 64 +++++++++++++++++++ .../TagGroup/List/ListTagsOptions.cs | 11 ++++ .../TagGroup/TagCommandGroup.cs | 10 +++ 6 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/BoolExtensions.cs create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsCommand.cs create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsOptions.cs create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/TagCommandGroup.cs diff --git a/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTag.cs b/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTag.cs index 39ea9d5..7741689 100644 --- a/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTag.cs +++ b/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTag.cs @@ -11,4 +11,6 @@ public interface IGitTag : IEquatable, IComparable, INamedRef string TargetSha { get; } IGitCommit? PeeledTargetCommit(); -} \ No newline at end of file + + IGitCommit? TargetCommit { get; } +} diff --git a/source/Git/CreativeCoders.Git/Tags/GitTag.cs b/source/Git/CreativeCoders.Git/Tags/GitTag.cs index d356f2d..31dd5d6 100644 --- a/source/Git/CreativeCoders.Git/Tags/GitTag.cs +++ b/source/Git/CreativeCoders.Git/Tags/GitTag.cs @@ -14,6 +14,11 @@ internal GitTag(Tag tag) _tag = Ensure.NotNull(tag); Name = new ReferenceName(_tag.CanonicalName); + + if (_tag.Target is Commit commit) + { + TargetCommit = GitCommit.From(commit); + } } static GitTag() => InitComparableObject(x => x.Name.Canonical); @@ -34,5 +39,7 @@ internal GitTag(Tag tag) return GitCommit.From(target as Commit); } + public IGitCommit? TargetCommit { get; } + public static implicit operator Tag(GitTag tag) => tag._tag; } diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/BoolExtensions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/BoolExtensions.cs new file mode 100644 index 0000000..875b3dd --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/BoolExtensions.cs @@ -0,0 +1,42 @@ +namespace CreativeCoders.GitTool.Cli.Commands.Shared; + +public static class BoolExtensions +{ + public static void IfElse(this bool condition, Action trueAction, Action falseAction) + { + if (condition) + { + trueAction(); + } + else + { + falseAction(); + } + } + + public static T IfElse(this bool condition, Func trueFunc, Func falseFunc) + { + return condition ? trueFunc() : falseFunc(); + } + + public static bool If(this bool condition, Action action) + { + if (!condition) + { + return false; + } + + action(); + return true; + } + + public static void Else(this bool condition, Action action) + { + if (condition) + { + return; + } + + action(); + } +} diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsCommand.cs new file mode 100644 index 0000000..c1b3dee --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsCommand.cs @@ -0,0 +1,64 @@ +using System.Globalization; +using CreativeCoders.Cli.Core; +using CreativeCoders.Core; +using CreativeCoders.Git.Abstractions; +using CreativeCoders.Git.Abstractions.Tags; +using CreativeCoders.GitTool.Cli.Commands.Shared; +using CreativeCoders.SysConsole.Core; +using JetBrains.Annotations; +using Spectre.Console; + +namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.List; + +[UsedImplicitly] +[CliCommand([TagCommandGroup.Name, "list"], Description = "Lists all tags")] +public class ListTagsCommand(IAnsiConsole ansiConsole, IGitRepository gitRepository) : ICliCommand +{ + private readonly IGitRepository _gitRepository = Ensure.NotNull(gitRepository); + + private readonly IAnsiConsole _ansiConsole = Ensure.NotNull(ansiConsole); + + public Task ExecuteAsync(ListTagsOptions options) + { + _ansiConsole.WriteLines("List all tags:", string.Empty); + + var tags = _gitRepository.Tags.OrderByDescending(x => + x.TargetCommit?.Author.When ?? DateTimeOffset.MinValue); + + options.ShowExtendedInformation + .If(() => ShowExtendedTable(tags)) + .Else(() => ShowSimpleList(tags)); + + return Task.FromResult(CommandResult.Success); + } + + private void ShowSimpleList(IEnumerable tags) + { + foreach (var tag in tags) + { + _ansiConsole.WriteLine($"- {tag.Name.Friendly}"); + } + } + + private void ShowExtendedTable(IEnumerable tags) + { + _ansiConsole.PrintTable(tags, [ + new TableColumnDef(x => x.Name.Friendly, "Name"), + new TableColumnDef(x => + { + var commit = x.TargetCommit; + return commit == null + ? string.Empty + : commit.Author.When.ToString( + $"{CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern} {CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern}"); + }, "Date of commit"), + new TableColumnDef(x => + { + var commit = x.TargetCommit; + return commit == null + ? string.Empty + : $"{commit.Author.Name} ({commit.Author.Email})"; + }, "Committer") + ]); + } +} diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsOptions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsOptions.cs new file mode 100644 index 0000000..fd54f82 --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsOptions.cs @@ -0,0 +1,11 @@ +using CreativeCoders.SysConsole.Cli.Parsing; +using JetBrains.Annotations; + +namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.List; + +[UsedImplicitly] +public class ListTagsOptions +{ + [OptionParameter('x', "extended", HelpText = "Show extended information")] + public bool ShowExtendedInformation { get; set; } +} diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/TagCommandGroup.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/TagCommandGroup.cs new file mode 100644 index 0000000..f8683f6 --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/TagCommandGroup.cs @@ -0,0 +1,10 @@ +using CreativeCoders.Cli.Core; + +[assembly: CliCommandGroup(["tag"], "Commands for managing tags")] + +namespace CreativeCoders.GitTool.Cli.Commands.TagGroup; + +public static class TagCommandGroup +{ + public const string Name = "tag"; +} From 2b5854996824a4ceb0ad56dd93b707a01e79eac7 Mon Sep 17 00:00:00 2001 From: darthsharp <48331467+darthsharp@users.noreply.github.com> Date: Sun, 8 Feb 2026 16:39:48 +0100 Subject: [PATCH 2/8] Add `FetchTagsCommand` to retrieve tags from remote - Introduced `IFetchTagsCommand` interface and `FetchTagsCommand` implementation for fetching tags. - Added CLI implementation for fetching tags under `TagGroup`. - Updated project structure and `GitCommands` to include the fetch tags functionality. --- .../GitCommands/IFetchTagsCommand.cs | 6 +++ .../GitCommands/IGitCommands.cs | 2 + .../GitCommands/FetchTagsCommand.cs | 21 ++++++++++ .../GitCommands/GitCommands.cs | 5 +++ ...CreativeCoders.GitTool.Cli.Commands.csproj | 5 +++ .../TagGroup/Fetch/FetchTagsCommand.cs | 40 +++++++++++++++++++ .../TagGroup/Fetch/FetchTagsOptions.cs | 12 ++++++ 7 files changed, 91 insertions(+) create mode 100644 source/Git/CreativeCoders.Git.Abstractions/GitCommands/IFetchTagsCommand.cs create mode 100644 source/Git/CreativeCoders.Git/GitCommands/FetchTagsCommand.cs create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs diff --git a/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IFetchTagsCommand.cs b/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IFetchTagsCommand.cs new file mode 100644 index 0000000..297cb7e --- /dev/null +++ b/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IFetchTagsCommand.cs @@ -0,0 +1,6 @@ +namespace CreativeCoders.Git.Abstractions.GitCommands; + +public interface IFetchTagsCommand +{ + void Execute(string remoteName = "origin"); +} diff --git a/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IGitCommands.cs b/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IGitCommands.cs index d719295..9542164 100644 --- a/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IGitCommands.cs +++ b/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IGitCommands.cs @@ -5,4 +5,6 @@ public interface IGitCommands IPullCommand CreatePullCommand(); IPushCommand CreatePushCommand(); + + IFetchTagsCommand CreateFetchTagsCommand(); } diff --git a/source/Git/CreativeCoders.Git/GitCommands/FetchTagsCommand.cs b/source/Git/CreativeCoders.Git/GitCommands/FetchTagsCommand.cs new file mode 100644 index 0000000..c0e1598 --- /dev/null +++ b/source/Git/CreativeCoders.Git/GitCommands/FetchTagsCommand.cs @@ -0,0 +1,21 @@ +using CreativeCoders.Git.Abstractions.GitCommands; + +namespace CreativeCoders.Git.GitCommands; + +internal class FetchTagsCommand(RepositoryContext repositoryContext) : IFetchTagsCommand +{ + private readonly RepositoryContext _repositoryContext = Ensure.NotNull(repositoryContext); + + public void Execute(string remoteName = "origin") + { + var fetchOptions = new FetchOptions + { + Prune = true, + TagFetchMode = TagFetchMode.All + }; + + Commands.Fetch(_repositoryContext.LibGitRepository, remoteName, ["+refs/tags/*:refs/tags/*"], + fetchOptions, + "Fetch all tags"); + } +} diff --git a/source/Git/CreativeCoders.Git/GitCommands/GitCommands.cs b/source/Git/CreativeCoders.Git/GitCommands/GitCommands.cs index 7585590..825fe78 100644 --- a/source/Git/CreativeCoders.Git/GitCommands/GitCommands.cs +++ b/source/Git/CreativeCoders.Git/GitCommands/GitCommands.cs @@ -20,4 +20,9 @@ public IPushCommand CreatePushCommand() { return new PushCommand(_repositoryContext); } + + public IFetchTagsCommand CreateFetchTagsCommand() + { + return new FetchTagsCommand(_repositoryContext); + } } diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj index 6ec2d32..25b37ee 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj @@ -15,4 +15,9 @@ + + + + + diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs new file mode 100644 index 0000000..9253b6b --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs @@ -0,0 +1,40 @@ +using CreativeCoders.Cli.Core; +using CreativeCoders.Core; +using CreativeCoders.Git.Abstractions; +using CreativeCoders.SysConsole.Core; +using Spectre.Console; + +namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Fetch; + +[CliCommand([TagCommandGroup.Name, "fetch"], Description = "Fetch tags from remote repository")] +public class FetchTagsCommand(IAnsiConsole ansiConsole, IGitRepository gitRepository) : ICliCommand +{ + private readonly IAnsiConsole _ansiConsole = Ensure.NotNull(ansiConsole); + + private readonly IGitRepository _gitRepository = Ensure.NotNull(gitRepository); + + public Task ExecuteAsync(FetchTagsOptions options) + { + _ansiConsole.WriteLines("Fetch tags from remote repository", string.Empty); + + var remotes = _gitRepository.Remotes.ToList(); + + if (remotes.Count == 0) + { + _ansiConsole.WriteLine("No remote repository found."); + return Task.FromResult(CommandResult.Success); + } + + var fetchTagsCommand = _gitRepository.Commands.CreateFetchTagsCommand(); + + foreach (var remote in remotes) + { + _ansiConsole.WriteLine($"Fetch tags from remote '{remote.Name}' ({remote.Url})..."); + fetchTagsCommand.Execute(remote.Name); + } + + _ansiConsole.WriteLine("Tags fetched successfully."); + + return Task.FromResult(CommandResult.Success); + } +} diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs new file mode 100644 index 0000000..676274f --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs @@ -0,0 +1,12 @@ +using CreativeCoders.SysConsole.Cli.Parsing; + +namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Fetch; + +public class FetchTagsOptions +{ + [OptionParameter('r', "remote", HelpText = "The remote to fetch tags from")] + public string RemoteName { get; set; } = "origin"; + + [OptionParameter('p', "prune", HelpText = "Prune deleted remote tags")] + public bool Prune { get; set; } = true; +} From a78dc8704382d0614213941883a330d1d7bf5099 Mon Sep 17 00:00:00 2001 From: darthsharp <48331467+darthsharp@users.noreply.github.com> Date: Sun, 8 Feb 2026 16:40:14 +0100 Subject: [PATCH 3/8] Mark `FetchTagsOptions` class with `[UsedImplicitly]` attribute --- .../TagGroup/Fetch/FetchTagsOptions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs index 676274f..ec43d72 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs @@ -1,7 +1,9 @@ using CreativeCoders.SysConsole.Cli.Parsing; +using JetBrains.Annotations; namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Fetch; +[UsedImplicitly] public class FetchTagsOptions { [OptionParameter('r', "remote", HelpText = "The remote to fetch tags from")] From 557ceae4633072e0489f9f9d060c30bc41ddc804 Mon Sep 17 00:00:00 2001 From: darthsharp <48331467+darthsharp@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:47:55 +0100 Subject: [PATCH 4/8] Refactor and enhance Git tag command functionality - Add `CreateTagCommand` for creating new tags with additional options. - Introduce `FetchTagsCommandOptions` for flexible tag fetching configuration. - Update `FetchTagsCommand` to use `FetchTagsCommandOptions`. - Simplify `IGitTagCollection` methods by combining similar tag creation methods. - Remove redundant console writes across various commands. --- .../GitCommands/FetchTagsCommandOptions.cs | 8 +++ .../GitCommands/IFetchTagsCommand.cs | 2 +- .../Tags/IGitTagCollection.cs | 10 ++-- .../GitCommands/FetchTagsCommand.cs | 6 +-- .../Tags/GitTagCollection.cs | 23 +++------ .../BranchGroup/Info/InfoBranchesCommand.cs | 2 - .../BranchGroup/List/ListBranchesCommand.cs | 3 -- .../Update/UpdateBranchesCommand.cs | 3 -- ...CreativeCoders.GitTool.Cli.Commands.csproj | 1 - .../Create/CreateReleaseCommand.cs | 2 +- .../Shared/GitToolPullCommand.cs | 2 - .../Shared/GitToolPushCommand.cs | 2 - .../TagGroup/Create/CreateTagCommand.cs | 50 +++++++++++++++++++ .../TagGroup/Create/CreateTagOptions.cs | 19 +++++++ .../TagGroup/Fetch/FetchTagsCommand.cs | 7 ++- .../Program.cs | 2 + 16 files changed, 101 insertions(+), 41 deletions(-) create mode 100644 source/Git/CreativeCoders.Git.Abstractions/GitCommands/FetchTagsCommandOptions.cs create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagCommand.cs create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagOptions.cs diff --git a/source/Git/CreativeCoders.Git.Abstractions/GitCommands/FetchTagsCommandOptions.cs b/source/Git/CreativeCoders.Git.Abstractions/GitCommands/FetchTagsCommandOptions.cs new file mode 100644 index 0000000..3051eba --- /dev/null +++ b/source/Git/CreativeCoders.Git.Abstractions/GitCommands/FetchTagsCommandOptions.cs @@ -0,0 +1,8 @@ +namespace CreativeCoders.Git.Abstractions.GitCommands; + +public class FetchTagsCommandOptions +{ + public bool Prune { get; set; } = true; + + public string RemoteName { get; set; } = "origin"; +} diff --git a/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IFetchTagsCommand.cs b/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IFetchTagsCommand.cs index 297cb7e..fcd6a0c 100644 --- a/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IFetchTagsCommand.cs +++ b/source/Git/CreativeCoders.Git.Abstractions/GitCommands/IFetchTagsCommand.cs @@ -2,5 +2,5 @@ namespace CreativeCoders.Git.Abstractions.GitCommands; public interface IFetchTagsCommand { - void Execute(string remoteName = "origin"); + void Execute(FetchTagsCommandOptions commandOptions); } diff --git a/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTagCollection.cs b/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTagCollection.cs index 23c2277..5e6fee6 100644 --- a/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTagCollection.cs +++ b/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTagCollection.cs @@ -4,15 +4,11 @@ namespace CreativeCoders.Git.Abstractions.Tags; public interface IGitTagCollection : IEnumerable { - IGitTag CreateTag(string tagName); + IGitTag CreateTag(string tagName, string? objectish = null); - IGitTag CreateTag(string tagName, string objectish); - - IGitTag CreateTagWithMessage(string tagName, string message); - - IGitTag CreateTagWithMessage(string tagName, string objectish, string message); + IGitTag CreateTagWithMessage(string tagName, string message, string? objectish = null); void PushTag(IGitTag tag); void PushAllTags(); -} \ No newline at end of file +} diff --git a/source/Git/CreativeCoders.Git/GitCommands/FetchTagsCommand.cs b/source/Git/CreativeCoders.Git/GitCommands/FetchTagsCommand.cs index c0e1598..c041bdf 100644 --- a/source/Git/CreativeCoders.Git/GitCommands/FetchTagsCommand.cs +++ b/source/Git/CreativeCoders.Git/GitCommands/FetchTagsCommand.cs @@ -6,15 +6,15 @@ internal class FetchTagsCommand(RepositoryContext repositoryContext) : IFetchTag { private readonly RepositoryContext _repositoryContext = Ensure.NotNull(repositoryContext); - public void Execute(string remoteName = "origin") + public void Execute(FetchTagsCommandOptions commandOptions) { var fetchOptions = new FetchOptions { - Prune = true, + Prune = commandOptions.Prune, TagFetchMode = TagFetchMode.All }; - Commands.Fetch(_repositoryContext.LibGitRepository, remoteName, ["+refs/tags/*:refs/tags/*"], + Commands.Fetch(_repositoryContext.LibGitRepository, commandOptions.RemoteName, ["+refs/tags/*:refs/tags/*"], fetchOptions, "Fetch all tags"); } diff --git a/source/Git/CreativeCoders.Git/Tags/GitTagCollection.cs b/source/Git/CreativeCoders.Git/Tags/GitTagCollection.cs index 4f50eed..7975110 100644 --- a/source/Git/CreativeCoders.Git/Tags/GitTagCollection.cs +++ b/source/Git/CreativeCoders.Git/Tags/GitTagCollection.cs @@ -19,25 +19,18 @@ internal GitTagCollection(RepositoryContext context) _libGitCaller = _context.LibGitCaller; } - public IGitTag CreateTag(string tagName) + public IGitTag CreateTag(string tagName, string? objectish = null) { - return new GitTag(_libGitCaller.Invoke(() => _repository.ApplyTag(tagName))); + return string.IsNullOrWhiteSpace(objectish) + ? new GitTag(_libGitCaller.Invoke(() => _repository.ApplyTag(tagName))) + : new GitTag(_libGitCaller.Invoke(() => _repository.ApplyTag(tagName, objectish))); } - public IGitTag CreateTag(string tagName, string objectish) + public IGitTag CreateTagWithMessage(string tagName, string message, string? objectish = null) { - return new GitTag(_libGitCaller.Invoke(() => _repository.ApplyTag(tagName, objectish))); - } - - public IGitTag CreateTagWithMessage(string tagName, string message) - { - return new GitTag(_libGitCaller.Invoke(() => _repository.ApplyTag(tagName, _context.GetSignature(), message))); - } - - public IGitTag CreateTagWithMessage(string tagName, string objectish, string message) - { - return new GitTag( - _libGitCaller + return string.IsNullOrWhiteSpace(objectish) + ? new GitTag(_libGitCaller.Invoke(() => _repository.ApplyTag(tagName, _context.GetSignature(), message))) + : new GitTag(_libGitCaller .Invoke(() => _repository.ApplyTag(tagName, objectish, _context.GetSignature(), message))); } diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/Info/InfoBranchesCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/Info/InfoBranchesCommand.cs index 4d36a3f..6ecc288 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/Info/InfoBranchesCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/Info/InfoBranchesCommand.cs @@ -46,8 +46,6 @@ public Task ExecuteAsync(InfoBranchesOptions options) _ansiConsole.PrintCommitLog(commits); } - _ansiConsole.WriteLine(); - return Task.FromResult(CommandResult.Success); } } diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/List/ListBranchesCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/List/ListBranchesCommand.cs index 793baef..877de82 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/List/ListBranchesCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/List/ListBranchesCommand.cs @@ -41,7 +41,6 @@ private void PrintBranch(IGitBranch branch, int column0Width, int column1Width) public Task ExecuteAsync(ListBranchesOptions options) { _sysConsole - .WriteLine() .WriteLine("List all branches:") .WriteLine(); @@ -62,8 +61,6 @@ public Task ExecuteAsync(ListBranchesOptions options) // ReSharper disable once AccessToDisposedClosure branches.ForEach(branch => PrintBranch(branch, column0Width, column1Width)); - _sysConsole.WriteLine(); - return Task.FromResult(CommandResult.Success); } } diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/Update/UpdateBranchesCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/Update/UpdateBranchesCommand.cs index 6aa8181..f0a2404 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/Update/UpdateBranchesCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/BranchGroup/Update/UpdateBranchesCommand.cs @@ -37,7 +37,6 @@ public async Task ExecuteAsync(UpdateBranchesOptions options) Ensure.NotNull(options); _ansiConsole - .EmptyLine() .WriteMarkupLine(_cml.Caption("Update permanent local branches")) .EmptyLine(); @@ -73,8 +72,6 @@ public async Task ExecuteAsync(UpdateBranchesOptions options) _gitRepository.Branches.CheckOut(currentBranch.Name.Friendly); } - _ansiConsole.EmptyLine(); - return CommandResult.Success; } diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj index 25b37ee..7fb2b01 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj @@ -16,7 +16,6 @@ - diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/ReleaseGroup/Create/CreateReleaseCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/ReleaseGroup/Create/CreateReleaseCommand.cs index ca4bf1c..5944a16 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/ReleaseGroup/Create/CreateReleaseCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/ReleaseGroup/Create/CreateReleaseCommand.cs @@ -55,7 +55,7 @@ public async Task ExecuteAsync(CreateReleaseOptions options) _gitRepository.Pull(); var versionTag = - _gitRepository.Tags.CreateTagWithMessage(tagName, mainBranchName, $"Version {options.Version}"); + _gitRepository.Tags.CreateTagWithMessage(tagName, $"Version {options.Version}", mainBranchName); if (options.PushAllTags) { diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/GitToolPullCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/GitToolPullCommand.cs index dd15d6a..bb2f9c4 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/GitToolPullCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/GitToolPullCommand.cs @@ -38,8 +38,6 @@ public Task ExecuteAsync(IGitRepository gitRepository, bool verbose) PrintMergeResultStatus(mergeResult.MergeStatus); - _ansiConsole.WriteLine(); - return Task.FromResult(0); } diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/GitToolPushCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/GitToolPushCommand.cs index a645653..3496b4e 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/GitToolPushCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/Shared/GitToolPushCommand.cs @@ -42,8 +42,6 @@ public Task ExecuteAsync(IGitRepository gitRepository, bool createRemoteIsN pushCommand.Run(); - _ansiConsole.WriteLine(); - return Task.FromResult(0); } diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagCommand.cs new file mode 100644 index 0000000..1155aa5 --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagCommand.cs @@ -0,0 +1,50 @@ +using CreativeCoders.Cli.Core; +using CreativeCoders.Core; +using CreativeCoders.Git.Abstractions; +using CreativeCoders.Git.Abstractions.Tags; +using CreativeCoders.SysConsole.Core; +using JetBrains.Annotations; +using Spectre.Console; + +namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Create; + +[UsedImplicitly] +[CliCommand([TagCommandGroup.Name, "create"], Description = "Creates a new tag")] +public class CreateTagCommand(IAnsiConsole ansiConsole, IGitRepository gitRepository) : ICliCommand +{ + private readonly IAnsiConsole _ansiConsole = Ensure.NotNull(ansiConsole); + + private readonly IGitRepository _gitRepository = Ensure.NotNull(gitRepository); + + public Task ExecuteAsync(CreateTagOptions options) + { + _ansiConsole.WriteLine($"Creating tag '{options.TagName}'..."); + + var tag = CreateTag(options); + + _ansiConsole.MarkupLines( + $"Tag '{tag.Name}' created.".ToSuccessMarkup(), + string.Empty, + $"Target commit: {tag.TargetCommit?.Id.Sha ?? "[none]"}".ToEscapedMarkup()); + + if (options.PushAfterCreate) + { + _ansiConsole.WriteLines( + string.Empty, + "Pushing tag after creation"); + + _gitRepository.Tags.PushTag(tag); + + _ansiConsole.MarkupLine("Tag pushed.".ToSuccessMarkup()); + } + + return Task.FromResult(CommandResult.Success); + } + + private IGitTag CreateTag(CreateTagOptions options) + { + return string.IsNullOrWhiteSpace(options.Message) + ? _gitRepository.Tags.CreateTag(options.TagName, options.Objectish) + : _gitRepository.Tags.CreateTagWithMessage(options.TagName, options.Message, options.Objectish); + } +} diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagOptions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagOptions.cs new file mode 100644 index 0000000..adc071a --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagOptions.cs @@ -0,0 +1,19 @@ +using CreativeCoders.SysConsole.Cli.Parsing; +using JetBrains.Annotations; + +namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Create; + +[UsedImplicitly] +public class CreateTagOptions +{ + [OptionValue(0, IsRequired = true)] public string TagName { get; set; } = string.Empty; + + [OptionParameter('p', "push", HelpText = "Push tag after creation")] + public bool PushAfterCreate { get; set; } + + [OptionParameter('m', "message", HelpText = "Message for tag")] + public string? Message { get; set; } + + [OptionParameter('o', "objectish", HelpText = "Object to tag")] + public string? Objectish { get; set; } +} diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs index 9253b6b..a514f53 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs @@ -1,6 +1,7 @@ using CreativeCoders.Cli.Core; using CreativeCoders.Core; using CreativeCoders.Git.Abstractions; +using CreativeCoders.Git.Abstractions.GitCommands; using CreativeCoders.SysConsole.Core; using Spectre.Console; @@ -30,7 +31,11 @@ public Task ExecuteAsync(FetchTagsOptions options) foreach (var remote in remotes) { _ansiConsole.WriteLine($"Fetch tags from remote '{remote.Name}' ({remote.Url})..."); - fetchTagsCommand.Execute(remote.Name); + fetchTagsCommand.Execute(new FetchTagsCommandOptions + { + RemoteName = remote.Name, + Prune = options.Prune + }); } _ansiConsole.WriteLine("Tags fetched successfully."); diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.GtApp/Program.cs b/source/GitTool/CreativeCoders.GitTool.Cli.GtApp/Program.cs index 51579ac..6e14a9d 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.GtApp/Program.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.GtApp/Program.cs @@ -24,6 +24,8 @@ internal static async Task Main(string[] args) { var result = await CliHostBuilder.Create() .ConfigureServices(ConfigureServices) + .PrintHeaderText([string.Empty]) + .PrintFooterText([string.Empty]) .EnableHelp(HelpCommandKind.CommandOrArgument) .ScanAssemblies(typeof(ShowConfigCommand).Assembly) .Build() From b7da82985e480fcecab5cca56a20200586e03da3 Mon Sep 17 00:00:00 2001 From: darthsharp <48331467+darthsharp@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:34:44 +0100 Subject: [PATCH 5/8] - Remove unused header text print in `Program.cs`. - Update `FetchTagsCommand` to use markup for success message. --- .../TagGroup/Fetch/FetchTagsCommand.cs | 2 +- source/GitTool/CreativeCoders.GitTool.Cli.GtApp/Program.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs index a514f53..d5c365a 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs @@ -38,7 +38,7 @@ public Task ExecuteAsync(FetchTagsOptions options) }); } - _ansiConsole.WriteLine("Tags fetched successfully."); + _ansiConsole.MarkupLine("Tags fetched successfully.".ToSuccessMarkup()); return Task.FromResult(CommandResult.Success); } diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.GtApp/Program.cs b/source/GitTool/CreativeCoders.GitTool.Cli.GtApp/Program.cs index 6e14a9d..8f16600 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.GtApp/Program.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.GtApp/Program.cs @@ -24,7 +24,6 @@ internal static async Task Main(string[] args) { var result = await CliHostBuilder.Create() .ConfigureServices(ConfigureServices) - .PrintHeaderText([string.Empty]) .PrintFooterText([string.Empty]) .EnableHelp(HelpCommandKind.CommandOrArgument) .ScanAssemblies(typeof(ShowConfigCommand).Assembly) From a0b3b42046ab69891f52fb87c182940459576a1f Mon Sep 17 00:00:00 2001 From: darthsharp <48331467+darthsharp@users.noreply.github.com> Date: Fri, 13 Feb 2026 19:13:20 +0100 Subject: [PATCH 6/8] Add `DeleteTagCommand` to remove local and remote Git tags - Implement CLI command for deleting tags with options for remote deletion. - Extend `IGitTagCollection` and `GitTagCollection` with methods for tag removal. - Update project structure to include `TagGroup/Delete` commands. --- .../Tags/IGitTagCollection.cs | 8 ++++ .../Tags/GitTagCollection.cs | 36 +++++++++++++++++- ...CreativeCoders.GitTool.Cli.Commands.csproj | 4 -- .../TagGroup/Delete/DeleteTagCommand.cs | 37 +++++++++++++++++++ .../TagGroup/Delete/DeleteTagOptions.cs | 14 +++++++ 5 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagCommand.cs create mode 100644 source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagOptions.cs diff --git a/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTagCollection.cs b/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTagCollection.cs index 5e6fee6..d620e8a 100644 --- a/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTagCollection.cs +++ b/source/Git/CreativeCoders.Git.Abstractions/Tags/IGitTagCollection.cs @@ -8,6 +8,14 @@ public interface IGitTagCollection : IEnumerable IGitTag CreateTagWithMessage(string tagName, string message, string? objectish = null); + void DeleteTag(string tagName, bool deleteOnRemote = false); + + void DeleteTag(IGitTag tag, bool deleteOnRemote = false); + + void DeleteRemoteTag(string tagName); + + void PushTag(string tagName); + void PushTag(IGitTag tag); void PushAllTags(); diff --git a/source/Git/CreativeCoders.Git/Tags/GitTagCollection.cs b/source/Git/CreativeCoders.Git/Tags/GitTagCollection.cs index 7975110..5d49ee0 100644 --- a/source/Git/CreativeCoders.Git/Tags/GitTagCollection.cs +++ b/source/Git/CreativeCoders.Git/Tags/GitTagCollection.cs @@ -34,7 +34,34 @@ public IGitTag CreateTagWithMessage(string tagName, string message, string? obje .Invoke(() => _repository.ApplyTag(tagName, objectish, _context.GetSignature(), message))); } - public void PushTag(IGitTag tag) + public void DeleteTag(string tagName, bool deleteOnRemote = false) + { + _libGitCaller.Invoke(() => _repository.Tags.Remove(tagName)); + + if (deleteOnRemote) + { + DeleteRemoteTag(tagName); + } + } + + public void DeleteTag(IGitTag tag, bool deleteOnRemote = false) + { + DeleteTag(tag.Name.Canonical, deleteOnRemote); + } + + public void DeleteRemoteTag(string tagName) + { + var pushOptions = new PushOptions + { + CredentialsProvider = _context.GetCredentialsHandler() + }; + + _libGitCaller.Invoke(() => + _repository.Network.Push(_repository.Network.Remotes[GitRemotes.Origin], $":refs/tags/{tagName}", + pushOptions)); + } + + public void PushTag(string tagName) { var pushOptions = new PushOptions { @@ -42,7 +69,12 @@ public void PushTag(IGitTag tag) }; _libGitCaller.Invoke(() => - _repository.Network.Push(_repository.Network.Remotes[GitRemotes.Origin], tag.Name.Canonical, pushOptions)); + _repository.Network.Push(_repository.Network.Remotes[GitRemotes.Origin], tagName, pushOptions)); + } + + public void PushTag(IGitTag tag) + { + PushTag(tag.Name.Canonical); } public void PushAllTags() diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj index 7fb2b01..6ec2d32 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/CreativeCoders.GitTool.Cli.Commands.csproj @@ -15,8 +15,4 @@ - - - - diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagCommand.cs new file mode 100644 index 0000000..219f084 --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagCommand.cs @@ -0,0 +1,37 @@ +using CreativeCoders.Cli.Core; +using CreativeCoders.Core; +using CreativeCoders.Git.Abstractions; +using CreativeCoders.SysConsole.Core; +using JetBrains.Annotations; +using Spectre.Console; + +namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Delete; + +[UsedImplicitly] +[CliCommand([TagCommandGroup.Name, "delete"], Description = "Deletes a tag from the repository")] +public class DeleteTagCommand(IAnsiConsole ansiConsole, IGitRepository gitRepository) : ICliCommand +{ + private readonly IAnsiConsole _ansiConsole = Ensure.NotNull(ansiConsole); + + private readonly IGitRepository _gitRepository = Ensure.NotNull(gitRepository); + + public Task ExecuteAsync(DeleteTagOptions options) + { + _ansiConsole.WriteLine($"Deleting tag '{options.TagName}'..."); + + _gitRepository.Tags.DeleteTag(options.TagName); + + _ansiConsole.MarkupLine($"Tag '{options.TagName}' deleted successfully".ToSuccessMarkup()); + + if (options.DeleteOnRemote) + { + _ansiConsole.WriteLine("Deleting tag on remote..."); + + _gitRepository.Tags.DeleteRemoteTag(options.TagName); + + _ansiConsole.MarkupLine($"Tag '{options.TagName}' deleted successfully on remote".ToSuccessMarkup()); + } + + return Task.FromResult(CommandResult.Success); + } +} diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagOptions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagOptions.cs new file mode 100644 index 0000000..07ddf2e --- /dev/null +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagOptions.cs @@ -0,0 +1,14 @@ +using CreativeCoders.SysConsole.Cli.Parsing; +using JetBrains.Annotations; + +namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Delete; + +[UsedImplicitly] +public class DeleteTagOptions +{ + [OptionValue(0, HelpText = "The name of the tag to delete")] + public string TagName { get; set; } = string.Empty; + + [OptionParameter('r', "remote", HelpText = "Delete tag on remote")] + public bool DeleteOnRemote { get; set; } +} From 9ed9789c0657e416d14dd913872f7b3317234eb7 Mon Sep 17 00:00:00 2001 From: darthsharp <48331467+darthsharp@users.noreply.github.com> Date: Fri, 13 Feb 2026 19:15:50 +0100 Subject: [PATCH 7/8] Replace `[UsedImplicitly]` attributes with `[PublicAPI]` across tag-related CLI option classes and add `[UsedImplicitly]` for `FetchTagsCommand`. --- .../TagGroup/Create/CreateTagOptions.cs | 2 +- .../TagGroup/Delete/DeleteTagOptions.cs | 2 +- .../TagGroup/Fetch/FetchTagsCommand.cs | 2 ++ .../TagGroup/Fetch/FetchTagsOptions.cs | 2 +- .../TagGroup/List/ListTagsOptions.cs | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagOptions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagOptions.cs index adc071a..5b74dfe 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagOptions.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagOptions.cs @@ -3,7 +3,7 @@ namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Create; -[UsedImplicitly] +[PublicAPI] public class CreateTagOptions { [OptionValue(0, IsRequired = true)] public string TagName { get; set; } = string.Empty; diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagOptions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagOptions.cs index 07ddf2e..7413433 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagOptions.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Delete/DeleteTagOptions.cs @@ -3,7 +3,7 @@ namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Delete; -[UsedImplicitly] +[PublicAPI] public class DeleteTagOptions { [OptionValue(0, HelpText = "The name of the tag to delete")] diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs index d5c365a..089e071 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsCommand.cs @@ -3,10 +3,12 @@ using CreativeCoders.Git.Abstractions; using CreativeCoders.Git.Abstractions.GitCommands; using CreativeCoders.SysConsole.Core; +using JetBrains.Annotations; using Spectre.Console; namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Fetch; +[UsedImplicitly] [CliCommand([TagCommandGroup.Name, "fetch"], Description = "Fetch tags from remote repository")] public class FetchTagsCommand(IAnsiConsole ansiConsole, IGitRepository gitRepository) : ICliCommand { diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs index ec43d72..5c51075 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Fetch/FetchTagsOptions.cs @@ -3,7 +3,7 @@ namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.Fetch; -[UsedImplicitly] +[PublicAPI] public class FetchTagsOptions { [OptionParameter('r', "remote", HelpText = "The remote to fetch tags from")] diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsOptions.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsOptions.cs index fd54f82..9c9a802 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsOptions.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/List/ListTagsOptions.cs @@ -3,7 +3,7 @@ namespace CreativeCoders.GitTool.Cli.Commands.TagGroup.List; -[UsedImplicitly] +[PublicAPI] public class ListTagsOptions { [OptionParameter('x', "extended", HelpText = "Show extended information")] From 79f97e5b73563ad38d5dcb34e62539ab267fbc78 Mon Sep 17 00:00:00 2001 From: darthsharp <48331467+darthsharp@users.noreply.github.com> Date: Fri, 13 Feb 2026 19:24:48 +0100 Subject: [PATCH 8/8] Update success message in `CreateTagCommand` to use friendly tag name --- .../TagGroup/Create/CreateTagCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagCommand.cs b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagCommand.cs index 1155aa5..ad97275 100644 --- a/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagCommand.cs +++ b/source/GitTool/CreativeCoders.GitTool.Cli.Commands/TagGroup/Create/CreateTagCommand.cs @@ -23,7 +23,7 @@ public Task ExecuteAsync(CreateTagOptions options) var tag = CreateTag(options); _ansiConsole.MarkupLines( - $"Tag '{tag.Name}' created.".ToSuccessMarkup(), + $"Tag '{tag.Name.Friendly}' created.".ToSuccessMarkup(), string.Empty, $"Target commit: {tag.TargetCommit?.Id.Sha ?? "[none]"}".ToEscapedMarkup());