Skip to content

Commit

Permalink
Support passing versions via build.psd1
Browse files Browse the repository at this point in the history
Merge pull request #129 from PoshCode/joel/build.psd1
  • Loading branch information
Jaykul authored Mar 17, 2024
2 parents fe0d086 + c607a97 commit 0ade8f4
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 44 deletions.
22 changes: 22 additions & 0 deletions Source/Private/InitializeBuild.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@ function InitializeBuild {
) -join ' ')"
$BuildInfo = GetBuildInfo -BuildManifest $BuildManifest -BuildCommandInvocation $BuildCommandInvocation

# Normalize the version (if it was passed in via build.psd1)
if ($BuildInfo.SemVer) {
Write-Verbose "Update the Version, Prerelease, and BuildMetadata from the SemVer (in case it was passed in via build.psd1)"
$BuildInfo = $BuildInfo | Update-Object @{
Version = if (($V = $BuildInfo.SemVer.Split("+")[0].Split("-", 2)[0])) {
[version]$V
}
Prerelease = $BuildInfo.SemVer.Split("+")[0].Split("-", 2)[1]
BuildMetadata = $BuildInfo.SemVer.Split("+", 2)[1]
}
} elseif($BuildInfo.Version) {
Write-Verbose "Calculate the Semantic Version from the Version - Prerelease + BuildMetadata"
$SemVer = "$($BuildInfo.Version)"
if ($BuildInfo.Prerelease) {
$SemVer = "$SemVer-$($BuildInfo.Prerelease)"
}
if ($BuildInfo.BuildMetadata) {
$SemVer = "$SemVer+$($BuildInfo.BuildMetadata)"
}
$BuildInfo = $BuildInfo | Update-Object @{ SemVer = $SemVer }
}

