doc: refactor vcs_link and git_info extensions
Refactor all git/github related extensions into one file, as they are working hand in hand. Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
This commit is contained in:
parent
701f59ee1e
commit
353f42d8bd
7 changed files with 230 additions and 264 deletions
|
@ -59,7 +59,7 @@ from sphinx.transforms import SphinxTransform
|
|||
from sphinx.transforms.post_transforms import SphinxPostTransform
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.nodes import NodeMatcher, make_refnode
|
||||
from zephyr.vcs_link import vcs_link_get_url
|
||||
from zephyr.gh_utils import gh_link_get_url
|
||||
|
||||
import json
|
||||
|
||||
|
@ -128,7 +128,7 @@ class ConvertCodeSampleNode(SphinxTransform):
|
|||
"name": node['name'],
|
||||
"description": node.children[0].astext(),
|
||||
"codeSampleType": "full",
|
||||
"codeRepository": vcs_link_get_url(self.app, self.env.docname)
|
||||
"codeRepository": gh_link_get_url(self.app, self.env.docname)
|
||||
})}
|
||||
</script>""",
|
||||
format="html",
|
||||
|
|
215
doc/_extensions/zephyr/gh_utils.py
Normal file
215
doc/_extensions/zephyr/gh_utils.py
Normal file
|
@ -0,0 +1,215 @@
|
|||
"""
|
||||
Git/GitHub utilities for Sphinx
|
||||
###############################
|
||||
|
||||
Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
Copyright (c) 2023 The Linux Foundation
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This Sphinx extension can be used to obtain various Git and GitHub related metadata for a page.
|
||||
This is useful, for example, when adding features like "Open on GitHub" on top
|
||||
of pages, direct links to open a GitHub issue regarding a page, or date of the most recent commit
|
||||
to a page.
|
||||
|
||||
The extension installs the following Jinja filter:
|
||||
|
||||
* ``gh_link_get_blob_url``: Returns a URL to the source of a page on GitHub.
|
||||
* ``gh_link_get_edit_url``: Returns a URL to edit the given page on GitHub.
|
||||
* ``gh_link_get_open_issue_url``: Returns a URL to open a new issue regarding the given page.
|
||||
* ``git_info``: Returns the date and SHA1 of the last commit made to a page (if this page is
|
||||
managed by Git).
|
||||
|
||||
Configuration options
|
||||
=====================
|
||||
|
||||
- ``gh_link_version``: GitHub version to use in the URL (e.g. "main")
|
||||
- ``gh_link_base_url``: Base URL used as a prefix for generated URLs.
|
||||
- ``gh_link_prefixes``: Mapping of pages (regex) <> GitHub prefix.
|
||||
- ``gh_link_exclude``: List of pages (regex) that will not report a URL. Useful
|
||||
for, e.g., auto-generated pages not in Git.
|
||||
"""
|
||||
|
||||
from functools import partial
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
from typing import Optional, Tuple
|
||||
from urllib.parse import quote
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.util.i18n import format_date
|
||||
|
||||
|
||||
__version__ = "0.1.0"
|
||||
|
||||
|
||||
def get_page_prefix(app: Sphinx, pagename: str) -> str:
|
||||
if not os.path.isfile(app.env.project.doc2path(pagename)):
|
||||
return None
|
||||
|
||||
for exclude in app.config.gh_link_exclude:
|
||||
if re.match(exclude, pagename):
|
||||
return None
|
||||
|
||||
found_prefix = ""
|
||||
for pattern, prefix in app.config.gh_link_prefixes.items():
|
||||
if re.match(pattern, pagename):
|
||||
found_prefix = prefix
|
||||
break
|
||||
|
||||
return found_prefix
|
||||
|
||||
|
||||
def gh_link_get_url(app: Sphinx, pagename: str, mode: str = "blob") -> Optional[str]:
|
||||
"""Obtain GitHub URL for the given page.
|
||||
|
||||
Args:
|
||||
app: Sphinx instance.
|
||||
mode: Typically "edit", or "blob".
|
||||
pagename: Page name (path).
|
||||
|
||||
Returns:
|
||||
GitHub URL if applicable, None otherwise.
|
||||
"""
|
||||
|
||||
page_prefix = get_page_prefix(app, pagename)
|
||||
if not page_prefix:
|
||||
return None
|
||||
|
||||
return "/".join(
|
||||
[
|
||||
app.config.gh_link_base_url,
|
||||
mode,
|
||||
app.config.gh_link_version,
|
||||
page_prefix,
|
||||
app.env.project.doc2path(pagename, basedir=False),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def gh_link_get_open_issue_url(app: Sphinx, pagename: str, sha1: str) -> Optional[str]:
|
||||
"""Link to open a new Github issue regarding "pagename" with title, body, and
|
||||
labels already pre-filled with useful information.
|
||||
|
||||
Args:
|
||||
app: Sphinx instance.
|
||||
pagename: Page name (path).
|
||||
|
||||
Returns:
|
||||
URL to open a new issue if applicable, None otherwise.
|
||||
"""
|
||||
|
||||
if not os.path.isfile(app.env.project.doc2path(pagename)):
|
||||
return None
|
||||
|
||||
title = quote(f"[doc] Documentation issue in '{pagename}'")
|
||||
labels = quote("area: Documentation")
|
||||
body = quote(
|
||||
dedent(
|
||||
f"""\
|
||||
**Describe the bug**
|
||||
|
||||
<< Please describe the issue here >>
|
||||
<< You may also want to update the automatically generated issue title above. >>
|
||||
|
||||
**Environment**
|
||||
|
||||
* Page: `{pagename}`
|
||||
* Version: {app.config.gh_link_version}
|
||||
* SHA-1: {sha1}
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
return f"{app.config.gh_link_base_url}/issues/new?title={title}&labels={labels}&body={body}"
|
||||
|
||||
|
||||
def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]:
|
||||
"""Return a tuple with the date and SHA1 of the last commit made to a page.
|
||||
|
||||
Arguments:
|
||||
app {Sphinx} -- Sphinx application object
|
||||
pagename {str} -- Page name
|
||||
|
||||
Returns:
|
||||
Optional[Tuple[str, str]] -- Tuple with the date and SHA1 of the last commit made to the
|
||||
page, or None if the page is not in the repo.
|
||||
"""
|
||||
|
||||
page_prefix = get_page_prefix(app, pagename)
|
||||
if not page_prefix:
|
||||
return None
|
||||
|
||||
orig_path = os.path.join(
|
||||
app.config.ZEPHYR_BASE,
|
||||
page_prefix,
|
||||
app.env.project.doc2path(pagename, basedir=False),
|
||||
)
|
||||
|
||||
try:
|
||||
date_and_sha1 = (
|
||||
subprocess.check_output(
|
||||
[
|
||||
"git",
|
||||
"log",
|
||||
"-1",
|
||||
"--format=%ad %H",
|
||||
"--date=unix",
|
||||
orig_path,
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
.decode("utf-8")
|
||||
.strip()
|
||||
)
|
||||
date, sha1 = date_and_sha1.split(" ", 1)
|
||||
date_object = datetime.fromtimestamp(int(date))
|
||||
last_update_fmt = app.config.html_last_updated_fmt
|
||||
if last_update_fmt is not None:
|
||||
date = format_date(last_update_fmt, date=date_object, language=app.config.language)
|
||||
|
||||
return (date, sha1)
|
||||
except subprocess.CalledProcessError:
|
||||
return None
|
||||
|
||||
|
||||
def add_jinja_filter(app: Sphinx):
|
||||
if app.builder.format != "html":
|
||||
return
|
||||
|
||||
app.builder.templates.environment.filters["gh_link_get_blob_url"] = partial(
|
||||
gh_link_get_url, app, mode="blob"
|
||||
)
|
||||
|
||||
app.builder.templates.environment.filters["gh_link_get_edit_url"] = partial(
|
||||
gh_link_get_url, app, mode="edit"
|
||||
)
|
||||
|
||||
app.builder.templates.environment.filters["gh_link_get_open_issue_url"] = partial(
|
||||
gh_link_get_open_issue_url, app
|
||||
)
|
||||
|
||||
app.builder.templates.environment.filters["git_info"] = partial(git_info_filter, app)
|
||||
|
||||
|
||||
def setup(app: Sphinx):
|
||||
app.add_config_value("ZEPHYR_BASE", Path(__file__).resolve().parents[3], "html")
|
||||
app.add_config_value("gh_link_version", "", "")
|
||||
app.add_config_value("gh_link_base_url", "", "")
|
||||
app.add_config_value("gh_link_prefixes", {}, "")
|
||||
app.add_config_value("gh_link_exclude", [], "")
|
||||
|
||||
app.connect("builder-inited", add_jinja_filter)
|
||||
|
||||
return {
|
||||
"version": __version__,
|
||||
"parallel_read_safe": True,
|
||||
"parallel_write_safe": True,
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
"""
|
||||
Git Info Extension
|
||||
##################
|
||||
|
||||
Copyright (c) 2023 The Linux Foundation
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This extension adds a new Jinja filter, ``git_info``, that returns the date and SHA1 of the last
|
||||
commit made to a page if this page is managed by Git.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Tuple
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.util.i18n import format_date
|
||||
|
||||
__version__ = "0.1.0"
|
||||
|
||||
|
||||
def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]:
|
||||
"""Return a tuple with the date and SHA1 of the last commit made to a page.
|
||||
|
||||
Arguments:
|
||||
app {Sphinx} -- Sphinx application object
|
||||
pagename {str} -- Page name
|
||||
|
||||
Returns:
|
||||
Optional[Tuple[str, str]] -- Tuple with the date and SHA1 of the last commit made to the
|
||||
page, or None if the page is not in the repo.
|
||||
"""
|
||||
|
||||
if not os.path.isfile(app.env.project.doc2path(pagename)):
|
||||
return None
|
||||
|
||||
for exclude in app.config.vcs_link_exclude:
|
||||
if re.match(exclude, pagename):
|
||||
return None
|
||||
|
||||
found_prefix = ""
|
||||
for pattern, prefix in app.config.vcs_link_prefixes.items():
|
||||
if re.match(pattern, pagename):
|
||||
found_prefix = prefix
|
||||
break
|
||||
|
||||
orig_path = os.path.join(
|
||||
app.config.ZEPHYR_BASE,
|
||||
found_prefix,
|
||||
app.env.project.doc2path(pagename, basedir=False),
|
||||
)
|
||||
|
||||
try:
|
||||
date_and_sha1 = (
|
||||
subprocess.check_output(
|
||||
[
|
||||
"git",
|
||||
"log",
|
||||
"-1",
|
||||
"--format=%ad %H",
|
||||
"--date=unix",
|
||||
orig_path,
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
.decode("utf-8")
|
||||
.strip()
|
||||
)
|
||||
date, sha1 = date_and_sha1.split(" ", 1)
|
||||
date_object = datetime.fromtimestamp(int(date))
|
||||
last_update_fmt = app.config.html_last_updated_fmt
|
||||
if last_update_fmt is not None:
|
||||
date = format_date(last_update_fmt, date=date_object, language=app.config.language)
|
||||
|
||||
return (date, sha1)
|
||||
except subprocess.CalledProcessError:
|
||||
return None
|
||||
|
||||
|
||||
def add_jinja_filter(app: Sphinx):
|
||||
if app.builder.name != "html":
|
||||
return
|
||||
|
||||
app.builder.templates.environment.filters["git_info"] = partial(git_info_filter, app)
|
||||
|
||||
|
||||
def setup(app: Sphinx):
|
||||
app.add_config_value("ZEPHYR_BASE", Path(__file__).resolve().parents[3], "html")
|
||||
app.connect("builder-inited", add_jinja_filter)
|
||||
|
||||
return {
|
||||
"version": __version__,
|
||||
"parallel_read_safe": True,
|
||||
"parallel_write_safe": True,
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
"""
|
||||
VCS Link
|
||||
########
|
||||
|
||||
Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This Sphinx extension can be used to obtain various VCS URLs for a given Sphinx page.
|
||||
This is useful, for example, when adding features like "Open on GitHub" on top
|
||||
of pages.
|
||||
The extension installs the following Jinja filter:
|
||||
|
||||
* ``vcs_link_get_blob_url``: Returns a URL to the source of a page in the VCS.
|
||||
* ``vcs_link_get_edit_url``: Returns a URL to edit the given page in the VCS.
|
||||
* ``vcs_link_get_open_issue_url``: Returns a URL to open a new issue regarding the given page.
|
||||
|
||||
Configuration options
|
||||
=====================
|
||||
|
||||
- ``vcs_link_version``: VCS version to use in the URL (e.g. "main")
|
||||
- ``vcs_link_base_url``: Base URL used as a prefix for generated URLs.
|
||||
- ``vcs_link_prefixes``: Mapping of pages (regex) <> VCS prefix.
|
||||
- ``vcs_link_exclude``: List of pages (regex) that will not report a URL. Useful
|
||||
for, e.g., auto-generated pages not in VCS.
|
||||
"""
|
||||
|
||||
from functools import partial
|
||||
import os
|
||||
import re
|
||||
from textwrap import dedent
|
||||
from typing import Optional
|
||||
from urllib.parse import quote
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
__version__ = "0.1.0"
|
||||
|
||||
|
||||
def vcs_link_get_url(app: Sphinx, pagename: str, mode: str = "blob") -> Optional[str]:
|
||||
"""Obtain VCS URL for the given page.
|
||||
|
||||
Args:
|
||||
app: Sphinx instance.
|
||||
mode: Typically "edit", or "blob".
|
||||
pagename: Page name (path).
|
||||
|
||||
Returns:
|
||||
VCS URL if applicable, None otherwise.
|
||||
"""
|
||||
|
||||
if not os.path.isfile(app.env.project.doc2path(pagename)):
|
||||
return None
|
||||
|
||||
for exclude in app.config.vcs_link_exclude:
|
||||
if re.match(exclude, pagename):
|
||||
return None
|
||||
|
||||
found_prefix = ""
|
||||
for pattern, prefix in app.config.vcs_link_prefixes.items():
|
||||
if re.match(pattern, pagename):
|
||||
found_prefix = prefix
|
||||
break
|
||||
|
||||
return "/".join(
|
||||
[
|
||||
app.config.vcs_link_base_url,
|
||||
mode,
|
||||
app.config.vcs_link_version,
|
||||
found_prefix,
|
||||
app.env.project.doc2path(pagename, basedir=False),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def vcs_link_get_open_issue_url(app: Sphinx, pagename: str, sha1: str) -> Optional[str]:
|
||||
"""Link to open a new Github issue regarding "pagename" with title, body, and
|
||||
labels already pre-filled with useful information.
|
||||
|
||||
Args:
|
||||
app: Sphinx instance.
|
||||
pagename: Page name (path).
|
||||
|
||||
Returns:
|
||||
URL to open a new issue if applicable, None otherwise.
|
||||
"""
|
||||
|
||||
if not os.path.isfile(app.env.project.doc2path(pagename)):
|
||||
return None
|
||||
|
||||
title = quote(f"[doc] Documentation issue in '{pagename}'")
|
||||
labels = quote("area: Documentation")
|
||||
body = quote(
|
||||
dedent(
|
||||
f"""\
|
||||
**Describe the bug**
|
||||
|
||||
<< Please describe the issue here >>
|
||||
<< You may also want to update the automatically generated issue title above. >>
|
||||
|
||||
**Environment**
|
||||
|
||||
* Page: `{pagename}`
|
||||
* Version: {app.config.vcs_link_version}
|
||||
* SHA-1: {sha1}
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
return f"{app.config.vcs_link_base_url}/issues/new?title={title}&labels={labels}&body={body}"
|
||||
|
||||
|
||||
def add_jinja_filter(app: Sphinx):
|
||||
if app.builder.name != "html":
|
||||
return
|
||||
|
||||
app.builder.templates.environment.filters["vcs_link_get_blob_url"] = partial(
|
||||
vcs_link_get_url, app, mode="blob"
|
||||
)
|
||||
|
||||
app.builder.templates.environment.filters["vcs_link_get_edit_url"] = partial(
|
||||
vcs_link_get_url, app, mode="edit"
|
||||
)
|
||||
|
||||
app.builder.templates.environment.filters["vcs_link_get_open_issue_url"] = partial(
|
||||
vcs_link_get_open_issue_url, app
|
||||
)
|
||||
|
||||
|
||||
def setup(app: Sphinx):
|
||||
app.add_config_value("vcs_link_version", "", "")
|
||||
app.add_config_value("vcs_link_base_url", "", "")
|
||||
app.add_config_value("vcs_link_prefixes", {}, "")
|
||||
app.add_config_value("vcs_link_exclude", [], "")
|
||||
|
||||
app.connect("builder-inited", add_jinja_filter)
|
||||
|
||||
return {
|
||||
"version": __version__,
|
||||
"parallel_read_safe": True,
|
||||
"parallel_write_safe": True,
|
||||
}
|
10
doc/_templates/breadcrumbs.html
vendored
10
doc/_templates/breadcrumbs.html
vendored
|
@ -18,14 +18,14 @@
|
|||
<dark-mode-toggle id="dark-mode-toggle" appearance="toggle" permanent="true"/>
|
||||
</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
{%- if display_vcs_link %}
|
||||
{% set vcs_blob_url = pagename | vcs_link_get_blob_url %}
|
||||
{% if vcs_blob_url %}
|
||||
<a href="{{ vcs_blob_url }}" class="fa fa-github"> {{ _('Open on GitHub') }}</a>
|
||||
{%- if display_gh_links %}
|
||||
{% set gh_blob_url = pagename | gh_link_get_blob_url %}
|
||||
{% if gh_blob_url %}
|
||||
<a href="{{ gh_blob_url }}" class="fa fa-github"> {{ _('Open on GitHub') }}</a>
|
||||
{% endif %}
|
||||
{%- set git_last_updated, sha1 = pagename | git_info | default((None, None), true) %}
|
||||
{%- if sha1 %}
|
||||
<a href="{{ pagename | vcs_link_get_open_issue_url(sha1) }}" class="fa fa-bug">
|
||||
<a href="{{ pagename | gh_link_get_open_issue_url(sha1) }}" class="fa fa-bug">
|
||||
{{ _('Report an issue')}}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
|
2
doc/_templates/footer.html
vendored
2
doc/_templates/footer.html
vendored
|
@ -23,7 +23,7 @@
|
|||
<p>
|
||||
If you find any errors on this page, outdated information, or have any other suggestion for
|
||||
improving its contents, please consider
|
||||
<a href="{{ pagename | vcs_link_get_open_issue_url(sha1) }}">opening an issue</a>.
|
||||
<a href="{{ pagename | gh_link_get_open_issue_url(sha1) }}">opening an issue</a>.
|
||||
</p>
|
||||
</div>
|
||||
{%- endif %}
|
||||
|
|
15
doc/conf.py
15
doc/conf.py
|
@ -82,9 +82,8 @@ extensions = [
|
|||
"sphinx_tabs.tabs",
|
||||
"zephyr.warnings_filter",
|
||||
"zephyr.doxyrunner",
|
||||
"zephyr.vcs_link",
|
||||
"zephyr.gh_utils",
|
||||
"zephyr.manifest_projects_table",
|
||||
"zephyr.git_info",
|
||||
"notfound.extension",
|
||||
"sphinx_copybutton",
|
||||
"sphinx_togglebutton",
|
||||
|
@ -171,7 +170,7 @@ html_context = {
|
|||
("3.3.0", "/3.3.0/"),
|
||||
("2.7.5 (LTS)", "/2.7.5/"),
|
||||
),
|
||||
"display_vcs_link": True,
|
||||
"display_gh_links": True,
|
||||
"reference_links": {
|
||||
"API": f"{reference_prefix}/doxygen/html/index.html",
|
||||
"Kconfig Options": f"{reference_prefix}/kconfig.html",
|
||||
|
@ -262,17 +261,17 @@ link_roles_manifest_baseurl = "https://github.com/zephyrproject-rtos/zephyr"
|
|||
|
||||
notfound_urls_prefix = f"/{version}/" if is_release else "/latest/"
|
||||
|
||||
# -- Options for zephyr.vcs_link ------------------------------------------
|
||||
# -- Options for zephyr.gh_utils ------------------------------------------
|
||||
|
||||
vcs_link_version = f"v{version}" if is_release else "main"
|
||||
vcs_link_base_url = f"https://github.com/zephyrproject-rtos/zephyr"
|
||||
vcs_link_prefixes = {
|
||||
gh_link_version = f"v{version}" if is_release else "main"
|
||||
gh_link_base_url = f"https://github.com/zephyrproject-rtos/zephyr"
|
||||
gh_link_prefixes = {
|
||||
"samples/.*": "",
|
||||
"boards/.*": "",
|
||||
"snippets/.*": "",
|
||||
".*": "doc",
|
||||
}
|
||||
vcs_link_exclude = [
|
||||
gh_link_exclude = [
|
||||
"reference/kconfig.*",
|
||||
"build/dts/api/bindings.*",
|
||||
"build/dts/api/compatibles.*",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue