Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# These are supported funding model platforms

github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
FriedrichWeinmann
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
2 changes: 1 addition & 1 deletion PSModuleDevelopment/PSModuleDevelopment.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
RootModule = 'PSModuleDevelopment.psm1'

# Version number of this module.
ModuleVersion = '2.2.7.90'
ModuleVersion = '2.2.7.98'

# ID used to uniquely identify this module
GUID = '37dd5fce-e7b5-4d57-ac37-832055ce49d6'
Expand Down
11 changes: 11 additions & 0 deletions PSModuleDevelopment/changelog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
# Changelog
## 2.2.7.98 (May 30th, 2020)

- Upd: Template PSFTest - Pester v5 compatibility
- Upd: Template PSFModule - Pester v5 compatibility
- Upd: Template PSFProject - Pester v5 compatibility
- Upd: Template PSFProject - Simplified module import workflow
- Upd: Template PSFProject - Improved build process cross-agent convenience
- Upd: Template PSFProject - Prerequisites task automatically detects module dependencies
- Upd: Template PSFProject - Prerequisites task can be configured to work with any registered repository
- Upd: Export-PSMDString - Now also detects splatted localization strings (thanks @StevePlp ; #117)

## 2.2.7.90 (September 1st, 2019)
- New: Export-PSMDString - Parses strings from modules using the PSFramework localization feature.
- Upd: Measure-PSMDCommand - Renamed from Measure-PSMDCommandEx, performance upgrades, adding option for comparing multiple test sets.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

Returns the module debugging configuration for all modules with a name that contains "net"
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
[CmdletBinding()]
Param (
[string]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
{
# Get original module configuration
$____module = $null
$____module = Import-Clixml -Path (Get-PSFConfigValue -FullName 'PSModuleDevelopment.Debug.ConfigPath') | Where-Object { $_.Name -eq $Name }
$____module = Import-Clixml -Path (Get-PSFConfigValue -FullName 'PSModuleDevelopment.Debug.ConfigPath') | Where-Object Name -eq $Name
if (-not $____module) { throw "No matching module configuration found" }

# Process entry
Expand Down
62 changes: 61 additions & 1 deletion PSModuleDevelopment/functions/refactor/Export-PSMDString.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,67 @@
StringValues = $stringValueParamValue
}
}


# Additional checks for splatted commands
# find all splatted commands
$splattedVariables = $ast.FindAll( {
if ($args[0] -isnot [System.Management.Automation.Language.VariableExpressionAst ]) { return $false }
if (-not ($args[0].Splatted -eq $true)) { return $false }
$true
}, $true)

foreach ($splattedVariable in $splattedVariables)
{
#get the variable name
$splatParamName = $splattedVariable.VariablePath.UserPath
if ($splatParamName)
{
# match the $param = @{
$splatParamNameRegex = "^\s?\`$$($splatParamName)\s?=\s?\@\{"
# get all variable assignments where the
# left side matches our param
# operator is =
# matches our assignment regex
$splatAssignmentAsts = $ast.FindAll( {
if ($args[0] -isnot [System.Management.Automation.Language.AssignmentStatementAst ]) { return $false }
if (-not ($args[0].Left -match $splatParamName)) { return $false }
if (-not ($args[0].Operator -eq 'Equals')) { return $false }
if (-not ($args[0].Extent -match $splatParamNameRegex)) { return $false }
$true
}, $true)
foreach ($splatAssignmentAst in $splatAssignmentAsts)
{
# get the hashtable
$splatHashTable = $splatAssignmentAst.Right.Expression
# see if its an empty assignment or null
if ($splatHashTable -and $splatHashTable.KeyValuePairs.Count -gt 0)
{
# find any String or ActionString
$splatParam = $splatAssignmentAst.Right.Expression.KeyValuePairs | Where-Object Item1 -match '^String$|^ActionString$'
# The kvp.item.extent.text returns nested quotes where as the commandast.extent.text doesn't so strip them off
$splatParamValue = $splatParam.Item2.Extent.Text.Trim('"').Trim("'")
# find any StringValue or ActionStringValue
$splatValueParam = $splatAssignmentAst.Right.Expression.KeyValuePairs | Where-Object Item1 -match '^StringValues$|^ActionStringValues$'
if ($splatValueParam)
{
# The kvp.item.extent.text returns nested quotes whereas the commandast.extent.text doesn't so strip them off
$splatValueParamValue = $splatValueParam.Item2.Extent.Text.Trim('"').Trim("'")
}
else { $splatValueParamValue = '' }

[PSCustomObject]@{
PSTypeName = 'PSModuleDevelopment.String.ParsedItem'
File = $file.FullName
Line = $splatHashTable.Extent.StartLineNumber
CommandName = $splattedVariable.Parent.CommandElements[0].Value
String = $splatParamValue
StringValues = $splatValueParamValue
}
}
}
}
}

$validateAsts = $ast.FindAll({
if ($args[0] -isnot [System.Management.Automation.Language.AttributeAst]) { return $false }
if ($args[0].TypeName -notmatch '^PsfValidateScript$|^PsfValidatePattern$') { return $false }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

Updates all commands in the module to have a cmdletbinding attribute.
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
[CmdletBinding(SupportsShouldProcess = $true)]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
Expand All @@ -45,6 +46,7 @@
#region Utility functions
function Invoke-AstWalk
{
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
[CmdletBinding()]
param (
$Ast,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#region Utility functions
function Invoke-AstWalk
{
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
[CmdletBinding()]
Param (
$Ast,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

foreach ($functionAst in ($ast.EndBlock.Statements | Where-Object { $_.GetType().FullName -eq "System.Management.Automation.Language.FunctionDefinitionAst" }))
{
$ast.Extent.Text.Substring($functionAst.Extent.StartOffset, ($functionAst.Extent.EndOffset - $functionAst.Extent.StartOffset)) | Set-Content "$Path\$($functionAst.Name).ps1" -Encoding UTF8
$ast.Extent.Text.Substring($functionAst.Extent.StartOffset, ($functionAst.Extent.EndOffset - $functionAst.Extent.StartOffset)) | Set-Content "$Path\$($functionAst.Name).ps1" -Encoding $Encoding
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
Creates a project based on the module template with the name "MyModule"
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSPossibleIncorrectUsageOfAssignmentOperator", "")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
[CmdletBinding(SupportsShouldProcess = $true)]
param (
[Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'NameStore')]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
- It will set authentication to windows
- It will skip the automatic restore of the project on create
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Create')]
Param (
[Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'Create')]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#region Utility Functions
function Invoke-AstWalk
{
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
[CmdletBinding()]
param (
$Ast,
Expand Down
103 changes: 54 additions & 49 deletions PSModuleDevelopment/tests/general/FileIntegrity.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,89 +1,94 @@
$moduleRoot = (Resolve-Path "$PSScriptRoot\..\..").Path
$moduleRoot = (Resolve-Path "$global:testroot\..").Path

. "$PSScriptRoot\FileIntegrity.Exceptions.ps1"

function Get-FileEncoding
{
<#
.SYNOPSIS
Tests a file for encoding.

.DESCRIPTION
Tests a file for encoding.

.PARAMETER Path
The file to test
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[Alias('FullName')]
[string]
$Path
)

[byte[]]$byte = get-content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $Path

if ($byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf) { 'UTF8' }
elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff) { 'Unicode' }
elseif ($byte[0] -eq 0 -and $byte[1] -eq 0 -and $byte[2] -eq 0xfe -and $byte[3] -eq 0xff) { 'UTF32' }
elseif ($byte[0] -eq 0x2b -and $byte[1] -eq 0x2f -and $byte[2] -eq 0x76) { 'UTF7' }
else { 'Unknown, possible ASCII' }
}
. "$global:testroot\general\FileIntegrity.Exceptions.ps1"

Describe "Verifying integrity of module files" {
BeforeAll {
function Get-FileEncoding
{
<#
.SYNOPSIS
Tests a file for encoding.

.DESCRIPTION
Tests a file for encoding.

.PARAMETER Path
The file to test
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[Alias('FullName')]
[string]
$Path
)

if ($PSVersionTable.PSVersion.Major -lt 6)
{
[byte[]]$byte = get-content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $Path
}
else
{
[byte[]]$byte = Get-Content -AsByteStream -ReadCount 4 -TotalCount 4 -Path $Path
}

if ($byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf) { 'UTF8 BOM' }
elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff) { 'Unicode' }
elseif ($byte[0] -eq 0 -and $byte[1] -eq 0 -and $byte[2] -eq 0xfe -and $byte[3] -eq 0xff) { 'UTF32' }
elseif ($byte[0] -eq 0x2b -and $byte[1] -eq 0x2f -and $byte[2] -eq 0x76) { 'UTF7' }
else { 'Unknown' }
}
}

Context "Validating PS1 Script files" {
$allFiles = Get-ChildItem -Path $moduleRoot -Recurse -Filter "*.ps1" | Where-Object FullName -NotLike "$moduleRoot\tests\*"
$allFiles = Get-ChildItem -Path $moduleRoot -Recurse | Where-Object Name -like "*.ps1" | Where-Object FullName -NotLike "$moduleRoot\tests\*"

foreach ($file in $allFiles)
{
$name = $file.FullName.Replace("$moduleRoot\", '')

It "[$name] Should have UTF8 encoding" {
Get-FileEncoding -Path $file.FullName | Should Be 'UTF8'
It "[$name] Should have UTF8 encoding with Byte Order Mark" -TestCases @{ file = $file } {
Get-FileEncoding -Path $file.FullName | Should -Be 'UTF8 BOM'
}

It "[$name] Should have no trailing space" {
($file | Select-String "\s$" | Where-Object { $_.Line.Trim().Length -gt 0} | Measure-Object).Count | Should Be 0
It "[$name] Should have no trailing space" -TestCases @{ file = $file } {
($file | Select-String "\s$" | Where-Object { $_.Line.Trim().Length -gt 0}).LineNumber | Should -BeNullOrEmpty
}

$tokens = $null
$parseErrors = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile($file.FullName, [ref]$tokens, [ref]$parseErrors)

It "[$name] Should have no syntax errors" {
$parseErrors | Should Be $Null
It "[$name] Should have no syntax errors" -TestCases @{ parseErrors = $parseErrors } {
$parseErrors | Should -BeNullOrEmpty
}

foreach ($command in $global:BannedCommands)
{
if ($global:MayContainCommand["$command"] -notcontains $file.Name)
{
It "[$name] Should not use $command" {
$tokens | Where-Object Text -EQ $command | Should Be $null
It "[$name] Should not use $command" -TestCases @{ tokens = $tokens; command = $command } {
$tokens | Where-Object Text -EQ $command | Should -BeNullOrEmpty
}
}
}

It "[$name] Should not contain aliases" {
$tokens | Where-Object TokenFlags -eq CommandName | Where-Object { Test-Path "alias:\$($_.Text)" } | Measure-Object | Select-Object -ExpandProperty Count | Should Be 0
}
}
}

Context "Validating help.txt help files" {
$allFiles = Get-ChildItem -Path $moduleRoot -Recurse -Filter "*.help.txt" | Where-Object FullName -NotLike "$moduleRoot\tests\*"
$allFiles = Get-ChildItem -Path $moduleRoot -Recurse | Where-Object Name -like "*.help.txt" | Where-Object FullName -NotLike "$moduleRoot\tests\*"

foreach ($file in $allFiles)
{
$name = $file.FullName.Replace("$moduleRoot\", '')

It "[$name] Should have UTF8 encoding" {
Get-FileEncoding -Path $file.FullName | Should Be 'UTF8'
It "[$name] Should have UTF8 encoding" -TestCases @{ file = $file } {
Get-FileEncoding -Path $file.FullName | Should -Be 'UTF8 BOM'
}

It "[$name] Should have no trailing space" {
($file | Select-String "\s$" | Where-Object { $_.Line.Trim().Length -gt 0 } | Measure-Object).Count | Should Be 0
It "[$name] Should have no trailing space" -TestCases @{ file = $file } {
($file | Select-String "\s$" | Where-Object { $_.Line.Trim().Length -gt 0 } | Measure-Object).Count | Should -Be 0
}
}
}
Expand Down
Loading