From cf336da27191716d29e9e1511ddb140bee0e6b20 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 24 Aug 2026 16:45:42 +1000 Subject: [PATCH 1/4] feat(git-provider): Load previous registrations, add debug hook - add way to redirect debug output - remove unique constraint on Location --- src/ModuleCore/Git/GitManager.cs | 66 ++++++++++++++++--- .../Git/Commands/NewGitRepoCommand.cs | 4 ++ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/ModuleCore/Git/GitManager.cs b/src/ModuleCore/Git/GitManager.cs index a530c4e..36f2886 100644 --- a/src/ModuleCore/Git/GitManager.cs +++ b/src/ModuleCore/Git/GitManager.cs @@ -12,18 +12,48 @@ public class GitManager private static readonly Lazy GitManagerInstance = new(() => new GitManager()); private readonly ConcurrentDictionary _registrations; private readonly DatabaseManager _db; + private static Action? _debugWriterDelegate; private GitManager() { - Debug.WriteLine($"{nameof(GitManager)} init"); - _registrations = new ConcurrentDictionary(); _db = new DatabaseManager("git.db"); + InitialiseRegistrations(); + } + + /// + /// Creates up any database tables and loads all previously saved git registrations. + /// + private void InitialiseRegistrations() + { + _debugWriterDelegate?.Invoke("Initialising GitManager from first run - this should only happen once."); + _db.InConnection(conn => { - conn.CreateTable(); + var createTableResult = conn.CreateTable(); + + if (createTableResult == CreateTableResult.Created) + { + _debugWriterDelegate?.Invoke($"Created table {InternalGitRegistration.TableName}."); + } }); + + _debugWriterDelegate?.Invoke("Loading previous registrations from database."); + + var registrations = _db.InConnection>(conn => + conn.Table() + .ToList() + ); + + foreach (var internalGitRegistration in registrations) + { + _debugWriterDelegate?.Invoke($"Loading {internalGitRegistration.Name} ({internalGitRegistration.Id}) from database..."); + if (!_registrations.TryAdd(internalGitRegistration.Name, internalGitRegistration)) + { + _debugWriterDelegate?.Invoke("...failed to restore - potential duplicate name."); + } + } } public static GitManager Instance => GitManagerInstance.Value; @@ -55,23 +85,22 @@ public class GitManager return _db.InConnection(conn => { - // Query if we already have a registration either by name or location. + // Query if we already have a registration either by name. Previously we also checked by location, but I + // decided to stick with constraining to the name only, same as the key used for the dictionary. // tbh this is a bit of a janky way to do exists when I have to pass the query in anyway, but I just didn't // want to do null checks and a truthy check so I wrap it in a barely-valuable method. var registrationExists = _db.Exists( $""" SELECT 1 FROM {InternalGitRegistration.TableName} - WHERE Name = ? OR - Location = ? + WHERE Name = ? """, - gitRegistration.Name, - gitRegistration.Location + gitRegistration.Name ); if (registrationExists) { - throw new Exception($"A Git repo is already registered with the name {registrationName} or location {absoluteRepositoryLocation}"); + throw new Exception($"A Git repo is already registered with the name {registrationName}."); } // Insert the new record @@ -116,6 +145,24 @@ public class GitManager throw new Exception($"No git repo has been registered with the name {registeredName}"); } + /// + /// Registers an output for debug output. should be called as soon as the need for output + /// is no longer needed. + /// + /// + public static void SetDebugWriter(Action commandRuntime) + { + _debugWriterDelegate = commandRuntime; + } + + /// + /// Clears any output previously registered with + /// + public static void ClearDebugWriter() + { + _debugWriterDelegate = null; + } + /// /// Used for internal git registration and handles getting the current branch /// @@ -132,7 +179,6 @@ public class GitManager [Indexed(Unique = true)] public string Name { get; set; } = null!; - [Indexed(Unique = true)] public string Location { get; set; } = null!; public string CurrentBranch => GetCurrentBranch(); diff --git a/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs b/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs index 103cffa..9be33a4 100644 --- a/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs +++ b/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs @@ -24,6 +24,8 @@ public sealed class NewGitRepoCommand : PSCmdlet var pwd = this.SessionState.Path.CurrentLocation.Path; WriteDebug("Checking if current directory is a git repository..."); + GitManager.SetDebugWriter(WriteDebug); + var repoFolfder = IsGitRepo(pwd); if (repoFolfder is not null) @@ -43,6 +45,8 @@ public sealed class NewGitRepoCommand : PSCmdlet ); } + GitManager.ClearDebugWriter(); + base.BeginProcessing(); } From 164df4ecf476a5c7642fd4114e37fa057ab2cd0a Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 24 Aug 2026 16:46:35 +1000 Subject: [PATCH 2/4] chore(git-provider): Code style --- src/ModuleCore/Git/GitManager.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ModuleCore/Git/GitManager.cs b/src/ModuleCore/Git/GitManager.cs index 36f2886..b0e847a 100644 --- a/src/ModuleCore/Git/GitManager.cs +++ b/src/ModuleCore/Git/GitManager.cs @@ -10,9 +10,9 @@ namespace ModuleCore.Git; public class GitManager { private static readonly Lazy GitManagerInstance = new(() => new GitManager()); - private readonly ConcurrentDictionary _registrations; - private readonly DatabaseManager _db; private static Action? _debugWriterDelegate; + private readonly DatabaseManager _db; + private readonly ConcurrentDictionary _registrations; private GitManager() { @@ -22,6 +22,13 @@ public class GitManager InitialiseRegistrations(); } + public static GitManager Instance => GitManagerInstance.Value; + + /// + /// Always returns a new clean instance of GitManager + /// + internal static GitManager InternalFreshInstance => new(); + /// /// Creates up any database tables and loads all previously saved git registrations. /// @@ -56,13 +63,6 @@ public class GitManager } } - public static GitManager Instance => GitManagerInstance.Value; - - /// - /// Always returns a new clean instance of GitManager - /// - internal static GitManager InternalFreshInstance => new(); - /// /// Registers a git repository based on an absolute location. If is null or empty, /// the registration will use the folder name for the git repo at the top level. @@ -146,7 +146,7 @@ public class GitManager } /// - /// Registers an output for debug output. should be called as soon as the need for output + /// Registers an output for debug output. should be called as soon as the need for output /// is no longer needed. /// /// @@ -156,7 +156,7 @@ public class GitManager } /// - /// Clears any output previously registered with + /// Clears any output previously registered with /// public static void ClearDebugWriter() { @@ -169,9 +169,9 @@ public class GitManager [Table(TableName)] private class InternalGitRegistration { + internal const string TableName = "GitRegistration"; private string _currentBranch = string.Empty; private long _nextCheckTime; - internal const string TableName = "GitRegistration"; [PrimaryKey] public Guid Id { get; set; } From 7b59b905720fa694bd5cff6836ecccc9b41d1fed Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 24 Aug 2026 17:10:20 +1000 Subject: [PATCH 3/4] chore(git-provider): Use -C when checking if current directory is a git repo - move WriteDebug to IsGitRepo - inline variable for SessionState.Path.CurrentLocation.Path --- .../Git/Commands/NewGitRepoCommand.cs | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs b/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs index 9be33a4..29f629a 100644 --- a/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs +++ b/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs @@ -15,22 +15,15 @@ public sealed class NewGitRepoCommand : PSCmdlet HelpMessage = "Reference name for the repo")] public string? Name { get; set; } - public NewGitRepoCommand() - { - } - protected override void BeginProcessing() { - var pwd = this.SessionState.Path.CurrentLocation.Path; - WriteDebug("Checking if current directory is a git repository..."); - GitManager.SetDebugWriter(WriteDebug); - var repoFolfder = IsGitRepo(pwd); + var repoFolder = IsGitRepo(SessionState.Path.CurrentLocation.Path); - if (repoFolfder is not null) + if (repoFolder is not null) { - GitManager.Instance.RegisterRepo(repoFolfder.Directory, Name ?? repoFolfder.Folder); + GitManager.Instance.RegisterRepo(repoFolder.Directory, Name ?? repoFolder.Folder); } else { @@ -52,12 +45,13 @@ public sealed class NewGitRepoCommand : PSCmdlet private ParsedGitFolderDetails? IsGitRepo(string path) { + WriteDebug("Checking if current directory is a git repository..."); + var ps = new ProcessStartInfo("git", - ["rev-parse", "--show-toplevel"]) + ["-C", path, "rev-parse", "--show-toplevel"]) { RedirectStandardOutput = true, RedirectStandardError = true, - WorkingDirectory = path }; // If the user doesn't have git on their path, this will throw an exception that I don't have to do anything @@ -79,6 +73,8 @@ public sealed class NewGitRepoCommand : PSCmdlet // Gotta trim what we get as it might already have a newline character at the end var dirInfo = new DirectoryInfo(directory.Trim()); + WriteDebug("...location is a git repo (duh)."); + var repoFolderInfo = new ParsedGitFolderDetails { Directory = dirInfo.FullName, From c48549117f602a26af3834bf83ef43155de92710 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 24 Aug 2026 17:35:53 +1000 Subject: [PATCH 4/4] chore(git-provider): Trim output when getting current branch --- src/ModuleCore/Git/GitManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ModuleCore/Git/GitManager.cs b/src/ModuleCore/Git/GitManager.cs index b0e847a..8b2b6f4 100644 --- a/src/ModuleCore/Git/GitManager.cs +++ b/src/ModuleCore/Git/GitManager.cs @@ -230,7 +230,8 @@ public class GitManager // Set the next check to be in the future so we don't hold up any list commands every time. _nextCheckTime = now.AddMinutes(15).Ticks; - return _currentBranch; + // The branch name could (will) have a newline character at the end, so we trim that off + return _currentBranch.Trim(); } } } \ No newline at end of file