docs(readme): update project links and formatting #15
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Docs | |
| on: | |
| pull_request: | |
| paths: | |
| - "**/*.md" | |
| - ".github/ISSUE_TEMPLATE/**" | |
| - ".github/PULL_REQUEST_TEMPLATE.md" | |
| - ".github/workflows/docs.yml" | |
| push: | |
| branches: [main] | |
| paths: | |
| - "**/*.md" | |
| - ".github/ISSUE_TEMPLATE/**" | |
| - ".github/PULL_REQUEST_TEMPLATE.md" | |
| - ".github/workflows/docs.yml" | |
| permissions: | |
| contents: read | |
| jobs: | |
| links: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Validate active relative Markdown links | |
| run: | | |
| python3 - <<'PY' | |
| from pathlib import Path | |
| import re | |
| import sys | |
| files = [ | |
| Path("README.md"), | |
| Path("use-cases/README.md"), | |
| Path("methods/README.md"), | |
| Path("benchmarks/README.md"), | |
| Path("AGENTS.md"), | |
| Path(".github/CONTRIBUTING.md"), | |
| Path(".github/CODE_OF_CONDUCT.md"), | |
| Path(".github/SECURITY.md"), | |
| ] | |
| missing = [] | |
| for path in files: | |
| if not path.exists(): | |
| continue | |
| text = path.read_text() | |
| active = re.sub(r"<!--.*?-->", "", text, flags=re.S) | |
| for raw in re.findall(r"\[[^\]]*\]\(([^)]+)\)", active): | |
| link = raw.split("#", 1)[0] | |
| if not link or link.startswith(("http://", "https://", "mailto:")): | |
| continue | |
| target = (path.parent / link).resolve() | |
| try: | |
| target.relative_to(Path.cwd().resolve()) | |
| except ValueError: | |
| missing.append((path, raw, "outside repository")) | |
| continue | |
| if not target.exists(): | |
| missing.append((path, raw, "missing")) | |
| if missing: | |
| for path, raw, reason in missing: | |
| print(f"{path}: {raw} -> {reason}") | |
| sys.exit(1) | |
| print("Active relative Markdown links resolve.") | |
| PY | |
| - name: Validate use-case banner links | |
| run: | | |
| python3 - <<'PY' | |
| from pathlib import Path | |
| import re | |
| import sys | |
| files = { | |
| Path("README.md"): "## Use Cases", | |
| Path("use-cases/README.md"): "## Use Case Catalogue", | |
| } | |
| failures = [] | |
| for path, heading in files.items(): | |
| text = path.read_text() | |
| start = text.find(heading) | |
| if start == -1: | |
| failures.append(f"{path}: missing {heading}") | |
| continue | |
| table_start = text.find("<table>", start) | |
| table_end = text.find("</table>", table_start) | |
| if table_start == -1 or table_end == -1: | |
| failures.append(f"{path}: missing use-case table") | |
| continue | |
| table = text[table_start:table_end] | |
| cells = re.findall(r"<td[^>]*>(.*?)</td>", table, flags=re.S) | |
| for index, cell in enumerate(cells, start=1): | |
| title_match = re.search(r"####\s+(.+)", cell) | |
| title = title_match.group(1).strip() if title_match else f"use case {index}" | |
| banner_match = re.search(r"\[!\[[^\]]*\]\([^)]+\)\]\(([^)]+)\)", cell) | |
| primary_match = re.search(r"^\[(?:Code|Plugin|Live Demo)\]\(([^)]+)\)", cell, flags=re.M) | |
| if not banner_match: | |
| failures.append(f"{path}: {title}: missing linked banner") | |
| elif not primary_match: | |
| failures.append(f"{path}: {title}: missing primary link") | |
| elif banner_match.group(1) != primary_match.group(1): | |
| failures.append( | |
| f"{path}: {title}: banner link {banner_match.group(1)} " | |
| f"does not match primary link {primary_match.group(1)}" | |
| ) | |
| if failures: | |
| print("\n".join(failures)) | |
| sys.exit(1) | |
| print("Use-case banner links match primary links.") | |
| PY | |
| - name: Validate issue template YAML | |
| run: | | |
| ruby -e 'require "yaml"; Dir[".github/ISSUE_TEMPLATE/*.yml"].sort.each { |p| YAML.load_file(p); puts "YAML ok: #{p}" }' |