-
-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathBuild-Module.ps1
More file actions
356 lines (306 loc) · 18.1 KB
/
Build-Module.ps1
File metadata and controls
356 lines (306 loc) · 18.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# This version is for local building
# We need to remove library before we start, as it may contain old files, which will be in use once PSD1 loads
# This is only required for PSPublisModule, as it's the only module that is being built by itself
[CmdletBinding()] param(
[switch] $JsonOnly,
[string] $JsonPath = (Join-Path $PSScriptRoot '../../powerforge.json'),
[ValidateSet('Release', 'Debug')][string] $Configuration = 'Release',
[switch] $NoDotnetBuild,
[string] $ModuleVersion = '3.0.X',
[string] $PreReleaseTag,
[switch] $SignModule,
[switch] $NoSign,
[string] $CertificateThumbprint = '483292C9E317AA13B07BB7A96AE9D1A5ED9E7703',
[switch] $SignIncludeBinaries,
[switch] $SignIncludeInternals,
[switch] $SignIncludeExe,
[string] $DiagnosticsBaselinePath,
[switch] $GenerateDiagnosticsBaseline,
[switch] $UpdateDiagnosticsBaseline,
[switch] $FailOnNewDiagnostics,
[ValidateSet('Warning', 'Error')]
[string] $FailOnDiagnosticsSeverity
)
if (-not $JsonOnly) {
Remove-Item -Path (Join-Path $PSScriptRoot '../Lib') -Recurse -Force -ErrorAction SilentlyContinue
}
$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$moduleRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
$artefactsRoot = Join-Path $moduleRoot 'Artefacts'
$csproj = Join-Path -Path $repoRoot -ChildPath 'PSPublishModule/PSPublishModule.csproj'
$sourceManifest = Join-Path -Path $moduleRoot -ChildPath 'PSPublishModule.psd1'
$sourceLibRoot = Join-Path -Path $moduleRoot -ChildPath 'Lib'
$runtimesText = (dotnet --list-runtimes 2>$null) -join "`n"
$tfm = if ($runtimesText -match '(?m)^Microsoft\\.NETCore\\.App\\s+10\\.') { 'net10.0' } else { 'net8.0' }
$binaryModule = Join-Path -Path $repoRoot -ChildPath ("PSPublishModule/bin/{0}/{1}/PSPublishModule.dll" -f $Configuration, $tfm)
if (-not $JsonOnly -and -not $NoDotnetBuild) {
if (Test-Path -LiteralPath $csproj) {
$i = [char]0x2139 # ℹ
Write-Host "$i Building PSPublishModule ($Configuration)" -ForegroundColor DarkGray
$buildOutput = & dotnet build $csproj -c $Configuration --nologo --verbosity quiet 2>&1
if ($LASTEXITCODE -ne 0) {
$buildOutput | Out-Host
$x = [char]0x274C # ❌
Write-Host "$x dotnet build failed (exit $LASTEXITCODE). Stopping." -ForegroundColor Red
return
}
}
}
# Always reload PSPublishModule from this repo for self-builds. Otherwise an older
# installed/imported module in the caller session can shadow the current source changes.
Get-Module -Name 'PSPublishModule' -All -ErrorAction SilentlyContinue | Remove-Module -Force -ErrorAction SilentlyContinue
$importPath = $null
# Json-only and no-dotnet-build flows should avoid importing the source manifest from Module\Lib.
# Once a PowerShell session loads those repo DLLs on Windows, later self-build attempts cannot
# refresh them in-place. Import the compiled binary module instead for config generation.
$preferBinaryImport = $JsonOnly -or $NoDotnetBuild
if ($preferBinaryImport) {
if (-not (Test-Path -LiteralPath $binaryModule)) {
if (Test-Path -LiteralPath $csproj) {
$i = [char]0x2139 # ℹ
Write-Host "$i Building PSPublishModule ($Configuration)" -ForegroundColor DarkGray
$buildOutput = & dotnet build $csproj -c $Configuration --nologo --verbosity quiet 2>&1
if ($LASTEXITCODE -ne 0) {
$buildOutput | Out-Host
throw "dotnet build failed (exit $LASTEXITCODE)."
}
}
}
if (Test-Path -LiteralPath $binaryModule) {
$importPath = $binaryModule
}
} elseif (Test-Path -LiteralPath $sourceLibRoot) {
# Keep the source-manifest path for regular repo builds where Module\Lib is intentionally populated.
# Build-ModuleSelf now prefers binary import to avoid in-place refreshes of loaded repo DLLs.
$importPath = $sourceManifest
} else {
if (-not (Test-Path -LiteralPath $binaryModule)) {
if (Test-Path -LiteralPath $csproj) {
$i = [char]0x2139 # ℹ
Write-Host "$i Building PSPublishModule ($Configuration)" -ForegroundColor DarkGray
$buildOutput = & dotnet build $csproj -c $Configuration --nologo --verbosity quiet 2>&1
if ($LASTEXITCODE -ne 0) {
$buildOutput | Out-Host
throw "dotnet build failed (exit $LASTEXITCODE)."
}
}
}
if (Test-Path -LiteralPath $binaryModule) {
$importPath = $binaryModule
}
}
if (-not $importPath) {
throw "Invoke-ModuleBuild is not available. Ensure PSPublishModule.dll built and importable."
}
Import-Module $importPath -Force
$invokeModuleBuildCommand = Get-Command Invoke-ModuleBuild -ErrorAction SilentlyContinue
if (-not $invokeModuleBuildCommand -or $invokeModuleBuildCommand.Source -ne 'PSPublishModule') {
throw "Invoke-ModuleBuild did not load from the local PSPublishModule build."
}
$buildParams = @{
ModuleName = 'PSPublishModule'
ExitCode = $true
}
if ($JsonOnly) {
$buildParams.JsonOnly = $true
$buildParams.JsonPath = $JsonPath
}
if ($PSBoundParameters.ContainsKey('DiagnosticsBaselinePath')) { $buildParams.DiagnosticsBaselinePath = $DiagnosticsBaselinePath }
if ($PSBoundParameters.ContainsKey('GenerateDiagnosticsBaseline')) { $buildParams.GenerateDiagnosticsBaseline = $GenerateDiagnosticsBaseline.IsPresent }
if ($PSBoundParameters.ContainsKey('UpdateDiagnosticsBaseline')) { $buildParams.UpdateDiagnosticsBaseline = $UpdateDiagnosticsBaseline.IsPresent }
if ($PSBoundParameters.ContainsKey('FailOnNewDiagnostics')) { $buildParams.FailOnNewDiagnostics = $FailOnNewDiagnostics.IsPresent }
if ($PSBoundParameters.ContainsKey('FailOnDiagnosticsSeverity')) { $buildParams.FailOnDiagnosticsSeverity = $FailOnDiagnosticsSeverity }
Invoke-ModuleBuild @buildParams -Settings {
# Usual defaults as per standard module
$Manifest = [ordered] @{
ModuleVersion = $ModuleVersion
CompatiblePSEditions = @('Desktop', 'Core')
GUID = 'eb76426a-1992-40a5-82cd-6480f883ef4d'
Author = 'Przemyslaw Klys'
CompanyName = 'Evotec'
Copyright = "(c) 2011 - $((Get-Date).Year) Przemyslaw Klys @ Evotec. All rights reserved."
Description = 'Simple project allowing preparing, managing, building and publishing modules to PowerShellGallery'
PowerShellVersion = '5.1'
Tags = @('Windows', 'MacOS', 'Linux', 'Build', 'Module')
IconUri = 'https://evotec.xyz/wp-content/uploads/2019/02/PSPublishModule.png'
ProjectUri = 'https://github.com/EvotecIT/PSPublishModule'
DotNetFrameworkVersion = '4.5.2'
}
if (-not [string]::IsNullOrWhiteSpace($PreReleaseTag)) {
$Manifest.PreReleaseTag = $PreReleaseTag
}
New-ConfigurationManifest @Manifest
# Add standard module dependencies (directly, but can be used with loop as well)
New-ConfigurationModule -Type RequiredModule -Name 'powershellget' -Guid 'Auto' -Version 'Latest'
New-ConfigurationModule -Type RequiredModule -Name 'PSScriptAnalyzer' -Guid 'Auto' -Version 'Latest'
New-ConfigurationModule -Type RequiredModule -Name 'Pester' -Version Auto -Guid Auto
# Do not add inbox Microsoft.PowerShell.* modules as Required/External dependencies.
# They are part of the runtime and publishing them as gallery dependencies breaks
# Save-Module / Install-Module resolution for consumers.
# Add approved modules, that can be used as a dependency, but only when specific function from those modules is used
# And on that time only that function and dependant functions will be copied over
# Keep in mind it has it's limits when "copying" functions such as it should not depend on DLLs or other external files
New-ConfigurationModule -Type ApprovedModule -Name 'PSSharedGoods', 'PSWriteColor', 'Connectimo', 'PSUnifi', 'PSWebToolbox', 'PSMyPassword'
New-ConfigurationModuleSkip -IgnoreModuleName 'PKI', 'OpenAuthenticode' -IgnoreFunctionName @(
# ignore functions from OpenAuthenticode module when used during linux/macos build
'Set-OpenAuthenticodeSignature'
'Get-OpenAuthenticodeSignature'
# ignore functions from Microsoft.PowerShell.Security, as those are not on linux/macos
'Get-AuthenticodeSignature'
'Set-AuthenticodeSignature'
# ignore functions from PKI module when used during linux/macos build
#'Import-PfxCertificate'
# seems to be windows only
'New-FileCatalog'
)
$ConfigurationFormat = [ordered] @{
RemoveComments = $true
RemoveEmptyLines = $true
PlaceOpenBraceEnable = $true
PlaceOpenBraceOnSameLine = $true
PlaceOpenBraceNewLineAfter = $true
PlaceOpenBraceIgnoreOneLineBlock = $false
PlaceCloseBraceEnable = $true
PlaceCloseBraceNewLineAfter = $true
PlaceCloseBraceIgnoreOneLineBlock = $false
PlaceCloseBraceNoEmptyLineBefore = $true
UseConsistentIndentationEnable = $true
UseConsistentIndentationKind = 'space'
UseConsistentIndentationPipelineIndentation = 'IncreaseIndentationAfterEveryPipeline'
UseConsistentIndentationIndentationSize = 4
UseConsistentWhitespaceEnable = $true
UseConsistentWhitespaceCheckInnerBrace = $true
UseConsistentWhitespaceCheckOpenBrace = $true
UseConsistentWhitespaceCheckOpenParen = $true
UseConsistentWhitespaceCheckOperator = $true
UseConsistentWhitespaceCheckPipe = $true
UseConsistentWhitespaceCheckSeparator = $true
AlignAssignmentStatementEnable = $true
AlignAssignmentStatementCheckHashtable = $true
UseCorrectCasingEnable = $true
}
# format PSD1 and PSM1 files when merging into a single file
# enable formatting is not required as Configuration is provided
New-ConfigurationFormat -ApplyTo 'OnMergePSM1', 'OnMergePSD1' -Sort None @ConfigurationFormat
# format PSD1 and PSM1 files within the module
# enable formatting is required to make sure that formatting is applied (with default settings)
New-ConfigurationFormat -ApplyTo 'DefaultPSD1', 'DefaultPSM1' -EnableFormatting -Sort None
# when creating PSD1 use special style without comments and with only required parameters
New-ConfigurationFormat -ApplyTo 'DefaultPSD1', 'OnMergePSD1' -PSD1Style 'Minimal'
# configuration for documentation, at the same time it enables documentation processing
New-ConfigurationDocumentation -Enable:$true -StartClean -UpdateWhenNew -SyncExternalHelpToProjectRoot -PathReadme 'Docs\Readme.md' -Path 'Docs' -AboutTopicsSourcePath 'Help\About'
# quality checks (non-blocking by default; add -FailOn* switches to hard-fail)
$newConfigurationValidationSplat = @{
Enable = $true
StructureSeverity = 'Warning'
DocumentationSeverity = 'Warning'
EnableScriptAnalyzer = $true
ScriptAnalyzerSeverity = 'Warning'
FileIntegritySeverity = 'Warning'
FileIntegrityCheckTrailingWhitespace = $true
FileIntegrityCheckSyntax = $true
}
New-ConfigurationValidation @newConfigurationValidationSplat
$newConfigurationFileConsistencySplat = @{
Enable = $true
RequiredEncoding = 'UTF8BOM'
RequiredLineEnding = 'CRLF'
ExcludeDirectories = 'Build', 'Docs', 'Documentation', 'Examples', 'Tests'
ExportReport = $true
CheckMixedLineEndings = $true
CheckMissingFinalNewline = $true
Scope = 'StagingAndProject'
EncodingOverrides = @{ '*.xml' = 'UTF8' }
}
New-ConfigurationFileConsistency @newConfigurationFileConsistencySplat
$newConfigurationCompatibilitySplat = @{
Enable = $true
RequireCrossCompatibility = $true
MinimumCompatibilityPercentage = 95
ExportReport = $true
}
New-ConfigurationCompatibility @newConfigurationCompatibilitySplat
New-ConfigurationImportModule -ImportSelf
$signEnabled = if ($NoSign.IsPresent) { $false } elseif ($SignModule.IsPresent) { $true } else { $Env:COMPUTERNAME -eq 'EVOMAGIC' }
$newConfigurationBuildSplat = @{
Enable = $true
SignModule = $signEnabled
# DeleteTargetModuleBeforeBuild = $true
MergeModuleOnBuild = $true
CertificateThumbprint = $CertificateThumbprint
#CertificatePFXBase64 = $BasePfx
#CertificatePFXPassword = "zGT"
DoNotAttemptToFixRelativePaths = $false
SkipBuiltinReplacements = $true
# required for Cmdlet/Alias functionality
NETProjectPath = (Join-Path $repoRoot 'PSPublishModule')
ResolveBinaryConflicts = $true
ResolveBinaryConflictsName = 'PSPublishModule'
NETProjectName = 'PSPublishModule'
NETConfiguration = 'Release'
NETFramework = 'net8.0', 'net472'
NETHandleAssemblyWithSameName = $true
#NETDocumentation = $true
DotSourceLibraries = $true
DotSourceClasses = $true
VersionedInstallStrategy = 'AutoRevision' # or 'Exact'
VersionedInstallKeep = 3 # how many versions to retain
InstallMissingModules = $true
KillLockersBeforeInstall = $true
KillLockersForce = $true
}
if ($PSBoundParameters.ContainsKey('SignIncludeBinaries')) {
$newConfigurationBuildSplat.SignIncludeBinaries = $SignIncludeBinaries.IsPresent
}
if ($PSBoundParameters.ContainsKey('SignIncludeInternals')) {
$newConfigurationBuildSplat.SignIncludeInternals = $SignIncludeInternals.IsPresent
}
if ($PSBoundParameters.ContainsKey('SignIncludeExe')) {
$newConfigurationBuildSplat.SignIncludeExe = $SignIncludeExe.IsPresent
}
New-ConfigurationBuild @newConfigurationBuildSplat
New-ConfigurationArtefact -Type Unpacked -Enable -Path (Join-Path $artefactsRoot 'Unpacked/<TagModuleVersionWithPreRelease>') -RequiredModulesPath (Join-Path $artefactsRoot 'Unpacked/<TagModuleVersionWithPreRelease>/Modules') -AddRequiredModules -CopyFiles @{
"Examples\Step01.CreateModuleProject.ps1" = "Examples\Step01.CreateModuleProject.ps1"
"Examples\Step02.BuildModuleOver.ps1" = "Examples\Step02.BuildModuleOver.ps1"
} -CopyFilesRelative
New-ConfigurationArtefact -Type Packed -Enable -Path (Join-Path $artefactsRoot 'PackedWithModules') -IncludeTagName -ID 'ToGitHub' -AddRequiredModules -CopyFiles @{
"Examples\Step01.CreateModuleProject.ps1" = "Examples\Step01.CreateModuleProject.ps1"
"Examples\Step02.BuildModuleOver.ps1" = "Examples\Step02.BuildModuleOver.ps1"
} -CopyFilesRelative -ArtefactName "PSPublishModule.<TagModuleVersionWithPreRelease>-FullPackage.zip"
New-ConfigurationArtefact -Type Packed -Enable -Path (Join-Path $artefactsRoot 'Packed') -IncludeTagName -ID 'ToGitHub' -ArtefactName "PSPublishModule.<TagModuleVersionWithPreRelease>.zip"
New-ConfigurationModuleSkip -IgnoreModuleName 'Microsoft.PowerShell.Utility', 'ActiveDirectory' -IgnoreFunctionName 'Get-ADUser'
# Disabled because PSPublishModule testing itself after build causes multiple module instances
# which breaks InModuleScope tests. The module is tested separately via PSPublishModule.Tests.ps1
#New-ConfigurationTest -TestsPath "$PSScriptRoot\..\Tests" -Enable
# global options for publishing to github/psgallery
# you can use FilePath where APIKey are saved in clear text or use APIKey directly
#New-ConfigurationPublish -Type PowerShellGallery -FilePath 'C:\Support\Important\PowerShellGalleryAPI.txt' -Enabled:$true
#New-ConfigurationPublish -Type GitHub -FilePath 'C:\Support\Important\GitHubAPI.txt' -UserName 'EvotecIT' -Enabled:$true -ID 'ToGitHub' -OverwriteTagName '<TagModuleVersionWithPreRelease>' -GenerateReleaseNotes
### FOR TESTING PURPOSES ONLY ###
### SHOWING HOW THINGS WORK HERE ###
#New-ConfigurationArtefact -Type Packed -Enable -Path "$PSScriptRoot\..\Artefacts\Packed2" -IncludeTagName -ID 'Packed2'
#New-ConfigurationArtefact -Type Packed -Enable -Path "$PSScriptRoot\..\Artefacts\Packed1" -IncludeTagName
# those 2 are only useful for testing purposes
# New-ConfigurationArtefact -Type Script -Enable -Path "$PSScriptRoot\..\Artefacts\Script" -IncludeTagName {
# # Lets test this, this will be added in the bottom of the script
# Invoke-ModuleBuilder
# } -ID 'ToGitHubAsScript'
# New-ConfigurationArtefact -Type ScriptPacked -Enable -Path "$PSScriptRoot\..\Artefacts\ScriptPacked" -ArtefactName "Script-<ModuleName>-$((Get-Date).ToString('yyyy-MM-dd')).zip" {
# Invoke-ModuleBuilder
# } -PreScriptMerge {
# # Lets test this
# param (
# [int]$Mode
# )
# } -ScriptName 'Invoke-ModuleBuilder.ps1'
# New-ConfigurationArtefact -Type Script -Enable -Path "$PSScriptRoot\..\Artefacts\Script" {
# Invoke-ModuleBuilder
# } -PreScriptMerge {
# # Lets test this
# param (
# [int]$Mode
# )
# } -ScriptName 'Invoke-ModuleBuilder.ps1'
#New-ConfigurationPublish -Type GitHub -FilePath 'C:\Support\Important\GitHubAPI.txt' -UserName 'EvotecIT' -Enabled:$true -ID 'ToGitHubWithoutModules' -OverwriteTagName 'v1.8.0-Preview1'
#New-ConfigurationPublish -Type GitHub -FilePath 'C:\Support\Important\GitHubAPI.txt' -UserName 'EvotecIT' -Enabled:$true -ID 'ToGitHubAsScript'
}