Workflow file for this run
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: PostgreSQL Module Tests | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| - develop | |
| types: [opened, synchronize, reopened, edited] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Specific PostgreSQL version to test (e.g., 16.9, 17.5) - leave empty to test latest 5' | |
| required: false | |
| type: string | |
| jobs: | |
| detect-versions: | |
| name: Detect PostgreSQL Versions | |
| runs-on: ubuntu-latest | |
| outputs: | |
| versions: ${{ steps.get-versions.outputs.versions }} | |
| has-changes: ${{ steps.check-changes.outputs.has-changes }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check for Changes | |
| id: check-changes | |
| run: | | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| echo "has-changes=true" >> $GITHUB_OUTPUT | |
| echo "Manual workflow trigger - will run tests" | |
| elif [ "${{ github.event_name }}" == "pull_request" ]; then | |
| echo "has-changes=true" >> $GITHUB_OUTPUT | |
| echo "Pull request - will run tests" | |
| else | |
| CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }}) | |
| if echo "$CHANGED_FILES" | grep -qE "releases\.properties|\.github/workflows/postgresql-test\.yml"; then | |
| echo "has-changes=true" >> $GITHUB_OUTPUT | |
| echo "Relevant files changed - will run tests" | |
| else | |
| echo "has-changes=false" >> $GITHUB_OUTPUT | |
| echo "No relevant changes - skipping tests" | |
| fi | |
| fi | |
| - name: Get PostgreSQL Versions | |
| id: get-versions | |
| run: | | |
| if [ "${{ github.event.inputs.version }}" != "" ]; then | |
| # Manual workflow with specific version | |
| VERSION="${{ github.event.inputs.version }}" | |
| echo "Testing specific version: $VERSION" | |
| VERSIONS="[\"$VERSION\"]" | |
| elif [ "${{ github.event_name }}" == "pull_request" ]; then | |
| # For PRs, detect which versions were added or modified using GitHub API | |
| echo "Detecting versions changed in PR #${{ github.event.pull_request.number }}" | |
| # Get the diff from GitHub API using curl | |
| PATCH=$(curl -s -H "Authorization: token ${{ github.token }}" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" | \ | |
| jq -r '.[] | select(.filename == "releases.properties") | .patch' 2>/dev/null || echo "") | |
| if [ -z "$PATCH" ]; then | |
| echo "No changes to releases.properties detected" | |
| echo "Testing latest 5 stable versions as fallback" | |
| VERSIONS=$(grep -E "^[0-9]+\.[0-9]+" releases.properties | \ | |
| grep -v -E "(RC|beta|alpha)" | \ | |
| cut -d'=' -f1 | \ | |
| tr -d ' ' | \ | |
| jq -R -s -c 'split("\n") | map(select(length > 0)) | unique | sort_by(split(".") | map(tonumber)) | reverse | .[0:5]') | |
| else | |
| echo "Analyzing diff for added/modified versions..." | |
| # Extract added lines (lines starting with +) that contain version numbers | |
| CHANGED_VERSIONS=$(echo "$PATCH" | \ | |
| grep "^+" | \ | |
| grep -v "^+++" | \ | |
| grep -E "^\+[0-9]+\.[0-9]+" | \ | |
| sed 's/^+//' | \ | |
| cut -d'=' -f1 | \ | |
| tr -d ' ' | \ | |
| grep -v -E "(RC|beta|alpha)" || echo "") | |
| if [ -z "$CHANGED_VERSIONS" ]; then | |
| echo "No new stable versions found in PR" | |
| echo "Testing latest 5 stable versions as fallback" | |
| VERSIONS=$(grep -E "^[0-9]+\.[0-9]+" releases.properties | \ | |
| grep -v -E "(RC|beta|alpha)" | \ | |
| cut -d'=' -f1 | \ | |
| tr -d ' ' | \ | |
| jq -R -s -c 'split("\n") | map(select(length > 0)) | unique | sort_by(split(".") | map(tonumber)) | reverse | .[0:5]') | |
| else | |
| echo "Changed versions detected:" | |
| echo "$CHANGED_VERSIONS" | |
| VERSIONS=$(echo "$CHANGED_VERSIONS" | jq -R -s -c 'split("\n") | map(select(length > 0)) | unique') | |
| fi | |
| fi | |
| else | |
| # For other events, test latest 5 stable versions | |
| echo "Testing latest 5 stable versions (excluding RC/beta/alpha)" | |
| VERSIONS=$(grep -E "^[0-9]+\.[0-9]+" releases.properties | \ | |
| grep -v -E "(RC|beta|alpha)" | \ | |
| cut -d'=' -f1 | \ | |
| tr -d ' ' | \ | |
| jq -R -s -c 'split("\n") | map(select(length > 0)) | unique | sort_by(split(".") | map(tonumber)) | reverse | .[0:5]') | |
| fi | |
| echo "versions=$VERSIONS" >> $GITHUB_OUTPUT | |
| echo "Versions to test: $VERSIONS" | |
| test-postgresql: | |
| name: Test PostgreSQL ${{ 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 | |
| - name: Create Test Directories | |
| run: | | |
| New-Item -ItemType Directory -Force -Path "test-postgresql" | Out-Null | |
| New-Item -ItemType Directory -Force -Path "test-results" | Out-Null | |
| New-Item -ItemType Directory -Force -Path "test-data" | Out-Null | |
| Write-Host "✅ Test directories created" | |
| - name: Phase 1.1 - Download PostgreSQL | |
| id: download-postgresql | |
| continue-on-error: true | |
| run: | | |
| $ErrorActionPreference = "Continue" | |
| $version = "${{ matrix.version }}" | |
| Write-Host "=== Phase 1.1: Download PostgreSQL $version ===" | |
| # Read releases.properties to get download URL | |
| $releasesFile = "releases.properties" | |
| $downloadUrl = "" | |
| if (Test-Path $releasesFile) { | |
| $content = Get-Content $releasesFile | |
| foreach ($line in $content) { | |
| if ($line -match "^$version\s*=\s*(.+)$") { | |
| $downloadUrl = $matches[1].Trim() | |
| break | |
| } | |
| } | |
| } else { | |
| Write-Host "❌ ERROR: releases.properties file not found!" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=releases.properties file not found" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| 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-postgresql" $fileName | |
| Write-Host "Downloading PostgreSQL $version..." | |
| Write-Host "Target file: $downloadPath" | |
| try { | |
| 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-postgresql" -y 2>&1 | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "✅ Extraction successful" | |
| # List extracted contents | |
| Write-Host "Extracted contents:" | |
| Get-ChildItem -Path "test-postgresql" -Directory | ForEach-Object { Write-Host " - $($_.Name)" } | |
| # Find the postgresql directory | |
| $pgDir = Get-ChildItem -Path "test-postgresql" -Directory | Where-Object { $_.Name -match "^postgresql" } | Select-Object -First 1 | |
| if ($pgDir) { | |
| $pgPath = $pgDir.FullName | |
| Write-Host "✅ PostgreSQL directory found: $pgPath" | |
| # Verify bin directory exists | |
| $binPath = Join-Path $pgPath "bin" | |
| if (Test-Path $binPath) { | |
| Write-Host "✅ bin directory exists" | |
| echo "pg-path=$pgPath" >> $env:GITHUB_OUTPUT | |
| echo "success=true" >> $env:GITHUB_OUTPUT | |
| } else { | |
| Write-Host "❌ ERROR: bin directory not found in $pgPath" | |
| Write-Host "Directory structure:" | |
| Get-ChildItem -Path $pgPath | ForEach-Object { Write-Host " - $($_.Name)" } | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=bin directory not found in extracted archive" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| } else { | |
| Write-Host "❌ ERROR: PostgreSQL directory not found after extraction" | |
| Write-Host "Expected directory pattern: postgresql*" | |
| Write-Host "Found directories:" | |
| Get-ChildItem -Path "test-postgresql" -Directory | ForEach-Object { Write-Host " - $($_.Name)" } | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| echo "error=PostgreSQL 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 PostgreSQL Installation | |
| id: verify-postgresql | |
| if: steps.download-postgresql.outputs.success == 'true' | |
| continue-on-error: true | |
| run: | | |
| $ErrorActionPreference = "Continue" | |
| $pgPath = "${{ steps.download-postgresql.outputs.pg-path }}" | |
| Write-Host "=== Phase 1.2: Verify PostgreSQL Installation ===" | |
| # Check for required executables | |
| $binPath = Join-Path $pgPath "bin" | |
| $requiredExes = @("postgres.exe", "psql.exe", "pg_ctl.exe", "initdb.exe", "createdb.exe", "dropdb.exe") | |
| $allFound = $true | |
| $verifyResults = @{} | |
| foreach ($exe in $requiredExes) { | |
| $exePath = Join-Path $binPath $exe | |
| if (Test-Path $exePath) { | |
| Write-Host "✅ Found: $exe" | |
| $verifyResults[$exe] = @{ found = $true; path = $exePath } | |
| } else { | |
| Write-Host "❌ Missing: $exe" | |
| $verifyResults[$exe] = @{ found = $false } | |
| $allFound = $false | |
| } | |
| } | |
| # Test postgres version | |
| if ($allFound) { | |
| try { | |
| $postgresExe = Join-Path $binPath "postgres.exe" | |
| $versionOutput = & $postgresExe --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 "bin-path=$binPath" >> $env:GITHUB_OUTPUT | |
| } else { | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| - name: Phase 2 - Test Basic Functionality | |
| id: test-basic | |
| if: steps.verify-postgresql.outputs.success == 'true' | |
| continue-on-error: true | |
| run: | | |
| $ErrorActionPreference = "Continue" | |
| $binPath = "${{ steps.verify-postgresql.outputs.bin-path }}" | |
| Write-Host "=== Phase 2: Test Basic Functionality ===" | |
| # Test that executables can run and show version | |
| try { | |
| $postgresExe = Join-Path $binPath "postgres.exe" | |
| $psqlExe = Join-Path $binPath "psql.exe" | |
| $initdbExe = Join-Path $binPath "initdb.exe" | |
| Write-Host "`nTesting postgres.exe --version..." | |
| $pgVersion = & $postgresExe --version 2>&1 | Out-String | |
| Write-Host $pgVersion | |
| Write-Host "`nTesting psql.exe --version..." | |
| $psqlVersion = & $psqlExe --version 2>&1 | Out-String | |
| Write-Host $psqlVersion | |
| Write-Host "`nTesting initdb.exe --version..." | |
| $initdbVersion = & $initdbExe --version 2>&1 | Out-String | |
| Write-Host $initdbVersion | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "`n✅ All executables are functional" | |
| echo "success=true" >> $env:GITHUB_OUTPUT | |
| } else { | |
| Write-Host "`n❌ Some executables failed" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| } catch { | |
| Write-Host "❌ Error testing executables: $_" | |
| echo "success=false" >> $env:GITHUB_OUTPUT | |
| exit 1 | |
| } | |
| - name: Generate Test Summary | |
| if: always() | |
| run: | | |
| $version = "${{ matrix.version }}" | |
| Write-Host "`n=== Test Summary for PostgreSQL $version ===" | |
| $phase1_1 = "${{ steps.download-postgresql.outputs.success }}" -eq "true" | |
| $phase1_2 = "${{ steps.verify-postgresql.outputs.success }}" -eq "true" | |
| $phase2 = "${{ steps.test-basic.outputs.success }}" -eq "true" | |
| # Get error messages if any | |
| $error1_1 = "${{ steps.download-postgresql.outputs.error }}" | |
| $summary = "### PostgreSQL $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`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" | |
| - name: Upload Test Results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-postgresql-${{ matrix.version }} | |
| path: test-results/ | |
| retention-days: 30 | |
| - name: Upload Server Logs | |
| if: always() && steps.start-server.outputs.success == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: server-logs-postgresql-${{ matrix.version }} | |
| path: test-results/postgresql.log | |
| retention-days: 7 | |
| report-results: | |
| name: Report Test Results | |
| needs: [detect-versions, test-postgresql] | |
| if: always() && needs.detect-versions.outputs.has-changes == 'true' && needs.test-postgresql.result != 'cancelled' | |
| 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 "## 🐘 PostgreSQL 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-postgresql.result }}" | |
| if [ "$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 | |
| # 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 | |
| for version_dir in all-results/test-results-postgresql-*; 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 "⚠️ No test results available" >> comment.md | |
| echo "" >> comment.md | |
| fi | |
| 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)" >> comment.md | |
| echo "- **Phase 2:** Server Initialization (Init Cluster, Start Server)" >> comment.md | |
| echo "- **Phase 3:** Database Operations (Connect, Create DB, Delete DB)" >> comment.md | |
| echo "- **Phase 4:** Cleanup (Stop Server)" >> comment.md | |
| echo "" >> comment.md | |
| echo "_Check artifacts for detailed logs and server output._" >> comment.md | |
| 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('🐘 PostgreSQL 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 "## 🐘 PostgreSQL Module Tests - Manual Run Results" | |
| echo "" | |
| cat comment.md |