Skip to content

fix(link-checker): preserve changed filenames with special characters - #1429

Closed
BichengWang wants to merge 2 commits into
google-gemini:mainfrom
BichengWang:fix-link-checker-changed-paths
Closed

BichengWang wants to merge 2 commits into
google-gemini:mainfrom
BichengWang:fix-link-checker-changed-paths

Conversation

@BichengWang

Copy link
Copy Markdown
Contributor

check_all_links.py --changed silently skips filenames that Git quotes, including non-ASCII names. In a temporary Git repository, adding 指南.md with [Broken](missing.md) makes the current checker report no modified documents and exit 0.

Read NUL-delimited paths from git diff --name-only -z and preserve each filename when filtering documents. Add regressions for Unicode, embedded newlines, tabs, quotes, and leading spaces, including a CLI check that reports the broken link.

Validation:

  • All 20 tests pass with python3 -m unittest tools/test_check_all_links.py -v on Python 3.13; both new regressions fail before the fix.
  • A real temporary Git repository with all five filename cases now reports all five broken links and exits 1.
  • Python compilation, git diff --check, and the actual --changed CLI pass.

The full offline audit still reports the same two pre-existing broken links in the Weaviate examples as on the base commit.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request improves the reliability of the link checker tool when identifying changed files in a Git repository. By switching to NUL-delimited output from Git, the tool now correctly handles filenames that were previously skipped or incorrectly processed due to special characters or unconventional formatting.

Highlights

  • Robust Filename Handling: Updated the Git diff command to use the -z flag, ensuring that filenames with special characters, Unicode, or whitespace are correctly parsed by splitting on NUL bytes instead of newlines.
  • Regression Testing: Added comprehensive test cases to verify that the link checker correctly processes complex filenames, including those with tabs, newlines, quotes, and non-ASCII characters.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@github-actions github-actions Bot added the status:awaiting review PR awaiting review from a maintainer label Oct 15, 2026

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request updates the git diff command in tools/check_all_links.py to use the -z flag and split paths on null bytes, ensuring robust handling of special characters and newlines in filenames. Corresponding test cases were updated, and new tests were added to verify special character and Unicode filename handling. Feedback on the changes suggests explicitly specifying encoding="utf-8" in subprocess.check_output instead of using text=True to prevent potential UnicodeDecodeError or filename corruption on systems where the default encoding is not UTF-8.

Comment thread tools/check_all_links.py Resolved
@kkorpal kkorpal self-assigned this Oct 16, 2026
@kkorpal
kkorpal requested a review from Giom-V October 16, 2026 11:55
@kkorpal

kkorpal commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

Thanks @BichengWang , nice catch. Reproduced locally: on main, --changed silently skips a file like quickstarts/指南.md because git prints it quoted ("quickstarts/\346\214\207\345\215\227.md") and the .md check fails. With your branch it's picked up. Also checked the UTF-8 decoding follow-up: the new locale test fails against the previous commit (None != ['quickstarts/指南.md']) and passes on 7bf7fa8, so it's a real regression test. 21/21 pass. LGTM.

@BichengWang

Copy link
Copy Markdown
Contributor Author

Thanks for verifying, @kkorpal. Is anything else needed to merge this and #1432? Checks are green on both; I can wire #1432's formatter tests into CI if that's preferred.

@kkorpal kkorpal added the type:bug Something isn't working label Oct 27, 2026
@kkorpal

kkorpal commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request updates the internal link-checking tool (tools/check_all_links.py) to use null-terminated output (-z) when executing git diff, which ensures that filenames containing special characters, newlines, or Unicode are correctly preserved and decoded. It also updates existing tests and adds new test cases to verify this behavior. However, according to the repository style guide, changes to internal tooling are only accepted if they address a concrete bug actively affecting files on the main branch rather than theoretical edge cases. Furthermore, the style guide explicitly prohibits adding or maintaining unit tests for internal helper scripts under tools/, meaning the newly added test cases should be removed.

