Skip to content

ci: check relative Markdown links and anchors - #575

Open
Jay (jay23606) wants to merge 2 commits into
microsoft:devfrom
jay23606:fix/md-link-check
Open

Jay (jay23606) wants to merge 2 commits into
microsoft:devfrom
jay23606:fix/md-link-check

Conversation

@jay23606

Copy link
Copy Markdown
Contributor

Fixes #563

Summary

  • scripts/check_markdown_links.py resolves every relative link and image target in tracked Markdown outside openvmm/, and every anchor against GitHub's heading slugs, ignoring fenced and inline code.
  • Runs in .github/actions/check-quality with its unit tests (scripts/test_check_markdown_links.py).
  • Fixes the one broken anchor it finds: aci_edge_sandboxes/README.md linked #native-proxy-and-forwarded-ports, a heading renamed to "Native proxy and host loopback".

Test

  • python scripts/check_markdown_links.py passes on this branch.
  • python -m unittest discover -s scripts -p test_check_markdown_links.py passes (6 tests).
  • ruff check/format and pyright (strict, Linux and Windows) are clean.
  • Links into openvmm/ are skipped: it is vendored and was not checked out in my clone, so two links into it could not be verified here.

🤖 Generated with Claude Code

Nothing in CI checked the repository's relative links, so a renamed heading
broke its anchors silently. scripts/check_markdown_links.py resolves every
relative link and image target, and every anchor against GitHub's heading
slugs, ignoring code. Fix the one anchor it finds broken.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 15, 2026 19:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Parsing defects can silently miss broken links or fail CI on valid documentation.

6 open findings
What changed in this PR

Adds Markdown link validation to the quality gate to catch broken documentation paths and anchors, addressing #563.

Changes:

  • Adds a dependency-free checker and unit tests.
  • Runs both in the quality action.
  • Corrects the sandbox README’s native-proxy anchor.
File Description
scripts/​test_check_markdown_links.py Tests slug generation, anchors, and target extraction.
scripts/​check_markdown_links.py Checks relative Markdown targets and anchors outside vendored files.
aci_edge_sandboxes/​README.md Fixes the native-proxy anchor destination.
.github/​actions/​check-quality/​action.yml Runs the checker and its tests.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/check_markdown_links.py Outdated
Comment thread scripts/check_markdown_links.py Outdated
Comment thread scripts/check_markdown_links.py Outdated
Comment thread scripts/check_markdown_links.py
Comment thread scripts/check_markdown_links.py Outdated
Comment thread scripts/check_markdown_links.py Outdated
Fences close only on their own character and length. Setext headings, code
spans of any backtick length, multiline labels, and reference-style
definitions are handled. Slugs come from rendered heading text, and duplicate
suffixes skip slugs already taken. Each rule has a regression test.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Signed-off-by: jay23606 <4602056+jay23606@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 15, 2026 20:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Verified parsing and resolution errors reject valid documentation links and allow broken links to pass.

1 open finding
6 resolved since last review
Previously missed (4)

In code that hasn't changed since last review

Medium severity Parse Markdown destinations with titles and balanced parentheses

scripts/​check_markdown_links.py:33

This expression misses or truncates valid Markdown destinations. [guide](missing.md 'Guide') and [guide](<missing guide.md>) produce no targets, so broken links pass CI. [guide](guide(v2).md) produces guide(v2, so an existing file is reported missing. Parse angle-delimited destinations, balanced/escaped parentheses, and Markdown title delimiters, and add regression cases for these forms.

Medium severity Decode HTML entities before generating heading slugs

scripts/​check_markdown_links.py:93

HTML entities are not decoded before generating heading slugs. For example, # Fish &amp; Chips renders with anchor fish--chips, but this checker generates fish-amp-chips. It therefore rejects the valid anchor and accepts an incorrect one. Decode entities after processing heading markup but before restoring stashed code spans, so entity text inside code remains literal, and add regression cases for both forms.

Medium severity Preserve inline-code-only Setext heading anchors

scripts/​check_markdown_links.py:104

A Setext heading containing only inline code, such as a line containing Setup in backticks followed by =====, loses its anchor: masking turns the heading text into whitespace, so the blank-line check discards it. GitHub generates setup, but this checker rejects links to it. Use nonblank placeholders for code spans during heading detection, while still masking fences, and add a regression case.

Medium severity Strip query strings before resolving link paths

scripts/​check_markdown_links.py:165

Query strings are treated as part of the filesystem path. Valid links such as README.md?plain=1 or image.png?raw=true are reported missing even when the file exists, causing the quality job to reject valid documentation. Strip the query before resolving the path, while retaining the fragment for anchor validation.

🧠 Review effort: Balanced



def _mask_code_spans(markdown: str) -> str:
return CODE_SPAN.sub(lambda match: _blank(match.group(0)), markdown)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: check relative Markdown links and anchors

2 participants