Skip to content

Commit b79b0d3

Browse files
committed
Add support for repository url relative URLs in readme
This allows permalinks at pack time by turning non-absolute URLs to repository-relative blob+commit URLs. We don't use the branch/tag since that isn't necessarily permanent. Since the repository metadata for the package is immutable, we map the URL to an equally immutable full path URL. Fixes #641
1 parent e113040 commit b79b0d3

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

src/NuGetizer.Tasks/CreatePackage.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public class CreatePackage : Task
4444
Manifest manifest;
4545
Dictionary<string, string> tokens;
4646
Regex tokensExpr;
47+
Regex linkExpr;
4748

4849
public override bool Execute()
4950
{
@@ -230,6 +231,26 @@ void GeneratePackage(Stream output = null)
230231
{
231232
// replace readme with includes replaced.
232233
var replaced = ReplaceTokens(IncludesResolver.Process(readmeFile.Source, message => Log.LogWarningCode("NG001", message)));
234+
235+
if (manifest.Metadata.Repository?.Type == "git" &&
236+
!string.IsNullOrEmpty(manifest.Metadata.Repository?.Commit) &&
237+
Uri.TryCreate(manifest.Metadata.Repository.Url, UriKind.Absolute, out var uri) &&
238+
uri.Host.EndsWith("github.com"))
239+
{
240+
// expr to match markdown links. use named groups to capture the link text and url.
241+
linkExpr ??= new Regex(@"\[(?<text>[^\]]+)\]\((?<url>[^)]+)\)", RegexOptions.None);
242+
var repoUrl = manifest.Metadata.Repository.Url.TrimEnd('/');
243+
replaced = linkExpr.Replace(replaced, match =>
244+
{
245+
var url = match.Groups["url"].Value;
246+
if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
247+
return match.Value;
248+
249+
var newUrl = $"{repoUrl}/blob/{manifest.Metadata.Repository.Commit}/{url.TrimStart('/')}";
250+
return $"[{match.Groups["text"].Value}]({newUrl})";
251+
});
252+
}
253+
233254
if (!replaced.Equals(File.ReadAllText(readmeFile.Source), StringComparison.Ordinal))
234255
{
235256
var temp = Path.GetTempFileName();

src/NuGetizer.Tests/CreatePackageTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,42 @@ public void when_readme_has_include_and_tokens_then_replacements_applied()
300300
Assert.Contains("NuGetizer", readme);
301301
}
302302

303+
[Fact]
304+
public void when_readme_has_relativeurl_then_expands_github_url()
305+
{
306+
var content = Path.GetTempFileName();
307+
File.WriteAllText(content, "See [license](license.txt).");
308+
task.Contents = new[]
309+
{
310+
new TaskItem(content, new Metadata
311+
{
312+
{ MetadataName.PackageId, task.Manifest.GetMetadata("Id") },
313+
{ MetadataName.PackFolder, PackFolderKind.None },
314+
{ MetadataName.PackagePath, "readme.md" }
315+
}),
316+
};
317+
318+
task.Manifest.SetMetadata("Readme", "readme.md");
319+
task.Manifest.SetMetadata("RepositoryType", "git");
320+
task.Manifest.SetMetadata("RepositoryUrl", "https://github.com/devlooped/nugetizer");
321+
task.Manifest.SetMetadata("RepositorySha", "9dc2cb5de");
322+
323+
createPackage = true;
324+
ExecuteTask(out var manifest);
325+
326+
Assert.NotNull(manifest);
327+
328+
Assert.Equal("readme.md", manifest.Metadata.Readme);
329+
330+
var file = manifest.Files.FirstOrDefault(f => Path.GetFileName(f.Target) == manifest.Metadata.Readme);
331+
Assert.NotNull(file);
332+
Assert.True(File.Exists(file.Source));
333+
334+
var readme = File.ReadAllText(file.Source);
335+
336+
Assert.Contains("[license](https://github.com/devlooped/nugetizer/blob/9dc2cb5de/license.txt)", readme);
337+
}
338+
303339
[Fact]
304340
public void when_creating_package_with_simple_dependency_then_contains_dependency_group()
305341
{

0 commit comments

Comments
 (0)