Comment on lines +403 to +464
def test_changed_files_preserves_special_characters(self) -> None:
"""Git paths must not be quoted, split on newlines, or stripped."""
paths = [
"quickstarts/指南.ipynb",
"quickstarts/line\nbreak.md",
"quickstarts/tab\tname.md",
'quickstarts/quoted"name.md',
" leading-space.md",
]
with mock.patch(
"tools.check_all_links.subprocess.check_output",
return_value="\0".join(paths + ["tools/check_all_links.py", ""]),
) as git_diff:
self.assertEqual(get_changed_files_from_git(self.repo_root), paths)
self.assertEqual(
git_diff.call_args.args[0],
["git", "diff", "--name-only", "-z", "upstream/main...HEAD"],
)

def test_changed_cli_audits_unicode_filename(self) -> None:
"""A changed Unicode filename must not hide a broken link from the CLI."""
target = self.quickstarts_dir / "指南.md"
target.write_text("[Broken](missing.md)\n", encoding="utf-8")
output = io.StringIO()
with (
mock.patch(
"tools.check_all_links.subprocess.check_output",
return_value="quickstarts/指南.md\0",
),
mock.patch.object(
sys,
"argv",
["check_all_links.py", "--repo-dir", str(self.repo_root), "--changed"],
),
contextlib.redirect_stdout(output),
self.assertRaises(SystemExit) as exit_context,
):
main()
self.assertEqual(exit_context.exception.code, 1, output.getvalue())
self.assertIn("quickstarts/指南.md", output.getvalue())
self.assertIn("File does not exist: missing.md", output.getvalue())

def test_changed_files_decodes_utf8_with_non_utf8_locale(self) -> None:
"""Unicode paths must survive subprocess decoding under an ASCII locale."""
path = "quickstarts/指南.md"
raw_output = (path + "\0").encode("utf-8")
check_output = subprocess.check_output
original_locale = locale.setlocale(locale.LC_CTYPE)
self.addCleanup(locale.setlocale, locale.LC_CTYPE, original_locale)
locale.setlocale(locale.LC_CTYPE, "C")

def git_diff_output(cmd, **kwargs):
return check_output(
[sys.executable, "-c", f"import sys; sys.stdout.buffer.write({raw_output!r})"],
**kwargs,
)

with mock.patch(
"tools.check_all_links.subprocess.check_output", side_effect=git_diff_output
):
self.assertEqual(get_changed_files_from_git(self.repo_root), [path])

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.

medium

According to the Repository Style Guide (under Internal tooling (tools/)), we do not want to multiply or maintain unit test suites for internal helper scripts, and we should ask to remove any new unit test files or unit test additions submitted for tools/. Please remove these new unit test additions (test_changed_files_preserves_special_characters, test_changed_cli_audits_unicode_filename, and test_changed_files_decodes_utf8_with_non_utf8_locale).

References
  1. Internal helper scripts under tools/ do not need unit tests, and we do not want to multiply or maintain unit test suites (tools/test_*.py). Never ask authors to add unit tests for tools/ changes, and ask to remove any new unit test files or unit test additions submitted for tools/. (link)

Comment thread tools/check_all_links.py
Comment on lines +308 to +312
cmd = ["git", "diff", "--name-only", "-z", f"{base}...HEAD"]
out = subprocess.check_output(
cmd, cwd=repo_root, encoding="utf-8", stderr=subprocess.DEVNULL
)
lines = [path for path in out.split("\0") if path.endswith((".md", ".ipynb"))]

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.

medium

According to the Repository Style Guide (under Internal tooling (tools/)), changes to internal scripts under tools/ are only accepted when they fix a concrete bug actively affecting existing notebooks, Markdown files, or CI checks on the main branch. If this PR only addresses theoretical or synthetic edge cases (such as files with non-ASCII or special characters in their names that do not currently exist on main), we recommend closing this PR. Could you clarify if there are any existing files on main currently affected by this issue?

References
  1. Changes to internal scripts under tools/ are only accepted when they fix a concrete bug actively affecting existing notebooks, Markdown files, or CI checks on the main branch. If a PR only addresses theoretical or synthetic edge cases that do not occur on main, call it out in the review and recommend closing it. (link)

@BichengWang

Copy link
Copy Markdown
Contributor Author

Checked this: no file on main (or anywhere in its history) has a name git would quote, and CI's link_checker.yml runs its own git diff instead of --changed, so nothing on main is hit today. Per the tools/ guidelines I'm closing this. Thanks @kkorpal for verifying it earlier.

@BichengWang BichengWang closed this Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status:awaiting review PR awaiting review from a maintainer type:bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants