name: Build and Deploy Documentation on: push: branches: - main paths: - 'docs/**' - 'templates/**' - 'mkdocs.yml' - 'api/**' - 'mcp-server/**' - '.github/workflows/**' pull_request: branches: - main # Trigger manuale workflow_dispatch: # Schedule per rebuild automatico (ogni giorno alle 2 AM) schedule: - cron: '0 2 * * *' env: DOCKER_REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }}/docs-server PYTHON_VERSION: '3.12' jobs: # Job 1: Linting e validazione lint-and-validate: name: Lint and Validate runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip pip install flake8 black pylint yamllint pip install -r requirements.txt pip install -r api/requirements-api.txt - name: Lint Python code run: | # Flake8 flake8 api/ mcp-server/ --max-line-length=120 --ignore=E501,W503 # Black check black --check api/ mcp-server/ - name: Validate YAML files run: | yamllint mkdocs.yml yamllint docker-compose.yml || true - name: Check MkDocs configuration run: | mkdocs build --strict --clean # Job 2: Build Documentation build-docs: name: Build MkDocs Documentation runs-on: ubuntu-latest needs: lint-and-validate steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # Necessario per git-revision-date plugin - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' - name: Install MkDocs and plugins run: | pip install mkdocs mkdocs-material pip install mkdocs-git-revision-date-localized-plugin pip install mkdocs-minify-plugin pip install mkdocs-awesome-pages-plugin pip install mkdocs-macros-plugin - name: Copy templates to docs run: | mkdir -p docs/sections cp templates/*.md docs/sections/ - name: Build documentation run: | mkdocs build --strict --clean --verbose - name: Upload documentation artifact uses: actions/upload-artifact@v4 with: name: documentation-site path: site/ retention-days: 7 - name: Check documentation size run: | SIZE=$(du -sh site/ | cut -f1) echo "Documentation size: $SIZE" # Verifica che non sia troppo grande SIZE_MB=$(du -sm site/ | cut -f1) if [ $SIZE_MB -gt 500 ]; then echo "WARNING: Documentation size exceeds 500MB" fi # Job 3: Build Docker image build-docker: name: Build Docker Image runs-on: ubuntu-latest needs: build-docs permissions: contents: read packages: write steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to Container Registry uses: docker/login-action@v3 with: registry: ${{ env.DOCKER_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=sha,prefix=,format=short type=raw,value=latest,enable={{is_default_branch}} - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64,linux/arm64 # Job 4: Security scanning security-scan: name: Security Scanning runs-on: ubuntu-latest needs: build-docker if: github.event_name != 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy results to GitHub Security uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: 'trivy-results.sarif' # Job 5: Deploy to production deploy-production: name: Deploy to Production runs-on: ubuntu-latest needs: [build-docker, security-scan] if: github.ref == 'refs/heads/main' && github.event_name == 'push' environment: name: production url: https://docs.datacenter.local steps: - name: Checkout code uses: actions/checkout@v4 - name: Configure SSH env: SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_KEY }} SSH_HOST: ${{ secrets.DEPLOY_HOST }} run: | mkdir -p ~/.ssh echo "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts - name: Deploy to server env: SSH_HOST: ${{ secrets.DEPLOY_HOST }} SSH_USER: ${{ secrets.DEPLOY_USER }} run: | ssh -i ~/.ssh/deploy_key $SSH_USER@$SSH_HOST << 'EOF' cd /opt/datacenter-docs # Pull latest code git pull origin main # Pull latest Docker image docker-compose pull docs-server # Restart services docker-compose up -d docs-server # Check health sleep 10 curl -f http://localhost:8000/health || exit 1 echo "Deployment successful!" EOF - name: Verify deployment run: | # Verifica che il servizio risponda curl -f https://docs.datacenter.local/health || exit 1 echo "Production deployment verified!" - name: Notify deployment if: always() uses: 8398a7/action-slack@v3 with: status: ${{ job.status }} text: | Deployment to production ${{ job.status }} Commit: ${{ github.sha }} Author: ${{ github.actor }} webhook_url: ${{ secrets.SLACK_WEBHOOK }} # Job 6: Run tests test: name: Run Tests runs-on: ubuntu-latest needs: lint-and-validate steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' - name: Install dependencies run: | pip install -r requirements.txt pip install -r api/requirements-api.txt pip install pytest pytest-cov pytest-asyncio httpx - name: Run unit tests run: | pytest tests/ -v --cov=api --cov=mcp-server --cov-report=xml --cov-report=html - name: Upload coverage reports uses: codecov/codecov-action@v3 with: files: ./coverage.xml flags: unittests name: codecov-umbrella # Job 7: Generate documentation report generate-report: name: Generate Documentation Report runs-on: ubuntu-latest needs: build-docs if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - name: Download documentation artifact uses: actions/download-artifact@v4 with: name: documentation-site path: site/ - name: Generate statistics run: | echo "# Documentation Statistics" > report.md echo "" >> report.md echo "- **Total files**: $(find site/ -type f | wc -l)" >> report.md echo "- **Total size**: $(du -sh site/ | cut -f1)" >> report.md echo "- **HTML pages**: $(find site/ -name '*.html' | wc -l)" >> report.md echo "- **Build date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> report.md echo "- **Commit**: ${{ github.sha }}" >> report.md cat report.md - name: Create GitHub Release if: startsWith(github.ref, 'refs/tags/v') uses: softprops/action-gh-release@v1 with: files: report.md body_path: report.md # Job 8: Update documentation metadata update-metadata: name: Update Documentation Metadata runs-on: ubuntu-latest needs: deploy-production if: github.ref == 'refs/heads/main' steps: - name: Checkout code uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} - name: Update last_updated.json run: | cat > docs/last_updated.json << EOF { "last_build": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", "commit": "${{ github.sha }}", "branch": "${{ github.ref_name }}", "actor": "${{ github.actor }}", "workflow_run": "${{ github.run_number }}" } EOF - name: Commit metadata run: | git config user.name "GitHub Actions Bot" git config user.email "actions@github.com" git add docs/last_updated.json git diff --quiet && git diff --staged --quiet || git commit -m "chore: update documentation metadata [skip ci]" git push