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