From c77523af671c382f186ad50fb80367dd9ea5a73d Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 29 Mar 2024 18:58:15 +0100 Subject: [PATCH 1/6] Dont require the source code to be in a folder with name of module --- scripts/helpers/Build-PSModule.ps1 | 12 +-- scripts/main.ps1 | 7 +- tests/src/PSModuleTest/PSModuleTest.psd1 | 4 - tests/src/PSModuleTest/PSModuleTest.psm1 | 73 ------------------ .../{PSModuleTest => }/assemblies/LsonLib.dll | Bin tests/src/{PSModuleTest => }/classes/Book.ps1 | 0 tests/src/{PSModuleTest => }/data/Config.psd1 | 0 .../src/{PSModuleTest => }/data/Settings.psd1 | 0 tests/src/{PSModuleTest => }/finally.ps1 | 0 .../formats/CultureInfo.Format.ps1xml | 0 .../formats/Mygciview.Format.ps1xml | 0 tests/src/{PSModuleTest => }/header.ps1 | 0 .../{PSModuleTest => }/init/initializer.ps1 | 0 tests/src/manifest.psd1 | 3 + .../modules/OtherPSModule.psm1 | 0 .../private/Get-InternalPSModule.ps1 | 0 .../private/Set-InternalPSModule.ps1 | 0 .../public/Get-PSModuleTest.ps1 | 0 .../public/New-PSModuleTest.ps1 | 0 .../public/Set-PSModuleTest.ps1 | 0 .../public/Test-PSModuleTest.ps1 | 0 .../src/{PSModuleTest => }/scripts/loader.ps1 | 0 .../types/DirectoryInfo.Types.ps1xml | 0 .../types/FileInfo.Types.ps1xml | 0 24 files changed, 16 insertions(+), 83 deletions(-) delete mode 100644 tests/src/PSModuleTest/PSModuleTest.psd1 delete mode 100644 tests/src/PSModuleTest/PSModuleTest.psm1 rename tests/src/{PSModuleTest => }/assemblies/LsonLib.dll (100%) rename tests/src/{PSModuleTest => }/classes/Book.ps1 (100%) rename tests/src/{PSModuleTest => }/data/Config.psd1 (100%) rename tests/src/{PSModuleTest => }/data/Settings.psd1 (100%) rename tests/src/{PSModuleTest => }/finally.ps1 (100%) rename tests/src/{PSModuleTest => }/formats/CultureInfo.Format.ps1xml (100%) rename tests/src/{PSModuleTest => }/formats/Mygciview.Format.ps1xml (100%) rename tests/src/{PSModuleTest => }/header.ps1 (100%) rename tests/src/{PSModuleTest => }/init/initializer.ps1 (100%) create mode 100644 tests/src/manifest.psd1 rename tests/src/{PSModuleTest => }/modules/OtherPSModule.psm1 (100%) rename tests/src/{PSModuleTest => }/private/Get-InternalPSModule.ps1 (100%) rename tests/src/{PSModuleTest => }/private/Set-InternalPSModule.ps1 (100%) rename tests/src/{PSModuleTest => }/public/Get-PSModuleTest.ps1 (100%) rename tests/src/{PSModuleTest => }/public/New-PSModuleTest.ps1 (100%) rename tests/src/{PSModuleTest => }/public/Set-PSModuleTest.ps1 (100%) rename tests/src/{PSModuleTest => }/public/Test-PSModuleTest.ps1 (100%) rename tests/src/{PSModuleTest => }/scripts/loader.ps1 (100%) rename tests/src/{PSModuleTest => }/types/DirectoryInfo.Types.ps1xml (100%) rename tests/src/{PSModuleTest => }/types/FileInfo.Types.ps1xml (100%) diff --git a/scripts/helpers/Build-PSModule.ps1 b/scripts/helpers/Build-PSModule.ps1 index a2df2ab..b6abf5f 100644 --- a/scripts/helpers/Build-PSModule.ps1 +++ b/scripts/helpers/Build-PSModule.ps1 @@ -10,6 +10,10 @@ function Build-PSModule { #> [CmdletBinding()] param( + # Name of the module. + [Parameter(Mandatory)] + [string] $ModuleName, + # Path to the folder where the modules are located. [Parameter(Mandatory)] [string] $ModuleSourceFolderPath, @@ -23,9 +27,7 @@ function Build-PSModule { [string] $DocsOutputFolderPath ) - $moduleName = Split-Path -Path $ModuleSourceFolderPath -Leaf - - Start-LogGroup "Building module [$moduleName]" + Start-LogGroup "Building module [$ModuleName]" Write-Verbose "Source path: [$ModuleSourceFolderPath]" if (-not (Test-Path -Path $ModuleSourceFolderPath)) { Write-Error "Source folder not found at [$ModuleSourceFolderPath]" @@ -33,10 +35,10 @@ function Build-PSModule { } $moduleSourceFolder = Get-Item -Path $ModuleSourceFolderPath - $moduleOutputFolder = New-Item -Path $ModulesOutputFolderPath -Name $moduleName -ItemType Directory -Force + $moduleOutputFolder = New-Item -Path $ModulesOutputFolderPath -Name $ModuleName -ItemType Directory -Force Write-Verbose "Module output folder: [$ModulesOutputFolderPath]" - $docsOutputFolder = New-Item -Path $DocsOutputFolderPath -Name $moduleName -ItemType Directory -Force + $docsOutputFolder = New-Item -Path $DocsOutputFolderPath -Name $ModuleName -ItemType Directory -Force Write-Verbose "Docs output folder: [$DocsOutputFolderPath]" Stop-LogGroup diff --git a/scripts/main.ps1 b/scripts/main.ps1 index 7e220be..77e9448 100644 --- a/scripts/main.ps1 +++ b/scripts/main.ps1 @@ -10,8 +10,12 @@ Stop-LogGroup Start-LogGroup 'Loading inputs' $moduleName = ($env:GITHUB_ACTION_INPUT_Name | IsNullOrEmpty) ? $env:GITHUB_REPOSITORY_NAME : $env:GITHUB_ACTION_INPUT_Name -$moduleSourceFolderPath = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath $env:GITHUB_ACTION_INPUT_Path $moduleName Write-Verbose "Module name: [$moduleName]" + +$moduleSourceFolderPath = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath $env:GITHUB_ACTION_INPUT_Path $moduleName +if (-not (Test-Path -Path $moduleSourceFolderPath)) { + $moduleSourceFolderPath = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath $env:GITHUB_ACTION_INPUT_Path +} Write-Verbose "Source module path: [$moduleSourceFolderPath]" if (-not (Test-Path -Path $moduleSourceFolderPath)) { throw "Module path [$moduleSourceFolderPath] does not exist." @@ -23,6 +27,7 @@ $docsOutputFolderPath = Join-Path $env:GITHUB_WORKSPACE $env:GITHUB_ACTION_INPUT Write-Verbose "Docs output path: [$docsOutputFolderPath]" Stop-LogGroup $params = @{ + ModuleName = $moduleName ModuleSourceFolderPath = $moduleSourceFolderPath ModulesOutputFolderPath = $modulesOutputFolderPath DocsOutputFolderPath = $docsOutputFolderPath diff --git a/tests/src/PSModuleTest/PSModuleTest.psd1 b/tests/src/PSModuleTest/PSModuleTest.psd1 deleted file mode 100644 index 466eca8..0000000 --- a/tests/src/PSModuleTest/PSModuleTest.psd1 +++ /dev/null @@ -1,4 +0,0 @@ -@{ - ModuleVersion = '0.0.0' - RootModule = 'PSModuleTest.psm1' -} diff --git a/tests/src/PSModuleTest/PSModuleTest.psm1 b/tests/src/PSModuleTest/PSModuleTest.psm1 deleted file mode 100644 index ab67c5e..0000000 --- a/tests/src/PSModuleTest/PSModuleTest.psm1 +++ /dev/null @@ -1,73 +0,0 @@ -[Cmdletbinding()] -param() - -Write-Verbose 'Importing subcomponents' -$Folders = 'init', 'classes', 'private', 'public' -# Import everything in these folders -Foreach ($Folder in $Folders) { - $Root = Join-Path -Path $PSScriptRoot -ChildPath $Folder - Write-Verbose "Processing folder: $Root" - if (Test-Path -Path $Root) { - Write-Verbose "Getting all files in $Root" - $Files = $null - $Files = Get-ChildItem -Path $Root -Include '*.ps1', '*.psm1' -Recurse - # dot source each file - foreach ($File in $Files) { - Write-Verbose "Importing $($File)" - Import-Module $File - Write-Verbose "Importing $($File): Done" - } - } -} - -. "$PSScriptRoot\finally.ps1" - -# Define the types to export with type accelerators. -$ExportableTypes = @( - [Book] - [BookList] -) - -# Get the internal TypeAccelerators class to use its static methods. -$TypeAcceleratorsClass = [psobject].Assembly.GetType( - 'System.Management.Automation.TypeAccelerators' -) -# Ensure none of the types would clobber an existing type accelerator. -# If a type accelerator with the same name exists, throw an exception. -$ExistingTypeAccelerators = $TypeAcceleratorsClass::Get -foreach ($Type in $ExportableTypes) { - if ($Type.FullName -in $ExistingTypeAccelerators.Keys) { - $Message = @( - "Unable to register type accelerator '$($Type.FullName)'" - 'Accelerator already exists.' - ) -join ' - ' - - throw [System.Management.Automation.ErrorRecord]::new( - [System.InvalidOperationException]::new($Message), - 'TypeAcceleratorAlreadyExists', - [System.Management.Automation.ErrorCategory]::InvalidOperation, - $Type.FullName - ) - } -} -# Add type accelerators for every exportable type. -foreach ($Type in $ExportableTypes) { - $TypeAcceleratorsClass::Add($Type.FullName, $Type) -} -# Remove type accelerators when the module is removed. -$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { - foreach ($Type in $ExportableTypes) { - $TypeAcceleratorsClass::Remove($Type.FullName) - } -}.GetNewClosure() - -$Param = @{ - Function = (Get-ChildItem -Path "$PSScriptRoot\public" -Include '*.ps1' -Recurse).BaseName - Variable = '*' - Cmdlet = '*' - Alias = '*' -} - -Write-Verbose 'Exporting module members' - -Export-ModuleMember @Param diff --git a/tests/src/PSModuleTest/assemblies/LsonLib.dll b/tests/src/assemblies/LsonLib.dll similarity index 100% rename from tests/src/PSModuleTest/assemblies/LsonLib.dll rename to tests/src/assemblies/LsonLib.dll diff --git a/tests/src/PSModuleTest/classes/Book.ps1 b/tests/src/classes/Book.ps1 similarity index 100% rename from tests/src/PSModuleTest/classes/Book.ps1 rename to tests/src/classes/Book.ps1 diff --git a/tests/src/PSModuleTest/data/Config.psd1 b/tests/src/data/Config.psd1 similarity index 100% rename from tests/src/PSModuleTest/data/Config.psd1 rename to tests/src/data/Config.psd1 diff --git a/tests/src/PSModuleTest/data/Settings.psd1 b/tests/src/data/Settings.psd1 similarity index 100% rename from tests/src/PSModuleTest/data/Settings.psd1 rename to tests/src/data/Settings.psd1 diff --git a/tests/src/PSModuleTest/finally.ps1 b/tests/src/finally.ps1 similarity index 100% rename from tests/src/PSModuleTest/finally.ps1 rename to tests/src/finally.ps1 diff --git a/tests/src/PSModuleTest/formats/CultureInfo.Format.ps1xml b/tests/src/formats/CultureInfo.Format.ps1xml similarity index 100% rename from tests/src/PSModuleTest/formats/CultureInfo.Format.ps1xml rename to tests/src/formats/CultureInfo.Format.ps1xml diff --git a/tests/src/PSModuleTest/formats/Mygciview.Format.ps1xml b/tests/src/formats/Mygciview.Format.ps1xml similarity index 100% rename from tests/src/PSModuleTest/formats/Mygciview.Format.ps1xml rename to tests/src/formats/Mygciview.Format.ps1xml diff --git a/tests/src/PSModuleTest/header.ps1 b/tests/src/header.ps1 similarity index 100% rename from tests/src/PSModuleTest/header.ps1 rename to tests/src/header.ps1 diff --git a/tests/src/PSModuleTest/init/initializer.ps1 b/tests/src/init/initializer.ps1 similarity index 100% rename from tests/src/PSModuleTest/init/initializer.ps1 rename to tests/src/init/initializer.ps1 diff --git a/tests/src/manifest.psd1 b/tests/src/manifest.psd1 new file mode 100644 index 0000000..9bbe918 --- /dev/null +++ b/tests/src/manifest.psd1 @@ -0,0 +1,3 @@ +@{ + ModuleVersion = '0.0.0' +} diff --git a/tests/src/PSModuleTest/modules/OtherPSModule.psm1 b/tests/src/modules/OtherPSModule.psm1 similarity index 100% rename from tests/src/PSModuleTest/modules/OtherPSModule.psm1 rename to tests/src/modules/OtherPSModule.psm1 diff --git a/tests/src/PSModuleTest/private/Get-InternalPSModule.ps1 b/tests/src/private/Get-InternalPSModule.ps1 similarity index 100% rename from tests/src/PSModuleTest/private/Get-InternalPSModule.ps1 rename to tests/src/private/Get-InternalPSModule.ps1 diff --git a/tests/src/PSModuleTest/private/Set-InternalPSModule.ps1 b/tests/src/private/Set-InternalPSModule.ps1 similarity index 100% rename from tests/src/PSModuleTest/private/Set-InternalPSModule.ps1 rename to tests/src/private/Set-InternalPSModule.ps1 diff --git a/tests/src/PSModuleTest/public/Get-PSModuleTest.ps1 b/tests/src/public/Get-PSModuleTest.ps1 similarity index 100% rename from tests/src/PSModuleTest/public/Get-PSModuleTest.ps1 rename to tests/src/public/Get-PSModuleTest.ps1 diff --git a/tests/src/PSModuleTest/public/New-PSModuleTest.ps1 b/tests/src/public/New-PSModuleTest.ps1 similarity index 100% rename from tests/src/PSModuleTest/public/New-PSModuleTest.ps1 rename to tests/src/public/New-PSModuleTest.ps1 diff --git a/tests/src/PSModuleTest/public/Set-PSModuleTest.ps1 b/tests/src/public/Set-PSModuleTest.ps1 similarity index 100% rename from tests/src/PSModuleTest/public/Set-PSModuleTest.ps1 rename to tests/src/public/Set-PSModuleTest.ps1 diff --git a/tests/src/PSModuleTest/public/Test-PSModuleTest.ps1 b/tests/src/public/Test-PSModuleTest.ps1 similarity index 100% rename from tests/src/PSModuleTest/public/Test-PSModuleTest.ps1 rename to tests/src/public/Test-PSModuleTest.ps1 diff --git a/tests/src/PSModuleTest/scripts/loader.ps1 b/tests/src/scripts/loader.ps1 similarity index 100% rename from tests/src/PSModuleTest/scripts/loader.ps1 rename to tests/src/scripts/loader.ps1 diff --git a/tests/src/PSModuleTest/types/DirectoryInfo.Types.ps1xml b/tests/src/types/DirectoryInfo.Types.ps1xml similarity index 100% rename from tests/src/PSModuleTest/types/DirectoryInfo.Types.ps1xml rename to tests/src/types/DirectoryInfo.Types.ps1xml diff --git a/tests/src/PSModuleTest/types/FileInfo.Types.ps1xml b/tests/src/types/FileInfo.Types.ps1xml similarity index 100% rename from tests/src/PSModuleTest/types/FileInfo.Types.ps1xml rename to tests/src/types/FileInfo.Types.ps1xml From 8f3a05d699e30b1e7503c08f4ec44fdc3d52a675 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 29 Mar 2024 19:15:09 +0100 Subject: [PATCH 2/6] update docs --- README.md | 57 +++++++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 119bc35..8c84158 100644 --- a/README.md +++ b/README.md @@ -36,38 +36,40 @@ During the build process the following steps are performed: The root module file is the main file that is loaded when the module is imported. It is built from the source code files in the module folder in the following order: -1. Adds module headers from `header.ps1`. +1. Adds module headers from `header.ps1` if it exists and removes the file from the module folder. 1. Adds data loader automation that loads files from the `data` folder as variables in the module scope, if it exists. The variables are available using the ´$script:´ syntax. -1. Adds content from subfolders, in the order: - - Init - - Private - - Public - - *.ps1 on module root -1. Adds the Export-ModuleMember function to the end of the file, to make sure that only the functions, cmdlets, variables and aliases that are defined in the module are exported. +1. Adds content from subfolders, if they exists, and removes them from the module folder in the following order: + - `init` + - `classes` + - `private` + - `public` + - `*.ps1` on module root +1. Adds a `class` and `enum` exporter that exports all classes and enums in the module to the caller session, using TypeAccelerators. +1. Adds the `Export-ModuleMember` function to the end of the file, to make sure that only the functions, cmdlets, variables and aliases that are defined in the module are exported. -### The root module in the `src` folder +### Root module -The root module file that is included in the source files contains the same functionality but is not optimized for performance. -The goal with this is to have a quick way to import and test the module without having to build it. +The `src` folder may contain a 'root module' file. If present, the build function will disregard this file and build a new root module file based on the source code in the module folder. ## Module manifest The module manifest file is the file that describes the module and its content. It is used by PowerShell to load the module and its prerequisites. -The file also contains important metadata that is used by the PowerShell Gallery. +The file also contains important metadata that is used by the PowerShell Gallery. If a file exists in the source code folder `src` it will be used as a base for the module manifest file. +Most of the values in the module manifest file are calculated during the build process however some of these will not be touched if specified in the source manifest file. During the module manifest build process the following steps are performed: -1. Get the manifest file from the source code. Content from this file overrides any value that would be calculated based on the source code. +1. Get the manifest file from the source code. If it does not exist, a new manifest file is created. 1. Find and set the `RootModule` based on filename and extension. 1. Set a temporary `ModuleVersion`, as this is set during the release process by [Publish-PSModule](https://github.com/PSModule/Publish-PSModule). -1. Set the `Author` and `CompanyName` based on GitHub Owner. -1. Set the `Copyright` information based on a default text (`(c) 2024 >>OwnerName<<. All rights reserved.`) and adds either the `Author`, `CompanyName` or both (`Author | CompanyName`) when these are different. -1. Set the `Description` based on the GitHub repository description. -1. Set various properties in the manifest such as `PowerShellHostName`, `PowerShellHostVersion`, `DotNetFrameworkVersion`, `ClrVersion`, and `ProcessorArchitecture`. There is currently no automation for these properties. +1. Set the `Author` and `CompanyName` based on GitHub Owner. If a value exists in the source manifest file, this value is used. +1. Set the `Copyright` information based on a default text (`(c) 2024 >>OwnerName<<. All rights reserved.`) and adds either the `Author`, `CompanyName` or both (`Author | CompanyName`) when these are different. If a value exists in the source manifest file, this value is used. +1. Set the `Description` based on the GitHub repository description. If a value exists in the source manifest file, this value is used. +1. Set various properties in the manifest such as `PowerShellHostName`, `PowerShellHostVersion`, `DotNetFrameworkVersion`, `ClrVersion`, and `ProcessorArchitecture`. There is currently no automation for these properties. If a value exists in the source manifest file, this value is used. 1. Get the list of files in the module source folder and set the `FileList` property in the manifest. 1. Get the list of required assemblies (`*.dll` files) from the `assemblies` folder and set the `RequiredAssemblies` property in the manifest. 1. Get the list of nested modules (`*.psm1` files) from the `modules` folder and set the `NestedModules` property in the manifest. -1. Get the list of scripts to process (`*.ps1` files) from the `classes` and `scripts` folders and set the `ScriptsToProcess` property in the manifest. This ensures that the scripts are loaded to the caller session (parent of module session). +1. Get the list of scripts to process (`*.ps1` files) from the `scripts` folders and set the `ScriptsToProcess` property in the manifest. This ensures that the scripts are loaded to the caller session (parent of module session). 1. Get the list of types to process by searching for `*.Types.ps1xml` files in the entire module source folder and set the `TypesToProcess` property in the manifest. 1. Get the list of formats to process by searching for `*.Format.ps1xml` files in the entire module source folder and set the `FormatsToProcess` property in the manifest. 1. Get the list of DSC resources to export by searching for `*.psm1` files in the `resources` folder and set the `DscResourcesToExport` property in the manifest. @@ -76,14 +78,14 @@ During the module manifest build process the following steps are performed: 1. Gather information from source files to update `RequiredModules`, `PowerShellVersion`, and `CompatiblePSEditions` properties. 1. The following values are gathered from the GitHub repository: - `Tags` are generated from Repository topics in addition to compatability tags gathered from the source code. - - `LicenseUri` is generated assuming there is a `LICENSE` file on the root of the repository. - - `ProjectUri` is the URL to the GitHub repository - - `IconUri` is generated assuming there is a `icon.png` file in the `icon` folder on the repository root. + - `LicenseUri` is generated assuming there is a `LICENSE` file on the root of the repository. If a value exists in the source manifest file, this value is used. + - `ProjectUri` is the URL to the GitHub repository. If a value exists in the source manifest file, this value is used. + - `IconUri` is generated assuming there is a `icon.png` file in the `icon` folder on the repository root. If a value exists in the source manifest file, this value is used. 1. `ReleaseNotes` currently not automated, but could be the PR description or release description. 1. `PreRelease` is not managed here, but is managed from [Publish-PSModule](https://github.com/PSModule/Publish-PSModule) -1. `RequireLicenseAcceptance` is not automated and defaults to `false`, and -1. `ExternalModuleDependencies` is currenlty not automated. -1. `HelpInfoURI` is not automated. +1. `RequireLicenseAcceptance` is not automated and defaults to `false`. If a value exists in the source manifest file, this value is used. +1. `ExternalModuleDependencies` is currenlty not automated. If a value exists in the source manifest file, this value is used. +1. `HelpInfoURI` is not automated. If a value exists in the source manifest file, this value is used. 1. Create a new manifest file in the output folder with the gathered info above. This also generates a new `GUID` for the module. 1. Format the manifest file using the `Set-ModuleManifest` function from the [Utilities](https://github.com/PSModule/Utilities) module. @@ -142,16 +144,9 @@ Linking the description to the module manifest file might show more how this wor } ``` -### The module manifest in the `src` folder - -The module manifest file that is included in the source files contains the same functionality but is not optimized for performance and does not automatically gather all the information that is gathered during the build process. -The goal with this is to have a quick way to import and test the module without having to build it. - -The source module manifest is also the only place where some of the values can be controlled. These values are typically difficult to calculate and are not automated. - ## Module documentation -The module documentation is built using platyPS and comment based help in the source code. +The module documentation is built using `platyPS` and comment based help in the source code. The documentation is currently not published anywhere, but should be published to GitHub Pages in a future release. ## Permissions From b213b21fcb455b11c0a10f29a2d8ce925889d68d Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 29 Mar 2024 19:34:49 +0100 Subject: [PATCH 3/6] fix --- README.md | 4 +- .../helpers/Build/Build-PSModuleManifest.ps1 | 21 ++++---- .../helpers/Build/Get-PSModuleRootModule.ps1 | 54 ------------------- 3 files changed, 14 insertions(+), 65 deletions(-) delete mode 100644 scripts/helpers/Build/Get-PSModuleRootModule.ps1 diff --git a/README.md b/README.md index 8c84158..70dd3fa 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Most of the values in the module manifest file are calculated during the build p During the module manifest build process the following steps are performed: 1. Get the manifest file from the source code. If it does not exist, a new manifest file is created. -1. Find and set the `RootModule` based on filename and extension. +1. Generate and set the `RootModule` based module name. 1. Set a temporary `ModuleVersion`, as this is set during the release process by [Publish-PSModule](https://github.com/PSModule/Publish-PSModule). 1. Set the `Author` and `CompanyName` based on GitHub Owner. If a value exists in the source manifest file, this value is used. 1. Set the `Copyright` information based on a default text (`(c) 2024 >>OwnerName<<. All rights reserved.`) and adds either the `Author`, `CompanyName` or both (`Author | CompanyName`) when these are different. If a value exists in the source manifest file, this value is used. @@ -93,7 +93,7 @@ Linking the description to the module manifest file might show more how this wor ```powershell @{ - RootModule = 'Utilities.psm1' # Get files from root of folder wher name is same as the folder and file extension is .psm1, .ps1, .psd1, .dll, .cdxml, .xaml. Error if there are multiple files that meet the criteria. + RootModule = 'Utilities.psm1' # Generated from the module name, .psm1 ModuleVersion = '0.0.1' # Set during release using Publish-PSModule. CompatiblePSEditions = @() # Get from source files, REQUIRES -PSEdition , null if not provided. GUID = '' # Generated when finally saving the manifest using New-ModuleManifest. diff --git a/scripts/helpers/Build/Build-PSModuleManifest.ps1 b/scripts/helpers/Build/Build-PSModuleManifest.ps1 index 55a0456..06a122a 100644 --- a/scripts/helpers/Build/Build-PSModuleManifest.ps1 +++ b/scripts/helpers/Build/Build-PSModuleManifest.ps1 @@ -26,14 +26,17 @@ function Build-PSModuleManifest { #region Build manifest file Start-LogGroup 'Build manifest file' $moduleName = Split-Path -Path $ModuleOutputFolder -Leaf - $manifestFileName = "$moduleName.psd1" - $manifestOutputPath = Join-Path -Path $ModuleOutputFolder -ChildPath $manifestFileName - $manifestFile = Get-Item -Path $manifestOutputPath - Write-Verbose ($manifestFile | Format-List | Out-String) - $manifest = Get-ModuleManifest -Path $manifestFile -Verbose:$false - - $rootModule = Get-PSModuleRootModule -SourceFolderPath $ModuleOutputFolder - $manifest.RootModule = $rootModule + $sourceManifestFilePath = Join-Path -Path $ModuleOutputFolder -ChildPath "$moduleName.psd1" + if (-not (Test-Path -Path $sourceManifestFilePath)) { + $sourceManifestFilePath = Join-Path -Path $ModuleOutputFolder -ChildPath 'manifest.psd1' + } + $manifest = if (-not (Test-Path -Path $sourceManifestFilePath)) { + @{} + } else { + Get-ModuleManifest -Path $sourceManifestFilePath -Verbose:$false + } + + $manifest.RootModule = "$moduleName.psm1" $manifest.ModuleVersion = '999.0.0' $manifest.Author = $manifest.Keys -contains 'Author' ? ($manifest.Author | IsNotNullOrEmpty) ? $manifest.Author : $env:GITHUB_REPOSITORY_OWNER : $env:GITHUB_REPOSITORY_OWNER @@ -322,7 +325,7 @@ function Build-PSModuleManifest { } Write-Verbose 'Creating new manifest file in outputs folder' - $outputManifestPath = Join-Path -Path $ModuleOutputFolder $manifestFileName + $outputManifestPath = Join-Path -Path $ModuleOutputFolder -ChildPath "$moduleName.psd1" Write-Verbose "OutputManifestPath - [$outputManifestPath]" New-ModuleManifest -Path $outputManifestPath @manifest Stop-LogGroup diff --git a/scripts/helpers/Build/Get-PSModuleRootModule.ps1 b/scripts/helpers/Build/Get-PSModuleRootModule.ps1 deleted file mode 100644 index cfb5375..0000000 --- a/scripts/helpers/Build/Get-PSModuleRootModule.ps1 +++ /dev/null @@ -1,54 +0,0 @@ -function Get-PSModuleRootModule { - <# - .SYNOPSIS - Gets the root module to export from the module manifest. - - .DESCRIPTION - This function will get the root module to export from the module manifest. - - .EXAMPLE - Get-PSModuleRootModule -SourceFolderPath 'C:\MyModule\src\MyModule' - #> - [CmdletBinding()] - param( - # Path to the folder where the module source code is located. - [Parameter(Mandatory)] - [string] $SourceFolderPath - ) - - $rootModuleExtensions = '.psm1', '.ps1', '.dll', '.cdxml', '.xaml' - $candidateFiles = Get-ChildItem -Path $SourceFolderPath -File | Where-Object { ($_.BaseName -like $_.Directory.BaseName) -and ($_.Extension -in $rootModuleExtensions) } - - Write-Verbose "Looking for root modules, matching extensions in order [$($rootModuleExtensions -join ', ')]" -Verbose - :ext foreach ($ext in $rootModuleExtensions) { - Write-Verbose "Looking for [$ext] files" - foreach ($file in $candidateFiles) { - Write-Verbose " - [$($file.Name)]" - if ($file.Extension -eq $ext) { - Write-Verbose " - [$($file.Name)] - RootModule found!" - $rootModule = $file.Name - break ext - } - } - } - - if (-not $rootModule) { - Write-Verbose 'No RootModule found' - } - - $moduleType = switch -Regex ($RootModule) { - '\.(ps1|psm1)$' { 'Script' } - '\.dll$' { 'Binary' } - '\.cdxml$' { 'CIM' } - '\.xaml$' { 'Workflow' } - default { 'Manifest' } - } - Write-Verbose "[$manifestPropertyName] - [$moduleType]" - - $supportedModuleTypes = @('Script', 'Manifest') - if ($moduleType -notin $supportedModuleTypes) { - Write-Warning "[$moduleType] - Module type not supported" - } - - $rootModule -} From aa1090e6ae22ac0491cab8ec66aaa89bc58dbca2 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 29 Mar 2024 21:30:47 +0100 Subject: [PATCH 4/6] tests --- .../helpers/Build/Build-PSModuleManifest.ps1 | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/scripts/helpers/Build/Build-PSModuleManifest.ps1 b/scripts/helpers/Build/Build-PSModuleManifest.ps1 index 06a122a..9b28e54 100644 --- a/scripts/helpers/Build/Build-PSModuleManifest.ps1 +++ b/scripts/helpers/Build/Build-PSModuleManifest.ps1 @@ -74,10 +74,19 @@ function Build-PSModuleManifest { $pathSeparator = [System.IO.Path]::DirectorySeparatorChar Write-Verbose '[FileList]' - $files = $ModuleOutputFolder | Get-ChildItem -File -ErrorAction SilentlyContinue | Where-Object -Property Name -NotLike '*.ps1' - $files += $ModuleOutputFolder | Get-ChildItem -Directory | Get-ChildItem -Recurse -File -ErrorAction SilentlyContinue + $ModuleOutputFolder = 'C:\Repos\GitHub\PSModule\Framework\Build-PSModule\tests\src' + $files = [System.Collections.Generic.List[System.IO.FileInfo]]::new() + + # Get files on module root + $ModuleOutputFolder | Get-ChildItem -File -ErrorAction SilentlyContinue | Where-Object -Property Name -NotLike '*.ps1' | ForEach-Object { $files.Add($_) } + + # Get files on module subfolders, excluding the following folders 'init', 'classes', 'public', 'private' + $skipList = @('init', 'classes', 'public', 'private') + $ModuleOutputFolder | Get-ChildItem -Directory | Where-Object { $_.Name -NotIn $skipList } | + Get-ChildItem -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object { $files.Add($_) } + + # Get the relative file path and store it in the manifest $files = $files | Select-Object -ExpandProperty FullName | ForEach-Object { $_.Replace($ModuleOutputFolder, '').TrimStart($pathSeparator) } - $fileList = $files | Where-Object { $_ -NotLike 'init*' -and $_ -NotLike 'classes*' -and $_ -NotLike 'public*' -and $_ -NotLike 'private*' } $manifest.FileList = $fileList.count -eq 0 ? @() : @($fileList) $manifest.FileList | ForEach-Object { Write-Verbose "[FileList] - [$_]" } @@ -145,9 +154,9 @@ function Build-PSModuleManifest { Write-Verbose '[Gather]' - $capturedModules = @() - $capturedVersions = @() - $capturedPSEdition = @() + $capturedModules = [System.Collections.Generic.List[System.Object]]::new() + $capturedVersions = [System.Collections.Generic.List[string]]::new() + $capturedPSEdition = [System.Collections.Generic.List[string]]::new() $files = $ModuleOutputFolder | Get-ChildItem -Recurse -File -ErrorAction SilentlyContinue Write-Verbose "[Gather] - Processing [$($files.Count)] files" @@ -168,22 +177,22 @@ function Build-PSModuleManifest { $hashtable = '@\{[^}]*\}' if ($_ -match $hashtable) { Write-Verbose " - [#Requires -Modules] - [$_] - Hashtable" - $capturedModules += ConvertTo-Hashtable -InputString $_ + $capturedModules.Add((ConvertTo-Hashtable -InputString $_)) } else { Write-Verbose " - [#Requires -Modules] - [$_] - String" - $capturedModules += $_ + $capturedModules.Add($_) } } } # PowerShellVersion -> REQUIRES -Version [.], $null if not provided '^\s*#Requires -Version (.+)$' { Write-Verbose " - [#Requires -Version] - [$($matches[1])]" - $capturedVersions += $matches[1] + $capturedVersions.Add($matches[1]) } #CompatiblePSEditions -> REQUIRES -PSEdition , $null if not provided '^\s*#Requires -PSEdition (.+)$' { Write-Verbose " - [#Requires -PSEdition] - [$($matches[1])]" - $capturedPSEdition += $matches[1] + $capturedPSEdition.Add($matches[1]) } } } @@ -247,7 +256,7 @@ function Build-PSModuleManifest { } catch { $repoLabels = @() } - $manifestTags = [Collections.Generic.List[string]]::new() + $manifestTags = [System.Collections.Generic.List[string]]::new() $tags = $PSData.Keys -contains 'Tags' ? ($PSData.Tags).Count -gt 0 ? $PSData.Tags : $repoLabels : $repoLabels $tags | ForEach-Object { $manifestTags.Add($_) } # Add tags for compatability mode. https://docs.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-module-manifest?view=powershell-7.1#compatibility-tags From 532dd76a8195c7e2ae4b6c4424694217d01eb820 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 29 Mar 2024 21:32:45 +0100 Subject: [PATCH 5/6] test --- scripts/helpers/Build/Build-PSModuleManifest.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/helpers/Build/Build-PSModuleManifest.ps1 b/scripts/helpers/Build/Build-PSModuleManifest.ps1 index 9b28e54..d22be64 100644 --- a/scripts/helpers/Build/Build-PSModuleManifest.ps1 +++ b/scripts/helpers/Build/Build-PSModuleManifest.ps1 @@ -74,11 +74,11 @@ function Build-PSModuleManifest { $pathSeparator = [System.IO.Path]::DirectorySeparatorChar Write-Verbose '[FileList]' - $ModuleOutputFolder = 'C:\Repos\GitHub\PSModule\Framework\Build-PSModule\tests\src' $files = [System.Collections.Generic.List[System.IO.FileInfo]]::new() # Get files on module root - $ModuleOutputFolder | Get-ChildItem -File -ErrorAction SilentlyContinue | Where-Object -Property Name -NotLike '*.ps1' | ForEach-Object { $files.Add($_) } + $ModuleOutputFolder | Get-ChildItem -File -ErrorAction SilentlyContinue | Where-Object -Property Name -NotLike '*.ps1' | + ForEach-Object { $files.Add($_) } # Get files on module subfolders, excluding the following folders 'init', 'classes', 'public', 'private' $skipList = @('init', 'classes', 'public', 'private') From a46efde2de5c61d3d7b8bba63cb0684c5221e216 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 29 Mar 2024 21:36:42 +0100 Subject: [PATCH 6/6] Fix linting --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 70dd3fa..4ec8cc4 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ During the build process the following steps are performed: ## Root module +The `src` folder may contain a 'root module' file. If present, the build function will disregard this file +and build a new root module file based on the source code in the module folder. + The root module file is the main file that is loaded when the module is imported. It is built from the source code files in the module folder in the following order: @@ -47,10 +50,6 @@ It is built from the source code files in the module folder in the following ord 1. Adds a `class` and `enum` exporter that exports all classes and enums in the module to the caller session, using TypeAccelerators. 1. Adds the `Export-ModuleMember` function to the end of the file, to make sure that only the functions, cmdlets, variables and aliases that are defined in the module are exported. -### Root module - -The `src` folder may contain a 'root module' file. If present, the build function will disregard this file and build a new root module file based on the source code in the module folder. - ## Module manifest The module manifest file is the file that describes the module and its content. It is used by PowerShell to load the module and its prerequisites.