Skip to content

fix: add debug statements #299

fix: add debug statements

fix: add debug statements #299

Workflow file for this run

name: Build and Deploy
on:
push:
branches: [main]
workflow_dispatch: # Allows manual triggering
jobs:
build-and-deploy:
# Prod
# runs-on: ubuntu-latest
# Self hosted
runs-on: self-hosted
environment: production # This tells GitHub to use the production environment secrets
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
# fetch-depth: 0 is recommended for a more reliable diff across multiple commits in a push
fetch-depth: 0
# lfs: true # Commented out - using B2 instead
# - name: Verify LFS and database file
# run: |
# echo "🔎 Verifying Git LFS and SQLite DB presence..."
# git lfs version || true
# echo "LFS-tracked files:"
# git lfs ls-files || true
# echo "Listing DB directories:"
# ls -l ./db || true
# ls -l ./frontend/db || true
# echo "File type of DB files (if present):"
# for f in ./db/*.db ./frontend/db/*.db; do
# if [ -f "$f" ]; then file "$f" || true; fi
# done
# - name: Pull LFS objects explicitly (workaround)
# run: |
# echo "⬇️ Pulling LFS objects explicitly..."
# git lfs pull --include="db/**,frontend/db/**" || git lfs pull || true
- name: Download database files from Backblaze B2
run: |
echo "⬇️ Downloading database files from Backblaze B2..."
# B2 credentials from GitHub secrets
B2_ACCOUNT_ID="${{ secrets.B2_ACCOUNT_ID }}"
B2_APPLICATION_KEY="${{ secrets.B2_APPLICATION_KEY }}"
# Verify credentials are set
if [ -z "$B2_ACCOUNT_ID" ] || [ -z "$B2_APPLICATION_KEY" ]; then
echo "❌ B2 credentials are missing. Please check GitHub secrets."
exit 1
fi
# Authorize and get token
echo "🔐 Authorizing with B2..."
AUTH_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -u "${B2_ACCOUNT_ID}:${B2_APPLICATION_KEY}" "https://api.backblazeb2.com/b2api/v2/b2_authorize_account")
HTTP_CODE=$(echo "$AUTH_RESPONSE" | grep "HTTP_CODE:" | cut -d':' -f2)
AUTH_JSON=$(echo "$AUTH_RESPONSE" | sed '/HTTP_CODE:/d')
if [ "$HTTP_CODE" != "200" ]; then
echo "❌ B2 authorization failed with HTTP code: $HTTP_CODE"
echo "Response: $AUTH_JSON"
exit 1
fi
# Parse JSON response (using grep as fallback if jq not available)
if command -v jq &> /dev/null; then
AUTH_TOKEN=$(echo "$AUTH_JSON" | jq -r '.authorizationToken // empty')
DOWNLOAD_URL=$(echo "$AUTH_JSON" | jq -r '.downloadUrl // empty')
else
AUTH_TOKEN=$(echo "$AUTH_JSON" | grep -o '"authorizationToken":"[^"]*' | cut -d'"' -f4)
DOWNLOAD_URL=$(echo "$AUTH_JSON" | grep -o '"downloadUrl":"[^"]*' | cut -d'"' -f4)
fi
if [ -z "$AUTH_TOKEN" ] || [ -z "$DOWNLOAD_URL" ]; then
echo "❌ Failed to parse B2 authorization response"
echo "Response: $AUTH_JSON"
exit 1
fi
echo "✅ Authorized successfully"
echo "📥 Download URL: $DOWNLOAD_URL"
# Create database directories
mkdir -p frontend/db/banner
mkdir -p frontend/db/man_pages
mkdir -p frontend/db/png_icons
mkdir -p frontend/db/svg_icons
# Download database files
echo "📦 Downloading database files..."
# Banner database
echo " - Downloading banner-db.db..."
curl -s -H "Authorization: ${AUTH_TOKEN}" "${DOWNLOAD_URL}/file/hexmos/freedevtools/content/db/banner-db.db" -o frontend/db/banner/banner-db.db || echo "⚠️ Failed to download banner-db.db"
# Man pages database
echo " - Downloading man-pages-db.db..."
curl -s -H "Authorization: ${AUTH_TOKEN}" "${DOWNLOAD_URL}/file/hexmos/freedevtools/content/db/man_pages/man-pages-db.db" -o frontend/db/man_pages/man-pages-db.db || echo "⚠️ Failed to download man-pages-db.db"
# Verify downloads
echo "✅ Download complete. Verifying files..."
ls -lh frontend/db/banner/ || true
ls -lh frontend/db/man_pages/ || true
- name: Detect changed sections
id: detect-changes
run: |
echo "🔍 Detecting changes based on custom build rules..."
# Use a more robust diff command that covers all commits in a push
all_changed=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} || git diff --name-only HEAD~1 HEAD)
if [ -z "$all_changed" ]; then
echo "❌ No changes detected. Skipping build and deploy."
echo "should_deploy=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "📁 All changed files:"
echo "$all_changed" | sed 's/^/ - /'
changed_dirs=""
requires_full_rebuild=false
# Helper function to add a directory to the list if it's not already there
add_dir() {
if [[ ! "$changed_dirs" =~ (^|[[:space:]])$1($|[[:space:]]) ]]; then
changed_dirs="$changed_dirs $1"
fi
}
for file in $all_changed; do
case "$file" in
frontend/src/pages/t/*)
add_dir "t"
;;
frontend/src/pages/markdown_pages/tldr/*|frontend/src/pages/tldr/*)
add_dir "markdown_pages"
add_dir "tldr"
;;
frontend/src/pages/html_pages/cheatsheets/*|frontend/src/pages/c/*)
add_dir "html_pages"
add_dir "c"
;;
frontend/src/pages/svg_icons/*)
add_dir "svg_icons"
;;
frontend/src/pages/png_icons/*)
# If png_icons changes, we build both png_icons and svg_icons
add_dir "png_icons"
add_dir "svg_icons"
;;
frontend/src/pages/emojies/*)
add_dir "emojies"
;;
frontend/src/pages/cars/*)
add_dir "cars"
;;
frontend/src/pages/mcp/*)
add_dir "mcp"
;;
frontend/src/pages/man-pages/*)
add_dir "man-pages"
;;
frontend/db/man_pages/*|scripts/man-pages/*)
# Database or script changes for man-pages
add_dir "man-pages"
;;
frontend/public/mcp/*)
add_dir "mcp"
;;
frontend/src/pages/index.astro)
# Index page changes only need to rebuild the index page
add_dir "index_only"
;;
frontend/public/*)
# Public assets are served directly, just sync without rebuild
add_dir "public_assets_only"
;;
frontend/src/*)
# Other src changes (components, layouts, styles, etc.) need full rebuild
requires_full_rebuild=true
;;
*)
# You can add a default case here if needed, for example, to build everything
# echo "Change detected in unhandled path: $file"
;;
esac
done
# Clean up leading/trailing whitespace
changed_dirs=$(echo "$changed_dirs" | xargs)
# Determine final build strategy
if [ "$requires_full_rebuild" = true ]; then
echo "🔧 Components/layouts/styles changed - requires full rebuild"
echo "📦 Build strategy: full_rebuild"
echo "should_deploy=true" >> $GITHUB_OUTPUT
echo "changed_sections=full_rebuild" >> $GITHUB_OUTPUT
elif [ -n "$changed_dirs" ]; then
echo "📦 Changed sections to build: $changed_dirs"
echo "should_deploy=true" >> $GITHUB_OUTPUT
echo "changed_sections=$changed_dirs" >> $GITHUB_OUTPUT
else
echo "❌ No changes matched the build rules. Skipping deployment."
echo "should_deploy=false" >> $GITHUB_OUTPUT
fi
# - name: Setup Bun
# if: steps.detect-changes.outputs.should_deploy == 'true'
# uses: oven-sh/setup-bun@v1
# with:
# bun-version: "1.1.34"
# - name: Cache Bun dependencies
# if: steps.detect-changes.outputs.should_deploy == 'true'
# uses: actions/cache@v4
# with:
# path: ~/.bun
# key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
# restore-keys: |
# ${{ runner.os }}-bun-
- name: Setup Node.js
if: steps.detect-changes.outputs.should_deploy == 'true'
uses: actions/setup-node@v4
with:
node-version: '22.17.0'
- name: Exclude unchanged sections from build
if: steps.detect-changes.outputs.should_deploy == 'true'
run: |
echo "🔧 Excluding unchanged sections from build..."
cd frontend/src/pages
changed_sections="${{ steps.detect-changes.outputs.changed_sections }}"
echo "Building strategy: $changed_sections"
# Only exclude sections if we're doing selective page builds
if [[ "$changed_sections" != "full_rebuild" && "$changed_sections" != "public_assets_only" && "$changed_sections" != "index_only" ]]; then
echo "🎯 Selective build mode"
for dir in */; do
if [ -d "$dir" ]; then
dir_name=${dir%/}
if [[ "$changed_sections" =~ (^|[[:space:]])$dir_name($|[[:space:]]) ]] || [[ "$dir_name" == _* ]]; then
echo "✅ Including: $dir_name"
else
echo "❌ Excluding: $dir_name -> _$dir_name"
mv "$dir" "_$dir"
fi
fi
done
elif [[ "$changed_sections" == "full_rebuild" ]]; then
echo "🔧 Full rebuild mode - building all sections"
for dir in */; do
if [ -d "$dir" ]; then
dir_name=${dir%/}
echo "✅ Including: $dir_name"
fi
done
elif [[ "$changed_sections" == "index_only" ]]; then
echo "🏠 Index page only mode - excluding all other pages"
for dir in */; do
if [ -d "$dir" ]; then
dir_name=${dir%/}
if [[ "$dir_name" == _* ]]; then
echo "✅ Keeping excluded: $dir_name"
else
echo "❌ Excluding: $dir_name -> _$dir_name"
mv "$dir" "_$dir"
fi
fi
done
else
echo "🔧 Public assets only mode - no page exclusions needed"
fi
# - name: Install dependencies
# if: steps.detect-changes.outputs.should_deploy == 'true' && steps.detect-changes.outputs.changed_sections != 'public_assets_only'
# run: |
# echo "📦 Installing dependencies with Bun..."
# cd frontend
# bun install
- name: Install dependencies
if: steps.detect-changes.outputs.should_deploy == 'true' && steps.detect-changes.outputs.changed_sections != 'public_assets_only'
run: |
echo "📦 Installing dependencies..."
cd frontend
npm install
- name: Clean dist directory
if: steps.detect-changes.outputs.should_deploy == 'true' && steps.detect-changes.outputs.changed_sections != 'public_assets_only'
run: |
echo "🧹 Cleaning dist directory before build..."
cd frontend
rm -rf dist
mkdir -p dist
# - name: Build project
# if: steps.detect-changes.outputs.should_deploy == 'true' && steps.detect-changes.outputs.changed_sections != 'public_assets_only'
# run: |
# echo "🔨 Building project with Bun..."
# cd frontend
# bun run astro build
- name: Build project
if: steps.detect-changes.outputs.should_deploy == 'true' && steps.detect-changes.outputs.changed_sections != 'public_assets_only'
run: |
echo "🔨 Building project..."
cd frontend
npx astro build
env:
NODE_OPTIONS: '--max-old-space-size=16384'
UV_THREADPOOL_SIZE: '16'
PUBLIC_GA_ID: ${{ secrets.PUBLIC_GA_ID }}
MEILISEARCH_API_KEY: ${{ secrets.MEILISEARCH_API_KEY }}
- name: Restore original folder structure
if: always() && steps.detect-changes.outputs.should_deploy == 'true'
run: |
echo "🔄 Restoring original folder structure..."
cd frontend/src/pages
for dir in _*/; do
if [ -d "$dir" ]; then
original_name=${dir#_}
original_name=${original_name%/}
echo "Restoring _$original_name to $original_name"
mv "$dir" "$original_name/"
fi
done
- name: Setup SSH
if: steps.detect-changes.outputs.should_deploy == 'true'
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add server to known hosts
if: steps.detect-changes.outputs.should_deploy == 'true'
run: |
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Deploy to server
if: steps.detect-changes.outputs.should_deploy == 'true'
run: |
echo "🚀 Deploying to server..."
echo "Deployed sections: ${{ steps.detect-changes.outputs.changed_sections }}"
changed_sections="${{ steps.detect-changes.outputs.changed_sections }}"
if [[ "$changed_sections" == "public_assets_only" ]]; then
echo "📁 Only public assets changed - syncing files only"
rsync -rvz --delete --no-perms --no-owner --no-group --no-times --progress ./frontend/public/ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:/tools/
elif [[ "$changed_sections" == "full_rebuild" ]]; then
echo "📦 Full deployment - deleting old files on server"
rsync -rvz --delete --no-perms --no-owner --no-group --no-times --progress ./frontend/dist/ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:/tools/
else
echo "📦 Partial deployment - keeping existing files on server"
rsync -rvz --no-perms --no-owner --no-group --no-times --progress ./frontend/dist/ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:/tools/
fi
- name: Purge entire Cloudflare cache
if: steps.detect-changes.outputs.should_deploy == 'true'
run: |
echo "Purging entire Cloudflare cache..."
RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.CLOUDFLARE_ZONE_ID }}/purge_cache" \
-H "Authorization: Bearer ${{ secrets.CLOUDFLARE_CACHE_PURGE_API_KEY }}" \
-H "Content-Type: application/json" \
--data '{"purge_everything":true}')
echo "Response:"
echo "$RESPONSE"
- name: Generate search index data and deploy to server
run: |
echo "🔍 Generating search index data..."
cd search-index
make sync-search-index
echo "✅ Search index generation completed"
- name: Skip deployment message
if: steps.detect-changes.outputs.should_deploy == 'false'
run: |
echo "⏭️ Skipping deployment - no changes matched the build rules."