API docs: infer git root for Edit on GitHub/source links#76
API docs: infer git root for Edit on GitHub/source links#76PrzemyslawKlys merged 1 commit intomainfrom
Conversation
Code Review for PR #76: API docs: infer git root for Edit on GitHub/source linksSummaryThis PR improves the source link generation for API documentation by automatically inferring the git root when Code Quality ✅Strengths:
Suggestions:
/// <summary>
/// Walks up from the specified path to find the nearest .git folder or file.
/// </summary>
/// <param name="path">Starting path (file or directory).</param>
/// <returns>The git root directory, or null if not found.</returns>
private static string? TryFindGitRoot(string path)
catch (Exception ex)
{
// best-effort - silently return null on any I/O errors
Trace.TraceWarning($"TryFindGitRoot failed: {ex.Message}");
}Potential Issues 🟡
Performance Considerations ✅
Security Concerns ✅
Test Coverage
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 639944b9d0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| { | ||
| try | ||
| { | ||
| var current = Directory.Exists(path) ? path : Path.GetDirectoryName(path); |
There was a problem hiding this comment.
Normalize path before searching for git root
TryFindGitRoot climbs parents from the raw assemblyPath string, so when the assembly is passed as a relative path like bin/Release/net10.0/MyLib.dll (a valid CLI input), Path.GetDirectoryName can terminate at an empty segment before ever checking the working directory’s .git. In that case Create treats git root discovery as failed and clears SourceUrlPattern, so source URLs are omitted even though the repo root is available.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Updates API docs source-link generation so that when SourceUrlPattern is set but SourceRootPath is not, the generator attempts to infer a suitable SourceRootPath by walking up to the nearest git root from the assembly location. If a git root cannot be found, it omits source URLs and emits a warning instead of generating broken URLs.
Changes:
- Infer
SourceRootPathvia a newTryFindGitRoothelper when onlySourceUrlPatternis provided. - Suppress URL generation (set pattern to null) with a warning when neither
SourceRootPathnor a git root can be determined.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (string.IsNullOrWhiteSpace(root) && !string.IsNullOrWhiteSpace(pattern)) | ||
| { | ||
| warnings.Add("SourceUrlPattern set without SourceRootPath (and git root not found); source URLs will be omitted."); | ||
| pattern = null; |
There was a problem hiding this comment.
When no SourceRootPath is provided and git root detection fails, this code sets pattern = null but still creates a SourceLinkContext. BuildSourceLink will then return ApiSourceLink objects whose Path is the absolute local file path from the PDB, and RenderSourceLink/BuildSourceJson will expose that path in the output even though the URL is omitted. Consider suppressing the entire source link (return null from BuildSourceLink or SourceLinkContext.Create) or at least sanitizing Path (e.g., make it relative/filename-only) when _sourceRoot is null to avoid leaking build-machine paths.
| if (string.IsNullOrWhiteSpace(root) && !string.IsNullOrWhiteSpace(pattern)) | |
| { | |
| warnings.Add("SourceUrlPattern set without SourceRootPath (and git root not found); source URLs will be omitted."); | |
| pattern = null; | |
| if (string.IsNullOrWhiteSpace(root)) | |
| { | |
| if (!string.IsNullOrWhiteSpace(pattern)) | |
| { | |
| warnings.Add("SourceUrlPattern set without SourceRootPath (and git root not found); source URLs will be omitted."); | |
| } | |
| // Without a resolved source root, exposing paths from the PDB may leak | |
| // absolute build-machine paths. Suppress source links in this case. | |
| provider.Dispose(); | |
| stream.Dispose(); | |
| return null; |
| else if (!string.IsNullOrWhiteSpace(options.SourceUrlPattern)) | ||
| { | ||
| // If the project lives in a subfolder of a repo, using the git root as SourceRootPath | ||
| // keeps generated URLs consistent (and avoids missing prefixes like "IntelligenceX/..."). | ||
| root = TryFindGitRoot(assemblyPath); | ||
| } |
There was a problem hiding this comment.
TryFindGitRoot may fail unexpectedly when options.AssemblyPath is relative or when the current working directory differs from the assembly location, because it walks up from the input path without normalizing it. Consider calling Path.GetFullPath on assemblyPath (or on current) before searching so git root inference is deterministic.
| var current = Directory.Exists(path) ? path : Path.GetDirectoryName(path); | ||
| while (!string.IsNullOrWhiteSpace(current)) | ||
| { | ||
| var git = Path.Combine(current, ".git"); | ||
| if (Directory.Exists(git) || File.Exists(git)) | ||
| return current; |
There was a problem hiding this comment.
In TryFindGitRoot, var current = Directory.Exists(path) ? path : Path.GetDirectoryName(path); can leave current as a relative path and can also be null if Path.GetDirectoryName returns null. It would be clearer/safer to early-return when current is null and to normalize current to a full path before entering the loop, so the .git probing is consistent.
If SourceUrlPattern is set but SourceRootPath is not, infer SourceRootPath from the nearest git root (walking up from the built assembly). This fixes Edit-on-GitHub/source URLs for repos where projects live in subfolders (e.g. IntelligenceX/...). If no git root is found, source URLs are omitted with a warning instead of producing broken absolute-path URLs.