diff --git a/.github/workflows/Action-Test.yml b/.github/workflows/Action-Test.yml index 1ee2812..8b48a56 100644 --- a/.github/workflows/Action-Test.yml +++ b/.github/workflows/Action-Test.yml @@ -26,6 +26,8 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v5 + with: + persist-credentials: false - name: Action-Test uses: ./ @@ -49,6 +51,8 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v5 + with: + persist-credentials: false - name: Action-Test uses: ./ @@ -73,6 +77,8 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v5 + with: + persist-credentials: false - name: Action-Test uses: ./ @@ -89,6 +95,32 @@ jobs: Write-Host "Outcome: ${{ steps.action-test.outcome }}" Write-Host "Conclusion: ${{ steps.action-test.conclusion }}" + ActionTestSrcWithManifestDefault: + name: Action-Test - [Src-WithManifest-Default] + runs-on: ubuntu-latest + outputs: + Outcome: ${{ steps.action-test.outcome }} + Conclusion: ${{ steps.action-test.conclusion }} + steps: + - name: Checkout repo + uses: actions/checkout@v5 + with: + persist-credentials: false + + - name: Action-Test + uses: ./ + continue-on-error: true + id: action-test + with: + Path: src + WorkingDirectory: tests/srcWithManifestTestRepo + + - name: Status + shell: pwsh + run: | + Write-Host "Outcome: ${{ steps.action-test.outcome }}" + Write-Host "Conclusion: ${{ steps.action-test.conclusion }}" + ActionTestOutputs: name: Action-Test - [outputs] runs-on: ubuntu-latest @@ -98,6 +130,8 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v5 + with: + persist-credentials: false - name: Action-Test uses: ./ @@ -118,25 +152,28 @@ jobs: - ActionTestSrcSourceCode - ActionTestSrcCustom - ActionTestSrcWithManifest + - ActionTestSrcWithManifestDefault - ActionTestOutputs if: always() runs-on: ubuntu-latest env: - ActionTestSrcSourceCodeOutcome: ${{ needs.ActionTestSrcSourceCode.outputs.Outcome }} - ActionTestSrcSourceCodeConclusion: ${{ needs.ActionTestSrcSourceCode.outputs.Conclusion }} - ActionTestSrcCustomOutcome: ${{ needs.ActionTestSrcCustom.outputs.Outcome }} - ActionTestSrcCustomConclusion: ${{ needs.ActionTestSrcCustom.outputs.Conclusion }} - ActionTestSrcWithManifestOutcome: ${{ needs.ActionTestSrcWithManifest.outputs.Outcome }} - ActionTestSrcWithManifestConclusion: ${{ needs.ActionTestSrcWithManifest.outputs.Conclusion }} - ActionTestOutputsOutcome: ${{ needs.ActionTestOutputs.outputs.Outcome }} - ActionTestOutputsConclusion: ${{ needs.ActionTestOutputs.outputs.Conclusion }} + SourceCodeOutcome: ${{ needs.ActionTestSrcSourceCode.outputs.Outcome }} + SourceCodeConclusion: ${{ needs.ActionTestSrcSourceCode.outputs.Conclusion }} + CustomOutcome: ${{ needs.ActionTestSrcCustom.outputs.Outcome }} + CustomConclusion: ${{ needs.ActionTestSrcCustom.outputs.Conclusion }} + WithManifestOutcome: ${{ needs.ActionTestSrcWithManifest.outputs.Outcome }} + WithManifestConclusion: ${{ needs.ActionTestSrcWithManifest.outputs.Conclusion }} + WithManifestDefaultOutcome: ${{ needs.ActionTestSrcWithManifestDefault.outputs.Outcome }} + WithManifestDefaultConclusion: ${{ needs.ActionTestSrcWithManifestDefault.outputs.Conclusion }} + OutputsOutcome: ${{ needs.ActionTestOutputs.outputs.Outcome }} + OutputsConclusion: ${{ needs.ActionTestOutputs.outputs.Conclusion }} steps: - name: Checkout repo uses: actions/checkout@v5 + with: + persist-credentials: false - name: Aggregated Status uses: PSModule/Github-Script@v1 with: - Script: | - # Aggregated Status - tests/Get-AggregatedStatus.ps1 + Script: tests/Get-AggregatedStatus.ps1 diff --git a/.github/workflows/Auto-Release.yml b/.github/workflows/Auto-Release.yml index 50a5a41..502e551 100644 --- a/.github/workflows/Auto-Release.yml +++ b/.github/workflows/Auto-Release.yml @@ -27,6 +27,8 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v5 + with: + persist-credentials: false - name: Auto-Release uses: PSModule/Auto-Release@v1 diff --git a/.github/workflows/Linter.yml b/.github/workflows/Linter.yml index 8291fcd..90050d4 100644 --- a/.github/workflows/Linter.yml +++ b/.github/workflows/Linter.yml @@ -21,6 +21,7 @@ jobs: - name: Checkout repo uses: actions/checkout@v5 with: + persist-credentials: false fetch-depth: 0 - name: Lint code base @@ -30,4 +31,7 @@ jobs: VALIDATE_JSON_PRETTIER: false VALIDATE_MARKDOWN_PRETTIER: false VALIDATE_YAML_PRETTIER: false + VALIDATE_BIOME_FORMAT: false + VALIDATE_BIOME_LINT: false + VALIDATE_GITHUB_ACTIONS_ZIZMOR: false FILTER_REGEX_EXCLUDE: '.*Set-PSModuleTest\.ps1$' diff --git a/README.md b/README.md index bd8f204..921d0ca 100644 --- a/README.md +++ b/README.md @@ -88,16 +88,41 @@ The action provides the following outputs: Choose a path for your code to test into the `Path` input. This can be a directory or a file. -2. **Configure settings file** +2. **Configure settings file (Optional)** Create a custom settings file to customize the analysis. The settings file is a hashtable that defines the rules to include, exclude, or customize. The settings file is in the format of a `.psd1` file. - By default, the action looks for a settings file at: - `.github/linters/.powershell-psscriptanalyzer.psd1` + **Settings File Precedence:** - You can override this by setting the `SettingsFilePath` input to point to your - custom settings file. + The action determines which settings to use in the following order: + + 1. **Custom Path**: If you provide a `SettingsFilePath` input, the action uses that file. + 2. **Default Action Path**: If no `SettingsFilePath` is provided, the action looks for a settings file at: + `.github/linters/.powershell-psscriptanalyzer.psd1` + 3. **PSScriptAnalyzer Defaults**: If no settings file is found in either location, the action uses + the default settings from the `Invoke-ScriptAnalyzer` cmdlet (all built-in rules with default severity). + + **Example configurations:** + + ```yaml + # Use a custom settings file + - uses: PSModule/Invoke-ScriptAnalyzer@v2 + with: + Path: src + SettingsFilePath: config/custom-rules.psd1 + + # Use the default action path (.github/linters/.powershell-psscriptanalyzer.psd1) + - uses: PSModule/Invoke-ScriptAnalyzer@v2 + with: + Path: src + + # Use PSScriptAnalyzer defaults (no settings file) + - uses: PSModule/Invoke-ScriptAnalyzer@v2 + with: + Path: src + SettingsFilePath: '' # Explicitly skip settings file + ``` For more info on how to create a settings file, see the [Settings Documentation](./Settings.md) file. diff --git a/scripts/main.ps1 b/scripts/main.ps1 index fd2ca24..64410f1 100644 --- a/scripts/main.ps1 +++ b/scripts/main.ps1 @@ -2,7 +2,18 @@ $testPath = Resolve-Path -Path "$PSScriptRoot/tests/PSScriptAnalyzer" | Select-Object -ExpandProperty Path $path = [string]::IsNullOrEmpty($env:PSMODULE_INVOKE_SCRIPTANALYZER_INPUT_Path) ? '.' : $env:PSMODULE_INVOKE_SCRIPTANALYZER_INPUT_Path $codePath = Resolve-Path -Path $path | Select-Object -ExpandProperty Path -$settingsFilePath = Resolve-Path -Path $env:PSMODULE_INVOKE_SCRIPTANALYZER_INPUT_SettingsFilePath | Select-Object -ExpandProperty Path + +# Try to resolve the settings file path, but allow it to be null if not found +[string]$settingsFilePath = '' +if (-not [string]::IsNullOrEmpty($env:PSMODULE_INVOKE_SCRIPTANALYZER_INPUT_SettingsFilePath)) { + try { + $settingsFilePath = Resolve-Path -Path $env:PSMODULE_INVOKE_SCRIPTANALYZER_INPUT_SettingsFilePath -ErrorAction Stop | + Select-Object -ExpandProperty Path + Write-Information "Using settings file: $settingsFilePath" + } catch { + Write-Warning "Settings file not found at path: $($env:PSMODULE_INVOKE_SCRIPTANALYZER_INPUT_SettingsFilePath). Using default settings." + } +} [pscustomobject]@{ CodePath = $codePath @@ -10,9 +21,6 @@ $settingsFilePath = Resolve-Path -Path $env:PSMODULE_INVOKE_SCRIPTANALYZER_INPUT SettingsFilePath = $settingsFilePath } | Format-List | Out-String -if (!(Test-Path -Path $settingsFilePath)) { - throw "Settings file not found at path: $settingsFilePath" -} Set-GitHubOutput -Name CodePath -Value $codePath Set-GitHubOutput -Name TestPath -Value $testPath Set-GitHubOutput -Name SettingsFilePath -Value $settingsFilePath diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index d8298ed..daed804 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -11,17 +11,25 @@ Justification = 'Write-Host is used for log output.' )] [CmdLetBinding()] -Param( +param( [Parameter(Mandatory)] [string] $Path, - [Parameter(Mandatory)] + [Parameter()] [string] $SettingsFilePath ) BeforeDiscovery { - LogGroup "PSScriptAnalyzer tests using settings file [$SettingsFilePath]" { - $settings = Import-PowerShellDataFile -Path $SettingsFilePath + $hasSettingsFile = -not [string]::IsNullOrEmpty($SettingsFilePath) + $settingsDescription = $hasSettingsFile ? "settings file [$SettingsFilePath]" : 'default settings' + + LogGroup "PSScriptAnalyzer tests using $settingsDescription" { + if ($hasSettingsFile) { + $settings = Import-PowerShellDataFile -Path $SettingsFilePath + } else { + $settings = @{} + } + $rules = [Collections.Generic.List[System.Collections.Specialized.OrderedDictionary]]::new() $ruleObjects = Get-ScriptAnalyzerRule -Verbose:$false | Sort-Object -Property Severity, CommonName $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique @@ -65,13 +73,18 @@ BeforeDiscovery { Describe 'PSScriptAnalyzer' { BeforeAll { - $relativeSettingsFilePath = if ($SettingsFilePath.StartsWith($PSScriptRoot)) { - $SettingsFilePath.Replace($PSScriptRoot, 'Action:').Trim('\').Trim('/') - } elseif ($SettingsFilePath.StartsWith($env:GITHUB_WORKSPACE)) { - $SettingsFilePath.Replace($env:GITHUB_WORKSPACE, 'Workspace:').Trim('\').Trim('/') - } else { - $SettingsFilePath + $hasSettingsFile = -not [string]::IsNullOrEmpty($SettingsFilePath) + + if ($hasSettingsFile) { + $relativeSettingsFilePath = if ($SettingsFilePath.StartsWith($PSScriptRoot)) { + $SettingsFilePath.Replace($PSScriptRoot, 'Action:').Trim('\').Trim('/') + } elseif ($SettingsFilePath.StartsWith($env:GITHUB_WORKSPACE)) { + $SettingsFilePath.Replace($env:GITHUB_WORKSPACE, 'Workspace:').Trim('\').Trim('/') + } else { + $SettingsFilePath + } } + $Path = Resolve-Path -Path $Path | Select-Object -ExpandProperty Path $relativePath = if ($Path.StartsWith($PSScriptRoot)) { $Path.Replace($PSScriptRoot, 'Action:').Trim('\').Trim('/').Replace('\', '/') @@ -88,9 +101,25 @@ Describe 'PSScriptAnalyzer' { GITHUB_WORKSPACE = $env:GITHUB_WORKSPACE } - LogGroup "Invoke-ScriptAnalyzer -Path [$relativePath] -Settings [$relativeSettingsFilePath]" { - $testResults = Invoke-ScriptAnalyzer -Path $Path -Settings $SettingsFilePath -Recurse -Verbose + $invokeParams = @{ + Path = $Path + Recurse = $true + } + + if ($hasSettingsFile) { + $invokeParams['Settings'] = $SettingsFilePath } + + $logMessage = if ($hasSettingsFile) { + "Invoke-ScriptAnalyzer -Path '$relativePath' -Recurse -Settings '$relativeSettingsFilePath'" + } else { + "Invoke-ScriptAnalyzer -Path '$relativePath' -Recurse (using default settings)" + } + + LogGroup $logMessage { + $testResults = Invoke-ScriptAnalyzer @invokeParams + } + LogGroup "TestResults [$($testResults.Count)]" { $testResults | Select-Object -Property * | Format-List | Out-String -Stream | ForEach-Object { Write-Verbose $_ -Verbose diff --git a/tests/Get-AggregatedStatus.ps1 b/tests/Get-AggregatedStatus.ps1 index d96cc5a..0f12daf 100644 --- a/tests/Get-AggregatedStatus.ps1 +++ b/tests/Get-AggregatedStatus.ps1 @@ -20,62 +20,76 @@ } # Build an array of objects for each job -$ActionTestSrcSourceCodeExpectedOutcome = 'success' -$ActionTestSrcSourceCodeOutcomeResult = $env:ActionTestSrcSourceCodeOutcome -eq $ActionTestSrcSourceCodeExpectedOutcome -$ActionTestSrcSourceCodeExpectedConclusion = 'success' -$ActionTestSrcSourceCodeConclusionResult = $env:ActionTestSrcSourceCodeConclusion -eq $ActionTestSrcSourceCodeExpectedConclusion +$SourceCodeExpectedOutcome = 'success' +$SourceCodeOutcomeResult = $env:SourceCodeOutcome -eq $SourceCodeExpectedOutcome +$SourceCodeExpectedConclusion = 'success' +$SourceCodeConclusionResult = $env:SourceCodeConclusion -eq $SourceCodeExpectedConclusion -$ActionTestSrcCustomExpectedOutcome = 'success' -$ActionTestSrcCustomOutcomeResult = $env:ActionTestSrcCustomOutcome -eq $ActionTestSrcCustomExpectedOutcome -$ActionTestSrcCustomExpectedConclusion = 'success' -$ActionTestSrcCustomConclusionResult = $env:ActionTestSrcCustomConclusion -eq $ActionTestSrcCustomExpectedConclusion +$CustomExpectedOutcome = 'success' +$CustomOutcomeResult = $env:CustomOutcome -eq $CustomExpectedOutcome +$CustomExpectedConclusion = 'success' +$CustomConclusionResult = $env:CustomConclusion -eq $CustomExpectedConclusion -$ActionTestSrcWithManifestExpectedOutcome = 'failure' -$ActionTestSrcWithManifestOutcomeResult = $env:ActionTestSrcWithManifestOutcome -eq $ActionTestSrcWithManifestExpectedOutcome -$ActionTestSrcWithManifestExpectedConclusion = 'success' -$ActionTestSrcWithManifestConclusionResult = $env:ActionTestSrcWithManifestConclusion -eq $ActionTestSrcWithManifestExpectedConclusion +$WithManifestExpectedOutcome = 'failure' +$WithManifestOutcomeResult = $env:WithManifestOutcome -eq $WithManifestExpectedOutcome +$WithManifestExpectedConclusion = 'success' +$WithManifestConclusionResult = $env:WithManifestConclusion -eq $WithManifestExpectedConclusion -$ActionTestOutputsExpectedOutcome = 'success' -$ActionTestOutputsOutcomeResult = $env:ActionTestOutputsOutcome -eq $ActionTestOutputsExpectedOutcome -$ActionTestOutputsExpectedConclusion = 'success' -$ActionTestOutputsConclusionResult = $env:ActionTestOutputsConclusion -eq $ActionTestOutputsExpectedConclusion +$WithManifestDefaultExpectedOutcome = 'failure' +$WithManifestDefaultOutcomeResult = $env:WithManifestDefaultOutcome -eq $WithManifestDefaultExpectedOutcome +$WithManifestDefaultExpectedConclusion = 'success' +$WithManifestDefaultConclusionResult = $env:WithManifestDefaultConclusion -eq $WithManifestDefaultExpectedConclusion + +$OutputsExpectedOutcome = 'success' +$OutputsOutcomeResult = $env:OutputsOutcome -eq $OutputsExpectedOutcome +$OutputsExpectedConclusion = 'success' +$OutputsConclusionResult = $env:OutputsConclusion -eq $OutputsExpectedConclusion $jobs = @( [PSCustomObject]@{ Name = 'Action-Test - [Src-SourceCode]' - Outcome = $env:ActionTestSrcSourceCodeOutcome - ExpectedOutcome = $ActionTestSrcSourceCodeExpectedOutcome - PassedOutcome = $ActionTestSrcSourceCodeOutcomeResult - Conclusion = $env:ActionTestSrcSourceCodeConclusion - ExpectedConclusion = $ActionTestSrcSourceCodeExpectedConclusion - PassedConclusion = $ActionTestSrcSourceCodeConclusionResult + Outcome = $env:SourceCodeOutcome + ExpectedOutcome = $SourceCodeExpectedOutcome + PassedOutcome = $SourceCodeOutcomeResult + Conclusion = $env:SourceCodeConclusion + ExpectedConclusion = $SourceCodeExpectedConclusion + PassedConclusion = $SourceCodeConclusionResult }, [PSCustomObject]@{ Name = 'Action-Test - [Src-Custom]' - Outcome = $env:ActionTestSrcCustomOutcome - ExpectedOutcome = $ActionTestSrcCustomExpectedOutcome - PassedOutcome = $ActionTestSrcCustomOutcomeResult - Conclusion = $env:ActionTestSrcCustomConclusion - ExpectedConclusion = $ActionTestSrcCustomExpectedConclusion - PassedConclusion = $ActionTestSrcCustomConclusionResult + Outcome = $env:CustomOutcome + ExpectedOutcome = $CustomExpectedOutcome + PassedOutcome = $CustomOutcomeResult + Conclusion = $env:CustomConclusion + ExpectedConclusion = $CustomExpectedConclusion + PassedConclusion = $CustomConclusionResult }, [PSCustomObject]@{ Name = 'Action-Test - [Src-WithManifest]' - Outcome = $env:ActionTestSrcWithManifestOutcome - ExpectedOutcome = $ActionTestSrcWithManifestExpectedOutcome - PassedOutcome = $ActionTestSrcWithManifestOutcomeResult - Conclusion = $env:ActionTestSrcWithManifestConclusion - ExpectedConclusion = $ActionTestSrcWithManifestExpectedConclusion - PassedConclusion = $ActionTestSrcWithManifestConclusionResult + Outcome = $env:WithManifestOutcome + ExpectedOutcome = $WithManifestExpectedOutcome + PassedOutcome = $WithManifestOutcomeResult + Conclusion = $env:WithManifestConclusion + ExpectedConclusion = $WithManifestExpectedConclusion + PassedConclusion = $WithManifestConclusionResult + }, + [PSCustomObject]@{ + Name = 'Action-Test - [Src-WithManifest-Default]' + Outcome = $env:WithManifestDefaultOutcome + ExpectedOutcome = $WithManifestDefaultExpectedOutcome + PassedOutcome = $WithManifestDefaultOutcomeResult + Conclusion = $env:WithManifestDefaultConclusion + ExpectedConclusion = $WithManifestDefaultExpectedConclusion + PassedConclusion = $WithManifestDefaultConclusionResult }, [PSCustomObject]@{ Name = 'Action-Test - [outputs]' - Outcome = $env:ActionTestOutputsOutcome - ExpectedOutcome = $ActionTestOutputsExpectedOutcome - PassedOutcome = $ActionTestOutputsOutcomeResult - Conclusion = $env:ActionTestOutputsConclusion - ExpectedConclusion = $ActionTestOutputsExpectedConclusion - PassedConclusion = $ActionTestOutputsConclusionResult + Outcome = $env:OutputsOutcome + ExpectedOutcome = $OutputsExpectedOutcome + PassedOutcome = $OutputsOutcomeResult + Conclusion = $env:OutputsConclusion + ExpectedConclusion = $OutputsExpectedConclusion + PassedConclusion = $OutputsConclusionResult } )