From 881adb6343a7088ca05cad89d7ea8c66dc36f55a Mon Sep 17 00:00:00 2001 From: Clint Branham Date: Tue, 17 Mar 2026 15:48:41 -0500 Subject: [PATCH] ci: add GitHub Actions workflows Build workflow validates both net48 and net10.0 targets with code coverage. Unit test workflow runs Pester across 6 OS/PS combinations. Integration test workflow is manual trigger only with secrets check. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 51 +++++++++ .github/workflows/integration-tests.yml | 65 ++++++++++++ .github/workflows/unit-tests.yml | 132 ++++++++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/integration-tests.yml create mode 100644 .github/workflows/unit-tests.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..0db4b5d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,51 @@ +name: Build + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build-net48: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + - name: Restore dependencies + run: dotnet restore + - name: Build net48 + run: dotnet build --configuration Release --framework net48 --no-restore + - name: Test net48 + run: dotnet test tests/PSProxmoxVE.Core.Tests/PSProxmoxVE.Core.Tests.csproj --configuration Release --framework net48 --no-build --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage + - name: Upload coverage + uses: actions/upload-artifact@v4 + with: + name: coverage-net48 + path: ./coverage + + build-net8: + strategy: + matrix: + os: [windows-latest, ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + - name: Restore dependencies + run: dotnet restore + - name: Build net8.0 + run: dotnet build --configuration Release --framework net8.0 --no-restore + - name: Test net8.0 + run: dotnet test tests/PSProxmoxVE.Core.Tests/PSProxmoxVE.Core.Tests.csproj --configuration Release --framework net8.0 --no-build --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage + - name: Upload coverage + uses: actions/upload-artifact@v4 + with: + name: coverage-net8-${{ matrix.os }} + path: ./coverage diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000..67538bb --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,65 @@ +name: Integration Tests + +on: + workflow_dispatch: + inputs: + pve_host: + description: 'Proxmox VE host (overrides secret)' + required: false + type: string + +# Integration tests require a live Proxmox VE node. +# Configure these repository secrets when a test node is available: +# PVETEST_HOST - Hostname or IP of the PVE node +# PVETEST_PORT - API port (default 8006) +# PVETEST_APITOKEN - API token in USER@REALM!TOKENID=UUID format +# PVETEST_NODE - Node name to run tests against +# PVETEST_STORAGE - Storage name for upload tests +# PVETEST_ISO_PATH - Local path to a test ISO file +# +# WARNING: Integration tests create and destroy real VMs, upload files, +# and modify network configuration. Never run against production. + +jobs: + integration: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + - name: Check required secrets + id: check-secrets + run: | + if [ -z "${{ secrets.PVETEST_HOST }}" ] || [ -z "${{ secrets.PVETEST_APITOKEN }}" ]; then + echo "skip=true" >> $GITHUB_OUTPUT + echo "::warning::Integration tests skipped - required secrets not configured" + else + echo "skip=false" >> $GITHUB_OUTPUT + fi + - name: Build module + if: steps.check-secrets.outputs.skip != 'true' + run: dotnet publish src/PSProxmoxVE/PSProxmoxVE.csproj --configuration Release --framework net8.0 + - name: Install Pester + if: steps.check-secrets.outputs.skip != 'true' + shell: pwsh + run: Install-Module -Name Pester -MinimumVersion 5.0 -Force -Scope CurrentUser + - name: Run integration tests + if: steps.check-secrets.outputs.skip != 'true' + shell: pwsh + env: + PVETEST_HOST: ${{ inputs.pve_host || secrets.PVETEST_HOST }} + PVETEST_PORT: ${{ secrets.PVETEST_PORT || '8006' }} + PVETEST_APITOKEN: ${{ secrets.PVETEST_APITOKEN }} + PVETEST_NODE: ${{ secrets.PVETEST_NODE }} + PVETEST_STORAGE: ${{ secrets.PVETEST_STORAGE }} + PVETEST_ISO_PATH: ${{ secrets.PVETEST_ISO_PATH }} + run: | + Invoke-Pester tests/PSProxmoxVE.Tests/Integration -Tag Integration -CI -OutputFormat NUnitXml -OutputFile TestResults/integration-results.xml + - name: Upload test results + if: always() && steps.check-secrets.outputs.skip != 'true' + uses: actions/upload-artifact@v4 + with: + name: integration-test-results + path: TestResults/ diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..7ba379c --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,132 @@ +name: Unit Tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + pester-tests: + strategy: + fail-fast: false + matrix: + include: + - os: windows-latest + ps_version: '5.1' + framework: net48 + shell: powershell + - os: windows-latest + ps_version: '7.2' + framework: net8.0 + shell: pwsh + - os: windows-latest + ps_version: '7.5' + framework: net8.0 + shell: pwsh + - os: ubuntu-latest + ps_version: '7.2' + framework: net8.0 + shell: pwsh + - os: ubuntu-latest + ps_version: '7.5' + framework: net8.0 + shell: pwsh + - os: macos-latest + ps_version: '7.5' + framework: net8.0 + shell: pwsh + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + + - name: Install PowerShell 7.2 (Windows) + if: matrix.ps_version == '7.2' && matrix.os == 'windows-latest' + shell: pwsh + run: | + winget install --id Microsoft.PowerShell --version 7.2 --accept-source-agreements --accept-package-agreements --silent + continue-on-error: true + + - name: Install PowerShell 7.2 (Linux) + if: matrix.ps_version == '7.2' && matrix.os == 'ubuntu-latest' + run: | + wget -q https://github.com/PowerShell/PowerShell/releases/download/v7.2.24/powershell_7.2.24-1.deb_amd64.deb + sudo dpkg -i powershell_7.2.24-1.deb_amd64.deb + sudo apt-get install -f -y + + - name: Build module + run: dotnet publish src/PSProxmoxVE/PSProxmoxVE.csproj --configuration Release --framework ${{ matrix.framework }} --output ./publish/${{ matrix.framework }} + + - name: Install Pester 5 (PS 5.1) + if: matrix.ps_version == '5.1' + shell: powershell + run: | + Install-Module -Name Pester -MinimumVersion 5.0 -Force -Scope CurrentUser -SkipPublisherCheck + + - name: Install Pester 5 (PS 7.x) + if: matrix.ps_version != '5.1' + shell: pwsh + run: | + Install-Module -Name Pester -MinimumVersion 5.0 -Force -Scope CurrentUser + + - name: Copy module to module path (PS 5.1) + if: matrix.ps_version == '5.1' + shell: powershell + run: | + $modulePath = "$env:USERPROFILE\Documents\WindowsPowerShell\Modules\PSProxmoxVE" + New-Item -ItemType Directory -Path $modulePath -Force | Out-Null + Copy-Item -Path .\publish\${{ matrix.framework }}\* -Destination $modulePath -Recurse -Force + + - name: Copy module to module path (PS 7.x, Windows) + if: matrix.ps_version != '5.1' && matrix.os == 'windows-latest' + shell: pwsh + run: | + $modulePath = "$env:USERPROFILE\Documents\PowerShell\Modules\PSProxmoxVE" + New-Item -ItemType Directory -Path $modulePath -Force | Out-Null + Copy-Item -Path .\publish\${{ matrix.framework }}\* -Destination $modulePath -Recurse -Force + + - name: Copy module to module path (PS 7.x, non-Windows) + if: matrix.ps_version != '5.1' && matrix.os != 'windows-latest' + shell: pwsh + run: | + $modulePath = "$HOME/.local/share/powershell/Modules/PSProxmoxVE" + New-Item -ItemType Directory -Path $modulePath -Force | Out-Null + Copy-Item -Path ./publish/${{ matrix.framework }}/* -Destination $modulePath -Recurse -Force + + - name: Create TestResults directory (PS 5.1) + if: matrix.ps_version == '5.1' + shell: powershell + run: New-Item -ItemType Directory -Path TestResults -Force | Out-Null + + - name: Create TestResults directory (PS 7.x) + if: matrix.ps_version != '5.1' + shell: pwsh + run: New-Item -ItemType Directory -Path TestResults -Force | Out-Null + + - name: Run Pester tests (PS 5.1) + if: matrix.ps_version == '5.1' + shell: powershell + run: | + Import-Module Pester -MinimumVersion 5.0 + Invoke-Pester tests/PSProxmoxVE.Tests -ExcludeTag Integration -CI -OutputFormat NUnitXml -OutputFile TestResults/pester-results.xml + + - name: Run Pester tests (PS 7.x) + if: matrix.ps_version != '5.1' + shell: pwsh + run: | + Import-Module Pester -MinimumVersion 5.0 + Invoke-Pester tests/PSProxmoxVE.Tests -ExcludeTag Integration -CI -OutputFormat NUnitXml -OutputFile TestResults/pester-results.xml + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: pester-results-${{ matrix.os }}-ps${{ matrix.ps_version }} + path: TestResults/