diff --git a/.github/actions/mdbook/action.yml b/.github/actions/mdbook/action.yml new file mode 100644 index 0000000..f3861dd --- /dev/null +++ b/.github/actions/mdbook/action.yml @@ -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 }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..e6af4e8 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -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', '') + + 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 diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml index 200dcce..1ce1e8b 100644 --- a/.github/workflows/mdbook.yml +++ b/.github/workflows/mdbook.yml @@ -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 diff --git a/justfile b/justfile new file mode 100644 index 0000000..baa84b1 --- /dev/null +++ b/justfile @@ -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 diff --git a/scripts/generate_sitemap.py b/scripts/generate_sitemap.py index b729de5..b490e61 100644 --- a/scripts/generate_sitemap.py +++ b/scripts/generate_sitemap.py @@ -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] @@ -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 = '\n' @@ -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)