Skip to content

Commit c6dca66

Browse files
authored
CXX-3081 Keep API doc index pages up-to-date with each release (#1180)
* Fix links to MongoDB C++ Driver doc pages * Add etc/patch-apidocs-index-pages.py * Run etc/patch-apidocs-index-pages.py during API doc deployment * Clarify expected contents of build/docs/api before API doc deployment * Update etc/requirements.txt with beautifulsoup4
1 parent 750c02d commit c6dca66

File tree

11 files changed

+190
-24
lines changed

11 files changed

+190
-24
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# MongoDB C++ Driver
22
[![codecov](https://codecov.io/gh/mongodb/mongo-cxx-driver/branch/master/graph/badge.svg)](https://codecov.io/gh/mongodb/mongo-cxx-driver)
33
[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](https://mongocxx.org/api/mongocxx-v3/)
4-
[![Documentation](https://img.shields.io/badge/docs-mongocxx-green.svg)](https://www.mongodb.com/docs/languages/cpp/drivers/current/)
4+
[![Documentation](https://img.shields.io/badge/docs-mongocxx-green.svg)](https://www.mongodb.com/docs/languages/cpp/cpp-driver/current/)
55
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/mongodb/mongo-cxx-driver/blob/master/LICENSE)
66

77
Welcome to the MongoDB C++ Driver!

etc/apidocmenu.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ Compatibility of each C++ driver version with each MongoDB server is documented
6767

6868
## Resources
6969

70-
* [MongoDB C++ Driver Quickstart](https://www.mongodb.com/docs/languages/cpp/drivers/current/tutorial/)
71-
* [MongoDB C++ Driver Manual](https://www.mongodb.com/docs/languages/cpp/drivers/current/)
70+
* [MongoDB C++ Driver Quickstart](https://www.mongodb.com/docs/languages/cpp/cpp-driver/current/tutorial/)
71+
* [MongoDB C++ Driver Manual](https://www.mongodb.com/docs/languages/cpp/cpp-driver/current/)
7272
* [MongoDB C++ Driver Source Code on GitHub](https://github.com/mongodb/mongo-cxx-driver)
7373
* [MongoDB Database Manual](https://www.mongodb.com/docs/manual/)
7474

etc/deploy-to-ghpages.pl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ sub _doxygen_rsync {
4141
( map { ; '--filter' => $_ } @filters ),
4242
"build/docs/api/", "$tmpdir/api/"
4343
);
44+
$ENV{APIDOCSPATH} = "$tmpdir/api";
45+
_try_run(qw{etc/patch-apidocs-index-pages.py})
4446
}
4547

4648
sub main {

etc/patch-apidocs-index-pages.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2009-present MongoDB, Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
"""
18+
Patches the root-level index.html file in each API doc site to match the state of the latest API doc site.
19+
"""
20+
21+
from packaging.version import Version, InvalidVersion
22+
from typing import List, Tuple
23+
24+
import bs4
25+
import os
26+
27+
28+
def find_api_docs_path() -> str:
29+
"""
30+
Return an absolute path to the directory containing the API docs.
31+
"""
32+
api_docs_path: str | None = os.environ.get('APIDOCSPATH')
33+
if not api_docs_path:
34+
raise RuntimeError('APIDOCSPATH environment variable is not set!')
35+
36+
if not os.path.exists(api_docs_path):
37+
raise RuntimeError('path to API docs does not exist!')
38+
39+
return os.path.abspath(api_docs_path)
40+
41+
42+
def find_api_docs(api_docs_path: str) -> List[str]:
43+
"""
44+
Return a list of API doc directories by name.
45+
"""
46+
api_docs: List[str] = []
47+
for dir in os.scandir(api_docs_path):
48+
if dir.is_dir() and not dir.is_symlink():
49+
api_docs.append(dir.name)
50+
51+
# Sort by legacy vs. modern, then by SemVer. Example:
52+
# - legacy-0.1.0
53+
# - legacy-0.2.0
54+
# - legacy-0.10.0
55+
# - mongocxx-3.1.0
56+
# - mongocxx-3.2.0
57+
# - mongocxx-3.10.0
58+
# Skip directories with a version suffix, e.g. `mongocxx-1.2.3-rc0`.
59+
def by_version(p: str) -> Tuple[bool, Version] | None:
60+
is_legacy: bool = p.startswith('legacy-')
61+
try:
62+
version = p.removeprefix('legacy-') if is_legacy else p.removeprefix('mongocxx-')
63+
if version.find('-') != -1:
64+
print(f' - Skipping: {p}')
65+
return None
66+
return (not is_legacy, Version(version))
67+
except InvalidVersion:
68+
raise RuntimeError(f'unexpected API doc name "{p}": APIDOCSPATH may not be correct!') from None
69+
70+
api_docs = [doc for doc in api_docs if by_version(doc) is not None]
71+
api_docs.sort(key=by_version)
72+
73+
return api_docs
74+
75+
76+
def find_index_page(root: str, doc: str) -> str:
77+
"""
78+
Return an absolute path to the index page of an API doc.
79+
"""
80+
filename = 'index.html'
81+
parent = os.path.join(root, doc)
82+
index_page = os.path.join(parent, filename)
83+
if not os.path.exists(index_page):
84+
raise RuntimeError(f' - error: cannot find {filename} in {doc}!')
85+
if not os.path.isfile(index_page):
86+
raise RuntimeError(f' - error: {index_page} is not a file in {doc}!')
87+
return index_page
88+
89+
90+
def format_latest_index_page(latest: str) -> None:
91+
"""
92+
Format the latest index page to improve readability of future patch diffs.
93+
"""
94+
with open(latest, "r+") as file:
95+
html = bs4.BeautifulSoup(file, 'html.parser')
96+
file.seek(0)
97+
file.write(html.prettify(formatter="html"))
98+
file.truncate()
99+
100+
101+
def extract_latest_contents(latest) -> bs4.PageElement:
102+
"""
103+
Return the page element corresponding to the contents of the latest index page.
104+
"""
105+
with open(latest) as file:
106+
html = bs4.BeautifulSoup(file, 'html.parser')
107+
return html.find("div", class_='contents')
108+
109+
110+
def patch_index_page(latest_contents: bs4.PageElement, index_page: str):
111+
"""
112+
Replace the contents of the index page with the latest contents.
113+
"""
114+
with open(index_page, "r+") as file:
115+
html = bs4.BeautifulSoup(file, 'html.parser')
116+
contents = html.find("div", class_="contents")
117+
contents.replace_with(latest_contents)
118+
119+
file.seek(0)
120+
file.write(html.prettify(formatter="html"))
121+
file.truncate()
122+
123+
124+
def main():
125+
api_docs_path: str = find_api_docs_path()
126+
127+
print(f'Patching API docs in: {api_docs_path}')
128+
129+
print('Finding API docs...')
130+
api_docs = find_api_docs(api_docs_path)
131+
if len(api_docs) == 0:
132+
raise RuntimeError(f'no API docs found: APIDOCSPATH may not be correct!')
133+
print('Finding API docs... done.')
134+
135+
print(f' - Found {len(api_docs)} API docs: {api_docs[0]} ... {api_docs[-1]}')
136+
137+
print('Searching for index pages...')
138+
index_pages = [find_index_page(api_docs_path, doc) for doc in api_docs]
139+
print('Searching for index pages... done.')
140+
141+
print(f' - Found {len(index_pages)} index pages within {len(api_docs)} API docs.')
142+
latest_doc = api_docs[-1]
143+
print(f' - Using {latest_doc} as the latest API doc.')
144+
145+
(latest_index, index_pages) = (index_pages[-1], index_pages[:-1])
146+
147+
print('Formatting latest index page...')
148+
format_latest_index_page(latest_index)
149+
print('Formatting latest index page... done.')
150+
151+
print('Extracting latest index page contents...')
152+
latest_contents = extract_latest_contents(latest_index)
153+
print('Extracting latest index page contents... done.')
154+
155+
print(f'Replacing contents of {len(index_pages)} index pages...')
156+
for page in index_pages:
157+
patch_index_page(latest_contents, page)
158+
print(f'Replacing contents of {len(index_pages)} index pages... done.')
159+
160+
161+
if __name__ == '__main__':
162+
main()

etc/releasing.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,12 @@ Test generating the latest versioned Doxygen docs by building the `doxygen-lates
592592
cmake --build build --target doxygen-latest
593593
```
594594

595-
Verify that the `build/docs/api/mongocxx-X.Y.Z` directory is present and populated.
595+
Verify that the `build/docs/api/mongocxx-X.Y.Z` directory is present and populated. Verify the resulting API doc looks as expected.
596+
597+
Remove all contents of `build/docs/api` before running the next commands.
598+
599+
> [!IMPORTANT]
600+
> Remove all contents of `build/docs/api` before running the next commands.
596601
597602
Generate and deploy the updated documentation to GitHub pages by building the `hugo-deploy` and `doxygen-deploy` targets:
598603

etc/requirements.txt

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,28 @@
1-
# Required packages for the release script.
2-
click==8.1.7
3-
GitPython==3.1.43
4-
PyGithub==2.3.0
5-
cryptography==42.0.7
6-
7-
# Pin `jira` to apply fix of https://github.com/pycontribs/jira/commit/010223289eb66663aaafb70447397038efb2d40d.
8-
# This avoids the `signature_method_rejected` error described in https://github.com/pycontribs/jira/pull/1643.
9-
# TODO: replace the following line with `jira` once there is a release of `jira` containing the fix.
10-
jira @ git+https://github.com/pycontribs/jira.git@010223289eb66663aaafb70447397038efb2d40d
1+
beautifulsoup4==4.12.3 # etc/patch-apidocs-index-pages.py.
2+
click==8.1.7 # etc/make_release.py
3+
cryptography==42.0.7 # etc/make_release.py (PyJWT)
4+
GitPython==3.1.43 # etc/make_release.py
5+
jira==3.5.2 # etc/make_release.py
6+
PyGithub==2.3.0 # etc/make_release.py
117

128
# Dependencies of required packages above.
13-
certifi==2024.2.2
9+
certifi==2024.7.4
1410
cffi==1.16.0
1511
charset-normalizer==3.3.2
1612
defusedxml==0.7.1
1713
Deprecated==1.2.14
1814
gitdb==4.0.11
1915
idna==3.7
2016
oauthlib==3.2.2
21-
packaging==24.0
17+
packaging==24.1
2218
pycparser==2.22
2319
PyJWT==2.8.0
2420
PyNaCl==1.5.0
25-
requests==2.32.2
21+
requests==2.32.3
2622
requests-oauthlib==2.0.0
2723
requests-toolbelt==1.0.0
2824
smmap==5.0.1
29-
typing_extensions==4.11.0
30-
urllib3==2.2.1
25+
soupsieve==2.5
26+
typing_extensions==4.12.2
27+
urllib3==2.2.2
3128
wrapt==1.16.0

examples/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
## Building project examples
1717

1818
1. Install `libmongoc` and `mongocxx` following the [installation
19-
instructions](https://www.mongodb.com/docs/languages/cpp/drivers/current/installation/)
19+
instructions](https://www.mongodb.com/docs/languages/cpp/cpp-driver/current/installation/)
2020
2. Change to one of the project example directories, e.g. `examples/projects/cmake/mongocxx/shared`
2121
3. Run `./build.sh`

examples/mongocxx/tutorial.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Compile with: c++ --std=c++11 tutorial.cpp $(pkg-config --cflags --libs libmongocxx)
22

33
// The following is a formatted copy from the tutorial
4-
// https://www.mongodb.com/docs/languages/cpp/drivers/current/tutorial/.
4+
// https://www.mongodb.com/docs/languages/cpp/cpp-driver/current/tutorial/.
55

66
#include <cstdint>
77
#include <iostream>

src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/stream/helpers.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ struct open_array_type {
6161
/// A stream manipulator to open a subarray.
6262
///
6363
/// @see
64-
/// https://www.mongodb.com/docs/languages/cpp/drivers/current/working-with-bson/#std-label-cpp-bson-builders
64+
/// https://www.mongodb.com/docs/languages/cpp/cpp-driver/current/working-with-bson/#std-label-cpp-bson-builders
6565
/// for help building arrays in loops.
6666
///
6767
constexpr open_array_type open_array;

src/mongocxx/include/mongocxx/v_noabi/mongocxx/client.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ namespace v_noabi {
5757
/// @endcode
5858
///
5959
/// Note that client is not thread-safe. See
60-
/// https://www.mongodb.com/docs/languages/cpp/drivers/current/thread-safety/ for more details.
60+
/// https://www.mongodb.com/docs/languages/cpp/cpp-driver/current/thread-safety/ for more details.
6161
class client {
6262
public:
6363
///

src/mongocxx/include/mongocxx/v_noabi/mongocxx/client_session.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ namespace v_noabi {
3939
/// or snapshots.
4040
///
4141
/// Note that client_session is not thread-safe. See
42-
/// https://www.mongodb.com/docs/languages/cpp/drivers/current/thread-safety/ for more details.
42+
/// https://www.mongodb.com/docs/languages/cpp/cpp-driver/current/thread-safety/ for more details.
4343
///
4444
/// @see
4545
/// https://www.mongodb.com/docs/manual/core/read-isolation-consistency-recency/#causal-consistency

0 commit comments

Comments
 (0)