diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e45543..9ac40b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,11 @@ All notable changes to this project are documented here. The format follows [Kee - nuget.org's allowed image hosts moved from a property default to `nuget.allowed-image-hosts.txt` in the Packaging part, read only on pack; `MSKit_PackageReadmeAllowedImageHosts` still replaces it. +### Fixed + +- A test project with a single `` (net8.0, net9.0, net10.0) no longer fails with a false `MSKIT_TEST005`, and on net8.0/net9.0 gets `TestingPlatformDotnetTestSupport`: the TfmConstants part now evaluates `IsNETxx` again in the targets phase, after the csproj body has set the framework. The props-phase values stay for multi-targeted inner builds. +- `MSKIT_PKG016` no longer fires on GitLab and the other hosts the generated readme knows: with `MSKit_PackageReadmeFrom` set, an empty `PackageReleaseNotes` defaults to the releases page the readme links (`MSKit_ReleasesUrl`). GitHub keeps its tag release page; `MSKit_DefaultReleaseNotes=False` still turns the default off. + ## [0.1.1] - 2026-10-04 ### Fixed diff --git a/README.md b/README.md index a1a43d0..2008df9 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Default parts are always installed; add optional ones with `--add`. | `Core` | yes | Developer-vs-CI switch, solution and git roots, branch, `TargetFramework(s)` switching, Roslyn project-type detection | | `Trunk` (`DragoAnt.MSBuildKit`) | yes | Language defaults, product and copyright, the version engine, global usings, reference audits | | `Vcs.GitHub` | yes | Maps `GITHUB_*` variables: CI detection, run number, release tag, pull-request number, repository URL | -| `TfmConstants` | yes | `IsNET8` … `IsNET14`, `IsNET8_OR_GREATER` …, `IsNETSTANDARD` for conditions | +| `TfmConstants` | yes | `IsNET8` … `IsNET14`, `IsNET8_OR_GREATER` …, `IsNETSTANDARD` for conditions; final in item and target conditions and `Directory.Build.targets`, in the props phase only once the framework is known (an inner build of a multi-targeted project) | | `Packaging` | yes | nuget.org metadata defaults and the `MSKIT_PKG` checks | | `Testing`, `Testing.XUnit.v3` | yes | Test-project detection, Microsoft.Testing.Platform, coverage, TRX, xUnit v3 | | `Locals.Secrets`, `Locals.DirectorySecrets`, `Locals.Compile` | yes | Local-only secrets and source files kept outside the repository | @@ -103,7 +103,7 @@ Defaults apply to projects with `IsPackable=True` and yield to any value you set | `PackageIcon` | `.toolkit/res/package.icon.png` (128×128), packed as `icon.png` | [icon](https://learn.microsoft.com/nuget/create-packages/package-authoring-best-practices#icon) | | `PackageReadmeFile` | generated from `MSKit_PackageReadmeFrom` ([package readme](./docs/package-readme.md)), else `package.readme.md` (else `README.md`) next to the csproj, packed as `readme.md` | [README](https://learn.microsoft.com/nuget/reference/msbuild-targets#packagereadmefile) | | `RepositoryUrl`, `PackageProjectUrl` | from `GITHUB_REPOSITORY`, else the git remote via Source Link | [repository](https://learn.microsoft.com/nuget/create-packages/package-authoring-best-practices#repository-type-and-url) | -| `PackageReleaseNotes` | the GitHub release page of the tag, else the releases page | [release notes](https://learn.microsoft.com/nuget/create-packages/package-authoring-best-practices#release-notes) | +| `PackageReleaseNotes` | the GitHub release page of the tag, else the releases page; on other hosts, the releases page the generated readme links (`MSKit_PackageReadmeFrom`) | [release notes](https://learn.microsoft.com/nuget/create-packages/package-authoring-best-practices#release-notes) | | `PublishRepositoryUrl`, `EmbedUntrackedSources`, `Deterministic`, `ContinuousIntegrationBuild` (CI) | `true` | [Source Link](https://learn.microsoft.com/dotnet/standard/library-guidance/sourcelink) | | `IncludeSymbols`, `SymbolPackageFormat` | `true`, `snupkg` | [symbols](https://learn.microsoft.com/nuget/create-packages/symbol-packages-snupkg) | | `EnablePackageValidation` | `true`; baseline from `MSKit_PackageValidationBaselineVersion` | [package validation](https://learn.microsoft.com/dotnet/fundamentals/apicompat/package-validation/overview) | diff --git a/docs/package-readme.md b/docs/package-readme.md index a773aea..4ff4ed4 100644 --- a/docs/package-readme.md +++ b/docs/package-readme.md @@ -51,7 +51,7 @@ A self-hosted GitLab is recognised through the same item Source Link uses: | `MSKit_RepoProvider` | detected | `GitHub`, `GitLab`, `AzureDevOps`, `Bitbucket` or `Gitea` | | `MSKit_RepoBlobUrlTemplate` | the provider's | File links; a `/blob/` in it becomes `/tree/` for folders | | `MSKit_RepoRawUrlTemplate` | the provider's | Images | -| `MSKit_ReleasesUrl` | `auto` | The release-notes page; empty leaves the link out | +| `MSKit_ReleasesUrl` | `auto` | The release-notes page, also the default `PackageReleaseNotes` off GitHub; empty leaves the link out | | `MSKit_IssuesUrl` | `auto` | The issues page; empty leaves the link out | | `MSKit_RepositoryVisibility` | `$(CI_PROJECT_VISIBILITY)` | `private` or `internal` raises `MSKIT_PKG022` | | `MSKit_GeneratedPackageReadmePath` | `obj//package.readme.md` | Where the generated file goes | diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets index 2eb368d..563bc1e 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets @@ -93,7 +93,7 @@ Text="Package '$(PackageId)' icon is not a $(MSKit_PackageIconSize)x$(MSKit_PackageIconSize) PNG (PNG: $(_MSKit_IconIsPng), size: $(_MSKit_IconWidth)x$(_MSKit_IconHeight))." Rule="$(_MSKit_PkgRules)#icon" /> <_MSKit_PkgFinding Include="MSKIT_PKG016" Condition="'$(PackageReleaseNotes)'==''" - Text="Package '$(PackageId)' has no PackageReleaseNotes. Set them, or a link to the changelog (on GitHub the kit links the releases page by default)." + Text="Package '$(PackageId)' has no PackageReleaseNotes. Set them, or a link to the changelog (the kit links the releases page by default on GitHub, and on any host the generated readme knows with MSKit_PackageReadmeFrom)." Rule="$(_MSKit_PkgRules)#release-notes" /> <_MSKit_PkgFinding Include="MSKIT_PKG017" Condition="'$(_MSKit_RelativeLinks)'!=''" Text="The package README of '$(PackageId)' has relative links, which break on nuget.org: $(_MSKit_RelativeLinks). Use absolute URLs." diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.readme.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.readme.targets index ec44f4c..c94651e 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.readme.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.readme.targets @@ -9,6 +9,7 @@ $(MSBuildThisFileDirectory)nuget.allowed-image-hosts.txt <_MSKit_ReadmeStampPath>$(MSKit_GeneratedPackageReadmePath).inputs <_MSKit_ReadmeFindingsBase>$(MSKit_GeneratedPackageReadmePath).findings + <_MSKit_ReadmeReleasesUrlPath>$(MSKit_GeneratedPackageReadmePath).releases @@ -28,7 +29,7 @@ + DependsOnTargets="_MSKit_PackageReadmeInputs;_MSKit_WritePackageReadme;_MSKit_ReportPackageReadmeFindings;_MSKit_DefaultReleaseNotesFromReadme" /> + + + + + + + $(_MSKit_ReadmeReleasesUrl) + + + diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt index 94de646..d590633 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt @@ -118,6 +118,7 @@ public sealed class MSKit_PackageAssets : Task public string OutputPath { get; set; } public string FindingsBase { get; set; } + public string ReleasesUrlPath { get; set; } public string RepoRoot { get; set; } public string PackageId { get; set; } public string RepositoryUrl { get; set; } @@ -410,5 +411,7 @@ public sealed class MSKit_PackageAssets : Task File.WriteAllText(OutputPath, string.Join("\n", result) + "\n", utf8); foreach (var code in codes) File.WriteAllText(FindingsBase + "." + code + ".txt", string.Join("\n", findings[code]) + (findings[code].Count > 0 ? "\n" : ""), utf8); + if (!string.IsNullOrWhiteSpace(ReleasesUrlPath)) + File.WriteAllText(ReleasesUrlPath, releasesUrl.Length > 0 ? releasesUrl + "\n" : "", utf8); } } diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.TfmConstants/init.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.TfmConstants/init.targets new file mode 100644 index 0000000..6c58f27 --- /dev/null +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.TfmConstants/init.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.TfmConstants/tfm.constants.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.TfmConstants/tfm.constants.targets new file mode 100644 index 0000000..d68b6f9 --- /dev/null +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.TfmConstants/tfm.constants.targets @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + True + True + True + + True + + True + True + True + True + True + True + True + True + + True + True + True + True + True + True + True + True + + + + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + diff --git a/kit/.toolkit/msbuild/init.targets b/kit/.toolkit/msbuild/init.targets index 0385214..f4e11ab 100644 --- a/kit/.toolkit/msbuild/init.targets +++ b/kit/.toolkit/msbuild/init.targets @@ -3,6 +3,7 @@ + diff --git a/tests/fixtures/TfmConstants/.gitignore b/tests/fixtures/TfmConstants/.gitignore new file mode 100644 index 0000000..428d735 --- /dev/null +++ b/tests/fixtures/TfmConstants/.gitignore @@ -0,0 +1 @@ +.toolkit/ diff --git a/tests/fixtures/TfmConstants/Directory.Build.props b/tests/fixtures/TfmConstants/Directory.Build.props new file mode 100644 index 0000000..95daf71 --- /dev/null +++ b/tests/fixtures/TfmConstants/Directory.Build.props @@ -0,0 +1,5 @@ + + + + + diff --git a/tests/fixtures/TfmConstants/Directory.Build.targets b/tests/fixtures/TfmConstants/Directory.Build.targets new file mode 100644 index 0000000..07200a8 --- /dev/null +++ b/tests/fixtures/TfmConstants/Directory.Build.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/tests/fixtures/TfmConstants/Multi.Tests/Multi.Tests.csproj b/tests/fixtures/TfmConstants/Multi.Tests/Multi.Tests.csproj new file mode 100644 index 0000000..6c52674 --- /dev/null +++ b/tests/fixtures/TfmConstants/Multi.Tests/Multi.Tests.csproj @@ -0,0 +1,8 @@ + + + + net8.0;net10.0 + True + + + diff --git a/tests/fixtures/TfmConstants/Net10.Tests/Net10.Tests.csproj b/tests/fixtures/TfmConstants/Net10.Tests/Net10.Tests.csproj new file mode 100644 index 0000000..4340f62 --- /dev/null +++ b/tests/fixtures/TfmConstants/Net10.Tests/Net10.Tests.csproj @@ -0,0 +1,7 @@ + + + + net10.0 + + + diff --git a/tests/fixtures/TfmConstants/Net6.Tests/Net6.Tests.csproj b/tests/fixtures/TfmConstants/Net6.Tests/Net6.Tests.csproj new file mode 100644 index 0000000..dbc1517 --- /dev/null +++ b/tests/fixtures/TfmConstants/Net6.Tests/Net6.Tests.csproj @@ -0,0 +1,7 @@ + + + + net6.0 + + + diff --git a/tests/fixtures/TfmConstants/Net8.Tests/Net8.Tests.csproj b/tests/fixtures/TfmConstants/Net8.Tests/Net8.Tests.csproj new file mode 100644 index 0000000..58990cd --- /dev/null +++ b/tests/fixtures/TfmConstants/Net8.Tests/Net8.Tests.csproj @@ -0,0 +1,7 @@ + + + + net8.0 + + + diff --git a/tests/fixtures/TfmConstants/Net9.Tests/Net9.Tests.csproj b/tests/fixtures/TfmConstants/Net9.Tests/Net9.Tests.csproj new file mode 100644 index 0000000..1f059d7 --- /dev/null +++ b/tests/fixtures/TfmConstants/Net9.Tests/Net9.Tests.csproj @@ -0,0 +1,7 @@ + + + + net9.0 + + + diff --git a/tests/package-readme.sh b/tests/package-readme.sh index a958aa6..dc444d8 100644 --- a/tests/package-readme.sh +++ b/tests/package-readme.sh @@ -25,6 +25,11 @@ rf_count() { n=$(grep -cF -- "$2" "$out/readme-$1.md" || true) [ "$n" = "$3" ] && pass "readme $1 has $2 $3 time(s)" || bad "readme $1 has $2 $n time(s), expected $3" } +rf_notes() { + nupkg=$(ls "$out/readme-$1"/*.nupkg 2>/dev/null | grep -v '\.snupkg$' | head -n 1) + actual=$([ -n "$nupkg" ] && unzip -p "$nupkg" '*.nuspec' | tr -d '\r' | sed -n 's:.*\(.*\).*:\1:p') + [ "$actual" = "$2" ] && pass "readme $1 release notes '$actual'" || bad "readme $1 release notes: expected '$2', got '$actual'" +} generated="$readme_fixture/Observer/obj/Release/package.readme.md" # Pack only: a build never writes the generated readme. @@ -55,7 +60,8 @@ rf_has github "[fenced](./fenced.md)" rf_has github "" awk '/^## /{exit} /\[Release notes\]/{found=1} END{exit !found}' "$out/readme-github.md" \ && pass "readme github: the release-notes link is in the overview" || bad "readme github: the release-notes link is not in the overview" -for code in MSKIT_PKG009 MSKIT_PKG012 MSKIT_PKG017 MSKIT_PKG020 MSKIT_PKG021 MSKIT_PKG022; do rf_quiet github $code; done +for code in MSKIT_PKG009 MSKIT_PKG012 MSKIT_PKG016 MSKIT_PKG017 MSKIT_PKG020 MSKIT_PKG021 MSKIT_PKG022; do rf_quiet github $code; done +rf_notes github "https://github.com/DragoAnt/Fixture/releases" # Incremental: the same inputs leave the generated file alone; a new commit regenerates it. stamp1=$(stat -c %Y "$generated" 2>/dev/null || echo none) @@ -93,12 +99,25 @@ rf_has gitlab "[Release notes](https://gitlab.com/dragoant/sub/fixture/-/release rf_has gitlab "[Issues](https://gitlab.com/dragoant/sub/fixture/-/issues)" rf_quiet gitlab MSKIT_PKG021 rf_quiet gitlab MSKIT_PKG017 +rf_quiet gitlab MSKIT_PKG016 +rf_notes gitlab "https://gitlab.com/dragoant/sub/fixture/-/releases" +rf_pack gitlab-again Observer $gl +rf_quiet gitlab-again MSKIT_PKG016 +rf_notes gitlab-again "https://gitlab.com/dragoant/sub/fixture/-/releases" +rf_pack gitlab-no-releases Observer $gl -p:MSKit_ReleasesUrl= +rf_warns gitlab-no-releases MSKIT_PKG016 +rf_pack gitlab-no-default Observer $gl -p:MSKit_DefaultReleaseNotes=False +rf_warns gitlab-no-default MSKIT_PKG016 +rf_pack gitlab-notes Observer $gl "-p:PackageReleaseNotes=See the changelog." +rf_notes gitlab-notes "See the changelog." # Self-hosted GitLab recognised through SourceLinkGitLabHost: its raw images are not on nuget.org's list. rf_pack gitlab-self Observer -p:RepositoryUrl=https://git.example.org/team/fixture -p:RepositoryCommit=$sha -p:FixtureGitLabHost=git.example.org rf_has gitlab-self "[the guide](https://git.example.org/team/fixture/-/blob/$sha/$rel/docs/guide.md)" rf_has gitlab-self "![diagram](https://git.example.org/team/fixture/-/raw/$sha/$rel/docs/diagram.png)" rf_has gitlab-self "[Issues](https://git.example.org/team/fixture/-/issues)" +rf_quiet gitlab-self MSKIT_PKG016 +rf_notes gitlab-self "https://git.example.org/team/fixture/-/releases" rf_warns gitlab-self MSKIT_PKG021 grep "warning MSKIT_PKG021" "$out/readme-gitlab-self.log" | grep -q "line 11" \ && pass "readme gitlab-self: MSKIT_PKG021 names the README line" || bad "readme gitlab-self: MSKIT_PKG021 does not name line 11" @@ -109,7 +128,12 @@ grep "warning MSKIT_PKG021" "$out/readme-gitlab-self.log" | grep -q "img.shields rf_pack unknown Observer -p:RepositoryUrl=https://code.example.net/team/fixture -p:RepositoryCommit=$sha rf_warns unknown MSKIT_PKG020 rf_warns unknown MSKIT_PKG017 +rf_warns unknown MSKIT_PKG016 rf_has unknown "[the guide](./docs/guide.md)" +rf_pack unknown-releases Observer -p:RepositoryUrl=https://code.example.net/team/fixture -p:RepositoryCommit=$sha \ + "-p:MSKit_ReleasesUrl=https://code.example.net/team/fixture/changes" +rf_quiet unknown-releases MSKIT_PKG016 +rf_notes unknown-releases "https://code.example.net/team/fixture/changes" # Overrides: provider, templates, an empty releases URL (link omitted), a custom issues URL. rf_pack provider Observer -p:RepositoryUrl=https://code.example.net/team/fixture -p:RepositoryCommit=$sha -p:MSKit_RepoProvider=GitLab diff --git a/tests/run.sh b/tests/run.sh index d617556..b42d5b7 100644 --- a/tests/run.sh +++ b/tests/run.sh @@ -9,6 +9,7 @@ kit="$here/kit" sample="$here/samples/MinimalLibrary" fixtures="$here/tests/fixtures/PackageChecks" readme_fixture="$here/tests/fixtures/PackageReadme" +tfm_fixture="$here/tests/fixtures/TfmConstants" out="$here/dist/selftest" run_tests=1 [ "${1:-}" = "--skip-tests" ] && run_tests=0 @@ -18,7 +19,7 @@ failures=0 pass() { echo "PASS $*"; } bad() { echo "FAIL $*"; failures=$((failures+1)); } -for root in "$sample" "$fixtures" "$readme_fixture"; do +for root in "$sample" "$fixtures" "$readme_fixture" "$tfm_fixture"; do sh "$kit/.toolkit/update.sh" --source "$kit" --root "$root" > "$out/install.log" || { cat "$out/install.log"; exit 1; } done pass "update.sh installed the kit into the sample and the fixtures" @@ -106,6 +107,7 @@ $clean_env dotnet pack "$fixtures/BadPackage/BadPackage.csproj" -c Release -nolo grep -q "MSKIT_PKG" "$out/checks-skip.log" && bad "MSKit_SkipPackageChecks=All did not silence the checks" || pass "MSKit_SkipPackageChecks=All silences the checks" . "$here/tests/package-readme.sh" +. "$here/tests/tfm-constants.sh" echo if [ "$failures" -eq 0 ]; then echo "self-test: all checks passed"; else echo "self-test: $failures failure(s)"; exit 1; fi diff --git a/tests/tfm-constants.sh b/tests/tfm-constants.sh new file mode 100644 index 0000000..e65e60e --- /dev/null +++ b/tests/tfm-constants.sh @@ -0,0 +1,58 @@ +# TfmConstants: IsNETxx follows the TargetFramework a csproj sets, single or multi-targeted. +# Sourced by tests/run.sh: uses its pass, bad, $out, $here, $clean_env and $tfm_fixture. + +tfm_prop() { + $clean_env dotnet msbuild "$tfm_fixture/$1/$1.csproj" -nologo "-getProperty:$2" ${3:+"$3"} 2>&1 | tr -d '\r' | tail -n 1 +} +tfm_expect() { + actual=$(tfm_prop "$1" "$2" "${4:-}") + [ "$actual" = "$3" ] && pass "tfm $1${4:+ $4}: $2='$actual'" || bad "tfm $1${4:+ $4}: $2 expected '$3', got '$actual'" +} +tfm_validate() { + name="$1"; expect="$2"; shift 2 + if $clean_env dotnet msbuild "$tfm_fixture/$name/$name.csproj" -nologo -t:ValidateXUnitV3TFM "$@" > "$out/tfm-$name.log" 2>&1; then + [ "$expect" = ok ] && pass "tfm $name passes MSKIT_TEST005" || bad "tfm $name: expected MSKIT_TEST005, the check passed" + elif grep -q "MSKIT_TEST005" "$out/tfm-$name.log"; then + [ "$expect" = fail ] && pass "tfm $name fails with MSKIT_TEST005" || bad "tfm $name: false MSKIT_TEST005 (see $out/tfm-$name.log)" + else + bad "tfm $name: the check failed without MSKIT_TEST005 (see $out/tfm-$name.log)" + fi +} + +tfm_dir="$here/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.TfmConstants" +grep 'Condition=' "$tfm_dir/tfm.constants.props" > "$out/tfm-props.defs" +grep 'Condition=' "$tfm_dir/tfm.constants.targets" > "$out/tfm-targets.defs" +cmp -s "$out/tfm-props.defs" "$out/tfm-targets.defs" && [ -s "$out/tfm-props.defs" ] \ + && pass "tfm tfm.constants.targets defines the same constants as tfm.constants.props" \ + || bad "tfm tfm.constants.targets and tfm.constants.props differ (diff $out/tfm-props.defs $out/tfm-targets.defs)" +sed -n 's/.*<\([A-Za-z0-9_]*\) Condition=.*/\1/p' "$out/tfm-props.defs" | sort -u > "$out/tfm-defined.names" +sed -n 's/^ *<\([A-Za-z0-9_]*\)><\/\1>$/\1/p' "$tfm_dir/tfm.constants.targets" | sort -u > "$out/tfm-cleared.names" +cmp -s "$out/tfm-defined.names" "$out/tfm-cleared.names" \ + && pass "tfm tfm.constants.targets clears every constant before redefining it" \ + || bad "tfm cleared and defined constants differ (diff $out/tfm-defined.names $out/tfm-cleared.names)" + +for v in 8 9 10; do + tfm_expect "Net$v.Tests" IsNET8_OR_GREATER True + tfm_expect "Net$v.Tests" IsNET$v True + tfm_expect "Net$v.Tests" TargetFrameworkVersionMajor "$v" + tfm_validate "Net$v.Tests" ok +done +tfm_expect Net8.Tests TestingPlatformDotnetTestSupport True +tfm_expect Net9.Tests TestingPlatformDotnetTestSupport True +tfm_expect Net10.Tests TestingPlatformDotnetTestSupport "" + +tfm_expect Net6.Tests IsNET8_OR_GREATER "" +tfm_validate Net6.Tests fail + +# Multi-targeted: the outer build has no TargetFramework; each inner build gets it as a global +# property, so the constants are right in the props phase too (a csproj property condition). +tfm_expect Multi.Tests IsNET8 "" +tfm_expect Multi.Tests IsNET8 True -p:TargetFramework=net8.0 +tfm_expect Multi.Tests FixturePropsPhaseIsNet8 True -p:TargetFramework=net8.0 +tfm_expect Multi.Tests IsNET10_OR_GREATER True -p:TargetFramework=net10.0 +tfm_expect Multi.Tests IsNET8 "" -p:TargetFramework=net10.0 +tfm_validate Multi.Tests ok -p:TargetFramework=net8.0 + +$clean_env dotnet build "$tfm_fixture/Net10.Tests/Net10.Tests.csproj" -c Release -nologo > "$out/tfm-build.log" 2>&1 \ + && pass "tfm a single-TFM net10.0 xunit.v3 test project builds" \ + || { bad "tfm Net10.Tests build (see $out/tfm-build.log)"; grep -m 3 "error" "$out/tfm-build.log"; }