diff --git a/build/BuildContext.cs b/build/BuildContext.cs
new file mode 100644
index 0000000..29634e9
--- /dev/null
+++ b/build/BuildContext.cs
@@ -0,0 +1,50 @@
+using Cake.Common.IO;
+using Cake.Common.IO.Paths;
+using Cake.Core;
+using Cake.Frosting;
+
+namespace Build;
+
+public class BuildContext : FrostingContext
+{
+ ///
+ /// Base source directory
+ ///
+ public ConvertableDirectoryPath BaseSourceLocation { get; set; }
+
+ ///
+ /// Powershell module project folder
+ ///
+ public ConvertableDirectoryPath PowershellModuleProjectDirectory { get; set; }
+
+ ///
+ /// Powershell module csproj location
+ ///
+ public ConvertableFilePath PowershellModuleCsproj { get; set; }
+
+ ///
+ /// Output directory for built DLLs and powershell module manifest files
+ ///
+ public ConvertableDirectoryPath PowershellModuleOutputDir { get; set; }
+
+ ///
+ /// Path to powershell script that creates the module manifest files
+ ///
+ public ConvertableFilePath CreateModuleManifestScript { get; set; }
+
+ public string BuildSuffix { get; set; }
+ public bool DisableCommitHash { get; set; }
+
+ public BuildContext(ICakeContext context)
+ : base(context)
+ {
+ BaseSourceLocation = context.Directory("../src");
+ 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));
+ DisableCommitHash = context.Configuration.GetBoolValue(nameof(DisableCommitHash));
+ }
+}
\ No newline at end of file
diff --git a/build/Program.cs b/build/Program.cs
index ffb3738..1c348c5 100644
--- a/build/Program.cs
+++ b/build/Program.cs
@@ -1,9 +1,6 @@
-using Cake.Common;
-using Cake.Common.IO;
-using Cake.Common.IO.Paths;
-using Cake.Core;
using Cake.Frosting;
-using Cake.Powershell;
+
+namespace Build;
public static class Program
{
@@ -11,45 +8,8 @@ public static class Program
{
return new CakeHost()
.UseContext()
+ // Uncomment this if you don't want to set the suffix via the run profile program arguments
+ //.UseCakeSetting(nameof(BuildContext.BuildSuffix), "")
.Run(args);
}
-}
-
-public class BuildContext : FrostingContext
-{
- ///
- /// Base source directory
- ///
- public ConvertableDirectoryPath BaseSourceLocation { get; set; }
-
- ///
- /// Powershell module project folder
- ///
- public ConvertableDirectoryPath PowershellModuleProjectDirectory { get; set; }
-
- ///
- /// Powershell module csproj location
- ///
- public ConvertableFilePath PowershellModuleCsproj { get; set; }
-
- ///
- /// Output directory for built DLLs and powershell module manifest files
- ///
- public ConvertableDirectoryPath PowershellModuleOutputDir { get; set; }
-
- ///
- /// Path to powershell script that creates the module manifest files
- ///
- public ConvertableFilePath CreateModuleManifestScript { get; set; }
-
- public BuildContext(ICakeContext context)
- : base(context)
- {
- BaseSourceLocation = context.Directory("../src");
- 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");
- }
}
\ No newline at end of file
diff --git a/build/Tasks/BuildTask.cs b/build/Tasks/BuildTask.cs
index c731bcb..d11cc79 100644
--- a/build/Tasks/BuildTask.cs
+++ b/build/Tasks/BuildTask.cs
@@ -17,14 +17,27 @@ public class BuildTask : FrostingTask
var buildSettings = new DotNetBuildSettings()
{
- MSBuildSettings = new DotNetMSBuildSettings()
- {
- VersionSuffix = "cake"
- },
+ MSBuildSettings = new DotNetMSBuildSettings(),
OutputDirectory = context.PowershellModuleOutputDir,
- DiagnosticOutput = true
+ DiagnosticOutput = true,
};
+ // If a build suffix is provided, use it, otherwise whatever comes from Directory.Build.props will be used.
+ // It's not possible to set the actual version number for a build in this project as that is purely controlled
+ // from individual Directory.Build.props files
+ if (!string.IsNullOrEmpty(context.BuildSuffix))
+ {
+ buildSettings.MSBuildSettings.VersionSuffix = context.BuildSuffix;
+ }
+
+ // Disable SourceLink automatic commit hash addition. Documentation about how that package work is garbage and
+ // this property is only mentioned in breaking changes https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/8.0/source-link
+ // which is pretty on par for shit like this.
+ if (context.DisableCommitHash)
+ {
+ buildSettings.MSBuildSettings.Properties.Add("IncludeSourceRevisionInInformationalVersion", ["false"]);
+ }
+
// /p:DebugSymbols=false
buildSettings.MSBuildSettings.Properties.Add("DebugSymbols", ["false"]);
// /p:DebugType=None
diff --git a/build/Tasks/CopyOutputTask.cs b/build/Tasks/CopyOutputTask.cs
index 2d531b0..f51763a 100644
--- a/build/Tasks/CopyOutputTask.cs
+++ b/build/Tasks/CopyOutputTask.cs
@@ -1,16 +1,15 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using Cake.Core.Diagnostics;
using Cake.Core.IO;
using Cake.Frosting;
using Cake.Powershell;
-using Path = System.IO.Path;
namespace Build.Tasks;
[TaskName("CopyOutput")]
+[IsDependeeOf(typeof(CreateBundleArchiveTask))]
public class CopyOutputTask : FrostingTask
{
public override void Run(BuildContext context)
@@ -47,9 +46,7 @@ public class CopyOutputTask : FrostingTask
psSettings.Arguments.Append("outputDir", ToPowershellSafeString(scriptParams.OutputLocation));
context.StartPowershellFile(context.CreateModuleManifestScript, psSettings);
- context.Log.Information($"Module output to: {context.PowershellModuleOutputDir.Path.MakeAbsolute(context.Environment)}");
-
- BundleMinimalFiles(context);
+ context.Log.Information($"Module files output to: {context.PowershellModuleOutputDir.Path.MakeAbsolute(context.Environment)}");
base.Run(context);
}
@@ -70,103 +67,4 @@ public class CopyOutputTask : FrostingTask
var commandName = "GitRepoRegistration";
return [.. verbs.Select(x => $"{x}-{commandName}")];
}
-
- private static void BundleMinimalFiles(BuildContext context)
- {
- // We're effectively replicating PostBuild.ps1 with all of this as Remove-Item at the end of it does not remove files the same way.
- // TODO: See if that's something I can fix
- var powershellModuleBuildLocation = context.PowershellModuleOutputDir.Path.MakeAbsolute(context.Environment).FullPath;
- // PowershellModule is here so that the script that adds to the users $Env:PSModulePath correctly resolves when using
- // Import-Module "PowershellModule"
- // TODO: Generate the script to add to the PSModulePath in the bundleOutputLocation directory
- var bundleOutputLocation = Directory.CreateDirectory(Path.Combine(powershellModuleBuildLocation, "bundle")).FullName;
- var moduleOutputLocation = Directory.CreateDirectory(Path.Combine(bundleOutputLocation, "PowershellModule")).FullName;
-
- context.Log.Information($"Bundle location: {bundleOutputLocation}");
- context.Log.Information($"Built file location: {powershellModuleBuildLocation}");
-
- // PostBuild.ps1 for PowershellModule should have already been run at this point - it won't remove files, but it will copy the
- // correct e_sqlite3.dll that we need.
- // TODO: Investigate this later as I'm not entirely happy with this now
- // // Get the location for the specific version of e_sqlite3.dll we need - PowerShell binary modules resolve dependent dlls
- // // from the executing assembly directory first, and the built output of the module includes a lot of other dlls that
- // // are already available with the dotnet runtime so there's no need for us to include them.
- // // I mean, we could, but we'd also be terrible software engineers if we couldn't do something as basic as reducing files we need.
- // // TODO: Account for other runtimes such as linux based ones where the dotnet runtime might _not_ provide these files for free.
- // // It'd require looking into how the module loads for PowerShell on those operating systems, and I might never
- // // get around to doing that because I use windows (currently).
- // // TODO: Update this later to handle other runtimes, for now we hardcode to win-x64 because it's what I use
- // var nativeSqliteDllLocation = System.IO.Path.Combine(powershellModuleBuildLocation, "runtimes", "win-x64", "native", "e_sqlite3.dll");
- //
- // if (!File.Exists(nativeSqliteDllLocation))
- // {
- // context.Log.Error($"BUNDLE FAILED: Unable to locate ${nativeSqliteDllLocation}");
- // return;
- // }
- //
- // context.Log.Information($"Copying '${nativeSqliteDllLocation}' to '${bundleOutputLocation}'");
- //
- // File.Copy(nativeSqliteDllLocation, System.IO.Path.Combine(bundleOutputLocation, System.IO.Path.GetFileName(nativeSqliteDllLocation)));
-
- var moduleCoreFiles = Directory.GetFiles(powershellModuleBuildLocation, "ModuleCore*", searchOption: SearchOption.TopDirectoryOnly);
- var powershellModuleFiles = Directory.GetFiles(powershellModuleBuildLocation, "PowershellModule*", searchOption: SearchOption.TopDirectoryOnly);
- var sqliteFiles = Directory.GetFiles(powershellModuleBuildLocation, "*SQLite*", searchOption: SearchOption.TopDirectoryOnly);
-
- string[] allFiles = [.. moduleCoreFiles, .. powershellModuleFiles, .. sqliteFiles];
-
- context.Log.Information($"Copying {allFiles.Length} files to the module folder {moduleOutputLocation}");
- foreach (var file in allFiles)
- {
- context.Log.Information($"Copying {Path.GetFileName(file)}");
- File.Copy(file, Path.Combine(moduleOutputLocation, Path.GetFileName(file)));
- }
-
- context.Log.Information($"Bundle files copied");
-
- GenerateModuleImportScript(bundleOutputLocation, context);
- // TODO: zip the bundle directory contents to NulahModule.zip, and have a top level folder inside that called NulahModule.
- // The intent is that users will drop this zip next to their $profile, and then extract the contents directly so everything
- // is contained as it should be
- }
-
- private static void GenerateModuleImportScript(string bundleLocation, BuildContext context)
- {
- context.Log.Information($"Generating module import script");
-
- using var scriptFile = File.Create(Path.Combine(bundleLocation, "NulahPowershell.ps1"));
- using var fileWriter = new StreamWriter(scriptFile);
- // TODO: Document the set up function
- // TODO: Create a ticket for fleshing out the set up function (or just do that work later)
- fileWriter.Write(
- """
- # To use, first copy all files to the same location as your $profile under ./NulahModule, then open your powershell profile located at $profile and add the following:
-
- # Script setup style: Using the setup script to import as needed (this method will also set custom prompts and other alias functions)
- # . "$PSScriptRoot/NulahModule/NulahPowershell.ps1"
- # SetupNulahPowershell
- # Just the module: Use the following to just import just the powershell module
- # Import-Module -Name "$PSScriptRoot/NulahModule/PowershellModule"
-
- function SetupNulahPowershell
- {
- # only add to our module path once
- # The intent for this is that a user will have copied this bundle folder alongside their $profile
- # location, eg, they'll have a folder called NulahModule that will contain everything within the bundle zip
- $testBundleDirectory = $PSScriptRoot
- $bundleInPath = ($Env:PSModulePath -split ';').TrimEnd('\') -contains $testBundleDirectory;
-
- if ($false -eq $bundleInPath)
- {
- $env:PSModulePath = @(
- $env:PSModulePath
- $testBundleDirectory
- ) -Join [System.IO.Path]::PathSeparator
- }
-
- Import-Module "PowershellModule"
- }
- """
- );
- context.Log.Information($"Module import script created");
- }
}
\ No newline at end of file
diff --git a/build/Tasks/CreateBundleArchiveTask.cs b/build/Tasks/CreateBundleArchiveTask.cs
new file mode 100644
index 0000000..54413b1
--- /dev/null
+++ b/build/Tasks/CreateBundleArchiveTask.cs
@@ -0,0 +1,130 @@
+using System.IO;
+using System.IO.Compression;
+using Cake.Core.Diagnostics;
+using Cake.Frosting;
+
+namespace Build.Tasks;
+
+[TaskName("CreateBundleArchive")]
+[IsDependentOn(typeof(CopyOutputTask))]
+public class CreateBundleArchiveTask : FrostingTask
+{
+ public override void Run(BuildContext context)
+ {
+ context.Log.Information($"Creating bundle archive");
+ BundleMinimalFiles(context);
+ base.Run(context);
+ }
+
+ private static void BundleMinimalFiles(BuildContext context)
+ {
+ // We're effectively replicating PostBuild.ps1 with all of this as Remove-Item at the end of it does not remove files the same way.
+ // TODO: See if that's something I can fix
+ var powershellModuleBuildLocation = context.PowershellModuleOutputDir.Path.MakeAbsolute(context.Environment).FullPath;
+ // PowershellModule is here so that the script that adds to the users $Env:PSModulePath correctly resolves when using
+ // Import-Module "PowershellModule"
+ // TODO: Generate the script to add to the PSModulePath in the bundleOutputLocation directory
+
+ // Top level bundle output location
+ var bundleRootLocation = Directory.CreateDirectory(Path.Combine(powershellModuleBuildLocation, "bundle")).FullName;
+ // Module folder location that will be zipped up and will contain any setup scripts/readme etc
+ var moduleFolderLocation = Directory.CreateDirectory(Path.Combine(bundleRootLocation, "NulahModule")).FullName;
+ // Location to put all the module dlls and other files
+ var powershelModuleOutputLocation = Directory.CreateDirectory(Path.Combine(moduleFolderLocation, "PowershellModule")).FullName;
+
+ context.Log.Information($"Bundle location: {bundleRootLocation}");
+ context.Log.Information($"Built file location: {powershellModuleBuildLocation}");
+
+ // PostBuild.ps1 for PowershellModule should have already been run at this point - it won't remove files, but it will copy the
+ // correct e_sqlite3.dll that we need.
+ // This code is all commented out because I'm not entirely satisfied with PostBuild.ps1 doing some things but
+ // this build doing slightly different.
+ // // Get the location for the specific version of e_sqlite3.dll we need - PowerShell binary modules resolve dependent dlls
+ // // from the executing assembly directory first, and the built output of the module includes a lot of other dlls that
+ // // are already available with the dotnet runtime so there's no need for us to include them.
+ // // I mean, we could, but we'd also be terrible software engineers if we couldn't do something as basic as reducing files we need.
+ // // TODO: Account for other runtimes such as linux based ones where the dotnet runtime might _not_ provide these files for free.
+ // // It'd require looking into how the module loads for PowerShell on those operating systems, and I might never
+ // // get around to doing that because I use windows (currently).
+ // // TODO: Update this later to handle other runtimes, for now we hardcode to win-x64 because it's what I use
+ // var nativeSqliteDllLocation = System.IO.Path.Combine(powershellModuleBuildLocation, "runtimes", "win-x64", "native", "e_sqlite3.dll");
+ //
+ // if (!File.Exists(nativeSqliteDllLocation))
+ // {
+ // context.Log.Error($"BUNDLE FAILED: Unable to locate ${nativeSqliteDllLocation}");
+ // return;
+ // }
+ //
+ // context.Log.Information($"Copying '${nativeSqliteDllLocation}' to '${bundleOutputLocation}'");
+ //
+ // File.Copy(nativeSqliteDllLocation, System.IO.Path.Combine(bundleOutputLocation, System.IO.Path.GetFileName(nativeSqliteDllLocation)));
+
+ var moduleCoreFiles = Directory.GetFiles(powershellModuleBuildLocation, "ModuleCore*", searchOption: SearchOption.TopDirectoryOnly);
+ var powershellModuleFiles = Directory.GetFiles(powershellModuleBuildLocation, "PowershellModule*", searchOption: SearchOption.TopDirectoryOnly);
+ var sqliteFiles = Directory.GetFiles(powershellModuleBuildLocation, "*SQLite*", searchOption: SearchOption.TopDirectoryOnly);
+
+ string[] allFiles = [.. moduleCoreFiles, .. powershellModuleFiles, .. sqliteFiles];
+
+ context.Log.Information($"Copying {allFiles.Length} files to the module folder {powershelModuleOutputLocation}");
+ foreach (var file in allFiles)
+ {
+ context.Log.Information($"Copying {Path.GetFileName(file)}");
+ File.Copy(file, Path.Combine(powershelModuleOutputLocation, Path.GetFileName(file)));
+ }
+
+ context.Log.Information($"Bundle files copied");
+
+ GenerateModuleImportScript(moduleFolderLocation, context);
+ CreateBundleZip(bundleRootLocation, moduleFolderLocation, context);
+ }
+
+ private static void GenerateModuleImportScript(string bundleLocation, BuildContext context)
+ {
+ context.Log.Information($"Generating module import script");
+ var scriptFileName = Path.Combine(bundleLocation, "NulahPowershell.ps1");
+
+ using var scriptFile = File.Create(scriptFileName);
+ using var fileWriter = new StreamWriter(scriptFile);
+ // TODO: Document the set up function
+ // TODO: Create a ticket for fleshing out the set up function (or just do that work later)
+ fileWriter.Write(
+ """
+ # To use, first copy all files to the same location as your $profile under ./NulahModule, then open your powershell profile located at $profile and add the following:
+
+ # Script setup style: Using the setup script to import as needed (this method will also set custom prompts and other alias functions)
+ # . "$PSScriptRoot/NulahModule/NulahPowershell.ps1"
+ # SetupNulahPowershell
+ # Just the module: Use the following to just import just the powershell module
+ # Import-Module -Name "$PSScriptRoot/NulahModule/PowershellModule"
+
+ function SetupNulahPowershell
+ {
+ # only add to our module path once
+ # The intent for this is that a user will have copied this bundle folder alongside their $profile
+ # location, eg, they'll have a folder called NulahModule that will contain everything within the bundle zip
+ $testBundleDirectory = $PSScriptRoot
+ $bundleInPath = ($Env:PSModulePath -split ';').TrimEnd('\') -contains $testBundleDirectory;
+
+ if ($false -eq $bundleInPath)
+ {
+ $env:PSModulePath = @(
+ $env:PSModulePath
+ $testBundleDirectory
+ ) -Join [System.IO.Path]::PathSeparator
+ }
+
+ Import-Module "PowershellModule"
+ }
+ """
+ );
+ context.Log.Information($"Module import script created at '{scriptFileName}'");
+ }
+
+ private static void CreateBundleZip(string bundleLocation, string moduleFolderLocation, BuildContext context)
+ {
+ var bundleZipFileLocaiton = Path.Combine(bundleLocation, "NulahModule.zip");
+ context.Log.Information($"Bundling module into archive '{bundleZipFileLocaiton}'");
+ ZipFile.CreateFromDirectory(moduleFolderLocation, bundleZipFileLocaiton, CompressionLevel.Fastest, true);
+ context.Log.Information($"Archive created at '{bundleZipFileLocaiton}'");
+ }
+}
\ No newline at end of file
diff --git a/build/Tasks/DefaultTask.cs b/build/Tasks/DefaultTask.cs
index 200768c..7f4bf67 100644
--- a/build/Tasks/DefaultTask.cs
+++ b/build/Tasks/DefaultTask.cs
@@ -6,7 +6,9 @@ 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(CopyOutputTask))]
+[IsDependentOn(typeof(CreateBundleArchiveTask))]
public class DefaultTask : FrostingTask
{
public override void Run(ICakeContext context)
diff --git a/src/ModuleCore/Directory.Build.props b/src/ModuleCore/Directory.Build.props
index afa6e9c..e0bdda9 100644
--- a/src/ModuleCore/Directory.Build.props
+++ b/src/ModuleCore/Directory.Build.props
@@ -1,6 +1,6 @@
- 0.0.0
+ 0.0.1
dev
\ No newline at end of file
diff --git a/src/PowershellModule/Directory.Build.props b/src/PowershellModule/Directory.Build.props
index afa6e9c..e0bdda9 100644
--- a/src/PowershellModule/Directory.Build.props
+++ b/src/PowershellModule/Directory.Build.props
@@ -1,6 +1,6 @@
- 0.0.0
+ 0.0.1
dev
\ No newline at end of file