diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml
new file mode 100644
index 0000000..bef8933
--- /dev/null
+++ b/.github/workflows/deploy-pages.yml
@@ -0,0 +1,211 @@
+name: Deploy to GitHub Pages
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+ workflow_dispatch:
+
+# Allow one concurrent deployment
+concurrency:
+ group: pages-${{ github.ref }}
+ cancel-in-progress: true
+
+# Sets permissions of the GITHUB_TOKEN
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+ pull-requests: write
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Full history for git-based features
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 9
+
+ - name: Get pnpm store directory
+ id: pnpm-cache
+ shell: bash
+ run: |
+ echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
+
+ - name: Setup pnpm cache
+ uses: actions/cache@v4
+ with:
+ path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
+ key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ ${{ runner.os }}-pnpm-store-
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Build site
+ run: |
+ # Set base URL for PR previews
+ if [ "${{ github.event_name }}" == "pull_request" ]; then
+ echo "Building PR preview..."
+ export BASE_URL="/docs-ng/pr-${{ github.event.pull_request.number }}/"
+ else
+ echo "Building production site..."
+ export BASE_URL="/docs-ng/"
+ fi
+ pnpm run docs:build
+ env:
+ NODE_ENV: production
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: docs/.vitepress/dist
+
+ deploy-production:
+ needs: build
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
+
+ - name: Comment on related PRs
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const { data: prs } = await github.rest.pulls.list({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ state: 'open',
+ base: 'main'
+ });
+
+ for (const pr of prs) {
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pr.number,
+ body: `โ
Production deployment updated!\n\nView at: ${{ steps.deployment.outputs.page_url }}`
+ });
+ }
+
+ deploy-preview:
+ needs: build
+ if: github.event_name == 'pull_request'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Download artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: github-pages
+ path: ./preview
+
+ - name: Extract artifact
+ run: |
+ cd preview
+ tar -xf artifact.tar
+ rm artifact.tar
+
+ - name: Deploy PR Preview
+ uses: peaceiris/actions-gh-pages@v4
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ./preview
+ destination_dir: pr-${{ github.event.pull_request.number }}
+ keep_files: false
+
+ - name: Comment PR
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const prNumber = context.issue.number;
+ const previewUrl = `https://${{ github.repository_owner }}.github.io/docs-ng/pr-${prNumber}/`;
+
+ // Find existing preview comment
+ const { data: comments } = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: prNumber,
+ });
+
+ const botComment = comments.find(comment =>
+ comment.user.type === 'Bot' &&
+ comment.body.includes('๐ Documentation Preview')
+ );
+
+ const commentBody = `## ๐ Documentation Preview
+
+ Preview deployment is ready! ๐
+
+ **Preview URL:** ${previewUrl}
+
+ The preview will be updated automatically with each new commit.
+
+ ---
+ Built with commit ${context.sha.substring(0, 7)}`;
+
+ if (botComment) {
+ // Update existing comment
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: botComment.id,
+ body: commentBody
+ });
+ } else {
+ // Create new comment
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: prNumber,
+ body: commentBody
+ });
+ }
+
+ cleanup-preview:
+ if: github.event_name == 'pull_request' && github.event.action == 'closed'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout gh-pages branch
+ uses: actions/checkout@v4
+ with:
+ ref: gh-pages
+
+ - name: Remove preview directory
+ run: |
+ rm -rf pr-${{ github.event.pull_request.number }}
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git add .
+ git commit -m "chore: cleanup preview for PR #${{ github.event.pull_request.number }}" || echo "No changes to commit"
+ git push
+
+ - name: Comment cleanup
+ uses: actions/github-script@v7
+ with:
+ script: |
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ body: '๐งน Preview deployment cleaned up.'
+ });
\ No newline at end of file
diff --git a/README.md b/README.md
index eaa9e21..b376447 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,21 @@ See `scripts/tests/README.md` for more details.
See `scripts/README.md` for documentation aggregation details.
+## GitHub Pages Deployment
+
+The documentation site is automatically deployed to GitHub Pages:
+
+- **Production**: Automatically deployed when changes are merged to `main`
+ - URL: https://gardenlinux.github.io/docs-ng/
+- **PR Previews**: Each pull request gets its own preview deployment
+ - URL: https://gardenlinux.github.io/docs-ng/pr-{PR_NUMBER}/
+ - Automatically updated with each commit
+ - Cleaned up when PR is closed
+
+The workflow is configured in `.github/workflows/deploy-pages.yml`.
+
+For detailed information about the deployment system, see the [GitHub Pages Deployment Guide](docs/contributing/github-pages-deployment.md).
+
## Commands
Run `make help` for all available commands.
diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
index 73fd56c..87c8916 100644
--- a/docs/.vitepress/config.mts
+++ b/docs/.vitepress/config.mts
@@ -1,9 +1,130 @@
import { defineConfig } from "vitepress";
+// Get base URL from environment variable (for GitHub Pages deployment)
+const base = process.env.BASE_URL || '/';
+
+// Shared sidebar for all documentation categories
+const documentationSidebar = [
+ {
+ text: "Tutorials",
+ collapsed: true,
+ items: [
+ { text: "Overview", link: "/tutorials/" },
+ { text: "First Boot - AWS", link: "/tutorials/first-boot-aws" },
+ { text: "First Boot - Azure", link: "/tutorials/first-boot-azure" },
+ { text: "First Boot - Bare Metal", link: "/tutorials/first-boot-bare-metal" },
+ { text: "First Boot - GCP", link: "/tutorials/first-boot-gcp" },
+ { text: "First Boot - KVM", link: "/tutorials/first-boot-kvm" },
+ { text: "First Boot - Lima", link: "/tutorials/first-boot-lima" },
+ { text: "First Boot - OCI", link: "/tutorials/first-boot-oci" },
+ { text: "First Boot - OpenStack", link: "/tutorials/first-boot-openstack" },
+ ],
+ },
+ {
+ text: "How-to Guides",
+ collapsed: true,
+ items: [
+ { text: "Overview", link: "/how-to/" },
+ { text: "Choosing Flavors", link: "/how-to/choosing-flavors" },
+ { text: "Getting Images", link: "/how-to/getting-images" },
+ { text: "Initial Configuration", link: "/how-to/initial-configuration" },
+ { text: "System Management", link: "/how-to/system-management" },
+ {
+ text: "Customization",
+ collapsed: true,
+ items: [
+ { text: "Overview", link: "/how-to/customization/" },
+ { text: "Building Features", link: "/how-to/customization/building-features" },
+ { text: "Building Flavors", link: "/how-to/customization/building-flavors" },
+ { text: "Testing Builds", link: "/how-to/customization/testing-builds" },
+ ],
+ },
+ {
+ text: "Platform-Specific",
+ collapsed: true,
+ items: [
+ { text: "Overview", link: "/how-to/platform-specific/" },
+ { text: "AWS", link: "/how-to/platform-specific/aws" },
+ { text: "Azure", link: "/how-to/platform-specific/azure" },
+ { text: "Bare Metal", link: "/how-to/platform-specific/bare-metal" },
+ { text: "Gardener", link: "/how-to/platform-specific/gardener" },
+ { text: "GCP", link: "/how-to/platform-specific/gcp" },
+ { text: "KVM", link: "/how-to/platform-specific/kvm" },
+ { text: "Lima", link: "/how-to/platform-specific/lima" },
+ { text: "OCI/Containers", link: "/how-to/platform-specific/oci" },
+ { text: "OpenStack", link: "/how-to/platform-specific/openstack" },
+ { text: "VMware", link: "/how-to/platform-specific/vmware" },
+ ],
+ },
+ {
+ text: "Security",
+ collapsed: true,
+ items: [
+ { text: "Overview", link: "/how-to/security/" },
+ { text: "Secure Boot", link: "/how-to/security/secure-boot" },
+ { text: "SSH Hardening", link: "/how-to/security/ssh-hardening" },
+ { text: "Time Configuration", link: "/how-to/security/time-configuration" },
+ ],
+ },
+ ],
+ },
+ {
+ text: "Explanation",
+ collapsed: true,
+ items: [
+ { text: "Overview", link: "/explanation/" },
+ { text: "Architecture", link: "/explanation/architecture" },
+ { text: "Design Decisions", link: "/explanation/design-decisions" },
+ { text: "Flavors and Features", link: "/explanation/flavors-and-features" },
+ { text: "Image Types", link: "/explanation/image-types" },
+ { text: "Release Cadence", link: "/explanation/release-cadence" },
+ { text: "Security Posture", link: "/explanation/security-posture" },
+ { text: "Use Cases", link: "/explanation/use-cases" },
+ ],
+ },
+ {
+ text: "Reference",
+ collapsed: true,
+ items: [
+ { text: "Overview", link: "/reference/" },
+ { text: "Feature Glossary", link: "/reference/feature-glossary" },
+ { text: "Flavor Matrix", link: "/reference/flavor-matrix" },
+ { text: "Image Formats", link: "/reference/image-formats" },
+ { text: "Kernels & Modules", link: "/reference/kernels-and-modules" },
+ { text: "Platform Compatibility", link: "/reference/platform-compatibility" },
+ {
+ text: "API",
+ collapsed: true,
+ items: [
+ { text: "Overview", link: "/reference/api/" },
+ { text: "CLI", link: "/reference/api/cli" },
+ { text: "Python Library", link: "/reference/api/python-lib" },
+ ],
+ },
+ {
+ text: "Releases",
+ collapsed: true,
+ items: [
+ { text: "Overview", link: "/reference/releases/" },
+ { text: "Maintained Releases", link: "/reference/releases/maintained-releases" },
+ { text: "Release Notes", link: "/reference/releases/release-notes" },
+ ],
+ },
+ ],
+ },
+];
+
// https://vitepress.dev/reference/site-config
export default defineConfig({
+ base,
title: "Garden Linux",
// description: "Operating system built for cloud native workloads.",
+ ignoreDeadLinks: [
+ // Ignore dead links in legacy documentation
+ /\/how-to\/troubleshooting\//,
+ /localhost/,
+ /\/projects\/gardenlinux\/02_operators\/deployment/,
+ ],
head: [
[
"link",
@@ -33,39 +154,43 @@ export default defineConfig({
dark: ".vitepress/theme/assets/gardenlinux-logo.svg",
},
nav: [
- { text: "Home", link: "/" },
- { text: "Quick Start", link: "/users/quickstart" },
+ { text: "Start Here", link: "/" },
{
- text: "Docs",
+ text: "Documentation",
items: [
{
- text: "User Docs",
- items: [
- { text: "Quickstart", link: "/users/quickstart" },
- { text: "Installation Guide", link: "/users/installation" },
- { text: "Build an Image", link: "/users/build-image" },
- ],
+ text: "Tutorials",
+ link: "/tutorials/",
},
{
- text: "Technical Documentation",
- items: [
- {
- text: "Garden Linux",
- link: "/projects/gardenlinux/introduction/index",
- },
- { text: "Builder", link: "/projects/builder/getting_started" },
- {
- text: "Python Library",
- link: "/projects/python-gardenlinux-lib/index",
- },
- ],
+ text: "How-to Guides",
+ link: "/how-to/",
},
{
- text: "Contributing",
- link: "/contributing/",
+ text: "Explanation",
+ link: "/explanation/",
+ },
+ {
+ text: "Reference",
+ link: "/reference/",
+ },
+ ],
+ },
+ {
+ text: "Legacy Docs",
+ items: [
+ {
+ text: "Garden Linux",
+ link: "/projects/gardenlinux/introduction/index",
+ },
+ { text: "Builder", link: "/projects/builder/getting_started" },
+ {
+ text: "Python Library",
+ link: "/projects/python-gardenlinux-lib/index",
},
],
},
+ { text: "Contributing", link: "/contributing/" },
],
// footer: {
@@ -74,40 +199,21 @@ export default defineConfig({
// },
sidebar: {
- // Default sidebar for root pages
- "/": [
- {
- text: "Getting Started",
- items: [{ text: "Quick Start", link: "/users/quickstart" }],
- },
- {
- text: "Usage Docs",
- items: [
- { text: "Installation Guide", link: "/users/installation" },
- { text: "Build an Image", link: "/users/build-image" },
- ],
- },
- {
- text: "Technical Documentation",
- items: [
- {
- text: "Garden Linux",
- link: "/projects/gardenlinux/introduction/index",
- },
- { text: "Builder", link: "/projects/builder/getting_started" },
- {
- text: "Python Library",
- link: "/projects/python-gardenlinux-lib/index",
- },
- ],
- },
+ // Shared sidebar for all documentation categories
+ "/tutorials/": documentationSidebar,
+ "/how-to/": documentationSidebar,
+ "/explanation/": documentationSidebar,
+ "/reference/": documentationSidebar,
+
+ // Contributing section
+ "/contributing/": [
{
text: "Contributing",
- collapsed: true,
items: [
+ { text: "Overview", link: "/contributing/" },
{
- text: "Development Environment",
- link: "/contributing/dev-environment",
+ text: "Documentation Guide",
+ link: "/contributing/documentation-guide",
},
{ text: "Building an Image", link: "/contributing/building-image" },
{ text: "Testing an Image", link: "/contributing/testing-image" },
@@ -117,15 +223,11 @@ export default defineConfig({
text: "Dependency Policy",
link: "/contributing/dependency-policy",
},
- {
- text: "Documentation Guide",
- link: "/contributing/documentation-guide",
- },
],
},
],
- // Garden Linux project docs
+ // Legacy documentation (temporary, for backward compatibility)
"/projects/gardenlinux/": [
{
text: "Introduction",
diff --git a/docs/.vitepress/config.mts.backup b/docs/.vitepress/config.mts.backup
deleted file mode 100644
index b03c61d..0000000
--- a/docs/.vitepress/config.mts.backup
+++ /dev/null
@@ -1,337 +0,0 @@
-import { defineConfig } from 'vitepress'
-import { fileURLToPath, URL } from 'node:url'
-
-// https://vitepress.dev/reference/site-config
-export default defineConfig({
- title: "Gardenlinux Documentation",
- description: "All your documentation need - in one place",
- base: process.env.VITE_PUBLIC_BASE_PATH || '',
- srcDir: 'docs',
- cleanUrls: true,
- head: [
- ['link', { rel: 'icon', type: 'image/png', href: '/favicon-96x96.png', sizes: '96x96' }],
- ['link', { rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' }],
- ['link', { rel: 'shortcut icon', href: '/favicon.ico' }],
- ['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' }],
- ['link', { rel: 'manifest', href: '/site.webmanifest' }],
- ['meta', {name: 'theme-color', content: '#009f76'}],
- ['meta', {property: 'og:type', content: 'website'}],
- ['meta', {property: 'og:site_name', content: 'Garden Linux'}],
- [
- 'meta',
- {
- property: 'og:image',
- content: 'https://raw.githubusercontent.com/gardenlinux/gardenlinux/main/logo/gardenlinux-logo-black-text.svg'
- }
- ],
- ['meta', {property: 'og:url', content: 'https://gardenlinux.io/'}],
- ],
- themeConfig: {
- // https://vitepress.dev/reference/default-theme-config
- logo: {
- light: '/gardenlinux-logo.svg',
- dark: '/gardenlinux-logo.svg',
- },
- nav: [
- { text: 'Home', link: '/' },
- { text: 'Quick Start', link: '/users/quickstart' },
- {
- text: 'Docs',
- items: [
- {
- text: 'User Docs',
- items: [
- { text: 'Quickstart', link: '/users/quickstart' },
- { text: 'Installation Guide', link: '/users/installation' },
- { text: 'Build an Image', link: '/users/build-image' }
- ]
- },
- {
- text: 'Technical Documentation',
- items: [
- { text: 'Gardenlinux', link: '/projects/gardenlinux/' },
- { text: 'Builder', link: '/projects/builder/features' },
- { text: 'Python Gardenlinux Lib', link: '/projects/python-gardenlinux-lib/' },
- ]
- },
- {
- text: 'Contributing', link: '/contributing/',
- }
- ]
- },
- ],
- socialLinks: [
- {
- icon: {
- svg: ''
- },
- link: 'https://x.com/GardenLinux'
- },
- {
- icon: {
- svg: '