Update pwsh style to latest community standards #52

Merged
OCram85 merged 19 commits from rework2022 into master 2022-06-28 08:56:33 +02:00
14 changed files with 533 additions and 168 deletions
Showing only changes of commit b3342d4ebb - Show all commits

31
.editorconfig Normal file
View File

@ -0,0 +1,31 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = crlf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.yml]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{.gitattributes,.gitignore,.gitkeep}]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true

22
.gitattributes vendored
View File

@ -1,2 +1,24 @@
# images
*.jpg binary
*.jpeg binary
*.bmp binary
*.tiff binary
*.png binary
*.svg binary
*.ico binary
# binary files
*.exe binary
*.dll binary
# PowerShell specific
*.ps1 working-tree-encoding=UTF-8
*.psm1 working-tree-encoding=UTF-8
*.psd1 working-tree-encoding=UTF-8
# set markdown to lf for online editing
*.md working-tree-encoding=UTF-8
# Vendor resources config
src/Vendor/libressl255/* filter=lfs diff=lfs merge=lfs -text
*.pfx filter=lfs diff=lfs merge=lfs -text

15
.gitignore vendored
View File

@ -1,3 +1,18 @@
# Don't local track test builds
bin/PSCredentialStore.zip
bin/PSCredentialStore/*
# Basic ignore patterns
*.log
*.secret
# data dir related prod files
data/*.csv
# Ignore templ build artifacts
/bin/*
!bin/.gitkeep
# Ignore Unit Test result files
coverage.xml
testResults.xml

42
.vscode/cSpell.json vendored
View File

@ -1,40 +1,22 @@
// cSpell Settings
{
// Version of the setting file. Always 0.1
"version": "0.1",
"version": "0.2",
// language - current active spelling language
"language": "en",
"language": "en,de,de-DE",
// words - list of words to be always considered correct
"words": [
"Cmdlet",
"Cmdlets",
"GUID",
"Hashtable",
"Httpclient",
"Multipart",
"NTFS",
"Params",
"Ponduit",
"Repo",
"Veyor",
"appveyor",
"callsign",
"choco",
"chocolatey",
"codecoverage",
"creds",
"formdata",
"googlemail",
"notlike",
"notmatch",
"powershellgallery",
"testresults",
"wildcards"
],
"words": [],
// flagWords - list of words to be always considered incorrect
// This is useful for offensive words and common spelling errors.
// For example "hte" should be "the"
"flagWords": [
"hte"
"flagWords": [],
"dictionaryDefinitions": [
{
"name": "default",
"path": "./dictionaries/default.txt"
}
],
"dictionaries": [
"default"
]
}

0
.vscode/dictionaries/default.txt vendored Normal file
View File

13
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,13 @@
{
"recommendations": [
"streetsidesoftware.code-spell-checker",
"streetsidesoftware.code-spell-checker-german",
"hediet.vscode-drawio",
"editorconfig.editorconfig",
"eamodio.gitlens",
"vscode-icons-team.vscode-icons",
"redhat.vscode-xml",
"redhat.vscode-yaml",
"ryanluker.vscode-coverage-gutters"
]
}

2
.vscode/launch.json vendored
View File

@ -42,7 +42,7 @@
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Interactive Session",
"cwd": ""
"cwd": "${workspaceRoot}"
}
]
}

31
.vscode/pwsh.code-snippets vendored Normal file
View File

@ -0,0 +1,31 @@
{
// Place your PowerShell-Module workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
// "Print to console": {
// "scope": "javascript,typescript",
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
// PSScriptAnalyzder Rule Suppression
"Rule Suppression": {
"scope": "powershell",
"prefix": "[Diag",
"description": "Suppresses Scriptanalyzer Rules",
"body": [
"[Diagnostics.CodeAnalysis.SuppressMessageAttribute(",
" '${1|PSProvideCommentHelp,PSAvoidLongLines,PSAvoidUsingWriteHost,PSUseShouldProcessForStateChangingFunctions|}',",
" '',",
" Justification = '${justification}'",
")]"
]
}
}

45
.vscode/settings.json vendored
View File

@ -1,34 +1,15 @@
// Place your settings in this file to overwrite default and user settings.
{
// Set basic file related options:
"files.encoding": "utf8",
"files.eol": "\r\n",
"files.eol": "auto",
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
// Formation and editor options
"editor.renderWhitespace": "boundary",
"editor.formatOnSave": true,
"editor.formatOnType": true,
"editor.rulers": [
116
],
// powershell general
"powershell.startAutomatically": true,
"powershell.useX86Host": false,
"powershell.enableProfileLoading": true,
"powershell.scriptAnalysis.enable": true,
// powershell code Formatting
"powershell.codeFormatting.openBraceOnSameLine": true,
"powershell.codeFormatting.newLineAfterOpenBrace": true,
"powershell.codeFormatting.newLineAfterCloseBrace": true,
"powershell.codeFormatting.whitespaceBeforeOpenBrace": true,
"powershell.codeFormatting.whitespaceBeforeOpenParen": true,
"powershell.codeFormatting.whitespaceAroundOperator": true,
"powershell.codeFormatting.whitespaceAfterSeparator": true,
"powershell.codeFormatting.ignoreOneLineBlock": true,
"powershell.codeFormatting.alignPropertyValuePairs": true,
"powershell.codeFormatting.preset": "Custom",
// cspell spellchecker options
"cSpell.enabled": true,
"cSpell.enabledLanguageIds": [
"c",
"cpp",
@ -46,6 +27,26 @@
"text",
"typescript",
"typescriptreact",
"yaml",
"yml"
]
],
"cSpell.language": "en,de,de-DE",
// powershell general
"powershell.startAutomatically": true,
"powershell.useX86Host": false,
"powershell.enableProfileLoading": true,
"powershell.scriptAnalysis.enable": true,
// powershell code Formatting
"powershell.codeFormatting.openBraceOnSameLine": true,
"powershell.codeFormatting.newLineAfterOpenBrace": true,
"powershell.codeFormatting.newLineAfterCloseBrace": true,
"powershell.codeFormatting.whitespaceBeforeOpenBrace": true,
"powershell.codeFormatting.whitespaceBeforeOpenParen": true,
"powershell.codeFormatting.whitespaceAroundOperator": true,
"powershell.codeFormatting.whitespaceAfterSeparator": true,
"powershell.codeFormatting.ignoreOneLineBlock": true,
"powershell.codeFormatting.alignPropertyValuePairs": true,
"powershell.scriptAnalysis.settingsPath": "./tools/PSScriptAnalyzerSettings.psd1",
"coverage-gutters.showGutterCoverage": false,
"coverage-gutters.showLineCoverage": true
}

151
.vscode/tasks.json vendored
View File

@ -1,56 +1,121 @@
// A task runner that invokes Pester to run all Pester tests under the
// current workspace folder.
// NOTE: This Test task runner requires an updated version of Pester (>=4.0.3)
// in order for the problemMatcher to find failed test information (message, line, file).
// If you don't have that version, you can update Pester from the PowerShell Gallery
// with this command:
//
// PS C:\> Update-Module Pester
//
// If that gives an error like:
// "Module 'Pester' was not installed by using Install-Module, so it cannot be updated."
// then execute:
//
// PS C:\> Install-Module Pester -Scope CurrentUser -Force
//
// NOTE: The Clean, Build and Publish tasks require PSake. PSake can be installed
// from the PowerShell Gallery with this command:
//
// PS C:\> Install-Module PSake -Scope CurrentUser -Force
//
// Available variables which can be used inside of strings:
// ${workspaceFolder} the path of the workspace folder that contains the tasks.json file
// ${workspaceFolderBasename} the name of the workspace folder that contains the tasks.json file without any slashes (/)
// ${file} the current opened file
// ${relativeFile} the current opened file relative to the workspace folder containing the file
// ${fileBasename} the current opened file's basename
// ${fileBasenameNoExtension} the current opened file's basename without the extension
// ${fileDirname} the current opened file's dirname
// ${fileExtname} the current opened file's extension
// ${cwd} the task runner's current working directory on startup
// ${lineNumber} the current selected line number in the active file
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
// Start PowerShell
"windows": {
"command": "${env:windir}/System32/WindowsPowerShell/v1.0/powershell.exe",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass"
]
},
//"windows": {
// "options": {
// "shell": {
// // switch back to windows powershell 5.1
// // "executable": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
// "executable": "pwsh.exe",
// "args": [
// "-NoProfile",
// "-ExecutionPolicy",
// "Bypass",
// "-Command"
// ]
// }
// }
//},
"linux": {
"command": "/usr/bin/powershell",
"args": [
"-NoProfile"
]
},
"osx": {
"command": "/usr/local/bin/powershell",
"args": [
"-NoProfile"
]
"options": {
"shell": {
"executable": "/usr/bin/pwsh",
"args": [
"-NoProfile",
"-Command"
]
}
}
},
//"osx": {
// "options": {
// "shell": {
// "executable": "/usr/local/bin/pwsh",
// "args": [
// "-NoProfile",
// "-Command"
// ]
// }
// }
//},
"tasks": [
{
"taskName": "Test",
"suppressTaskName": true,
"args": [
"Write-Host 'Invoking Pester...'; $ProgressPreference = 'SilentlyContinue'; Invoke-Pester -Script ( Get-ChildItem -Path '.\\tests\\*.Tests.ps1' -Recurse | Sort-Object -Property Name ) -EnableExit $flase -PesterOption @{IncludeVSCodeMarker=$true};",
"Invoke-Command { Write-Host 'Completed Test task in task runner.' }"
"label": "DroneIO: Invoke-Linter",
"type": "shell",
"command": [
"Import-Module ./tools/DroneIO.psm1;",
"Invoke-Linterq | Format-Table -AutoSize"
],
"problemMatcher": "$pester",
"group": {
"kind": "test",
"isDefault": true
}
"group": "test",
"problemMatcher": [
"$pester"
]
},
{
"taskName": "DebugBuild",
"suppressTaskName": true,
"args": [
"Write-Host 'Invoking Build...';",
"Write-Host -Object 'Test previous builds.' -ForegroundColor Blue;",
"If (Test-Path -Path '.\\bin\\PSCredentialStore.zip') { Remove-Item -Path '.\\bin\\PSCredentialStore.zip' -Verbose};",
"Copy-Item -Path '.\\src\\' -Destination '.\\bin\\PSCredentialStore' -Recurse -Verbose -Force;",
"Compress-Archive -Path '.\\src\\*' -DestinationPath '.\\bin\\PSCredentialStore.zip' -Update -Verbose;"
"label": "DroneIO: Invoke-UnitTest",
"type": "shell",
"command": [
"Remove-Item ./coverage.xml -ErrorAction 'SilentlyContinue';",
"Remove-Item ./testResults.xml -ErrorAction 'SilentlyContinue';",
"Import-Module ./tools/DroneIO.psm1;",
"Invoke-UnitTest -CoverageFormat 'CoverageGutters' -Verbosity 'Debug'"
],
"group": {
"kind": "build",
"isDefault": true
}
"group": "test",
"problemMatcher": [
"$pester"
]
},
{
"label": "Add dictionary item",
"type": "shell",
"command": [
"$DefaultFile = Get-ChildItem -Path './.vscode/dictionaries/default.txt';",
"$Content = Get-Content -Path $DefaultFile;",
"$Content += '${input:DictionaryItem}';",
"$Content = $Content | Sort-Object -Unique;",
"Set-Content -Value $Content -Path $DefaultFile"
],
"group": "none",
"problemMatcher": [
"$pester"
]
}
],
"inputs": [
{
"id": "DictionaryItem",
"type": "promptString",
"description": "Input for dictionary file default.txt"
}
]
}

14
src/PSModule.Tests.ps1 Normal file
View File

@ -0,0 +1,14 @@
Describe 'Test module meta' {
It 'Test manifest file' {
$ManifestFile = (Get-Item -Path "./src/*.psd1").FullName
Test-ModuleManifest -Path $ManifestFile | Should -Be $true
}
It 'Import Module' {
$ManifestFile = (Get-Item -Path "./src/*.psd1").FullName
{ Import-Module $ManifestFile } | Should -Not -Throw
}
# Dummy test to force pester error
#It 'Force Pester Error' {
# $true | Should -BeFalse
#}
}

View File

@ -1,7 +1,13 @@
$Global:ProgressPreference = 'SilentlyContinue'
$ErrorActionPreference = 'Stop'
function Invoke-ShowEnv {
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSProvideCommentHelp',
'',
Justification = 'internal function'
)]
param ()
process {
@ -11,6 +17,16 @@ function Invoke-ShowEnv {
function Invoke-InstallDependencies {
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSProvideCommentHelp',
'',
Justification = 'internal function'
)]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSUseSingularNouns',
'',
Justification = 'internal function'
)]
param ()
process {
@ -36,44 +52,78 @@ function Invoke-InstallDependencies {
function Invoke-Linter {
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSProvideCommentHelp',
'',
Justification = 'internal function'
)]
param ()
process {
Invoke-ScriptAnalyzer -Path './src/' -Recurse
Import-Module -Name PSScriptAnalyzer
$AnalyzerSettings = @{
Path = './src/'
Recurse = $true
Settings = './tools/PSScriptAnalyzerSettings.psd1'
ReportSummary = $true
}
Invoke-ScriptAnalyzer @AnalyzerSettings
}
}
function Invoke-UnitTests {
function Invoke-UnitTest {
[CmdletBinding()]
param ()
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSProvideCommentHelp',
'',
Justification = 'internal function'
)]
param (
[Parameter( Mandatory = $false )]
[ValidateSet('JaCoCo', 'CoverageGutters')]
[string]$CoverageFormat = 'JaCoCo',
[Parameter(Mandatory = $false)]
[ValidateSet('None', 'Normal', 'Detailed', 'Diagnostic')]
[string]$Verbosity = 'Normal',
[Parameter(Mandatory = $false)]
[switch]$PassThru,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string[]]$Tag,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string[]]$ExcludeTag
)
process {
try {
Write-Host '===== Preload internal private functions =====' -ForegroundColor Black -BackgroundColor Yellow
$Privates = Get-ChildItem -Path (Join-Path -Path $Env:DRONE_WORKSPACE -ChildPath '/src/Private/*') -Include "*.ps1" -Recurse -ErrorAction Stop
foreach ($File in $Privates) {
if (Test-Path -Path $File.FullName) {
. $File.FullName
Write-Verbose -Message ('Private function dot-sourced: {0}' -f $File.FullName) -Verbose
}
else {
Write-Warning -Message ('Could not find file: {0} !' -f $File.FullName)
}
}
Write-Verbose -Message '===== Running Pester =====' -Verbose:$VerbosePreference
$PesterConf = New-PesterConfiguration
$PesterConf.Run.Path = (Resolve-Path -Path './src').Path
$PesterConf.Run.Exit = $false
$PesterConf.Run.PassThru = $true
$PesterConf.CodeCoverage.Enabled = $true
$PesterConf.CodeCoverage.OutputFormat = $CoverageFormat
$PesterConf.TestResult.Enabled = $true
$CovFiles = Get-ChildItem -Path "./src/*.ps1" -Recurse | Where-Object {
$_.BaseName -notmatch '.Tests'
} | Select-Object -ExpandProperty 'FullName'
$PesterConf.CodeCoverage.Path = $CovFiles
$PesterConf.Output.Verbosity = $Verbosity
# Set Tags if given
if ($Tag) {
$PesterConf.Filter.Tag = $Tag
}
catch {
$_.Exception.Message | Write-Error
throw 'Could not load required private functions!'
if ($ExcludeTag) {
$PesterConf.Filter.ExcludeTag = $ExcludeTag
}
Write-Host '===== Running Pester =====' -ForegroundColor Black -BackgroundColor Yellow
$srcFiles = Get-ChildItem -Path "./src/*.ps1" -Recurse | Sort-Object -Property 'Name' | Select-Object -ExpandProperty 'FullName'
$TestFiles = Get-ChildItem -Path (Join-Path -Path '.' -ChildPath './tests/*.Tests.ps1') -Recurse | Sort-Object -Property Name
$TestResults = Invoke-Pester -Path $testFiles -CodeCoverage $srcFiles -PassThru -CodeCoverageOutputFile "./coverage.xml" -CodeCoverageOutputFileEncoding ascii -CodeCoverageOutputFileFormat JaCoCo
if ($TestResults.FailedCount -gt 0) {
throw ('{0} tests failed!' -f $TestResults.FailedCount)
$TestResults = Invoke-Pester -Configuration $PesterConf -ErrorAction 'Stop'
if ($PassThru.IsPresent) {
Write-Output -InputObject $TestResults
}
}
}

View File

@ -0,0 +1,141 @@
@{
Severity = 'Error', 'Warning', 'Information'
IncludeRules = @(
'PSAlignAssignmentStatement',
'PSAvoidAssignmentToAutomaticVariable',
'PSAvoidDefaultValueForMandatoryParameter',
'PSAvoidDefaultValueSwitchParameter',
'PSAvoidGlobalAliases',
'PSAvoidGlobalFunctions',
'PSAvoidGlobalVars',
'PSAvoidInvokingEmptyMembers',
'PSAvoidLongLines',
'PSAvoidNullOrEmptyHelpMessageAttribute',
'PSAvoidOverwritingBuiltInCmdlets',
'PSAvoidShouldContinueWithoutForce',
'PSAvoidTrailingWhitespace',
'PSAvoidUsingCmdletAliases',
'PSAvoidUsingComputerNameHardcoded',
'PSAvoidUsingConvertToSecureStringWithPlainText',
'PSAvoidUsingDeprecatedManifestFields',
'PSAvoidUsingDoubleQuotesForConstantString',
'PSAvoidUsingEmptyCatchBlock',
'PSAvoidUsingInvokeExpression',
'PSAvoidUsingPlainTextForPassword',
'PSAvoidUsingPositionalParameters',
'PSAvoidUsingUsernameAndPasswordParams',
'PSAvoidUsingWMICmdlet',
'PSAvoidUsingWriteHost',
'PSMisleadingBacktick',
'PSMissingModuleManifestField',
'PSPlaceCloseBrace',
'PSPlaceOpenBrace',
'PSPossibleIncorrectComparisonWithNull',
'PSPossibleIncorrectUsageOfAssignmentOperator',
'PSPossibleIncorrectUsageOfRedirectionOperator',
'PSProvideCommentHelp',
'PSReservedCmdletChar',
'PSReservedParams',
'PSReviewUnusedParameter',
'PSShouldProcess',
'PSUseApprovedVerbs',
'PSUseBOMForUnicodeEncodedFile',
'PSUseCmdletCorrectly',
# There is no predefined set for Pwsh7 Cmdlets
'PSUseCompatibleCmdlets',
#'PSUseCompatibleCommands',
'PSUseCompatibleSyntax',
#'PSUseCompatibleTypes',
'PSUseConsistentIndentation',
# Disable if bug in 1.19.1 version occurs.
'PSUseConsistentWhitespace',
'PSUseCorrectCasing',
'PSUseDeclaredVarsMoreThanAssignments',
'PSUseLiteralInitializerForHashtable',
'PSUseOutputTypeCorrectly',
'PSUsePSCredentialType',
'PSUseProcessBlockForPipelineCommand',
'PSUseShouldProcessForStateChangingFunctions',
'PSUseSingularNouns',
'PSUseSupportsShouldProcess',
'PSUseToExportFieldsInManifest',
'PSUseUTF8EncodingForHelpFile',
'PSUseUsingScopeModifierInNewRunspaces'
)
Rules = @{
PSAvoidLongLines = @{
Enable = $true
MaximumLineLength = 116
}
PSPlaceOpenBrace = @{
Enable = $true
OnSameLine = $true
NewLineAfter = $true
IgnoreOneLineBlock = $true
}
PSPlaceCloseBrace = @{
Enable = $true
NewLineAfter = $true
IgnoreOneLineBlock = $true
NoEmptyLineBefore = $false
}
PSProvideCommentHelp = @{
Enable = $true
ExportedOnly = $false
BlockComment = $true
VSCodeSnippetCorrection = $false
Placement = "begin"
}
PSUseCompatibleCmdlets = @{
compatibility = @(
"desktop-5.1.14393.206-windows",
"core-6.1.0-windows"
)
}
PSUseCompatibleSyntax = @{
Enable = $true
TargetVersions = @(
"7.0",
"5.1"
)
}
PSUseConsistentIndentation = @{
Enable = $true
Kind = 'space'
PipelineIndentation = 'IncreaseIndentationForFirstPipeline'
IndentationSize = 4
}
PSUseConsistentWhitespace = @{
Enable = $true
CheckInnerBrace = $true
CheckOpenBrace = $true
CheckOpenParen = $true
CheckOperator = $true
CheckPipe = $true
CheckPipeForRedundantWhitespace = $false
CheckSeparator = $true
CheckParameter = $false
IgnoreAssignmentOperatorInsideHashTable = $true
}
PSAlignAssignmentStatement = @{
Enable = $true
CheckHashtable = $false
}
PSUseCorrectCasing = @{
Enable = $true
}
}
}