Skip to content

ci

ci #18

Workflow file for this run

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