From dcb3f40371e32a258311d1720f74a242817f6400 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Sun, 25 Mar 2018 15:39:30 -0700 Subject: [PATCH 01/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] #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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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 } From e5a0147d7169c839d292f4eaccdab7c0f1386809 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Fri, 28 Dec 2018 15:01:15 -0800 Subject: [PATCH 45/47] Clean up Pester tests --- Docs/en-US/Format-Chronometer.md | 126 ++++++++++++++++++++++++ Docs/en-US/Get-Chronometer.md | 88 +++++++++++++++++ Docs/en-US/chronometer.md | 19 ++++ Tests/Classes/MonitoredScript.Tests.ps1 | 16 +++ Tests/Classes/ScriptLine.Tests.ps1 | 16 +++ Tests/Classes/ScriptProfiler.Tests.ps1 | 13 +++ Tests/Format-Chronometer.Tests.ps1 | 11 +++ Tests/Get-Chronometer.Tests.ps1 | 23 +++++ Tests/Help.Tests.ps1 | 30 ------ Tests/Project.Tests.ps1 | 51 ---------- Tests/Unit.Tests.ps1 | 83 ---------------- 11 files changed, 312 insertions(+), 164 deletions(-) create mode 100644 Docs/en-US/Format-Chronometer.md create mode 100644 Docs/en-US/Get-Chronometer.md create mode 100644 Docs/en-US/chronometer.md create mode 100644 Tests/Classes/MonitoredScript.Tests.ps1 create mode 100644 Tests/Classes/ScriptLine.Tests.ps1 create mode 100644 Tests/Classes/ScriptProfiler.Tests.ps1 create mode 100644 Tests/Format-Chronometer.Tests.ps1 create mode 100644 Tests/Get-Chronometer.Tests.ps1 delete mode 100644 Tests/Help.Tests.ps1 delete mode 100644 Tests/Project.Tests.ps1 delete mode 100644 Tests/Unit.Tests.ps1 diff --git a/Docs/en-US/Format-Chronometer.md b/Docs/en-US/Format-Chronometer.md new file mode 100644 index 0000000..033c8e2 --- /dev/null +++ b/Docs/en-US/Format-Chronometer.md @@ -0,0 +1,126 @@ +--- +external help file: chronometer-help.xml +Module Name: chronometer +online version: +schema: 2.0.0 +--- + +# Format-Chronometer + +## SYNOPSIS + +## SYNTAX + +### Script (Default) +``` +Format-Chronometer [-InputObject ] [-WarningAt ] [-ErrorAt ] [-ShowAll] + [] +``` + +### Line +``` +Format-Chronometer [-Line ] [-WarningAt ] [-ErrorAt ] [-ShowAll] + [] +``` + +## DESCRIPTION +Generates a report from a Chronometer + +## EXAMPLES + +### EXAMPLE 1 +``` +$script = ls C:\workspace\PSGraph\PSGraph -Recurse -Filter *.ps1 +``` + +$resultes = Get-Chronometer -Path $script.fullname -ScriptBlock {Invoke-Pester C:\workspace\PSGraph} +$results | Format-Chronometer -WarnAt 20 -ErrorAt 200 + +## PARAMETERS + +### -ErrorAt +If the average time of a comamand is more than this, the output is red + +```yaml +Type: Int32 +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: 200 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -InputObject +This is a MonitoredScript object from Get-Chronometer + +```yaml +Type: MonitoredScript[] +Parameter Sets: Script +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -Line +This is a ScriptLine object from a MonitoredScript object + +```yaml +Type: ScriptLine[] +Parameter Sets: Line +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -ShowAll +Forces the report to show scripts with no execution time + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WarningAt +If the average time of a command is more than this, the output is yellow + +```yaml +Type: Int32 +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: 20 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. +For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +## OUTPUTS + +## NOTES + +## RELATED LINKS diff --git a/Docs/en-US/Get-Chronometer.md b/Docs/en-US/Get-Chronometer.md new file mode 100644 index 0000000..2ccdaf1 --- /dev/null +++ b/Docs/en-US/Get-Chronometer.md @@ -0,0 +1,88 @@ +--- +external help file: chronometer-help.xml +Module Name: chronometer +online version: +schema: 2.0.0 +--- + +# Get-Chronometer + +## SYNOPSIS + +## SYNTAX + +``` +Get-Chronometer [-Path ] [-LineNumber ] [[-ScriptBlock] ] [] +``` + +## DESCRIPTION +Loads a script and then tracks the line by line execution times + +## EXAMPLES + +### EXAMPLE 1 +``` +Get-Chronometer -Path .\example.ps1 -Script { +``` + +.\example.ps1 +} + +## PARAMETERS + +### -LineNumber +Line numbers within the script file to measure + +```yaml +Type: Int32[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Path +Script file to measure execution times on + +```yaml +Type: Object[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -ScriptBlock +The script to start the scrupt or execute other commands + +```yaml +Type: ScriptBlock +Parameter Sets: (All) +Aliases: Script, CommandScript + +Required: False +Position: 1 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. +For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +## OUTPUTS + +## NOTES + +## RELATED LINKS diff --git a/Docs/en-US/chronometer.md b/Docs/en-US/chronometer.md new file mode 100644 index 0000000..8d269f2 --- /dev/null +++ b/Docs/en-US/chronometer.md @@ -0,0 +1,19 @@ +--- +Module Name: chronometer +Module Guid: f3719c3c-008a-4b25-b94d-fc9f587f62dd +Download Help Link: {{Please enter FwLink manually}} +Help Version: {{Please enter version of help manually (X.X.X.X) format}} +Locale: en-US +--- + +# chronometer Module +## Description +{{Manually Enter Description Here}} + +## chronometer Cmdlets +### [Format-Chronometer](Format-Chronometer.md) +{{Manually Enter Format-Chronometer Description Here}} + +### [Get-Chronometer](Get-Chronometer.md) +{{Manually Enter Get-Chronometer Description Here}} + diff --git a/Tests/Classes/MonitoredScript.Tests.ps1 b/Tests/Classes/MonitoredScript.Tests.ps1 new file mode 100644 index 0000000..bf1abe1 --- /dev/null +++ b/Tests/Classes/MonitoredScript.Tests.ps1 @@ -0,0 +1,16 @@ +InModuleScope Chronometer { + + Describe "Class: MonitoredScript" -Tag Build { + + It "Creates an object" { + {[MonitoredScript]::New()} | Should Not Throw + } + + It "SetScript()" { + + $monitor = [MonitoredScript]::New() + {$monitor.SetScript("$PSScriptRoot\..\..\scratchfiles\example.ps1")} | Should Not Throw + } + } + +} diff --git a/Tests/Classes/ScriptLine.Tests.ps1 b/Tests/Classes/ScriptLine.Tests.ps1 new file mode 100644 index 0000000..dbe2244 --- /dev/null +++ b/Tests/Classes/ScriptLine.Tests.ps1 @@ -0,0 +1,16 @@ +InModuleScope Chronometer { + Describe "Class: ScriptLine" -Tag Build { + + It "Creates an Object" { + {[ScriptLine]::New()} | Should Not Throw + } + + It "ToString()" { + {[ScriptLine]::New().toString()} | Should Not Throw + } + + It "Creates an Object" { + {[ScriptLine]::New().AddExecutionTime(1)} | Should Not Throw + } + } +} diff --git a/Tests/Classes/ScriptProfiler.Tests.ps1 b/Tests/Classes/ScriptProfiler.Tests.ps1 new file mode 100644 index 0000000..1e499d2 --- /dev/null +++ b/Tests/Classes/ScriptProfiler.Tests.ps1 @@ -0,0 +1,13 @@ +InModuleScope Chronometer { + + Describe "Class: ScriptProfiler" -Tag Build { + + It "Creates an Object" { + {[ScriptProfiler]::New()} | Should Not Throw + } + + It "Start()" { + {[ScriptProfiler]::Start()} | Should Not Throw + } + } +} diff --git a/Tests/Format-Chronometer.Tests.ps1 b/Tests/Format-Chronometer.Tests.ps1 new file mode 100644 index 0000000..d9bc862 --- /dev/null +++ b/Tests/Format-Chronometer.Tests.ps1 @@ -0,0 +1,11 @@ +Describe "Function: Format-Chronometer" -Tag Build { + + It "Does not throw" { + {$null | Format-Chronometer } | Should Not Throw + } + + It "Can process a result object without throwing" { + $results = Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {. "$PSScriptRoot\..\ScratchFiles\example.ps1"} + $results | Format-Chronometer *>&1 | Should Not BeNullOrEmpty + } +} diff --git a/Tests/Get-Chronometer.Tests.ps1 b/Tests/Get-Chronometer.Tests.ps1 new file mode 100644 index 0000000..71d9a54 --- /dev/null +++ b/Tests/Get-Chronometer.Tests.ps1 @@ -0,0 +1,23 @@ +Describe "Function: Get-Chronometer" -Tag Build { + It "Does not throw" { + # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} + {Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {"Test"} } | Should Not Throw + } + + It "Executes a script and gives results" { + # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} + $results = Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {. "$PSScriptRoot\..\ScratchFiles\example.ps1"} + $results | Should Not BeNullOrEmpty + } + + It "Executes a script with linenumbers and gives results" { + # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} + $params = @{ + Path = "$PSScriptRoot\..\ScratchFiles\example.ps1" + Script = {. "$PSScriptRoot\..\ScratchFiles\example.ps1"} + LineNumber = 2,3,5,6 + } + $results = Get-Chronometer @params + $results | Should Not BeNullOrEmpty + } +} diff --git a/Tests/Help.Tests.ps1 b/Tests/Help.Tests.ps1 deleted file mode 100644 index 7a61ead..0000000 --- a/Tests/Help.Tests.ps1 +++ /dev/null @@ -1,30 +0,0 @@ -$projectRoot = Resolve-Path "$PSScriptRoot\.." -$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psm1") -$moduleName = Split-Path $moduleRoot -Leaf - - -Describe "Help tests for $moduleName" -Tags Build { - - Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force - - $functions = Get-Command -Module $moduleName - $help = $functions | %{Get-Help $_.name} - foreach($node in $help) - { - Context $node.name { - - it "has a description" { - $node.description | Should Not BeNullOrEmpty - } - it "has an example" { - $node.examples | Should Not BeNullOrEmpty - } - foreach($parameter in $node.parameters.parameter) - { - it "parameter $($parameter.name) has a description" { - $parameter.Description.text | Should Not BeNullOrEmpty - } - } - } - } -} diff --git a/Tests/Project.Tests.ps1 b/Tests/Project.Tests.ps1 deleted file mode 100644 index 0cd47cb..0000000 --- a/Tests/Project.Tests.ps1 +++ /dev/null @@ -1,51 +0,0 @@ -$projectRoot = Resolve-Path "$PSScriptRoot\.." -$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") -$moduleName = Split-Path $moduleRoot -Leaf - -Describe "General project validation: $moduleName" -Tags Build { - - Context "Valid Powershell" { - $scripts = Get-ChildItem $projectRoot -Include *.ps1,*.psm1,*.psd1 -Recurse | where fullname -notmatch 'classes' - # TestCases are splatted to the script so we need hashtables - $testCase = $scripts | Foreach-Object{@{file=$_}} - - It "Script should be valid powershell" -TestCases $testCase { - param($file) - - $file.fullname | Should Exist - - $contents = Get-Content -Path $file.fullname -ErrorAction Stop - $errors = $null - $null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors) - $errors.Count | Should Be 0 - } - - It "Classes are valid" { - $classes = Get-ChildItem $projectRoot -Include *.ps1,*.psm1,*.psd1 -Recurse | where fullname -match 'classes' - - # Must be imported togehter incase they depend on each other - $contents = Get-Content -Path $classes.FullName | Out-String - - $errors = $null - $null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors) - $errors.Count | Should Be 0 - } - } - - Context "ScriptAnalyzer" { - - $scripts = Get-ChildItem $moduleRoot -Include *.ps1,*.psm1,*.psd1 -Recurse | where fullname -notmatch 'classes' - $testCase = $scripts | Foreach-Object{@{file=$_}} - - it "Script should pass ScriptAnalyzer rules" -TestCases $testCase { - param($file) - - $file.fullname | Should Exist - Invoke-ScriptAnalyzer $file| Should BeNullOrEmpty - } - } - - It "Module '$moduleName' can import cleanly" { - {Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force } | Should Not Throw - } -} diff --git a/Tests/Unit.Tests.ps1 b/Tests/Unit.Tests.ps1 deleted file mode 100644 index 71f832d..0000000 --- a/Tests/Unit.Tests.ps1 +++ /dev/null @@ -1,83 +0,0 @@ -$projectRoot = Resolve-Path "$PSScriptRoot\.." -$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") -$moduleName = Split-Path $moduleRoot -Leaf - -Describe "Basic unit tests" -Tags Build { - - Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force - - Context "Function: Get-Chronometer" { - it "Does not throw" { - # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} - {Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {"Test"} } | Should Not Throw - } - - it "Executes a script and gives results" { - # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} - $results = Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {. "$PSScriptRoot\..\ScratchFiles\example.ps1"} - $results | Should Not BeNullOrEmpty - } - - it "Executes a script with linenumbers and gives results" { - # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} - $params = @{ - Path = "$PSScriptRoot\..\ScratchFiles\example.ps1" - Script = {. "$PSScriptRoot\..\ScratchFiles\example.ps1"} - LineNumber = 2,3,5,6 - } - $results = Get-Chronometer @params - $results | Should Not BeNullOrEmpty - } - } - - Context "Function: Format-Chronometer" { - - it "Does not throw" { - {$null | Format-Chronometer } | Should Not Throw - } - - it "Can process a result object without throwing" { - $results = Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {. "$PSScriptRoot\..\ScratchFiles\example.ps1"} - $results | Format-Chronometer *>&1 | Should Not BeNullOrEmpty - } - } - - InModuleScope $moduleName { - Context "Class: ScriptLine" { - - it "Creates an Object" { - {[ScriptLine]::New()} | Should Not Throw - } - it "ToString()" { - {[ScriptLine]::New().toString()} | Should Not Throw - } - it "Creates an Object" { - {[ScriptLine]::New().AddExecutionTime(1)} | Should Not Throw - } - } - - Context "Class: ScriptProfiler" { - - it "Creates an Object" { - {[ScriptProfiler]::New()} | Should Not Throw - } - it "Start()" { - {[ScriptProfiler]::Start()} | Should Not Throw - } - } - - Context "Class: MonitoredScript" { - it "Creates an object" { - {[MonitoredScript]::New()} | Should Not Throw - } - - it "SetScript()" { - pushd $projectRoot - $monitor = [MonitoredScript]::New() - {$monitor.SetScript(".\scratchfiles\example.ps1")} | Should Not Throw - popd - } - } - - } -} \ No newline at end of file From 3b671a49fc38fd9633a04f3a30b83abc2a547980 Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Fri, 28 Dec 2018 15:02:24 -0800 Subject: [PATCH 46/47] bump version --- Chronometer/chronometer.psd1 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Chronometer/chronometer.psd1 b/Chronometer/chronometer.psd1 index 24c1106..96d7bb7 100644 --- a/Chronometer/chronometer.psd1 +++ b/Chronometer/chronometer.psd1 @@ -1,4 +1,4 @@ -# Module manifest for module 'chronometer' +# Module manifest for module 'chronometer' # Generated by: Kevin Marquette # Generated on: 2/2/2017 @@ -8,7 +8,7 @@ RootModule = 'chronometer.psm1' # Version number of this module. -ModuleVersion = '0.5.2' +ModuleVersion = '1.0.0' # ID used to uniquely identify this module GUID = 'f3719c3c-008a-4b25-b94d-fc9f587f62dd' @@ -17,7 +17,7 @@ GUID = 'f3719c3c-008a-4b25-b94d-fc9f587f62dd' Author = 'Kevin Marquette' # Copyright statement for this module -Copyright = '(c) 2017 Kevin Marquette. All rights reserved.' +Copyright = '(c) 2019 Kevin Marquette. All rights reserved.' # Description of the functionality provided by this module Description = 'Performs a line by line measurement of execution times for scripts' @@ -26,7 +26,7 @@ Description = 'Performs a line by line measurement of execution times for script PowerShellVersion = '5.0' # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = @('Get-Chronometer','Format-Chronometer') +FunctionsToExport = @('Format-Chronometer','Get-Chronometer') # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() @@ -55,4 +55,3 @@ PrivateData = @{ } # End of PrivateData hashtable } - From bbe311b1dcf0df5cd050867598ad6b6efe8239cf Mon Sep 17 00:00:00 2001 From: Kevin Marquette Date: Fri, 28 Dec 2018 15:03:10 -0800 Subject: [PATCH 47/47] spell check --- Tests/Get-Chronometer.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Get-Chronometer.Tests.ps1 b/Tests/Get-Chronometer.Tests.ps1 index 71d9a54..1462c47 100644 --- a/Tests/Get-Chronometer.Tests.ps1 +++ b/Tests/Get-Chronometer.Tests.ps1 @@ -10,7 +10,7 @@ Describe "Function: Get-Chronometer" -Tag Build { $results | Should Not BeNullOrEmpty } - It "Executes a script with linenumbers and gives results" { + It "Executes a script with line numbers and gives results" { # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} $params = @{ Path = "$PSScriptRoot\..\ScratchFiles\example.ps1"