Add workflow for generating C++ docs with Doxygen on GitHub Pages #6
Workflow file for this run
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
| name: Build and Deploy C++ Documentation | |
| on: | |
| # workflow only triggers when C++ file, the doxygen config, or css are changed | |
| pull_request: | |
| branches: | |
| - master | |
| paths: | |
| - '**/*.cpp' | |
| - '**/*.h' | |
| - 'doc/fulldoc.conf.in' | |
| - 'doc/htmldoc/static/css/doxygen-awesome.css' | |
| push: | |
| paths: | |
| - '.github/workflows/docs.yml' | |
| - '**/*.cpp' | |
| - '**/*.h' | |
| - 'doc/fulldoc.conf.in' | |
| - 'doc/htmldoc/static/css/doxygen-awesome.css' | |
| env: | |
| DOXYGEN_VERSION: 1.9.8 | |
| jobs: | |
| determine-versions: | |
| if: github.event_name == 'push' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| steps: | |
| - name: Compute versions matrix (master + latest two releases) | |
| id: set-matrix | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| try { | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| core.startGroup('Compute versions matrix debug'); | |
| core.info(`Repository: ${owner}/${repo}`); | |
| const versions = [{ version: 'master', branch: 'master' }]; | |
| core.info( 'Fetching tags (per_page=20) ...'); | |
| const tagResp = await github.rest.repos.listTags({ owner, repo, per_page: 20 }); | |
| const allTagNames = tagResp.data.map(x => x.name); | |
| core.info(`Total tags returned: ${tagResp.data.length}`); | |
| core.info('All tag names: ' + JSON.stringify(allTagNames)); | |
| const mmPattern = /^v(\d+)\.(\d+)$/; | |
| core.info(`Filter regex: ${mmPattern}`); | |
| const mmTags = allTagNames.filter(name => mmPattern.test(name)); | |
| core.info('Filtered major.minor tags: ' + JSON.stringify(mmTags)); | |
| const semverSort = (a, b) => { | |
| const [, amaj, amin] = a.match(/^v(\d+)\.(\d+)$/); | |
| const [, bmaj, bmin] = b.match(/^v(\d+)\.(\d+)$/); | |
| const ai = parseInt(amaj, 10); | |
| const aj = parseInt(amin, 10); | |
| const bi = parseInt(bmaj, 10); | |
| const bj = parseInt(bmin, 10); | |
| if (ai !== bi) return bi - ai; // major desc | |
| return bj - aj; // minor desc | |
| }; | |
| const sorted = [...mmTags].sort(semverSort); | |
| core.info('Sorted matching tags (desc): ' + JSON.stringify(sorted)); | |
| const picked = sorted.slice(0, 2); | |
| core.info('Picked latest two: ' + JSON.stringify(picked)); | |
| if (picked.length === 0) { | |
| core.warning('No tags matched the pattern vX.Y. Is your repo using tags like vX.Y.Z?'); | |
| } | |
| for (const name of picked) { | |
| versions.push({ version: name, branch: name }); | |
| } | |
| const matrix = { include: versions }; | |
| core.setOutput('matrix', JSON.stringify(matrix)); | |
| core.info( 'Final matrix: ' + JSON.stringify(matrix, null, 2)); | |
| core.endGroup(); | |
| } catch (err) { | |
| core.error( 'Error while computing versions matrix: ' + (err && err.stack ? err.stack : err)); | |
| throw err; | |
| } | |
| # Separate job for push events that builds all versions | |
| build-docs-push: | |
| if: github.event_name == 'push' | |
| needs: determine-versions | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: ${{ fromJson(needs.determine-versions.outputs.matrix) }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ matrix.branch }} | |
| - name: Get master config files | |
| if: matrix.version != 'master' | |
| run: | | |
| git fetch $GITHUB_SERVER_URL/$GITHUB_REPOSITORY master --depth=1 | |
| # get the version of files from master to ensure consistent output of docs on all versions | |
| git show FETCH_HEAD:doc/fulldoc.conf.in > doc/fulldoc.conf.in.master | |
| git show FETCH_HEAD:doc/htmldoc/static/css/doxygen-awesome.css > doc/htmldoc/static/css/doxygen-awesome.css.master | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y doxygen graphviz cmake build-essential | |
| - name: Configure with CMake | |
| run: | | |
| mkdir -p build-${{ matrix.version }} | |
| cd build-${{ matrix.version }} | |
| if [ "${{ matrix.version }}" != "master" ]; then | |
| # Use master config files for non-master versions before CMake | |
| cp ../doc/fulldoc.conf.in.master ../doc/fulldoc.conf.in | |
| cp ../doc/htmldoc/static/css/doxygen-awesome.css.master ../doc/htmldoc/static/css/doxygen-awesome.css | |
| fi | |
| cmake -Dwith-devdoc=ON -Dwith-python=OFF .. | |
| - name: Generate Doxygen documentation | |
| run: | | |
| cd build-${{ matrix.version }} | |
| doxygen doc/fulldoc.conf | |
| - name: Upload docs artifact ${{ matrix.version }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docs-${{ matrix.version }} | |
| path: build-${{ matrix.version }}/doc/doxygen/html/ | |
| prepare-pages: | |
| needs: build-docs-push | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download all docs artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| pattern: docs-* | |
| # Combine all versions' artifacts into 1 because GitHub pages requires a single deployment | |
| - name: Prepare combined site directory | |
| run: | | |
| set -euo pipefail | |
| mkdir -p _site | |
| shopt -s nullglob | |
| for d in artifacts/docs-*; do | |
| version=${d#artifacts/docs-} | |
| mkdir -p "_site/${version}" | |
| cp -r "${d}"/* "_site/${version}/" | |
| done | |
| # Dynamic index listing built versions | |
| cat > _site/index.html << 'HTML_HEAD' | |
| <!doctype html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>NEST Simulator C++ Doxygen</title> | |
| <style> | |
| body { font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif; margin: 40px; } | |
| a { display:inline-block; margin: 8px 12px; padding: 10px 14px; background:#ff6633; color:#fff; border-radius:6px; text-decoration:none; } | |
| a:hover { background:#072f42; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>NEST Simulator C++ Doxygen</h1> | |
| <p>Select a version:</p> | |
| <div> | |
| HTML_HEAD | |
| for d in $(ls -1 _site | sort -Vr); do | |
| if [ -d "_site/$d" ]; then | |
| echo " <a href=\"$d/\">$d</a>" >> _site/index.html | |
| fi | |
| done | |
| cat >> _site/index.html << 'HTML_TAIL' | |
| </div> | |
| </body> | |
| </html> | |
| HTML_TAIL | |
| - name: Upload Pages artifact (combined) | |
| uses: actions/upload-pages-artifact@v3 | |
| with: | |
| path: _site | |
| deploy: | |
| needs: prepare-pages | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pages: write | |
| id-token: write | |
| environment: | |
| name: github-pages | |
| # url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| - name: Configure Pages | |
| id: pages | |
| uses: actions/configure-pages@v5 | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v4 | |
| # build the documentation for pull requests | |
| build-docs-pull: | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Need full history to compare with base branch | |
| - name: Check which config files changed | |
| id: check-changes | |
| run: | | |
| git fetch origin ${{ github.base_ref }} --depth=1 | |
| # Check if Doxyfile or CSS changed in this PR | |
| DOXYFILE_CHANGED=false | |
| CSS_CHANGED=false | |
| if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q "^doc/fulldoc.conf.in$"; then | |
| DOXYFILE_CHANGED=true | |
| echo "Doxyfile changed in this PR" | |
| fi | |
| if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q "^doc/htmldoc/static/css/doxygen-awesome.css$"; then | |
| CSS_CHANGED=true | |
| echo "CSS file changed in this PR" | |
| fi | |
| echo "doxyfile_changed=$DOXYFILE_CHANGED" >> $GITHUB_OUTPUT | |
| echo "css_changed=$CSS_CHANGED" >> $GITHUB_OUTPUT | |
| - name: Get master config files (if not changed in PR) | |
| if: steps.check-changes.outputs.doxyfile_changed != 'true' || steps.check-changes.outputs.css_changed != 'true' | |
| run: | | |
| git fetch $GITHUB_SERVER_URL/$GITHUB_REPOSITORY master --depth=1 | |
| # Get master config files only if they weren't changed in the PR | |
| # This ensures consistent output when config files are unchanged | |
| if [ "${{ steps.check-changes.outputs.doxyfile_changed }}" != "true" ]; then | |
| git show FETCH_HEAD:doc/fulldoc.conf.in > $RUNNER_TEMP/fulldoc.conf.in.master | |
| echo "Using master Doxyfile (not changed in PR)" | |
| fi | |
| if [ "${{ steps.check-changes.outputs.css_changed }}" != "true" ]; then | |
| git show FETCH_HEAD:doc/htmldoc/static/css/doxygen-awesome.css > $RUNNER_TEMP/doxygen-awesome.css.master | |
| echo "Using master CSS (not changed in PR)" | |
| fi | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y doxygen graphviz cmake build-essential | |
| - name: Configure with CMake | |
| run: | | |
| mkdir -p build-${{ github.run_id }} | |
| cd build-${{ github.run_id }} | |
| # Use master config files only if they weren't changed in the PR | |
| # If they changed, use the PR version to preview the changes | |
| if [ "${{ steps.check-changes.outputs.doxyfile_changed }}" != "true" ]; then | |
| cp $RUNNER_TEMP/fulldoc.conf.in.master ../doc/fulldoc.conf.in | |
| echo "Copied master Doxyfile" | |
| else | |
| echo "Using PR version of Doxyfile for preview" | |
| fi | |
| if [ "${{ steps.check-changes.outputs.css_changed }}" != "true" ]; then | |
| cp $RUNNER_TEMP/doxygen-awesome.css.master ../doc/htmldoc/static/css/doxygen-awesome.css | |
| echo "Copied master CSS" | |
| else | |
| echo "Using PR version of CSS for preview" | |
| fi | |
| cmake -Dwith-devdoc=ON -Dwith-python=OFF .. | |
| - name: Generate Doxygen documentation | |
| run: | | |
| cd build-${{ github.run_id }} | |
| doxygen doc/fulldoc.conf | |
| - name: Upload docs artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docs-${{ github.run_id }} | |
| path: build-${{ github.run_id }}/doc/doxygen/html/ |