From dcb3f40371e32a258311d1720f74a242817f6400 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Sun, 25 Mar 2018 15:39:30 -0700 Subject: [PATCH 01/44] Initial commit --- BuildTasks/Analyze.Task.ps1 | 17 +++++ BuildTasks/BuildManifest.Task.ps1 | 103 +++++++++++++++++++++++++++ BuildTasks/BuildModule.Task.ps1 | 91 +++++++++++++++++++++++ BuildTasks/Clean.Task.ps1 | 9 +++ BuildTasks/Copy.Task.ps1 | 23 ++++++ BuildTasks/FullTests.Task.ps1 | 25 +++++++ BuildTasks/GenerateHelp.Task.ps1 | 23 ++++++ BuildTasks/GenerateMarkdown.Task.ps1 | 41 +++++++++++ BuildTasks/ImportDevModule.Task.ps1 | 20 ++++++ BuildTasks/ImportModule.Task.ps1 | 19 +++++ BuildTasks/Install.Task.ps1 | 21 ++++++ BuildTasks/InvokeBuildInit.ps1 | 9 +++ BuildTasks/Uninstall.Task.ps1 | 28 ++++++++ BuildTasks/UpdateSource.Task.ps1 | 3 + 14 files changed, 432 insertions(+) create mode 100644 BuildTasks/Analyze.Task.ps1 create mode 100644 BuildTasks/BuildManifest.Task.ps1 create mode 100644 BuildTasks/BuildModule.Task.ps1 create mode 100644 BuildTasks/Clean.Task.ps1 create mode 100644 BuildTasks/Copy.Task.ps1 create mode 100644 BuildTasks/FullTests.Task.ps1 create mode 100644 BuildTasks/GenerateHelp.Task.ps1 create mode 100644 BuildTasks/GenerateMarkdown.Task.ps1 create mode 100644 BuildTasks/ImportDevModule.Task.ps1 create mode 100644 BuildTasks/ImportModule.Task.ps1 create mode 100644 BuildTasks/Install.Task.ps1 create mode 100644 BuildTasks/InvokeBuildInit.ps1 create mode 100644 BuildTasks/Uninstall.Task.ps1 create mode 100644 BuildTasks/UpdateSource.Task.ps1 diff --git a/BuildTasks/Analyze.Task.ps1 b/BuildTasks/Analyze.Task.ps1 new file mode 100644 index 0000000..73825e3 --- /dev/null +++ b/BuildTasks/Analyze.Task.ps1 @@ -0,0 +1,17 @@ +task Analyze { + $params = @{ + IncludeDefaultRules = $true + Path = $ManifestPath + Settings = "$BuildRoot\ScriptAnalyzerSettings.psd1" + Severity = 'Warning' + } + + "Analyzing $ManifestPath..." + $results = Invoke-ScriptAnalyzer @params + if ($results) + { + 'One or more PSScriptAnalyzer errors/warnings were found.' + 'Please investigate or add the required SuppressMessage attribute.' + $results | Format-Table -AutoSize + } +} diff --git a/BuildTasks/BuildManifest.Task.ps1 b/BuildTasks/BuildManifest.Task.ps1 new file mode 100644 index 0000000..755d3f1 --- /dev/null +++ b/BuildTasks/BuildManifest.Task.ps1 @@ -0,0 +1,103 @@ + +taskx BuildManifest @{ + Inputs = (Get-ChildItem -Path $Source -Recurse -File) + Outputs = $ManifestPath + Jobs = { + "Updating [$ManifestPath]..." + Copy-Item -Path "$Source\$ModuleName.psd1" -Destination $ManifestPath + + $functions = Get-ChildItem -Path "$ModuleName\Public\*.ps1" -ErrorAction 'Ignore' | + Where-Object 'Name' -notmatch 'Tests' + + if ($functions) + { + 'Setting FunctionsToExport...' + Set-ModuleFunctions -Name $ManifestPath -FunctionsToExport $functions.BaseName + } + + 'Detecting semantic versioning...' + "Importing Module [$ManifestPath]..." + Import-Module -FullyQualifiedName $ManifestPath + + "Get-Command -Module [$ModuleName]..." + $commands = Get-Command -Module $ModuleName + + "Removing Module [$ModuleName]..." + Remove-Module -Name $ModuleName -Force + + 'Calculating fingerprint...' + $fingerprint = foreach ($command in $commands) + { + foreach ($parameter in $command.Parameters.Keys) + { + '{0}:{1}' -f $command.Name, $command.Parameters[$parameter].Name + foreach ($alias in $command.Parameters[$parameter].Aliases) + { + '{0}:{1}' -f $command.Name, $alias + } + } + } + + $fingerprint = $fingerprint | Sort-Object + + if (Test-Path -Path '.\fingerprint') + { + $oldFingerprint = Get-Content -Path '.\fingerprint' + } + + $bumpVersionType = 'Patch' + + 'Detecting new features...' + $features = $fingerprint | + Where-Object { $_ -notin $oldFingerprint } + + foreach ($feature in $features) + { + $feature + $bumpVersionType = 'Minor' + } + + 'Detecting breaking changes...' + $breakingChanges = $oldFingerprint | + Where-Object { $_ -notin $fingerprint } + + foreach ($breakingChange in $breakingChanges) + { + $breakingChange + $bumpVersionType = 'Major' + } + + Set-Content -Path '.\fingerprint' -Value $fingerprint + + # Bump the module version + $version = [version] (Get-Metadata -Path $manifestPath -PropertyName 'ModuleVersion') + + if ($version -lt ([version] '1.0.0')) + { + "Module is still in beta; don't bump major version." + if ($bumpVersionType -eq 'Major') + { + $bumpVersionType = 'Minor' + } + else + { + $bumpVersionType = 'Patch' + } + } + + "Stepping [$bumpVersionType] version [$version]..." + $version = [version] (Step-Version -Version $version -Type $bumpVersionType) + + $build = 0 + if ($null -ne $env:Build_BuildID) + { + $build = $env:Build_BuildID + } + + $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) + "Using version [$version]..." + "##vso[build.updatebuildnumber]$version" + + Update-Metadata -Path $ManifestPath -PropertyName 'ModuleVersion' -Value $version + } +} diff --git a/BuildTasks/BuildModule.Task.ps1 b/BuildTasks/BuildModule.Task.ps1 new file mode 100644 index 0000000..b55e961 --- /dev/null +++ b/BuildTasks/BuildModule.Task.ps1 @@ -0,0 +1,91 @@ + +function Import-ClassOrder +{ + [cmdletbinding()] + param($cName,$Map) + Write-Verbose "Checking on [$cName]" + if($Map.ContainsKey($cName) -and $Map[$cName].Imported -ne $true) + { + if($Map[$cName].Base) + { + Write-Verbose " Base class [$($Map[$cName].Base)]" + Import-ClassOrder $Map[$cName].Base $Map + } + $cPath = $Map[$cName].Path + Write-Verbose "Dot Sourcing [$cPath]" + $cPath + $Map[$cName].Imported = $true + } +} + +taskx BuildModule @{ + Inputs = (Get-ChildItem -Path $Source -Recurse -Filter *.ps1) + Outputs = $ModulePath + Jobs = { + $sb = [Text.StringBuilder]::new() + $null = $sb.AppendLine('$Script:PSModuleRoot = $PSScriptRoot') + + # Class importer + $root = Join-Path -Path $source -ChildPath 'Classes' + "Load classes from [$root]" + $classFiles = Get-ChildItem -Path $root -Filter '*.ps1' -Recurse | + Where-Object Name -notlike '*.Tests.ps1' + + $classes = @{} + + foreach($file in $classFiles) + { + $name = $file.BaseName + $classes[$name] = @{ + Name = $name + Path = $file.FullName + } + $data = Get-Content $file.fullname + foreach($line in $data) + { + if($line -match "class\s+($Name)\s*:\s*(?\w*)") + { + $classes[$name].Base = $Matches.baseclass + } + } + } + + $importOrder = foreach($className in $classes.Keys) + { + Import-ClassOrder $className $classes + } + + foreach($class in $importOrder) + { + "Importing [$class]..." + $null = $sb.AppendLine("# .$class") + $null = $sb.AppendLine([IO.File]::ReadAllText($class)) + } + + foreach ($folder in ($Folders -ne 'Classes')) + { + if (Test-Path -Path "$Source\$folder") + { + $null = $sb.AppendLine("# Importing from [$Source\$folder]") + $files = Get-ChildItem -Path "$Source\$folder\*.ps1" | + Where-Object 'Name' -notlike '*.Tests.ps1' + + foreach ($file in $files) + { + $name = $file.Fullname.Replace($buildroot, '') + + "Importing [$($file.FullName)]..." + $null = $sb.AppendLine("# .$name") + $null = $sb.AppendLine([IO.File]::ReadAllText($file.FullName)) + } + } + } + + "Creating Module [$ModulePath]..." + $null = New-Item -Path (Split-path $ModulePath) -ItemType Directory -ErrorAction SilentlyContinue -Force + Set-Content -Path $ModulePath -Value $sb.ToString() -Encoding 'UTF8' + + 'Moving "#Requires" statements and "using" directives...' + Move-Statement -Path $ModulePath -Type 'Comment', 'Keyword' -Token '#Requires', 'using' -Index 0 + } +} diff --git a/BuildTasks/Clean.Task.ps1 b/BuildTasks/Clean.Task.ps1 new file mode 100644 index 0000000..59b3ebf --- /dev/null +++ b/BuildTasks/Clean.Task.ps1 @@ -0,0 +1,9 @@ +task Clean { + 'Cleaning Output files...' + $null = Get-ChildItem -Path $Output -File -Recurse | + Remove-Item -Force -ErrorAction 'Ignore' + + 'Cleaning Output directories...' + $null = Get-ChildItem -Path $Output -Directory -Recurse | + Remove-Item -Recurse -Force -ErrorAction 'Ignore' +} diff --git a/BuildTasks/Copy.Task.ps1 b/BuildTasks/Copy.Task.ps1 new file mode 100644 index 0000000..9a43b8e --- /dev/null +++ b/BuildTasks/Copy.Task.ps1 @@ -0,0 +1,23 @@ + +task Copy { + "Creating Directory [$Destination]..." + $null = New-Item -ItemType 'Directory' -Path $Destination -ErrorAction 'Ignore' + + $files = Get-ChildItem -Path $Source -File | + Where-Object 'Name' -notmatch "$ModuleName\.ps[dm]1" + + foreach ($file in $files) + { + 'Creating [.{0}]...' -f $file.FullName.Replace($buildroot, '') + Copy-Item -Path $file.FullName -Destination $Destination -Force + } + + $directories = Get-ChildItem -Path $Source -Directory | + Where-Object 'Name' -notin $Folders + + foreach ($directory in $directories) + { + 'Creating [.{0}]...' -f $directory.FullName.Replace($buildroot, '') + Copy-Item -Path $directory.FullName -Destination $Destination -Recurse -Force + } +} diff --git a/BuildTasks/FullTests.Task.ps1 b/BuildTasks/FullTests.Task.ps1 new file mode 100644 index 0000000..ac4ccfa --- /dev/null +++ b/BuildTasks/FullTests.Task.ps1 @@ -0,0 +1,25 @@ +task FullTests { + $params = @{ + CodeCoverage = 'Output\*\*.psm1' + CodeCoverageOutputFile = 'Output\codecoverage.xml' + OutputFile = $testFile + OutputFormat = 'NUnitXml' + PassThru = $true + Path = 'Tests' + Show = 'Failed', 'Fails', 'Summary' + Tag = 'Build' + } + + $results = Invoke-Pester @params + if ($results.FailedCount -gt 0) + { + Write-Error -Message "Failed [$($results.FailedCount)] Pester tests." + } + + $requiredPercent = 0.70 + $codeCoverage = $results.codecoverage.NumberOfCommandsExecuted / $results.codecoverage.NumberOfCommandsAnalyzed + if($codeCoverage -lt $requiredPercent) + { + Write-Error ("Failed Code Coverage [{0:P}] below {1:P}" -f $codeCoverage,$requiredPercent) + } +} diff --git a/BuildTasks/GenerateHelp.Task.ps1 b/BuildTasks/GenerateHelp.Task.ps1 new file mode 100644 index 0000000..51d3a36 --- /dev/null +++ b/BuildTasks/GenerateHelp.Task.ps1 @@ -0,0 +1,23 @@ + +task GenerateHelp { + if (-not(Get-ChildItem -Path $DocsPath -Filter '*.md' -Recurse -ErrorAction 'Ignore')) + { + "No Markdown help files to process. Skipping help file generation..." + return + } + + $locales = (Get-ChildItem -Path $DocsPath -Directory).Name + foreach ($locale in $locales) + { + $params = @{ + ErrorAction = 'SilentlyContinue' + Force = $true + OutputPath = "$Destination\en-US" + Path = "$DocsPath\en-US" + } + + # Generate the module's primary MAML help file. + "Creating new External help for [$ModuleName]..." + $null = New-ExternalHelp @params + } +} diff --git a/BuildTasks/GenerateMarkdown.Task.ps1 b/BuildTasks/GenerateMarkdown.Task.ps1 new file mode 100644 index 0000000..c1181ec --- /dev/null +++ b/BuildTasks/GenerateMarkdown.Task.ps1 @@ -0,0 +1,41 @@ + +task GenerateMarkdown { + $module = Import-Module -FullyQualifiedName $ManifestPath -Force -PassThru + + try + { + if ($module.ExportedFunctions.Count -eq 0) + { + 'No functions have been exported for this module. Skipping Markdown generation...' + return + } + + if (Get-ChildItem -Path $DocsPath -Filter '*.md' -Recurse) + { + $items = Get-ChildItem -Path $DocsPath -Directory -Recurse + foreach ($item in $items) + { + "Updating Markdown help in [$($item.BaseName)]..." + $null = Update-MarkdownHelp -Path $item.FullName -AlphabeticParamsOrder + } + } + + $params = @{ + AlphabeticParamsOrder = $true + ErrorAction = 'SilentlyContinue' + Locale = 'en-US' + Module = $ModuleName + OutputFolder = "$DocsPath\en-US" + WithModulePage = $true + } + + # ErrorAction is set to SilentlyContinue so this + # command will not overwrite an existing Markdown file. + "Creating new Markdown help for [$ModuleName]..." + $null = New-MarkdownHelp @params + } + finally + { + Remove-Module -Name $ModuleName + } +} diff --git a/BuildTasks/ImportDevModule.Task.ps1 b/BuildTasks/ImportDevModule.Task.ps1 new file mode 100644 index 0000000..f4271fc --- /dev/null +++ b/BuildTasks/ImportDevModule.Task.ps1 @@ -0,0 +1,20 @@ + +task ImportDevModule { + + if (-not(Test-Path -Path "$Source\$ModuleName.psd1")) + { + "Module [$ModuleName] is not built; cannot find [$Source\$ModuleName.psd1]." + Write-Error -Message "Could not find module manifest [$Source\$ModuleName.psd1]." + } + else + { + if (Get-Module -Name $ModuleName) + { + "Unloading Module [$ModuleName] from a previous import..." + Remove-Module -Name $ModuleName + } + + "Importing Module [$ModuleName] from [$Source\$ModuleName.psd1]..." + Import-Module -FullyQualifiedName "$Source\$ModuleName.psd1" -Force + } +} diff --git a/BuildTasks/ImportModule.Task.ps1 b/BuildTasks/ImportModule.Task.ps1 new file mode 100644 index 0000000..1017e6b --- /dev/null +++ b/BuildTasks/ImportModule.Task.ps1 @@ -0,0 +1,19 @@ + +task ImportModule { + if (-not(Test-Path -Path $ManifestPath)) + { + "Module [$ModuleName] is not built; cannot find [$ManifestPath]." + Write-Error -Message "Could not find module manifest [$ManifestPath]. You may need to build the module first." + } + else + { + if (Get-Module -Name $ModuleName) + { + "Unloading Module [$ModuleName] from a previous import..." + Remove-Module -Name $ModuleName + } + + "Importing Module [$ModuleName] from [$ManifestPath]..." + Import-Module -FullyQualifiedName $ManifestPath -Force + } +} diff --git a/BuildTasks/Install.Task.ps1 b/BuildTasks/Install.Task.ps1 new file mode 100644 index 0000000..1727f86 --- /dev/null +++ b/BuildTasks/Install.Task.ps1 @@ -0,0 +1,21 @@ + +task Install Uninstall, { + $version = [version] (Get-Metadata -Path $manifestPath -PropertyName 'ModuleVersion') + + $path = $env:PSModulePath.Split(';').Where({ + $_ -like 'C:\Users\*' + }, 'First', 1) + + if ($path -and (Test-Path -Path $path)) + { + "Using [$path] as base path..." + $path = Join-Path -Path $path -ChildPath $ModuleName + $path = Join-Path -Path $path -ChildPath $version + + "Creating directory at [$path]..." + New-Item -Path $path -ItemType 'Directory' -Force -ErrorAction 'Ignore' + + "Copying items from [$Destination] to [$path]..." + Copy-Item -Path "$Destination\*" -Destination $path -Recurse -Force + } +} diff --git a/BuildTasks/InvokeBuildInit.ps1 b/BuildTasks/InvokeBuildInit.ps1 new file mode 100644 index 0000000..1972500 --- /dev/null +++ b/BuildTasks/InvokeBuildInit.ps1 @@ -0,0 +1,9 @@ +$Script:DocsPath = Join-Path -Path $BuildRoot -ChildPath 'Docs' +$Script:Output = Join-Path -Path $BuildRoot -ChildPath 'Output' +$Script:Source = Join-Path -Path $BuildRoot -ChildPath $ModuleName +$Script:Destination = Join-Path -Path $Output -ChildPath $ModuleName +$Script:ManifestPath = Join-Path -Path $Destination -ChildPath "$ModuleName.psd1" +$Script:ModulePath = Join-Path -Path $Destination -ChildPath "$ModuleName.psm1" +$Script:Folders = 'Classes', 'Includes', 'Internal', 'Private', 'Public', 'Resources' +$Script:TestFile = "$BuildRoot\Output\TestResults_PS$PSVersion`_$TimeStamp.xml" +function taskx($Name, $Parameters) { task $Name @Parameters -Source $MyInvocation } diff --git a/BuildTasks/Uninstall.Task.ps1 b/BuildTasks/Uninstall.Task.ps1 new file mode 100644 index 0000000..2bb4346 --- /dev/null +++ b/BuildTasks/Uninstall.Task.ps1 @@ -0,0 +1,28 @@ + +task Uninstall { + 'Unloading Modules...' + Get-Module -Name $ModuleName -ErrorAction 'Ignore' | Remove-Module + + 'Uninstalling Module packages...' + $modules = Get-Module $ModuleName -ErrorAction 'Ignore' -ListAvailable + foreach ($module in $modules) + { + Uninstall-Module -Name $module.Name -RequiredVersion $module.Version -ErrorAction 'Ignore' + } + + 'Cleaning up manually installed Modules...' + $path = $env:PSModulePath.Split(';').Where({ + $_ -like 'C:\Users\*' + }, 'First', 1) + + $path = Join-Path -Path $path -ChildPath $ModuleName + if ($path -and (Test-Path -Path $path)) + { + 'Removing files... (This may fail if any DLLs are in use.)' + Get-ChildItem -Path $path -File -Recurse | + Remove-Item -Force | ForEach-Object 'FullName' + + 'Removing folders... (This may fail if any DLLs are in use.)' + Remove-Item $path -Recurse -Force + } +} diff --git a/BuildTasks/UpdateSource.Task.ps1 b/BuildTasks/UpdateSource.Task.ps1 new file mode 100644 index 0000000..730ab9a --- /dev/null +++ b/BuildTasks/UpdateSource.Task.ps1 @@ -0,0 +1,3 @@ +task UpdateSource { + Copy-Item -Path $ManifestPath -Destination "$Source\$ModuleName.psd1" +} From 4c9a8ce7743538f4f55a5b9e58808f900abe8938 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Sat, 14 Jul 2018 10:46:17 -0700 Subject: [PATCH 02/44] add support for dynamic parameters --- BuildTasks/BuildManifest.Task.ps1 | 3 +++ BuildTasks/ImportDevModule.Task.ps1 | 5 +++-- BuildTasks/ImportModule.Task.ps1 | 5 +++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/BuildTasks/BuildManifest.Task.ps1 b/BuildTasks/BuildManifest.Task.ps1 index 755d3f1..7f6f286 100644 --- a/BuildTasks/BuildManifest.Task.ps1 +++ b/BuildTasks/BuildManifest.Task.ps1 @@ -30,10 +30,13 @@ taskx BuildManifest @{ { foreach ($parameter in $command.Parameters.Keys) { + if($false -eq $command.Parameters[$parameter].IsDynamic) + { '{0}:{1}' -f $command.Name, $command.Parameters[$parameter].Name foreach ($alias in $command.Parameters[$parameter].Aliases) { '{0}:{1}' -f $command.Name, $alias + } } } } diff --git a/BuildTasks/ImportDevModule.Task.ps1 b/BuildTasks/ImportDevModule.Task.ps1 index f4271fc..c852471 100644 --- a/BuildTasks/ImportDevModule.Task.ps1 +++ b/BuildTasks/ImportDevModule.Task.ps1 @@ -8,10 +8,11 @@ task ImportDevModule { } else { - if (Get-Module -Name $ModuleName) + $loaded = Get-Module -Name $ModuleName -All + if ($loaded) { "Unloading Module [$ModuleName] from a previous import..." - Remove-Module -Name $ModuleName + $loaded | Remove-Module -Force } "Importing Module [$ModuleName] from [$Source\$ModuleName.psd1]..." diff --git a/BuildTasks/ImportModule.Task.ps1 b/BuildTasks/ImportModule.Task.ps1 index 1017e6b..dfe72c6 100644 --- a/BuildTasks/ImportModule.Task.ps1 +++ b/BuildTasks/ImportModule.Task.ps1 @@ -7,10 +7,11 @@ task ImportModule { } else { - if (Get-Module -Name $ModuleName) + $loaded = Get-Module -Name $ModuleName -All + if ($loaded) { "Unloading Module [$ModuleName] from a previous import..." - Remove-Module -Name $ModuleName + $loaded | Remove-Module -Force } "Importing Module [$ModuleName] from [$ManifestPath]..." From 03f56638949361c01b547596fed25e74fb7e1d5c Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Sat, 14 Jul 2018 11:06:31 -0700 Subject: [PATCH 03/44] Adjust code coverage --- BuildTasks/FullTests.Task.ps1 | 2 +- Module.build.ps1 | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Module.build.ps1 diff --git a/BuildTasks/FullTests.Task.ps1 b/BuildTasks/FullTests.Task.ps1 index ac4ccfa..28f9e7a 100644 --- a/BuildTasks/FullTests.Task.ps1 +++ b/BuildTasks/FullTests.Task.ps1 @@ -16,7 +16,7 @@ task FullTests { Write-Error -Message "Failed [$($results.FailedCount)] Pester tests." } - $requiredPercent = 0.70 + $requiredPercent = $Script:CodeCoveragePercent $codeCoverage = $results.codecoverage.NumberOfCommandsExecuted / $results.codecoverage.NumberOfCommandsAnalyzed if($codeCoverage -lt $requiredPercent) { diff --git a/Module.build.ps1 b/Module.build.ps1 new file mode 100644 index 0000000..f67806e --- /dev/null +++ b/Module.build.ps1 @@ -0,0 +1,12 @@ +$Script:ModuleName = 'LDTestFramework' +$Script:CodeCoveragePercent = 0.0 # 0 to 1 +. $psscriptroot\BuildTasks\InvokeBuildInit.ps1 + +task Default Build, Test, UpdateSource +task Build Copy, BuildModule, BuildManifest, Helpify +task Helpify GenerateMarkdown, GenerateHelp +task Test Build, ImportModule, FullTests + +Write-Host 'Import common tasks' +Get-ChildItem -Path $buildroot\BuildTasks\*.Task.ps1 | + ForEach-Object {Write-Host $_.FullName;. $_.FullName} From 01a9c11c8b906d48819d7fb2eb611e699de048b6 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Sat, 14 Jul 2018 11:09:41 -0700 Subject: [PATCH 04/44] make module name dynamic --- Module.build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Module.build.ps1 b/Module.build.ps1 index f67806e..b5f93b2 100644 --- a/Module.build.ps1 +++ b/Module.build.ps1 @@ -1,4 +1,4 @@ -$Script:ModuleName = 'LDTestFramework' +$Script:ModuleName = Split-Path -Leaf $PSScriptRoot $Script:CodeCoveragePercent = 0.0 # 0 to 1 . $psscriptroot\BuildTasks\InvokeBuildInit.ps1 From d26917f9af3d376f15f795b3cc858e53edafdcbc Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Sat, 14 Jul 2018 11:17:09 -0700 Subject: [PATCH 05/44] Add all other common module files --- .gitignore | 43 +++++++++++++++ .vscode/settings.json | 25 +++++++++ .vscode/tasks.json | 95 ++++++++++++++++++++++++++++++++++ ScriptAnalyzerSettings.psd1 | 34 ++++++++++++ Tests/Project/Help.Tests.ps1 | 32 ++++++++++++ Tests/Project/Module.Tests.ps1 | 44 ++++++++++++++++ build.ps1 | 35 +++++++++++++ 7 files changed, 308 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 ScriptAnalyzerSettings.psd1 create mode 100644 Tests/Project/Help.Tests.ps1 create mode 100644 Tests/Project/Module.Tests.ps1 create mode 100644 build.ps1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..83762c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +/output/ +debug*.ps1 +temp*.ps1 + +# Most of these heavily cannibalized by Travis Drake from https://gist.github.com/kmorcinek/2710267 + +# C# VS build detritus +/.vs/ +/*/[Bb]in/ +/*/[Oo]bj/ +**/packages/* + +# Except this, this needs to be checked in when present +!**/packages/build/ + +# More C# / Visual Studio detritus +*.suo +*.user +*.sln.docstates +*.psess +*.vsp +*.vspx +project.lock.json +_UpgradeReport_Files/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SASS Compiler cache +.sass-cache + +# Mac OS stuff +.DS_Store* +Icon? + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e8caa5d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,25 @@ +// Place your settings in this file to overwrite default and user settings. +{ + //-------- Editor configuration -------- + "editor.insertSpaces": true, + "editor.tabSize": 4, + + //-------- Files configuration -------- + "files.autoGuessEncoding": false, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + + //-------- PowerShell configuration -------- + "powershell.codeFormatting.alignPropertyValuePairs": true, + "powershell.codeFormatting.preset": "Allman", + "powershell.scriptAnalysis.settingsPath": "./ScriptAnalyzerSettings.psd1", + + //-------- Language configuration -------- + "[json]": { + "editor.tabSize": 2 + }, + + "[xml]": { + "editor.tabSize": 2 + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..8845dfa --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,95 @@ +// Available variables which can be used inside of strings: +// ${workspaceRoot}: The root folder of the team +// ${file}: The current opened file +// ${relativeFile}: The current opened file relative to workspaceRoot +// ${fileBasename}: The current opened file's basename +// ${fileDirname}: The current opened file's dirname +// ${fileExtname}: The current opened file's extension +// ${cwd}: The current working directory of the spawned process +{ + "version": "2.0.0", + "windows": { + "options": { + "shell": { + "executable": "powershell.exe", + "args": [ "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command" ] + } + } + }, + "linux": { + "options": { + "shell": { + "executable": "/usr/bin/pwsh", + "args": [ "-NoProfile", "-Command" ] + } + } + }, + "osx": { + "options": { + "shell": { + "executable": "/usr/local/bin/pwsh", + "args": [ "-NoProfile", "-Command" ] + } + } + }, + "tasks": [ + { + "label": "Default", + "type": "shell", + "problemMatcher": [ "$msCompile" ], + "group": { + "kind": "build", + "isDefault": true + }, + "command": "Invoke-Build -Task Default -File './Module.build.ps1'" + }, + { + "label": "Analyze", + "type": "shell", + "problemMatcher": [ "$msCompile" ], + "command": "Invoke-Build -Task Analyze -File './Module.build.ps1'" + }, + { + "label": "Build", + "type": "shell", + "problemMatcher": [ "$msCompile" ], + "command": "Invoke-Build -Task Build -File './Module.build.ps1'" + }, + { + "label": "Clean", + "type": "shell", + "problemMatcher": [ "$msCompile" ], + "command": "Invoke-Build -Task Clean -File './Module.build.ps1'" + }, + { + "label": "Helpify", + "type": "shell", + "problemMatcher": [ "$msCompile" ], + "command": "Invoke-Build -Task Helpify -File './Module.build.ps1'" + }, + { + "label": "Install", + "type": "shell", + "problemMatcher": [ "$msCompile" ], + "command": "Invoke-Build -Task Install -File './Module.build.ps1'" + }, + { + "label": "Test", + "type": "shell", + "problemMatcher": [ "$msCompile" ], + "command": "Invoke-Build -Task Test -File './Module.build.ps1'" + }, + { + "label": "Uninstall", + "type": "shell", + "problemMatcher": [ "$msCompile" ], + "command": "Invoke-Build -Task Uninstall -File './Module.build.ps1'" + }, + { + "label": "?", + "type": "shell", + "problemMatcher": [], + "command": "Invoke-Build -Task ? -File './Module.build.ps1'" + } + ] +} diff --git a/ScriptAnalyzerSettings.psd1 b/ScriptAnalyzerSettings.psd1 new file mode 100644 index 0000000..c338b30 --- /dev/null +++ b/ScriptAnalyzerSettings.psd1 @@ -0,0 +1,34 @@ +@{ + # Use Severity when you want to limit the generated diagnostic records to a + # subset of: Error, Warning and Information. + # Uncomment the following line if you only want Errors and Warnings but + # not Information diagnostic records. + Severity = @('Error','Warning') + + # Use IncludeRules when you want to run only a subset of the default rule set. + #IncludeRules = @('PSAvoidDefaultValueSwitchParameter', + # 'PSMisleadingBacktick', + # 'PSMissingModuleManifestField', + # 'PSReservedCmdletChar', + # 'PSReservedParams', + # 'PSShouldProcess', + # 'PSUseApprovedVerbs', + # 'PSUseDeclaredVarsMoreThanAssigments') + + # Use ExcludeRules when you want to run most of the default set of rules except + # for a few rules you wish to "exclude". Note: if a rule is in both IncludeRules + # and ExcludeRules, the rule will be excluded. + #ExcludeRules = @('PSAvoidUsingWriteHost') + + # You can use the following entry to supply parameters to rules that take parameters. + # For instance, the PSAvoidUsingCmdletAliases rule takes a whitelist for aliases you + # want to allow. + Rules = @{ + # Do not flag 'cd' alias. + PSAvoidUsingCmdletAliases = @{Whitelist = @('Where','Select')} + + # Check if your script uses cmdlets that are compatible on PowerShell Core, + # version 6.0.0-alpha, on Linux. + # PSUseCompatibleCmdlets = @{Compatibility = @("core-6.0.0-alpha-linux")} + } +} \ No newline at end of file diff --git a/Tests/Project/Help.Tests.ps1 b/Tests/Project/Help.Tests.ps1 new file mode 100644 index 0000000..2ec5c0f --- /dev/null +++ b/Tests/Project/Help.Tests.ps1 @@ -0,0 +1,32 @@ +$Script:ModuleName = 'LDTestFramework' +$Script:ModuleRoot = Split-Path -Path $PSScriptRoot -Parent + +Describe "Public commands have comment-based or external help" -Tags 'Build' { + $functions = Get-Command -Module $ModuleName + $help = foreach ($function in $functions) { + Get-Help -Name $function.Name + } + + foreach ($node in $help) + { + Context $node.Name { + It "Should have a Description or Synopsis" -Pending { + ($node.Description + $node.Synopsis) | Should Not BeNullOrEmpty + } + + It "Should have an Example" -Pending { + $node.Examples | Should Not BeNullOrEmpty + } + + foreach ($parameter in $node.Parameters.Parameter) + { + if ($parameter -notmatch 'WhatIf|Confirm') + { + It "Should have a Description for Parameter [$($parameter.Name)]" -Pending { + $parameter.Description.Text | Should Not BeNullOrEmpty + } + } + } + } + } +} diff --git a/Tests/Project/Module.Tests.ps1 b/Tests/Project/Module.Tests.ps1 new file mode 100644 index 0000000..8a75a66 --- /dev/null +++ b/Tests/Project/Module.Tests.ps1 @@ -0,0 +1,44 @@ +$Script:ModuleName = 'LDTestFramework' +$Script:ModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent +$Script:SourceRoot = Join-Path -Path $ModuleRoot -ChildPath $ModuleName + +Describe "All commands pass PSScriptAnalyzer rules" -Tag 'Build' { + $rules = "$ModuleRoot\ScriptAnalyzerSettings.psd1" + $scripts = Get-ChildItem -Path $SourceRoot -Include '*.ps1', '*.psm1', '*.psd1' -Recurse | + Where-Object FullName -notmatch 'Classes' + + foreach ($script in $scripts) + { + Context $script.FullName { + $results = Invoke-ScriptAnalyzer -Path $script.FullName -Settings $rules + if ($results) + { + foreach ($rule in $results) + { + It $rule.RuleName -Pending { + $message = "{0} Line {1}: {2}" -f $rule.Severity, $rule.Line, $rule.Message + $message | Should Be "" + } + } + } + else + { + It "Should not fail any rules" { + $results | Should BeNullOrEmpty + } + } + } + } +} + +Describe "Public commands have Pester tests" -Tag 'Build' { + $commands = Get-Command -Module $ModuleName + + foreach ($command in $commands.Name) + { + $file = Get-ChildItem -Path "$ModuleRoot\Tests" -Include "$command.Tests.ps1" -Recurse + It "Should have a Pester test for [$command]" -Skip:($null -eq $file) { + $file.FullName | Should Not BeNullOrEmpty + } + } +} diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..0f8b032 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,35 @@ +[CmdletBinding()] + +param($Task = 'Default') + +$Script:Modules = @( + 'BuildHelpers', + 'InvokeBuild', + 'LDModuleBuilder', + 'Pester', + 'platyPS', + 'PSScriptAnalyzer' +) + +$Script:ModuleInstallScope = 'CurrentUser' + +'Starting build...' +'Installing module dependencies...' + +Get-PackageProvider -Name 'NuGet' -ForceBootstrap | Out-Null + +Update-LDModule -Name $Script:Modules -Scope $Script:ModuleInstallScope + +Set-BuildEnvironment +$Error.Clear() + +'Invoking build...' + +Invoke-Build $Task -Result 'Result' +if ($Result.Error) +{ + $Error[-1].ScriptStackTrace | Out-String + exit 1 +} + +exit 0 \ No newline at end of file From 0a2b90079d94e03a61c9519b0f205e8db77b6057 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Sat, 14 Jul 2018 17:19:46 -0700 Subject: [PATCH 06/44] Change test defaults --- Tests/Project/Help.Tests.ps1 | 6 +++--- Tests/Project/Module.Tests.ps1 | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/Project/Help.Tests.ps1 b/Tests/Project/Help.Tests.ps1 index 2ec5c0f..bf08337 100644 --- a/Tests/Project/Help.Tests.ps1 +++ b/Tests/Project/Help.Tests.ps1 @@ -10,11 +10,11 @@ Describe "Public commands have comment-based or external help" -Tags 'Build' { foreach ($node in $help) { Context $node.Name { - It "Should have a Description or Synopsis" -Pending { + It "Should have a Description or Synopsis" { ($node.Description + $node.Synopsis) | Should Not BeNullOrEmpty } - It "Should have an Example" -Pending { + It "Should have an Example" { $node.Examples | Should Not BeNullOrEmpty } @@ -22,7 +22,7 @@ Describe "Public commands have comment-based or external help" -Tags 'Build' { { if ($parameter -notmatch 'WhatIf|Confirm') { - It "Should have a Description for Parameter [$($parameter.Name)]" -Pending { + It "Should have a Description for Parameter [$($parameter.Name)]" { $parameter.Description.Text | Should Not BeNullOrEmpty } } diff --git a/Tests/Project/Module.Tests.ps1 b/Tests/Project/Module.Tests.ps1 index 8a75a66..87344c4 100644 --- a/Tests/Project/Module.Tests.ps1 +++ b/Tests/Project/Module.Tests.ps1 @@ -15,7 +15,7 @@ Describe "All commands pass PSScriptAnalyzer rules" -Tag 'Build' { { foreach ($rule in $results) { - It $rule.RuleName -Pending { + It $rule.RuleName { $message = "{0} Line {1}: {2}" -f $rule.Severity, $rule.Line, $rule.Message $message | Should Be "" } @@ -37,7 +37,7 @@ Describe "Public commands have Pester tests" -Tag 'Build' { foreach ($command in $commands.Name) { $file = Get-ChildItem -Path "$ModuleRoot\Tests" -Include "$command.Tests.ps1" -Recurse - It "Should have a Pester test for [$command]" -Skip:($null -eq $file) { + It "Should have a Pester test for [$command]" { $file.FullName | Should Not BeNullOrEmpty } } From fd5d87bf2a97211f108d372b8e0348a6386e427a Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Mon, 16 Jul 2018 02:22:48 -0700 Subject: [PATCH 07/44] LDX-822 add compile support --- BuildTasks/Compile.Task.ps1 | 14 ++++++++++++++ Module.build.ps1 | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 BuildTasks/Compile.Task.ps1 diff --git a/BuildTasks/Compile.Task.ps1 b/BuildTasks/Compile.Task.ps1 new file mode 100644 index 0000000..28d1886 --- /dev/null +++ b/BuildTasks/Compile.Task.ps1 @@ -0,0 +1,14 @@ +taskx Compile @{ + If = (Get-ChildItem -Path $BuildRoot -Include *.csproj -Recurse) + Inputs = { + Get-ChildItem $BuildRoot -Recurse -File -Include *.cs + } + Outputs = "$Destination\bin\$ModuleName.dll" + Jobs = { + # This build command requires .Net Core + "Building Module" + $csproj = Get-ChildItem -Path $BuildRoot -Include *.csproj -Recurse + $folder = Split-Path $csproj + dotnet build $folder -c Release -o $Destination\bin + } +} diff --git a/Module.build.ps1 b/Module.build.ps1 index b5f93b2..ab022b4 100644 --- a/Module.build.ps1 +++ b/Module.build.ps1 @@ -3,7 +3,7 @@ $Script:CodeCoveragePercent = 0.0 # 0 to 1 . $psscriptroot\BuildTasks\InvokeBuildInit.ps1 task Default Build, Test, UpdateSource -task Build Copy, BuildModule, BuildManifest, Helpify +task Build Copy, Compile, BuildModule, BuildManifest, Helpify task Helpify GenerateMarkdown, GenerateHelp task Test Build, ImportModule, FullTests From e38eb66540a0da5a4fb56049360882e28aebc4d4 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Mon, 16 Jul 2018 02:32:54 -0700 Subject: [PATCH 08/44] Correct the way ModuleName is calculated in tests --- Tests/Project/Help.Tests.ps1 | 4 ++-- Tests/Project/Module.Tests.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Project/Help.Tests.ps1 b/Tests/Project/Help.Tests.ps1 index bf08337..84428f7 100644 --- a/Tests/Project/Help.Tests.ps1 +++ b/Tests/Project/Help.Tests.ps1 @@ -1,5 +1,5 @@ -$Script:ModuleName = 'LDTestFramework' -$Script:ModuleRoot = Split-Path -Path $PSScriptRoot -Parent +$Script:ModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent +$Script:ModuleName = Split-Path -Path $ModuleRoot -Leaf Describe "Public commands have comment-based or external help" -Tags 'Build' { $functions = Get-Command -Module $ModuleName diff --git a/Tests/Project/Module.Tests.ps1 b/Tests/Project/Module.Tests.ps1 index 87344c4..0cd02e7 100644 --- a/Tests/Project/Module.Tests.ps1 +++ b/Tests/Project/Module.Tests.ps1 @@ -1,5 +1,5 @@ -$Script:ModuleName = 'LDTestFramework' $Script:ModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent +$Script:ModuleName = Split-Path -Path $ModuleRoot -Leaf $Script:SourceRoot = Join-Path -Path $ModuleRoot -ChildPath $ModuleName Describe "All commands pass PSScriptAnalyzer rules" -Tag 'Build' { From 2c08bb2b7ca5bacc570f774af88593043048e850 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 17 Jul 2018 12:15:47 -0700 Subject: [PATCH 09/44] LDX-825 add better module name handling --- BuildTasks/InvokeBuildInit.ps1 | 18 ++++++++++++++++++ Module.build.ps1 | 2 +- Tests/Project/Help.Tests.ps1 | 2 +- Tests/Project/Module.Tests.ps1 | 3 ++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/BuildTasks/InvokeBuildInit.ps1 b/BuildTasks/InvokeBuildInit.ps1 index 1972500..d0fcb36 100644 --- a/BuildTasks/InvokeBuildInit.ps1 +++ b/BuildTasks/InvokeBuildInit.ps1 @@ -1,9 +1,27 @@ +Write-Verbose "Initializing build variables" + $Script:DocsPath = Join-Path -Path $BuildRoot -ChildPath 'Docs' +Write-Verbose " DocsPath [$DocsPath]" + $Script:Output = Join-Path -Path $BuildRoot -ChildPath 'Output' +Write-Verbose " Output [$Output]" + $Script:Source = Join-Path -Path $BuildRoot -ChildPath $ModuleName +Write-Verbose " Source [$Source]" + $Script:Destination = Join-Path -Path $Output -ChildPath $ModuleName +Write-Verbose " Destination [$Destination]" + $Script:ManifestPath = Join-Path -Path $Destination -ChildPath "$ModuleName.psd1" +Write-Verbose " ManifestPath [$ManifestPath]" + $Script:ModulePath = Join-Path -Path $Destination -ChildPath "$ModuleName.psm1" +Write-Verbose " ModulePath [$ModulePath]" + $Script:Folders = 'Classes', 'Includes', 'Internal', 'Private', 'Public', 'Resources' +Write-Verbose " Folders [$Folders]" + $Script:TestFile = "$BuildRoot\Output\TestResults_PS$PSVersion`_$TimeStamp.xml" +Write-Verbose " TestFile [$TestFile]" + function taskx($Name, $Parameters) { task $Name @Parameters -Source $MyInvocation } diff --git a/Module.build.ps1 b/Module.build.ps1 index ab022b4..69905a5 100644 --- a/Module.build.ps1 +++ b/Module.build.ps1 @@ -1,4 +1,4 @@ -$Script:ModuleName = Split-Path -Leaf $PSScriptRoot +$Script:ModuleName = Get-ChildItem .\*\*.psm1 | Select-object -ExpandProperty BaseName $Script:CodeCoveragePercent = 0.0 # 0 to 1 . $psscriptroot\BuildTasks\InvokeBuildInit.ps1 diff --git a/Tests/Project/Help.Tests.ps1 b/Tests/Project/Help.Tests.ps1 index 84428f7..4465f53 100644 --- a/Tests/Project/Help.Tests.ps1 +++ b/Tests/Project/Help.Tests.ps1 @@ -1,5 +1,5 @@ $Script:ModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent -$Script:ModuleName = Split-Path -Path $ModuleRoot -Leaf +$Script:ModuleName = $Script:ModuleName = Get-ChildItem $ModuleRoot\*\*.psm1 | Select-object -ExpandProperty BaseName Describe "Public commands have comment-based or external help" -Tags 'Build' { $functions = Get-Command -Module $ModuleName diff --git a/Tests/Project/Module.Tests.ps1 b/Tests/Project/Module.Tests.ps1 index 0cd02e7..f652dc4 100644 --- a/Tests/Project/Module.Tests.ps1 +++ b/Tests/Project/Module.Tests.ps1 @@ -1,5 +1,6 @@ $Script:ModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent -$Script:ModuleName = Split-Path -Path $ModuleRoot -Leaf +$Script:ModuleName = $Script:ModuleName = Get-ChildItem $ModuleRoot\*\*.psm1 | Select-object -ExpandProperty BaseName + $Script:SourceRoot = Join-Path -Path $ModuleRoot -ChildPath $ModuleName Describe "All commands pass PSScriptAnalyzer rules" -Tag 'Build' { From cf21c9eb8ad891c248030d073a7c30fbbf92f06f Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Fri, 3 Aug 2018 16:32:04 -0700 Subject: [PATCH 10/44] LDX-845 add license --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..52cc82e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 loanDepot + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 1063e713b5f3fff38414c93c69597a94fbe1273a Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 14 Aug 2018 13:35:35 -0700 Subject: [PATCH 11/44] Exclude test data from vscode searches --- .vscode/settings.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e8caa5d..99356f2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,9 @@ "files.autoGuessEncoding": false, "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true, - + "search.exclude": { + "**/Tests/Data*": true + }, //-------- PowerShell configuration -------- "powershell.codeFormatting.alignPropertyValuePairs": true, "powershell.codeFormatting.preset": "Allman", From c8d84157dc5be7b5ea2fc024ae5d0563a95dfacc Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 14 Aug 2018 13:42:50 -0700 Subject: [PATCH 12/44] update .gitignore to only exclude files debug files in root of project --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 83762c4..8e9286f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /output/ -debug*.ps1 -temp*.ps1 +/debug*.ps1 +/temp*.ps1 # Most of these heavily cannibalized by Travis Drake from https://gist.github.com/kmorcinek/2710267 From 1b3777475bf2ff0b66d6024ec1a1c96e7c95e1ed Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 14 Aug 2018 14:02:08 -0700 Subject: [PATCH 13/44] require test to have call to function --- Tests/Project/Help.Tests.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Project/Help.Tests.ps1 b/Tests/Project/Help.Tests.ps1 index 4465f53..954cf88 100644 --- a/Tests/Project/Help.Tests.ps1 +++ b/Tests/Project/Help.Tests.ps1 @@ -16,6 +16,7 @@ Describe "Public commands have comment-based or external help" -Tags 'Build' { It "Should have an Example" { $node.Examples | Should Not BeNullOrEmpty + $node.Examples | Out-String | Should -Match ($node.Name) } foreach ($parameter in $node.Parameters.Parameter) From 2d9e5fbd71588bd858fa4856fa2646a417a84939 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 14 Aug 2018 14:02:18 -0700 Subject: [PATCH 14/44] whitespace --- .vscode/settings.json | 1 + BuildTasks/BuildManifest.Task.ps1 | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 99356f2..0df401f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,7 @@ "search.exclude": { "**/Tests/Data*": true }, + //-------- PowerShell configuration -------- "powershell.codeFormatting.alignPropertyValuePairs": true, "powershell.codeFormatting.preset": "Allman", diff --git a/BuildTasks/BuildManifest.Task.ps1 b/BuildTasks/BuildManifest.Task.ps1 index 7f6f286..818a7c4 100644 --- a/BuildTasks/BuildManifest.Task.ps1 +++ b/BuildTasks/BuildManifest.Task.ps1 @@ -33,9 +33,9 @@ taskx BuildManifest @{ if($false -eq $command.Parameters[$parameter].IsDynamic) { '{0}:{1}' -f $command.Name, $command.Parameters[$parameter].Name - foreach ($alias in $command.Parameters[$parameter].Aliases) - { - '{0}:{1}' -f $command.Name, $alias + foreach ($alias in $command.Parameters[$parameter].Aliases) + { + '{0}:{1}' -f $command.Name, $alias } } } From 79f4985864992a383d15e57cdc408a13aa5ee1b0 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 14 Aug 2018 14:03:36 -0700 Subject: [PATCH 15/44] whitespace --- BuildTasks/BuildManifest.Task.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BuildTasks/BuildManifest.Task.ps1 b/BuildTasks/BuildManifest.Task.ps1 index 818a7c4..9602c08 100644 --- a/BuildTasks/BuildManifest.Task.ps1 +++ b/BuildTasks/BuildManifest.Task.ps1 @@ -32,7 +32,7 @@ taskx BuildManifest @{ { if($false -eq $command.Parameters[$parameter].IsDynamic) { - '{0}:{1}' -f $command.Name, $command.Parameters[$parameter].Name + '{0}:{1}' -f $command.Name, $command.Parameters[$parameter].Name foreach ($alias in $command.Parameters[$parameter].Aliases) { '{0}:{1}' -f $command.Name, $alias From 0a8fb01841ca6400f21d61e147abeefb1121c8a8 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Fri, 17 Aug 2018 02:50:34 -0700 Subject: [PATCH 16/44] add appveyor details --- appveyor.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..49bc64d --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,19 @@ +# see https://www.appveyor.com/docs/appveyor-yml + +environment: + NugetApiKey: + secure: Bnrv6GbJAwEINiebF7/lIZTgdaKq2oQHmc5Z1kYoLgNJ1tGOwo4lKNCHsFhkqZok + +# Allow WMF5 (i.e. PowerShellGallery functionality) +os: WMF 5 + +# Skip on updates to the readme. +# We can force this by adding [skip ci] or [ci skip] anywhere in commit message +skip_commits: + message: /updated (readme|doc).*|update (readme|doc).*s/ + +build: false + +#Kick off the CI/CD pipeline +test_script: + - ps: . .\build.ps1 From 49332ecf34a12f8a38917ddd89ca1833390072c7 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Fri, 17 Aug 2018 03:12:40 -0700 Subject: [PATCH 17/44] set build image --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 49bc64d..10f1594 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ environment: secure: Bnrv6GbJAwEINiebF7/lIZTgdaKq2oQHmc5Z1kYoLgNJ1tGOwo4lKNCHsFhkqZok # Allow WMF5 (i.e. PowerShellGallery functionality) -os: WMF 5 +image: Visual Studio 2017 # Skip on updates to the readme. # We can force this by adding [skip ci] or [ci skip] anywhere in commit message From c3da819e5f2ce1b04eb1b48f2ed9e42c69131a28 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Fri, 17 Aug 2018 04:59:21 -0700 Subject: [PATCH 18/44] Add PSGallery publishing support --- BuildTasks/InvokeBuildInit.ps1 | 3 +++ BuildTasks/PublishModule.Task.ps1 | 25 +++++++++++++++++++++++++ Module.build.ps1 | 1 + appveyor.yml | 8 +++++--- build.ps1 | 5 ++++- 5 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 BuildTasks/PublishModule.Task.ps1 diff --git a/BuildTasks/InvokeBuildInit.ps1 b/BuildTasks/InvokeBuildInit.ps1 index d0fcb36..d231732 100644 --- a/BuildTasks/InvokeBuildInit.ps1 +++ b/BuildTasks/InvokeBuildInit.ps1 @@ -24,4 +24,7 @@ Write-Verbose " Folders [$Folders]" $Script:TestFile = "$BuildRoot\Output\TestResults_PS$PSVersion`_$TimeStamp.xml" Write-Verbose " TestFile [$TestFile]" +$Script:PSRepository = 'PSGallery' +Write-Verbose " PSRepository [$TestFile]" + function taskx($Name, $Parameters) { task $Name @Parameters -Source $MyInvocation } diff --git a/BuildTasks/PublishModule.Task.ps1 b/BuildTasks/PublishModule.Task.ps1 new file mode 100644 index 0000000..305e19d --- /dev/null +++ b/BuildTasks/PublishModule.Task.ps1 @@ -0,0 +1,25 @@ +task PublishModule { + + if ( $ENV:BHBuildSystem -ne 'Unknown' -and + $ENV:BHBranchName -eq "master" -and + [string]::IsNullOrWhiteSpace($ENV:APPVEYOR_PULL_REQUEST_NUMBER) -and + -not [string]::IsNullOrWhiteSpace($ENV:NugetApiKey)) + { + $publishModuleSplat = @{ + Path = $Destination + NuGetApiKey = $ENV:NugetApiKey + Verbose = $true + Force = $true + Repository = $PSRepository + ErrorAction = 'Stop' + } + Publish-Module @publishModuleSplat + } + else + { + "Skipping deployment: To deploy, ensure that...`n" + + "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + + "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + + "`t* This is not a pull request" + } +} diff --git a/Module.build.ps1 b/Module.build.ps1 index 69905a5..3eeb453 100644 --- a/Module.build.ps1 +++ b/Module.build.ps1 @@ -6,6 +6,7 @@ task Default Build, Test, UpdateSource task Build Copy, Compile, BuildModule, BuildManifest, Helpify task Helpify GenerateMarkdown, GenerateHelp task Test Build, ImportModule, FullTests +task Publish Build, Test, PublishModule Write-Host 'Import common tasks' Get-ChildItem -Path $buildroot\BuildTasks\*.Task.ps1 | diff --git a/appveyor.yml b/appveyor.yml index 10f1594..8390ae8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,8 +12,10 @@ image: Visual Studio 2017 skip_commits: message: /updated (readme|doc).*|update (readme|doc).*s/ +skip_branch_with_pr: true + build: false -#Kick off the CI/CD pipeline -test_script: - - ps: . .\build.ps1 +# Kick off the CI/CD pipeline +build_script: + - ps: . .\build.ps1 Publish diff --git a/build.ps1 b/build.ps1 index 0f8b032..8a61c9a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -21,6 +21,9 @@ Get-PackageProvider -Name 'NuGet' -ForceBootstrap | Out-Null Update-LDModule -Name $Script:Modules -Scope $Script:ModuleInstallScope Set-BuildEnvironment +Get-ChildItem Env:BH* +Get-ChildItem Env:APPVEYOR* + $Error.Clear() 'Invoking build...' @@ -32,4 +35,4 @@ if ($Result.Error) exit 1 } -exit 0 \ No newline at end of file +exit 0 From b068194cee74c54af1ca24ab1fe60529567ca30e Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Fri, 17 Aug 2018 05:13:35 -0700 Subject: [PATCH 19/44] because nuget broke versioniong --- BuildTasks/BuildManifest.Task.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BuildTasks/BuildManifest.Task.ps1 b/BuildTasks/BuildManifest.Task.ps1 index 9602c08..ef5f460 100644 --- a/BuildTasks/BuildManifest.Task.ps1 +++ b/BuildTasks/BuildManifest.Task.ps1 @@ -91,7 +91,7 @@ taskx BuildManifest @{ "Stepping [$bumpVersionType] version [$version]..." $version = [version] (Step-Version -Version $version -Type $bumpVersionType) - $build = 0 + $build = 1 if ($null -ne $env:Build_BuildID) { $build = $env:Build_BuildID From c386851a0675fcca07fa5edd7513bc18e968ad39 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Fri, 17 Aug 2018 14:41:16 -0700 Subject: [PATCH 20/44] add support for class requires directives --- BuildTasks/BuildModule.Task.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BuildTasks/BuildModule.Task.ps1 b/BuildTasks/BuildModule.Task.ps1 index b55e961..7b2fc88 100644 --- a/BuildTasks/BuildModule.Task.ps1 +++ b/BuildTasks/BuildModule.Task.ps1 @@ -43,7 +43,7 @@ taskx BuildModule @{ $data = Get-Content $file.fullname foreach($line in $data) { - if($line -match "class\s+($Name)\s*:\s*(?\w*)") + if($line -match "\s+($Name)\s*(:|requires)\s*(?\w*)") { $classes[$name].Base = $Matches.baseclass } From de13e3154296384a652491af220d71c4dc74e84c Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Sun, 19 Aug 2018 20:12:05 -0700 Subject: [PATCH 21/44] Change the way version numbers are generated --- BuildTasks/BuildManifest.Task.ps1 | 88 --------------------------- BuildTasks/ImportDevModule.Task.ps1 | 19 +----- BuildTasks/ImportModule.Task.ps1 | 28 ++++++--- BuildTasks/SetVersion.Task.ps1 | 92 +++++++++++++++++++++++++++++ Module.build.ps1 | 6 +- 5 files changed, 116 insertions(+), 117 deletions(-) create mode 100644 BuildTasks/SetVersion.Task.ps1 diff --git a/BuildTasks/BuildManifest.Task.ps1 b/BuildTasks/BuildManifest.Task.ps1 index ef5f460..343e0e3 100644 --- a/BuildTasks/BuildManifest.Task.ps1 +++ b/BuildTasks/BuildManifest.Task.ps1 @@ -14,93 +14,5 @@ taskx BuildManifest @{ 'Setting FunctionsToExport...' Set-ModuleFunctions -Name $ManifestPath -FunctionsToExport $functions.BaseName } - - 'Detecting semantic versioning...' - "Importing Module [$ManifestPath]..." - Import-Module -FullyQualifiedName $ManifestPath - - "Get-Command -Module [$ModuleName]..." - $commands = Get-Command -Module $ModuleName - - "Removing Module [$ModuleName]..." - Remove-Module -Name $ModuleName -Force - - 'Calculating fingerprint...' - $fingerprint = foreach ($command in $commands) - { - foreach ($parameter in $command.Parameters.Keys) - { - if($false -eq $command.Parameters[$parameter].IsDynamic) - { - '{0}:{1}' -f $command.Name, $command.Parameters[$parameter].Name - foreach ($alias in $command.Parameters[$parameter].Aliases) - { - '{0}:{1}' -f $command.Name, $alias - } - } - } - } - - $fingerprint = $fingerprint | Sort-Object - - if (Test-Path -Path '.\fingerprint') - { - $oldFingerprint = Get-Content -Path '.\fingerprint' - } - - $bumpVersionType = 'Patch' - - 'Detecting new features...' - $features = $fingerprint | - Where-Object { $_ -notin $oldFingerprint } - - foreach ($feature in $features) - { - $feature - $bumpVersionType = 'Minor' - } - - 'Detecting breaking changes...' - $breakingChanges = $oldFingerprint | - Where-Object { $_ -notin $fingerprint } - - foreach ($breakingChange in $breakingChanges) - { - $breakingChange - $bumpVersionType = 'Major' - } - - Set-Content -Path '.\fingerprint' -Value $fingerprint - - # Bump the module version - $version = [version] (Get-Metadata -Path $manifestPath -PropertyName 'ModuleVersion') - - if ($version -lt ([version] '1.0.0')) - { - "Module is still in beta; don't bump major version." - if ($bumpVersionType -eq 'Major') - { - $bumpVersionType = 'Minor' - } - else - { - $bumpVersionType = 'Patch' - } - } - - "Stepping [$bumpVersionType] version [$version]..." - $version = [version] (Step-Version -Version $version -Type $bumpVersionType) - - $build = 1 - if ($null -ne $env:Build_BuildID) - { - $build = $env:Build_BuildID - } - - $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) - "Using version [$version]..." - "##vso[build.updatebuildnumber]$version" - - Update-Metadata -Path $ManifestPath -PropertyName 'ModuleVersion' -Value $version } } diff --git a/BuildTasks/ImportDevModule.Task.ps1 b/BuildTasks/ImportDevModule.Task.ps1 index c852471..ea36fcc 100644 --- a/BuildTasks/ImportDevModule.Task.ps1 +++ b/BuildTasks/ImportDevModule.Task.ps1 @@ -1,21 +1,4 @@ task ImportDevModule { - - if (-not(Test-Path -Path "$Source\$ModuleName.psd1")) - { - "Module [$ModuleName] is not built; cannot find [$Source\$ModuleName.psd1]." - Write-Error -Message "Could not find module manifest [$Source\$ModuleName.psd1]." - } - else - { - $loaded = Get-Module -Name $ModuleName -All - if ($loaded) - { - "Unloading Module [$ModuleName] from a previous import..." - $loaded | Remove-Module -Force - } - - "Importing Module [$ModuleName] from [$Source\$ModuleName.psd1]..." - Import-Module -FullyQualifiedName "$Source\$ModuleName.psd1" -Force - } + ImportModule -Path "$Source\$ModuleName.psd1" } diff --git a/BuildTasks/ImportModule.Task.ps1 b/BuildTasks/ImportModule.Task.ps1 index dfe72c6..8b27fa6 100644 --- a/BuildTasks/ImportModule.Task.ps1 +++ b/BuildTasks/ImportModule.Task.ps1 @@ -1,20 +1,32 @@ +funciton ImportModule +{ + param( + [string]$path, + [switch]$PassThru + ) -task ImportModule { - if (-not(Test-Path -Path $ManifestPath)) + $file = Get-ChildItem $path + $name = $file.BaseName + + if (-not(Test-Path -Path $path)) { - "Module [$ModuleName] is not built; cannot find [$ManifestPath]." - Write-Error -Message "Could not find module manifest [$ManifestPath]. You may need to build the module first." + "Cannot find [$($path.fullname)]." + Write-Error -Message "Could not find module manifest [$($path.fullname)]" } else { - $loaded = Get-Module -Name $ModuleName -All + $loaded = Get-Module -Name $name -All -ErrorAction Ignore if ($loaded) { - "Unloading Module [$ModuleName] from a previous import..." + "Unloading Module [$name] from a previous import..." $loaded | Remove-Module -Force } - "Importing Module [$ModuleName] from [$ManifestPath]..." - Import-Module -FullyQualifiedName $ManifestPath -Force + "Importing Module [$name] from [$($path.fullname)]..." + Import-Module -FullyQualifiedName $path.fullname -Force -PassThru:$PassThru } } + +task ImportModule { + ImportModule -Path $ManifestPath +} diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 new file mode 100644 index 0000000..9b26c10 --- /dev/null +++ b/BuildTasks/SetVersion.Task.ps1 @@ -0,0 +1,92 @@ +funciton GetModulePublicInterfaceMap +{ + param($Path) + $module = ImportModule -Path $Path -PassThru + $exportedCommands = @( + $module.ExportedFunctions.values + $module.ExportedCmdlets.values + $module.ExportedAliases.values + ) + + $data = foreach($command in $exportedCommands) + { + foreach ($parameter in $command.Parameters.Keys) + { + if($false -eq $command.Parameters[$parameter].IsDynamic) + { + '{0}:{1}' -f $command.Name, $command.Parameters[$parameter].Name + foreach ($alias in $command.Parameters[$parameter].Aliases) + { + '{0}:{1}' -f $command.Name, $alias + } + } + } + } + [System.Collections.Generic.HashSet[string]]$data +} + +task SetVersion +{ + $publishedModule = Find-Module -Name $ModuleName | + Sort-Object -Property {[version]$_.Version} -Descending | + Select -First 1 + + [version] $publishedVersion = $publishedModule.Version + [version] $sourceVersion = (Get-Metadata -Path $manifestPath -PropertyName 'ModuleVersion') + + if($sourceVersion -gt $publishedVersion) + { + Write-Verbose "Using existing version as base [$sourceVersion]" + $version = $sourceVersion + } + else + { + "Downloading published module to check for breaking changes" + $downloadFolder = Join-Path -Path $output downloads + $null = New-Item -ItemType Directory -Path $downloadFolder -Force -ErrorAction Ignore + $publishedModule | Save-Module -Path $downloadFolder + + $publishedInterface = GetModulePublicInterfaceMap -Path (Join-Path $downloadFolder $ModuleName) + $buildInterface = GetModulePublicInterfaceMap -Path $ManifestPath + + $bumpVersionType = 'Patch' + if($publishedInterface.IsSubsetOf($buildInterface)) + { + $bumpVersionType = 'Major' + } + elseif ($publishedInterface.count -ne $buildInterface.count) + { + $bumpVersionType = 'Minor' + } + + if ($version -lt ([version] '1.0.0')) + { + "Module is still in beta; don't bump major version." + if ($bumpVersionType -eq 'Major') + { + $bumpVersionType = 'Minor' + } + else + { + $bumpVersionType = 'Patch' + } + } + + $version = [version] (Step-Version -Version $version -Type $bumpVersionType) + } + + $build = -1 + if ($null -ne $env:Build_BuildID) + { + $build = $env:Build_BuildID + } + + $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) + "Using version [$version]" + Update-Metadata -Path $ManifestPath -PropertyName 'ModuleVersion' -Value $version + + if(Test-Path $BuildRoot\fingerprint) + { + Remove-Item $BuildRoot\fingerprint + } +} diff --git a/Module.build.ps1 b/Module.build.ps1 index 3eeb453..d40fae0 100644 --- a/Module.build.ps1 +++ b/Module.build.ps1 @@ -2,11 +2,11 @@ $Script:ModuleName = Get-ChildItem .\*\*.psm1 | Select-object -ExpandProperty Ba $Script:CodeCoveragePercent = 0.0 # 0 to 1 . $psscriptroot\BuildTasks\InvokeBuildInit.ps1 -task Default Build, Test, UpdateSource -task Build Copy, Compile, BuildModule, BuildManifest, Helpify +task Default Build, Test, UpdateSource, Helpify +task Build Copy, Compile, BuildModule, BuildManifest, SetVersion task Helpify GenerateMarkdown, GenerateHelp task Test Build, ImportModule, FullTests -task Publish Build, Test, PublishModule +task Publish Build, Test, Helpify, PublishModule Write-Host 'Import common tasks' Get-ChildItem -Path $buildroot\BuildTasks\*.Task.ps1 | From 996b2d91954ee03b72a7a509270a3854da8ee54c Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Mon, 20 Aug 2018 02:11:14 -0700 Subject: [PATCH 22/44] resolve bugs around versioning added version caching --- BuildTasks/ImportModule.Task.ps1 | 15 ++--- BuildTasks/SetVersion.Task.ps1 | 98 +++++++++++++++++++------------- 2 files changed, 67 insertions(+), 46 deletions(-) diff --git a/BuildTasks/ImportModule.Task.ps1 b/BuildTasks/ImportModule.Task.ps1 index 8b27fa6..a903b45 100644 --- a/BuildTasks/ImportModule.Task.ps1 +++ b/BuildTasks/ImportModule.Task.ps1 @@ -1,20 +1,21 @@ -funciton ImportModule +function ImportModule { param( [string]$path, [switch]$PassThru ) - $file = Get-ChildItem $path - $name = $file.BaseName if (-not(Test-Path -Path $path)) { - "Cannot find [$($path.fullname)]." - Write-Error -Message "Could not find module manifest [$($path.fullname)]" + "Cannot find [$path]." + Write-Error -Message "Could not find module manifest [$path]" } else { + $file = Get-Item $path + $name = $file.BaseName + $loaded = Get-Module -Name $name -All -ErrorAction Ignore if ($loaded) { @@ -22,8 +23,8 @@ funciton ImportModule $loaded | Remove-Module -Force } - "Importing Module [$name] from [$($path.fullname)]..." - Import-Module -FullyQualifiedName $path.fullname -Force -PassThru:$PassThru + "Importing Module [$name] from [$($file.fullname)]..." + Import-Module -Name $file.fullname -Force -PassThru:$PassThru } } diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 index 9b26c10..b43138a 100644 --- a/BuildTasks/SetVersion.Task.ps1 +++ b/BuildTasks/SetVersion.Task.ps1 @@ -1,4 +1,4 @@ -funciton GetModulePublicInterfaceMap +function GetModulePublicInterfaceMap { param($Path) $module = ImportModule -Path $Path -PassThru @@ -8,7 +8,7 @@ funciton GetModulePublicInterfaceMap $module.ExportedAliases.values ) - $data = foreach($command in $exportedCommands) + foreach($command in $exportedCommands) { foreach ($parameter in $command.Parameters.Keys) { @@ -22,69 +22,89 @@ funciton GetModulePublicInterfaceMap } } } - [System.Collections.Generic.HashSet[string]]$data } -task SetVersion -{ +task SetVersion { + $version = $null + + $versionStamp = (git rev-parse origin/master) + (git rev-parse head) + + "Load current version" + [version] $sourceVersion = (Get-Metadata -Path $manifestPath -PropertyName 'ModuleVersion') + " Source version [$sourceVersion]" + + $downloadFolder = Join-Path -Path $output downloads + $null = New-Item -ItemType Directory -Path $downloadFolder -Force -ErrorAction Ignore + + $versionFile = Join-Path $downloadFolder versionfile + if(Test-Path $versionFile) + { + $versionFileData = Get-Content $versionFile -raw + if($versionFileData -eq $versionStamp) + { + continue + } + } + + "Checking for published version" $publishedModule = Find-Module -Name $ModuleName | Sort-Object -Property {[version]$_.Version} -Descending | Select -First 1 [version] $publishedVersion = $publishedModule.Version - [version] $sourceVersion = (Get-Metadata -Path $manifestPath -PropertyName 'ModuleVersion') + " Published version [$publishedVersion]" - if($sourceVersion -gt $publishedVersion) + $version = $publishedVersion + + "Downloading published module to check for breaking changes" + $publishedModule | Save-Module -Path $downloadFolder + + [System.Collections.Generic.HashSet[string]] $publishedInterface = GetModulePublicInterfaceMap -Path (Join-Path $downloadFolder $ModuleName) + [System.Collections.Generic.HashSet[string]] $buildInterface = GetModulePublicInterfaceMap -Path $ManifestPath + + $bumpVersionType = 'Patch' + if( -not $publishedInterface.IsSubsetOf($buildInterface)) { - Write-Verbose "Using existing version as base [$sourceVersion]" - $version = $sourceVersion + $bumpVersionType = 'Major' } - else + elseif ($publishedInterface.count -ne $buildInterface.count) { - "Downloading published module to check for breaking changes" - $downloadFolder = Join-Path -Path $output downloads - $null = New-Item -ItemType Directory -Path $downloadFolder -Force -ErrorAction Ignore - $publishedModule | Save-Module -Path $downloadFolder + $bumpVersionType = 'Minor' + } - $publishedInterface = GetModulePublicInterfaceMap -Path (Join-Path $downloadFolder $ModuleName) - $buildInterface = GetModulePublicInterfaceMap -Path $ManifestPath - - $bumpVersionType = 'Patch' - if($publishedInterface.IsSubsetOf($buildInterface)) - { - $bumpVersionType = 'Major' - } - elseif ($publishedInterface.count -ne $buildInterface.count) + if ($version -lt ([version] '1.0.0')) + { + "Module is still in beta; don't bump major version." + if ($bumpVersionType -eq 'Major') { $bumpVersionType = 'Minor' } - - if ($version -lt ([version] '1.0.0')) + else { - "Module is still in beta; don't bump major version." - if ($bumpVersionType -eq 'Major') - { - $bumpVersionType = 'Minor' - } - else - { - $bumpVersionType = 'Patch' - } + $bumpVersionType = 'Patch' } - - $version = [version] (Step-Version -Version $version -Type $bumpVersionType) } - $build = -1 + " Steping version [$bumpVersionType]" + $version = [version] (Step-Version -Version $version -Type $bumpVersionType) + if ($null -ne $env:Build_BuildID) { $build = $env:Build_BuildID + $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) } - $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) - "Using version [$version]" + " Comparing to source version [$sourceVersion]" + if($sourceVersion -gt $version) + { + " Using existing version" + $version = $sourceVersion + } + " Setting version [$version]" Update-Metadata -Path $ManifestPath -PropertyName 'ModuleVersion' -Value $version + Set-Content -Path $versionFile -Value $versionStamp -NoNewline -Encoding UTF8 + if(Test-Path $BuildRoot\fingerprint) { Remove-Item $BuildRoot\fingerprint From 816462927d122c48d52205fd5f730d7acd56c5e7 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Mon, 20 Aug 2018 02:17:46 -0700 Subject: [PATCH 23/44] add appveyor build number support --- BuildTasks/SetVersion.Task.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 index b43138a..8da718e 100644 --- a/BuildTasks/SetVersion.Task.ps1 +++ b/BuildTasks/SetVersion.Task.ps1 @@ -93,6 +93,11 @@ task SetVersion { $build = $env:Build_BuildID $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) } + elseif ($null -ne $env:APPVEYOR_BUILD_ID) + { + $build = $env:APPVEYOR_BUILD_ID + $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) + } " Comparing to source version [$sourceVersion]" if($sourceVersion -gt $version) From 94471ccfc0b9a4f7bbba049527a6b7f130d8ca36 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Mon, 20 Aug 2018 02:45:38 -0700 Subject: [PATCH 24/44] trim trailing newline --- BuildTasks/SetVersion.Task.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 index 8da718e..8f2412d 100644 --- a/BuildTasks/SetVersion.Task.ps1 +++ b/BuildTasks/SetVersion.Task.ps1 @@ -108,6 +108,10 @@ task SetVersion { " Setting version [$version]" Update-Metadata -Path $ManifestPath -PropertyName 'ModuleVersion' -Value $version + (Get-Content -Path $ManifestPath -Raw -Encoding UTF8) | + % trimend | + Set-Content -Path $ManifestPath -Encoding UTF8 + Set-Content -Path $versionFile -Value $versionStamp -NoNewline -Encoding UTF8 if(Test-Path $BuildRoot\fingerprint) From a9a73ae9b2e294c777c7600062e1670230545586 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Mon, 20 Aug 2018 03:14:42 -0700 Subject: [PATCH 25/44] add PublishVersion task --- BuildTasks/{FullTests.Task.ps1 => Pester.Task.ps1} | 11 ++++++++--- BuildTasks/PublishVersion.Task.ps1 | 7 +++++++ BuildTasks/SetVersion.Task.ps1 | 2 +- Module.build.ps1 | 8 +++++--- 4 files changed, 21 insertions(+), 7 deletions(-) rename BuildTasks/{FullTests.Task.ps1 => Pester.Task.ps1} (82%) create mode 100644 BuildTasks/PublishVersion.Task.ps1 diff --git a/BuildTasks/FullTests.Task.ps1 b/BuildTasks/Pester.Task.ps1 similarity index 82% rename from BuildTasks/FullTests.Task.ps1 rename to BuildTasks/Pester.Task.ps1 index 28f9e7a..01f0d29 100644 --- a/BuildTasks/FullTests.Task.ps1 +++ b/BuildTasks/Pester.Task.ps1 @@ -1,7 +1,7 @@ task FullTests { + $requiredPercent = $Script:CodeCoveragePercent + $params = @{ - CodeCoverage = 'Output\*\*.psm1' - CodeCoverageOutputFile = 'Output\codecoverage.xml' OutputFile = $testFile OutputFormat = 'NUnitXml' PassThru = $true @@ -10,13 +10,18 @@ task FullTests { Tag = 'Build' } + if($requiredPercent -gt 0.00) + { + $params['CodeCoverage'] = 'Output\*\*.psm1' + $params['CodeCoverageOutputFile'] = 'Output\codecoverage.xml' + } + $results = Invoke-Pester @params if ($results.FailedCount -gt 0) { Write-Error -Message "Failed [$($results.FailedCount)] Pester tests." } - $requiredPercent = $Script:CodeCoveragePercent $codeCoverage = $results.codecoverage.NumberOfCommandsExecuted / $results.codecoverage.NumberOfCommandsAnalyzed if($codeCoverage -lt $requiredPercent) { diff --git a/BuildTasks/PublishVersion.Task.ps1 b/BuildTasks/PublishVersion.Task.ps1 new file mode 100644 index 0000000..79c9eba --- /dev/null +++ b/BuildTasks/PublishVersion.Task.ps1 @@ -0,0 +1,7 @@ +task PublishVersion { + [version] $sourceVersion = (Get-Metadata -Path $manifestPath -PropertyName 'ModuleVersion') + "##vso[build.updatebuildnumber]$sourceVersion" + + # Do the same for appveyor + # https://www.appveyor.com/docs/build-worker-api/#update-build-details +} diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 index 8f2412d..715af54 100644 --- a/BuildTasks/SetVersion.Task.ps1 +++ b/BuildTasks/SetVersion.Task.ps1 @@ -30,7 +30,7 @@ task SetVersion { $versionStamp = (git rev-parse origin/master) + (git rev-parse head) "Load current version" - [version] $sourceVersion = (Get-Metadata -Path $manifestPath -PropertyName 'ModuleVersion') + [version] $sourceVersion = (Get-Metadata -Path $manifestPath -PropertyName 'ModuleVersion') " Source version [$sourceVersion]" $downloadFolder = Join-Path -Path $output downloads diff --git a/Module.build.ps1 b/Module.build.ps1 index d40fae0..690fc54 100644 --- a/Module.build.ps1 +++ b/Module.build.ps1 @@ -2,11 +2,13 @@ $Script:ModuleName = Get-ChildItem .\*\*.psm1 | Select-object -ExpandProperty Ba $Script:CodeCoveragePercent = 0.0 # 0 to 1 . $psscriptroot\BuildTasks\InvokeBuildInit.ps1 -task Default Build, Test, UpdateSource, Helpify +task Default Build, Helpify, Test, UpdateSource task Build Copy, Compile, BuildModule, BuildManifest, SetVersion task Helpify GenerateMarkdown, GenerateHelp -task Test Build, ImportModule, FullTests -task Publish Build, Test, Helpify, PublishModule +task Test Build, ImportModule, Pester +task Publish Build, PublishVersion, Helpify, Test, PublishModule +task TFS Clean, Build, PublishVersion, Helpify, Test +task DevTest, ImportDevModule, Pester Write-Host 'Import common tasks' Get-ChildItem -Path $buildroot\BuildTasks\*.Task.ps1 | From d3dfccabc15e51873f6824025109005b4968f218 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Mon, 20 Aug 2018 03:17:44 -0700 Subject: [PATCH 26/44] rename task --- BuildTasks/Pester.Task.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BuildTasks/Pester.Task.ps1 b/BuildTasks/Pester.Task.ps1 index 01f0d29..528a343 100644 --- a/BuildTasks/Pester.Task.ps1 +++ b/BuildTasks/Pester.Task.ps1 @@ -1,4 +1,4 @@ -task FullTests { +task Pester { $requiredPercent = $Script:CodeCoveragePercent $params = @{ From 73d9253b792a5a5ce0dd2280d1da5ca271f1b92b Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Mon, 20 Aug 2018 03:17:57 -0700 Subject: [PATCH 27/44] remove extra coma --- Module.build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Module.build.ps1 b/Module.build.ps1 index 690fc54..f549433 100644 --- a/Module.build.ps1 +++ b/Module.build.ps1 @@ -8,7 +8,7 @@ task Helpify GenerateMarkdown, GenerateHelp task Test Build, ImportModule, Pester task Publish Build, PublishVersion, Helpify, Test, PublishModule task TFS Clean, Build, PublishVersion, Helpify, Test -task DevTest, ImportDevModule, Pester +task DevTest ImportDevModule, Pester Write-Host 'Import common tasks' Get-ChildItem -Path $buildroot\BuildTasks\*.Task.ps1 | From 45b674cf3d7f9bccc7c6444baa6c5b24b55efb18 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 21 Aug 2018 14:20:08 -0700 Subject: [PATCH 28/44] handles versioning when module is notpublished resolves #5 --- BuildTasks/SetVersion.Task.ps1 | 46 ++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 index 715af54..a2cddb6 100644 --- a/BuildTasks/SetVersion.Task.ps1 +++ b/BuildTasks/SetVersion.Task.ps1 @@ -25,8 +25,9 @@ function GetModulePublicInterfaceMap } task SetVersion { - $version = $null - + $version = [version]"0.1.0" + $publishedModule = $null + $bumpVersionType = 'Patch' $versionStamp = (git rev-parse origin/master) + (git rev-parse head) "Load current version" @@ -51,25 +52,28 @@ task SetVersion { Sort-Object -Property {[version]$_.Version} -Descending | Select -First 1 - [version] $publishedVersion = $publishedModule.Version - " Published version [$publishedVersion]" - - $version = $publishedVersion - - "Downloading published module to check for breaking changes" - $publishedModule | Save-Module -Path $downloadFolder - - [System.Collections.Generic.HashSet[string]] $publishedInterface = GetModulePublicInterfaceMap -Path (Join-Path $downloadFolder $ModuleName) - [System.Collections.Generic.HashSet[string]] $buildInterface = GetModulePublicInterfaceMap -Path $ManifestPath - - $bumpVersionType = 'Patch' - if( -not $publishedInterface.IsSubsetOf($buildInterface)) + if($null -ne $publishedModule) { - $bumpVersionType = 'Major' - } - elseif ($publishedInterface.count -ne $buildInterface.count) - { - $bumpVersionType = 'Minor' + [version] $publishedVersion = $publishedModule.Version + " Published version [$publishedVersion]" + + $version = $publishedVersion + + "Downloading published module to check for breaking changes" + $publishedModule | Save-Module -Path $downloadFolder + + [System.Collections.Generic.HashSet[string]] $publishedInterface = GetModulePublicInterfaceMap -Path (Join-Path $downloadFolder $ModuleName) + [System.Collections.Generic.HashSet[string]] $buildInterface = GetModulePublicInterfaceMap -Path $ManifestPath + + + if( -not $publishedInterface.IsSubsetOf($buildInterface)) + { + $bumpVersionType = 'Major' + } + elseif ($publishedInterface.count -ne $buildInterface.count) + { + $bumpVersionType = 'Minor' + } } if ($version -lt ([version] '1.0.0')) @@ -109,7 +113,7 @@ task SetVersion { Update-Metadata -Path $ManifestPath -PropertyName 'ModuleVersion' -Value $version (Get-Content -Path $ManifestPath -Raw -Encoding UTF8) | - % trimend | + ForEach-Object {$_.TrimEnd()} | Set-Content -Path $ManifestPath -Encoding UTF8 Set-Content -Path $versionFile -Value $versionStamp -NoNewline -Encoding UTF8 From f8caf5c2ae02fa421c5342adca1609d216b758ac Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 21 Aug 2018 18:12:59 -0700 Subject: [PATCH 29/44] #7 handle divide by zero error --- BuildTasks/Pester.Task.ps1 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/BuildTasks/Pester.Task.ps1 b/BuildTasks/Pester.Task.ps1 index 528a343..3a4f2fe 100644 --- a/BuildTasks/Pester.Task.ps1 +++ b/BuildTasks/Pester.Task.ps1 @@ -22,9 +22,13 @@ task Pester { Write-Error -Message "Failed [$($results.FailedCount)] Pester tests." } - $codeCoverage = $results.codecoverage.NumberOfCommandsExecuted / $results.codecoverage.NumberOfCommandsAnalyzed - if($codeCoverage -lt $requiredPercent) + if($results.codecoverage.NumberOfCommandsAnalyzed -gt 0) { - Write-Error ("Failed Code Coverage [{0:P}] below {1:P}" -f $codeCoverage,$requiredPercent) + $codeCoverage = $results.codecoverage.NumberOfCommandsExecuted / $results.codecoverage.NumberOfCommandsAnalyzed + + if($codeCoverage -lt $requiredPercent) + { + Write-Error ("Failed Code Coverage [{0:P}] below {1:P}" -f $codeCoverage,$requiredPercent) + } } } From ff21a6ef78e2b60b72ce8a78b6e87b3f043589a2 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Thu, 23 Aug 2018 16:32:15 -0700 Subject: [PATCH 30/44] Added -force to remove-module calls --- BuildTasks/GenerateMarkdown.Task.ps1 | 2 +- BuildTasks/Uninstall.Task.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BuildTasks/GenerateMarkdown.Task.ps1 b/BuildTasks/GenerateMarkdown.Task.ps1 index c1181ec..cfb4204 100644 --- a/BuildTasks/GenerateMarkdown.Task.ps1 +++ b/BuildTasks/GenerateMarkdown.Task.ps1 @@ -36,6 +36,6 @@ task GenerateMarkdown { } finally { - Remove-Module -Name $ModuleName + Remove-Module -Name $ModuleName -Force } } diff --git a/BuildTasks/Uninstall.Task.ps1 b/BuildTasks/Uninstall.Task.ps1 index 2bb4346..61e0539 100644 --- a/BuildTasks/Uninstall.Task.ps1 +++ b/BuildTasks/Uninstall.Task.ps1 @@ -1,7 +1,7 @@ task Uninstall { 'Unloading Modules...' - Get-Module -Name $ModuleName -ErrorAction 'Ignore' | Remove-Module + Get-Module -Name $ModuleName -ErrorAction 'Ignore' | Remove-Module -Force 'Uninstalling Module packages...' $modules = Get-Module $ModuleName -ErrorAction 'Ignore' -ListAvailable From aea4cd1a507717f611690aa6a888ac77122ec0f6 Mon Sep 17 00:00:00 2001 From: Travis Drake Date: Mon, 27 Aug 2018 16:43:43 -0700 Subject: [PATCH 31/44] Fixing SetVersion when run before module has been published before --- BuildTasks/SetVersion.Task.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 index a2cddb6..4078213 100644 --- a/BuildTasks/SetVersion.Task.ps1 +++ b/BuildTasks/SetVersion.Task.ps1 @@ -48,7 +48,7 @@ task SetVersion { } "Checking for published version" - $publishedModule = Find-Module -Name $ModuleName | + $publishedModule = Find-Module -Name $ModuleName -ErrorAction 'SilentlyContinue' | Sort-Object -Property {[version]$_.Version} -Descending | Select -First 1 From 7c3cfd7152011d483324643af5e4508e45ac8814 Mon Sep 17 00:00:00 2001 From: Travis Drake Date: Mon, 27 Aug 2018 17:58:55 -0700 Subject: [PATCH 32/44] More setVersion fixes --- BuildTasks/SetVersion.Task.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 index 4078213..dcfe45c 100644 --- a/BuildTasks/SetVersion.Task.ps1 +++ b/BuildTasks/SetVersion.Task.ps1 @@ -48,7 +48,7 @@ task SetVersion { } "Checking for published version" - $publishedModule = Find-Module -Name $ModuleName -ErrorAction 'SilentlyContinue' | + $publishedModule = Find-Module -Name $ModuleName -ErrorAction 'Ignore' | Sort-Object -Property {[version]$_.Version} -Descending | Select -First 1 @@ -64,7 +64,10 @@ task SetVersion { [System.Collections.Generic.HashSet[string]] $publishedInterface = GetModulePublicInterfaceMap -Path (Join-Path $downloadFolder $ModuleName) [System.Collections.Generic.HashSet[string]] $buildInterface = GetModulePublicInterfaceMap -Path $ManifestPath - + if ($null -eq $publishedInterface) + { + $publishedInterface = [System.Collections.Generic.HashSet[string]]::new() + } if( -not $publishedInterface.IsSubsetOf($buildInterface)) { From f0c105190e9ecd19439160a1921b42babe7378f8 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 28 Aug 2018 04:01:20 -0700 Subject: [PATCH 33/44] add build number to all verison --- BuildTasks/SetVersion.Task.ps1 | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 index dcfe45c..bb023f7 100644 --- a/BuildTasks/SetVersion.Task.ps1 +++ b/BuildTasks/SetVersion.Task.ps1 @@ -95,23 +95,24 @@ task SetVersion { " Steping version [$bumpVersionType]" $version = [version] (Step-Version -Version $version -Type $bumpVersionType) - if ($null -ne $env:Build_BuildID) - { - $build = $env:Build_BuildID - $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) - } - elseif ($null -ne $env:APPVEYOR_BUILD_ID) - { - $build = $env:APPVEYOR_BUILD_ID - $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) - } - " Comparing to source version [$sourceVersion]" if($sourceVersion -gt $version) { " Using existing version" $version = $sourceVersion } + + if ( -not [string]::IsNullOrEmpty( $env:Build_BuildID ) ) + { + $build = $env:Build_BuildID + $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) + } + elseif ( -not [string]::IsNullOrEmpty( $env:APPVEYOR_BUILD_ID ) ) + { + $build = $env:APPVEYOR_BUILD_ID + $version = [version]::new($version.Major, $version.Minor, $version.Build, $build) + } + " Setting version [$version]" Update-Metadata -Path $ManifestPath -PropertyName 'ModuleVersion' -Value $version From 4433d8b88fe0431d12856df009259aa6b2b87fcd Mon Sep 17 00:00:00 2001 From: Travis Drake Date: Wed, 5 Sep 2018 11:10:43 -0700 Subject: [PATCH 34/44] fixing output clean and making build init vars verbose output --- BuildTasks/Clean.Task.ps1 | 15 +++++++++------ BuildTasks/InvokeBuildInit.ps1 | 21 +++++++++++---------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/BuildTasks/Clean.Task.ps1 b/BuildTasks/Clean.Task.ps1 index 59b3ebf..7ccead5 100644 --- a/BuildTasks/Clean.Task.ps1 +++ b/BuildTasks/Clean.Task.ps1 @@ -1,9 +1,12 @@ task Clean { - 'Cleaning Output files...' - $null = Get-ChildItem -Path $Output -File -Recurse | - Remove-Item -Force -ErrorAction 'Ignore' + if (Test-Path $Output) + { + "Cleaning Output files in [$Output]..." + $null = Get-ChildItem -Path $Output -File -Recurse | + Remove-Item -Force -ErrorAction 'Ignore' - 'Cleaning Output directories...' - $null = Get-ChildItem -Path $Output -Directory -Recurse | - Remove-Item -Recurse -Force -ErrorAction 'Ignore' + "Cleaning Output directories in [$Output]..." + $null = Get-ChildItem -Path $Output -Directory -Recurse | + Remove-Item -Recurse -Force -ErrorAction 'Ignore' + } } diff --git a/BuildTasks/InvokeBuildInit.ps1 b/BuildTasks/InvokeBuildInit.ps1 index d231732..620e51d 100644 --- a/BuildTasks/InvokeBuildInit.ps1 +++ b/BuildTasks/InvokeBuildInit.ps1 @@ -1,30 +1,31 @@ -Write-Verbose "Initializing build variables" +Write-Verbose "Initializing build variables" -Verbose +Write-Verbose " Existing BuildRoot [$BuildRoot]" -Verbose $Script:DocsPath = Join-Path -Path $BuildRoot -ChildPath 'Docs' -Write-Verbose " DocsPath [$DocsPath]" +Write-Verbose " DocsPath [$DocsPath]" -Verbose $Script:Output = Join-Path -Path $BuildRoot -ChildPath 'Output' -Write-Verbose " Output [$Output]" +Write-Verbose " Output [$Output]" -Verbose $Script:Source = Join-Path -Path $BuildRoot -ChildPath $ModuleName -Write-Verbose " Source [$Source]" +Write-Verbose " Source [$Source]" -Verbose $Script:Destination = Join-Path -Path $Output -ChildPath $ModuleName -Write-Verbose " Destination [$Destination]" +Write-Verbose " Destination [$Destination]" -Verbose $Script:ManifestPath = Join-Path -Path $Destination -ChildPath "$ModuleName.psd1" -Write-Verbose " ManifestPath [$ManifestPath]" +Write-Verbose " ManifestPath [$ManifestPath]" -Verbose $Script:ModulePath = Join-Path -Path $Destination -ChildPath "$ModuleName.psm1" -Write-Verbose " ModulePath [$ModulePath]" +Write-Verbose " ModulePath [$ModulePath]" -Verbose $Script:Folders = 'Classes', 'Includes', 'Internal', 'Private', 'Public', 'Resources' -Write-Verbose " Folders [$Folders]" +Write-Verbose " Folders [$Folders]" -Verbose $Script:TestFile = "$BuildRoot\Output\TestResults_PS$PSVersion`_$TimeStamp.xml" -Write-Verbose " TestFile [$TestFile]" +Write-Verbose " TestFile [$TestFile]" -Verbose $Script:PSRepository = 'PSGallery' -Write-Verbose " PSRepository [$TestFile]" +Write-Verbose " PSRepository [$TestFile]" -Verbose function taskx($Name, $Parameters) { task $Name @Parameters -Source $MyInvocation } From da5b7b2c46a75ff4dcfd0f63ff2261bc33428605 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 16 Oct 2018 09:04:18 -0700 Subject: [PATCH 35/44] Add license file to the built module resolves #14 --- BuildTasks/Copy.Task.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BuildTasks/Copy.Task.ps1 b/BuildTasks/Copy.Task.ps1 index 9a43b8e..2daadd3 100644 --- a/BuildTasks/Copy.Task.ps1 +++ b/BuildTasks/Copy.Task.ps1 @@ -20,4 +20,10 @@ task Copy { 'Creating [.{0}]...' -f $directory.FullName.Replace($buildroot, '') Copy-Item -Path $directory.FullName -Destination $Destination -Recurse -Force } + + $license = Join-Path -Path $buildroot -ChildPath 'LICENSE' + if ( Test-Path -Path $license -PathType Leaf ) + { + Copy-Item -Path $license -Destination $Destination + } } From 915ccb5dbce9780e57014c13c43d168ef817b9c1 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 16 Oct 2018 09:09:10 -0700 Subject: [PATCH 36/44] add better handling of $null values when setting the version --- BuildTasks/SetVersion.Task.ps1 | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/BuildTasks/SetVersion.Task.ps1 b/BuildTasks/SetVersion.Task.ps1 index bb023f7..1587856 100644 --- a/BuildTasks/SetVersion.Task.ps1 +++ b/BuildTasks/SetVersion.Task.ps1 @@ -62,14 +62,10 @@ task SetVersion { "Downloading published module to check for breaking changes" $publishedModule | Save-Module -Path $downloadFolder - [System.Collections.Generic.HashSet[string]] $publishedInterface = GetModulePublicInterfaceMap -Path (Join-Path $downloadFolder $ModuleName) - [System.Collections.Generic.HashSet[string]] $buildInterface = GetModulePublicInterfaceMap -Path $ManifestPath - if ($null -eq $publishedInterface) - { - $publishedInterface = [System.Collections.Generic.HashSet[string]]::new() - } + [System.Collections.Generic.HashSet[string]] $publishedInterface = @(GetModulePublicInterfaceMap -Path (Join-Path $downloadFolder $ModuleName)) + [System.Collections.Generic.HashSet[string]] $buildInterface = @(GetModulePublicInterfaceMap -Path $ManifestPath) - if( -not $publishedInterface.IsSubsetOf($buildInterface)) + if (-not $publishedInterface.IsSubsetOf($buildInterface)) { $bumpVersionType = 'Major' } From e20c048eb13c408077a29da1fe5b9cd7833302c3 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 16 Oct 2018 09:14:03 -0700 Subject: [PATCH 37/44] add support for Azure DevOps Pipelines resolves #18 --- BuildTasks/PublishModule.Task.ps1 | 12 +++++++++--- azure-pipelines.yml | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 azure-pipelines.yml diff --git a/BuildTasks/PublishModule.Task.ps1 b/BuildTasks/PublishModule.Task.ps1 index 305e19d..bf01c12 100644 --- a/BuildTasks/PublishModule.Task.ps1 +++ b/BuildTasks/PublishModule.Task.ps1 @@ -2,17 +2,22 @@ task PublishModule { if ( $ENV:BHBuildSystem -ne 'Unknown' -and $ENV:BHBranchName -eq "master" -and - [string]::IsNullOrWhiteSpace($ENV:APPVEYOR_PULL_REQUEST_NUMBER) -and - -not [string]::IsNullOrWhiteSpace($ENV:NugetApiKey)) + -not [string]::IsNullOrWhiteSpace($ENV:nugetapikey)) { $publishModuleSplat = @{ Path = $Destination - NuGetApiKey = $ENV:NugetApiKey + NuGetApiKey = $ENV:nugetapikey Verbose = $true Force = $true Repository = $PSRepository ErrorAction = 'Stop' } + "Files in module output:" + Get-ChildItem $Destination -Recurse -File | + Select-Object -Expand FullName + + "Publishing [$Destination] to [$PSRepository]" + Publish-Module @publishModuleSplat } else @@ -20,6 +25,7 @@ task PublishModule { "Skipping deployment: To deploy, ensure that...`n" + "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + + "`t* The repository APIKey is defined in `$ENV:nugetapikey (Current: $(![string]::IsNullOrWhiteSpace($ENV:nugetapikey))) `n" + "`t* This is not a pull request" } } diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..c982e14 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,26 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +#resources: +#- repo: self +# clean: true +# fetchDepth: 1 +#queue: +# name: Hosted VS2017 +trigger: + batch: true + branches: + include: + - master + +pool: + vmImage: 'Ubuntu 16.04' + +steps: +- script: pwsh -File build.ps1 Publish + displayName: 'Build and Publish Module' + env: + nugetapikey: $(nugetapikey) + From 00de5a093a3028df08b0515c68afd15841e0fdfc Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 16 Oct 2018 09:15:50 -0700 Subject: [PATCH 38/44] remove comments --- BuildTasks/BuildModule.Task.ps1 | 2 +- azure-pipelines.yml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/BuildTasks/BuildModule.Task.ps1 b/BuildTasks/BuildModule.Task.ps1 index 7b2fc88..85df93c 100644 --- a/BuildTasks/BuildModule.Task.ps1 +++ b/BuildTasks/BuildModule.Task.ps1 @@ -86,6 +86,6 @@ taskx BuildModule @{ Set-Content -Path $ModulePath -Value $sb.ToString() -Encoding 'UTF8' 'Moving "#Requires" statements and "using" directives...' - Move-Statement -Path $ModulePath -Type 'Comment', 'Keyword' -Token '#Requires', 'using' -Index 0 + #Move-Statement -Path $ModulePath -Type 'Comment', 'Keyword' -Token '#Requires', 'using' -Index 0 } } diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c982e14..d976f2c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,8 +7,7 @@ #- repo: self # clean: true # fetchDepth: 1 -#queue: -# name: Hosted VS2017 + trigger: batch: true branches: From fecb5d3605bb57c32d5bfd87d18224a24f7226e6 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 16 Oct 2018 09:16:49 -0700 Subject: [PATCH 39/44] revert commit --- BuildTasks/BuildModule.Task.ps1 | 2 +- azure-pipelines.yml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/BuildTasks/BuildModule.Task.ps1 b/BuildTasks/BuildModule.Task.ps1 index 85df93c..7b2fc88 100644 --- a/BuildTasks/BuildModule.Task.ps1 +++ b/BuildTasks/BuildModule.Task.ps1 @@ -86,6 +86,6 @@ taskx BuildModule @{ Set-Content -Path $ModulePath -Value $sb.ToString() -Encoding 'UTF8' 'Moving "#Requires" statements and "using" directives...' - #Move-Statement -Path $ModulePath -Type 'Comment', 'Keyword' -Token '#Requires', 'using' -Index 0 + Move-Statement -Path $ModulePath -Type 'Comment', 'Keyword' -Token '#Requires', 'using' -Index 0 } } diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d976f2c..c982e14 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,8 @@ #- repo: self # clean: true # fetchDepth: 1 - +#queue: +# name: Hosted VS2017 trigger: batch: true branches: From ace42677ad4c5d60b892c4d776cee45ebd08be2f Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Tue, 16 Oct 2018 09:17:29 -0700 Subject: [PATCH 40/44] remove comment --- azure-pipelines.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c982e14..d976f2c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,8 +7,7 @@ #- repo: self # clean: true # fetchDepth: 1 -#queue: -# name: Hosted VS2017 + trigger: batch: true branches: From b625193e997023c34e7e77019e675942f9c8ef85 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Wed, 17 Oct 2018 11:12:21 -0700 Subject: [PATCH 41/44] add temporary Move-Statement #3 --- BuildTasks/BuildModule.Task.ps1 | 123 ++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/BuildTasks/BuildModule.Task.ps1 b/BuildTasks/BuildModule.Task.ps1 index 7b2fc88..5b3247c 100644 --- a/BuildTasks/BuildModule.Task.ps1 +++ b/BuildTasks/BuildModule.Task.ps1 @@ -1,4 +1,9 @@ +# namespaces for Move-Statement +using namespace System.Collections.Generic +using namespace System.IO +using namespace System.Management.Automation + function Import-ClassOrder { [cmdletbinding()] @@ -18,6 +23,124 @@ function Import-ClassOrder } } +# Temporarily added this here to be refactored/replaced by LDModuleBuilder Module + + +function Move-Statement +{ +<# +.SYNOPSIS + Moves statements containing a specified token to the specified index in a file. +.DESCRIPTION + Move-Statement moves statements containing a specified token, to the specified index + in a file. This can be used when building a module to move any using directives and + #Requires statements to the top of a file. +.PARAMETER Path + Specifies the path to an item to get its contents. +.PARAMETER Type + Specifies the type of tokens to examine. Accepted values include "Comment" and "Keyword". +.PARAMETER Token + Specifies the contents to filter on when examining a supplied token. +.PARAMETER Index + Specifies the line to move a statement to. Each line in an item has a corresponding + index, starting from 0. +.EXAMPLE + Move-Statement -Path $Path -Type 'Comment', 'Keyword' -Token '#Requires', 'using' -Index 0 + + Moves any using directives or #Requires statements to the top of a file. +.NOTES + Copy/Paste from LDModuleBuilder +#> + [CmdletBinding(SupportsShouldProcess)] + + param( + [Parameter(Mandatory, + Position = 0, + ValueFromPipeline, + ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [ValidateScript({ Test-Path -Path $PSItem })] + [string] $Path, + + [Parameter(Position = 1, + ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [ValidateSet('Comment', 'Keyword')] + [string[]] $Type = ('Comment', 'Keyword'), + + [Parameter(Position = 2, + ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string[]] $Token = ('#Requires', 'using'), + + [Parameter(Position = 3, + ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int] $Index = 0 + ) + + process + { + try + { + $statements = [SortedSet[String]]::new( + [StringComparer]::InvariantCultureIgnoreCase + ) + + Write-Verbose -Message "Reading content from $Path..." + $content = [List[String]] ([File]::ReadLines($Path)) + + Write-Verbose -Message "Tokenizing content from $Path..." + $tokens = [PSParser]::Tokenize($content, [ref] $null) + + $match = $Token -join '|' + + Write-Verbose -Message 'Matching tokens...' + Write-Verbose -Message "Type = [$Type]; Token = [$Token]" + $keywords = $tokens.Where({ + $PSItem.Type -in $Type -and + $PSItem.Content -imatch "^(?:$match)" + }) + + if (-not $keywords) { + Write-Verbose -Message 'No matching tokens found! Returning...' + return + } + + $offset = 1 + foreach ($keyword in $keywords) + { + $line = $keyword.StartLine - $offset + + Write-Verbose -Message "Moving [$($content[$line])] to Index [$Index]..." + $null = $statements.Add($content[$line]), + $content.RemoveAt($line) + $offset++ + } + + [string[]] $comments, [string[]] $statements = $statements.Where({ + $PSItem -match '^#' + }, 'Split') + + foreach ($item in ($statements, $comments)) + { + $content.Insert($Index, '') + $content.InsertRange($Index, $item) + } + + if ($PSCmdlet.ShouldProcess($Path, $MyInvocation.MyCommand.Name)) + { + Write-Verbose -Message "Writing content to $Path..." + [File]::WriteAllLines($Path, $content) + } + } + catch + { + $PSCmdlet.ThrowTerminatingError($PSItem) + } + } +} + taskx BuildModule @{ Inputs = (Get-ChildItem -Path $Source -Recurse -Filter *.ps1) Outputs = $ModulePath From 716ecdfba261348562516299dd38f01851902471 Mon Sep 17 00:00:00 2001 From: Travis Drake Date: Mon, 5 Nov 2018 13:35:02 -0800 Subject: [PATCH 42/44] LDX-995 Exclude to avoid psscriptanalyzer transient failures --- ScriptAnalyzerSettings.psd1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ScriptAnalyzerSettings.psd1 b/ScriptAnalyzerSettings.psd1 index c338b30..e42e87d 100644 --- a/ScriptAnalyzerSettings.psd1 +++ b/ScriptAnalyzerSettings.psd1 @@ -18,7 +18,7 @@ # Use ExcludeRules when you want to run most of the default set of rules except # for a few rules you wish to "exclude". Note: if a rule is in both IncludeRules # and ExcludeRules, the rule will be excluded. - #ExcludeRules = @('PSAvoidUsingWriteHost') + ExcludeRules = @('PSUseToExportFieldsInManifest','PSMissingModuleManifestField') # You can use the following entry to supply parameters to rules that take parameters. # For instance, the PSAvoidUsingCmdletAliases rule takes a whitelist for aliases you @@ -31,4 +31,4 @@ # version 6.0.0-alpha, on Linux. # PSUseCompatibleCmdlets = @{Compatibility = @("core-6.0.0-alpha-linux")} } -} \ No newline at end of file +} From 5bdaa3446ee1cbe2e536e45dd6457870648a9a8d Mon Sep 17 00:00:00 2001 From: Travis Drake Date: Mon, 12 Nov 2018 11:53:15 -0800 Subject: [PATCH 43/44] LDX-1015 ImportDevModule should force import so it can be rerun in the same session and pick up new changes --- BuildTasks/ImportDevModule.Task.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BuildTasks/ImportDevModule.Task.ps1 b/BuildTasks/ImportDevModule.Task.ps1 index ea36fcc..c868aa7 100644 --- a/BuildTasks/ImportDevModule.Task.ps1 +++ b/BuildTasks/ImportDevModule.Task.ps1 @@ -1,4 +1,4 @@ task ImportDevModule { - ImportModule -Path "$Source\$ModuleName.psd1" + ImportModule -Path "$Source\$ModuleName.psd1" -Force } From b38aca3e80296d1989624b3ccf19bcbb36637d69 Mon Sep 17 00:00:00 2001 From: Travis Drake Date: Mon, 12 Nov 2018 13:17:19 -0800 Subject: [PATCH 44/44] LDX-1015 fix psd1 trailing whitespace --- BuildTasks/UpdateSource.Task.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/BuildTasks/UpdateSource.Task.ps1 b/BuildTasks/UpdateSource.Task.ps1 index 730ab9a..fa46401 100644 --- a/BuildTasks/UpdateSource.Task.ps1 +++ b/BuildTasks/UpdateSource.Task.ps1 @@ -1,3 +1,6 @@ task UpdateSource { Copy-Item -Path $ManifestPath -Destination "$Source\$ModuleName.psd1" + + $content = Get-Content -Path "$Source\$ModuleName.psd1" -Raw -Encoding UTF8 + $content.Trim() | Set-Content -Path "$Source\$ModuleName.psd1" -Encoding UTF8 }