Skip to content

feat: Add issue and pull request templates for better contribution gu… #10

feat: Add issue and pull request templates for better contribution gu…

feat: Add issue and pull request templates for better contribution gu… #10

name: Test with Comments
on:
pull_request:
branches: [ main, develop ]
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
checks: write
jobs:
test-with-comments:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: test_backend
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11.x
- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-cov pytest-html pytest-json-report
- name: Set up environment variables
run: |
echo "DJANGO_DEBUG=False" >> $GITHUB_ENV
echo "SECRET_KEY=test-secret-key-for-ci" >> $GITHUB_ENV
echo "ALLOWED_HOSTS=localhost,127.0.0.1" >> $GITHUB_ENV
echo "DATABASE_TYPE=pgsql" >> $GITHUB_ENV
echo "DATABASE_USER=postgres" >> $GITHUB_ENV
echo "DATABASE_PASSWORD=postgres" >> $GITHUB_ENV
echo "DATABASE_HOST=localhost" >> $GITHUB_ENV
echo "DATABASE_PORT=5432" >> $GITHUB_ENV
echo "DATABASE_NAME=test_backend" >> $GITHUB_ENV
echo "REDIS_HOST=localhost" >> $GITHUB_ENV
echo "REDIS_PORT=6379" >> $GITHUB_ENV
echo "REDIS_DB=0" >> $GITHUB_ENV
- name: Run migrations
run: |
python manage.py migrate
- name: Run tests with coverage and reporting
run: |
pytest \
--verbose \
--tb=short \
--cov=. \
--cov-report=xml \
--cov-report=html \
--cov-report=term \
--html=reports/pytest-report.html \
--self-contained-html \
--json-report \
--json-report-file=reports/pytest-report.json \
--junit-xml=reports/junit.xml \
2>&1 | tee test-output.log
- name: Parse test results
if: always()
run: |
# Create test results summary
python3 << 'EOF'
import json
import sys
import os
# Parse pytest JSON report
try:
with open('reports/pytest-report.json', 'r') as f:
report = json.load(f)
summary = report.get('summary', {})
tests = report.get('tests', [])
total = summary.get('total', 0)
passed = summary.get('passed', 0)
failed = summary.get('failed', 0)
skipped = summary.get('skipped', 0)
# Calculate percentages
if total > 0:
pass_rate = (passed / total) * 100
fail_rate = (failed / total) * 100
else:
pass_rate = 0
fail_rate = 0
# Get failed tests details
failed_tests = [test for test in tests if test.get('outcome') == 'failed']
# Write summary to file
with open('test_summary.json', 'w') as f:
json.dump({
'total': total,
'passed': passed,
'failed': failed,
'skipped': skipped,
'pass_rate': round(pass_rate, 2),
'fail_rate': round(fail_rate, 2),
'failed_tests': failed_tests[:5] # Limit to first 5 failures
}, f, indent=2)
except FileNotFoundError:
print("Test report not found, creating default summary")
with open('test_summary.json', 'w') as f:
json.dump({
'total': 0,
'passed': 0,
'failed': 0,
'skipped': 0,
'pass_rate': 0,
'fail_rate': 0,
'failed_tests': []
}, f)
EOF
- name: Parse coverage results
if: always()
run: |
# Extract coverage percentage
if [ -f "coverage.xml" ]; then
COVERAGE=$(python3 -c "
import xml.etree.ElementTree as ET
try:
tree = ET.parse('coverage.xml')
root = tree.getroot()
coverage = root.attrib.get('line-rate', '0')
print(f'{float(coverage) * 100:.1f}')
except:
print('0.0')
")
else
COVERAGE="0.0"
fi
echo "COVERAGE_PERCENT=$COVERAGE" >> $GITHUB_ENV
- name: Generate detailed comment
if: always()
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
// Read test summary
let testSummary;
try {
testSummary = JSON.parse(fs.readFileSync('test_summary.json', 'utf8'));
} catch (error) {
testSummary = {
total: 0, passed: 0, failed: 0, skipped: 0,
pass_rate: 0, fail_rate: 0, failed_tests: []
};
}
// Read test output log
let testOutput = '';
try {
testOutput = fs.readFileSync('test-output.log', 'utf8');
} catch (error) {
testOutput = 'Test output not available';
}
// Determine overall status
const overallStatus = testSummary.failed === 0 ? '✅ PASSED' : '❌ FAILED';
const statusEmoji = testSummary.failed === 0 ? '🎉' : '⚠️';
// Create progress bars
const createProgressBar = (percentage, width = 20) => {
const filled = Math.round((percentage / 100) * width);
const empty = width - filled;
return '█'.repeat(filled) + '░'.repeat(empty);
};
const passBar = createProgressBar(testSummary.pass_rate);
const coverageBar = createProgressBar(parseFloat(process.env.COVERAGE_PERCENT || '0'));
// Generate failed tests section
let failedTestsSection = '';
if (testSummary.failed_tests && testSummary.failed_tests.length > 0) {
failedTestsSection = `
### ❌ Failed Tests
${testSummary.failed_tests.map(test => `

Check failure on line 226 in .github/workflows/test-with-comments.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/test-with-comments.yml

Invalid workflow file

You have an error in your yaml syntax on line 226
**${test.nodeid}**
\`\`\`
${test.call?.longrepr || 'No details available'}
\`\`\`
`).join('\n')}
${testSummary.failed_tests.length >= 5 ? '_Note: Only showing first 5 failures_' : ''}
`;
}
// Create the comment
const comment = `## ${statusEmoji} Test Results Report
### 📊 Overall Status: ${overallStatus}
| Metric | Value | Progress |
|--------|-------|----------|
| **Total Tests** | ${testSummary.total} | |
| **Passed** | ${testSummary.passed} | ${passBar} ${testSummary.pass_rate}% |
| **Failed** | ${testSummary.failed} | |
| **Skipped** | ${testSummary.skipped} | |
| **Coverage** | ${process.env.COVERAGE_PERCENT || '0.0'}% | ${coverageBar} |
### 🔍 Test Details
<details>
<summary>📋 Click to view detailed test output</summary>
\`\`\`
${testOutput.slice(-2000)} // Last 2000 chars to avoid comment size limits
\`\`\`
</details>
${failedTestsSection}
### 🏗️ Build Information
- **Python Version**: 3.11.x
- **Django Version**: 5.2.1
- **Database**: PostgreSQL 15
- **Cache**: Redis 7
- **Commit**: \`${context.sha.substring(0, 8)}\`
- **Branch**: \`${context.payload.pull_request.head.ref}\`
### 📎 Artifacts
${testSummary.failed === 0 ?
'✅ All tests passed! No artifacts generated.' :
'📄 Test reports and coverage details are available in the workflow artifacts.'
}
---
${testSummary.failed === 0 ?
'🎉 **Great job!** All tests are passing. This PR is ready for review!' :
'⚠️ **Please fix the failing tests** before merging this PR.'
}
<sub>🤖 This comment was automatically generated by the test workflow</sub>`;
// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existingComment = comments.find(comment =>
comment.body.includes('Test Results Report') &&
comment.user.type === 'Bot'
);
// Update or create comment
if (existingComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.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: Upload test reports
if: always()
uses: actions/upload-artifact@v3
with:
name: test-reports-${{ github.run_number }}
path: |
reports/
coverage.xml
test-output.log
test_summary.json
retention-days: 30
- name: Publish test results
if: always()
uses: dorny/test-reporter@v1
with:
name: Django Tests
path: reports/junit.xml
reporter: java-junit
fail-on-error: false
- name: Set job status
if: always()
run: |
if [ -f "test_summary.json" ]; then
FAILED=$(python3 -c "import json; print(json.load(open('test_summary.json'))['failed'])")
if [ "$FAILED" -gt 0 ]; then
echo "Tests failed, marking job as failed"
exit 1
fi
fi
echo "All tests passed successfully!"