# Override VersionedOutputDirectory with UnversionedOutputDirectory
if ($BuildInfo.UnversionedOutputDirectory -and $BuildInfo.VersionedOutputDirectory) {
$BuildInfo.VersionedOutputDirectory = $false
Expand Down
44 changes: 15 additions & 29 deletions Source/Public/Build-Module.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ function Build-Module {
Build-Module -SemVer $gitVersion
This example shows how to use a semantic version from gitversion to version your build.
Note, this is how we version ModuleBuilder, so if you want to see it in action, check out our azure-pipelines.yml
https://github.com/PoshCode/ModuleBuilder/blob/master/azure-pipelines.yml
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="Build is approved now")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCmdletCorrectly", "")]
Expand Down Expand Up @@ -150,42 +148,30 @@ function Build-Module {
}
process {
try {
# BEFORE we InitializeBuild we need to "fix" the version
if($PSCmdlet.ParameterSetName -ne "SemanticVersion") {
Write-Verbose "Calculate the Semantic Version from the $Version - $Prerelease + $BuildMetadata"
$SemVer = "$Version"
if($Prerelease) {
$SemVer = "$Version-$Prerelease"
}
if($BuildMetadata) {
$SemVer = "$SemVer+$BuildMetadata"
}
}

# Push into the module source (it may be a subfolder)
$ModuleInfo = InitializeBuild $SourcePath
Write-Progress "Building $($ModuleInfo.Name)" -Status "Use -Verbose for more information"
Write-Verbose "Building $($ModuleInfo.Name)"

# Ensure the OutputDirectory (exists for build, or is cleaned otherwise)
$OutputDirectory = $ModuleInfo | ResolveOutputFolder
if ($Target -notmatch "Build") {
if ($ModuleInfo.Target -notmatch "Build") {
return
}
$RootModule = Join-Path $OutputDirectory "$($ModuleInfo.Name).psm1"
$OutputManifest = Join-Path $OutputDirectory "$($ModuleInfo.Name).psd1"
Write-Verbose "Output to: $OutputDirectory"

# Skip the build if it's up to date already
Write-Verbose "Target $Target"
Write-Verbose "Target $($ModuleInfo.Target)"
$NewestBuild = (Get-Item $RootModule -ErrorAction SilentlyContinue).LastWriteTime
$IsNew = Get-ChildItem $ModuleInfo.ModuleBase -Recurse |
Where-Object LastWriteTime -gt $NewestBuild |
Select-Object -First 1 -ExpandProperty LastWriteTime

if ($null -eq $IsNew) {
# This is mostly for testing ...
if ($Passthru) {
if ($ModuleInfo.Passthru) {
Get-Module $OutputManifest -ListAvailable
}
return # Skip the build
Expand Down Expand Up @@ -240,31 +226,31 @@ function Build-Module {
}

try {
if ($Version) {
Write-Verbose "Update Manifest at $OutputManifest with version: $Version"
Update-Metadata -Path $OutputManifest -PropertyName ModuleVersion -Value $Version
if ($ModuleInfo.Version) {
Write-Verbose "Update Manifest at $OutputManifest with version: $($ModuleInfo.Version)"
Update-Metadata -Path $OutputManifest -PropertyName ModuleVersion -Value $ModuleInfo.Version
}
} catch {
Write-Warning "Failed to update version to $Version. $_"
Write-Warning "Failed to update version to $($ModuleInfo.Version). $_"
}

if ($null -ne (Get-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.Prerelease -ErrorAction SilentlyContinue)) {
if ($Prerelease) {
Write-Verbose "Update Manifest at $OutputManifest with Prerelease: $Prerelease"
Update-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.Prerelease -Value $Prerelease
if ($ModuleInfo.Prerelease) {
Write-Verbose "Update Manifest at $OutputManifest with Prerelease: $($ModuleInfo.Prerelease)"
Update-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.Prerelease -Value $ModuleInfo.Prerelease
} elseif ($PSCmdlet.ParameterSetName -eq "SemanticVersion" -or $PSBoundParameters.ContainsKey("Prerelease")) {
Update-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.Prerelease -Value ""
}
} elseif($Prerelease) {
} elseif ($ModuleInfo.Prerelease) {
Write-Warning ("Cannot set Prerelease in module manifest. Add an empty Prerelease to your module manifest, like:`n" +
' PrivateData = @{ PSData = @{ Prerelease = "" } }')
}

if ($BuildMetadata) {
Write-Verbose "Update Manifest at $OutputManifest with metadata: $BuildMetadata from $SemVer"
if ($ModuleInfo.BuildMetadata) {
Write-Verbose "Update Manifest at $OutputManifest with metadata: $($ModuleInfo.BuildMetadata) from $($ModuleInfo.SemVer)"
$RelNote = Get-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.ReleaseNotes -ErrorAction SilentlyContinue
if ($null -ne $RelNote) {
$Line = "$($ModuleInfo.Name) v$($SemVer)"
$Line = "$($ModuleInfo.Name) v$($($ModuleInfo.SemVer))"
if ([string]::IsNullOrWhiteSpace($RelNote)) {
Write-Verbose "New ReleaseNotes:`n$Line"
Update-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.ReleaseNotes -Value $Line
Expand All @@ -284,7 +270,7 @@ function Build-Module {
}

# This is mostly for testing ...
if ($Passthru) {
if ($ModuleInfo.Passthru) {
Get-Module $OutputManifest -ListAvailable
}
} finally {
Expand Down
29 changes: 29 additions & 0 deletions Tests/Integration/Parameters.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#requires -Module ModuleBuilder
. $PSScriptRoot\..\Convert-FolderSeparator.ps1

Describe "Parameters.Set in build manifest" -Tag Integration {
BeforeAll {
New-Item $PSScriptRoot\Result3\Parameters\ReadMe.md -ItemType File -Force
$Output = Build-Module $PSScriptRoot\Parameters\build.psd1
if ($Output) {
$Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
$Metadata = Import-Metadata $Output.Path
}
}

It "Passthru works" {
$Output | Should -Not -BeNullOrEmpty
}

It "The Target is Build" {
"$PSScriptRoot\Result3\Parameters\ReadMe.md" | Should -Exist
}

It "The version is set" {
$Metadata.ModuleVersion | Should -Be "3.0.0"
}

It "The PreRelease is set" {
$Metadata.PrivateData.PSData.Prerelease | Should -Be 'alpha001'
}
}
56 changes: 56 additions & 0 deletions Tests/Integration/Parameters/Parameters.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
@{
# The module version should be SemVer.org compatible
ModuleVersion = "1.0.0"

# PrivateData is where all third-party metadata goes
PrivateData = @{
# PrivateData.PSData is the PowerShell Gallery data
PSData = @{
# Prerelease string should be here, so we can set it
Prerelease = ''

# Release Notes have to be here, so we can update them
ReleaseNotes = '
A test module
'

# Tags applied to this module. These help with module discovery in online galleries.
Tags = 'Authoring','Build','Development','BestPractices'

# A URL to the license for this module.
LicenseUri = 'https://github.com/PoshCode/ModuleBuilder/blob/master/LICENSE'

# A URL to the main website for this project.
ProjectUri = 'https://github.com/PoshCode/ModuleBuilder'

# A URL to an icon representing this module.
IconUri = 'https://github.com/PoshCode/ModuleBuilder/blob/resources/ModuleBuilder.png?raw=true'
} # End of PSData
} # End of PrivateData

# The main script module that is automatically loaded as part of this module
RootModule = 'Parameters.psm1'

# Modules that must be imported into the global environment prior to importing this module
RequiredModules = @()

# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
DefaultCommandPrefix = 'Param'

# Always define FunctionsToExport as an empty @() which will be replaced on build
FunctionsToExport = @()
AliasesToExport = @()

# ID used to uniquely identify this module
GUID = 'a264e183-e0f7-4219-bc80-c30d14e0e98e'
Description = 'A module for authoring and building PowerShell modules'

# Common stuff for all our modules:
CompanyName = 'PoshCode'
Author = 'Joel Bennett'
Copyright = "Copyright 2024 Joel Bennett"

# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '5.1'
CompatiblePSEditions = @('Core','Desktop')
}
7 changes: 7 additions & 0 deletions Tests/Integration/Parameters/Private/GetFinale.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using module ModuleBuilder

function GetFinale {
[CmdletBinding()]
# [Alias("gf")]
param()
}
1 change: 1 addition & 0 deletions Tests/Integration/Parameters/Private/GetMyAlias.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
New-Alias -Name 'Get-MyAlias' -Value 'Get-ChildItem'
7 changes: 7 additions & 0 deletions Tests/Integration/Parameters/Private/GetPreview.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using module ModuleBuilder

function GetPreview {
[CmdletBinding()]
# [Alias("gp")]
param()
}
13 changes: 13 additions & 0 deletions Tests/Integration/Parameters/Private/TestUnExportedAliases.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function TestUnExportedAliases {
[CmdletBinding()]
param()

New-Alias -Name 'New-NotExportedAlias1' -Value 'Write-Verbose'
Set-Alias -Name 'New-NotExportedAlias2' -Value 'Write-Verbose'
}

New-Alias -Name 'New-NotExportedAlias3' -Value 'Write-Verbose' -Scope Global
Set-Alias -Name 'New-NotExportedAlias4' -Value 'Write-Verbose' -Scope Global

New-Alias -Name 'New-NotExportedAlias5' -Value 'Write-Verbose'
Remove-Alias -Name 'New-NotExportedAlias5'
7 changes: 7 additions & 0 deletions Tests/Integration/Parameters/Public/Get-Source.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using module ModuleBuilder

function Get-Source {
[CmdletBinding()]
[Alias("gs","gsou")]
param()
}
6 changes: 6 additions & 0 deletions Tests/Integration/Parameters/Public/Set-Source.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function Set-Source {
[CmdletBinding()]
[Alias("ss", "ssou")]
param()
"sto͞o′pĭd"
}
7 changes: 7 additions & 0 deletions Tests/Integration/Parameters/build.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@{
Path = "Parameters.psd1"
OutputDirectory = "..\Result3"
SemVer = "3.0.0-alpha001"
Target = "Build"
Passthru = $true
}
Empty file.
54 changes: 39 additions & 15 deletions Tests/Public/Build-Module.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -257,21 +257,28 @@ Describe "Build-Module" {
New-Item -ItemType Directory -Path TestDrive:/MyModule/ -Force
New-Item -ItemType Directory -Path "TestDrive:/Output/MyModule/$ExpectedVersion" -Force

Mock InitializeBuild {
# These are actually all the values that we need
Mock ResolveBuildManifest { "TestDrive:/MyModule/build.psd1" }

Mock GetBuildInfo {
[PSCustomObject]@{
OutputDirectory = "TestDrive:/Output"
Name = "MyModule"
Version = $Version
SourcePath = "TestDrive:/MyModule/"
SemVer = $SemVer
Target = $Target
ModuleBase = "TestDrive:/MyModule/"
CopyPaths = @()
Encoding = "UTF8"
PublicFilter = "Public/*.ps1"
VersionedOutputDirectory = $true
}
}

Mock ImportModuleManifest {
[PSCustomObject]@{
Name = "MyModule"
ModuleBase = "TestDrive:/MyModule/"
}
}

$global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule/$ExpectedVersion"

Mock Get-ChildItem {
Expand Down Expand Up @@ -356,22 +363,31 @@ Describe "Build-Module" {
$global:ExpectedVersion = "1.0.0"
Push-Location TestDrive:/ -StackName BuildModuleTest
New-Item -ItemType Directory -Path TestDrive:/MyModule/ -Force
New-Item -ItemType Directory -Path "TestDrive:/Output/MyModule/$ExpectedVersion" -Force
New-Item -ItemType Directory -Path "TestDrive:/Output/MyModule" -Force

Mock InitializeBuild {
# These are actually all the values that we need
Mock ResolveBuildManifest { "TestDrive:/MyModule/build.psd1" }

Mock GetBuildInfo {
[PSCustomObject]@{
OutputDirectory = "TestDrive:/Output"
Name = "MyModule"
Version = $Version
Target = $Target
ModuleBase = "TestDrive:/MyModule/"
CopyPaths = @()
SourcePath = "TestDrive:/MyModule/"
Version = "1.0.0"
Prerelease = "beta03"
BuildMetadata = "Sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11"
Target = "CleanBuild"
CopyPaths = @()
Encoding = "UTF8"
PublicFilter = "Public/*.ps1"
}
}

Mock ImportModuleManifest {
[PSCustomObject]@{
Name = "MyModule"
ModuleBase = "TestDrive:/MyModule/"
}
}

$global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule"
Mock Get-ChildItem {
[IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1"
Expand Down Expand Up @@ -510,20 +526,28 @@ Describe "Build-Module" {
New-Item -ItemType Directory -Path TestDrive:/MyModule/ -Force
New-Item -ItemType Directory -Path "TestDrive:/$ExpectedVersion/" -Force

Mock InitializeBuild {
Mock GetBuildInfo {
# These are actually all the values that we need
[PSCustomObject]@{
OutputDirectory = "TestDrive:/$Version"
Name = "MyModule"
Version = $Version
PreRelease = $PreRelease
Target = $Target
ModuleBase = "TestDrive:/MyModule/"
SourcePath = "TestDrive:/MyModule/"
CopyPaths = @()
Encoding = "UTF8"
PublicFilter = "Public/*.ps1"
}
}

Mock ImportModuleManifest {
[PSCustomObject]@{
Name = "MyModule"
ModuleBase = "TestDrive:/MyModule/"
}
}

$global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/MyModule/$ExpectedVersion"

Mock Get-ChildItem {
Expand Down

0 comments on commit 0ade8f4

Please sign in to comment.