diff --git a/AGENTS.md b/AGENTS.md index 69dde55..4e944d0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -35,7 +35,7 @@ Compatible with both SDK Pack and NuGetizer. Does not require NuGetizer. - **Fragment resolution**: explicit `` pairs win (placement controls whether a section title is included); otherwise GitHub heading auto-anchors match and **include the heading line** (e.g. `## Usage` for `#usage`). - **Token replacement**: after includes, `$token$` placeholders are replaced via `@(PackageReplacementToken)` (official NuGet: Id/Version/Author/Title/Description/Copyright/Configuration; plus Authors and Product; consumer-extensible). Case-insensitive names; **last value wins** for duplicates (never fails). Same item name as NuGetizer for coexistence; newer NuGetizers can adopt this model. - **`CollectReplacementTokens`**: populates default `@(PackageReplacementToken)` items. Depend on it before using tokens. Consumers add items anytime; `AfterTargets="CollectReplacementTokens"` to remove/replace defaults; `$(CollectReplacementTokensDependsOn)` / `BeforeTargets` for pre-work. -- **`ProcessPackageReadme`**: pack-time target (`DependsOnTargets=CollectReplacementTokens;$(ProcessPackageReadmeDependsOn)`) runs the process task then retargets pack items to the intermediate file. Does **not** warn on leftover `$token$` (readme may document that syntax). +- **`ProcessPackageReadme`**: pack-time target (`DependsOnTargets=CollectReplacementTokens;$(ProcessPackageReadmeDependsOn)`) runs the process task then retargets pack items to the intermediate file. Does **not** warn on leftover `$token$` (readme may document that syntax). Target-time `Update`/`Remove` must use `%(Identity)` + a `Condition` (or Remove of a filtered item list); `Update="path"` matches every `None`/`Content` item on Unix and clears `Pack` on license files (NU5030). - **`ReplacePackageTokens`**: public task for arbitrary InputFile→OutputFile replacement with `Tokens="@(PackageReplacementToken)"`. Emits **RDM001** for remaining unknown placeholders (suppress via `NoWarn`). Suitable for incremental targets (`Inputs`/`Outputs`). - **GitHub relative URLs**: after tokens, relative Markdown links/images are rewritten to `https://raw.githubusercontent.com/{owner}/{repo}/{commit}/…` when `ReadmeExpandGitHubUrls` is true (default), `RepositoryUrl` is a github.com absolute URL, and a commit is available (`RepositoryCommit` → `RepositorySha` → `SourceRevisionId`). Auto-skips otherwise. Opt out with `ReadmeExpandGitHubUrls=false`. Uses Markdig `LinkInline` + `NormalizeRenderer` (same as NuGetizer). - **ILRepack Markdig**: Markdig and its polyfill deps are internalized into `build/Readme.dll` so the package ships a single task assembly (no satellite DLLs under `build/`). diff --git a/src/Readme/build/Readme.targets b/src/Readme/build/Readme.targets index a34c22c..abc1773 100644 --- a/src/Readme/build/Readme.targets +++ b/src/Readme/build/Readme.targets @@ -81,8 +81,9 @@ - - + + + @@ -118,9 +119,9 @@ Condition="'$(IsPackable)' == 'true' and '$(PackReadme)' == 'true' and '$(PackageReadmeFile)' != ''"> - - <_ReadmeSourceFile Condition="'$(_ReadmeSourceFile)' == '' and Exists('$(MSBuildProjectDirectory)\$(PackageReadmeFile)')">$(MSBuildProjectDirectory)\$(PackageReadmeFile) - <_ReadmeSourceFile Condition="'$(_ReadmeSourceFile)' == '' and Exists('$(PackageReadmeFile)')">$(PackageReadmeFile) + + <_ReadmeSourceFile Condition="'$(_ReadmeSourceFile)' == '' and Exists('$(MSBuildProjectDirectory)\$(PackageReadmeFile)')">$([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '$(PackageReadmeFile)')) + <_ReadmeSourceFile Condition="'$(_ReadmeSourceFile)' == '' and Exists('$(PackageReadmeFile)')">$([MSBuild]::NormalizePath('$(PackageReadmeFile)')) <_ReadmePackagePath Condition="'$(_ReadmePackagePath)' == ''">$(PackageReadmeFilename)$(PackageReadmeExtension) @@ -160,11 +161,15 @@ 'readme' would also hit Readme.props / Readme.targets / Readme.dll). --> - - + + + - + <_ReadmeProcessedNone Include="@(None)" Condition="'%(None.FullPath)' == '$(_ReadmeProcessedFile)'" /> + e.FullName).ToList(); - File.WriteAllLines(Path.Combine(evidenceDir, "nupkg-entries.txt"), entries); - Assert.DoesNotContain(entries, e => e.Equals("readme.md", StringComparison.OrdinalIgnoreCase)); - } + var entries = ZipEntries(nupkg); + File.WriteAllLines(Path.Combine(evidenceDir, "nupkg-entries.txt"), entries); + Assert.DoesNotContain(entries, e => e.Equals("readme.md", StringComparison.OrdinalIgnoreCase)); + Assert.Contains(entries, e => e.Equals("OSMFEULA.txt", StringComparison.Ordinal)); var nuspec = ReadPackageEntry(nupkg, "PackReadmeFalseSample.nuspec"); File.WriteAllText(Path.Combine(evidenceDir, "package.nuspec"), nuspec); Assert.DoesNotContain("", nuspec, StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("NU5039", File.ReadAllText(packLog), StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("NU5030", File.ReadAllText(packLog), StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SdkPack_DoesNotClearPackOnLicenseOrOtherNoneItems() + { + var evidenceDir = Path.Combine(ScratchRoot, "sdk-pack-license"); + Directory.CreateDirectory(evidenceDir); + + var work = PrepareScenario("SdkPackLicense", evidenceDir); + var packed = EnsureReadmePackage(evidenceDir); + InjectLocalFeedAndReference(work, packed, useNuGetizer: false); + + var packLog = Path.Combine(evidenceDir, "pack.log"); + var exit = RunDotnet( + $"pack \"{Path.Combine(work, "SdkPackLicense.csproj")}\" -c Release -o \"{Path.Combine(work, "out")}\" -v:n", + work, packLog); + Assert.True(exit == 0, $"SDK pack with license file failed (NU5030?). See {packLog}\n{File.ReadAllText(packLog)}"); + + var nupkg = Directory.GetFiles(Path.Combine(work, "out"), "*.nupkg").Single(); + var entries = ZipEntries(nupkg); + File.WriteAllLines(Path.Combine(evidenceDir, "nupkg-entries.txt"), entries); + Assert.Contains(entries, e => e.Equals("OSMFEULA.txt", StringComparison.Ordinal)); + Assert.Contains(entries, e => e.Equals("NOTICE.txt", StringComparison.Ordinal)); + Assert.Contains(entries, e => e.Equals("readme.md", StringComparison.OrdinalIgnoreCase)); + Assert.DoesNotContain("NU5030", File.ReadAllText(packLog), StringComparison.OrdinalIgnoreCase); + + var nuspec = ReadPackageEntry(nupkg, "SdkPackLicenseSample.nuspec"); + Assert.Contains("OSMFEULA.txt", nuspec, StringComparison.Ordinal); + } + + static IReadOnlyList ZipEntries(string nupkg) + { + using var zip = ZipFile.OpenRead(nupkg); + return zip.Entries.Select(e => e.FullName).ToList(); } string PrepareScenario(string name, string evidenceDir) diff --git a/src/Tests/Scenarios/PackReadmeFalse/OSMFEULA.txt b/src/Tests/Scenarios/PackReadmeFalse/OSMFEULA.txt new file mode 100644 index 0000000..4d2fdf8 --- /dev/null +++ b/src/Tests/Scenarios/PackReadmeFalse/OSMFEULA.txt @@ -0,0 +1 @@ +OSMF EULA for PackReadme=false pack regression. diff --git a/src/Tests/Scenarios/PackReadmeFalse/PackReadmeFalse.csproj b/src/Tests/Scenarios/PackReadmeFalse/PackReadmeFalse.csproj index 4c127c2..f3f28f3 100644 --- a/src/Tests/Scenarios/PackReadmeFalse/PackReadmeFalse.csproj +++ b/src/Tests/Scenarios/PackReadmeFalse/PackReadmeFalse.csproj @@ -12,5 +12,11 @@ true false + OSMFEULA.txt + true + + + + diff --git a/src/Tests/Scenarios/SdkPackLicense/Class1.cs b/src/Tests/Scenarios/SdkPackLicense/Class1.cs new file mode 100644 index 0000000..876c902 --- /dev/null +++ b/src/Tests/Scenarios/SdkPackLicense/Class1.cs @@ -0,0 +1,6 @@ +namespace SdkPackLicense +{ + public class Class1 + { + } +} diff --git a/src/Tests/Scenarios/SdkPackLicense/NOTICE.txt b/src/Tests/Scenarios/SdkPackLicense/NOTICE.txt new file mode 100644 index 0000000..5fe1f48 --- /dev/null +++ b/src/Tests/Scenarios/SdkPackLicense/NOTICE.txt @@ -0,0 +1 @@ +Notice file that must stay packed. diff --git a/src/Tests/Scenarios/SdkPackLicense/OSMFEULA.txt b/src/Tests/Scenarios/SdkPackLicense/OSMFEULA.txt new file mode 100644 index 0000000..20eea7f --- /dev/null +++ b/src/Tests/Scenarios/SdkPackLicense/OSMFEULA.txt @@ -0,0 +1 @@ +OSMF EULA for pack regression. diff --git a/src/Tests/Scenarios/SdkPackLicense/SdkPackLicense.csproj b/src/Tests/Scenarios/SdkPackLicense/SdkPackLicense.csproj new file mode 100644 index 0000000..5a2fc44 --- /dev/null +++ b/src/Tests/Scenarios/SdkPackLicense/SdkPackLicense.csproj @@ -0,0 +1,18 @@ + + + netstandard2.0 + true + SdkPackLicenseSample + 1.0.0 + false + false + false + true + OSMFEULA.txt + true + + + + + + diff --git a/src/Tests/Scenarios/SdkPackLicense/readme.md b/src/Tests/Scenarios/SdkPackLicense/readme.md new file mode 100644 index 0000000..7a5e6df --- /dev/null +++ b/src/Tests/Scenarios/SdkPackLicense/readme.md @@ -0,0 +1 @@ +# SdkPackLicense sample