Enhance Python CI workflow with main branch releases.properties sync … #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Python Module Tests | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Python version to test (e.g., 3.13.5, 3.12.9)' | |
| required: false | |
| type: string | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| detect-versions: | |
| name: Detect Python Versions to Test | |
| runs-on: ubuntu-latest | |
| outputs: | |
| versions: ${{ steps.detect.outputs.versions }} | |
| has-changes: ${{ steps.detect.outputs.has-changes }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Ensure releases.properties from main branch | |
| run: | | |
| # For PRs, ensure we're checking releases.properties from main branch | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| echo "Fetching releases.properties from main branch..." | |
| git fetch origin main:main | |
| git checkout main -- releases.properties || echo "Could not fetch releases.properties from main" | |
| fi | |
| - name: Detect Versions to Test | |
| id: detect | |
| run: | | |
| echo "=== Smart Version Detection for Pull Request Testing ===" | |
| # Initialize versions array | |
| VERSIONS="[]" | |
| HAS_CHANGES="false" | |
| # Check if manual dispatch with specific version | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.version }}" ]; then | |
| echo "Manual workflow dispatch with version: ${{ github.event.inputs.version }}" | |
| VERSIONS='["${{ github.event.inputs.version }}"]' | |
| HAS_CHANGES="true" | |
| echo "versions=$VERSIONS" >> $GITHUB_OUTPUT | |
| echo "has-changes=$HAS_CHANGES" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # For pull requests, use smart detection | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| echo "Pull request detected - using smart version detection" | |
| echo "" | |
| # Get changed files in the PR | |
| CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD) | |
| echo "Changed files in PR:" | |
| echo "$CHANGED_FILES" | |
| echo "" | |
| # PRIMARY METHOD: Extract versions from /bin directory changes | |
| echo "🔍 Primary Method: Checking /bin directory for version changes..." | |
| BIN_CHANGES=$(echo "$CHANGED_FILES" | grep -E '^bin/python[0-9]+\.[0-9]+\.[0-9]+' || true) | |
| if [ -n "$BIN_CHANGES" ]; then | |
| echo "✅ Found changes in /bin directory:" | |
| echo "$BIN_CHANGES" | |
| echo "" | |
| # Extract version numbers from bin directory names (e.g., bin/python3.19.1/ -> 3.19.1) | |
| DETECTED_VERSIONS="" | |
| while IFS= read -r file; do | |
| VERSION=$(echo "$file" | grep -oE 'python[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?' | sed 's/python//') | |
| if [ -n "$VERSION" ]; then | |
| echo " 📦 Detected version: $VERSION from $file" | |
| DETECTED_VERSIONS="$DETECTED_VERSIONS $VERSION" | |
| fi | |
| done <<< "$BIN_CHANGES" | |
| # Remove duplicates and verify versions exist in releases.properties | |
| VALID_VERSIONS="" | |
| for version in $(echo "$DETECTED_VERSIONS" | tr ' ' '\n' | sort -u); do | |
| if [ -n "$version" ] && grep -q "^${version}" releases.properties; then | |
| echo " ✅ Version $version confirmed in releases.properties" | |
| VALID_VERSIONS="$VALID_VERSIONS $version" | |
| HAS_CHANGES="true" | |
| else | |
| echo " ⚠️ Version $version not found in releases.properties (will skip)" | |
| fi | |
| done | |
| if [ -n "$VALID_VERSIONS" ]; then | |
| VERSIONS=$(echo "$VALID_VERSIONS" | tr ' ' '\n' | grep -v '^$' | sort -u | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| echo "" | |
| echo "✅ Primary method successful - versions to test: $VERSIONS" | |
| fi | |
| else | |
| echo "ℹ️ No changes detected in /bin directory" | |
| fi | |
| # FALLBACK METHOD: Check PR title for version numbers | |
| if [ "$HAS_CHANGES" = "false" ]; then | |
| echo "" | |
| echo "🔍 Fallback Method: Checking PR title for version numbers..." | |
| PR_TITLE="${{ github.event.pull_request.title }}" | |
| echo "PR Title: $PR_TITLE" | |
| # Extract version numbers from PR title (e.g., 3.13.5, 3.12.9) | |
| TITLE_VERSIONS=$(echo "$PR_TITLE" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?(-[a-z0-9]+)?' || true) | |
| if [ -n "$TITLE_VERSIONS" ]; then | |
| echo "Found versions in PR title: $TITLE_VERSIONS" | |
| # Verify these versions exist in releases.properties | |
| VALID_VERSIONS="" | |
| for version in $TITLE_VERSIONS; do | |
| if grep -q "^${version}" releases.properties; then | |
| echo " ✅ Version $version confirmed in releases.properties" | |
| VALID_VERSIONS="$VALID_VERSIONS $version" | |
| HAS_CHANGES="true" | |
| else | |
| echo " ⚠️ Version $version not found in releases.properties" | |
| fi | |
| done | |
| if [ -n "$VALID_VERSIONS" ]; then | |
| VERSIONS=$(echo "$VALID_VERSIONS" | tr ' ' '\n' | grep -v '^$' | sort -u | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| echo "" | |
| echo "✅ Fallback method successful - versions to test: $VERSIONS" | |
| fi | |
| else | |
| echo "ℹ️ No version numbers found in PR title" | |
| fi | |
| fi | |
| # FINAL FALLBACK: Test latest 5 versions if no versions detected | |
| if [ "$HAS_CHANGES" = "false" ]; then | |
| echo "" | |
| echo "🔍 Final Fallback: No versions detected, testing latest 5 versions..." | |
| LATEST_VERSIONS=$(grep -E "^[0-9]" releases.properties | cut -d'=' -f1 | tr -d ' ' | head -n 5) | |
| if [ -n "$LATEST_VERSIONS" ]; then | |
| VERSIONS=$(echo "$LATEST_VERSIONS" | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| HAS_CHANGES="true" | |
| echo "✅ Testing latest 5 versions: $VERSIONS" | |
| else | |
| echo "⚠️ No versions found in releases.properties" | |
| VERSIONS="[]" | |
| HAS_CHANGES="false" | |
| fi | |
| fi | |
| else | |
| # For push events, test only the latest version | |
| echo "Push event detected, testing latest version only" | |
| HAS_CHANGES="true" | |
| LATEST_VERSION=$(grep -E "^[0-9]" releases.properties | cut -d'=' -f1 | tr -d ' ' | head -n 1) | |
| if [ -n "$LATEST_VERSION" ]; then | |
| VERSIONS=$(echo "$LATEST_VERSION" | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| echo "Latest version to test: $VERSIONS" | |
| else | |
| echo "⚠️ No versions found in releases.properties" | |
| VERSIONS="[]" | |
| HAS_CHANGES="false" | |
| fi | |
| fi | |
| echo "" | |
| echo "==========================================" | |
| echo "Final versions to test: $VERSIONS" | |
| echo "Has changes: $HAS_CHANGES" | |
| echo "==========================================" | |
| echo "versions=$VERSIONS" >> $GITHUB_OUTPUT | |
| echo "has-changes=$HAS_CHANGES" >> $GITHUB_OUTPUT | |
| test-python: | |
| name: Test Python ${{ matrix.version }} | |
| needs: detect-versions | |
| if: needs.detect-versions.outputs.has-changes == 'true' | |
| runs-on: windows-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| version: ${{ fromJson(needs.detect-versions.outputs.versions) }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Create Test Results Directory | |
| run: | | |
| New-Item -ItemType Directory -Force -Path "test-results" | |
| Write-Host "✅ Created test-results directory" | |
| - name: Phase 1.1 - Download and Extract Python | |
| id: download-python | |
| continue-on-error: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GH_PAT }} | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $version = "${{ matrix.version }}" | |
| Write-Host "=== Phase 1.1: Download and Extract Python $version ===" | |
| # Create test directory | |
| New-Item -ItemType Directory -Force -Path "test-python" | Out-Null | |
| # Read releases.properties | |
| $releasesFile = "releases.properties" | |
| if (-not (Test-Path $releasesFile)) { | |
| Write-Host "❌ ERROR: releases.properties not found" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=releases.properties not found" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| # Parse releases.properties to find download URL | |
| $downloadUrl = $null | |
| Get-Content $releasesFile | ForEach-Object { | |
| $line = $_.Trim() | |
| if ($line -match "^$version\s*=\s*(.+)$") { | |
| $downloadUrl = $matches[1].Trim() | |
| } | |
| } | |
| if (-not $downloadUrl) { | |
| Write-Host "❌ ERROR: Version $version not found in releases.properties" | |
| Write-Host "Available versions in releases.properties:" | |
| Get-Content $releasesFile | Select-String "^[0-9]" | ForEach-Object { Write-Host " - $($_.Line.Split('=')[0].Trim())" } | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=Version $version not found in releases.properties" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| Write-Host "Download URL: $downloadUrl" | |
| try { | |
| $fileName = [System.IO.Path]::GetFileName($downloadUrl) | |
| $downloadPath = Join-Path "test-python" $fileName | |
| Write-Host "Downloading Python $version..." | |
| Write-Host "Target file: $downloadPath" | |
| try { | |
| # Try download with GitHub token for authentication (helps with pre-releases) | |
| $headers = @{} | |
| if ($env:GITHUB_TOKEN) { | |
| $headers["Authorization"] = "token $env:GITHUB_TOKEN" | |
| Write-Host "Using GitHub token for authentication" | |
| } | |
| if ($headers.Count -gt 0) { | |
| Invoke-WebRequest -Uri $downloadUrl -OutFile $downloadPath -Headers $headers -UseBasicParsing -TimeoutSec 300 | |
| } else { | |
| Invoke-WebRequest -Uri $downloadUrl -OutFile $downloadPath -UseBasicParsing -TimeoutSec 300 | |
| } | |
| } catch { | |
| Write-Host "❌ ERROR: Download failed!" | |
| Write-Host "Error details: $($_.Exception.Message)" | |
| Write-Host "Status Code: $($_.Exception.Response.StatusCode.value__)" | |
| Write-Host "URL attempted: $downloadUrl" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=Download failed: $($_.Exception.Message)" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| if (Test-Path $downloadPath) { | |
| $fileSize = (Get-Item $downloadPath).Length / 1MB | |
| Write-Host "✅ Downloaded: $fileName ($([math]::Round($fileSize, 2)) MB)" | |
| # Verify file is not empty or too small | |
| if ($fileSize -lt 0.1) { | |
| Write-Host "❌ ERROR: Downloaded file is too small ($([math]::Round($fileSize, 2)) MB), likely corrupted" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=Downloaded file is too small or corrupted" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| # Extract the archive | |
| Write-Host "Extracting archive..." | |
| $extractOutput = & 7z x $downloadPath -o"test-python" -y 2>&1 | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "✅ Extraction successful" | |
| # List extracted contents | |
| Write-Host "Extracted contents:" | |
| Get-ChildItem -Path "test-python" -Directory | ForEach-Object { Write-Host " - $($_.Name)" } | |
| # Find the python directory | |
| $pythonDir = Get-ChildItem -Path "test-python" -Directory | Where-Object { $_.Name -match "^python" } | Select-Object -First 1 | |
| if ($pythonDir) { | |
| $pythonPath = $pythonDir.FullName | |
| Write-Host "✅ Python directory found: $pythonPath" | |
| # Verify python.exe exists | |
| $pythonExe = Join-Path $pythonPath "python.exe" | |
| if (Test-Path $pythonExe) { | |
| Write-Host "✅ python.exe exists" | |
| echo "python-path=$pythonPath" >> $env:GITHUB_OUTPUT | |
| echo "success=true" >> $env:GITHUB_OUTPUT | |
| } else { | |
| Write-Host "❌ ERROR: python.exe not found in $pythonPath" | |
| Write-Host "Directory structure:" | |
| Get-ChildItem -Path $pythonPath | ForEach-Object { Write-Host " - $($_.Name)" } | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=python.exe not found in extracted archive" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| } else { | |
| Write-Host "❌ ERROR: Python directory not found after extraction" | |
| Write-Host "Expected directory pattern: python*" | |
| Write-Host "Found directories:" | |
| Get-ChildItem -Path "test-python" -Directory | ForEach-Object { Write-Host " - $($_.Name)" } | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=Python directory not found after extraction" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| } else { | |
| Write-Host "❌ ERROR: Extraction failed with exit code: $LASTEXITCODE" | |
| Write-Host "7z output:" | |
| Write-Host $extractOutput | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=Extraction failed with exit code $LASTEXITCODE" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| } else { | |
| Write-Host "❌ ERROR: Download file not found at expected path: $downloadPath" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=Download file not found after download attempt" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| } catch { | |
| Write-Host "❌ ERROR: Unexpected error occurred" | |
| Write-Host "Error message: $($_.Exception.Message)" | |
| Write-Host "Stack trace: $($_.ScriptStackTrace)" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=$($_.Exception.Message)" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| - name: Phase 1.2 - Verify Python Installation | |
| id: verify-python | |
| if: steps.download-python.outputs.success == 'true' | |
| continue-on-error: true | |
| run: | | |
| $ErrorActionPreference = "Continue" | |
| $pythonPath = "${{ steps.download-python.outputs.python-path }}" | |
| Write-Host "=== Phase 1.2: Verify Python Installation ===" | |
| # Check for required executables | |
| $requiredExes = @("python.exe", "pip.exe") | |
| $allFound = $true | |
| $verifyResults = @{} | |
| foreach ($exe in $requiredExes) { | |
| $exePath = Join-Path $pythonPath $exe | |
| if (Test-Path $exePath) { | |
| Write-Host "✅ Found: $exe" | |
| $verifyResults[$exe] = @{ found = $true; path = $exePath } | |
| } else { | |
| # pip might be in Scripts directory | |
| $scriptsPath = Join-Path $pythonPath "Scripts" | |
| $exePath = Join-Path $scriptsPath $exe | |
| if (Test-Path $exePath) { | |
| Write-Host "✅ Found: $exe (in Scripts)" | |
| $verifyResults[$exe] = @{ found = $true; path = $exePath } | |
| } else { | |
| Write-Host "❌ Missing: $exe" | |
| $verifyResults[$exe] = @{ found = $false } | |
| if ($exe -ne "pip.exe") { | |
| $allFound = $false | |
| } | |
| } | |
| } | |
| } | |
| # Test python version | |
| if ($allFound) { | |
| try { | |
| $pythonExe = Join-Path $pythonPath "python.exe" | |
| $versionOutput = & $pythonExe --version 2>&1 | Out-String | |
| Write-Host "Version: $versionOutput" | |
| $verifyResults["version"] = $versionOutput.Trim() | |
| } catch { | |
| Write-Host "⚠️ Could not get version: $_" | |
| } | |
| } | |
| $verifyResults | ConvertTo-Json -Depth 10 | Out-File "test-results/verify.json" | |
| if ($allFound) { | |
| echo "success=true" >> $env:GITHUB_OUTPUT | |
| echo "python-exe=$pythonExe" >> $env:GITHUB_OUTPUT | |
| } else { | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| - name: Phase 2 - Test Basic Functionality | |
| id: test-basic | |
| if: steps.verify-python.outputs.success == 'true' | |
| continue-on-error: true | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $pythonExe = "${{ steps.verify-python.outputs.python-exe }}" | |
| Write-Host "=== Phase 2: Test Basic Functionality ===" | |
| try { | |
| $allFunctional = $true | |
| $testResults = @() | |
| Write-Host "`nTesting python.exe --version..." | |
| try { | |
| $pythonVersion = & $pythonExe --version 2>&1 | |
| Write-Host $pythonVersion | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "✅ python.exe is functional" | |
| $testResults += "python: PASS" | |
| } else { | |
| Write-Host "❌ python.exe failed with exit code: $LASTEXITCODE" | |
| $allFunctional = $false | |
| $testResults += "python: FAIL" | |
| } | |
| } catch { | |
| Write-Host "❌ python.exe error: $_" | |
| $allFunctional = $false | |
| $testResults += "python: ERROR" | |
| } | |
| Write-Host "`nTesting pip..." | |
| try { | |
| $pipVersion = & $pythonExe -m pip --version 2>&1 | |
| Write-Host $pipVersion | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "✅ pip is functional" | |
| $testResults += "pip: PASS" | |
| } else { | |
| Write-Host "⚠️ pip failed with exit code: $LASTEXITCODE" | |
| $testResults += "pip: WARN" | |
| } | |
| } catch { | |
| Write-Host "⚠️ pip error: $_" | |
| $testResults += "pip: WARN" | |
| } | |
| Write-Host "`nTesting Python import system..." | |
| try { | |
| $importTest = & $pythonExe -c "import sys; print(f'Python {sys.version}')" 2>&1 | |
| Write-Host $importTest | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "✅ Python import system is functional" | |
| $testResults += "import: PASS" | |
| } else { | |
| Write-Host "❌ Python import failed with exit code: $LASTEXITCODE" | |
| $allFunctional = $false | |
| $testResults += "import: FAIL" | |
| } | |
| } catch { | |
| Write-Host "❌ Python import error: $_" | |
| $allFunctional = $false | |
| $testResults += "import: ERROR" | |
| } | |
| Write-Host "`nTest Results:" | |
| $testResults | ForEach-Object { Write-Host " $_" } | |
| if ($allFunctional) { | |
| Write-Host "`n✅ All critical tests passed" | |
| echo "success=true" >> $env:GITHUB_OUTPUT | |
| } else { | |
| Write-Host "`n❌ Some critical tests failed" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=One or more critical tests failed" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| } catch { | |
| Write-Host "❌ Error testing Python: $_" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=$($_.Exception.Message)" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| - name: Generate Test Summary | |
| if: always() | |
| run: | | |
| $version = "${{ matrix.version }}" | |
| Write-Host "`n=== Test Summary for Python $version ===" | |
| $phase1_1 = "${{ steps.download-python.outputs.success }}" -eq "true" | |
| $phase1_2 = "${{ steps.verify-python.outputs.success }}" -eq "true" | |
| $phase2 = "${{ steps.test-basic.outputs.success }}" -eq "true" | |
| # Get error messages if any | |
| $error1_1 = "${{ steps.download-python.outputs.error }}" | |
| $error2 = "${{ steps.test-basic.outputs.error }}" | |
| $summary = "### Python $version`n`n" | |
| $summary += "**Phase 1: Installation Validation**`n" | |
| $summary += "- Download & Extract: $(if ($phase1_1) { '✅ PASS' } else { '❌ FAIL' })`n" | |
| if (-not $phase1_1 -and $error1_1) { | |
| $summary += " - Error: $error1_1`n" | |
| } | |
| $summary += "- Verify Executables: $(if ($phase1_2) { '✅ PASS' } else { '❌ FAIL' })`n`n" | |
| if ($phase1_2) { | |
| $summary += "**Phase 2: Basic Functionality**`n" | |
| $summary += "- Test Executables: $(if ($phase2) { '✅ PASS' } else { '❌ FAIL' })`n" | |
| if (-not $phase2 -and $error2) { | |
| $summary += " - Error: $error2`n" | |
| } | |
| $summary += "`n" | |
| } | |
| # Overall status | |
| $allPassed = $phase1_1 -and $phase1_2 -and $phase2 | |
| if ($allPassed) { | |
| $summary += "**Overall Status:** ✅ ALL TESTS PASSED`n" | |
| } else { | |
| $summary += "**Overall Status:** ❌ SOME TESTS FAILED`n" | |
| $summary += "`n" | |
| $summary += "<details>`n" | |
| $summary += "<summary>💡 Click here for troubleshooting tips</summary>`n`n" | |
| $summary += "- Check the workflow logs for detailed error messages`n" | |
| $summary += "- Download the test artifacts for complete logs`n" | |
| $summary += "- Verify the .7z archive structure matches expected format`n" | |
| $summary += "- Ensure all required DLL dependencies are included`n" | |
| $summary += "</details>`n" | |
| } | |
| Write-Host $summary | |
| $summary | Out-File "test-results/summary.md" | |
| # Set job outcome based on test results | |
| if (-not $allPassed) { | |
| Write-Host "##[error]Tests failed for Python $version" | |
| exit 1 | |
| } | |
| - name: Upload Test Results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-python-${{ matrix.version }} | |
| path: test-results/ | |
| retention-days: 30 | |
| report-results: | |
| name: Report Test Results | |
| needs: [detect-versions, test-python] | |
| if: always() && needs.detect-versions.outputs.has-changes == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download all test results | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: all-results | |
| continue-on-error: true | |
| - name: Generate PR Comment | |
| run: | | |
| echo "## 🐍 Python Module Tests - Results" > comment.md | |
| echo "" >> comment.md | |
| echo "**Test Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> comment.md | |
| # Determine overall test status | |
| TEST_STATUS="${{ needs.test-python.result }}" | |
| VERSIONS='${{ needs.detect-versions.outputs.versions }}' | |
| if [ "$TEST_STATUS" = "skipped" ] || [ "$VERSIONS" = "[]" ]; then | |
| echo "**Status:** ⏭️ Tests skipped - no versions to test" >> comment.md | |
| echo "" >> comment.md | |
| echo "ℹ️ **Smart Version Detection**" >> comment.md | |
| echo "" >> comment.md | |
| echo "This workflow uses intelligent three-tier detection:" >> comment.md | |
| echo "" >> comment.md | |
| echo "1. **Primary Method**: Detects versions from \`/bin/pythonX.X.X/\` directory changes" >> comment.md | |
| echo "2. **Fallback Method**: Extracts versions from PR title (e.g., \"3.13.5\", \"3.12.9\")" >> comment.md | |
| echo "3. **Final Fallback**: Tests latest 5 versions if no versions detected" >> comment.md | |
| echo "" >> comment.md | |
| echo "**To trigger tests:**" >> comment.md | |
| echo "- Add changes to \`/bin/pythonX.X.X/\` directories, OR" >> comment.md | |
| echo "- Add version numbers to your PR title (e.g., \"Update Python 3.13.5\"), OR" >> comment.md | |
| echo "- Manually trigger the workflow from the Actions tab" >> comment.md | |
| elif [ "$TEST_STATUS" = "success" ]; then | |
| echo "**Status:** ✅ All tests passed" >> comment.md | |
| elif [ "$TEST_STATUS" = "failure" ]; then | |
| echo "**Status:** ❌ Some tests failed" >> comment.md | |
| else | |
| echo "**Status:** ⚠️ Tests completed with issues" >> comment.md | |
| fi | |
| echo "" >> comment.md | |
| # Generate badges for each version | |
| if [ "$TEST_STATUS" != "skipped" ] && [ "$VERSIONS" != "[]" ]; then | |
| echo "### 📊 Test Results by Version" >> comment.md | |
| echo "" >> comment.md | |
| # Parse versions and check results | |
| VERSION_LIST=$(echo '${{ needs.detect-versions.outputs.versions }}' | jq -r '.[]') | |
| for version in $VERSION_LIST; do | |
| # Check if summary file exists for this version | |
| SUMMARY_FILE="all-results/test-results-python-${version}/summary.md" | |
| if [ -f "$SUMMARY_FILE" ]; then | |
| # Check if tests passed by looking for "ALL TESTS PASSED" in summary | |
| if grep -q "ALL TESTS PASSED" "$SUMMARY_FILE"; then | |
| # Success badge (green) | |
| echo "" >> comment.md | |
| else | |
| # Failure badge (red) | |
| echo "" >> comment.md | |
| fi | |
| else | |
| # No results badge (gray) | |
| echo "" >> comment.md | |
| fi | |
| done | |
| echo "" >> comment.md | |
| fi | |
| echo "" >> comment.md | |
| # Check if artifacts exist | |
| if [ -d "all-results" ]; then | |
| # Count expected vs actual results | |
| EXPECTED_COUNT=$(echo '${{ needs.detect-versions.outputs.versions }}' | jq '. | length') | |
| ACTUAL_COUNT=$(find all-results -name "summary.md" 2>/dev/null | wc -l) | |
| echo "**Results:** $ACTUAL_COUNT of $EXPECTED_COUNT versions tested" >> comment.md | |
| echo "" >> comment.md | |
| # Check if there are any failures | |
| HAS_FAILURES=false | |
| for version_dir in all-results/test-results-python-*; do | |
| if [ -d "$version_dir" ]; then | |
| for summary_file in "$version_dir"/summary.md; do | |
| if [ -f "$summary_file" ]; then | |
| if ! grep -q "ALL TESTS PASSED" "$summary_file"; then | |
| HAS_FAILURES=true | |
| break 2 | |
| fi | |
| fi | |
| done | |
| fi | |
| done | |
| # Only show detailed results if there are failures | |
| if [ "$HAS_FAILURES" = true ]; then | |
| echo "### 📋 Detailed Test Results" >> comment.md | |
| echo "" >> comment.md | |
| for version_dir in all-results/test-results-python-*; do | |
| if [ -d "$version_dir" ]; then | |
| for summary_file in "$version_dir"/summary.md; do | |
| if [ -f "$summary_file" ]; then | |
| cat "$summary_file" >> comment.md | |
| echo "" >> comment.md | |
| fi | |
| done | |
| fi | |
| done | |
| else | |
| echo "_All tests passed successfully! ✨_" >> comment.md | |
| echo "" >> comment.md | |
| fi | |
| elif [ "$TEST_STATUS" != "skipped" ] && [ "$VERSIONS" != "[]" ]; then | |
| echo "⚠️ No test results available" >> comment.md | |
| echo "" >> comment.md | |
| fi | |
| if [ "$TEST_STATUS" != "skipped" ] && [ "$VERSIONS" != "[]" ]; then | |
| echo "---" >> comment.md | |
| echo "" >> comment.md | |
| echo "### 📋 Test Phases" >> comment.md | |
| echo "" >> comment.md | |
| echo "Each version is tested through the following phases:" >> comment.md | |
| echo "- **Phase 1:** Installation Validation (Download, Extract, Verify Executables)" >> comment.md | |
| echo "- **Phase 2:** Basic Functionality (Test Python Version, pip, Import System)" >> comment.md | |
| echo "" >> comment.md | |
| echo "_Check artifacts for detailed logs._" >> comment.md | |
| fi | |
| cat comment.md | |
| - name: Comment on PR | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const comment = fs.readFileSync('comment.md', 'utf8'); | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('🐍 Python Module Tests') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: comment | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: comment | |
| }); | |
| } | |
| - name: Display Results Summary (Manual Run) | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| echo "## 🐍 Python Module Tests - Manual Run Results" | |
| echo "" | |
| cat comment.md |