Skip to content

Commit 94e9007

Browse files
authored
Generate spec index pages in mkdocs (#4514)
When clicking on the "specs" links in the readme, it would show a 404. The simplest solution to this is to generate a basic index page for each spec. The "tests" link will still 404 but that's alright, no great way to fix that. Fixes #4472.
1 parent cbaa006 commit 94e9007

File tree

6 files changed

+126
-15
lines changed

6 files changed

+126
-15
lines changed

.github/workflows/docs.yml

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11

22
name: Publish docs
3+
4+
defaults:
5+
run:
6+
shell: zsh -e {0}
7+
38
on:
49
push:
510
branches:
611
- master
12+
713
permissions:
814
contents: write
15+
916
jobs:
1017
deploy:
1118
runs-on: ubuntu-latest
1219
steps:
13-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
20+
- name: Checkout repository
21+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
22+
23+
- name: Setup python
24+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
25+
with:
26+
python-version: '3.13'
27+
cache: 'pip'
28+
29+
- name: Install dependencies to venv
30+
run: make pyspec
31+
1432
- name: Build docs
1533
run: make _copy_docs
16-
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
17-
with:
18-
python-version: 3.x
19-
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
20-
with:
21-
key: ${{ github.ref }}
22-
path: .cache
23-
- run: pip install mkdocs==1.4.2 mkdocs-material==9.1.5 mdx-truly-sane-lists==1.3 mkdocs-awesome-pages-plugin==2.8.0
24-
- run: mkdocs gh-deploy --force
34+
35+
- name: Deploy
36+
run: venv/bin/mkdocs gh-deploy --force

Makefile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ PYTHON_VENV = $(VENV)/bin/python3
5555
PIP_VENV = $(VENV)/bin/pip3
5656
CODESPELL_VENV = $(VENV)/bin/codespell
5757
MDFORMAT_VENV = $(VENV)/bin/mdformat
58+
MKDOCS_VENV = $(VENV)/bin/mkdocs
5859

5960
# Make a virtual environment.
6061
$(VENV):
@@ -164,9 +165,9 @@ _copy_docs:
164165
@cp $(CURDIR)/README.md $(DOCS_DIR)/README.md
165166

166167
# Start a local documentation server.
167-
serve_docs: _copy_docs
168-
@mkdocs build
169-
@mkdocs serve
168+
serve_docs: pyspec _copy_docs
169+
@$(MKDOCS_VENV) build
170+
@$(MKDOCS_VENV) serve
170171

171172
###############################################################################
172173
# Checks

mkdocs.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ markdown_extensions:
3232
plugins:
3333
- search
3434
- awesome-pages
35+
- gen-files:
36+
scripts:
37+
- scripts/gen_spec_indices.py
3538
extra_css:
3639
- stylesheets/extra.css
3740
extra:

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ generator = [
5959
docs = [
6060
"mdx-truly-sane-lists==1.3",
6161
"mkdocs-awesome-pages-plugin==2.10.1",
62+
"mkdocs-gen-files==0.5.0",
6263
"mkdocs-material==9.6.17",
6364
"mkdocs==1.6.1",
6465
]

scripts/gen_spec_indices.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Generate index.md files for specification directories to enable directory browsing in mkdocs.
4+
5+
This script is used by the mkdocs-gen-files plugin to create virtual index pages
6+
that list all files in each specification directory, providing a GitHub-like
7+
directory browsing experience on the mkdocs documentation site.
8+
"""
9+
10+
import os
11+
import mkdocs_gen_files
12+
13+
14+
def format_filename_as_title(filename: str) -> str:
15+
"""Convert a filename to a human-readable title."""
16+
name = filename[-3] if filename.endswith(".md") else filename
17+
18+
replacements = {
19+
"api": "API",
20+
"bls": "BLS",
21+
"das": "DAS",
22+
"p2p": "P2P",
23+
"ssz": "SSZ",
24+
}
25+
26+
name = name.replace("-", " ").replace("_", " ")
27+
28+
words = name.split()
29+
formatted_words = []
30+
for word in words:
31+
lower_word = word.lower()
32+
if lower_word in replacements:
33+
formatted_words.append(replacements[lower_word])
34+
else:
35+
formatted_words.append(word.title())
36+
37+
return " ".join(formatted_words)
38+
39+
40+
def generate_spec_index(dir_path: str, level: int = 1) -> str:
41+
"""Generate index content for a specification directory."""
42+
files = []
43+
subdirs = []
44+
45+
if os.path.exists(dir_path):
46+
for item in sorted(os.listdir(dir_path)):
47+
item_path = os.path.join(dir_path, item)
48+
if os.path.isdir(item_path):
49+
subdirs.append(item)
50+
elif item.endswith(".md") and item != "index.md":
51+
files.append(item)
52+
53+
content = ""
54+
55+
if level == 1:
56+
content = "# Index\n\n"
57+
if files:
58+
content += "## Core\n\n"
59+
60+
for file in files:
61+
name = format_filename_as_title(file)
62+
content += f"- [{name}](./{file})\n"
63+
64+
for subdir in subdirs:
65+
formatted_name = format_filename_as_title(subdir)
66+
heading_level = "#" * (level + 1)
67+
content += f"\n{heading_level} {formatted_name}\n\n"
68+
subdir_path = os.path.join(dir_path, subdir)
69+
subdir_content = generate_spec_index(subdir_path, level + 1)
70+
if subdir_content.strip():
71+
content += subdir_content
72+
else:
73+
content += f"*No files in {subdir}/*\n"
74+
75+
if not files and not subdirs and level == 1:
76+
content += "*No specification files found in this directory.*\n"
77+
78+
return content
79+
80+
81+
print("Generating specification index pages...")
82+
83+
spec_forks = []
84+
if os.path.exists("specs"):
85+
for item in sorted(os.listdir("specs")):
86+
item_path = os.path.join("specs", item)
87+
if os.path.isdir(item_path) and item not in {"_deprecated", "_features"}:
88+
spec_forks.append(item)
89+
90+
for fork in spec_forks:
91+
spec_path = f"specs/{fork}"
92+
print(f" - Generating index for {spec_path}")
93+
with mkdocs_gen_files.open(f"{spec_path}/index.md", "w") as f:
94+
f.write(generate_spec_index(spec_path))

specs/gloas/beacon-chain.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@
7979
This is the beacon chain specification of the enshrined proposer builder
8080
separation feature.
8181

82-
*Note*: This specification is built upon [Fulu](../../fulu/beacon-chain.md) and
83-
is under active development.
82+
*Note*: This specification is built upon [Fulu](../fulu/beacon-chain.md) and is
83+
under active development.
8484

8585
This feature adds new staked consensus participants called *Builders* and new
8686
honest validators duties called *payload timeliness attestations*. The slot is

0 commit comments

Comments
 (0)