diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml new file mode 100644 index 0000000..bdc038a --- /dev/null +++ b/.github/workflows/build-pr.yml @@ -0,0 +1,13 @@ +name: Validate PR Build + +on: + pull_request: + branches: ["main"] + +permissions: + contents: read + +jobs: + validate: + uses: ./.github/workflows/build.yml + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..3d5059f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,59 @@ +name: Build mdBook + +on: + workflow_call: + outputs: + artifact-path: + description: "Path to the built book artifact" + value: ${{ jobs.build.outputs.artifact-path }} + +permissions: + contents: read + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + outputs: + artifact-path: ./better-code/book + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Cache Rust toolchain and cargo registry + - name: Cache Rust + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + ~/.cargo/.crates.toml + ~/.cargo/.crates2.json + key: ${{ runner.os }}-cargo-${{ hashFiles('versions.txt') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Install mdBook and plugins (Linux) + if: runner.os != 'Windows' + run: | + chmod +x scripts/install-tools.sh + ./scripts/install-tools.sh + + - name: Install mdBook and plugins (Windows) + if: runner.os == 'Windows' + run: .\scripts\install-tools.ps1 + + - name: Build with mdBook + run: mdbook build ./better-code + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: mdbook-build-${{ matrix.os }} + path: ./better-code/book + retention-days: 1 + diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d977ea9..3536ff5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,58 +1,52 @@ -name: Deploy mdBook to GitHub Pages +name: Deploy to GitHub Pages +# Tool versions are managed in versions.txt at the repository root. +# To update mdbook or plugin versions, edit versions.txt and the CI will automatically use them. 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 jobs: - # Build job build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install mdBook - run: cargo install mdbook - - - name: Setup Pages - id: pages - uses: actions/configure-pages@v5 - - - name: Build with mdBook - run: | - cd better-code - mdbook build - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: ./better-code/book + uses: ./.github/workflows/build.yml + permissions: + contents: read - # Deployment job deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build + permissions: + pages: write + id-token: write steps: + - name: Download build artifact + uses: actions/download-artifact@v4 + with: + name: mdbook-build-ubuntu-latest + path: ./book + + - name: Setup Pages + id: pages + uses: actions/configure-pages@v5 + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v4 + with: + path: ./book + - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..7e21b6d --- /dev/null +++ b/.tool-versions @@ -0,0 +1,7 @@ +# Tool versions for asdf version manager +# See: https://asdf-vm.com/ +# +# Note: For mdbook and plugin versions, see versions.txt +# Use the install scripts to install the correct versions: ./scripts/install-tools.sh +rust stable + diff --git a/README.md b/README.md index 27e4924..3c17924 100644 --- a/README.md +++ b/README.md @@ -1,97 +1,117 @@ -# Welcome to Better Code +# Better Code -This is the development home of the STLab Better Code course. +Development repository for the STLab Better Code course. -## Working with the Book +**Read the book:** https://stlab.github.io/better-code/ -We're migrating from using Jekyll to using -[mdBook](https://github.com/rust-lang/mdBook). The mdBook version is located in -the `./better-code` directory and includes automated CI/CD deployment to GitHub Pages. +## Quick Start -## Installing and updating mdBook +### 1. Install Prerequisites -Install [Rust and -Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html): +Install [Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html). -Linux and macOS: -``` -curl https://sh.rustup.rs -sSf | sh -``` - -On Windows, you can download the installer from -[here](https://win.rustup.rs/). - -Once you have Rust and Cargo installed, you can install or upgrade mdBook by running: +### 2. Install mdBook and Plugins +**Linux/macOS:** +```bash +./scripts/install-tools.sh ``` -cargo install mdbook + +**Windows (PowerShell):** +```powershell +.\scripts\install-tools.ps1 ``` -## Building the book +These scripts install mdBook and all required plugins using versions from `versions.txt`. -To build the book, run: +### 3. Build and Serve -``` +```bash mdbook serve ./better-code ``` -Open the browser to http://localhost:3000 to see the book. You can use the -Simple Browser in VSCode/Cursor to view the book while editing. +Open http://localhost:3000 in your browser. -## Automated Deployment +## Contributing -The mdBook is automatically built and deployed to GitHub Pages using GitHub Actions. -When you push changes to the main branch: +### Editing Content -1. GitHub Actions will build the book using mdBook -2. The built book will be deployed to GitHub Pages -3. The book will be available at https://stlab.github.io/better-code/ +1. Edit markdown files in `better-code/src/` +2. Add new chapters by creating `.md` files and updating `better-code/src/SUMMARY.md` +3. Changes automatically rebuild when you push to the main branch -No manual deployment steps are required! +### Content Conventions -### Conventions and Guidelines +* Use Markdown formatting; avoid unnecessary HTML +* Wrap lines at 80 columns for diff-friendly change tracking +* Start each chapter with a level-2 heading (`## Chapter Name`) +* Use level-3+ headings within chapters +* Keep file names and heading titles stable for linkability -* Avoid unnecessary HTML tags; use Markdown formatting to the degree possible. -* Wrap lines at 80 columns to support diff-friendly change tracking. -* Chapters are represented as individual Markdown files in the chapters/ - subdirectory. -* Each chapter begins with a 2nd-level heading, e.g. `## Chapter Name`. All - other headings in a chapter are 3rd-level and below. -* Each file's name starts with a 4-digit number that determines its order in the - overall document. Initial numbering is spaced by 100s. -* Maintain stable file names and heading titles for linkability until another - solution is in place. +## Deployment -### Older draft +### CI/CD Pipeline -Please see the [latest published draft](https://stlab.github.io/better-code/) -for information about the motivation for this project. +**Pull Requests:** +- Validates build on Ubuntu and Windows +- No deployment; PR check shows build status -### Infrastructure +**Main Branch:** +- Builds book using mdBook with versions from `versions.txt` +- Deploys to GitHub Pages +- Available at https://stlab.github.io/better-code/ -The book is being migrated from [Jekyll](https://jekyllrb.com) to [mdBook](https://github.com/rust-lang/mdBook). -The new mdBook version is automatically built and deployed to [GitHub Pages](https://pages.github.com) using GitHub Actions. +### Managing Dependencies -The legacy Jekyll files remain in the root directory for reference during the transition. +All tool versions are centrally managed in `versions.txt`. To update: -### Running a local server +1. Edit version number in `versions.txt` +2. Run the appropriate install script locally +3. Test with `mdbook serve ./better-code` +4. Commit - CI automatically uses the new version -If you are able to install the necessary parts for jekyll, +## Project Structure ``` -bundle exec jekyll serve -l +better-code/ # mdBook source and configuration +├── src/ # Markdown chapter files +├── book.toml # mdBook configuration +└── book/ # Generated HTML (gitignored) + +scripts/ # Installation scripts +├── install-tools.sh # Linux/macOS +└── install-tools.ps1 # Windows + +versions.txt # Single source of truth for tool versions +archive/ # Legacy Jekyll site (for reference only) ``` -will start a server for the site at http://localhost:4000. +## Advanced Usage -Creating a complete installation of jekyll and all the parts needed for github -pages development can be fraught. If you install -[docker-compose](https://docs.docker.com/compose/), you can start the server -by invoking +### Building Without Serving + +```bash +mdbook build ./better-code ``` -docker-compose up + +Output will be in `./better-code/book/`. + + +## Legacy Content + +The `archive/` directory contains the legacy Jekyll site for reference during migration. +You can safely ignore it unless working on migration tasks. + +To run the Jekyll version (not recommended for regular development): + +```bash +bundle exec jekyll serve -l # Starts server at http://localhost:4000 ``` -in the root directory of your working copy. +Or with Docker: + +```bash +docker-compose up +``` diff --git a/better-code/README.md b/better-code/README.md deleted file mode 100644 index 1125d25..0000000 --- a/better-code/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Better Code - mdBook - -This directory contains the mdBook version of the Better Code course. - -## Local Development - -### Prerequisites - -Install [Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html): - -**Linux and macOS:** -```bash -curl https://sh.rustup.rs -sSf | sh -``` - -**Windows:** -Download the installer from [here](https://win.rustup.rs/). - -### Install mdBook - -```bash -cargo install mdbook -``` - -### Building and Serving the Book - -To build and serve the book locally: - -```bash -mdbook serve -``` - -This will start a local server at `http://localhost:3000`. - -To just build the book without serving: - -```bash -mdbook build -``` - -The built book will be in the `book/` directory. - -## Deployment - -The book is automatically built and deployed to GitHub Pages using GitHub Actions when changes are pushed to the main branch. - -## Adding Content - -1. Edit existing chapters in the `src/` directory -2. Add new chapters by creating new `.md` files in `src/` -3. Update `src/SUMMARY.md` to include new chapters in the table of contents -4. The book will automatically rebuild when you push changes to GitHub diff --git a/better-code/book.toml b/better-code/book.toml index 5bd576a..f626b05 100644 --- a/better-code/book.toml +++ b/better-code/book.toml @@ -1,7 +1,6 @@ [book] authors = ["Sean Parent"] language = "en" -multilingual = false src = "src" title = "Better Code" description = "A principled and rigorous approach to software development" diff --git a/scripts/install-tools.ps1 b/scripts/install-tools.ps1 new file mode 100644 index 0000000..59fb2b6 --- /dev/null +++ b/scripts/install-tools.ps1 @@ -0,0 +1,66 @@ +# Installs mdBook and plugins using versions from versions.txt. +# +# Reads tool versions from the repository root's versions.txt file and +# installs them via cargo. This ensures consistency between local development +# and CI environments. +# +# Usage: .\install-tools.ps1 +# +# Preconditions: +# - Rust and Cargo are installed and in PATH +# - versions.txt exists in the repository root + +$ErrorActionPreference = "Stop" + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$VersionsFile = Join-Path (Split-Path -Parent $ScriptDir) "versions.txt" + +Write-Host "Reading versions from $VersionsFile..." -ForegroundColor Cyan + +# Install mdBook +$mdbookLine = Get-Content $VersionsFile | Where-Object { $_ -match '^mdbook=' } +if ($mdbookLine) { + $mdbookVersion = $mdbookLine.Split('=')[1] + Write-Host "`nInstalling mdBook $mdbookVersion..." -ForegroundColor Cyan + cargo install mdbook --version $mdbookVersion + if ($LASTEXITCODE -ne 0) { + exit 1 + } +} else { + Write-Host "Error: Could not find mdbook version in versions.txt" -ForegroundColor Red + exit 1 +} + +# Install mdBook plugins +Write-Host "`nInstalling mdBook plugins..." -ForegroundColor Cyan + +# Process all lines starting with "mdbook-" (plugins) +Get-Content $VersionsFile | Where-Object { $_ -match '^mdbook-' } | ForEach-Object { + $pluginName, $pluginVersion = $_ -split '=', 2 + + # mdbook-katex requires special handling on Windows + # See: https://github.com/lzanini/mdbook-katex#windows-users + if ($pluginName -eq "mdbook-katex") { + Write-Host "Installing $pluginName $pluginVersion with duktape backend (Windows)..." -ForegroundColor Cyan + Write-Host " Note: Using duktape backend. Some features like matrices may not work." -ForegroundColor Yellow + Write-Host " For full functionality, download pre-built binary from:" -ForegroundColor Yellow + Write-Host " https://github.com/lzanini/mdbook-katex/releases" -ForegroundColor Yellow + cargo install $pluginName --version $pluginVersion --no-default-features --features duktape + if ($LASTEXITCODE -ne 0) { + Write-Host "Failed to install $pluginName. Continuing without it..." -ForegroundColor Yellow + return + } + } else { + Write-Host "Installing $pluginName $pluginVersion..." -ForegroundColor Cyan + cargo install $pluginName --version $pluginVersion + if ($LASTEXITCODE -ne 0) { + exit 1 + } + } +} + +Write-Host "`n✓ Installation complete!" -ForegroundColor Green +Write-Host "`nInstalled versions:" -ForegroundColor Cyan +mdbook --version +cargo install --list | Select-String "mdbook" + diff --git a/scripts/install-tools.sh b/scripts/install-tools.sh new file mode 100644 index 0000000..d05c5b6 --- /dev/null +++ b/scripts/install-tools.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# Installs mdBook and plugins using versions from versions.txt. +# +# Reads tool versions from the repository root's versions.txt file and +# installs them via cargo. This ensures consistency between local development +# and CI environments. +# +# Usage: ./install-tools.sh +# +# Preconditions: +# - Rust and Cargo are installed and in PATH +# - versions.txt exists in the repository root + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +VERSIONS_FILE="${SCRIPT_DIR}/../versions.txt" + +echo "Reading versions from ${VERSIONS_FILE}..." + +# Install mdBook +MDBOOK_VERSION=$(grep "^mdbook=" "$VERSIONS_FILE" | cut -d'=' -f2) +if [ -n "$MDBOOK_VERSION" ]; then + echo "Installing mdBook ${MDBOOK_VERSION}..." + cargo install mdbook --version "${MDBOOK_VERSION}" +else + echo "Error: Could not find mdbook version in versions.txt" + exit 1 +fi + +# Install mdBook plugins +echo "" +echo "Installing mdBook plugins..." + +# Process all lines starting with "mdbook-" (plugins) +while IFS='=' read -r plugin version; do + echo "Installing ${plugin} ${version}..." + cargo install "${plugin}" --version "${version}" +done < <(grep "^mdbook-" "$VERSIONS_FILE") + +echo "" +echo "✓ Installation complete!" +echo "" +echo "Installed versions:" +mdbook --version +# List installed plugins +cargo install --list | grep mdbook + diff --git a/versions.txt b/versions.txt new file mode 100644 index 0000000..121f5c2 --- /dev/null +++ b/versions.txt @@ -0,0 +1,36 @@ +# Tool versions - single source of truth for all build dependencies +# Used by CI and local development scripts +# +# Format: tool=version (one per line, no quotes needed) +# Lines starting with # are comments +# +# Usage: +# Linux/macOS: ./scripts/install-tools.sh +# Windows: .\scripts\install-tools.ps1 +# +# To update a version: +# 1. Change the version number here +# 2. Run the install script from the repository root +# 3. Test locally: mdbook serve ./better-code +# 4. Commit the change - CI will automatically use the new version +# +# Note: After adding mdbook plugins, you may also need to configure +# them in better-code/book.toml. See mdbook documentation for details. + +# Core mdBook +mdbook=0.5.2 + +# mdBook plugins +# Note: On Windows, mdbook-katex installs with the duktape backend (limited functionality). +# For full features, download pre-built binaries: https://github.com/lzanini/mdbook-katex/releases +mdbook-katex=0.10.0-alpha + +# Uncomment to add more plugins: +# mdbook-mermaid=x.y.z + +# Add other tool dependencies here as the project grows +# Examples: +# swift=5.9 +# python=3.11 +# node=20.10.0 +