Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c09b7c5a8 |
56 changed files with 371 additions and 192 deletions
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
*.verified.txt text eol=lf working-tree-encoding=UTF-8
|
||||
*.verified.xml text eol=lf working-tree-encoding=UTF-8
|
||||
*.verified.json text eol=lf working-tree-encoding=UTF-8
|
||||
*.verified.bin binary
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using Cake.Common.IO;
|
||||
using Cake.Common.IO;
|
||||
using Cake.Common.IO.Paths;
|
||||
using Cake.Core;
|
||||
using Cake.Core.IO;
|
||||
using Cake.Frosting;
|
||||
|
||||
namespace Build;
|
||||
|
|
@ -10,7 +11,7 @@ public class BuildContext : FrostingContext
|
|||
/// <summary>
|
||||
/// Base source directory
|
||||
/// </summary>
|
||||
public ConvertableDirectoryPath BaseSourceLocation { get; set; }
|
||||
public DirectoryPath BaseSourceLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Powershell module project folder
|
||||
|
|
@ -32,19 +33,29 @@ public class BuildContext : FrostingContext
|
|||
/// </summary>
|
||||
public ConvertableFilePath CreateModuleManifestScript { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Suffix to tag the build with, defaults to pre-release.
|
||||
/// <para>
|
||||
/// Immediately follows the version number and before the commit hash.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public string BuildSuffix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disable the commit hash from being added
|
||||
/// </summary>
|
||||
public bool DisableCommitHash { get; set; }
|
||||
|
||||
public BuildContext(ICakeContext context)
|
||||
: base(context)
|
||||
{
|
||||
BaseSourceLocation = context.Directory("../src");
|
||||
BaseSourceLocation = context.Directory("../src").Path.MakeAbsolute(context.Environment);
|
||||
PowershellModuleProjectDirectory = BaseSourceLocation + context.Directory("PowershellModule");
|
||||
PowershellModuleCsproj = PowershellModuleProjectDirectory + context.File("PowershellModule.csproj");
|
||||
PowershellModuleOutputDir = context.Directory("../") + context.Directory("output") + context.Directory("PowershellModule");
|
||||
var buildScriptDirectory = context.Directory("./Scripts");
|
||||
CreateModuleManifestScript = buildScriptDirectory + context.File("CreateModuleManifest.ps1");
|
||||
BuildSuffix = context.Configuration.GetValue(nameof(BuildSuffix));
|
||||
BuildSuffix = context.Configuration.GetValue(nameof(BuildSuffix)) ?? "pre-release";
|
||||
DisableCommitHash = context.Configuration.GetBoolValue(nameof(DisableCommitHash));
|
||||
}
|
||||
}
|
||||
48
build/Helpers.cs
Normal file
48
build/Helpers.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Build;
|
||||
|
||||
public class Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a formatted version of the assembly that contains PowerShell cmdlets
|
||||
/// </summary>
|
||||
/// <param name="powershelModuleOutputLocation"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetPowershellModuleVersion(string powershelModuleOutputLocation)
|
||||
{
|
||||
// When the project name changes, this dll will also need to be updated
|
||||
var moduleVersionInfo = FileVersionInfo.GetVersionInfo(Path.Combine(powershelModuleOutputLocation, "PowershellModule.dll"));
|
||||
|
||||
// It's (almost) impossible to not have a product version tag here. There is a reason why the implementation
|
||||
// returns a string? but I can't find it and I don't really care too much. If we have null return an empty string
|
||||
// and append no version to the archive bundle.
|
||||
if (moduleVersionInfo.ProductVersion == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var versionRegex = new Regex(@"(\d+\.\d+\.\d+)(?:\-?([\w\-]+)\+?(\w+)?)?");
|
||||
var match = versionRegex.Match(moduleVersionInfo.ProductVersion);
|
||||
if (match.Success)
|
||||
{
|
||||
// If we have 4 groups, we've got a version number, suffix, and commit hash, so we return the first 2 as is
|
||||
// and the commit has capped to 8 characters
|
||||
if (match.Groups.Count == 4)
|
||||
{
|
||||
return $"{match.Groups[1]}-{match.Groups[2]}+{match.Groups[3].Value.Substring(0, 8)}";
|
||||
}
|
||||
|
||||
if (match.Groups.Count == 3)
|
||||
{
|
||||
return $"{match.Groups[1]}-{match.Groups[2]}";
|
||||
}
|
||||
|
||||
return $"{match.Groups[1]}";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,8 +8,6 @@ public static class Program
|
|||
{
|
||||
return new CakeHost()
|
||||
.UseContext<BuildContext>()
|
||||
// Uncomment this if you don't want to set the suffix via the run profile program arguments
|
||||
//.UseCakeSetting(nameof(BuildContext.BuildSuffix), "<your suffix here>")
|
||||
.Run(args);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
param (
|
||||
param (
|
||||
[string]$powershellModuleFileLocation,
|
||||
[string]$guid,
|
||||
[string]$author,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Cake.Common.Tools.DotNet;
|
||||
using Cake.Common.Tools.DotNet;
|
||||
using Cake.Common.Tools.DotNet.Build;
|
||||
using Cake.Common.Tools.DotNet.MSBuild;
|
||||
using Cake.Core.Diagnostics;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Cake.Common;
|
||||
using Cake.Common;
|
||||
using Cake.Common.Tools.DotNet;
|
||||
using Cake.Core.Diagnostics;
|
||||
using Cake.Frosting;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cake.Core.Diagnostics;
|
||||
|
|
@ -15,8 +15,8 @@ public class CopyOutputTask : FrostingTask<BuildContext>
|
|||
public override void Run(BuildContext context)
|
||||
{
|
||||
var powershellModuleName = "PowershellModule";
|
||||
// TODO: probably don't create full file locations when I can pass the output dir in and have the script
|
||||
// make the path
|
||||
// TODO: [#10] Refactor file paths used in build project to be more explict and easier to understand
|
||||
// Probably don't create full file locations when I can pass the output dir in and have the script make the path
|
||||
var scriptParams = new
|
||||
{
|
||||
PowershellModuleFileLocation = $"{context.PowershellModuleOutputDir}/{powershellModuleName}.psd1",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text.RegularExpressions;
|
||||
|
|
@ -79,7 +80,7 @@ public class CreateBundleArchiveTask : FrostingTask<BuildContext>
|
|||
context.Log.Information($"Bundle files copied");
|
||||
|
||||
GenerateModuleImportScript(moduleFolderLocation, context);
|
||||
var moduleVersionForFilename = GetPowershellModuleVersion(powershelModuleOutputLocation);
|
||||
var moduleVersionForFilename = Helpers.GetPowershellModuleVersion(powershelModuleOutputLocation);
|
||||
CreateBundleZip(bundleRootLocation, moduleFolderLocation, moduleVersionForFilename, context);
|
||||
}
|
||||
|
||||
|
|
@ -132,38 +133,4 @@ public class CreateBundleArchiveTask : FrostingTask<BuildContext>
|
|||
ZipFile.CreateFromDirectory(moduleFolderLocation, bundleZipFileLocaiton, CompressionLevel.Fastest, true);
|
||||
context.Log.Information($"Archive created at '{bundleZipFileLocaiton}'");
|
||||
}
|
||||
|
||||
private static string GetPowershellModuleVersion(string powershelModuleOutputLocation)
|
||||
{
|
||||
var moduleVersionInfo = FileVersionInfo.GetVersionInfo(Path.Combine(powershelModuleOutputLocation, "PowershellModule.dll"));
|
||||
|
||||
// It's (almost) impossible to not have a product version tag here. There is a reason why the implementation
|
||||
// returns a string? but I can't find it and I don't really care too much. If we have null return an empty string
|
||||
// and append no version to the archive bundle.
|
||||
if (moduleVersionInfo.ProductVersion == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var versionRegex = new Regex(@"(\d+\.\d+\.\d+)(?:\-?([\w\-]+)\+?(\w+)?)?");
|
||||
var match = versionRegex.Match(moduleVersionInfo.ProductVersion);
|
||||
if (match.Success)
|
||||
{
|
||||
// If we have 4 groups, we've got a version number, suffix, and commit hash, so we return the first 2 as is
|
||||
// and the commit has capped to 8 characters
|
||||
if (match.Groups.Count == 4)
|
||||
{
|
||||
return $"{match.Groups[1]}-{match.Groups[2]}+{match.Groups[3].Value.Substring(0, 8)}";
|
||||
}
|
||||
|
||||
if (match.Groups.Count == 3)
|
||||
{
|
||||
return $"{match.Groups[1]}-{match.Groups[2]}";
|
||||
}
|
||||
|
||||
return $"{match.Groups[1]}";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using Cake.Core;
|
||||
using Cake.Core;
|
||||
using Cake.Core.Diagnostics;
|
||||
using Cake.Frosting;
|
||||
|
||||
|
|
@ -7,6 +7,7 @@ namespace Build.Tasks;
|
|||
// Consider this the "entry" point for builds, task order is defined by a chain of IsDependentOn
|
||||
[TaskName("Default")]
|
||||
[IsDependentOn(typeof(BuildTask))]
|
||||
[IsDependentOn(typeof(TagCommitTask))]
|
||||
[IsDependentOn(typeof(CopyOutputTask))]
|
||||
[IsDependentOn(typeof(CreateBundleArchiveTask))]
|
||||
public class DefaultTask : FrostingTask
|
||||
|
|
|
|||
54
build/Tasks/TagCommitTask.cs
Normal file
54
build/Tasks/TagCommitTask.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using Cake.Core.Diagnostics;
|
||||
using Cake.Frosting;
|
||||
|
||||
namespace Build.Tasks;
|
||||
|
||||
[TaskName("TagCurrentCommitWithVersion")]
|
||||
[IsDependentOn(typeof(BuildTask))]
|
||||
public class TagCommitTask : FrostingTask<BuildContext>
|
||||
{
|
||||
public override void Run(BuildContext context)
|
||||
{
|
||||
// This task only really exists to create pre-release builds for pull requests.
|
||||
// It'll tag the current commit with the same version that'll be used for the bundle archive filename.
|
||||
// TODO: update build.ps1 in the solution root so it doesn't do this tagging task
|
||||
TagCommit(context);
|
||||
base.Run(context);
|
||||
}
|
||||
|
||||
private static void TagCommit(BuildContext context)
|
||||
{
|
||||
var moduleVersionForFilename = Helpers.GetPowershellModuleVersion(context.PowershellModuleOutputDir.Path.MakeAbsolute(context.Environment).FullPath);
|
||||
|
||||
var ps = new ProcessStartInfo("git",
|
||||
["-C", context.BaseSourceLocation.FullPath, "tag", moduleVersionForFilename])
|
||||
{
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
};
|
||||
|
||||
// If the user doesn't have git on their path, this will throw an exception that I don't have to do anything
|
||||
// special with, it'll be unhandled and powershell will handle it
|
||||
var gitProcess = Process.Start(ps);
|
||||
|
||||
// This probably shouldn't be possible?
|
||||
if (gitProcess is null)
|
||||
{
|
||||
throw new Exception("git failed to start")
|
||||
{
|
||||
Source = "git-process",
|
||||
};
|
||||
}
|
||||
|
||||
gitProcess.WaitForExit();
|
||||
|
||||
if (!gitProcess.StandardError.EndOfStream)
|
||||
{
|
||||
throw new Exception($"Unable to tag: {gitProcess.StandardError.ReadToEnd().Trim()}. Either remove the existing tag, or commit your changes before running a build");
|
||||
}
|
||||
|
||||
context.Log.Information($"Tagged commit with {moduleVersionForFilename}");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Git Repo Registration
|
||||
# Git Repo Registration
|
||||
|
||||
- all commands support `-debug`
|
||||
- at its simplest level these commands allow you to register a git repo against a simple name, and provide the ability to quickly pushd to a location
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace ModuleCore.Calendar;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using SQLite;
|
||||
using SQLite;
|
||||
|
||||
namespace ModuleCore.Database;
|
||||
|
||||
|
|
@ -26,12 +26,22 @@ public class DatabaseManager
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the given action within a new database connection
|
||||
/// </summary>
|
||||
/// <param name="dbAction"></param>
|
||||
public void InConnection(Action<SQLiteConnection> dbAction)
|
||||
{
|
||||
using var conn = new SQLiteConnection(_databaseLocation.FullName);
|
||||
dbAction(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the given func in a new database connection, returning the result
|
||||
/// </summary>
|
||||
/// <param name="dbAction"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public T InConnection<T>(Func<SQLiteConnection, T> dbAction)
|
||||
{
|
||||
using var conn = new SQLiteConnection(_databaseLocation.FullName);
|
||||
|
|
@ -51,6 +61,18 @@ public class DatabaseManager
|
|||
return exists ?? false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the current database file. This will cause any future instance methods to fail on database action if
|
||||
/// a new instance is not created.
|
||||
/// <para>
|
||||
/// This method should be avoided unless calling from a test.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
internal void DeleteDatabase()
|
||||
{
|
||||
_databaseLocation.Delete();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes double dots from the filename and removes the file extension
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project>
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>0.0.1</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using ModuleCore.Database;
|
||||
using ModuleCore.Git.Models;
|
||||
|
|
@ -6,28 +6,44 @@ using SQLite;
|
|||
|
||||
namespace ModuleCore.Git;
|
||||
|
||||
// TODO: better name for this
|
||||
public class GitManager
|
||||
/// <summary>
|
||||
/// Manages git repo registration, including creating any registration persistence via a backing <see cref="DatabaseManager"/>
|
||||
/// </summary>
|
||||
public class GitRepoRegistrationManager
|
||||
{
|
||||
private static readonly Lazy<GitManager> GitManagerInstance = new(() => new GitManager());
|
||||
private static readonly Lazy<GitRepoRegistrationManager> GitManagerInstance = new(() => new GitRepoRegistrationManager());
|
||||
private static Action<string>? _debugWriterDelegate;
|
||||
private readonly DatabaseManager _db;
|
||||
private readonly ConcurrentDictionary<string, InternalGitRegistration> _registrations;
|
||||
|
||||
private GitManager()
|
||||
private GitRepoRegistrationManager(string? databaseName = null)
|
||||
{
|
||||
_registrations = new ConcurrentDictionary<string, InternalGitRegistration>();
|
||||
_db = new DatabaseManager("git.db");
|
||||
// Regular usage of this constructor will never pass a database name in. Currently only tests should be hitting
|
||||
// a code path that has a different database name
|
||||
_db = new DatabaseManager(databaseName ?? "git.db");
|
||||
|
||||
InitialiseRegistrations();
|
||||
}
|
||||
|
||||
public static GitManager Instance => GitManagerInstance.Value;
|
||||
/// <summary>
|
||||
/// Returns the current <see cref="GitRepoRegistrationManager"/> instance. If no instance has been created, returns a new instance
|
||||
/// and then the same instance every call after.
|
||||
/// </summary>
|
||||
public static GitRepoRegistrationManager Instance => GitManagerInstance.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Always returns a new clean instance of GitManager
|
||||
/// </summary>
|
||||
internal static GitManager InternalFreshInstance => new();
|
||||
internal static GitRepoRegistrationManager InternalFreshInstance(string databaseName) => new(databaseName);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the underlying database file.
|
||||
/// <para>
|
||||
/// Avoid calling this outside of tests.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
internal void DeleteDatabase() => _db.DeleteDatabase();
|
||||
|
||||
/// <summary>
|
||||
/// Creates up any database tables and loads all previously saved git registrations.
|
||||
|
|
@ -118,6 +134,11 @@ public class GitManager
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters a git repo registration by name. If no registration exists an exception will be thrown.
|
||||
/// </summary>
|
||||
/// <param name="registrationName"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void UnregisterRepo(string registrationName)
|
||||
{
|
||||
_db.InConnection(conn =>
|
||||
|
|
@ -185,7 +206,13 @@ public class GitManager
|
|||
.ToList();
|
||||
}
|
||||
|
||||
public string GetRepo(string? registeredName)
|
||||
/// <summary>
|
||||
/// Returns the file location for a git repo registration by name.
|
||||
/// </summary>
|
||||
/// <param name="registeredName"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public string GetDirectoryForRegisteredRepo(string? registeredName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(registeredName))
|
||||
{
|
||||
|
|
@ -312,7 +339,7 @@ public class GitManager
|
|||
/// </summary>
|
||||
public string CurrentBranch => GetCurrentBranch();
|
||||
|
||||
// TODO: not fully decided on if I want this feature or not, but keeping it in for now
|
||||
// TODO: [#13] Create GitManager to centralise calls to git process
|
||||
private string GetCurrentBranch()
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
|
@ -364,19 +391,3 @@ public class GitManager
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The directory details of the directory returned from git rev-parse --show-toplevel
|
||||
/// </summary>
|
||||
public class ParsedGitFolderDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// The full path to the top level folder containing a git repository
|
||||
/// </summary>
|
||||
public string Directory { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The last folder name of the directory
|
||||
/// </summary>
|
||||
public string Folder { get; init; } = null!;
|
||||
}
|
||||
|
|
@ -1,8 +1,21 @@
|
|||
namespace ModuleCore.Git.Models;
|
||||
namespace ModuleCore.Git.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Details for a registered git repo
|
||||
/// </summary>
|
||||
public class GitRegistration
|
||||
{
|
||||
/// <summary>
|
||||
/// Display name for the registration. Can either be the name of the repo retrieved from git, or a user supplied
|
||||
/// alias
|
||||
/// </summary>
|
||||
public required string Name { get; set; }
|
||||
/// <summary>
|
||||
/// Location on disk for the top level of the registered git repo. Not guaranteed to exist on disk
|
||||
/// </summary>
|
||||
public required string Location { get; set; }
|
||||
/// <summary>
|
||||
/// Current branch for the git repo
|
||||
/// </summary>
|
||||
public required string CurrentBranch { get; set; }
|
||||
}
|
||||
17
src/ModuleCore/Git/Models/ParsedGitFolderDetails.cs
Normal file
17
src/ModuleCore/Git/Models/ParsedGitFolderDetails.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
namespace ModuleCore.Git.Models;
|
||||
|
||||
/// <summary>
|
||||
/// The directory details of the directory returned from git rev-parse --show-toplevel
|
||||
/// </summary>
|
||||
public class ParsedGitFolderDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// The full path to the top level folder containing a git repository
|
||||
/// </summary>
|
||||
public string Directory { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The last folder name of the directory
|
||||
/// </summary>
|
||||
public string Folder { get; init; } = null!;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Management.Automation;
|
||||
using ModuleCore.Calendar;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project>
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>0.0.1</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Management.Automation;
|
||||
using System.Management.Automation;
|
||||
using ModuleCore.Git;
|
||||
using ModuleCore.Git.Models;
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ public class GetGitRepoRegistrationCommand : PSCmdlet
|
|||
{
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
var repos = GitManager.Instance.ListRepos();
|
||||
var repos = GitRepoRegistrationManager.Instance.ListRepos();
|
||||
|
||||
WriteObject(repos);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace PowershellModule.Git.Commands;
|
||||
namespace PowershellModule.Git.Commands;
|
||||
|
||||
public class GitCommands
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using ModuleCore.Git;
|
||||
|
||||
|
|
@ -17,19 +17,19 @@ public sealed class NewGitRepoRegistrationCommand : PSCmdlet
|
|||
{
|
||||
try
|
||||
{
|
||||
GitManager.SetDebugWriter(WriteDebug);
|
||||
GitRepoRegistrationManager.SetDebugWriter(WriteDebug);
|
||||
|
||||
// Test that we're in a git repo first. If we aren't (or git isn't available), this method will throw
|
||||
// so we don't need to handle for null (yet).
|
||||
var repoFolder = GitManager.IsGitRepo(SessionState.Path.CurrentLocation.Path);
|
||||
var repoFolder = GitRepoRegistrationManager.IsGitRepo(SessionState.Path.CurrentLocation.Path);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Name))
|
||||
{
|
||||
WriteDebug("No name given for registration, defaulting to git folder root.");
|
||||
}
|
||||
|
||||
GitManager.Instance.RegisterRepo(repoFolder.Directory, Name ?? repoFolder.Folder);
|
||||
GitManager.ClearDebugWriter();
|
||||
GitRepoRegistrationManager.Instance.RegisterRepo(repoFolder.Directory, Name ?? repoFolder.Folder);
|
||||
GitRepoRegistrationManager.ClearDebugWriter();
|
||||
|
||||
base.BeginProcessing();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using ModuleCore.Git;
|
||||
|
||||
|
|
@ -17,21 +17,21 @@ public class RemoveGitRepoRegistrationCommand : PSCmdlet
|
|||
{
|
||||
try
|
||||
{
|
||||
GitManager.SetDebugWriter(WriteDebug);
|
||||
GitRepoRegistrationManager.SetDebugWriter(WriteDebug);
|
||||
|
||||
// If we aren't given a value for the Name argument, default behaviour is to attempt to remove a registration
|
||||
// by the current git repo folder name for the current location.
|
||||
// If we have a name, don't bother testing for a git repo, just attempt to remove the registration by name
|
||||
// regardless of where we're being called from
|
||||
var registrationNameToRemove = string.IsNullOrEmpty(Name)
|
||||
? GitManager.IsGitRepo(SessionState.Path.CurrentLocation.Path).Folder
|
||||
? GitRepoRegistrationManager.IsGitRepo(SessionState.Path.CurrentLocation.Path).Folder
|
||||
: Name;
|
||||
|
||||
GitManager.Instance.UnregisterRepo(registrationNameToRemove);
|
||||
GitRepoRegistrationManager.Instance.UnregisterRepo(registrationNameToRemove);
|
||||
|
||||
// Removing a registration works similar to registering a new one - we either remove by exact name, or by
|
||||
// the folder if no name is given (so a user can remove a registration from a git repo they're currently in)
|
||||
GitManager.ClearDebugWriter();
|
||||
GitRepoRegistrationManager.ClearDebugWriter();
|
||||
|
||||
base.BeginProcessing();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Management.Automation;
|
||||
using System.Management.Automation;
|
||||
using ModuleCore.Git;
|
||||
|
||||
namespace PowershellModule.Git.Commands;
|
||||
|
|
@ -21,7 +21,7 @@ public class ShowGitRepoRegistrationCommand : PSCmdlet
|
|||
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
var location = GitManager.Instance.GetRepo(Name);
|
||||
var location = GitRepoRegistrationManager.Instance.GetDirectoryForRegisteredRepo(Name);
|
||||
|
||||
// By default instead of doing the same as cd, we instead do pushd so a user can popd straight back to where
|
||||
// they came from.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Provider;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Management.Automation;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace PowershellModule.Git;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<#
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Removes all non-core files from build output
|
||||
#>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using ModuleCore.Calendar;
|
||||
using ModuleCore.Calendar;
|
||||
using ModuleTests.Calendar.TestData;
|
||||
using System.Globalization;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Text;
|
||||
using System.Text;
|
||||
using ModuleCore.Calendar;
|
||||
|
||||
namespace ModuleTests.Calendar;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
┌─────────────────────────────────────────┐
|
||||
┌─────────────────────────────────────────┐
|
||||
│ June 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
│ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ Sun │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌─────────────────────────────────────────┐
|
||||
┌─────────────────────────────────────────┐
|
||||
│ July 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
│ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ Sun │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌─────────────────────────────────────────┐
|
||||
┌─────────────────────────────────────────┐
|
||||
│ August 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
│ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ Sun │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌──────────────────────────────────┐
|
||||
┌──────────────────────────────────┐
|
||||
│ srpen 2026 │
|
||||
├────┬────┬────┬────┬────┬────┬────┤
|
||||
│ po │ út │ st │ čt │ pá │ so │ ne │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌─────────────────────────────────────────┐
|
||||
┌─────────────────────────────────────────┐
|
||||
│ august 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
│ man │ tir │ ons │ tor │ fre │ lør │ søn │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌─────────────────────────────────────────┐
|
||||
┌─────────────────────────────────────────┐
|
||||
│ August 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
│ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ Sun │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌────────────────────────────────────────────────┐
|
||||
┌────────────────────────────────────────────────┐
|
||||
│ agosto 2026 │
|
||||
├──────┬──────┬──────┬──────┬──────┬──────┬──────┤
|
||||
│ lun. │ mar. │ mié. │ jue. │ vie. │ sáb. │ dom. │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌────────────────────────────────────────────────┐
|
||||
┌────────────────────────────────────────────────┐
|
||||
│ août 2026 │
|
||||
├──────┬──────┬──────┬──────┬──────┬──────┬──────┤
|
||||
│ lun. │ mar. │ mer. │ jeu. │ ven. │ sam. │ dim. │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌──────────────────────────────────┐
|
||||
┌──────────────────────────────────┐
|
||||
│ augustus 2026 │
|
||||
├────┬────┬────┬────┬────┬────┬────┤
|
||||
│ ma │ di │ wo │ do │ vr │ za │ zo │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌───────────────────────────────────────────────────────┐
|
||||
┌───────────────────────────────────────────────────────┐
|
||||
│ ఆగస్టు 2026 │
|
||||
├───────┬───────┬───────┬───────┬───────┬───────┬───────┤
|
||||
│ సోమ │ మంగళ │ బుధ │ గురు │ శుక్ర │ శని │ ఆది │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌─────────────────────────────────────────┐
|
||||
┌─────────────────────────────────────────┐
|
||||
│ August 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
│ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ Sun │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
Double-wide characters will display incorrectly but still tested until rendering can be improved
|
||||
Double-wide characters will display incorrectly but still tested until rendering can be improved
|
||||
┌─────────────────────────────────────────┐
|
||||
│ August 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
Emojis will display incorrectly in text but output correctly in terminals with UTF-8 encoding.
|
||||
Emojis will display incorrectly in text but output correctly in terminals with UTF-8 encoding.
|
||||
┌─────────────────────────────────────────┐
|
||||
│ August 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌──────────────────────────────────────────────────────────────┐
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ August 2026 │
|
||||
├────────┬────────┬────────┬────────┬────────┬────────┬────────┤
|
||||
│ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ Sun │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
┌─────────────────────────────────────────┐
|
||||
┌─────────────────────────────────────────┐
|
||||
│ August 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
│ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ Sun │
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
Start Day: Sunday
|
||||
Start Day: Sunday
|
||||
┌─────────────────────────────────────────┐
|
||||
│ August 2026 │
|
||||
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Text;
|
||||
using System.Text;
|
||||
using ModuleCore.Calendar;
|
||||
|
||||
namespace ModuleTests.Calendar;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace ModuleTests.Calendar.TestData;
|
||||
namespace ModuleTests.Calendar.TestData;
|
||||
|
||||
public class CalendarTestDates : TestDataEnumerator<DateTime>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace ModuleTests.Calendar.TestData;
|
||||
namespace ModuleTests.Calendar.TestData;
|
||||
|
||||
public class CultureCodeTestData : TestDataEnumerator<string>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System.Text;
|
||||
using ModuleCore.Calendar;
|
||||
using System.Text;
|
||||
using ModuleCore.Git;
|
||||
using ModuleTests.Git.TestData;
|
||||
|
||||
namespace ModuleTests.Git;
|
||||
|
||||
// TODO: [#12] GitRepoRegistration tests should reset database at start of each test
|
||||
public class AddRegistrationTests
|
||||
{
|
||||
private static readonly VerifySettings Settings;
|
||||
|
|
@ -23,9 +23,10 @@ public class AddRegistrationTests
|
|||
public Task BasicRepoRegistration((int testId, string path) testData)
|
||||
{
|
||||
Settings.UseFileName($"{nameof(BasicRepoRegistration)}_{testData.testId}");
|
||||
var gitManager = GitRepoRegistrationManager.InternalFreshInstance(nameof(BasicRepoRegistration));
|
||||
|
||||
var gitManager = GitManager.InternalFreshInstance;
|
||||
|
||||
try
|
||||
{
|
||||
var repoRegistration = gitManager.RegisterRepo("Test:/some/test/repo", testData.path);
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"Attempted to register: {testData.path}")
|
||||
|
|
@ -33,60 +34,82 @@ public class AddRegistrationTests
|
|||
|
||||
return Verify(sb, Settings);
|
||||
}
|
||||
finally
|
||||
{
|
||||
gitManager.DeleteDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RepoRegistrationWithEmptyName()
|
||||
{
|
||||
Settings.UseFileName(nameof(RepoRegistrationWithEmptyName));
|
||||
|
||||
var gitManager = GitManager.InternalFreshInstance;
|
||||
var gitManager = GitRepoRegistrationManager.InternalFreshInstance(nameof(RepoRegistrationWithEmptyName));
|
||||
var testRepoAbsolutePath = "Test:/some/test/repo";
|
||||
|
||||
try
|
||||
{
|
||||
var emptyName = gitManager.RegisterRepo(testRepoAbsolutePath, "");
|
||||
|
||||
Assert.Equal("repo", emptyName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
gitManager.DeleteDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RepoRegistrationWithNullName()
|
||||
{
|
||||
Settings.UseFileName(nameof(RepoRegistrationWithNullName));
|
||||
|
||||
var gitManager = GitManager.InternalFreshInstance;
|
||||
var gitManager = GitRepoRegistrationManager.InternalFreshInstance(nameof(RepoRegistrationWithNullName));
|
||||
var testRepoAbsolutePath = "Test:/some/test/repo";
|
||||
|
||||
try
|
||||
{
|
||||
// Name is technically not-nullable, but string is a reference type so null can be passed in so we should test
|
||||
// it regardless
|
||||
var nullName = gitManager.RegisterRepo(testRepoAbsolutePath, null!);
|
||||
|
||||
Assert.Equal("repo", nullName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
gitManager.DeleteDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RepoRegistrationWithWhitespaceName()
|
||||
{
|
||||
Settings.UseFileName(nameof(RepoRegistrationWithWhitespaceName));
|
||||
|
||||
var gitManager = GitManager.InternalFreshInstance;
|
||||
var gitManager = GitRepoRegistrationManager.InternalFreshInstance(nameof(RepoRegistrationWithWhitespaceName));
|
||||
var testRepoAbsolutePath = "Test:/some/test/repo";
|
||||
|
||||
try
|
||||
{
|
||||
var whitespaceName = gitManager.RegisterRepo(testRepoAbsolutePath, " ");
|
||||
|
||||
Assert.Equal("repo", whitespaceName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
gitManager.DeleteDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DuplicateRepoRegistrationShouldFail()
|
||||
{
|
||||
Settings.UseFileName(nameof(RepoRegistrationWithWhitespaceName));
|
||||
|
||||
var gitManager = GitManager.InternalFreshInstance;
|
||||
var gitManager = GitRepoRegistrationManager.InternalFreshInstance(nameof(RepoRegistrationWithWhitespaceName));
|
||||
var testRepoAbsolutePath = "Test:/some/test/repo";
|
||||
string[] paths = ["test", "nested", "path"];
|
||||
var names = (NormalSeparator: string.Join(Path.DirectorySeparatorChar, paths), AltSeparator: string.Join(Path.AltDirectorySeparatorChar, paths));
|
||||
|
||||
try
|
||||
{
|
||||
var firstRegistration = gitManager.RegisterRepo(testRepoAbsolutePath, names.NormalSeparator);
|
||||
// TODO: make nested registrations fail in both directions and test
|
||||
var secondRegistration = gitManager.RegisterRepo(testRepoAbsolutePath, Path.Combine(paths[..1]));
|
||||
|
||||
Assert.Equal(Path.Combine(paths), firstRegistration);
|
||||
|
|
@ -94,19 +117,24 @@ public class AddRegistrationTests
|
|||
|
||||
Assert.Throws<Exception>(() => gitManager.RegisterRepo(testRepoAbsolutePath, Path.Combine(paths[..1])));
|
||||
}
|
||||
finally
|
||||
{
|
||||
gitManager.DeleteDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DuplicateRepoRegistrationDifferentSlashShouldNotFail()
|
||||
{
|
||||
Settings.UseFileName(nameof(RepoRegistrationWithWhitespaceName));
|
||||
|
||||
var gitManager = GitManager.InternalFreshInstance;
|
||||
var gitManager = GitRepoRegistrationManager.InternalFreshInstance(nameof(RepoRegistrationWithWhitespaceName));
|
||||
var testRepoAbsolutePath = "Test:/some/test/repo";
|
||||
string[] paths = ["test", "nested", "path"];
|
||||
var names = (NormalSeparator: string.Join(Path.DirectorySeparatorChar, paths), AltSeparator: string.Join(Path.AltDirectorySeparatorChar, paths));
|
||||
|
||||
try
|
||||
{
|
||||
var firstRegistration = gitManager.RegisterRepo(testRepoAbsolutePath, names.NormalSeparator);
|
||||
// TODO: make nested registrations fail in both directions and test
|
||||
var secondRegistration = gitManager.RegisterRepo(testRepoAbsolutePath, Path.Combine(paths[..1]));
|
||||
var differentPathSeparatorRegistration = gitManager.RegisterRepo(testRepoAbsolutePath, names.AltSeparator);
|
||||
|
||||
|
|
@ -114,4 +142,9 @@ public class AddRegistrationTests
|
|||
Assert.Equal(Path.Combine(paths[..1]), secondRegistration);
|
||||
Assert.Equal(names.AltSeparator, differentPathSeparatorRegistration);
|
||||
}
|
||||
finally
|
||||
{
|
||||
gitManager.DeleteDatabase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Linq;
|
||||
using System.Linq;
|
||||
|
||||
namespace ModuleTests.Git.TestData;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace ModuleTests;
|
||||
namespace ModuleTests;
|
||||
|
||||
public class TestConstants
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections;
|
||||
using System.Collections;
|
||||
|
||||
namespace ModuleTests;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue