Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ci): run mdbook on pull requests #226

Merged
98 changes: 98 additions & 0 deletions .github/actions/mdbook/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: mdbook

description: |
Run the mdbook build, optionally outputting a pages artifact

inputs:
publish-pages-artifact:
type: boolean
required: false
default: false
description: |
Whether to publish a pages artifact

publish-domain:
type: string
required: false
default: "component-model.bytecodealliance.org"
description: |
Path to which to store the artifac

mdbook-version:
type: string
required: false
default: "0.4.21"
description: |
Version of mdbook to use (ex. '0.4.21')

mdbook-alerts-version:
type: string
required: false
default: "0.6.7"
description: |
Version of mdbook-alerts to use (ex. '0.6.7')

mdbook-linkcheck-version:
type: string
required: false
default: "0.7.7"
description: |
Version of mdbook-linkcheck to use (ex. '0.7.7')

runs:
using: composite
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- uses: extractions/setup-just@v2

- uses: taiki-e/cache-cargo-install-action@4d586f211d9b0bca9e7b59e57e2a0febf36c0929 # v2.1.1
with:
tool: "mdbook@${{ inputs.mdbook-version }}"

- uses: taiki-e/cache-cargo-install-action@4d586f211d9b0bca9e7b59e57e2a0febf36c0929 # v2.1.1
with:
tool: "mdbook-alerts@${{ inputs.mdbook-alerts-version }}"

- uses: taiki-e/cache-cargo-install-action@4d586f211d9b0bca9e7b59e57e2a0febf36c0929 # v2.1.1
with:
tool: "mdbook-linkcheck@${{ inputs.mdbook-linkcheck-version }}"

- name: Setup Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: '3.13'

- name: Build with mdBook
shell: bash
id: book-build
env:
PUBLISH_DOMAIN: ${{ inputs.publish-domain }}
run: |
just build-book
echo "output-path=$(just print-book-dir)" >> $GITHUB_OUTPUT

- name: Generate sitemap
shell: bash
run: |
just build-sitemap

- name: Ensure publish-domain was provided
if: ${{ inputs.publish-pages-artifact }}
shell: bash
run: |
if [ -z "${{ inputs.publish-domain }}" ]; then
echo "[error] publish-domain input is required when publishing";
exit 1;
fi

- name: Setup Pages
if: ${{ inputs.publish-pages-artifact }}
id: pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0

- name: Upload artifact
if: ${{ inputs.publish-pages-artifact }}
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
with:
path: ${{ steps.book-build.outputs.output-path }}
64 changes: 64 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Deploy mdBook site to Pages

on:
push:
branches:
- main

workflow_dispatch:
inputs:
ref:
required: false
type: string
default: main
description: |
The git ref to deploy (ex. 'main', 'branch', '<commit sha>')

publish-domain:
required: false
type: string
default: "component-model.bytecodealliance.org"
description: |
The domain to which to publish (ex. 'component-model.bytecodealliance.org')

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: false

env:
MDBOOK_VERSION: 0.4.21
MDBOOK_ALERTS_VERSION: 0.6.7
MDBOOK_LINKCHECK_VERSION: 0.7.7
ARTIFACT_PATH: ./component-model/book/html

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.ref || 'main' }}

- name: build mdbook
uses: ./.github/actions/mdbook
with:
publish-pages-artifact: true
publish-domain: ${{ inputs.publish-domain || 'component-model.bytecodealliance.org' }}

deploy:
if: ${{ github.repository_owner == 'bytecodealliance' }}
runs-on: ubuntu-latest
needs:
- build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
88 changes: 6 additions & 82 deletions .github/workflows/mdbook.yml
Original file line number Diff line number Diff line change
@@ -1,91 +1,15 @@
# Sample workflow for building and deploying a mdBook site to GitHub Pages
#
# To get started with mdBook see: https://rust-lang.github.io/mdBook/index.html
#
name: Deploy mdBook site to Pages
name: mdbook

on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write

# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false

env:
MDBOOK_VERSION: 0.4.21
MDBOOK_ALERTS_VERSION: 0.6.7
MDBOOK_LINKCHECK_VERSION: 0.7.7
PUBLISH_DOMAIN: component-model.bytecodealliance.org
ARTIFACT_PATH: ./component-model/book/html
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install mdBook
run: |
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh
rustup update
cargo install --version ${{ env.MDBOOK_VERSION }} mdbook
cargo install --version ${{ env.MDBOOK_ALERTS_VERSION }} mdbook-alerts
cargo install --version ${{ env.MDBOOK_LINKCHECK_VERSION }} mdbook-linkcheck
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Build with mdBook
run: mdbook build component-model

- name: Setup Python
uses: actions/setup-python@v5
- name: build mdbook
uses: ./.github/actions/mdbook
with:
python-version: '3.13'

# Ensure the build generated properly
- name: Ensure build outputs are present
shell: bash
run: |
if [[ ! -f "${{ env.ARTIFACT_PATH }}/index.html" ]]; then
echo "[error] index.html @ [${{ env.ARTIFACT_PATH }}] is missing. Build or path misconfigured";
exit 1;
fi

