From 1a8bdec5897673067377a747431e90f4d94f72d8 Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 4 Sep 2026 17:40:51 +1000 Subject: [PATCH] feat(build): Create helpers and TagCommit step - adjust the BaseSourceLocation to be absolute - refactor getting the PowershellModule version to Helpers.cs --- build/BuildContext.cs | 5 ++- build/Helpers.cs | 42 ++++++++++++++++++++ build/Tasks/CreateBundleArchiveTask.cs | 39 ++----------------- build/Tasks/DefaultTask.cs | 1 + build/Tasks/TagCommitTask.cs | 54 ++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 38 deletions(-) create mode 100644 build/Helpers.cs create mode 100644 build/Tasks/TagCommitTask.cs diff --git a/build/BuildContext.cs b/build/BuildContext.cs index 29634e9..a2265a4 100644 --- a/build/BuildContext.cs +++ b/build/BuildContext.cs @@ -1,6 +1,7 @@ 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 /// /// Base source directory /// - public ConvertableDirectoryPath BaseSourceLocation { get; set; } + public DirectoryPath BaseSourceLocation { get; set; } /// /// Powershell module project folder @@ -38,7 +39,7 @@ public class BuildContext : FrostingContext 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"); diff --git a/build/Helpers.cs b/build/Helpers.cs new file mode 100644 index 0000000..564c3e7 --- /dev/null +++ b/build/Helpers.cs @@ -0,0 +1,42 @@ +using System.Diagnostics; +using System.IO; +using System.Text.RegularExpressions; + +namespace Build; + +public class Helpers +{ + public 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; + } +} \ No newline at end of file diff --git a/build/Tasks/CreateBundleArchiveTask.cs b/build/Tasks/CreateBundleArchiveTask.cs index 0abd876..8cf82ec 100644 --- a/build/Tasks/CreateBundleArchiveTask.cs +++ b/build/Tasks/CreateBundleArchiveTask.cs @@ -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 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 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; - } } \ No newline at end of file diff --git a/build/Tasks/DefaultTask.cs b/build/Tasks/DefaultTask.cs index 7f4bf67..5b4fcef 100644 --- a/build/Tasks/DefaultTask.cs +++ b/build/Tasks/DefaultTask.cs @@ -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 diff --git a/build/Tasks/TagCommitTask.cs b/build/Tasks/TagCommitTask.cs new file mode 100644 index 0000000..324a6fc --- /dev/null +++ b/build/Tasks/TagCommitTask.cs @@ -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 +{ + 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}"); + } +} \ No newline at end of file