Skip to content

feat: release v1.3.0 - enhanced validation and documentation #68

feat: release v1.3.0 - enhanced validation and documentation

feat: release v1.3.0 - enhanced validation and documentation #68

Workflow file for this run

name: Documentation - Build & Deploy
on:
push:
branches: [main, develop]
tags: ['v*']
paths:
- 'docs/**'
- 'src/**'
- 'README.md'
- 'CHANGELOG.md'
- 'pyproject.toml'
- '.github/workflows/docs.yml'
pull_request:
branches: [main, develop]
paths:
- 'docs/**'
- 'src/**'
- 'README.md'
- 'CHANGELOG.md'
- 'pyproject.toml'
- '.github/workflows/docs.yml'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
PYTHONUNBUFFERED: "1"
FORCE_COLOR: "1"
jobs:
# Build documentation
build-docs:
name: Build Documentation
runs-on: ubuntu-latest
timeout-minutes: 15
outputs:
docs-artifact: ${{ steps.upload.outputs.artifact-id }}
docs-size: ${{ steps.check-size.outputs.size }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for version info
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -e .[docs]
- name: Verify documentation structure
run: |
if [ ! -d "docs" ]; then
echo "❌ docs/ directory not found!"
exit 1
fi
if [ ! -f "docs/conf.py" ]; then
echo "❌ docs/conf.py not found!"
exit 1
fi
if [ ! -f "docs/index.rst" ]; then
echo "❌ docs/index.rst not found!"
exit 1
fi
echo "✅ Documentation structure verified"
echo "📁 Documentation files found:"
find docs -name "*.rst" -o -name "*.md" | head -10
- name: Clean previous builds
run: |
cd docs
rm -rf _build
echo "🧹 Cleaned previous builds"
- name: Build with Sphinx
run: |
cd docs
echo "🔨 Building HTML documentation..."
sphinx-build -b html . _build/html -W --keep-going -j auto -v
echo "✅ Documentation built successfully"
- name: Check for build warnings
run: |
cd docs
# Check if there were any warnings in the build
if sphinx-build -b html . _build/html -W --keep-going 2>&1 | grep -i warning; then
echo "⚠️ Build completed with warnings"
else
echo "✅ Build completed without warnings"
fi
- name: Run quality checks
run: |
cd docs
echo "🔗 Checking documentation links..."
sphinx-build -b linkcheck . _build/linkcheck || echo "⚠️ Some links may be broken"
echo "📊 Generating documentation coverage..."
sphinx-build -b coverage . _build/coverage
if [ -f "_build/coverage/python.txt" ]; then
echo "📈 Documentation coverage report:"
cat _build/coverage/python.txt | head -20
fi
- name: Check build size and quality
id: check-size
run: |
cd docs/_build/html
# Check total size
DOCS_SIZE=$(du -sh . | cut -f1)
DOCS_SIZE_BYTES=$(du -sb . | cut -f1)
echo "size=$DOCS_SIZE" >> $GITHUB_OUTPUT
echo "size_bytes=$DOCS_SIZE_BYTES" >> $GITHUB_OUTPUT
echo "📊 Documentation metrics:"
echo " Size: $DOCS_SIZE"
echo " Files: $(find . -type f | wc -l)"
echo " HTML files: $(find . -name "*.html" | wc -l)"
# Check for essential files
if [ ! -f "index.html" ]; then
echo "❌ index.html not found!"
exit 1
fi
if [ ! -f "genindex.html" ]; then
echo "⚠️ genindex.html not found - API documentation may be incomplete"
fi
# Size warning
if [ $DOCS_SIZE_BYTES -gt 104857600 ]; then # 100MB
echo "⚠️ Documentation is quite large ($DOCS_SIZE). Consider optimization."
fi
echo "✅ Build quality checks completed"
- name: Upload documentation artifact
id: upload
uses: actions/upload-artifact@v4
with:
name: documentation-${{ github.sha }}
path: docs/_build/html/
retention-days: 30
compression-level: 6
# Validate documentation
validate-docs:
name: Validate Documentation
runs-on: ubuntu-latest
needs: build-docs
timeout-minutes: 10
steps:
- name: Download documentation
uses: actions/download-artifact@v4
with:
name: documentation-${{ github.sha }}
path: ./docs
- name: Validate HTML structure
run: |
echo "🔍 Validating HTML structure..."
# Check for broken internal links in HTML
echo "🔗 Checking for broken internal references..."
BROKEN_LINKS=$(find docs -name "*.html" -exec grep -l "404\|File not found\|broken reference" {} \; || true)
if [ -n "$BROKEN_LINKS" ]; then
echo "⚠️ Found files with potential broken references:"
echo "$BROKEN_LINKS" | head -5
else
echo "✅ No obvious broken references found"
fi
# Check for missing images
echo "🖼️ Checking for missing images..."
MISSING_IMAGES=$(find docs -name "*.html" -exec grep -o 'src="[^"]*"' {} \; | sed 's/src="//;s/"//' | while read img; do
if [[ "$img" == http* ]] || [[ "$img" == //* ]]; then
continue # Skip external URLs
fi
if [ ! -f "docs/$img" ]; then
echo "Missing: $img"
fi
done)
if [ -n "$MISSING_IMAGES" ]; then
echo "⚠️ Missing image files:"
echo "$MISSING_IMAGES" | head -5
else
echo "✅ All local images found"
fi
- name: Performance analysis
run: |
echo "⚡ Performance analysis:"
# File counts
TOTAL_FILES=$(find docs -type f | wc -l)
HTML_FILES=$(find docs -name "*.html" | wc -l)
echo "📊 File statistics:"
echo " Total files: $TOTAL_FILES"
echo " HTML files: $HTML_FILES"
# Size breakdown
echo "📦 Size breakdown:"
find docs -name "*.html" -exec du -sch {} + 2>/dev/null | tail -1 | awk '{print " HTML: " $1}' || echo " HTML: N/A"
find docs -name "*.css" -exec du -sch {} + 2>/dev/null | tail -1 | awk '{print " CSS: " $1}' || echo " CSS: N/A"
find docs -name "*.js" -exec du -sch {} + 2>/dev/null | tail -1 | awk '{print " JS: " $1}' || echo " JS: N/A"
find docs \( -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" -o -name "*.svg" \) -exec du -sch {} + 2>/dev/null | tail -1 | awk '{print " Images: " $1}' || echo " Images: N/A"
# Large files check
echo "🏋️ Large files (>1MB):"
find docs -type f -size +1M -exec ls -lh {} \; 2>/dev/null | awk '{print " " $5 " " $9}' | head -5 || echo " None found"
- name: Accessibility check
run: |
echo "♿ Basic accessibility check..."
# Check for images without alt text
IMAGES_NO_ALT=$(find docs -name "*.html" -exec grep -l '<img[^>]*>' {} \; | xargs grep '<img[^>]*>' | grep -v 'alt=' | wc -l)
if [ "$IMAGES_NO_ALT" -gt 0 ]; then
echo "⚠️ Found $IMAGES_NO_ALT images without alt text"
else
echo "✅ All images have alt text"
fi
echo "✅ Validation completed"
# Deploy to GitHub Pages
deploy-pages:
name: Deploy to GitHub Pages
runs-on: ubuntu-latest
needs: [build-docs, validate-docs]
if: startsWith(github.ref, 'refs/tags/v')
timeout-minutes: 10
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check if tag is on main branch
id: check-branch
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
echo "Checking if tag $TAG_NAME exists on main branch..."
# Check if the tag points to a commit that exists on main
if git merge-base --is-ancestor $TAG_NAME origin/main; then
echo "✅ Tag $TAG_NAME is on main branch"
echo "deploy=true" >> $GITHUB_OUTPUT
else
echo "❌ Tag $TAG_NAME is NOT on main branch"
echo "🚫 Skipping deployment - tags must be on main branch"
echo "deploy=false" >> $GITHUB_OUTPUT
fi
- name: Download documentation
if: steps.check-branch.outputs.deploy == 'true' || github.event.inputs.deploy_to_pages == 'true'
uses: actions/download-artifact@v4
with:
name: documentation-${{ github.sha }}
path: ./docs
- name: Setup GitHub Pages
if: steps.check-branch.outputs.deploy == 'true' || github.event.inputs.deploy_to_pages == 'true'
uses: actions/configure-pages@v4
- name: Upload to GitHub Pages
if: steps.check-branch.outputs.deploy == 'true' || github.event.inputs.deploy_to_pages == 'true'
uses: actions/upload-pages-artifact@v3
with:
path: ./docs
- name: Deploy to GitHub Pages
if: steps.check-branch.outputs.deploy == 'true' || github.event.inputs.deploy_to_pages == 'true'
id: deployment
uses: actions/deploy-pages@v4
- name: Report deployment
if: steps.check-branch.outputs.deploy == 'true' || github.event.inputs.deploy_to_pages == 'true'
run: |
echo "🚀 Documentation deployed successfully!"
echo "📖 Documentation URL: ${{ steps.deployment.outputs.page_url }}"
echo "📊 Documentation size: ${{ needs.build-docs.outputs.docs-size }}"
- name: Report skipped deployment
if: steps.check-branch.outputs.deploy == 'false'
run: |
echo "🚫 Deployment skipped - tag must be created from main branch"
echo "ℹ️ To deploy documentation, create tags from the main branch only"