DevOps-Cheatsheet: fix(ci): Resolve PDF Generation Image Issues #20
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: DevOps Cheatsheet PDF Generator | |
| on: | |
| push: | |
| branches: [ main, master ] | |
| paths: | |
| - '**/*.md' | |
| - '**/*.png' | |
| - '**/*.jpg' | |
| - '**/*.jpeg' | |
| - '.github/workflows/generate-pdf.yml' | |
| pull_request: | |
| branches: [ main, master ] | |
| paths: | |
| - '**/*.md' | |
| workflow_dispatch: | |
| inputs: | |
| specific_category: | |
| description: 'Generate PDFs for specific category (leave empty for all)' | |
| required: false | |
| type: string | |
| jobs: | |
| generate-pdfs: | |
| name: Generate Cheatsheet PDFs | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18' | |
| cache: 'npm' | |
| - name: Install Dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y pandoc texlive-xetex texlive-fonts-recommended texlive-fonts-extra \ | |
| imagemagick webp librsvg2-bin | |
| - name: Configure ImageMagick Policy | |
| run: | | |
| sudo sed -i 's/rights="none" pattern="PDF"/rights="read|write" pattern="PDF"/' /etc/ImageMagick-6/policy.xml | |
| sudo sed -i 's/rights="none" pattern="LABEL"/rights="read|write" pattern="LABEL"/' /etc/ImageMagick-6/policy.xml | |
| - name: Cache PDF Generation | |
| uses: actions/cache@v3 | |
| with: | |
| path: | | |
| .pdf-cache | |
| .image-cache | |
| key: ${{ runner.os }}-pdf-${{ hashFiles('**/*.md', '**/*.png', '**/*.jpg', '**/*.jpeg', '**/*.webp') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pdf- | |
| - name: Setup Directories | |
| run: | | |
| mkdir -p pdfs | |
| mkdir -p .pdf-cache | |
| mkdir -p .image-cache | |
| - name: Process Images | |
| run: | | |
| # Function to process images | |
| process_image() { | |
| local input_file="$1" | |
| local output_file="$2" | |
| # Convert WebP to PNG | |
| if [[ "${input_file,,}" == *.webp ]]; then | |
| convert "$input_file" "${output_file%.webp}.png" | |
| echo "${output_file%.webp}.png" | |
| else | |
| # For other formats, optimize and copy | |
| convert "$input_file" -quality 90 "$output_file" | |
| echo "$output_file" | |
| fi | |
| } | |
| # Process all images in markdown files | |
| find . -type f -name "*.md" -exec grep -l '!\[.*\](' {} \; | while read mdfile; do | |
| dir=$(dirname "$mdfile") | |
| mkdir -p ".image-cache/$dir" | |
| # Extract and process images | |
| grep -o '!\[.*\]([^)]*)' "$mdfile" | sed 's/!\[.*\](\(.*\))/\1/' | while read img; do | |
| if [[ "$img" =~ ^https?:// ]]; then | |
| # Skip external images | |
| continue | |
| fi | |
| img_path="$dir/$img" | |
| if [ -f "$img_path" ]; then | |
| cache_path=".image-cache/${img_path#./}" | |
| mkdir -p "$(dirname "$cache_path")" | |
| if [ ! -f "$cache_path" ] || [ "$img_path" -nt "$cache_path" ]; then | |
| echo "Processing image: $img_path" | |
| processed_img=$(process_image "$img_path" "$cache_path") | |
| # Update markdown to use processed image | |
| sed -i "s|$img|$processed_img|g" "$mdfile" | |
| fi | |
| fi | |
| done | |
| done | |
| - name: Generate PDFs | |
| run: | | |
| # Function to generate PDF with custom styling | |
| generate_pdf() { | |
| local input_file="$1" | |
| local output_file="$2" | |
| local category="$(dirname "$input_file" | sed 's/.\///')" | |
| local title="$(basename "$input_file" .md)" | |
| # Create header with metadata | |
| cat > header.yaml <<EOF | |
| --- | |
| title: "${title//-/ } Cheatsheet" | |
| author: "DevOps Cheatsheet Hub" | |
| date: "$(date +'%B %d, %Y')" | |
| geometry: margin=2cm | |
| colorlinks: true | |
| linkcolor: blue | |
| urlcolor: blue | |
| toccolor: blue | |
| toc: true | |
| toc-depth: 2 | |
| category: "${category}" | |
| header-includes: | |
| - \usepackage{fancyhdr} | |
| - \usepackage{graphicx} | |
| - \usepackage{float} | |
| - \pagestyle{fancy} | |
| - \fancyhead[L]{DevOps Cheatsheet Hub} | |
| - \fancyhead[R]{${category}} | |
| - \fancyfoot[C]{\thepage} | |
| --- | |
| EOF | |
| # Combine header with content and generate PDF | |
| cat header.yaml "$input_file" | pandoc \ | |
| -f markdown \ | |
| -t pdf \ | |
| --pdf-engine=xelatex \ | |
| --highlight-style=tango \ | |
| -o "$output_file" \ | |
| --toc \ | |
| --toc-depth=2 \ | |
| --variable=geometry:margin=2cm \ | |
| --wrap=preserve \ | |
| --number-sections \ | |
| --verbose | |
| } | |
| # Process files based on input | |
| if [ -n "${{ github.event.inputs.specific_category }}" ]; then | |
| category="${{ github.event.inputs.specific_category }}" | |
| echo "Generating PDFs for category: $category" | |
| for file in "$category"/*.md; do | |
| if [ -f "$file" ]; then | |
| output_file="pdfs/$(basename "${file%.md}.pdf")" | |
| if [ ! -f ".pdf-cache/$(basename "$output_file")" ] || [ "$file" -nt ".pdf-cache/$(basename "$output_file")" ]; then | |
| echo "Generating PDF for $file" | |
| generate_pdf "$file" "$output_file" | |
| cp "$output_file" ".pdf-cache/" | |
| else | |
| echo "Using cached version for $file" | |
| cp ".pdf-cache/$(basename "$output_file")" "$output_file" | |
| fi | |
| fi | |
| done | |
| else | |
| echo "Generating PDFs for all categories" | |
| for file in */*.md; do | |
| if [ -f "$file" ]; then | |
| output_file="pdfs/$(dirname "$file")-$(basename "${file%.md}.pdf")" | |
| if [ ! -f ".pdf-cache/$(basename "$output_file")" ] || [ "$file" -nt ".pdf-cache/$(basename "$output_file")" ]; then | |
| echo "Generating PDF for $file" | |
| generate_pdf "$file" "$output_file" | |
| cp "$output_file" ".pdf-cache/" | |
| else | |
| echo "Using cached version for $file" | |
| cp ".pdf-cache/$(basename "$output_file")" "$output_file" | |
| fi | |
| fi | |
| done | |
| fi | |
| - name: Create PDF Index | |
| run: | | |
| echo "# DevOps Cheatsheet PDFs" > pdfs/index.md | |
| echo "Generated on: $(date +'%B %d, %Y')" >> pdfs/index.md | |
| echo "" >> pdfs/index.md | |
| for category in */; do | |
| if [ -d "$category" ]; then | |
| echo "## ${category%/}" >> pdfs/index.md | |
| for pdf in pdfs/${category%/}*.pdf; do | |
| if [ -f "$pdf" ]; then | |
| name=$(basename "$pdf" .pdf | sed 's/-/ /g') | |
| echo "- [$name]($pdf)" >> pdfs/index.md | |
| fi | |
| done | |
| echo "" >> pdfs/index.md | |
| fi | |
| done | |
| - name: Upload Individual PDFs | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: cheatsheet-pdfs | |
| path: pdfs/*.pdf | |
| retention-days: 30 | |
| - name: Create Release | |
| if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') | |
| run: | | |
| # Zip all PDFs | |
| cd pdfs | |
| zip -r ../cheatsheets.zip *.pdf | |
| cd .. | |
| # Create release tag | |
| TAG="v$(date +'%Y.%m.%d-%H%M')" | |
| gh release create "$TAG" \ | |
| --title "DevOps Cheatsheets $TAG" \ | |
| --notes-file pdfs/index.md \ | |
| cheatsheets.zip | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} | |
| - name: Update Documentation | |
| if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') | |
| run: | | |
| git config --local user.email "[email protected]" | |
| git config --local user.name "GitHub Action" | |
| # Update README with latest PDF links | |
| sed -i '/## Available PDFs/q' README.md | |
| echo "" >> README.md | |
| cat pdfs/index.md >> README.md | |
| # Commit and push if there are changes | |
| git add README.md | |
| git diff --quiet && git diff --staged --quiet || (git commit -m "docs: Update PDF links [skip ci]" && git push) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} |