diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 49a2009..672149c 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -63,6 +63,15 @@ jobs: with: node-version: '20' + - name: Setup caching for build artifacts + uses: actions/cache@v4 + id: cache-npm + with: + path: ~/.npm + key: npm-${{ runner.os }}-${{ hashFiles('${{ env.TEMP_DIR }}/llama-stack/docs/package-lock.json') }} + restore-keys: | + npm-${{ runner.os }}- + - name: Install dependencies and setup versioning run: | echo "📦 Installing dependencies..." @@ -196,13 +205,114 @@ jobs: echo "✅ Versioning artifacts import completed" + - name: Check for content changes (optimization) + id: content-changes + run: | + cd "${{ env.TEMP_DIR }}/llama-stack/docs" + + # Create hash of all documentation content + CONTENT_HASH=$(find docs static -type f \( -name "*.md" -o -name "*.mdx" -o -name "*.yaml" -o -name "*.json" \) -exec md5sum {} \; | sort | md5sum | cut -d' ' -f1) + echo "CONTENT_HASH=$CONTENT_HASH" >> $GITHUB_OUTPUT + echo "📊 Content hash: $CONTENT_HASH" + + # For latest builds, check if content has changed since last deployment + if [ "${{ env.BUILDING_LATEST }}" = "true" ]; then + # Try to get the last deployment hash from the deployed site + LAST_HASH="" + if curl -s "https://llamastack.github.io/content-hash.txt" > /tmp/last_hash.txt 2>/dev/null; then + LAST_HASH=$(cat /tmp/last_hash.txt) + echo "📊 Previous hash: $LAST_HASH" + fi + + if [ "$CONTENT_HASH" = "$LAST_HASH" ] && [ -n "$LAST_HASH" ]; then + echo "✅ Content unchanged since last deployment" + echo "CONTENT_CHANGED=false" >> $GITHUB_OUTPUT + else + echo "🔄 Content has changed since last deployment" + echo "CONTENT_CHANGED=true" >> $GITHUB_OUTPUT + fi + else + # For version builds, always process (new version) + echo "🔄 Building version ${{ env.VERSION_TAG }}" + echo "CONTENT_CHANGED=true" >> $GITHUB_OUTPUT + fi + + - name: Cache stable API docs + uses: actions/cache@v4 + id: cache-api-stable + with: + path: ${{ env.TEMP_DIR }}/llama-stack/docs/docs/api + key: api-stable-${{ env.VERSION_TAG }}-${{ hashFiles('${{ env.TEMP_DIR }}/llama-stack/docs/static/llama-stack-spec.yaml') }} + restore-keys: | + api-stable-${{ env.VERSION_TAG }}- + api-stable- + + - name: Cache experimental API docs + uses: actions/cache@v4 + id: cache-api-experimental + with: + path: ${{ env.TEMP_DIR }}/llama-stack/docs/docs/api-experimental + key: api-experimental-${{ env.VERSION_TAG }}-${{ hashFiles('${{ env.TEMP_DIR }}/llama-stack/docs/static/experimental-llama-stack-spec.yaml') }} + restore-keys: | + api-experimental-${{ env.VERSION_TAG }}- + api-experimental- + + - name: Cache deprecated API docs + uses: actions/cache@v4 + id: cache-api-deprecated + with: + path: ${{ env.TEMP_DIR }}/llama-stack/docs/docs/api-deprecated + key: api-deprecated-${{ env.VERSION_TAG }}-${{ hashFiles('${{ env.TEMP_DIR }}/llama-stack/docs/static/deprecated-llama-stack-spec.yaml') }} + restore-keys: | + api-deprecated-${{ env.VERSION_TAG }}- + api-deprecated- + + - name: Cache Docusaurus build artifacts + uses: actions/cache@v4 + id: cache-docusaurus-build + with: + path: | + ${{ env.TEMP_DIR }}/llama-stack/docs/.docusaurus + ${{ env.TEMP_DIR }}/llama-stack/docs/build + key: docusaurus-build-${{ env.VERSION_TAG }}-${{ hashFiles('${{ env.TEMP_DIR }}/llama-stack/docs/docs/**/*.{md,mdx}', '${{ env.TEMP_DIR }}/llama-stack/docs/static/**/*', '${{ env.TEMP_DIR }}/llama-stack/docs/docusaurus.config.ts', '${{ env.TEMP_DIR }}/llama-stack/docs/package.json') }} + restore-keys: | + docusaurus-build-${{ env.VERSION_TAG }}- + docusaurus-build- + - name: Build documentation + # Skip if content hasn't changed (latest builds only) + if: ${{ steps.content-changes.outputs.CONTENT_CHANGED == 'true' }} run: | cd "${{ env.TEMP_DIR }}/llama-stack/docs" - # Generate API docs first (required for current build) - npm run gen-api-docs all - echo "✅ API docs generated" + # Generate API docs selectively based on cache status + echo "🔄 Generating API docs..." + + # Generate stable API docs if not cached + if [ "${{ steps.cache-api-stable.outputs.cache-hit }}" != 'true' ]; then + echo " 📄 Generating stable API docs (cache miss)..." + npm run gen-api-docs stable + else + echo " ⚡ Using cached stable API docs" + fi + + # Generate experimental API docs if not cached + if [ "${{ steps.cache-api-experimental.outputs.cache-hit }}" != 'true' ]; then + echo " 📄 Generating experimental API docs (cache miss)..." + npm run gen-api-docs experimental + else + echo " ⚡ Using cached experimental API docs" + fi + + # Generate deprecated API docs if not cached + if [ "${{ steps.cache-api-deprecated.outputs.cache-hit }}" != 'true' ]; then + echo " 📄 Generating deprecated API docs (cache miss)..." + npm run gen-api-docs deprecated + else + echo " ⚡ Using cached deprecated API docs" + fi + + echo "✅ API docs generation completed" # Create version if not latest (after content is ready) if [ "${{ env.BUILDING_LATEST }}" != "true" ]; then @@ -227,43 +337,75 @@ jobs: fi - name: Build Docusaurus site + # Skip if content hasn't changed (latest builds only) + if: ${{ steps.content-changes.outputs.CONTENT_CHANGED == 'true' }} run: | - echo "🏗️ Building Docusaurus site..." cd "${{ env.TEMP_DIR }}/llama-stack/docs" - # Generate API docs for current build - npm run gen-api-docs all - - # Patch out duplicate version badges from OpenAPI MDX files - echo "🔧 Patching out duplicate version badges..." - find . -name "llama-stack-specification.info.mdx" -type f -exec sed -i '/$/d' {} \; + # Check if we can skip build due to cache hit + if [ "${{ steps.cache-docusaurus-build.outputs.cache-hit }}" = 'true' ]; then + echo "⚡ Using cached Docusaurus build (cache hit)" - # Also patch versioned files if they exist - if [ -d "versioned_docs" ]; then - find versioned_docs -name "llama-stack-specification.info.mdx" -type f -exec sed -i '/$/d' {} \; + # Verify build output exists and is valid + if [ -f "build/index.html" ] && [ -d "build/assets" ]; then + echo "✅ Cached build is valid, skipping build step" + else + echo "⚠️ Cache hit but build output missing/invalid, rebuilding..." + FORCE_BUILD=true + fi + else + echo "🔄 Building Docusaurus site (cache miss)..." + FORCE_BUILD=true fi - echo "✅ Version badge patching completed" - # Build the site - npm run build + if [ "${FORCE_BUILD:-false}" = 'true' ]; then + # Patch out duplicate version badges from OpenAPI MDX files + echo "🔧 Patching out duplicate version badges..." + find . -name "llama-stack-specification.info.mdx" -type f -exec sed -i '/$/d' {} \; - echo "✅ Docusaurus build completed" + # Also patch versioned files if they exist + if [ -d "versioned_docs" ]; then + find versioned_docs -name "llama-stack-specification.info.mdx" -type f -exec sed -i '/$/d' {} \; + fi + echo "✅ Version badge patching completed" + + # Build the site + npm run build + echo "✅ Docusaurus build completed" + fi - name: Deploy to GitHub Pages run: | - echo "🗂️ Deploying Docusaurus build..." + if [ "${{ steps.content-changes.outputs.CONTENT_CHANGED }}" = 'false' ]; then + echo "⚡ Deploying cached build (no content changes detected)" + else + echo "🗂️ Deploying fresh Docusaurus build..." + fi DOCS_DIR="${{ github.workspace }}/docs" - # Smart deployment: clear everything except .git, .nojekyll, and archived versions - find "$DOCS_DIR" -mindepth 1 -maxdepth 1 ! -name '.git' ! -name '.nojekyll' ! -name 'v[0-9]*' -exec rm -rf {} + + # Handle deployment based on whether content changed + if [ "${{ steps.content-changes.outputs.CONTENT_CHANGED }}" = 'true' ]; then + # Fresh build - deploy new content + # Smart deployment: clear everything except .git, .nojekyll, and archived versions + find "$DOCS_DIR" -mindepth 1 -maxdepth 1 ! -name '.git' ! -name '.nojekyll' ! -name 'v[0-9]*' -exec rm -rf {} + - # Copy Docusaurus build output - cp -r "${{ env.TEMP_DIR }}/llama-stack/docs/build/"* "$DOCS_DIR/" + # Copy Docusaurus build output + cp -r "${{ env.TEMP_DIR }}/llama-stack/docs/build/"* "$DOCS_DIR/" + else + # No content changes - keep existing deployment, just update metadata + echo "📂 Keeping existing deployment (content unchanged)" + fi # Ensure .nojekyll exists touch "$DOCS_DIR/.nojekyll" + # Save content hash for future optimization checks + if [ -n "${{ steps.content-changes.outputs.CONTENT_HASH }}" ]; then + echo "${{ steps.content-changes.outputs.CONTENT_HASH }}" > "$DOCS_DIR/content-hash.txt" + echo "💾 Saved content hash for future builds" + fi + echo "✅ Docusaurus content deployed" - name: Update workspace artifacts