GitHub Actions expression for versioned docs base path #177
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
| # Workflow for building and deploying versioned VitePress docs to GitHub Pages | |
| name: Deploy VitePress site to Pages | |
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| concurrency: | |
| group: pages | |
| cancel-in-progress: false | |
| jobs: | |
| # Build current (main) docs | |
| build-current: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install system deps | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: "3.4" | |
| bundler-cache: true | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Generate versions.json | |
| run: | | |
| CURRENT_VERSION=$(grep 'VERSION = "' lib/active_agent/version.rb | sed 's/.*VERSION = "\([^"]*\)".*/\1/') | |
| cat > docs/.vitepress/versions.json << EOF | |
| { | |
| "current": "$CURRENT_VERSION", | |
| "versions": [ | |
| { "version": "$CURRENT_VERSION", "label": "$CURRENT_VERSION (Latest)", "path": "/" }, | |
| { "version": "1.0.0", "label": "1.0.0", "path": "/v1.0.0/" }, | |
| { "version": "0.6.3", "label": "0.6.3", "path": "/v0.6.3/" } | |
| ] | |
| } | |
| EOF | |
| - name: Install dummy app dependencies | |
| working-directory: test/dummy | |
| run: bundle install | |
| - name: Setup database | |
| env: | |
| RAILS_ENV: test | |
| RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }} | |
| working-directory: test/dummy | |
| run: | | |
| bundle exec rails db:create | |
| bundle exec rails db:migrate | |
| - name: Generate doc examples from tests | |
| env: | |
| RAILS_ENV: test | |
| RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }} | |
| ANTHROPIC_API_KEY: ANTHROPIC_API_KEY | |
| OPEN_AI_API_KEY: OPEN_AI_API_KEY | |
| OPEN_ROUTER_API_KEY: OPEN_ROUTER_API_KEY | |
| run: bin/test | |
| - name: Build with VitePress | |
| run: npm run docs:build | |
| - name: Upload current docs artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: docs-current | |
| path: docs/.vitepress/dist | |
| # Build versioned docs using matrix strategy | |
| # Note: Versioned docs are built from static content in tags (no test generation needed) | |
| build-versioned: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| version: ["1.0.0", "0.6.3"] | |
| steps: | |
| - name: Checkout version ${{ matrix.version }} | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: v${{ matrix.version }} | |
| fetch-depth: 0 | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Create versions.json for versioned build | |
| run: | | |
| cat > docs/.vitepress/versions.json << 'EOF' | |
| { | |
| "current": "1.0.0", | |
| "versions": [ | |
| { "version": "1.0.0", "label": "1.0.0 (Latest)", "path": "/" }, | |
| { "version": "0.6.3", "label": "0.6.3", "path": "/v0.6.3/" } | |
| ] | |
| } | |
| EOF | |
| - name: Create versioned config | |
| run: | | |
| cat > docs/.vitepress/config.versioned.mts << 'EOFCONFIG' | |
| import { defineConfig } from 'vitepress' | |
| import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs' | |
| import { | |
| groupIconMdPlugin, | |
| groupIconVitePlugin, | |
| localIconLoader, | |
| } from "vitepress-plugin-group-icons" | |
| // Read the original config dynamically | |
| import originalConfig from './config.mts' | |
| const BASE = '/v${{ matrix.version }}/' | |
| // Helper to prefix links with base path | |
| function prefixLink(link: string): string { | |
| if (!link || link.startsWith('http') || link.startsWith('#')) return link | |
| return BASE.slice(0, -1) + link | |
| } | |
| // Recursively prefix links in nav/sidebar items | |
| function prefixItems(items: any[]): any[] { | |
| if (!items) return items | |
| return items.map(item => ({ | |
| ...item, | |
| link: item.link ? prefixLink(item.link) : undefined, | |
| items: item.items ? prefixItems(item.items) : undefined | |
| })) | |
| } | |
| // Get the original theme config | |
| const origTheme = originalConfig.themeConfig || {} | |
| export default defineConfig({ | |
| base: BASE, | |
| ignoreDeadLinks: true, | |
| markdown: { | |
| config(md) { | |
| md.use(groupIconMdPlugin) | |
| md.use(tabsMarkdownPlugin) | |
| } | |
| }, | |
| vite: { | |
| plugins: [ | |
| groupIconVitePlugin({ | |
| customIcon: { | |
| ruby: "vscode-icons:file-type-ruby", | |
| ".rb": "vscode-icons:file-type-ruby", | |
| ".erb": "vscode-icons:file-type-erb", | |
| ".html.erb": "https://raw.githubusercontent.com/marcoroth/herb/refs/heads/main/docs/.vitepress/assets/herb.svg", | |
| openai: 'logos:openai-icon', | |
| anthropic: 'logos:anthropic-icon', | |
| google: 'logos:google-icon', | |
| ollama: 'simple-icons:ollama', | |
| openrouter: localIconLoader(import.meta.url, './assets/icons/openrouter.svg'), | |
| } | |
| }), | |
| ], | |
| }, | |
| title: "Active Agent", | |
| description: "The AI framework for Rails with less code & more fun.", | |
| head: [ | |
| ['link', { rel: 'icon', href: BASE + 'activeagent.png' }], | |
| ['link', { rel: 'icon', href: BASE + 'favicon-16x16.png', sizes: '16x16' }], | |
| ['link', { rel: 'icon', href: BASE + 'favicon-32x32.png', sizes: '32x32' }], | |
| ['link', { rel: 'apple-touch-icon', href: BASE + 'apple-touch-icon.png' }], | |
| ['meta', { property: 'og:image', content: BASE + 'social.png' }], | |
| ['meta', { property: 'og:title', content: 'Active Agent' }], | |
| ['meta', { property: 'og:description', content: 'The AI framework for Rails with less code & more fun.' }], | |
| ['meta', { property: 'og:url', content: 'https://docs.activeagents.ai' + BASE }], | |
| ['meta', { property: 'og:type', content: 'website' }], | |
| ], | |
| cleanUrls: true, | |
| themeConfig: { | |
| search: { | |
| provider: 'local', | |
| }, | |
| editLink: origTheme.editLink, | |
| nav: prefixItems(origTheme.nav || []), | |
| sidebar: Array.isArray(origTheme.sidebar) | |
| ? prefixItems(origTheme.sidebar) | |
| : origTheme.sidebar, | |
| socialLinks: origTheme.socialLinks || [], | |
| }, | |
| }) | |
| EOFCONFIG | |
| - name: Build VitePress docs for v${{ matrix.version }} | |
| run: npx vitepress build docs --config docs/.vitepress/config.versioned.mts | |
| - name: Upload versioned docs artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: docs-v${{ matrix.version }} | |
| path: docs/.vitepress/dist | |
| # Combine all docs and deploy | |
| deploy: | |
| needs: [build-current, build-versioned] | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| - name: Download all docs artifacts | |
| uses: actions/download-artifact@v6 | |
| with: | |
| path: artifacts | |
| - name: Combine docs into single directory | |
| run: | | |
| mkdir -p dist | |
| # Move current docs to root | |
| cp -r artifacts/docs-current/* dist/ | |
| # Move versioned docs to their subdirectories | |
| for dir in artifacts/docs-v*/; do | |
| version=$(basename "$dir" | sed 's/docs-//') | |
| mkdir -p "dist/$version" | |
| cp -r "$dir"* "dist/$version/" | |
| done | |
| echo "Combined docs structure:" | |
| ls -la dist/ | |
| - name: Setup Pages | |
| uses: actions/configure-pages@v5 | |
| - name: Upload combined artifact | |
| uses: actions/upload-pages-artifact@v4 | |
| with: | |
| path: dist | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v4 |