Skip to content

Commit e48b7f1

Browse files
authored
Doc versioning (#84)
* test versioning * publish doc * publish doc * fix make * fix make * fetch tags only * fetch all * add versions * add versions * test * test * upd ci * upd ci * upd ci * upd ci * upd ci * change dir * build tags * fix cp * update url * remove sphinx multiversion * fix url * upd json * fix static paths * static url * use again sphinx-multiversion * upd * upd * upd dir name * add ifs * uncomment * lint
1 parent cd01cdc commit e48b7f1

File tree

9 files changed

+160
-40
lines changed

9 files changed

+160
-40
lines changed

.github/workflows/build-docs.yaml

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
name: Build and publish docs
1+
name: Build and Publish Multi-Version Docs
22

33
on:
44
push:
55
branches:
6-
- dev
6+
- dev
7+
release:
8+
types:
9+
- published
710
pull_request:
811
branches:
912
- dev
@@ -17,13 +20,18 @@ permissions:
1720
contents: write
1821

1922
jobs:
20-
publish:
21-
name: build and publish docs
23+
build-docs:
24+
name: Build Documentation
2225
runs-on: ubuntu-latest
26+
2327
steps:
24-
- uses: actions/checkout@v4
28+
- name: Checkout code
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 0
32+
fetch-tags: true
2533

26-
- name: set up python 3.10
34+
- name: Set up Python 3.10
2735
uses: actions/setup-python@v5
2836
with:
2937
python-version: "3.10"
@@ -36,37 +44,30 @@ jobs:
3644
run: |
3745
sudo apt install pandoc
3846
39-
- name: install dependencies
47+
- name: Install dependencies
4048
run: |
4149
poetry install --with docs
4250
43-
- name: Test documentation
51+
- name: Run tests
4452
run: |
53+
echo "Testing documentation build..."
4554
make test-docs
4655
47-
- name: build documentation
56+
- name: Build documentation
57+
if: ${{ github.ref == 'refs/heads/dev' }}
4858
run: |
4959
make docs
5060
51-
- name: save branch name without slashes
52-
env:
53-
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
61+
- name: build multiversion documentation
62+
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
5463
run: |
55-
BRANCH_NAME=${{ env.BRANCH_NAME }}
56-
BRANCH_NAME=${BRANCH_NAME////_}
57-
echo BRANCH_NAME=${BRANCH_NAME} >> $GITHUB_ENV
58-
59-
- name: Upload artifact
60-
uses: actions/upload-artifact@v4
61-
with:
62-
name: ${{ format('github-pages-for-branch-{0}', env.BRANCH_NAME) }}
63-
path: docs/build/
64-
retention-days: 3
64+
make multi-version-docs
6565
6666
- name: Deploy to GitHub Pages
67-
uses: JamesIves/[email protected]
68-
if: ${{ github.ref == 'refs/heads/dev' }}
67+
uses: peaceiris/actions-gh-pages@v3
68+
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
6969
with:
70-
branch: gh-pages
71-
folder: docs/build/html/
72-
single-commit: True
70+
github_token: ${{ github.token }}
71+
publish_dir: docs/build/html/versions
72+
destination_dir: versions
73+
keep_files: true

.github/workflows/ruff.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ jobs:
55
runs-on: ubuntu-latest
66
steps:
77
- uses: actions/checkout@v4
8-
- uses: astral-sh/ruff-action@v1
8+
- uses: astral-sh/ruff-action@v1

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,17 @@ docs:
3131
$(poetry) python -m sphinx build -b html docs/source docs/build/html
3232

3333
.PHONY: test-docs
34-
test-docs: docs
34+
test-docs:
3535
$(poetry) python -m sphinx build -b doctest docs/source docs/build/html
3636

3737
.PHONY: serve-docs
3838
serve-docs: docs
3939
$(poetry) python -m http.server -d docs/build/html 8333
4040

41+
.PHONY: multi-version-docs
42+
multi-version-docs:
43+
$(poetry) sphinx-multiversion docs/source docs/build/html
44+
4145
.PHONY: clean-docs
4246
clean-docs:
4347
rm -rf docs/build

autointent/_pipeline/_pipeline.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ def fit(self, dataset: Dataset, force_multilabel: bool = False) -> Context:
135135
predictions = self.predict(context.data_handler.test_utterances())
136136
for metric_name, metric in PREDICTION_METRICS_MULTILABEL.items():
137137
context.optimization_info.pipeline_metrics[metric_name] = metric(
138-
context.data_handler.test_labels(), predictions,
138+
context.data_handler.test_labels(),
139+
predictions,
139140
)
140141

141142
return context

docs/_static/versions.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[
2+
{
3+
"name": "v0.0.1 (stable)",
4+
"version": "v0.0.1",
5+
"url": "https://deeppavlov.github.io/AutoIntent/versions/v0.0.1/",
6+
"preferred": true
7+
},
8+
{
9+
"version": "dev (dev)",
10+
"url": "https://deeppavlov.github.io/AutoIntent/versions/dev/"
11+
}
12+
]

docs/source/conf.py

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@
55

66
# -- Project information -----------------------------------------------------
77
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8-
98
import os
109
import sys
10+
from importlib.metadata import version
1111
from pathlib import Path
1212

13+
from docs.source.docs_utils.tutorials import generate_tutorial_links_for_notebook_creation
14+
1315
conf_dir = os.path.dirname(os.path.abspath(__file__)) # noqa: PTH100, PTH120
1416

1517
sys.path.insert(0, conf_dir)
1618

1719
from docs_utils.skip_members import skip_member # noqa: E402
18-
from docs_utils.tutorials import generate_tutorial_links_for_notebook_creation # noqa: E402
20+
from docs_utils.versions_generator import generate_versions_json # noqa: E402
1921

2022
project = "AutoIntent"
2123
copyright = "2024, DeepPavlov"
@@ -44,6 +46,7 @@
4446
"sphinx_copybutton",
4547
"nbsphinx",
4648
"sphinx.ext.intersphinx",
49+
"sphinx_multiversion",
4750
]
4851

4952
templates_path = ["_templates"]
@@ -81,12 +84,16 @@
8184

8285
html_theme = "pydata_sphinx_theme"
8386
html_static_path = ["../_static"]
87+
version = version("autointent").replace("dev", "") # may differ
88+
89+
BASE_URL = "https://deeppavlov.github.io/AutoIntent/versions"
90+
BASE_STATIC_URL = f"{BASE_URL}/dev/_static"
8491

8592
html_theme_options = {
8693
"logo": {
8794
"text": "AutoIntent",
88-
"image_light": "../_static/logo-light.svg",
89-
"image_dark": "../_static/logo-dark.svg",
95+
"image_light": f"{BASE_STATIC_URL}/logo-light.svg",
96+
"image_dark": f"{BASE_STATIC_URL}/logo-dark.svg",
9097
},
9198
"icon_links": [
9299
{
@@ -98,14 +105,19 @@
98105
{
99106
"name": "HuggingFace",
100107
"url": "https://huggingface.co/AutoIntent",
101-
"icon": "../_static/hf-logo.svg",
108+
"icon": f"{BASE_STATIC_URL}/hf-logo.svg",
102109
"type": "local",
103110
},
104111
],
112+
"switcher": {
113+
"json_url": f"{BASE_STATIC_URL}/versions.json",
114+
"version_match": version,
115+
},
116+
"navbar_start": ["navbar-logo", "version-switcher"],
105117
"show_toc_level": 3,
106118
}
107119

108-
html_favicon = "../_static/logo-white.svg"
120+
html_favicon = f"{BASE_STATIC_URL}/logo-white.svg"
109121
html_show_sourcelink = False
110122

111123
toc_object_entries_show_parents = "hide"
@@ -133,8 +145,28 @@
133145

134146
mathjax_path = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
135147

148+
# sphinx_multiversion
149+
# Whitelist for tags matching v1.0.0, v2.1.0 format
150+
# smv_tag_whitelist = r'^v\d+\.\d+\.\d+$'
151+
smv_tag_whitelist = r"^.*$"
152+
153+
# Whitelist for the dev branch
154+
smv_branch_whitelist = r"^dev$"
155+
156+
# Output format (keeping your current format)
157+
smv_outputdir_format = "versions/{ref.name}"
158+
159+
# Include both tags and dev branch as released
160+
smv_released_pattern = r"^(refs/tags/.*|refs/heads/dev)$"
161+
162+
smv_remote_whitelist = r"^(origin|upstream)$" # Use branches from origin and upstream
163+
164+
repo_root = Path(__file__).resolve().parents[2] # if conf.py is in docs/
165+
136166

137167
def setup(app) -> None: # noqa: ANN001
168+
generate_versions_json(repo_root, BASE_URL)
169+
138170
generate_tutorial_links_for_notebook_creation(
139171
include=[
140172
(
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import json
2+
import logging
3+
import os
4+
import re
5+
import subprocess
6+
from pathlib import Path
7+
8+
logging.basicConfig(level=logging.INFO)
9+
logger = logging.getLogger(__name__)
10+
11+
12+
def get_sorted_versions(repo_root: Path, base_url: str) -> list[dict]:
13+
os.chdir(repo_root)
14+
# Fetch tags and branches
15+
tags_output = subprocess.check_output(["git", "tag"], text=True).strip().split("\n") # noqa: S603, S607
16+
tag_regex = re.compile(r"^v\d+\.\d+\.\d+$") # Matches tags like v0.0.1
17+
tags = [tag for tag in tags_output if tag_regex.match(tag)]
18+
19+
sorted_tags = sorted(tags, reverse=True)
20+
21+
logger.info("sorted_tags: %s", sorted_tags)
22+
23+
# Prepare versions list (similar to previous implementation)
24+
versions = []
25+
26+
if sorted_tags:
27+
versions.append(
28+
{
29+
"name": f"{sorted_tags[0]} (stable)",
30+
"version": sorted_tags[0],
31+
"url": f"{base_url}/{sorted_tags[0]}/",
32+
"preferred": True,
33+
}
34+
)
35+
36+
for tag in sorted_tags[1:]:
37+
versions.append({"version": tag, "url": f"{base_url}/{tag}/"}) # noqa: PERF401
38+
39+
# Get branches
40+
branches_output = subprocess.check_output(["git", "branch", "-r"], text=True).strip().split("\n") # noqa: S603, S607
41+
dev_branches = [
42+
branch.strip().split("/")[-1] for branch in branches_output if "origin/dev" in branch and "HEAD" not in branch
43+
]
44+
logger.info("dev_branches: %s", dev_branches)
45+
46+
for branch in dev_branches:
47+
versions.append({"version": f"{branch} (dev)", "url": f"{base_url}/{branch}/"}) # noqa: PERF401
48+
49+
return versions
50+
51+
52+
def generate_versions_json(repo_root: Path, base_url: str) -> None:
53+
"""
54+
Sphinx extension to generate versions.json during documentation build.
55+
"""
56+
# Only generate if no exception occurred
57+
# Ensure _static directory exists
58+
static_dir = repo_root / "docs" / "_static"
59+
static_dir.mkdir(parents=True, exist_ok=True)
60+
61+
# Generate and write versions JSON
62+
versions = get_sorted_versions(repo_root, base_url)
63+
versions_path = static_dir / "versions.json"
64+
65+
# Always generate a JSON, even if empty
66+
with versions_path.open("w") as f:
67+
json.dump(versions, f, indent=4)
68+
69+
logger.info("versions.json generated at %s", versions_path)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ sphinx-autodoc-typehints = "^2.5.0"
9595
sphinx-copybutton = "^0.5.2"
9696
sphinx-autoapi = "^3.3.3"
9797
ipykernel = "^6.29.5"
98+
sphinx-multiversion = "^0.2.4"
9899

99100
[tool.poetry.scripts]
100101
"autointent" = "autointent._pipeline._cli_endpoint:optimize"

tests/context/datahandler/test_data_handler.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def test_sample_validation(label):
129129
"validation_1": mock_split(),
130130
"test": mock_split(),
131131
},
132-
]
132+
],
133133
)
134134
def test_dataset_initialization(mapping):
135135
dataset = Dataset.from_dict(mapping)
@@ -151,8 +151,8 @@ def test_dataset_initialization(mapping):
151151
{"train": mock_split(), "validation": mock_split(), "validation_0": mock_split()},
152152
{"train": mock_split(), "validation": mock_split(), "validation_1": mock_split()},
153153
{"train": mock_split(), "validation": mock_split(), "validation_0": mock_split(), "validation_1": mock_split()},
154-
{"train": mock_split(), "oos": mock_split()}
155-
]
154+
{"train": mock_split(), "oos": mock_split()},
155+
],
156156
)
157157
def test_dataset_validation(mapping):
158158
with pytest.raises(ValueError):
@@ -169,7 +169,7 @@ def test_dataset_validation(mapping):
169169
"test": [{"utterance": "Hello!", "label": 0}],
170170
},
171171
{"train": [{"utterance": "Hello!"}]},
172-
]
172+
],
173173
)
174174
def test_intents_validation(mapping):
175175
with pytest.raises(ValueError):

0 commit comments

Comments
 (0)