- name: Generate sitemap
shell: bash
run: |
cd ${{ env.ARTIFACT_PATH }}
python3 ../../../scripts/generate_sitemap.py --domain "component-model.bytecodealliance.org" --higher-priority "design" --output-path sitemap.xml
cd ../../../

- name: Setup Pages
id: pages
uses: actions/configure-pages@v3

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ${{ env.ARTIFACT_PATH }}

# Deployment job
deploy:
if: ${{ github.repository_owner == 'bytecodealliance' }}
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
publish-pages-artifact: true
35 changes: 35 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
just := env_var_or_default("JUST", "just")
just_dir := env_var_or_default("JUST_DIR", justfile_directory())

python := env_var_or_default("PYTHON", "python3")
cargo := env_var_or_default("CARGO", "cargo")
mdbook := env_var_or_default("MDBOOK", "mdbook")

publish_domain := env_var_or_default("PUBLISH_DOMAIN", "component-model.bytecodealliance.org")

scripts_dir := env_var_or_default("SCRIPTS_DIR", "scripts")

sitemap_output_path := env_var_or_default("SITEMAP_OUTPUT_PATH", absolute_path("./component-model/book/html/sitemap.xml"))
book_output_dir := env_var_or_default("BOOK_OUTPUT_DIR", "./component-model/book/html")

@_default:
{{just}} --list

# Print the directory the book is/would be output to
[group('meta')]
@print-book-dir:
echo -n {{book_output_dir}}

# Build the book
[group('build')]
@build-book:
{{mdbook}} build component-model

# Build the sitemap
[group('build')]
@build-sitemap:
{{python}} {{scripts_dir}}/generate_sitemap.py --domain "{{publish_domain}}" --higher-priority "design" --output-path {{sitemap_output_path}}
if [ ! -f "{{book_output_dir}}/index.html" ]; then \
echo "[error] index.html @ [{{book_output_dir}}] is missing. Build or path misconfigured"; \
exit 1; \
fi
28 changes: 21 additions & 7 deletions scripts/generate_sitemap.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import os
from urllib.parse import urljoin
from datetime import datetime
from pathlib import Path

import argparse

def parse_summary():
def parse_summary(summary_file_path):
"""Parse URLs from the SUMMARY.md file."""
with open("../../src/SUMMARY.md", "r") as file:
with open(summary_file_path, "r") as file:
for line in file:
if "](" in line:
url = line.split("](")[1].split(")")[0]
Expand All @@ -23,10 +25,10 @@ def determine_priority(url_path, higher_priority_section):
else:
return "0.5" # All other pages

def generate_sitemap(domain, output_path, higher_priority_section):
def generate_sitemap(domain, output_path, summary_file_path, higher_priority_section):
"""Generate a sitemap XML file from SUMMARY.md structure."""
domain = "https://" + domain
urls = parse_summary() # Add base URL to the list of URLs
urls = parse_summary(summary_file_path) # Add base URL to the list of URLs
urls = [""] + list(urls)

sitemap = '<?xml version="1.0" encoding="UTF-8"?>\n'
Expand All @@ -48,11 +50,23 @@ def generate_sitemap(domain, output_path, higher_priority_section):
with open(output_path, "w") as file:
file.write(sitemap)

DEFAULT_SUMMARY_MD_PATH = (Path(__file__).parent / "../component-model/src/SUMMARY.md").resolve()
DEFAULT_SITEMAP_XML_PATH = (Path(__file__).parent / "../component-model/book/html/sitemap.sml").resolve()

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate a sitemap for mdBook")
parser.add_argument("-d", "--domain", required=True, help="Domain for the mdBook site (e.g., component-model.bytecodealliance.org)")
parser.add_argument("-o", "--output-path", default="sitemap.xml", help="Output path for the sitemap file")
parser.add_argument("-d", "--domain", required=True, help="Domain for the mdBook site (e.g., 'component-model.bytecodealliance.org')")
parser.add_argument("-o", "--output-path", default=DEFAULT_SITEMAP_XML_PATH, help="Output path for the sitemap file")
parser.add_argument("-s", "--summary-md-path", default=DEFAULT_SUMMARY_MD_PATH, help="Path to SUMMARY.md")
parser.add_argument("-p", "--higher-priority", help="Subsection path (e.g., 'design') to assign a higher priority of 0.8")
args = parser.parse_args()

generate_sitemap(args.domain, args.output_path, args.higher_priority)
summary_file_path = Path(args.summary_md_path).resolve()
if not summary_file_path.exists():
raise FileNotFoundError(f"failed to find summary file [{summary_file_path}]")

output_path = Path(args.output_path).resolve()
if not output_path.parent.exists():
raise FileNotFoundError(f"failed to find output dir [{output_path.parent}]")

generate_sitemap(args.domain, output_path, summary_file_path, args.higher_priority)