From 9c8e9eb7e3b72bf82a84fccdd56960e2f1fc16e3 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 13:46:33 -0800 Subject: [PATCH] [release/v7.5] Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26794) --- .github/actions/build/ci/action.yml | 14 --- .github/actions/test/verify_xunit/action.yml | 21 ---- .../instructions/build-configuration-guide.md | 95 +++++++++++++++++++ .../git-requirements-for-builds.md | 71 ++++++++++++++ .github/instructions/start-psbuild-basics.md | 92 ++++++++++++++++++ .../instructions/troubleshooting-builds.md | 92 ++++++++++++++++++ .../instructions/workflow-prerequisites.md | 91 ++++++++++++++++++ .github/workflows/linux-ci.yml | 22 ++--- .github/workflows/macos-ci.yml | 22 ++--- .github/workflows/windows-ci.yml | 22 ++--- .github/workflows/xunit-tests.yml | 53 +++++++++++ 11 files changed, 521 insertions(+), 74 deletions(-) delete mode 100644 .github/actions/test/verify_xunit/action.yml create mode 100644 .github/instructions/build-configuration-guide.md create mode 100644 .github/instructions/git-requirements-for-builds.md create mode 100644 .github/instructions/start-psbuild-basics.md create mode 100644 .github/instructions/troubleshooting-builds.md create mode 100644 .github/instructions/workflow-prerequisites.md create mode 100644 .github/workflows/xunit-tests.yml diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index 93adaf6b17..997be8b264 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -31,22 +31,8 @@ runs: Import-Module .\tools\ci.psm1 Invoke-CIBuild shell: pwsh - - name: xUnit Tests - if: success() - continue-on-error: true - run: |- - Write-Verbose -Verbose "Running xUnit tests..." - Import-Module .\tools\ci.psm1 - Restore-PSOptions - Invoke-CIxUnit -SkipFailing - shell: pwsh - name: Upload build artifact uses: actions/upload-artifact@v4 with: name: build path: ${{ runner.workspace }}/build - - name: Upload xunit artifact - uses: actions/upload-artifact@v4 - with: - name: testResults-xunit - path: ${{ runner.workspace }}/xunit diff --git a/.github/actions/test/verify_xunit/action.yml b/.github/actions/test/verify_xunit/action.yml deleted file mode 100644 index fccca27182..0000000000 --- a/.github/actions/test/verify_xunit/action.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: verify_xunit -description: 'Verify xUnit Results' - -runs: - using: composite - steps: - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - path: "${{ github.workspace }}" - - name: Capture artifacts directory - continue-on-error: true - run: dir "${{ github.workspace }}\testResults-xunit\*" -Recurse - shell: pwsh - - name: Test - if: success() - run: |- - Import-Module .\tools\ci.psm1 - $xUnitTestResultsFile = "${{ github.workspace }}\testResults-xunit\xUnitTestResults.xml" - Test-XUnitTestResults -TestResultsFile $xUnitTestResultsFile - shell: pwsh diff --git a/.github/instructions/build-configuration-guide.md b/.github/instructions/build-configuration-guide.md new file mode 100644 index 0000000000..d082bcbe77 --- /dev/null +++ b/.github/instructions/build-configuration-guide.md @@ -0,0 +1,95 @@ +# Build Configuration Guide + +## Choosing the Right Configuration + +### For Testing + +**Use: Default (Debug)** + +```yaml +- name: Build for Testing + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +**Why Debug:** +- Includes debugging symbols +- Better error messages +- Faster build times +- Suitable for xUnit and Pester tests + +**Do NOT use:** +- `-Configuration 'Release'` (unnecessary for tests) +- `-ReleaseTag` (not needed for tests) +- `-CI` (unless you specifically need Pester module) + +### For Release/Packaging + +**Use: Release with version tag** + +```yaml +- name: Build for Release + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag +``` + +**Why Release:** +- Optimized binaries +- No debug symbols (smaller size) +- Production-ready + +### For Code Coverage + +**Use: CodeCoverage configuration** + +```yaml +- name: Build with Coverage + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild -Configuration 'CodeCoverage' +``` + +## Platform Considerations + +### All Platforms + +Same commands work across Linux, Windows, and macOS: + +```yaml +strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] +runs-on: ${{ matrix.os }} +steps: + - name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +### Output Locations + +**Linux/macOS:** +``` +src/powershell-unix/bin/Debug///publish/ +``` + +**Windows:** +``` +src/powershell-win-core/bin/Debug///publish/ +``` + +## Best Practices + +1. Use default configuration for testing +2. Avoid redundant parameters +3. Match configuration to purpose +4. Use `-CI` only when needed +5. Always specify `-ReleaseTag` for release or packaging builds diff --git a/.github/instructions/git-requirements-for-builds.md b/.github/instructions/git-requirements-for-builds.md new file mode 100644 index 0000000000..3c8cd91e7c --- /dev/null +++ b/.github/instructions/git-requirements-for-builds.md @@ -0,0 +1,71 @@ +# Git Requirements for Building PowerShell + +## Fetch Depth + +**Required:** `fetch-depth: 1000` + +The PowerShell build process uses `git describe --abbrev=60 --long` to generate version information. This requires access to git history and tags. + +### Problem + +Without sufficient fetch depth, builds fail with: +``` +error MSB3073: The command "git describe --abbrev=60 --long" exited with code 128. +``` + +### Solution + +Always use `fetch-depth: 1000` in the checkout step: + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 +``` + +## Tag Synchronization + +**Required:** `Sync-PSTags -AddRemoteIfMissing` + +The build process needs git tags to properly version the build. + +### Problem + +Without tag synchronization: +- Version information is incorrect +- Build versioning fails + +### Solution + +Include tag synchronization in the bootstrap step: + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Sync-PSTags -AddRemoteIfMissing +``` + +## Complete Example + +```yaml +steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` diff --git a/.github/instructions/start-psbuild-basics.md b/.github/instructions/start-psbuild-basics.md new file mode 100644 index 0000000000..ae216a1584 --- /dev/null +++ b/.github/instructions/start-psbuild-basics.md @@ -0,0 +1,92 @@ +# Start-PSBuild Basics + +## Purpose + +`Start-PSBuild` builds PowerShell from source. It's defined in `build.psm1` and used in CI/CD workflows. + +## Default Usage + +For most scenarios, use with no parameters: + +```powershell +Import-Module ./tools/ci.psm1 +Start-PSBuild +``` + +**Default behavior:** +- Configuration: `Debug` +- PSModuleRestore: Enabled +- Runtime: Auto-detected for platform + +## Common Configurations + +### Debug Build (Default) + +```powershell +Start-PSBuild +``` + +Use for: +- Testing (xUnit, Pester) +- Development +- Debugging + +### Release Build + +```powershell +Start-PSBuild -Configuration 'Release' +``` + +Use for: +- Production packages +- Distribution +- Performance testing + +### Code Coverage Build + +```powershell +Start-PSBuild -Configuration 'CodeCoverage' +``` + +Use for: +- Code coverage analysis +- Test coverage reports + +## Common Parameters + +### -Configuration + +Values: `Debug`, `Release`, `CodeCoverage`, `StaticAnalysis` + +Default: `Debug` + +### -CI + +Restores Pester module for CI environments. + +```powershell +Start-PSBuild -CI +``` + +### -PSModuleRestore + +Now enabled by default. Use `-NoPSModuleRestore` to skip. + +### -ReleaseTag + +Specifies version tag for release builds: + +```powershell +$releaseTag = Get-ReleaseTag +Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag +``` + +## Workflow Example + +```yaml +- name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` diff --git a/.github/instructions/troubleshooting-builds.md b/.github/instructions/troubleshooting-builds.md new file mode 100644 index 0000000000..37f5df0091 --- /dev/null +++ b/.github/instructions/troubleshooting-builds.md @@ -0,0 +1,92 @@ +# Troubleshooting Build Issues + +## Git Describe Error + +**Error:** +``` +error MSB3073: The command "git describe --abbrev=60 --long" exited with code 128. +``` + +**Cause:** Insufficient git history (shallow clone) + +**Solution:** Add `fetch-depth: 1000` to checkout step + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 +``` + +## Version Information Incorrect + +**Symptom:** Build produces wrong version numbers + +**Cause:** Git tags not synchronized + +**Solution:** Run `Sync-PSTags -AddRemoteIfMissing`: + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` + +## PowerShell Binary Not Built + +**Error:** +``` +Exception: CoreCLR pwsh.exe was not built +``` + +**Causes:** +1. Build failed (check logs) +2. Wrong configuration used +3. Build output location incorrect + +**Solutions:** +1. Check build logs for errors +2. Verify correct configuration for use case +3. Use default parameters: `Start-PSBuild` + +## Module Restore Issues + +**Symptom:** Slow build or module restore failures + +**Causes:** +- Network issues +- Module cache problems +- Package source unavailable + +**Solutions:** +1. Retry the build +2. Check network connectivity +3. Use `-NoPSModuleRestore` if modules not needed +4. Clear package cache if persistent + +## .NET SDK Not Found + +**Symptom:** Build can't find .NET SDK + +**Solution:** Ensure .NET setup step runs first: + +```yaml +- name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json +``` + +## Bootstrap Failures + +**Symptom:** Invoke-CIInstall fails + +**Causes:** +- Missing dependencies +- Network issues +- Platform-specific requirements not met + +**Solution:** Check prerequisites for your platform in build system docs diff --git a/.github/instructions/workflow-prerequisites.md b/.github/instructions/workflow-prerequisites.md new file mode 100644 index 0000000000..fe88abb384 --- /dev/null +++ b/.github/instructions/workflow-prerequisites.md @@ -0,0 +1,91 @@ +# Workflow Prerequisites for Building PowerShell + +## Required Steps Before Start-PSBuild + +These steps must run before calling `Start-PSBuild`: + +### 1. Checkout + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 # Required for version generation +``` + +### 2. Setup .NET + +```yaml +- name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json +``` + +### 3. Bootstrap + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` + +## Complete Prerequisites Example + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing + + - name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +## Why Each Step Matters + +**Checkout with fetch-depth:** +- Build needs git history for versioning +- Without it: `git describe` fails + +**Setup .NET:** +- Provides SDK for building +- Uses version from global.json + +**Bootstrap:** +- Installs dependencies +- Syncs git tags +- Prepares build environment + +## Optional Steps + +### Environment Capture (Debugging) + +```yaml +- name: Capture Environment + run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | Write-Verbose -Verbose + shell: pwsh +``` diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index e5cb91dac6..a27c5157ee 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -145,20 +145,16 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v4.1.0 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: ubuntu-latest + test_results_artifact_name: testResults-xunit + analyze: permissions: @@ -222,7 +218,7 @@ jobs: ready_to_merge: name: Linux ready to merge needs: - - verify_xunit + - xunit_tests - linux_test_elevated_ci - linux_test_elevated_others - linux_test_unelevated_ci @@ -246,4 +242,4 @@ jobs: with: fetch-depth: 0 - name: Linux Packaging - uses: "./.github/actions/test/linux-packaging" + uses: "./.github/actions/test/linux-packaging" \ No newline at end of file diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index e0a8504205..996e76750b 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -141,20 +141,16 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v4.1.0 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: macos-15-large + test_results_artifact_name: testResults-xunit + PackageMac-macos_packaging: name: macOS packaging (bootstrap only) needs: @@ -174,7 +170,7 @@ jobs: ready_to_merge: name: macos ready to merge needs: - - verify_xunit + - xunit_tests - PackageMac-macos_packaging - macos_test_elevated_ci - macos_test_elevated_others @@ -183,4 +179,4 @@ jobs: if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: - needs_context: ${{ toJson(needs) }} + needs_context: ${{ toJson(needs) }} \ No newline at end of file diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index e960c0c255..a3776fb26a 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -145,20 +145,16 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: windows-latest - steps: - - name: checkout - uses: actions/checkout@v4.1.0 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: windows-latest + test_results_artifact_name: testResults-xunit + windows_packaging: name: Windows Packaging needs: @@ -168,7 +164,7 @@ jobs: ready_to_merge: name: windows ready to merge needs: - - verify_xunit + - xunit_tests - windows_test_elevated_ci - windows_test_elevated_others - windows_test_unelevated_ci @@ -177,4 +173,4 @@ jobs: if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: - needs_context: ${{ toJson(needs) }} + needs_context: ${{ toJson(needs) }} \ No newline at end of file diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml new file mode 100644 index 0000000000..8bf5fd699d --- /dev/null +++ b/.github/workflows/xunit-tests.yml @@ -0,0 +1,53 @@ +name: xUnit Tests (Reusable) + +on: + workflow_call: + inputs: + runner_os: + description: 'Runner OS for xUnit tests' + type: string + required: false + default: ubuntu-latest + test_results_artifact_name: + description: 'Artifact name for xUnit test results directory' + type: string + required: false + default: testResults-xunit + +jobs: + xunit: + name: Run xUnit Tests + runs-on: ${{ inputs.runner_os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing + + - name: Build PowerShell and run xUnit tests + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild + Write-Host "Running full xUnit test suite (no skipping)..." + Invoke-CIxUnit + Write-Host "Completed xUnit test run." + + - name: Upload xUnit results + uses: actions/upload-artifact@v4 + if: always() + with: + name: ${{ inputs.test_results_artifact_name }} + path: ${{ github.workspace }}/xUnitTestResults.xml