Skip to content

Commit 0ff8610

Browse files
authored
refactor(docs): simplify docs files / pipelines (inventree#9633)
* refactor(doc): only use one command * restructure * move all generated helpers to a dedicated directory * move to pathlib * and more pathlib * add empty generated folder
1 parent 6d0a08d commit 0ff8610

8 files changed

Lines changed: 70 additions & 85 deletions

File tree

.github/workflows/release.yaml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,7 @@ jobs:
121121
pip install --require-hashes -r docs/requirements.txt
122122
- name: Build documentation
123123
run: |
124-
invoke migrate
125-
invoke int.export-definitions --basedir "docs"
126-
invoke dev.schema --filename docs/schema.yml --ignore-warnings
127-
python docs/extract_schema.py docs/schema.yml
128-
mkdocs build -f docs/mkdocs.yml
124+
invoke build-docs --mkdocs
129125
- name: Zip build docs
130126
run: |
131127
cd docs/site

.gitignore

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,3 @@ api.yaml
113113
# web frontend (static files)
114114
src/backend/InvenTree/web/static
115115
InvenTree/web/static
116-
117-
# Exported interim files
118-
docs/schema.yml
119-
docs/docs/api/*.yml
120-
docs/docs/api/schema/*.yml

docs/.gitignore

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,5 @@ site/
1313
# Generated API schema files
1414
docs/api/schema/*.yml
1515

16-
# Temporary cache files
17-
url_cache.txt
18-
invoke-commands.txt
19-
20-
# Temp files
21-
releases.json
22-
versions.json
23-
inventree_filters.yml
24-
inventree_settings.json
25-
inventree_tags.yml
26-
2716
.vscode/
28-
29-
inventree_filters.yml
30-
inventree_report_context.json
31-
inventree_settings.json
32-
inventree_tags.yml
17+
generated/

docs/docs/hooks.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
import re
66
from datetime import datetime
77
from distutils.version import StrictVersion
8+
from pathlib import Path
89

910
import requests
1011

12+
here = Path(__file__).parent
13+
1114

1215
def fetch_rtd_versions():
1316
"""Get a list of RTD docs versions to build the version selector."""
@@ -77,7 +80,7 @@ def make_request(url, headers):
7780
'aliases': [],
7881
})
7982

80-
output_filename = os.path.join(os.path.dirname(__file__), 'versions.json')
83+
output_filename = here.joinpath('versions.json')
8184

8285
print('Discovered the following versions:')
8386
print(versions)
@@ -92,11 +95,11 @@ def get_release_data():
9295
- First look to see if 'releases.json' file exists
9396
- If data does not exist in this file, request via the github API
9497
"""
95-
json_file = os.path.join(os.path.dirname(__file__), 'releases.json')
98+
json_file = here.parent.joinpath('generated', 'releases.json')
9699

97100
releases = []
98101

99-
if os.path.exists(json_file):
102+
if json_file.exists():
100103
# Release information has been cached to file
101104

102105
print("Loading release information from 'releases.json'")
@@ -165,7 +168,7 @@ def on_config(config, *args, **kwargs):
165168
# Note: version selection is handled by RTD internally
166169
# Check for 'versions.json' file
167170
# If it does not exist, we need to fetch it from the RTD API
168-
# if os.path.exists(os.path.join(os.path.dirname(__file__), 'versions.json')):
171+
# if here.joinpath('versions.json').exists():
169172
# print("Found 'versions.json' file")
170173
# else:
171174
# fetch_rtd_versions()
@@ -230,9 +233,9 @@ def on_config(config, *args, **kwargs):
230233
continue
231234

232235
# Check if there is a local file with release information
233-
local_path = os.path.join(os.path.dirname(__file__), 'releases', f'{tag}.md')
236+
local_path = here.joinpath('releases', f'{tag}.md')
234237

235-
if os.path.exists(local_path):
238+
if local_path.exists():
236239
item['local_path'] = local_path
237240

238241
# Extract the date

docs/generated/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*

docs/main.py

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import subprocess
66
import textwrap
7+
from pathlib import Path
78
from typing import Literal, Optional
89

910
import requests
@@ -37,29 +38,29 @@
3738
global REPORT_CONTEXT
3839

3940
# Read in the InvenTree settings file
40-
here = os.path.dirname(__file__)
41-
settings_file = os.path.join(here, 'inventree_settings.json')
41+
here = Path(__file__).parent
42+
gen_base = here.joinpath('generated')
4243

43-
with open(settings_file, encoding='utf-8') as sf:
44+
with open(gen_base.joinpath('inventree_settings.json'), encoding='utf-8') as sf:
4445
settings = json.load(sf)
4546

4647
GLOBAL_SETTINGS = settings['global']
4748
USER_SETTINGS = settings['user']
4849

4950
# Tags
50-
with open(os.path.join(here, 'inventree_tags.yml'), encoding='utf-8') as f:
51+
with open(gen_base.joinpath('inventree_tags.yml'), encoding='utf-8') as f:
5152
TAGS = yaml.load(f, yaml.BaseLoader)
5253
# Filters
53-
with open(os.path.join(here, 'inventree_filters.yml'), encoding='utf-8') as f:
54+
with open(gen_base.joinpath('inventree_filters.yml'), encoding='utf-8') as f:
5455
FILTERS = yaml.load(f, yaml.BaseLoader)
5556
# Report context
56-
with open(os.path.join(here, 'inventree_report_context.json'), encoding='utf-8') as f:
57+
with open(gen_base.joinpath('inventree_report_context.json'), encoding='utf-8') as f:
5758
REPORT_CONTEXT = json.load(f)
5859

5960

6061
def get_repo_url(raw=False):
6162
"""Return the repository URL for the current project."""
62-
mkdocs_yml = os.path.join(os.path.dirname(__file__), 'mkdocs.yml')
63+
mkdocs_yml = here.joinpath('mkdocs.yml')
6364

6465
with open(mkdocs_yml, encoding='utf-8') as f:
6566
mkdocs_config = yaml.safe_load(f)
@@ -77,10 +78,10 @@ def check_link(url) -> bool:
7778
We allow a number attempts and a lengthy timeout,
7879
as we do not want false negatives.
7980
"""
80-
CACHE_FILE = os.path.join(os.path.dirname(__file__), 'url_cache.txt')
81+
CACHE_FILE = gen_base.joinpath('url_cache.txt')
8182

8283
# Keep a local cache file of URLs we have already checked
83-
if os.path.exists(CACHE_FILE):
84+
if CACHE_FILE.exists():
8485
with open(CACHE_FILE, encoding='utf-8') as f:
8586
cache = f.read().splitlines()
8687

@@ -93,6 +94,7 @@ def check_link(url) -> bool:
9394

9495
while attempts > 0:
9596
response = requests.head(url, timeout=5000)
97+
9698
# Ensure GH is not causing issues
9799
if response.status_code in (200, 429):
98100
# Update the cache file
@@ -147,13 +149,8 @@ def sourcedir(dirname: str, branch=None):
147149
dirname = dirname[1:]
148150

149151
# This file exists at ./docs/main.py, so any directory we link to must be relative to the top-level directory
150-
here = os.path.dirname(__file__)
151-
root = os.path.abspath(os.path.join(here, '..'))
152-
153-
directory = os.path.join(root, dirname)
154-
directory = os.path.abspath(directory)
155-
156-
if not os.path.exists(directory) or not os.path.isdir(directory):
152+
directory = here.parent.joinpath(dirname)
153+
if not directory.exists() or not directory.is_dir():
157154
raise FileNotFoundError(f'Source directory {dirname} does not exist.')
158155

159156
repo_url = get_repo_url()
@@ -188,12 +185,8 @@ def sourcefile(filename, branch=None, raw=False):
188185
filename = filename[1:]
189186

190187
# This file exists at ./docs/main.py, so any file we link to must be relative to the top-level directory
191-
here = os.path.dirname(__file__)
192-
root = os.path.abspath(os.path.join(here, '..'))
193-
194-
file_path = os.path.join(root, filename)
195-
196-
if not os.path.exists(file_path):
188+
file_path = here.parent.joinpath(filename)
189+
if not file_path.exists():
197190
raise FileNotFoundError(f'Source file {filename} does not exist.')
198191

199192
# Construct repo URL
@@ -214,11 +207,8 @@ def sourcefile(filename, branch=None, raw=False):
214207
@env.macro
215208
def invoke_commands():
216209
"""Provides an output of the available commands."""
217-
here = os.path.dirname(__file__)
218-
base = os.path.join(here, '..')
219-
base = os.path.abspath(base)
220-
tasks = os.path.join(base, 'tasks.py')
221-
output = os.path.join(here, 'invoke-commands.txt')
210+
tasks = here.parent.joinpath('tasks.py')
211+
output = gen_base.joinpath('invoke-commands.txt')
222212

223213
command = f'invoke -f {tasks} --list > {output}'
224214

@@ -232,17 +222,15 @@ def invoke_commands():
232222
@env.macro
233223
def listimages(subdir):
234224
"""Return a listing of all asset files in the provided subdir."""
235-
here = os.path.dirname(__file__)
236-
237-
directory = os.path.join(here, 'docs', 'assets', 'images', subdir)
225+
directory = here.joinpath('docs', 'assets', 'images', subdir)
238226

239227
assets = []
240228

241229
allowed = ['.png', '.jpg']
242230

243-
for asset in os.listdir(directory):
244-
if any(asset.endswith(x) for x in allowed):
245-
assets.append(os.path.join(subdir, asset))
231+
for asset in directory.iterdir():
232+
if any(str(asset).endswith(x) for x in allowed):
233+
assets.append(str(subdir / asset.relative_to(directory)))
246234

247235
return assets
248236

@@ -255,11 +243,9 @@ def includefile(filename: str, title: str, fmt: str = ''):
255243
title: The title of the collapse block in the documentation
256244
fmt: The format of the included file (e.g., 'python', 'html', etc.)
257245
"""
258-
here = os.path.dirname(__file__)
259-
path = os.path.join(here, '..', filename)
260-
path = os.path.abspath(path)
246+
path = here.parent.joinpath(filename)
261247

262-
if not os.path.exists(path):
248+
if not path.exists():
263249
raise FileNotFoundError(f'Required file {path} does not exist.')
264250

265251
with open(path, encoding='utf-8') as f:
@@ -276,10 +262,8 @@ def includefile(filename: str, title: str, fmt: str = ''):
276262
@env.macro
277263
def templatefile(filename):
278264
"""Include code for a provided template file."""
279-
base = os.path.basename(filename)
280-
fn = os.path.join(
281-
'src', 'backend', 'InvenTree', 'report', 'templates', filename
282-
)
265+
base = Path(filename).name
266+
fn = Path('src', 'backend', 'InvenTree', 'report', 'templates', filename)
283267

284268
return includefile(fn, f'Template: {base}', fmt='html')
285269

readthedocs.yml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ build:
1414
python: "3.9"
1515
jobs:
1616
post_install:
17-
- echo "Generating API schema file"
1817
- pip install -U invoke
19-
- invoke migrate
20-
- invoke int.export-definitions --basedir "docs"
21-
- invoke dev.schema --filename docs/schema.yml --ignore-warnings
22-
- python docs/extract_schema.py docs/schema.yml
18+
- echo "Generating API schema file"
19+
- invoke build-docs

tasks.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,12 +1325,13 @@ def export_definitions(c, basedir: str = ''):
13251325
"""Export various definitions."""
13261326
if basedir != '' and basedir.endswith('/') is False:
13271327
basedir += '/'
1328+
base_path = Path(basedir, 'generated').resolve()
13281329

13291330
filenames = [
1330-
Path(basedir + 'inventree_settings.json').resolve(),
1331-
Path(basedir + 'inventree_tags.yml').resolve(),
1332-
Path(basedir + 'inventree_filters.yml').resolve(),
1333-
Path(basedir + 'inventree_report_context.json').resolve(),
1331+
base_path.joinpath('inventree_settings.json'),
1332+
base_path.joinpath('inventree_tags.yml'),
1333+
base_path.joinpath('inventree_filters.yml'),
1334+
base_path.joinpath('inventree_report_context.json'),
13341335
]
13351336

13361337
info('Exporting definitions...')
@@ -1704,6 +1705,14 @@ def check_already_current(tag=None, sha=None):
17041705
)
17051706

17061707

1708+
def doc_schema(c):
1709+
"""Generate schema documentation for the API."""
1710+
schema(
1711+
c, ignore_warnings=True, overwrite=True, filename='docs/generated/schema.yml'
1712+
)
1713+
run(c, 'python docs/extract_schema.py docs/generated/schema.yml')
1714+
1715+
17071716
@task(
17081717
help={
17091718
'address': 'Host and port to run the server on (default: localhost:8080)',
@@ -1716,13 +1725,27 @@ def docs_server(c, address='localhost:8080', compile_schema=False):
17161725
export_definitions(c, basedir='docs')
17171726

17181727
if compile_schema:
1719-
# Build the schema docs first
1720-
schema(c, ignore_warnings=True, overwrite=True, filename='docs/schema.yml')
1721-
run(c, 'python docs/extract_schema.py docs/schema.yml')
1728+
doc_schema(c)
17221729

17231730
run(c, f'mkdocs serve -a {address} -f docs/mkdocs.yml')
17241731

17251732

1733+
@task(
1734+
help={'mkdocs': 'Build the documentation using mkdocs at the end (default: False)'}
1735+
)
1736+
def build_docs(c, mkdocs=False):
1737+
"""Build the required documents for building the docs. Optionally build the documentation using mkdocs."""
1738+
migrate(c)
1739+
export_definitions(c, basedir='docs')
1740+
doc_schema(c)
1741+
1742+
if mkdocs:
1743+
run(c, 'mkdocs build -f docs/mkdocs.yml')
1744+
info('Documentation build complete')
1745+
else:
1746+
info('Documentation build complete, but mkdocs not requested')
1747+
1748+
17261749
@task
17271750
def clear_generated(c):
17281751
"""Clear generated files from `invoke update`."""
@@ -1787,6 +1810,7 @@ def clear_generated(c):
17871810
version,
17881811
wait,
17891812
worker,
1813+
build_docs,
17901814
)
17911815

17921816
ns.add_collection(development, 'dev')

0 commit comments

Comments
 (0)