quiz-docs-updated #19
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: Deploy GitHub Pages Federation | |
| # Unified atomic workflow for deploying both corporate site and documentation | |
| # Solves race condition by deploying everything in a single atomic transaction | |
| on: | |
| # Triggered by corporate site updates | |
| repository_dispatch: | |
| types: | |
| - corporate-site-updated | |
| - quiz-docs-updated | |
| - hugo-templates-docs-updated | |
| - web-terminal-docs-updated | |
| - cli-docs-updated | |
| # Manual trigger with options | |
| workflow_dispatch: | |
| inputs: | |
| rebuild_corporate: | |
| description: 'Rebuild corporate site' | |
| type: boolean | |
| default: true | |
| rebuild_docs: | |
| description: 'Rebuild documentation' | |
| type: boolean | |
| default: true | |
| debug: | |
| description: 'Enable debug mode' | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| # Single concurrency group ensures atomic deployments | |
| concurrency: | |
| group: "github-pages-federation" | |
| cancel-in-progress: false | |
| jobs: | |
| deploy: | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| # ========================================== | |
| # PHASE 1: Download Current State | |
| # ========================================== | |
| - name: Download Current GitHub Pages State | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: gh-pages | |
| path: current-site | |
| continue-on-error: true | |
| - name: Validate Current State | |
| run: | | |
| echo "📦 Checking current site state..." | |
| if [ -d "current-site" ]; then | |
| echo "✅ Current site downloaded" | |
| echo "📊 Current site size: $(du -sh current-site | cut -f1)" | |
| if [ -f "current-site/index.html" ]; then | |
| echo "✅ Corporate site exists" | |
| fi | |
| if [ -d "current-site/docs" ]; then | |
| echo "✅ Docs directory exists: $(du -sh current-site/docs | cut -f1)" | |
| fi | |
| else | |
| echo "⚠️ No existing site found (fresh deployment)" | |
| mkdir -p current-site | |
| fi | |
| # ========================================== | |
| # PHASE 2: Setup Build Environment | |
| # ========================================== | |
| - name: Checkout Hub Repository (for configs) | |
| uses: actions/checkout@v4 | |
| with: | |
| path: hub-repo | |
| - name: Setup Hugo | |
| uses: peaceiris/actions-hugo@v2 | |
| with: | |
| hugo-version: '0.148.0' | |
| extended: true | |
| - name: Clone Hugo Templates Framework | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: info-tech-io/hugo-templates | |
| token: ${{ secrets.PAT_TOKEN }} | |
| path: hugo-templates | |
| submodules: recursive | |
| ref: main | |
| - name: Prepare Hugo Templates | |
| run: | | |
| echo "🔧 Preparing Hugo Templates framework..." | |
| cd hugo-templates | |
| git submodule update --init --recursive | |
| npm install || echo "⚠️ npm install failed, continuing..." | |
| chmod +x scripts/build.sh scripts/federated-build.sh | |
| cd .. | |
| echo "✅ Hugo Templates ready" | |
| # ========================================== | |
| # PHASE 3: Determine Federation Strategy | |
| # ========================================== | |
| - name: Determine Federation Strategy | |
| id: build-strategy | |
| run: | | |
| echo "🎯 Determining federation build strategy..." | |
| TRIGGER="${{ github.event_name }}" | |
| EVENT_TYPE="${{ github.event.action }}" | |
| if [ "$TRIGGER" = "workflow_dispatch" ]; then | |
| # Manual trigger - full rebuild | |
| echo "📢 Manual trigger - full rebuild" | |
| STRATEGY="merge-and-build" | |
| BUILD_CORPORATE="${{ github.event.inputs.rebuild_corporate }}" | |
| BUILD_DOCS="${{ github.event.inputs.rebuild_docs }}" | |
| # Apply defaults | |
| BUILD_CORPORATE="${BUILD_CORPORATE:-true}" | |
| BUILD_DOCS="${BUILD_DOCS:-true}" | |
| elif [ "$TRIGGER" = "repository_dispatch" ]; then | |
| if [ "$EVENT_TYPE" = "corporate-site-updated" ]; then | |
| # Corporate update - full rebuild | |
| echo "📢 Corporate site update - full rebuild" | |
| STRATEGY="merge-and-build" | |
| BUILD_CORPORATE="true" | |
| BUILD_DOCS="true" | |
| else | |
| # Documentation update - incremental | |
| echo "📢 Documentation update ($EVENT_TYPE) - incremental with preservation" | |
| STRATEGY="preserve-base-site" | |
| BUILD_CORPORATE="false" | |
| BUILD_DOCS="true" | |
| fi | |
| else | |
| echo "❌ Unknown trigger: $TRIGGER" | |
| exit 1 | |
| fi | |
| echo "strategy=$STRATEGY" >> $GITHUB_OUTPUT | |
| echo "build_corporate=$BUILD_CORPORATE" >> $GITHUB_OUTPUT | |
| echo "build_docs=$BUILD_DOCS" >> $GITHUB_OUTPUT | |
| echo "" | |
| echo "📋 Federation Strategy:" | |
| echo " - Strategy: $STRATEGY" | |
| echo " - Corporate: $BUILD_CORPORATE" | |
| echo " - Documentation: $BUILD_DOCS" | |
| # ========================================== | |
| # PHASE 4: Build Corporate Site (Conditional) | |
| # ========================================== | |
| - name: Clone Corporate Content | |
| if: steps.build-strategy.outputs.build_corporate == 'true' | |
| run: | | |
| echo "📥 Cloning corporate content repository..." | |
| git clone https://github.com/info-tech-io/info-tech.git info-tech | |
| echo "✅ Corporate content cloned" | |
| - name: Build Corporate Site | |
| if: steps.build-strategy.outputs.build_corporate == 'true' | |
| run: | | |
| echo "🏗️ Building corporate site..." | |
| cd hugo-templates | |
| # Copy corporate content to module-content | |
| rm -rf module-content | |
| cp -r ../info-tech/docs ./module-content | |
| # Build corporate site | |
| if [ "${{ github.event.inputs.debug }}" = "true" ]; then | |
| ./scripts/build.sh \ | |
| --config ./module-content/module.json \ | |
| --content ./module-content/content \ | |
| --output ../corporate-build \ | |
| --force \ | |
| --debug \ | |
| --verbose | |
| else | |
| ./scripts/build.sh \ | |
| --config ./module-content/module.json \ | |
| --content ./module-content/content \ | |
| --output ../corporate-build \ | |
| --force | |
| fi | |
| cd .. | |
| echo "✅ Corporate site built" | |
| - name: Validate Corporate Build | |
| if: steps.build-strategy.outputs.build_corporate == 'true' | |
| run: | | |
| echo "🔍 Validating corporate build..." | |
| if [ ! -f "corporate-build/index.html" ]; then | |
| echo "❌ Build failed: No index.html found" | |
| exit 1 | |
| fi | |
| html_count=$(find corporate-build -name '*.html' | wc -l) | |
| echo "✅ Corporate build successful: $html_count HTML files" | |
| echo "📦 Build size: $(du -sh corporate-build | cut -f1)" | |
| # ========================================== | |
| # PHASE 5: Build Documentation (Conditional) | |
| # ========================================== | |
| - name: Run Federation Build | |
| if: steps.build-strategy.outputs.build_docs == 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| run: | | |
| echo "🚀 Running Hugo Templates federated build..." | |
| cd hugo-templates | |
| STRATEGY="${{ steps.build-strategy.outputs.strategy }}" | |
| if [ "$STRATEGY" = "preserve-base-site" ]; then | |
| echo "🔄 Incremental build - using existing current-site as base" | |
| # КЛЮЧЕВОЕ ИСПРАВЛЕНИЕ: Создать временную конфигурацию с current-site как local source | |
| echo "📄 Creating temporary federation config with local base site..." | |
| # Создать правильную структуру для local source | |
| mkdir -p ../current-site/content | |
| # Переместить все файлы в content поддиректорию | |
| find ../current-site -maxdepth 1 -type f -exec mv {} ../current-site/content/ \; | |
| # Создать минимальный module.json для current-site | |
| cat > ../current-site/module.json <<'EOF' | |
| { | |
| "module": { | |
| "name": "base-site", | |
| "version": "1.0.0", | |
| "description": "Current GitHub Pages content (downloaded)" | |
| }, | |
| "build": { | |
| "template": "corporate", | |
| "theme": "compose", | |
| "copy_static": true | |
| } | |
| } | |
| EOF | |
| # Создать модифицированную конфигурацию | |
| jq --arg current_site_path "$(pwd)/../current-site" ' | |
| .federation.strategy = "download-merge-deploy" | | |
| .modules = [ | |
| { | |
| "name": "base-site", | |
| "source": { | |
| "repository": "local", | |
| "local_path": $current_site_path, | |
| "path": "content", | |
| "branch": "main" | |
| }, | |
| "module_json": "module.json", | |
| "destination": "/", | |
| "css_path_prefix": "" | |
| } | |
| ] + .modules | |
| ' ../hub-repo/configs/documentation-modules.json > ../temp-preserve-config.json | |
| echo "✅ Temporary config created with current-site as base module" | |
| ./scripts/federated-build.sh \ | |
| --config=../temp-preserve-config.json \ | |
| --output=../docs-build \ | |
| --verbose \ | |
| ${{ github.event.inputs.debug == 'true' && '--debug' || '' }} | |
| else | |
| echo "🔄 Full rebuild - building everything" | |
| ./scripts/federated-build.sh \ | |
| --config=../hub-repo/configs/documentation-modules.json \ | |
| --output=../docs-build \ | |
| --verbose \ | |
| ${{ github.event.inputs.debug == 'true' && '--debug' || '' }} | |
| fi | |
| # Cleanup temporary files | |
| if [ -f "../temp-preserve-config.json" ]; then | |
| rm -f ../temp-preserve-config.json | |
| echo "🧹 Cleaned up temporary config" | |
| fi | |
| cd .. | |
| echo "✅ Federation build complete" | |
| - name: Validate Documentation Build | |
| if: steps.build-strategy.outputs.build_docs == 'true' | |
| run: | | |
| echo "🔍 Validating documentation builds..." | |
| products=("quiz" "hugo-templates" "web-terminal" "info-tech-cli") | |
| for product in "${products[@]}"; do | |
| if [ -d "docs-build/docs/$product" ]; then | |
| html_count=$(find "docs-build/docs/$product" -name '*.html' | wc -l) | |
| echo " ✅ $product: $html_count HTML files" | |
| if [ ! -f "docs-build/docs/$product/index.html" ]; then | |
| echo " ⚠️ Warning: $product missing index.html" | |
| fi | |
| else | |
| echo " ❌ $product: Build output missing" | |
| exit 1 | |
| fi | |
| done | |
| echo "✅ All documentation validated" | |
| - name: Create Documentation Hub | |
| if: steps.build-strategy.outputs.build_docs == 'true' | |
| run: | | |
| echo "🏠 Creating documentation hub..." | |
| mkdir -p docs-build/docs | |
| cat > docs-build/docs/index.html <<'EOF' | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Documentation Hub - InfoTech.io</title> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| line-height: 1.6; | |
| color: #14171a; | |
| background: #ffffff; | |
| } | |
| header { | |
| background: #14171a; | |
| color: white; | |
| padding: 2rem; | |
| text-align: center; | |
| } | |
| h1 { font-size: 2.5rem; margin-bottom: 0.5rem; } | |
| .subtitle { color: rgba(255,255,255,0.8); font-size: 1.1rem; } | |
| .container { max-width: 1200px; margin: 3rem auto; padding: 0 2rem; } | |
| .products { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 2rem; } | |
| .card { | |
| background: #f7f9fa; | |
| border: 1px solid #e1e8ed; | |
| border-radius: 12px; | |
| padding: 2rem; | |
| transition: transform 0.3s, box-shadow 0.3s; | |
| text-decoration: none; | |
| color: inherit; | |
| display: block; | |
| } | |
| .card:hover { transform: translateY(-4px); box-shadow: 0 8px 24px rgba(0,0,0,0.12); } | |
| .icon { font-size: 3rem; margin-bottom: 1rem; } | |
| .card h2 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #14171a; } | |
| .card p { color: #657786; margin-bottom: 1rem; } | |
| .link { color: #1da1f2; font-weight: 500; text-decoration: none; } | |
| .back { display: inline-block; margin: 2rem 0; color: #1da1f2; text-decoration: none; } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <h1>📚 Documentation Hub</h1> | |
| <p class="subtitle">Comprehensive documentation for all InfoTech.io products</p> | |
| </header> | |
| <main class="container"> | |
| <div class="products"> | |
| <a href="/docs/quiz/" class="card"> | |
| <div class="icon">🎯</div> | |
| <h2>Quiz Engine</h2> | |
| <p>Interactive quiz and assessment platform for creating engaging educational content</p> | |
| <span class="link">View Documentation →</span> | |
| </a> | |
| <a href="/docs/hugo-templates/" class="card"> | |
| <div class="icon">🏗️</div> | |
| <h2>Hugo Templates Framework</h2> | |
| <p>Powerful Hugo-based static site generation framework with federated build capabilities</p> | |
| <span class="link">View Documentation →</span> | |
| </a> | |
| <a href="/docs/web-terminal/" class="card"> | |
| <div class="icon">💻</div> | |
| <h2>Web Terminal</h2> | |
| <p>Browser-based terminal emulator for interactive command-line experiences</p> | |
| <span class="link">View Documentation →</span> | |
| </a> | |
| <a href="/docs/info-tech-cli/" class="card"> | |
| <div class="icon">⚡</div> | |
| <h2>InfoTech CLI</h2> | |
| <p>Command-line interface for managing InfoTech.io projects and workflows</p> | |
| <span class="link">View Documentation →</span> | |
| </a> | |
| </div> | |
| <a href="/" class="back">← Back to Main Site</a> | |
| </main> | |
| </body> | |
| </html> | |
| EOF | |
| echo "✅ Documentation hub created" | |
| # ========================================== | |
| # PHASE 6: Prepare Final Site | |
| # ========================================== | |
| - name: Prepare Final Site Structure | |
| run: | | |
| echo "📦 Preparing final site from federation build..." | |
| STRATEGY="${{ steps.build-strategy.outputs.strategy }}" | |
| if [ "$STRATEGY" = "preserve-base-site" ]; then | |
| # For incremental updates, federated-build.sh already handled content preservation | |
| echo "🔄 Using federated build output (content already preserved)" | |
| if [ -d "docs-build" ]; then | |
| mv docs-build final-site | |
| echo "✅ Federation output moved to final-site" | |
| else | |
| echo "❌ Federation build output not found!" | |
| exit 1 | |
| fi | |
| else | |
| # For full rebuilds, combine corporate and docs | |
| echo "🔄 Combining corporate site and documentation" | |
| mkdir -p final-site | |
| # Add corporate site if built | |
| if [ "${{ steps.build-strategy.outputs.build_corporate }}" = "true" ] && [ -d "corporate-build" ]; then | |
| echo "📋 Adding corporate site..." | |
| rsync -av corporate-build/ final-site/ | |
| echo "✅ Corporate site added" | |
| fi | |
| # Add documentation if built | |
| if [ "${{ steps.build-strategy.outputs.build_docs }}" = "true" ] && [ -d "docs-build" ]; then | |
| echo "📋 Adding documentation..." | |
| if [ -d "docs-build/docs" ]; then | |
| # If docs-build contains docs/, copy it | |
| mkdir -p final-site/docs | |
| rsync -av docs-build/docs/ final-site/docs/ | |
| else | |
| # If docs-build is the docs content, copy it to /docs/ | |
| mkdir -p final-site/docs | |
| rsync -av docs-build/ final-site/docs/ | |
| fi | |
| echo "✅ Documentation added" | |
| fi | |
| fi | |
| echo "✅ Final site preparation complete" | |
| - name: Verify Final Site Structure | |
| run: | | |
| echo "📊 Final site structure verification:" | |
| echo "" | |
| echo "=== Root directory ===" | |
| if [ -f "final-site/index.html" ]; then | |
| echo "✅ Corporate index.html present" | |
| else | |
| echo "⚠️ Corporate index.html missing" | |
| fi | |
| echo "" | |
| echo "=== Documentation (/docs/) ===" | |
| if [ -d "final-site/docs" ]; then | |
| echo "✅ /docs/ directory exists" | |
| if [ -f "final-site/docs/index.html" ]; then | |
| echo "✅ /docs/index.html present" | |
| fi | |
| products=("quiz" "hugo-templates" "web-terminal" "info-tech-cli") | |
| for product in "${products[@]}"; do | |
| if [ -d "final-site/docs/$product" ]; then | |
| files=$(find "final-site/docs/$product" -type f | wc -l) | |
| echo " ✅ $product: $files files" | |
| else | |
| echo " ⚠️ $product: Not present" | |
| fi | |
| done | |
| else | |
| echo "❌ /docs/ directory missing!" | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "=== Final statistics ===" | |
| echo "📦 Total size: $(du -sh final-site | cut -f1)" | |
| echo "📄 Total files: $(find final-site -type f | wc -l)" | |
| echo "" | |
| echo "✅ Verification complete" | |
| # ========================================== | |
| # PHASE 7: Atomic Deployment | |
| # ========================================== | |
| - name: Upload Pages Artifact | |
| uses: actions/upload-pages-artifact@v3 | |
| with: | |
| path: final-site | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v4 | |
| - name: Deployment Success | |
| run: | | |
| echo "✅ GitHub Pages federation deployed successfully!" | |
| echo "🌐 URL: ${{ steps.deployment.outputs.page_url }}" | |
| echo "" | |
| echo "📋 Deployment Summary:" | |
| echo " - Corporate site: ${{ steps.build-targets.outputs.build_corporate == 'true' && 'Updated ✅' || 'Preserved ✅' }}" | |
| echo " - Documentation: ${{ steps.build-targets.outputs.build_docs == 'true' && 'Updated ✅' || 'Preserved ✅' }}" | |
| echo " - Deployment mode: Atomic (single transaction)" | |
| echo " - Concurrency: Serialized via unified group" | |
| # ========================================== | |
| # PHASE 8: Error Handling | |
| # ========================================== | |
| - name: Cleanup on Failure | |
| if: failure() | |
| run: | | |
| echo "❌ Workflow failed!" | |
| echo "🧹 Cleaning up temporary files..." | |
| rm -rf corporate-build docs-build current-site final-site hugo-templates info-tech hub-repo | |
| echo "✅ Cleanup complete" | |
| - name: Notify on Failure | |
| if: failure() | |
| run: | | |
| echo "::error::GitHub Pages deployment failed. Check logs for details." | |
| echo "::error::Failed job: ${{ github.job }}" | |
| echo "::error::Build targets: Corporate=${{ steps.build-targets.outputs.build_corporate }}, Docs=${{ steps.build-targets.outputs.build_docs }}" |