Skip to content

Commit

Permalink
docs: Add tooling to check and validate build: (y-scope#447)
Browse files Browse the repository at this point in the history
- Add script to check for invalid links.
- Add workflow to validate build.
- Fail on warnings.
- Fix invalid link in log-viewer-webui README.

Co-authored-by: Henry8192 <[email protected]>
  • Loading branch information
2 people authored and Jack Luo committed Dec 4, 2024
1 parent e3eacca commit a564af2
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 1 deletion.
38 changes: 38 additions & 0 deletions .github/workflows/clp-docs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: "clp-docs"

on:
pull_request:
push:
workflow_dispatch:

concurrency:
group: "${{github.workflow}}-${{github.ref}}"
# Cancel in-progress jobs for efficiency
cancel-in-progress: true

jobs:
build:
strategy:
matrix:
os: ["macos-latest", "ubuntu-latest"]
runs-on: "${{matrix.os}}"
steps:
- uses: "actions/checkout@v4"
with:
submodules: "recursive"

- uses: "actions/setup-python@v5"
with:
python-version: "3.10"

- name: "Install task"
shell: "bash"
run: "npm install -g @go-task/cli"

- if: "matrix.os == 'macos-latest'"
name: "Install coreutils (for md5sum)"
run: "brew install coreutils"

- name: "Build docs"
shell: "bash"
run: "task docs:site"
2 changes: 1 addition & 1 deletion components/log-viewer-webui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ A webapp that allows us to serve the [log-viewer] and integrate it with CLP's [w

See the [docs] for more details.

[docs]: https://docs.yscope.com/clp/main/dev-guide/components-log-viewer-webui.md
[docs]: https://docs.yscope.com/clp/main/dev-guide/components-log-viewer-webui
[log-viewer]: https://github.com/y-scope/yscope-log-viewer
[webui]: ../webui
4 changes: 4 additions & 0 deletions docs/tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,16 @@ tasks:
# Call `clean` before building since `sphinx-build --write-all --fresh-env` isn't always
# equivalent to building from scratch.
- task: "clean"
- "python3 '{{.ROOT_DIR}}/tools/scripts/find-broken-docs-links.py'"
- |-
. "{{.G_DOCS_VENV_DIR}}/bin/activate"
sphinx-build \
--write-all \
--fresh-env \
--conf-dir conf \
--nitpicky \
--fail-on-warning \
--keep-going \
--builder html \
src "{{.OUTPUT_DIR}}"
# This command must be last
Expand Down
117 changes: 117 additions & 0 deletions tools/scripts/find-broken-docs-links.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import os
import subprocess
import sys
from pathlib import Path


def main(argv):
repo_root = _get_repo_root()

found_violation = False

# Check for docs.yscope.com links with ".md" suffixes
if _check_tracked_files(
r"docs\.yscope\.com/.+\.md",
repo_root,
repo_root,
"docs.yscope.com links cannot have \".md\" suffixes."
):
found_violation = True

# Check for sphinx :link: attributes that have ".md" suffixes
if _check_tracked_files(
r":link:[[:space:]]*.+\.md",
repo_root,
repo_root / "docs",
"sphinx :link: attributes cannot have \".md\" suffixes"
):
found_violation = True

if found_violation:
return 1

return 0


def _get_repo_root() -> Path:
path_str = subprocess.check_output(
["git", "rev-parse", "--show-toplevel"],
cwd=Path(__file__).parent,
text=True
)
return Path(path_str.strip())


def _check_tracked_files(
pattern: str,
repo_root: Path,
dir_to_search: Path,
error_msg: str
) -> bool:
"""
Check for a pattern in all tracked files in the repo (except this script).
:param pattern: The pattern to search for.
:param repo_root: The root of the repository.
:param dir_to_search: The directory to search in.
:param error_msg: Error message if the pattern is found.
:return: Whether the pattern was found in any file.
"""
found_matches = False

# NOTE: "-z" ensures the paths won't be quoted (while delimiting them using '\0')
for path_str in subprocess.check_output(
[
"git",
"ls-files",
"--cached",
"--exclude-standard",
"-z",
str(dir_to_search.relative_to(repo_root))
],
cwd=repo_root,
text=True,
).split("\0"):
path = Path(path_str)

# Skip directories and this script
if path == __file__ or (repo_root / path).is_dir():
continue

try:
for match in subprocess.check_output(
[
"grep",
"--extended-regexp",
"--line-number",
"--with-filename",
pattern,
path
],
cwd=repo_root,
text=True,
).splitlines():
_parse_and_print_match(match, error_msg)
found_matches = True
except subprocess.CalledProcessError:
pass

return found_matches


def _parse_and_print_match(match: str, error_msg: str):
"""
Parses and prints grep matches in a format relevant to the current environment.
:param match: The match to parse and print.
:param error_msg: Error message if the pattern is found.
"""
if os.getenv("GITHUB_ACTIONS") == "true":
# Print a GitHub Actions error annotation
file, line, _ = match.split(":", 2)
print(f"::error file={file},line={line}::{error_msg}")
else:
print(error_msg, file=sys.stderr)
print(match, file=sys.stderr)


if "__main__" == __name__:
sys.exit(main(sys.argv))

0 comments on commit a564af2

Please sign in to comment.