mirror of https://github.com/raandree/NTFSSecurity
Browse Source
.github/workflows/ci.yml replaces appveyor.yml and runs on pull requests and pushes to master: - build (windows-2025): the same restore, Release build, and documentation checks as before, then the Pester tests in Windows PowerShell 5.1 and in PowerShell 7. .github/scripts/Invoke-Tests.ps1 writes the counts and the failed tests to the job summary and the NUnit file to the test-results artifact, and also fails on test files that fail. - wiki (ubuntu-latest): generates the wiki from Docs; on pull requests it lists the pages that would change, from master it publishes them with the built-in token. Only this job has contents: write. Actions are pinned by commit SHA. Every native command checks its exit code, because GitHub checks only the last one. The contributor guide describes the workflow and the wiki. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com>pull/96/head
4 changed files with 296 additions and 98 deletions
@ -0,0 +1,79 @@ |
|||||
|
<# |
||||
|
.SYNOPSIS |
||||
|
Runs the Pester tests in the Tests folder and reports the result to GitHub Actions. |
||||
|
|
||||
|
.DESCRIPTION |
||||
|
Imports Pester 5.7.1, runs the tests against the module build in NTFSSecurity\bin\Release, writes the result |
||||
|
file in the NUnit format, and adds the counts and the failed tests to the job summary of GitHub Actions. Fails if |
||||
|
a test or a test file fails. |
||||
|
|
||||
|
.PARAMETER ResultPath |
||||
|
Specifies the path of the result file. |
||||
|
|
||||
|
.PARAMETER Title |
||||
|
Specifies the heading of the test results in the job summary, such as the PowerShell edition. |
||||
|
|
||||
|
.EXAMPLE |
||||
|
.\.github\scripts\Invoke-Tests.ps1 -ResultPath TestResults\WindowsPowerShell.xml -Title 'Windows PowerShell 5.1' |
||||
|
|
||||
|
Runs the tests and writes the result file. Outside GitHub Actions, the script writes no job summary. |
||||
|
#> |
||||
|
[CmdletBinding()] |
||||
|
param ( |
||||
|
[Parameter(Mandatory)] |
||||
|
[ValidateNotNullOrEmpty()] |
||||
|
[string] |
||||
|
$ResultPath, |
||||
|
|
||||
|
[Parameter(Mandatory)] |
||||
|
[ValidateNotNullOrEmpty()] |
||||
|
[string] |
||||
|
$Title |
||||
|
) |
||||
|
|
||||
|
$ErrorActionPreference = 'Stop' |
||||
|
Import-Module -Name Pester -RequiredVersion 5.7.1 |
||||
|
|
||||
|
$resultFolder = Split-Path -Path $ResultPath -Parent |
||||
|
if ($resultFolder -and -not (Test-Path -LiteralPath $resultFolder)) { |
||||
|
New-Item -ItemType Directory -Path $resultFolder | Out-Null |
||||
|
} |
||||
|
|
||||
|
$configuration = New-PesterConfiguration |
||||
|
$configuration.Run.Path = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Tests' |
||||
|
$configuration.Run.PassThru = $true |
||||
|
$configuration.Output.Verbosity = 'Detailed' |
||||
|
$configuration.TestResult.Enabled = $true |
||||
|
$configuration.TestResult.OutputFormat = 'NUnitXml' |
||||
|
$configuration.TestResult.OutputPath = $ResultPath |
||||
|
$result = Invoke-Pester -Configuration $configuration |
||||
|
|
||||
|
if ($env:GITHUB_STEP_SUMMARY) { |
||||
|
$summary = New-Object -TypeName 'System.Collections.Generic.List[string]' |
||||
|
$summary.Add("### Tests in $Title") |
||||
|
$summary.Add('') |
||||
|
$summary.Add('| Result | Passed | Failed | Skipped | Total |') |
||||
|
$summary.Add('| --- | ---: | ---: | ---: | ---: |') |
||||
|
$summary.Add(('| {0} | {1} | {2} | {3} | {4} |' -f $result.Result, $result.PassedCount, $result.FailedCount, |
||||
|
$result.SkippedCount, $result.TotalCount)) |
||||
|
if ($result.Failed.Count -gt 0 -or $result.FailedContainersCount -gt 0) { |
||||
|
$summary.Add('') |
||||
|
$summary.Add('Failed:') |
||||
|
$summary.Add('') |
||||
|
foreach ($test in $result.Failed) { |
||||
|
$message = "$(@($test.ErrorRecord)[0])" -replace '\s+', ' ' |
||||
|
$summary.Add(('- {0}: {1}' -f $test.ExpandedPath, $message)) |
||||
|
} |
||||
|
foreach ($container in $result.Containers | Where-Object -Property Result -EQ -Value 'Failed') { |
||||
|
$summary.Add(('- {0}: {1}' -f $container.Item, ("$(@($container.ErrorRecord)[0])" -replace '\s+', ' '))) |
||||
|
} |
||||
|
} |
||||
|
$summary.Add('') |
||||
|
|
||||
|
$encoding = New-Object -TypeName 'System.Text.UTF8Encoding' -ArgumentList $false |
||||
|
[IO.File]::AppendAllText($env:GITHUB_STEP_SUMMARY, ($summary -join "`n") + "`n", $encoding) |
||||
|
} |
||||
|
|
||||
|
if ($result.Result -ne 'Passed') { |
||||
|
throw "The tests in $Title failed: $($result.FailedCount) failed tests, $($result.FailedContainersCount) failed test files." |
||||
|
} |
||||
@ -0,0 +1,181 @@ |
|||||
|
# Builds the NTFSSecurity module from source, checks that the cmdlet |
||||
|
# documentation in Docs/Cmdlets and the help file generated from it match the |
||||
|
# cmdlets of that build, runs the Pester tests in Windows PowerShell 5.1 and |
||||
|
# PowerShell 7, and publishes Docs to the GitHub wiki from master. |
||||
|
name: CI |
||||
|
|
||||
|
on: |
||||
|
pull_request: |
||||
|
push: |
||||
|
branches: |
||||
|
- master |
||||
|
workflow_dispatch: |
||||
|
|
||||
|
permissions: |
||||
|
contents: read |
||||
|
|
||||
|
concurrency: |
||||
|
group: ci-${{ github.ref }} |
||||
|
cancel-in-progress: ${{ github.event_name == 'pull_request' }} |
||||
|
|
||||
|
jobs: |
||||
|
build: |
||||
|
name: Build and test |
||||
|
runs-on: windows-2025 |
||||
|
timeout-minutes: 30 |
||||
|
steps: |
||||
|
- name: Keep Windows line endings in the working tree |
||||
|
run: git config --global core.autocrlf true |
||||
|
|
||||
|
- name: Check out the repository |
||||
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
||||
|
with: |
||||
|
persist-credentials: false |
||||
|
|
||||
|
- name: Install platyPS, MarkdownLinkCheck, and Pester |
||||
|
shell: powershell |
||||
|
run: | |
||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 |
||||
|
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force | Out-Null |
||||
|
# Installed for all users, so that PowerShell 7 finds the modules, too |
||||
|
Install-Module -Name platyPS -RequiredVersion 0.14.2 -Scope AllUsers -Force |
||||
|
Install-Module -Name MarkdownLinkCheck -RequiredVersion 0.2.0 -Scope AllUsers -Force |
||||
|
# The image includes Pester 3.4.0, which is signed by a different publisher. |
||||
|
Install-Module -Name Pester -RequiredVersion 5.7.1 -Scope AllUsers -Force -SkipPublisherCheck |
||||
|
|
||||
|
- name: Restore the NuGet packages |
||||
|
shell: powershell |
||||
|
run: | |
||||
|
nuget restore NTFSSecurity\packages.config -PackagesDirectory packages -NonInteractive |
||||
|
if ($LASTEXITCODE -ne 0) { |
||||
|
throw "NuGet failed with exit code $LASTEXITCODE." |
||||
|
} |
||||
|
nuget restore Security2\packages.config -PackagesDirectory packages -NonInteractive |
||||
|
if ($LASTEXITCODE -ne 0) { |
||||
|
throw "NuGet failed with exit code $LASTEXITCODE." |
||||
|
} |
||||
|
# Provides the .NET Framework 4.5.2 reference assemblies, so the build does |
||||
|
# not depend on a targeting pack installed on the runner. |
||||
|
nuget install Microsoft.NETFramework.ReferenceAssemblies.net452 -Version 1.0.3 -OutputDirectory packages -NonInteractive |
||||
|
if ($LASTEXITCODE -ne 0) { |
||||
|
throw "NuGet failed with exit code $LASTEXITCODE." |
||||
|
} |
||||
|
|
||||
|
- name: Build the module |
||||
|
id: build |
||||
|
shell: powershell |
||||
|
run: | |
||||
|
# MSBuild isn't on the path of the runner; vswhere finds the one of Visual Studio. |
||||
|
$vswhere = Join-Path -Path ${env:ProgramFiles(x86)} -ChildPath 'Microsoft Visual Studio\Installer\vswhere.exe' |
||||
|
$msbuild = & $vswhere -latest -requires Microsoft.Component.MSBuild -find 'MSBuild\**\Bin\MSBuild.exe' | Select-Object -First 1 |
||||
|
if (-not $msbuild) { |
||||
|
throw 'MSBuild was not found.' |
||||
|
} |
||||
|
$referenceAssemblies = "$env:GITHUB_WORKSPACE\packages\Microsoft.NETFramework.ReferenceAssemblies.net452.1.0.3\build" |
||||
|
& $msbuild NTFSSecurity\NTFSSecurity.csproj /nologo /verbosity:minimal /p:Configuration=Release "/p:TargetFrameworkRootPath=$referenceAssemblies" "/p:FrameworkPathOverride=$referenceAssemblies\.NETFramework\v4.5.2" |
||||
|
if ($LASTEXITCODE -ne 0) { |
||||
|
throw "MSBuild failed with exit code $LASTEXITCODE." |
||||
|
} |
||||
|
|
||||
|
- name: Check the documentation against the build |
||||
|
shell: powershell |
||||
|
run: | |
||||
|
Import-Module -Name platyPS -RequiredVersion 0.14.2 |
||||
|
Import-Module -Name MarkdownLinkCheck -RequiredVersion 0.2.0 |
||||
|
Import-Module -Name .\NTFSSecurity\bin\Release\NTFSSecurity.psd1 -Force |
||||
|
|
||||
|
# 01. Test that the documentation matches the cmdlets built from source |
||||
|
Update-MarkdownHelp -Path ./Docs/Cmdlets | Out-Null |
||||
|
$diff = git diff -- Docs/Cmdlets |
||||
|
if ($diff) { |
||||
|
throw "Help is not up-to-date, run Update-MarkdownHelp: $diff" |
||||
|
} |
||||
|
|
||||
|
# 02. Verify hyperlinks |
||||
|
$brokenLinks = Get-MarkdownLink -Path .\Docs\ -BrokenOnly |
||||
|
if ($brokenLinks) { |
||||
|
throw "Found broken hyperlinks $brokenLinks" |
||||
|
} |
||||
|
|
||||
|
# 03. Test that the help file of the module matches the documentation |
||||
|
New-ExternalHelp -Path ./Docs/Cmdlets -OutputPath ./NTFSSecurity/en-US -Force | Out-Null |
||||
|
$helpChanges = git status --porcelain -- NTFSSecurity/en-US |
||||
|
if ($helpChanges) { |
||||
|
throw "The help file is not up-to-date, run New-ExternalHelp -Path .\Docs\Cmdlets -OutputPath .\NTFSSecurity\en-US -Force: $helpChanges" |
||||
|
} |
||||
|
|
||||
|
# 04. Run the Pester tests against the build, also when the documentation check failed |
||||
|
- name: Run the tests in Windows PowerShell 5.1 |
||||
|
if: ${{ !cancelled() && steps.build.outcome == 'success' }} |
||||
|
shell: powershell |
||||
|
run: .\.github\scripts\Invoke-Tests.ps1 -ResultPath TestResults\WindowsPowerShell.xml -Title 'Windows PowerShell 5.1' |
||||
|
|
||||
|
- name: Run the tests in PowerShell 7 |
||||
|
if: ${{ !cancelled() && steps.build.outcome == 'success' }} |
||||
|
shell: pwsh |
||||
|
run: ./.github/scripts/Invoke-Tests.ps1 -ResultPath TestResults/PowerShell7.xml -Title 'PowerShell 7' |
||||
|
|
||||
|
- name: Upload the test results |
||||
|
if: ${{ !cancelled() }} |
||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 |
||||
|
with: |
||||
|
name: test-results |
||||
|
path: TestResults/ |
||||
|
if-no-files-found: ignore |
||||
|
|
||||
|
wiki: |
||||
|
name: Wiki |
||||
|
needs: build |
||||
|
runs-on: ubuntu-latest |
||||
|
timeout-minutes: 10 |
||||
|
# Only this job can write: it publishes the wiki from master. On pull |
||||
|
# requests, it shows the pages that would change. |
||||
|
permissions: |
||||
|
contents: write |
||||
|
steps: |
||||
|
- name: Check out the repository |
||||
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
||||
|
with: |
||||
|
persist-credentials: false |
||||
|
|
||||
|
- name: Generate the wiki pages |
||||
|
shell: pwsh |
||||
|
env: |
||||
|
GH_TOKEN: ${{ github.token }} |
||||
|
run: | |
||||
|
gh auth setup-git |
||||
|
$wiki = Join-Path -Path $env:RUNNER_TEMP -ChildPath 'wiki' |
||||
|
git clone --quiet --depth 1 "$env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY.wiki.git" $wiki |
||||
|
if ($LASTEXITCODE -ne 0) { |
||||
|
throw "Cloning the wiki failed with exit code $LASTEXITCODE." |
||||
|
} |
||||
|
./.github/scripts/Export-WikiContent.ps1 -Path ./Docs -DestinationPath $wiki -RepositoryUrl "$env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY" |
||||
|
git -C $wiki add --all |
||||
|
$changes = @(git -C $wiki diff --cached --name-status) |
||||
|
$summary = if ($changes) { |
||||
|
@('### Wiki', '', 'Changed pages (A added, M modified, D deleted):', '', '```text') + $changes + @('```') |
||||
|
} else { |
||||
|
@('### Wiki', '', 'The wiki is up to date.') |
||||
|
} |
||||
|
Add-Content -LiteralPath $env:GITHUB_STEP_SUMMARY -Value $summary |
||||
|
Add-Content -LiteralPath $env:GITHUB_ENV -Value "WIKI_PATH=$wiki" |
||||
|
|
||||
|
- name: Publish the wiki |
||||
|
if: ${{ github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} |
||||
|
shell: pwsh |
||||
|
env: |
||||
|
GH_TOKEN: ${{ github.token }} |
||||
|
run: | |
||||
|
git -C $env:WIKI_PATH diff --cached --quiet |
||||
|
if ($LASTEXITCODE -eq 0) { |
||||
|
'The wiki is up to date.' |
||||
|
exit 0 |
||||
|
} |
||||
|
git -C $env:WIKI_PATH -c user.name='github-actions[bot]' -c user.email='41898282+github-actions[bot]@users.noreply.github.com' commit --quiet --message "Update from $env:GITHUB_SHA" |
||||
|
if ($LASTEXITCODE -ne 0) { |
||||
|
throw "Committing the wiki failed with exit code $LASTEXITCODE." |
||||
|
} |
||||
|
git -C $env:WIKI_PATH push --quiet |
||||
|
if ($LASTEXITCODE -ne 0) { |
||||
|
throw "Publishing the wiki failed with exit code $LASTEXITCODE." |
||||
|
} |
||||
@ -1,86 +0,0 @@ |
|||||
# Builds the NTFSSecurity module from source, checks that the cmdlet |
|
||||
# documentation in Docs/Cmdlets and the help file generated from it match the |
|
||||
# cmdlets of that build, and runs the Pester tests against the build. |
|
||||
image: Visual Studio 2022 |
|
||||
|
|
||||
init: |
|
||||
- ps: git config --global core.autocrlf true |
|
||||
|
|
||||
install: |
|
||||
- ps: | |
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 |
|
||||
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force | Out-Null |
|
||||
Install-Module -Name platyPS -RequiredVersion 0.14.2 -Force |
|
||||
Install-Module -Name MarkdownLinkCheck -RequiredVersion 0.2.0 -Force |
|
||||
# The image includes Pester 3.4.0, which is signed by a different publisher. |
|
||||
Install-Module -Name Pester -RequiredVersion 5.7.1 -Force -SkipPublisherCheck |
|
||||
|
|
||||
before_build: |
|
||||
- nuget restore NTFSSecurity\packages.config -PackagesDirectory packages -NonInteractive |
|
||||
- nuget restore Security2\packages.config -PackagesDirectory packages -NonInteractive |
|
||||
# Provides the .NET Framework 4.5.2 reference assemblies, so the build does |
|
||||
# not depend on a targeting pack installed on the build image. |
|
||||
- nuget install Microsoft.NETFramework.ReferenceAssemblies.net452 -Version 1.0.3 -OutputDirectory packages -NonInteractive |
|
||||
|
|
||||
build_script: |
|
||||
- ps: | |
|
||||
$referenceAssemblies = "$env:APPVEYOR_BUILD_FOLDER\packages\Microsoft.NETFramework.ReferenceAssemblies.net452.1.0.3\build" |
|
||||
msbuild NTFSSecurity\NTFSSecurity.csproj /nologo /verbosity:minimal /p:Configuration=Release "/p:TargetFrameworkRootPath=$referenceAssemblies" "/p:FrameworkPathOverride=$referenceAssemblies\.NETFramework\v4.5.2" |
|
||||
if ($LASTEXITCODE -ne 0) { |
|
||||
throw "MSBuild failed with exit code $LASTEXITCODE." |
|
||||
} |
|
||||
|
|
||||
test_script: |
|
||||
- ps: | |
|
||||
$ErrorActionPreference = 'Stop' |
|
||||
Import-Module -Name platyPS |
|
||||
Import-Module -Name MarkdownLinkCheck |
|
||||
Import-Module -Name .\NTFSSecurity\bin\Release\NTFSSecurity.psd1 -Force |
|
||||
|
|
||||
# 01. Test that the documentation matches the cmdlets built from source |
|
||||
Update-MarkdownHelp -Path ./Docs/Cmdlets | Out-Null |
|
||||
$diff = git diff -- Docs/Cmdlets |
|
||||
if ($diff) { |
|
||||
throw "Help is not up-to-date, run Update-MarkdownHelp: $diff" |
|
||||
} |
|
||||
|
|
||||
# 02. Verify hyperlinks |
|
||||
$brokenLinks = Get-MarkdownLink -Path .\Docs\ -BrokenOnly |
|
||||
if ($brokenLinks) { |
|
||||
throw "Found broken hyperlinks $brokenLinks" |
|
||||
} |
|
||||
|
|
||||
# 03. Test that the help file of the module matches the documentation |
|
||||
New-ExternalHelp -Path ./Docs/Cmdlets -OutputPath ./NTFSSecurity/en-US -Force | Out-Null |
|
||||
$helpChanges = git status --porcelain -- NTFSSecurity/en-US |
|
||||
if ($helpChanges) { |
|
||||
throw "The help file is not up-to-date, run New-ExternalHelp -Path .\Docs\Cmdlets -OutputPath .\NTFSSecurity\en-US -Force: $helpChanges" |
|
||||
} |
|
||||
|
|
||||
# 04. Run the Pester tests against the module build |
|
||||
Import-Module -Name Pester -RequiredVersion 5.7.1 |
|
||||
$configuration = New-PesterConfiguration |
|
||||
$configuration.Run.Path = '.\Tests' |
|
||||
$configuration.Run.PassThru = $true |
|
||||
$configuration.Output.Verbosity = 'Detailed' |
|
||||
$result = Invoke-Pester -Configuration $configuration |
|
||||
|
|
||||
# Report every test once on the Tests tab. An uploaded NUnit file lists a |
|
||||
# Pester 5 test once for each block that contains it. |
|
||||
if ($env:APPVEYOR_API_URL -and $result.Tests) { |
|
||||
$tests = @(foreach ($test in $result.Tests) { |
|
||||
@{ |
|
||||
testName = $test.ExpandedPath |
|
||||
testFramework = 'Pester' |
|
||||
fileName = Split-Path -Path $test.ScriptBlock.File -Leaf |
|
||||
outcome = if ($test.Result -eq 'NotRun') { 'NotRunnable' } else { "$($test.Result)" } |
|
||||
durationMilliseconds = [long] $test.Duration.TotalMilliseconds |
|
||||
ErrorMessage = @($test.ErrorRecord | ForEach-Object -Process { "$_" }) -join [Environment]::NewLine |
|
||||
} |
|
||||
}) |
|
||||
$body = [Text.Encoding]::UTF8.GetBytes((ConvertTo-Json -InputObject $tests -Compress)) |
|
||||
Invoke-RestMethod -Method Post -Uri ($env:APPVEYOR_API_URL.TrimEnd('/') + '/api/tests/batch') -Body $body -ContentType 'application/json; charset=utf-8' | Out-Null |
|
||||
} |
|
||||
if ($result.FailedCount -gt 0) { |
|
||||
throw "$($result.FailedCount) Pester tests failed." |
|
||||
} |
|
||||
Loading…
Reference in new issue