diff --git a/CHANGELOG.md b/CHANGELOG.md index 868b09b..2f4ca31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,13 @@ All notable changes to this project are documented here. The format follows [Kee ## [Unreleased] +### Breaking changes + +- Warning and error codes drop the underscore after the prefix: `MSKITVER006`, `MSKITPKG015`, and so on, with the same family and number. `NoWarn`, `WarningsAsErrors`, `WarningsNotAsErrors` and `MSKit_SkipPackageChecks` entries that name a code the old way no longer match: rename them. Each section of the [code reference](./docs/reference/codes.md) names the code's former spelling. + ### Added +- Every warning and error links to its section of the [code reference](./docs/reference/codes.md) (`HelpLink`, shown by the terminal logger and IDEs). `MSKit_CodesHelpBaseUrl` points the links at another copy of the page. - `manager/`: the first build of `mskit-manager`, the `DragoAnt.MSBuildKit.Manager` .NET tool (`net8.0`, `net10.0`, `RollForward=Major`) that will install, update and migrate the kit. This build has one command, `status [--json]`, which prints the tool version; the logo goes to stderr, only on a terminal and never with `--no-logo`, so `--json` output always parses. Each run writes a log under `/mskit-manager/logs/`, named after the command, newest 20 kept. Not published yet. ### Changed @@ -14,7 +19,7 @@ All notable changes to this project are documented here. The format follows [Kee ### Fixed -- A JPEG `PackageIconPath` no longer fails `dotnet pack` with NU5046: the icon is packed as `icon.`, lowercased (`icon.jpg`), and the nuspec names that file. `MSKIT_PKG015` accepts a 128×128 JPEG as well as a PNG, as nuget.org does ([#11](https://github.com/DragoAnt/MSBuildKit/pull/11)). +- A JPEG `PackageIconPath` no longer fails `dotnet pack` with NU5046: the icon is packed as `icon.`, lowercased (`icon.jpg`), and the nuspec names that file. `MSKITPKG015` accepts a 128×128 JPEG as well as a PNG, as nuget.org does ([#11](https://github.com/DragoAnt/MSBuildKit/pull/11)). ## [0.2.1] - 2026-10-05 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 762d448..51e5470 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,7 @@ You need the .NET 10 SDK and the .NET 8 runtime, plus `sh` (Git Bash on Windows) sh tests/run.sh ``` -It installs the working-tree kit into the sample and the fixtures with `update.sh`, then checks the computed versions for local, branch, pull-request and tag builds, runs the sample's tests with coverage, inspects the packed nuspec, asserts that every `MSKIT_PKG` check fires on the fixtures, and runs `sh tools/docs-check.sh`. CI runs the same script on Linux and Windows. +It installs the working-tree kit into the sample and the fixtures with `update.sh`, then checks the computed versions for local, branch, pull-request and tag builds, runs the sample's tests with coverage, inspects the packed nuspec, asserts that every `MSKITPKG` check fires on the fixtures, and runs `sh tools/docs-check.sh`. CI runs the same script on Linux and Windows. The tool's tests run from `manager/`, so its `global.json` selects Microsoft.Testing.Platform: @@ -32,7 +32,7 @@ CI's `manager` job also packs the tool, installs it into a tool path and runs `m ## Changing the kit - A new property defaults with `Condition="'$(Name)'==''"`, so a consumer's value always wins, and gets a row in [docs/reference/properties.md](./docs/reference/properties.md) plus a mention on its topic page. -- A new check gets an `MSKIT_` code (a shipped code is never renumbered or reused), a message that says how to fix it, a section in [docs/reference/codes.md](./docs/reference/codes.md) headed by the code id without the underscore, a fixture that triggers it and a line in `tests/run.sh`. +- A new check gets an `MSKIT` code with no separator (a shipped code is never renumbered or reused), a `HelpLink="$(MSKit_CodesHelpBaseUrl)#"`, a message that says how to fix it, a section in [docs/reference/codes.md](./docs/reference/codes.md) headed by the code, a fixture that triggers it and a line in `tests/run.sh`. - `sh tools/docs-check.sh` fails on a property, item or code without its reference entry, on a name the docs mention that the kit lacks, and on a broken relative link; `--list properties|items|codes` prints the kit's inventory with the file and line of each. - The README stays short: key features, install, links. Detail goes to the topic page in `docs/`. - A new part needs a line in `kit/.toolkit/kit.parts` and its `init.props` / `init.targets` imports in the entry points. diff --git a/README.md b/README.md index 686c0b5..15fc5a1 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Shared MSBuild settings for .NET repositories that publish NuGet packages: nuget ## Key features -- **Packages that pass nuget.org's rules by default.** Licence, icon, README, [Source Link](https://learn.microsoft.com/dotnet/standard/library-guidance/sourcelink), symbols, repository and release-notes links, [package validation](https://learn.microsoft.com/dotnet/fundamentals/apicompat/package-validation/overview) and [NuGet audit](https://learn.microsoft.com/nuget/concepts/auditing-packages); nineteen `MSKIT_PKG` checks run on `dotnet pack`, warnings on your machine and errors on CI. [Packaging](./docs/packaging.md) +- **Packages that pass nuget.org's rules by default.** Licence, icon, README, [Source Link](https://learn.microsoft.com/dotnet/standard/library-guidance/sourcelink), symbols, repository and release-notes links, [package validation](https://learn.microsoft.com/dotnet/fundamentals/apicompat/package-validation/overview) and [NuGet audit](https://learn.microsoft.com/nuget/concepts/auditing-packages); nineteen `MSKITPKG` checks run on `dotnet pack`, warnings on your machine and errors on CI. [Packaging](./docs/packaging.md) - **One README for the repository and its packages.** `MSKit_PackageReadmeFrom=README.md` generates each package's readme on pack, with links pinned to the commit. [Package readme](./docs/package-readme.md) - **Versions from release tags.** Tag `v1.4.0` and the packages are `1.4.0`; branch builds are `1.4.0-ci.`, pull requests `1.4.0-pr..`, local builds `9999.0.0`. [Versioning](./docs/versioning.md) - **Tests on Microsoft.Testing.Platform v2.** Projects named `*.Tests` become [xUnit v3](https://xunit.net/docs/getting-started/v3/microsoft-testing-platform) test projects with coverage, TRX and JUnit reports, an assertion library and [NSubstitute](https://nsubstitute.github.io/). [Testing](./docs/testing.md) diff --git a/docs/README.md b/docs/README.md index 9068739..b3055a7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,7 +11,7 @@ Read in this order; each page stands on its own, so jump to the one you need. | 5 | [Versioning](./versioning.md) | control how package versions are computed | | 6 | [Local files and secrets](./local-files.md) | keep secrets and machine-only source files out of the repository | | 7 | [Optional parts](./optional-parts.md) | debug a dependency from source, list a project's packages, run Entity Framework migrations | -| 8 | [Packaging](./packaging.md) | understand the nuget.org defaults and the `MSKIT_PKG` checks | +| 8 | [Packaging](./packaging.md) | understand the nuget.org defaults and the `MSKITPKG` checks | | 9 | [Package readme](./package-readme.md) | generate every package's readme from the repository README | | 10 | [Testing](./testing.md) | set up test projects, assertions, mocking and coverage | | 11 | [Roslyn components](./roslyn.md) | build analyzers, code fixes and source generators | diff --git a/docs/build.md b/docs/build.md index 9956b9a..b5ffa0a 100644 --- a/docs/build.md +++ b/docs/build.md @@ -24,7 +24,7 @@ The owner layer adds `IsPackable=True`, `TreatWarningsAsErrors=True`, `NoWarn` ` | | Developer machine | CI | | --- | --- | --- | | Version | `9999.0.0` | from the tag, pull request or run ([Versioning](./versioning.md)) | -| `MSKIT_PKG` checks | warnings | errors ([Packaging](./packaging.md)) | +| `MSKITPKG` checks | warnings | errors ([Packaging](./packaging.md)) | | [`ContinuousIntegrationBuild`](https://learn.microsoft.com/dotnet/core/project-sdk/msbuild-props#continuousintegrationbuild) | unset (PDBs keep real paths) | `true` | | Local secrets | created from templates | deleted ([Local files](./local-files.md)) | | `TreatWarningsAsErrors` drift check | on | off: CI passes its own `-p:TreatWarningsAsErrors` | @@ -52,9 +52,9 @@ Declare `TargetFramework` or `TargetFrameworks` once, in `Directory.Build.props` | Code | When | | --- | --- | -| [`MSKIT_SHARED006`](./reference/codes.md#mskitshared006), [`MSKIT_SHARED007`](./reference/codes.md#mskitshared007) | error: the csproj repeats the shared `TargetFramework` / `TargetFrameworks` value | -| [`MSKIT_SHARED008`](./reference/codes.md#mskitshared008), [`MSKIT_SHARED009`](./reference/codes.md#mskitshared009) | warning: the csproj sets a different value of the same shape; `MSKit_SkipAudit_TargetFrameworkOverride=True` accepts it | -| [`MSKIT_SHARED010`](./reference/codes.md#mskitshared010) | error: the csproj declares both shapes | +| [`MSKITSHARED006`](./reference/codes.md#mskitshared006), [`MSKITSHARED007`](./reference/codes.md#mskitshared007) | error: the csproj repeats the shared `TargetFramework` / `TargetFrameworks` value | +| [`MSKITSHARED008`](./reference/codes.md#mskitshared008), [`MSKITSHARED009`](./reference/codes.md#mskitshared009) | warning: the csproj sets a different value of the same shape; `MSKit_SkipAudit_TargetFrameworkOverride=True` accepts it | +| [`MSKITSHARED010`](./reference/codes.md#mskitshared010) | error: the csproj declares both shapes | `MSKit_GuardXmlPeekRoutine=False` and `MSKit_GuardXmlPeekAudit=False` turn off a cheap text pre-check and always parse the csproj; leave them alone unless a declaration is missed. @@ -86,7 +86,7 @@ A project with `ExcludeFromCodeCoverage=true` gets the [`[ExcludeFromCodeCoverag ## Central package versions -The parts that add package references also provide their versions: as `PackageVersion` items with [central package management](https://learn.microsoft.com/nuget/consume-packages/central-package-management), else on the `PackageReference` itself when it has no version. Each version is a property you can override, `MSKit_PackageVersion_` (lists: [Testing](./testing.md#package-versions), [Roslyn](./roslyn.md#package-versions)); `MSKit_ImplicitPackageVersions=False` turns them all off. A `PackageVersion` of yours for the same id fails restore with [`MSKIT_DUP001`](./reference/codes.md#mskitdup001) (bypass: `MSKit_SkipAudit_ImplicitPackageDuplicates=True`). +The parts that add package references also provide their versions: as `PackageVersion` items with [central package management](https://learn.microsoft.com/nuget/consume-packages/central-package-management), else on the `PackageReference` itself when it has no version. Each version is a property you can override, `MSKit_PackageVersion_` (lists: [Testing](./testing.md#package-versions), [Roslyn](./roslyn.md#package-versions)); `MSKit_ImplicitPackageVersions=False` turns them all off. A `PackageVersion` of yours for the same id fails restore with [`MSKITDUP001`](./reference/codes.md#mskitdup001) (bypass: `MSKit_SkipAudit_ImplicitPackageDuplicates=True`). `PrivateAssets=all` is set on references to `Fody`, `ConfigureAwait.Fody`, `IgnoresAccessChecksToGenerator`, `Grpc.Tools`, `Microsoft.EntityFrameworkCore.Design` and `Microsoft.EntityFrameworkCore.Tools`, so these build-time tools never become package dependencies. Add your own `Update` items in `Directory.Packages.Metadata.targets`. @@ -101,13 +101,13 @@ The parts that add package references also provide their versions: as `PackageVe ``` -A reference to a `Type="Error"` package fails with [`MSKIT_RES001`](./reference/codes.md#mskitres001), a `Type="Warning"` one warns with [`MSKIT_RES002`](./reference/codes.md#mskitres002). `SkipGlobalRestriction="True"` on one `PackageReference` allows it (an error becomes a warning). The owner layer bans `Moq`. +A reference to a `Type="Error"` package fails with [`MSKITRES001`](./reference/codes.md#mskitres001), a `Type="Warning"` one warns with [`MSKITRES002`](./reference/codes.md#mskitres002). `SkipGlobalRestriction="True"` on one `PackageReference` allows it (an error becomes a warning). The owner layer bans `Moq`. -**Allow-list mode.** With `MSKit_RestrictProjectReferences=True` (or `MSKit_RestrictPackageReferences`, or `MSKit_RestrictReferences` for both) every reference must carry `Allowed="True"`, else [`MSKIT_RES003`](./reference/codes.md#mskitres003) / [`MSKIT_RES004`](./reference/codes.md#mskitres004). Off by default. +**Allow-list mode.** With `MSKit_RestrictProjectReferences=True` (or `MSKit_RestrictPackageReferences`, or `MSKit_RestrictReferences` for both) every reference must carry `Allowed="True"`, else [`MSKITRES003`](./reference/codes.md#mskitres003) / [`MSKITRES004`](./reference/codes.md#mskitres004). Off by default. -**Prerelease dependencies on a stable branch.** On a stable branch a reference to a prerelease version of a package whose id starts with `MSKit_PrereleasePackagePrefix` (owner layer: `DragoAnt.`) warns with [`MSKIT_PRE001`](./reference/codes.md#mskitpre001); `MSKit_PrereleasePackageCheckAsWarning=false` makes it an error. +**Prerelease dependencies on a stable branch.** On a stable branch a reference to a prerelease version of a package whose id starts with `MSKit_PrereleasePackagePrefix` (owner layer: `DragoAnt.`) warns with [`MSKITPRE001`](./reference/codes.md#mskitpre001); `MSKit_PrereleasePackageCheckAsWarning=false` makes it an error. -**`TreatWarningsAsErrors` drift.** On a developer machine a csproj that changes the shared `TreatWarningsAsErrors` fails with [`MSKIT_SHARED020`](./reference/codes.md#mskitshared020); `MSKit_SkipAudit_TreatWarningsAsErrors=True` allows it. +**`TreatWarningsAsErrors` drift.** On a developer machine a csproj that changes the shared `TreatWarningsAsErrors` fails with [`MSKITSHARED020`](./reference/codes.md#mskitshared020); `MSKit_SkipAudit_TreatWarningsAsErrors=True` allows it. ## Private references diff --git a/docs/customizing.md b/docs/customizing.md index 92d1eeb..351030a 100644 --- a/docs/customizing.md +++ b/docs/customizing.md @@ -32,7 +32,7 @@ Almost every default is written as ``, so the first va | `MSKit_TestingFramework`, `MSKit_TestsAssertions` | `xunit.v3`, `AwesomeAssertions` | [Testing](./testing.md) | | `MSKit_RestrictPackageReference` | `Moq` as an error | [reference checks](./build.md#reference-checks) | -**Another owner:** fork the kit, change `kit/.toolkit/msbuild/init.company.props` (and `.targets`) and `kit/.toolkit/res/package.icon.png`, publish releases from the fork and install with `update.sh --repo /` (recorded in `kit.json`, so later updates come from the fork). No part names an owner. +**Another owner:** fork the kit, change `kit/.toolkit/msbuild/init.company.props` (and `.targets`) and `kit/.toolkit/res/package.icon.png`, publish releases from the fork and install with `update.sh --repo /` (recorded in `kit.json`, so later updates come from the fork). Set `MSKit_CodesHelpBaseUrl` in the owner layer to point the code links at the fork's code reference. No part names an owner. ## Extension files diff --git a/docs/getting-started.md b/docs/getting-started.md index 87c4a61..b3feba8 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -88,7 +88,7 @@ A project whose name ends in `.Tests` is a test project: [xUnit v3](https://xuni ``` -With [central package management](https://learn.microsoft.com/nuget/consume-packages/central-package-management), leave the test packages out of `Directory.Packages.props`: the kit provides their versions ([`MSKIT_DUP001`](./reference/codes.md#mskitdup001) reports a duplicate). +With [central package management](https://learn.microsoft.com/nuget/consume-packages/central-package-management), leave the test packages out of `Directory.Packages.props`: the kit provides their versions ([`MSKITDUP001`](./reference/codes.md#mskitdup001) reports a duplicate). ## 5 Build, test, pack diff --git a/docs/migrating-from-msbuild-routine.md b/docs/migrating-from-msbuild-routine.md index d90eab4..be3fa6a 100644 --- a/docs/migrating-from-msbuild-routine.md +++ b/docs/migrating-from-msbuild-routine.md @@ -5,7 +5,7 @@ 1. **Remove the submodule:** `git rm .msbuild`, delete `.gitmodules`, and drop `submodules:` from your workflows. 2. **Install the kit** ([Getting started](./getting-started.md)), with `--add PackageAsProj` if you use `Directory.PackageAsProj.targets`, and replace the `.msbuild\shared\init.props` / `init.targets` imports with the `.toolkit/msbuild/` ones. 3. **Drop what is now a default:** `Copyright`, `PackageLicenseExpression`, `RepositoryUrl`, `PackageReleaseNotes`, `TargetFrameworkStrategy`, and the `.msbuild\tfm.constants.props` import. -4. **Remove the versions the kit provides** from `Directory.Packages.props` (`xunit.v3*`, `xunit.runner.visualstudio`, `Microsoft.NET.Test.Sdk`, `Microsoft.Testing.Extensions.CodeCoverage`, `NSubstitute*`, your assertion library, `coverlet.collector`) and the explicit `Microsoft.Testing.Extensions.CodeCoverage` references from test projects; [`MSKIT_DUP001`](./reference/codes.md#mskitdup001) lists any you missed. To keep FluentAssertions 7, set `MSKit_TestsAssertions=FluentAssertions`. +4. **Remove the versions the kit provides** from `Directory.Packages.props` (`xunit.v3*`, `xunit.runner.visualstudio`, `Microsoft.NET.Test.Sdk`, `Microsoft.Testing.Extensions.CodeCoverage`, `NSubstitute*`, your assertion library, `coverlet.collector`) and the explicit `Microsoft.Testing.Extensions.CodeCoverage` references from test projects; [`MSKITDUP001`](./reference/codes.md#mskitdup001) lists any you missed. To keep FluentAssertions 7, set `MSKit_TestsAssertions=FluentAssertions`. 5. **Add `Directory.Version.props`** with the next `VersionPrefix`, and publish releases with tags such as `v2.0.1` ([Versioning](./versioning.md)). Renamed properties: diff --git a/docs/optional-parts.md b/docs/optional-parts.md index d2a26d0..84fa5be 100644 --- a/docs/optional-parts.md +++ b/docs/optional-parts.md @@ -19,8 +19,8 @@ The kit imports `Directory.PackageAsProj.targets` from the solution folder when | Code | When | | --- | --- | -| [`MSKIT_PAP001`](./reference/codes.md#mskitpap001) | a package switched to a project is still resolved from the package: restore with `--force` | -| [`MSKIT_PAP002`](./reference/codes.md#mskitpap002) | a package switched back is not restored yet: restore with `--force`, or set `PackageAsProj_SkipChecks=True` | +| [`MSKITPAP001`](./reference/codes.md#mskitpap001) | a package switched to a project is still resolved from the package: restore with `--force` | +| [`MSKITPAP002`](./reference/codes.md#mskitpap002) | a package switched back is not restored yet: restore with `--force`, or set `PackageAsProj_SkipChecks=True` | Keep `Directory.PackageAsProj.targets` out of git if the paths point at your own checkouts. diff --git a/docs/package-readme.md b/docs/package-readme.md index 4992077..2e4753c 100644 --- a/docs/package-readme.md +++ b/docs/package-readme.md @@ -18,7 +18,7 @@ The path is relative to the git root (or absolute). It wins over a `package.read 3. **`` … ``** blocks stay only in the readme of the packages they name (several ids: separate with spaces or commas). Unmarked content goes to every package, so a multi-package repository keeps one README. 4. **The title is the package id.** The first level-1 heading (`# …`, or a `===`-underlined one) becomes `# `, so each package of a multi-package repository is named on its own page; a README with no level-1 heading gets the title as its first line. Only the content this package keeps counts: a heading inside a `nuget:skip` block, another package's `nuget:only` block or a code fence is never the one replaced. Set `MSKit_PackageReadmeTitle` to another title, or empty to keep the README's own heading. 5. **Release notes and Issues links** are added to the overview when it does not already link those pages: the `## Overview` section when there is one, else the text above the first `##` heading. -6. The `MSKIT_PKG` checks then run on the generated file, so a link the generator could not rewrite is still caught by `MSKIT_PKG017` / `MSKIT_PKG009`. +6. The `MSKITPKG` checks then run on the generated file, so a link the generator could not rewrite is still caught by `MSKITPKG017` / `MSKITPKG009`. The markers are matched on lines of their own, outside code fences. A README that documents the markers in a fenced block is safe. @@ -55,7 +55,7 @@ A self-hosted GitLab is recognised through the same item Source Link uses: | `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_PackageReadmeTitle` | `auto` (the `PackageId`) | The text of the first level-1 heading; empty keeps the README's own heading | -| `MSKit_RepositoryVisibility` | `$(CI_PROJECT_VISIBILITY)` | `private` or `internal` raises `MSKIT_PKG022` | +| `MSKit_RepositoryVisibility` | `$(CI_PROJECT_VISIBILITY)` | `private` or `internal` raises `MSKITPKG022` | | `MSKit_GeneratedPackageReadmePath` | `obj//package.readme.md` | Where the generated file goes | | `MSKit_PackageReadmeAllowedImageHosts` | the kit's list | `;`-separated hosts that replace the list below | @@ -73,14 +73,14 @@ These stay warnings on CI; skip one with `MSKit_SkipPackageChecks` or `NoWarn` l | Code | Fires when | | --- | --- | -| [`MSKIT_PKG020`](./reference/codes.md#mskitpkg020) | the README is missing, a marker is unbalanced, a path leaves the repository, or links cannot be rewritten (no repository URL, an unknown host, no commit) | -| [`MSKIT_PKG021`](./reference/codes.md#mskitpkg021) | an image is served from a host nuget.org does not render images from; the warning names the image and its README line | -| [`MSKIT_PKG022`](./reference/codes.md#mskitpkg022) | the repository is private or internal, so the links will not open for package readers | +| [`MSKITPKG020`](./reference/codes.md#mskitpkg020) | the README is missing, a marker is unbalanced, a path leaves the repository, or links cannot be rewritten (no repository URL, an unknown host, no commit) | +| [`MSKITPKG021`](./reference/codes.md#mskitpkg021) | an image is served from a host nuget.org does not render images from; the warning names the image and its README line | +| [`MSKITPKG022`](./reference/codes.md#mskitpkg022) | the repository is private or internal, so the links will not open for package readers | ## Allowed image hosts -nuget.org shows readme images only from [a fixed list of hosts](https://learn.microsoft.com/nuget/nuget-org/package-readme-on-nuget-org#allowed-domains-for-images-and-badges). The kit ships that list as `.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/nuget.allowed-image-hosts.txt` (copied from the page on 2026-10-05) and refreshes it with kit releases; nothing is downloaded during a build. `raw.githubusercontent.com` and `gitlab.com` are on it, so images from a GitHub or gitlab.com repository render; a self-hosted GitLab is not, and its images raise `MSKIT_PKG021`. +nuget.org shows readme images only from [a fixed list of hosts](https://learn.microsoft.com/nuget/nuget-org/package-readme-on-nuget-org#allowed-domains-for-images-and-badges). The kit ships that list as `.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/nuget.allowed-image-hosts.txt` (copied from the page on 2026-10-05) and refreshes it with kit releases; nothing is downloaded during a build. `raw.githubusercontent.com` and `gitlab.com` are on it, so images from a GitHub or gitlab.com repository render; a self-hosted GitLab is not, and its images raise `MSKITPKG021`. ## Build cost -The generator runs on `dotnet pack` only, once per project (before `GenerateNuspec`), never on `dotnet build`, a design-time build or a per-framework inner build. It is incremental: the README, the kit's host list and a stamp of the settings above are its inputs, so a second pack with nothing changed skips it. One in-process pass, no network, no process started. The generator and the `MSKIT_PKG` checks are one inline task, so a pack compiles it once whichever of the two runs. +The generator runs on `dotnet pack` only, once per project (before `GenerateNuspec`), never on `dotnet build`, a design-time build or a per-framework inner build. It is incremental: the README, the kit's host list and a stamp of the settings above are its inputs, so a second pack with nothing changed skips it. One in-process pass, no network, no process started. The generator and the `MSKITPKG` checks are one inline task, so a pack compiles it once whichever of the two runs. diff --git a/docs/packaging.md b/docs/packaging.md index 988d545..1c86cfa 100644 --- a/docs/packaging.md +++ b/docs/packaging.md @@ -40,26 +40,26 @@ Set `MSKit_PackageValidationBaselineVersion` to the last published version once | Code | Fires when | | --- | --- | -| [`MSKIT_PKG001`](./reference/codes.md#mskitpkg001) | `Description` is missing, the SDK default, or the package id | -| [`MSKIT_PKG002`](./reference/codes.md#mskitpkg002) | `Description` is shorter than `MSKit_PackageDescriptionMinLength` (30) | -| [`MSKIT_PKG003`](./reference/codes.md#mskitpkg003) | no README is packed | -| [`MSKIT_PKG004`](./reference/codes.md#mskitpkg004) | no `PackageTags` | -| [`MSKIT_PKG005`](./reference/codes.md#mskitpkg005) | no icon | -| [`MSKIT_PKG006`](./reference/codes.md#mskitpkg006) | no licence expression or file | -| [`MSKIT_PKG007`](./reference/codes.md#mskitpkg007) | the deprecated `PackageLicenseUrl` is set | -| [`MSKIT_PKG008`](./reference/codes.md#mskitpkg008) | the deprecated `PackageIconUrl` is set | -| [`MSKIT_PKG009`](./reference/codes.md#mskitpkg009) | the README has relative images | -| [`MSKIT_PKG010`](./reference/codes.md#mskitpkg010) | the README contains HTML | -| [`MSKIT_PKG011`](./reference/codes.md#mskitpkg011) | the README uses GitHub alerts (`> [!NOTE]`) | -| [`MSKIT_PKG012`](./reference/codes.md#mskitpkg012) | the README loads images from a host nuget.org blocks | -| [`MSKIT_PKG013`](./reference/codes.md#mskitpkg013) | the version is not SemVer 2.0 (`MSKit_SemVerRegex`) | -| [`MSKIT_PKG014`](./reference/codes.md#mskitpkg014) | no repository or project URL | -| [`MSKIT_PKG015`](./reference/codes.md#mskitpkg015) | the icon is not a 128×128 PNG or JPEG (`MSKit_PackageIconSize`) | -| [`MSKIT_PKG016`](./reference/codes.md#mskitpkg016) | no `PackageReleaseNotes` | -| [`MSKIT_PKG017`](./reference/codes.md#mskitpkg017) | the README has relative links | -| [`MSKIT_PKG018`](./reference/codes.md#mskitpkg018) | an open-source licence with an "All rights reserved" copyright | -| [`MSKIT_PKG019`](./reference/codes.md#mskitpkg019) | the README contains a Mermaid diagram | +| [`MSKITPKG001`](./reference/codes.md#mskitpkg001) | `Description` is missing, the SDK default, or the package id | +| [`MSKITPKG002`](./reference/codes.md#mskitpkg002) | `Description` is shorter than `MSKit_PackageDescriptionMinLength` (30) | +| [`MSKITPKG003`](./reference/codes.md#mskitpkg003) | no README is packed | +| [`MSKITPKG004`](./reference/codes.md#mskitpkg004) | no `PackageTags` | +| [`MSKITPKG005`](./reference/codes.md#mskitpkg005) | no icon | +| [`MSKITPKG006`](./reference/codes.md#mskitpkg006) | no licence expression or file | +| [`MSKITPKG007`](./reference/codes.md#mskitpkg007) | the deprecated `PackageLicenseUrl` is set | +| [`MSKITPKG008`](./reference/codes.md#mskitpkg008) | the deprecated `PackageIconUrl` is set | +| [`MSKITPKG009`](./reference/codes.md#mskitpkg009) | the README has relative images | +| [`MSKITPKG010`](./reference/codes.md#mskitpkg010) | the README contains HTML | +| [`MSKITPKG011`](./reference/codes.md#mskitpkg011) | the README uses GitHub alerts (`> [!NOTE]`) | +| [`MSKITPKG012`](./reference/codes.md#mskitpkg012) | the README loads images from a host nuget.org blocks | +| [`MSKITPKG013`](./reference/codes.md#mskitpkg013) | the version is not SemVer 2.0 (`MSKit_SemVerRegex`) | +| [`MSKITPKG014`](./reference/codes.md#mskitpkg014) | no repository or project URL | +| [`MSKITPKG015`](./reference/codes.md#mskitpkg015) | the icon is not a 128×128 PNG or JPEG (`MSKit_PackageIconSize`) | +| [`MSKITPKG016`](./reference/codes.md#mskitpkg016) | no `PackageReleaseNotes` | +| [`MSKITPKG017`](./reference/codes.md#mskitpkg017) | the README has relative links | +| [`MSKITPKG018`](./reference/codes.md#mskitpkg018) | an open-source licence with an "All rights reserved" copyright | +| [`MSKITPKG019`](./reference/codes.md#mskitpkg019) | the README contains a Mermaid diagram | -Images, links, HTML and alerts inside a fenced block or inline code are ignored; a GitHub Actions workflow badge from `github.com` counts as an allowed image. The readme generator adds three warnings of its own, `MSKIT_PKG020`-`022`, which stay warnings on CI ([Package readme](./package-readme.md#warnings)). +Images, links, HTML and alerts inside a fenced block or inline code are ignored; a GitHub Actions workflow badge from `github.com` counts as an allowed image. The readme generator adds three warnings of its own, `MSKITPKG020`-`022`, which stay warnings on CI ([Package readme](./package-readme.md#warnings)). -**Skipping a check:** list its code in `MSKit_SkipPackageChecks` (`MSKIT_PKG004;MSKIT_PKG016`) or in `NoWarn`; `MSKit_SkipPackageChecks=All` skips them all. Set it in a csproj to skip for one package. +**Skipping a check:** list its code in `MSKit_SkipPackageChecks` (`MSKITPKG004;MSKITPKG016`) or in `NoWarn`; `MSKit_SkipPackageChecks=All` skips them all. Set it in a csproj to skip for one package. diff --git a/docs/parts.md b/docs/parts.md index b905ffd..0f92001 100644 --- a/docs/parts.md +++ b/docs/parts.md @@ -8,7 +8,7 @@ The kit is split into parts, one folder each under `.toolkit/msbuild/` (`DragoAn | `Trunk` | default | | Language defaults, product and copyright, the version engine, global usings, reference and consistency checks | [Build](./build.md), [Versioning](./versioning.md) | | `Vcs.GitHub` | default | | Reads the GitHub Actions variables: CI detection, run number, tag, pull request, repository URL | [Versioning](./versioning.md#ci-variables) | | `TfmConstants` | default | | `IsNET8`, `IsNET8_OR_GREATER`, `IsNETSTANDARD` and the rest, for conditions | [Build](./build.md#target-framework-constants) | -| `Packaging` | default | | nuget.org metadata defaults, the readme generator and the `MSKIT_PKG` checks | [Packaging](./packaging.md) | +| `Packaging` | default | | nuget.org metadata defaults, the readme generator and the `MSKITPKG` checks | [Packaging](./packaging.md) | | `Testing` | default | | Test-project detection, Microsoft.Testing.Platform, assertions, mocking, `InternalsVisibleTo` | [Testing](./testing.md) | | `Testing.XUnit.v3` | default | `Testing` | The xUnit v3 wiring | [Testing](./testing.md) | | `Locals.Secrets`, `Locals.DirectorySecrets`, `Locals.Compile` | default | | Secrets and source files that stay on the developer's machine | [Local files](./local-files.md) | diff --git a/docs/reference/codes.md b/docs/reference/codes.md index d7f5557..bea7a21 100644 --- a/docs/reference/codes.md +++ b/docs/reference/codes.md @@ -1,6 +1,8 @@ # Code reference -Every warning and error the kit reports, one section per code. The kit reports each code as `MSKIT_` (for example `MSKIT_VER006`); the section anchors use the id without the underscore (`#mskitver006`). Severity is the default; the section says how to change or skip it. +Every warning and error the kit reports, one section per code. A code is the kit prefix, a family and a three-digit number with no separator (`MSKITVER006`); its section anchor is the code in lower case (`#mskitver006`). Every warning and error carries a `HelpLink` to its section, which the terminal logger and IDEs show as a link on the code; `MSKit_CodesHelpBaseUrl` names the page the links point at ([property reference](./properties.md#machine-ci-and-paths)). Severity is the default; the section says how to change or skip it. + +Earlier releases put an underscore between the prefix and the family; each section names its former spelling, and `NoWarn`, `WarningsAsErrors`, `WarningsNotAsErrors` or `MSKit_SkipPackageChecks` entries that use it no longer match. A code is never renumbered or reused: `VER003` is reserved, and no release reported it. | Family | Part | Codes | | --- | --- | --- | @@ -18,91 +20,91 @@ Every warning and error the kit reports, one section per code. The kit reports e ### MSKITPKG001 -`MSKIT_PKG001` — the package has no real `Description`: it is empty, the SDK's `Package Description`, the package id or the project name. Write one or two sentences on what the package does and what sets it apart; nuget.org search shows it first. +`MSKITPKG001` (formerly `MSKIT_PKG001`) — the package has no real `Description`: it is empty, the SDK's `Package Description`, the package id or the project name. Write one or two sentences on what the package does and what sets it apart; nuget.org search shows it first. ### MSKITPKG002 -`MSKIT_PKG002` — `Description` is shorter than `MSKit_PackageDescriptionMinLength` (30 characters). Say what it does and for whom, or lower the bar. +`MSKITPKG002` (formerly `MSKIT_PKG002`) — `Description` is shorter than `MSKit_PackageDescriptionMinLength` (30 characters). Say what it does and for whom, or lower the bar. ### MSKITPKG003 -`MSKIT_PKG003` — no README is packed. Add `package.readme.md` (or `README.md`) next to the csproj, or set `MSKit_PackageReadmeFrom`. +`MSKITPKG003` (formerly `MSKIT_PKG003`) — no README is packed. Add `package.readme.md` (or `README.md`) next to the csproj, or set `MSKit_PackageReadmeFrom`. ### MSKITPKG004 -`MSKIT_PKG004` — no `PackageTags`. Add a few search terms that are not already in the package id. +`MSKITPKG004` (formerly `MSKIT_PKG004`) — no `PackageTags`. Add a few search terms that are not already in the package id. ### MSKITPKG005 -`MSKIT_PKG005` — no icon. Set `PackageIconPath` to a 128×128 PNG or JPEG, packed as `icon`; the owner layer sets one for every package. +`MSKITPKG005` (formerly `MSKIT_PKG005`) — no icon. Set `PackageIconPath` to a 128×128 PNG or JPEG, packed as `icon`; the owner layer sets one for every package. ### MSKITPKG006 -`MSKIT_PKG006` — no licence. Set `PackageLicenseExpression` to an [SPDX id](https://spdx.org/licenses/) or `PackageLicenseFile`. +`MSKITPKG006` (formerly `MSKIT_PKG006`) — no licence. Set `PackageLicenseExpression` to an [SPDX id](https://spdx.org/licenses/) or `PackageLicenseFile`. ### MSKITPKG007 -`MSKIT_PKG007` — the deprecated `PackageLicenseUrl` is set. Use `PackageLicenseExpression` or `PackageLicenseFile`. +`MSKITPKG007` (formerly `MSKIT_PKG007`) — the deprecated `PackageLicenseUrl` is set. Use `PackageLicenseExpression` or `PackageLicenseFile`. ### MSKITPKG008 -`MSKIT_PKG008` — the deprecated `PackageIconUrl` is set. Pack the image and use `PackageIcon` or `PackageIconPath`. +`MSKITPKG008` (formerly `MSKIT_PKG008`) — the deprecated `PackageIconUrl` is set. Pack the image and use `PackageIcon` or `PackageIconPath`. ### MSKITPKG009 -`MSKIT_PKG009` — the package README has relative images, which nuget.org does not render. Use absolute `https` URLs from an [allowed host](https://learn.microsoft.com/nuget/nuget-org/package-readme-on-nuget-org#allowed-domains-for-images-and-badges), or generate the readme with `MSKit_PackageReadmeFrom`. +`MSKITPKG009` (formerly `MSKIT_PKG009`) — the package README has relative images, which nuget.org does not render. Use absolute `https` URLs from an [allowed host](https://learn.microsoft.com/nuget/nuget-org/package-readme-on-nuget-org#allowed-domains-for-images-and-badges), or generate the readme with `MSKit_PackageReadmeFrom`. ### MSKITPKG010 -`MSKIT_PKG010` — the package README contains HTML, which nuget.org does not render. Use Markdown. +`MSKITPKG010` (formerly `MSKIT_PKG010`) — the package README contains HTML, which nuget.org does not render. Use Markdown. ### MSKITPKG011 -`MSKIT_PKG011` — the package README uses GitHub alerts (`> [!NOTE]`), which nuget.org shows as plain quotes. Use a bold lead-in such as `**Note:**`. +`MSKITPKG011` (formerly `MSKIT_PKG011`) — the package README uses GitHub alerts (`> [!NOTE]`), which nuget.org shows as plain quotes. Use a bold lead-in such as `**Note:**`. ### MSKITPKG012 -`MSKIT_PKG012` — the package README loads images from a host nuget.org blocks. Host them on an allowed domain (`img.shields.io`, `raw.githubusercontent.com`, …). +`MSKITPKG012` (formerly `MSKIT_PKG012`) — the package README loads images from a host nuget.org blocks. Host them on an allowed domain (`img.shields.io`, `raw.githubusercontent.com`, …). ### MSKITPKG013 -`MSKIT_PKG013` — the package version is not [SemVer 2.0](https://semver.org/) (`MSKit_SemVerRegex`). +`MSKITPKG013` (formerly `MSKIT_PKG013`) — the package version is not [SemVer 2.0](https://semver.org/) (`MSKit_SemVerRegex`). ### MSKITPKG014 -`MSKIT_PKG014` — no repository or project URL. Set `RepositoryUrl`, or build from a git clone whose `origin` remote Source Link can read. +`MSKITPKG014` (formerly `MSKIT_PKG014`) — no repository or project URL. Set `RepositoryUrl`, or build from a git clone whose `origin` remote Source Link can read. ### MSKITPKG015 -`MSKIT_PKG015` — the icon is not a PNG or JPEG of `MSKit_PackageIconSize` × `MSKit_PackageIconSize` pixels (128); the size is checked on both formats. +`MSKITPKG015` (formerly `MSKIT_PKG015`) — the icon is not a PNG or JPEG of `MSKit_PackageIconSize` × `MSKit_PackageIconSize` pixels (128); the size is checked on both formats. ### MSKITPKG016 -`MSKIT_PKG016` — no `PackageReleaseNotes`. The kit fills them on `github.com`, and on any host the generated readme knows with `MSKit_PackageReadmeFrom`; elsewhere set them (a link to the changelog is enough). +`MSKITPKG016` (formerly `MSKIT_PKG016`) — no `PackageReleaseNotes`. The kit fills them on `github.com`, and on any host the generated readme knows with `MSKit_PackageReadmeFrom`; elsewhere set them (a link to the changelog is enough). ### MSKITPKG017 -`MSKIT_PKG017` — the package README has relative links, which break on nuget.org. Use absolute URLs, or generate the readme with `MSKit_PackageReadmeFrom`. +`MSKITPKG017` (formerly `MSKIT_PKG017`) — the package README has relative links, which break on nuget.org. Use absolute URLs, or generate the readme with `MSKit_PackageReadmeFrom`. ### MSKITPKG018 -`MSKIT_PKG018` — the package has an open-source licence expression, but its `Copyright` says "all rights reserved". Use `Copyright (c) YEAR OWNER`. +`MSKITPKG018` (formerly `MSKIT_PKG018`) — the package has an open-source licence expression, but its `Copyright` says "all rights reserved". Use `Copyright (c) YEAR OWNER`. ### MSKITPKG019 -`MSKIT_PKG019` — the package README contains a Mermaid diagram, which nuget.org shows as code. Link to the diagram on the repository host instead. +`MSKITPKG019` (formerly `MSKIT_PKG019`) — the package README contains a Mermaid diagram, which nuget.org shows as code. Link to the diagram on the repository host instead. ### MSKITPKG020 -`MSKIT_PKG020` (warning) — the readme cannot be generated as asked: the `MSKit_PackageReadmeFrom` file is missing, a `nuget:skip` / `nuget:only` marker is unbalanced, a link leaves the repository, or links cannot be rewritten (no repository URL, an unknown host or provider, no commit). The message names the line. +`MSKITPKG020` (formerly `MSKIT_PKG020`) (warning) — the readme cannot be generated as asked: the `MSKit_PackageReadmeFrom` file is missing, a `nuget:skip` / `nuget:only` marker is unbalanced, a link leaves the repository, or links cannot be rewritten (no repository URL, an unknown host or provider, no commit). The message names the line. ### MSKITPKG021 -`MSKIT_PKG021` (warning) — a generated readme loads an image from a host nuget.org does not render images from; the message names the image and its README line. +`MSKITPKG021` (formerly `MSKIT_PKG021`) (warning) — a generated readme loads an image from a host nuget.org does not render images from; the message names the image and its README line. ### MSKITPKG022 -`MSKIT_PKG022` (warning) — the repository is private or internal (`MSKit_RepositoryVisibility`, else GitLab's `CI_PROJECT_VISIBILITY`), so the readme's links will not open for package readers. +`MSKITPKG022` (formerly `MSKIT_PKG022`) (warning) — the repository is private or internal (`MSKit_RepositoryVisibility`, else GitLab's `CI_PROJECT_VISIBILITY`), so the readme's links will not open for package readers. ## Versioning @@ -110,23 +112,23 @@ Background: [Versioning](../versioning.md). ### MSKITVER001 -`MSKIT_VER001` (error) — the csproj declares `` while a template strategy renders the version, so the value would be ignored. Remove it and declare `VersionPrefix` in `Directory.Version.props`, or set `MSKit_VersionStrategy=Manual`. +`MSKITVER001` (formerly `MSKIT_VER001`) (error) — the csproj declares `` while a template strategy renders the version, so the value would be ignored. Remove it and declare `VersionPrefix` in `Directory.Version.props`, or set `MSKit_VersionStrategy=Manual`. ### MSKITVER002 -`MSKIT_VER002` (error) — a version template uses an unknown placeholder. The message lists the valid ones ([placeholders](../versioning.md#placeholders)). +`MSKITVER002` (formerly `MSKIT_VER002`) (error) — a version template uses an unknown placeholder. The message lists the valid ones ([placeholders](../versioning.md#placeholders)). ### MSKITVER004 -`MSKIT_VER004` (error) — `MSKit_VersionStrategy=VersionTag` but `VersionTag` is empty. Pass `-p:VersionTag=1.2.3`, or use `ReleaseTag`. +`MSKITVER004` (formerly `MSKIT_VER004`) (error) — `MSKit_VersionStrategy=VersionTag` but `VersionTag` is empty. Pass `-p:VersionTag=1.2.3`, or use `ReleaseTag`. ### MSKITVER006 -`MSKIT_VER006` (error, stops restore) — a tag build whose tag, after removing a leading `v`, is not [SemVer 2.0](https://semver.org/) (`MSKit_ReleaseTagRegex`). Delete the tag and its release and tag again (`v2.1.0`, `v2.1.0-beta.1`). +`MSKITVER006` (formerly `MSKIT_VER006`) (error, stops restore) — a tag build whose tag, after removing a leading `v`, is not [SemVer 2.0](https://semver.org/) (`MSKit_ReleaseTagRegex`). Delete the tag and its release and tag again (`v2.1.0`, `v2.1.0-beta.1`). ### MSKITVER007 -`MSKIT_VER007` (warning) — the tag's `MAJOR.MINOR.PATCH` differs from the `VersionPrefix` the repository declares. Bump `VersionPrefix` after the release so branch builds sort above it; `MSKit_SkipAudit_ReleaseTagPrefix=True` silences it. +`MSKITVER007` (formerly `MSKIT_VER007`) (warning) — the tag's `MAJOR.MINOR.PATCH` differs from the `VersionPrefix` the repository declares. Bump `VersionPrefix` after the release so branch builds sort above it; `MSKit_SkipAudit_ReleaseTagPrefix=True` silences it. ## References @@ -134,27 +136,27 @@ Background: [reference checks](../build.md#reference-checks), [central package v ### MSKITDUP001 -`MSKIT_DUP001` (error, stops restore) — `Directory.Packages.props` declares a `PackageVersion` the kit already provides. Delete the line; to pin another version set the kit's `MSKit_PackageVersion_*` property, or turn the kit's versions off with `MSKit_ImplicitPackageVersions=False`. `MSKit_SkipAudit_ImplicitPackageDuplicates=True` skips the check. +`MSKITDUP001` (formerly `MSKIT_DUP001`) (error, stops restore) — `Directory.Packages.props` declares a `PackageVersion` the kit already provides. Delete the line; to pin another version set the kit's `MSKit_PackageVersion_*` property, or turn the kit's versions off with `MSKit_ImplicitPackageVersions=False`. `MSKit_SkipAudit_ImplicitPackageDuplicates=True` skips the check. ### MSKITPRE001 -`MSKIT_PRE001` (warning) — a stable-branch build references a prerelease version of a package whose id starts with `MSKit_PrereleasePackagePrefix`. Use a stable version; `MSKit_PrereleasePackageCheckAsWarning=false` makes it an error. +`MSKITPRE001` (formerly `MSKIT_PRE001`) (warning) — a stable-branch build references a prerelease version of a package whose id starts with `MSKit_PrereleasePackagePrefix`. Use a stable version; `MSKit_PrereleasePackageCheckAsWarning=false` makes it an error. ### MSKITRES001 -`MSKIT_RES001` (error) — a referenced package is banned by an `MSKit_RestrictPackageReference` item with `Type="Error"`. Remove it or use the suggested alternative; `SkipGlobalRestriction="True"` on the one `PackageReference` turns it into a warning. +`MSKITRES001` (formerly `MSKIT_RES001`) (error) — a referenced package is banned by an `MSKit_RestrictPackageReference` item with `Type="Error"`. Remove it or use the suggested alternative; `SkipGlobalRestriction="True"` on the one `PackageReference` turns it into a warning. ### MSKITRES002 -`MSKIT_RES002` (warning) — a referenced package is discouraged by an `MSKit_RestrictPackageReference` item with `Type="Warning"`. `SkipGlobalRestriction="True"` on the reference silences it. +`MSKITRES002` (formerly `MSKIT_RES002`) (warning) — a referenced package is discouraged by an `MSKit_RestrictPackageReference` item with `Type="Warning"`. `SkipGlobalRestriction="True"` on the reference silences it. ### MSKITRES003 -`MSKIT_RES003` (error) — with `MSKit_RestrictProjectReferences=True` (or `MSKit_RestrictReferences=True`), a `ProjectReference` lacks `Allowed="True"`. +`MSKITRES003` (formerly `MSKIT_RES003`) (error) — with `MSKit_RestrictProjectReferences=True` (or `MSKit_RestrictReferences=True`), a `ProjectReference` lacks `Allowed="True"`. ### MSKITRES004 -`MSKIT_RES004` (error) — with `MSKit_RestrictPackageReferences=True` (or `MSKit_RestrictReferences=True`), a `PackageReference` lacks `Allowed="True"`. +`MSKITRES004` (formerly `MSKIT_RES004`) (error) — with `MSKit_RestrictPackageReferences=True` (or `MSKit_RestrictReferences=True`), a `PackageReference` lacks `Allowed="True"`. ## Shared properties @@ -162,27 +164,27 @@ Background: [target frameworks declared once](../build.md#target-frameworks-decl ### MSKITSHARED006 -`MSKIT_SHARED006` (error) — the csproj declares the same `TargetFramework` as `Directory.Build.props`. Delete it from the csproj. +`MSKITSHARED006` (formerly `MSKIT_SHARED006`) (error) — the csproj declares the same `TargetFramework` as `Directory.Build.props`. Delete it from the csproj. ### MSKITSHARED007 -`MSKIT_SHARED007` (error) — the csproj declares the same `TargetFrameworks` as `Directory.Build.props`. Delete it from the csproj. +`MSKITSHARED007` (formerly `MSKIT_SHARED007`) (error) — the csproj declares the same `TargetFrameworks` as `Directory.Build.props`. Delete it from the csproj. ### MSKITSHARED008 -`MSKIT_SHARED008` (warning) — the csproj overrides the shared `TargetFramework` with another value. Remove it, or accept it with `MSKit_SkipAudit_TargetFrameworkOverride=True` in the csproj. +`MSKITSHARED008` (formerly `MSKIT_SHARED008`) (warning) — the csproj overrides the shared `TargetFramework` with another value. Remove it, or accept it with `MSKit_SkipAudit_TargetFrameworkOverride=True` in the csproj. ### MSKITSHARED009 -`MSKIT_SHARED009` (warning) — the csproj overrides the shared `TargetFrameworks` with another value. Remove it, or accept it with `MSKit_SkipAudit_TargetFrameworkOverride=True`. +`MSKITSHARED009` (formerly `MSKIT_SHARED009`) (warning) — the csproj overrides the shared `TargetFrameworks` with another value. Remove it, or accept it with `MSKit_SkipAudit_TargetFrameworkOverride=True`. ### MSKITSHARED010 -`MSKIT_SHARED010` (error) — the csproj declares both `TargetFramework` and `TargetFrameworks` (an empty `` counts). Keep one. +`MSKITSHARED010` (formerly `MSKIT_SHARED010`) (error) — the csproj declares both `TargetFramework` and `TargetFrameworks` (an empty `` counts). Keep one. ### MSKITSHARED020 -`MSKIT_SHARED020` (error, developer machines only) — the csproj's final `TreatWarningsAsErrors` differs from the shared value. Align it, or set `MSKit_SkipAudit_TreatWarningsAsErrors=True`. +`MSKITSHARED020` (formerly `MSKIT_SHARED020`) (error, developer machines only) — the csproj's final `TreatWarningsAsErrors` differs from the shared value. Align it, or set `MSKit_SkipAudit_TreatWarningsAsErrors=True`. ## Project types @@ -190,19 +192,19 @@ Background: [Roslyn components](../roslyn.md). ### MSKITCORE001 -`MSKIT_CORE001` (error) — the project name matches more than one detection regex (analyzer, code fix, source generator). Rename the project, narrow a `MSKit_*ProjectNameRegex`, or set the matching `MSKit_Disable*AutoDetect=true` in `Directory.Build.props` above the kit import. +`MSKITCORE001` (formerly `MSKIT_CORE001`) (error) — the project name matches more than one detection regex (analyzer, code fix, source generator). Rename the project, narrow a `MSKit_*ProjectNameRegex`, or set the matching `MSKit_Disable*AutoDetect=true` in `Directory.Build.props` above the kit import. ### MSKITROSLYN001 -`MSKIT_ROSLYN001` (error) — the name matches the analyzer regex, but the `Project.CodeAnalyzer` part is not installed. `sh .toolkit/update.sh --add Project.CodeAnalyzer`, or rename the project, or set `MSKit_DisableCodeAnalyzerAutoDetect=true` in `Directory.Build.props` above the kit import. +`MSKITROSLYN001` (formerly `MSKIT_ROSLYN001`) (error) — the name matches the analyzer regex, but the `Project.CodeAnalyzer` part is not installed. `sh .toolkit/update.sh --add Project.CodeAnalyzer`, or rename the project, or set `MSKit_DisableCodeAnalyzerAutoDetect=true` in `Directory.Build.props` above the kit import. ### MSKITROSLYN002 -`MSKIT_ROSLYN002` (error) — the name matches the code-fix regex, but `Project.CodeFixer` is not installed. Add the part, rename, or set `MSKit_DisableCodeFixerAutoDetect=true` in `Directory.Build.props` above the kit import. +`MSKITROSLYN002` (formerly `MSKIT_ROSLYN002`) (error) — the name matches the code-fix regex, but `Project.CodeFixer` is not installed. Add the part, rename, or set `MSKit_DisableCodeFixerAutoDetect=true` in `Directory.Build.props` above the kit import. ### MSKITROSLYN003 -`MSKIT_ROSLYN003` (error) — the name matches the source-generator regex, but `Project.SourceGenerator` is not installed. Add the part, rename, or set `MSKit_DisableSourceGeneratorAutoDetect=true` in `Directory.Build.props` above the kit import. +`MSKITROSLYN003` (formerly `MSKIT_ROSLYN003`) (error) — the name matches the source-generator regex, but `Project.SourceGenerator` is not installed. Add the part, rename, or set `MSKit_DisableSourceGeneratorAutoDetect=true` in `Directory.Build.props` above the kit import. ## Testing @@ -210,55 +212,55 @@ Background: [Testing](../testing.md). ### MSKITTEST005 -`MSKIT_TEST005` (error) — an xUnit v3 test project targets a framework older than net8.0. +`MSKITTEST005` (formerly `MSKIT_TEST005`) (error) — an xUnit v3 test project targets a framework older than net8.0. ### MSKITTEST010 -`MSKIT_TEST010` (error) — `$(TestsProjectCommonPropsPath)` was imported before `MSKit_TestingFramework` was set. Put the `PropertyGroup` above the `Import`. +`MSKITTEST010` (formerly `MSKIT_TEST010`) (error) — `$(TestsProjectCommonPropsPath)` was imported before `MSKit_TestingFramework` was set. Put the `PropertyGroup` above the `Import`. ### MSKITTEST011 -`MSKIT_TEST011` (error) — `MSKit_TestingFramework` changed after `$(TestsProjectCommonPropsPath)` was imported. Move the `PropertyGroup` above the `Import`. +`MSKITTEST011` (formerly `MSKIT_TEST011`) (error) — `MSKit_TestingFramework` changed after `$(TestsProjectCommonPropsPath)` was imported. Move the `PropertyGroup` above the `Import`. ### MSKITTEST012 -`MSKIT_TEST012` (error) — no wiring exists for the `MSKit_TestingFramework` of an explicit test project. Use `xunit.v3`, or point `MSKit_TestingFramework_CommonPropsPath` at your own props file. +`MSKITTEST012` (formerly `MSKIT_TEST012`) (error) — no wiring exists for the `MSKit_TestingFramework` of an explicit test project. Use `xunit.v3`, or point `MSKit_TestingFramework_CommonPropsPath` at your own props file. ### MSKITTEST013 -`MSKIT_TEST013` (error) — the csproj sets `IsTestsProject` directly, too late for the props-phase wiring. Rename the project to match `MSKit_TestsProjectNameRegex`, or use the explicit endpoint `$(TestsProjectCommonPropsPath)`. +`MSKITTEST013` (formerly `MSKIT_TEST013`) (error) — the csproj sets `IsTestsProject` directly, too late for the props-phase wiring. Rename the project to match `MSKit_TestsProjectNameRegex`, or use the explicit endpoint `$(TestsProjectCommonPropsPath)`. ### MSKITTEST014 -`MSKIT_TEST014` (error) — the name matches the test-project regex, but the project is marked as a test helper library. Rename it (`Acme.TestUtils`), narrow the regex, or drop the helper-library flag. +`MSKITTEST014` (formerly `MSKIT_TEST014`) (error) — the name matches the test-project regex, but the project is marked as a test helper library. Rename it (`Acme.TestUtils`), narrow the regex, or drop the helper-library flag. ### MSKITTEST020 -`MSKIT_TEST020` (error) — `$(TestsLibProjectCommonPropsPath)` was imported before `MSKit_TestingFramework` was set. +`MSKITTEST020` (formerly `MSKIT_TEST020`) (error) — `$(TestsLibProjectCommonPropsPath)` was imported before `MSKit_TestingFramework` was set. ### MSKITTEST021 -`MSKIT_TEST021` (error) — `MSKit_TestingFramework` changed after `$(TestsLibProjectCommonPropsPath)` was imported. +`MSKITTEST021` (formerly `MSKIT_TEST021`) (error) — `MSKit_TestingFramework` changed after `$(TestsLibProjectCommonPropsPath)` was imported. ### MSKITTEST022 -`MSKIT_TEST022` (error) — no helper-library wiring exists for `MSKit_TestingFramework`. Use `xunit.v3`, or set `MSKit_TestingFramework_LibCommonPropsPath`. +`MSKITTEST022` (formerly `MSKIT_TEST022`) (error) — no helper-library wiring exists for `MSKit_TestingFramework`. Use `xunit.v3`, or set `MSKit_TestingFramework_LibCommonPropsPath`. ### MSKITTEST025 -`MSKIT_TEST025` (error) — a test project or helper library has no `MSKit_TestingFramework`. Set it in `Directory.Build.props` (the owner layer sets `xunit.v3`). +`MSKITTEST025` (formerly `MSKIT_TEST025`) (error) — a test project or helper library has no `MSKit_TestingFramework`. Set it in `Directory.Build.props` (the owner layer sets `xunit.v3`). ### MSKITTEST026 -`MSKIT_TEST026` (error) — no installed part wires the `MSKit_TestingFramework` value. Use `xunit.v3` (part `Testing.XUnit.v3`), or set `MSKit_TestingFramework_CommonPropsPath`. +`MSKITTEST026` (formerly `MSKIT_TEST026`) (error) — no installed part wires the `MSKit_TestingFramework` value. Use `xunit.v3` (part `Testing.XUnit.v3`), or set `MSKit_TestingFramework_CommonPropsPath`. ### MSKITTEST030 -`MSKIT_TEST030` (warning) — `MSKit_TestsDir` is empty, so `InternalsVisibleTo` cannot be added. Set it, or turn `InternalsVisibleToAllTestsProjects` off. +`MSKITTEST030` (formerly `MSKIT_TEST030`) (warning) — `MSKit_TestsDir` is empty, so `InternalsVisibleTo` cannot be added. Set it, or turn `InternalsVisibleToAllTestsProjects` off. ### MSKITTEST031 -`MSKIT_TEST031` (warning) — `MSKit_TestsDir` points at a folder that does not exist. +`MSKITTEST031` (formerly `MSKIT_TEST031`) (warning) — `MSKit_TestsDir` points at a folder that does not exist. ## PackageAsProj @@ -266,8 +268,8 @@ Background: [PackageAsProj](../optional-parts.md#packageasproj). ### MSKITPAP001 -`MSKIT_PAP001` (error) — a package switched to a `ProjectReference` is still resolved from the package. Run `dotnet restore --force`. +`MSKITPAP001` (formerly `MSKIT_PAP001`) (error) — a package switched to a `ProjectReference` is still resolved from the package. Run `dotnet restore --force`. ### MSKITPAP002 -`MSKIT_PAP002` (error) — a package switched back from a project is not restored yet. Run `dotnet restore --force`, or set `PackageAsProj_SkipChecks=True`. +`MSKITPAP002` (formerly `MSKIT_PAP002`) (error) — a package switched back from a project is not restored yet. Run `dotnet restore --force`, or set `PackageAsProj_SkipChecks=True`. diff --git a/docs/reference/properties.md b/docs/reference/properties.md index 6fe2a8b..868d637 100644 --- a/docs/reference/properties.md +++ b/docs/reference/properties.md @@ -29,6 +29,7 @@ Every property and item the kit sets or reads, grouped by topic. **Set** = a val | `MSKit_ProjectObjDir` | out | | The project's `obj` folder, absolute | | `MSKit_Templates` | set | `.toolkit/.local/` | Templates for local files ([Local files](../local-files.md)) | | `MSKit_Diagnostic` | set | `false` | Reserved; nothing reads it in this version | +| `MSKit_CodesHelpBaseUrl` | set | `https://github.com/DragoAnt/MSBuildKit/blob/main/docs/reference/codes.md` | The page every warning and error links to (`HelpLink`); the link adds `#` and the code in lower case ([code reference](./codes.md)). Point it at your own copy of the page | ## Versioning @@ -45,7 +46,7 @@ Every property and item the kit sets or reads, grouped by topic. **Set** = a val | `MSKit_IsReleaseTagValid` | out | | | | `MSKit_PullRequestNumber` | set | from `GITHUB_REF` / `GITHUB_REF_NAME` | `{prNumber}` | | `MSKit_BuildDateTimeUtc` | set | the environment variable of that name, else each project's own clock | One date for a whole build | -| `MSKit_SkipAudit_ReleaseTagPrefix` | set | empty | `True` silences `MSKIT_VER007` | +| `MSKit_SkipAudit_ReleaseTagPrefix` | set | empty | `True` silences `MSKITVER007` | ## Target frameworks @@ -59,7 +60,7 @@ Every property and item the kit sets or reads, grouped by topic. **Set** = a val | `IsTfmConstantsImported` | out | | The constants file is loaded | | `MSKit_TargetFramework_Shared`, `MSKit_TargetFrameworks_Shared` | out | | The value declared in `Directory.Build.props` ([declared once](../build.md#target-frameworks-declared-once)) | | `MSKit_TargetFramework_Proj`, `MSKit_TargetFrameworks_Proj` | out | | The value declared in the csproj | -| `MSKit_SkipAudit_TargetFrameworkOverride` | set | empty | `True` accepts a different csproj value (`MSKIT_SHARED008` / `009`) | +| `MSKit_SkipAudit_TargetFrameworkOverride` | set | empty | `True` accepts a different csproj value (`MSKITSHARED008` / `009`) | | `MSKit_GuardXmlPeekRoutine`, `MSKit_GuardXmlPeekAudit` | set | empty (on) | `False` skips the text pre-check before parsing the csproj | ## Build defaults and reference checks @@ -69,15 +70,15 @@ Every property and item the kit sets or reads, grouped by topic. **Set** = a val | `MSKit_IncludeCodeAnalysisGlobalUsings` | set | `True` | The kit's [global usings](../build.md#global-usings) | | `ExcludeFromCodeCoverage` | set | `True` for test projects | Adds `[ExcludeFromCodeCoverage]` to the assembly | | `MSKit_TreatWarningsAsErrors_Shared` | out | | `TreatWarningsAsErrors` before the csproj body | -| `MSKit_SkipAudit_TreatWarningsAsErrors` | set | `True` on CI | Skips `MSKIT_SHARED020` | +| `MSKit_SkipAudit_TreatWarningsAsErrors` | set | `True` on CI | Skips `MSKITSHARED020` | | `MSKit_ImplicitPackageVersions` | set | `True` | The kit's [package versions](../build.md#central-package-versions) | -| `MSKit_SkipAudit_ImplicitPackageDuplicates` | set | `False` | `True` skips `MSKIT_DUP001` | +| `MSKit_SkipAudit_ImplicitPackageDuplicates` | set | `False` | `True` skips `MSKITDUP001` | | `MSKit_RestrictPackageReference` | item | `Moq` (`Type="Error"`, owner layer) | A banned (`Type="Error"`) or discouraged (`Type="Warning"`) package, with a `Message` ([reference checks](../build.md#reference-checks)) | | `MSKit_PackageReferenceNotAllowed`, `MSKit_ProjectReferenceNotAllowed` | item | | The checks' findings; read-only | | `MSKit_RestrictReferences` | set | `False` | Allow-list mode for both reference kinds | | `MSKit_RestrictProjectReferences`, `MSKit_RestrictPackageReferences` | set | `MSKit_RestrictReferences` | Allow-list mode for one kind (`Allowed="True"` required) | | `MSKit_PrereleasePackagePrefix` | set | owner layer `DragoAnt.` | Ids the prerelease check covers | -| `MSKit_PrereleasePackageCheckAsWarning` | set | `true` | `false` makes `MSKIT_PRE001` an error | +| `MSKit_PrereleasePackageCheckAsWarning` | set | `true` | `false` makes `MSKITPRE001` an error | | `MSKit_ProjectReferenceAsPrivateAssets`, `MSKit_PackageReferenceAsPrivateAssets` | set | empty | `True` makes every reference of that kind private ([Build](../build.md#private-references)) | | `ManufacturerName`, `FullManufacturerName` | set | `DragoAnt` (owner layer, unconditional) | The owner ([Customizing](../customizing.md#the-owner-layer)) | @@ -98,11 +99,11 @@ Every property and item the kit sets or reads, grouped by topic. **Set** = a val | `MSKit_PackageReadmeSourcePath` | set | `package.readme.md`, else `README.md` next to the csproj | The README packed as `readme.md` | | `MSKit_PackageValidationBaselineVersion` | set | empty | The release package validation compares against | | `MSKit_DefaultReleaseNotes` | set | empty (on) | `False` turns the `PackageReleaseNotes` default off | -| `MSKit_PackageChecksAsErrors` | set | `True` on CI | The `MSKIT_PKG` checks as errors ([Packaging](../packaging.md#checks)) | +| `MSKit_PackageChecksAsErrors` | set | `True` on CI | The `MSKITPKG` checks as errors ([Packaging](../packaging.md#checks)) | | `MSKit_SkipPackageChecks` | set | empty | Codes to skip, `;`-separated, or `All` | -| `MSKit_PackageDescriptionMinLength` | set | `30` | `MSKIT_PKG002` | -| `MSKit_PackageIconSize` | set | `128` | `MSKIT_PKG015` | -| `MSKit_SemVerRegex` | set | SemVer 2.0 | `MSKIT_PKG013` | +| `MSKit_PackageDescriptionMinLength` | set | `30` | `MSKITPKG002` | +| `MSKit_PackageIconSize` | set | `128` | `MSKITPKG015` | +| `MSKit_SemVerRegex` | set | SemVer 2.0 | `MSKITPKG013` | ## Package readme @@ -114,7 +115,7 @@ Every property and item the kit sets or reads, grouped by topic. **Set** = a val | `MSKit_RepoProvider` | set | detected | `GitHub`, `GitLab`, `AzureDevOps`, `Bitbucket`, `Gitea` | | `MSKit_RepoBlobUrlTemplate`, `MSKit_RepoRawUrlTemplate` | set | the provider's | File-link and image templates | | `MSKit_ReleasesUrl`, `MSKit_IssuesUrl` | set | `auto` | The links added to the overview; empty leaves one out | -| `MSKit_RepositoryVisibility` | set | `CI_PROJECT_VISIBILITY` | `private` / `internal` raises `MSKIT_PKG022` | +| `MSKit_RepositoryVisibility` | set | `CI_PROJECT_VISIBILITY` | `private` / `internal` raises `MSKITPKG022` | | `MSKit_PackageReadmeAllowedImageHosts` | set | the hosts file | `;`-separated hosts that replace the file's list | | `MSKit_PackageReadmeAllowedImageHostsFile` | set | the kit's `nuget.allowed-image-hosts.txt` | The hosts file | @@ -148,7 +149,7 @@ Every property and item the kit sets or reads, grouped by topic. **Set** = a val | `MSKit_CodeAnalyzerProjectNameRegex`, `MSKit_CodeFixerProjectNameRegex`, `MSKit_SourceGeneratorProjectNameRegex` | set | `\.Analyzers$`, `\.CodeFixes$`, `\.SourceGenerator$` | Role names | | `MSKit_DisableCodeAnalyzerAutoDetect`, `MSKit_DisableCodeFixerAutoDetect`, `MSKit_DisableSourceGeneratorAutoDetect` | set | empty | `true` above the kit import turns detection off | | `MSKit_IsCodeAnalyzerAutoDetected`, `MSKit_IsCodeFixerAutoDetected`, `MSKit_IsSourceGeneratorAutoDetected` | out | | The name matched | -| `MSKit_AutoDetectedProjectType` | item | | Every role the name matched; more than one is `MSKIT_CORE001` | +| `MSKit_AutoDetectedProjectType` | item | | Every role the name matched; more than one is `MSKITCORE001` | | `MSKit_CodeAnalyzerSatelliteAttached`, `MSKit_CodeFixerSatelliteAttached`, `MSKit_SourceGeneratorSatelliteAttached` | out | | The role's part is installed | | `CodeAnalyzerCommonPropsPath`, `CodeFixerCommonPropsPath`, `SourceGeneratorCommonPropsPath`, `RoslynComponentCommonPropsPath` | out | | The props a Roslyn project imports | | `MSKit_HasCodeFixer` | set | `True` | Look for the sibling code-fix project | @@ -176,6 +177,6 @@ Every property and item the kit sets or reads, grouped by topic. **Set** = a val | Name | Kind | Default | Meaning | | --- | --- | --- | --- | -| `PackageAsProj_SkipChecks` | set | empty | `True` skips `MSKIT_PAP002` ([PackageAsProj](../optional-parts.md#packageasproj)) | +| `PackageAsProj_SkipChecks` | set | empty | `True` skips `MSKITPAP002` ([PackageAsProj](../optional-parts.md#packageasproj)) | | `ProjMetadataOutDir` | set | empty (off) | Where the metadata YAML goes ([ProjMetadata](../optional-parts.md#projmetadata)) | | `MSKit_EFScriptsDir` | out | | The EF scripts folder ([EF](../optional-parts.md#ef)) | diff --git a/docs/roslyn.md b/docs/roslyn.md index e7b0eb4..080d4ab 100644 --- a/docs/roslyn.md +++ b/docs/roslyn.md @@ -28,9 +28,9 @@ A project needs **both** of these: | code fix (`Acme.CodeFixes`) | `$(CodeFixerCommonPropsPath)` | | source generator (`Acme.SourceGenerator`) | `$(SourceGeneratorCommonPropsPath)` | -The analyzer and code-fix props set their role themselves, so a project with another name only needs the import; a source generator with another name also sets `true` above it. Set your own `Description`: the analyzer's default, "Code analyzers description", fails [`MSKIT_PKG002`](./reference/codes.md#mskitpkg002). +The analyzer and code-fix props set their role themselves, so a project with another name only needs the import; a source generator with another name also sets `true` above it. Set your own `Description`: the analyzer's default, "Code analyzers description", fails [`MSKITPKG002`](./reference/codes.md#mskitpkg002). -A project whose name matches a role but whose part is not installed fails with [`MSKIT_ROSLYN001`](./reference/codes.md#mskitroslyn001)-[`003`](./reference/codes.md#mskitroslyn003); a name that matches two roles fails with [`MSKIT_CORE001`](./reference/codes.md#mskitcore001). Detection runs in the props phase, so to stop it set `MSKit_DisableAutoDetect=true` (`MSKit_DisableCodeAnalyzerAutoDetect`, …) or narrow the regex, in `Directory.Build.props` above the kit import; set in the csproj, as the error text suggests, it comes too late. +A project whose name matches a role but whose part is not installed fails with [`MSKITROSLYN001`](./reference/codes.md#mskitroslyn001)-[`003`](./reference/codes.md#mskitroslyn003); a name that matches two roles fails with [`MSKITCORE001`](./reference/codes.md#mskitcore001). Detection runs in the props phase, so to stop it set `MSKit_DisableAutoDetect=true` (`MSKit_DisableCodeAnalyzerAutoDetect`, …) or narrow the regex, in `Directory.Build.props` above the kit import; set in the csproj, as the error text suggests, it comes too late. ## What the props set @@ -38,7 +38,7 @@ Every role (`$(RoslynComponentCommonPropsPath)`, imported by the three above): | Setting | Value | | --- | --- | -| `TargetFramework` | `netstandard2.0` (a shared `TargetFrameworks` is cleared, and the `MSKIT_SHARED008` override warning is skipped) | +| `TargetFramework` | `netstandard2.0` (a shared `TargetFrameworks` is cleared, and the `MSKITSHARED008` override warning is skipped) | | `IsRoslynComponent`, `EnforceExtendedAnalyzerRules`, `DevelopmentDependency` | `True` | | `IsPackable` | `True` | | `IncludeBuildOutput`, `IncludeSymbols` | `False`: the dll goes to `analyzers/dotnet/cs/`, not `lib/` | diff --git a/docs/testing.md b/docs/testing.md index 9d495b7..8657d6d 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -9,7 +9,7 @@ The Testing and Testing.XUnit.v3 parts turn a project into a test project by its | test project | `MSKit_TestsProjectNameRegex`, default `\.(Tests(\.Integration\|\.Unit)?\|IntegrationTests\|UnitTests)$`: `Acme.Tests`, `Acme.Tests.Unit`, `Acme.Tests.Integration`, `Acme.UnitTests`, `Acme.IntegrationTests` | `IsTestsProject=True`: an executable test host, never packable | | test helper library | `MSKit_TestsLibProjectNameRegex`, default `\.(TestsSuite\|TestsFixtures\|Fixtures)$` | `IsTestsLibProject=True`: shared fixtures and base classes with the assertion and xUnit libraries, not runnable | -Detection runs in the props phase, because the test framework's own targets read the result before `Directory.Build.targets`. So a project whose name does not match cannot just set `IsTestsProject` in its csproj — that fails with [`MSKIT_TEST013`](./reference/codes.md#mskittest013). Use the explicit endpoint instead: +Detection runs in the props phase, because the test framework's own targets read the result before `Directory.Build.targets`. So a project whose name does not match cannot just set `IsTestsProject` in its csproj — that fails with [`MSKITTEST013`](./reference/codes.md#mskittest013). Use the explicit endpoint instead: ```xml @@ -48,7 +48,7 @@ dotnet test --solution MyRepo.slnx -c Release --coverage --coverage-output-forma ## `InternalsVisibleTo` -Every project that is neither a test project nor a helper library exposes its internals to **every** test project and helper library found under `MSKit_TestsDir` (default: the solution folder, else the git root), and to `DynamicProxyGenAssembly2`, so NSubstitute can mock internal types. `InternalsVisibleToAllTestsProjects=False` in a csproj turns it off for that project. [`MSKIT_TEST030`](./reference/codes.md#mskittest030) and [`MSKIT_TEST031`](./reference/codes.md#mskittest031) warn when `MSKit_TestsDir` is empty or missing. +Every project that is neither a test project nor a helper library exposes its internals to **every** test project and helper library found under `MSKit_TestsDir` (default: the solution folder, else the git root), and to `DynamicProxyGenAssembly2`, so NSubstitute can mock internal types. `InternalsVisibleToAllTestsProjects=False` in a csproj turns it off for that project. [`MSKITTEST030`](./reference/codes.md#mskittest030) and [`MSKITTEST031`](./reference/codes.md#mskittest031) warn when `MSKit_TestsDir` is empty or missing. ## Package versions @@ -73,8 +73,8 @@ The kit provides these versions ([Build](./build.md#central-package-versions)); | Code | When | | --- | --- | -| [`MSKIT_TEST005`](./reference/codes.md#mskittest005) | an xUnit v3 test project targets a framework older than net8.0 | -| [`MSKIT_TEST010`](./reference/codes.md#mskittest010)-[`012`](./reference/codes.md#mskittest012), [`MSKIT_TEST020`](./reference/codes.md#mskittest020)-[`022`](./reference/codes.md#mskittest022) | the explicit endpoint was imported before `MSKit_TestingFramework` was set, the framework changed after it, or no wiring exists for it | -| [`MSKIT_TEST013`](./reference/codes.md#mskittest013) | a csproj sets `IsTestsProject` directly | -| [`MSKIT_TEST014`](./reference/codes.md#mskittest014) | a project named like a test project is marked as a helper library | -| [`MSKIT_TEST025`](./reference/codes.md#mskittest025), [`MSKIT_TEST026`](./reference/codes.md#mskittest026) | a test project has no `MSKit_TestingFramework`, or no installed part wires it | +| [`MSKITTEST005`](./reference/codes.md#mskittest005) | an xUnit v3 test project targets a framework older than net8.0 | +| [`MSKITTEST010`](./reference/codes.md#mskittest010)-[`012`](./reference/codes.md#mskittest012), [`MSKITTEST020`](./reference/codes.md#mskittest020)-[`022`](./reference/codes.md#mskittest022) | the explicit endpoint was imported before `MSKit_TestingFramework` was set, the framework changed after it, or no wiring exists for it | +| [`MSKITTEST013`](./reference/codes.md#mskittest013) | a csproj sets `IsTestsProject` directly | +| [`MSKITTEST014`](./reference/codes.md#mskittest014) | a project named like a test project is marked as a helper library | +| [`MSKITTEST025`](./reference/codes.md#mskittest025), [`MSKITTEST026`](./reference/codes.md#mskittest026) | a test project has no `MSKit_TestingFramework`, or no installed part wires it | diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 83bed30..40134a4 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,6 +1,6 @@ # Troubleshooting -Symptoms, their cause, and the fix. A build message with an `MSKIT_` code is explained in the [code reference](./reference/codes.md). +Symptoms, their cause, and the fix. A kit warning or error code such as `MSKITVER006` is explained in the [code reference](./reference/codes.md), and the code links to its section. ## Updating @@ -10,18 +10,19 @@ Symptoms, their cause, and the fix. A build message with an `MSKIT_` code is exp | `SHA-256 mismatch … expected … (kit.json or --sha256)` | the release zip differs from the one pinned in `kit.json` for the same version | find out why the release changed before installing; `--sha256` with the new hash accepts it | | `update.sh` without `--version` installs the version you already have | it reinstalls the pinned version | pass `--version ` ([Install and update](./install-and-update.md)) | | `'' is a default part and cannot be removed` | default parts are always installed | — | +| After an update, `NoWarn`, `WarningsAsErrors`, `WarningsNotAsErrors` or `MSKit_SkipPackageChecks` no longer affect a kit code | codes lost the underscore after the prefix (`MSKITVER006`) | rename the entries; each section of the [code reference](./reference/codes.md) names the code's former spelling | ## Building | Symptom | Cause | Fix | | --- | --- | --- | -| Many [`MSKIT_DUP001`](./reference/codes.md#mskitdup001) errors right after installing | `Directory.Packages.props` repeats versions the kit provides | delete those `PackageVersion` lines, or override the kit's `MSKit_PackageVersion_*` property ([Build](./build.md#central-package-versions)) | +| Many [`MSKITDUP001`](./reference/codes.md#mskitdup001) errors right after installing | `Directory.Packages.props` repeats versions the kit provides | delete those `PackageVersion` lines, or override the kit's `MSKit_PackageVersion_*` property ([Build](./build.md#central-package-versions)) | | The version is `9999.0.0` | a developer-machine build (no `GITHUB_RUN_ID`) | expected; `-p:MSKit_IsDevEnv=False` builds as CI ([Versioning](./versioning.md)) | -| `dotnet msbuild -getProperty:Version` prints `unknown placeholder: …` | a version template uses a placeholder the engine does not know | fix the template; a real build stops with [`MSKIT_VER002`](./reference/codes.md#mskitver002) | -| Restore fails on a tag build with [`MSKIT_VER006`](./reference/codes.md#mskitver006) | the tag is not a SemVer 2.0 version | delete the tag and the release, tag again (`v2.1.0`, `v2.1.0-beta.1`) | -| [`MSKIT_SHARED006`](./reference/codes.md#mskitshared006) / [`007`](./reference/codes.md#mskitshared007) after moving `TargetFrameworks` to `Directory.Build.props` | the csproj still repeats the value | delete it from the csproj | -| [`MSKIT_SHARED020`](./reference/codes.md#mskitshared020) locally, but CI is green | a csproj changes `TreatWarningsAsErrors`; the check runs on developer machines only | align the csproj, or set `MSKit_SkipAudit_TreatWarningsAsErrors=True` | -| [`MSKIT_ROSLYN001`](./reference/codes.md#mskitroslyn001)-`003` on a project that is not a Roslyn component | its name ends in `.Analyzers`, `.CodeFixes` or `.SourceGenerator` | rename it, or set `MSKit_DisableAutoDetect=true` in `Directory.Build.props` above the kit import ([Roslyn](./roslyn.md#wiring-a-project)) | +| `dotnet msbuild -getProperty:Version` prints `unknown placeholder: …` | a version template uses a placeholder the engine does not know | fix the template; a real build stops with [`MSKITVER002`](./reference/codes.md#mskitver002) | +| Restore fails on a tag build with [`MSKITVER006`](./reference/codes.md#mskitver006) | the tag is not a SemVer 2.0 version | delete the tag and the release, tag again (`v2.1.0`, `v2.1.0-beta.1`) | +| [`MSKITSHARED006`](./reference/codes.md#mskitshared006) / [`007`](./reference/codes.md#mskitshared007) after moving `TargetFrameworks` to `Directory.Build.props` | the csproj still repeats the value | delete it from the csproj | +| [`MSKITSHARED020`](./reference/codes.md#mskitshared020) locally, but CI is green | a csproj changes `TreatWarningsAsErrors`; the check runs on developer machines only | align the csproj, or set `MSKit_SkipAudit_TreatWarningsAsErrors=True` | +| [`MSKITROSLYN001`](./reference/codes.md#mskitroslyn001)-`003` on a project that is not a Roslyn component | its name ends in `.Analyzers`, `.CodeFixes` or `.SourceGenerator` | rename it, or set `MSKit_DisableAutoDetect=true` in `Directory.Build.props` above the kit import ([Roslyn](./roslyn.md#wiring-a-project)) | | An `*.Analyzers` project builds for the shared target frameworks and references no Roslyn package | the role's props are not imported | add `` ([Roslyn](./roslyn.md#wiring-a-project)) | | `IsNET8` is empty in a csproj `PropertyGroup` of a single-framework project | the constants are known in the props phase only for multi-targeted inner builds | test them in item and target conditions or in `Directory.Build.targets` ([Build](./build.md#target-framework-constants)) | @@ -29,7 +30,7 @@ Symptoms, their cause, and the fix. A build message with an `MSKIT_` code is exp | Symptom | Cause | Fix | | --- | --- | --- | -| [`MSKIT_TEST013`](./reference/codes.md#mskittest013) | the csproj sets `IsTestsProject` | rename the project to `*.Tests`, or use `$(TestsProjectCommonPropsPath)` ([Testing](./testing.md#which-projects-are-test-projects)) | +| [`MSKITTEST013`](./reference/codes.md#mskittest013) | the csproj sets `IsTestsProject` | rename the project to `*.Tests`, or use `$(TestsProjectCommonPropsPath)` ([Testing](./testing.md#which-projects-are-test-projects)) | | `dotnet test` on SDK 10 rejects `--solution`, `--coverage` or `--report-trx` | without the runner in `global.json` it runs in VSTest mode | add `"test": { "runner": "Microsoft.Testing.Platform" }` ([Microsoft.Testing.Platform mode](https://learn.microsoft.com/dotnet/core/testing/unit-testing-with-dotnet-test)) | | NSubstitute cannot mock an internal type | the project under test is not exposing internals | keep `InternalsVisibleToAllTestsProjects` on and the test project under `MSKit_TestsDir` ([Testing](./testing.md#internalsvisibleto)) | @@ -37,6 +38,6 @@ Symptoms, their cause, and the fix. A build message with an `MSKIT_` code is exp | Symptom | Cause | Fix | | --- | --- | --- | -| `dotnet pack` passes locally and fails on CI with `MSKIT_PKG` errors | the checks are warnings on a developer machine and errors on CI | fix the warnings the local pack prints ([Packaging](./packaging.md#checks)) | -| [`MSKIT_PKG016`](./reference/codes.md#mskitpkg016) on GitHub Enterprise, GitLab or another host | the release-notes default exists only for `github.com` | set `PackageReleaseNotes`, or generate the readme with `MSKit_PackageReadmeFrom` ([Package readme](./package-readme.md)) | -| [`MSKIT_PKG021`](./reference/codes.md#mskitpkg021) for every image of a self-hosted GitLab | nuget.org shows images only from its allowed hosts | host the images elsewhere, or point `MSKit_RepoRawUrlTemplate` at an allowed host | +| `dotnet pack` passes locally and fails on CI with `MSKITPKG` errors | the checks are warnings on a developer machine and errors on CI | fix the warnings the local pack prints ([Packaging](./packaging.md#checks)) | +| [`MSKITPKG016`](./reference/codes.md#mskitpkg016) on GitHub Enterprise, GitLab or another host | the release-notes default exists only for `github.com` | set `PackageReleaseNotes`, or generate the readme with `MSKit_PackageReadmeFrom` ([Package readme](./package-readme.md)) | +| [`MSKITPKG021`](./reference/codes.md#mskitpkg021) for every image of a self-hosted GitLab | nuget.org shows images only from its allowed hosts | host the images elsewhere, or point `MSKit_RepoRawUrlTemplate` at an allowed host | diff --git a/docs/versioning.md b/docs/versioning.md index a9fc710..330c9be 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -14,7 +14,7 @@ With the owner layer's `MSKit_VersionStrategy=ReleaseTag`: | A stable branch (`main`, `release/*`), run 7 | `1.4.0-ci.7` | `MSKit_StableVersionTemplate` = `{prefix}-ci.{buildNumber}` | | Any other branch, run 7 | `1.4.0-ci.7` | `MSKit_VersionTemplate` = `{prefix}-ci.{buildNumber}` | -A **tag build** is any GitHub Actions run with `GITHUB_REF_TYPE=tag`: publishing a GitHub release creates one, and so does pushing a tag without a release. A leading `v` or `V` is removed; the rest must be [SemVer 2.0](https://semver.org/), or restore fails with [`MSKIT_VER006`](./reference/codes.md#mskitver006). When the tag's `MAJOR.MINOR.PATCH` differs from `VersionPrefix`, [`MSKIT_VER007`](./reference/codes.md#mskitver007) reminds you to bump `VersionPrefix` after the release, so branch builds sort above it. +A **tag build** is any GitHub Actions run with `GITHUB_REF_TYPE=tag`: publishing a GitHub release creates one, and so does pushing a tag without a release. A leading `v` or `V` is removed; the rest must be [SemVer 2.0](https://semver.org/), or restore fails with [`MSKITVER006`](./reference/codes.md#mskitver006). When the tag's `MAJOR.MINOR.PATCH` differs from `VersionPrefix`, [`MSKITVER007`](./reference/codes.md#mskitver007) reminds you to bump `VersionPrefix` after the release, so branch builds sort above it. The template is picked in this order: a tag build with `MSKit_ReleaseVersionTemplate` set; a pull-request build with `MSKit_PullRequestVersionTemplate` set; a stable branch (`MSKit_IsStableBranch`, [Build](./build.md#roots-branch-and-commit)) → `MSKit_StableVersionTemplate`; anything else → `MSKit_VersionTemplate`. The version is rendered twice — in the props phase, so `dotnet msbuild -getProperty:Version` answers, and again before compile and pack, so a `VersionPrefix` or template set in a csproj is honoured. @@ -31,7 +31,7 @@ Set `MSKit_VersionStrategy` in `Directory.Build.props`. Any template can be over | `VersionTag` | | `{versionTag}` | `{versionTag}` | | `Manual` | | the engine is off: set `Version` yourself | | -Only `ReleaseTag` defines release-tag and pull-request templates; with the others a tag or pull-request build uses the branch templates unless you set them. `DateBased` uses the run id modulo 65535 as `{buildNumber}` (never 0). `VersionTag` needs `-p:VersionTag=1.2.3`, else [`MSKIT_VER004`](./reference/codes.md#mskitver004). +Only `ReleaseTag` defines release-tag and pull-request templates; with the others a tag or pull-request build uses the branch templates unless you set them. `DateBased` uses the run id modulo 65535 as `{buildNumber}` (never 0). `VersionTag` needs `-p:VersionTag=1.2.3`, else [`MSKITVER004`](./reference/codes.md#mskitver004). ## Placeholders @@ -50,12 +50,12 @@ Only `ReleaseTag` defines release-tag and pull-request templates; with the other | `{versionTag}` | `VersionTag` | | `{commitShaShort}` | the first 8 characters of `MSKit_CommitSha` | -An unknown placeholder fails the build with [`MSKIT_VER002`](./reference/codes.md#mskitver002). Each project reads the clock on its own; set `MSKit_BuildDateTimeUtc` (property or environment variable) once in CI so every project of one build gets the same date. +An unknown placeholder fails the build with [`MSKITVER002`](./reference/codes.md#mskitver002). Each project reads the clock on its own; set `MSKit_BuildDateTimeUtc` (property or environment variable) once in CI so every project of one build gets the same date. ## Setting the version yourself - **`-p:Version=2.0.0`**, or `Version` set in `Directory.Build.props` above the kit import, always wins: the engine renders nothing (`MSKit_ExplicitVersion`). -- **`` in a csproj** fails with [`MSKIT_VER001`](./reference/codes.md#mskitver001) while a template strategy is active, because it would be ignored: declare `VersionPrefix` in `Directory.Version.props`, or set `MSKit_VersionStrategy=Manual`. +- **`` in a csproj** fails with [`MSKITVER001`](./reference/codes.md#mskitver001) while a template strategy is active, because it would be ignored: declare `VersionPrefix` in `Directory.Version.props`, or set `MSKit_VersionStrategy=Manual`. ## CI variables diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.autodetect-mutex.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.autodetect-mutex.targets index 74fc36e..d0ef456 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.autodetect-mutex.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.autodetect-mutex.targets @@ -1,13 +1,13 @@ - + <_MSKit_AutoDetectedTypes>@(MSKit_AutoDetectedProjectType, ', ') - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.roslyn-satellites.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.roslyn-satellites.targets index d5b0b61..dd97fe2 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.roslyn-satellites.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.roslyn-satellites.targets @@ -1,13 +1,13 @@ - - @@ -16,7 +16,7 @@ BeforeTargets="CoreCompile;Build" Condition="'$(MSKit_IsCodeFixerAutoDetected)'=='True' AND '$(MSKit_CodeFixerSatelliteAttached)'!='true'"> - @@ -25,7 +25,7 @@ BeforeTargets="CoreCompile;Build" Condition="'$(MSKit_IsSourceGeneratorAutoDetected)'=='True' AND '$(MSKit_SourceGeneratorSatelliteAttached)'!='true'"> - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/core.common.props b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/core.common.props index cac50d6..f114686 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/core.common.props +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/core.common.props @@ -2,6 +2,7 @@ false + https://github.com/DragoAnt/MSBuildKit/blob/main/docs/reference/codes.md True diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.PackageAsProj/packageAsProj.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.PackageAsProj/packageAsProj.targets index 03588d0..e90fbe4 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.PackageAsProj/packageAsProj.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.PackageAsProj/packageAsProj.targets @@ -21,7 +21,7 @@ - @@ -33,7 +33,7 @@ - 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 fa84441..bf15e43 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets @@ -1,8 +1,8 @@ - @@ -47,61 +47,61 @@ - <_MSKit_PkgFinding Include="MSKIT_PKG001" Condition="'$(_MSKit_DescriptionIsPlaceholder)'=='True'" + <_MSKit_PkgFinding Include="MSKITPKG001" Condition="'$(_MSKit_DescriptionIsPlaceholder)'=='True'" Text="Package '$(PackageId)' has no real Description ('$(_MSKit_Description)'). nuget.org search shows it first: say what the package does and what sets it apart, in one or two sentences." Rule="$(_MSKit_PkgRules)#description" /> - <_MSKit_PkgFinding Include="MSKIT_PKG002" Condition="'$(_MSKit_DescriptionIsPlaceholder)'!='True' AND $(_MSKit_Description.Length) < $(MSKit_PackageDescriptionMinLength)" + <_MSKit_PkgFinding Include="MSKITPKG002" Condition="'$(_MSKit_DescriptionIsPlaceholder)'!='True' AND $(_MSKit_Description.Length) < $(MSKit_PackageDescriptionMinLength)" Text="Package '$(PackageId)' Description is $(_MSKit_Description.Length) characters ('$(_MSKit_Description)'); write at least $(MSKit_PackageDescriptionMinLength): what it does and for whom (MSKit_PackageDescriptionMinLength sets the bar)." Rule="$(_MSKit_PkgRules)#description" /> - <_MSKit_PkgFinding Include="MSKIT_PKG003" Condition="'$(PackageReadmeFile)'==''" + <_MSKit_PkgFinding Include="MSKITPKG003" Condition="'$(PackageReadmeFile)'==''" Text="Package '$(PackageId)' ships no README. Add package.readme.md next to the csproj: what it is, how to start, a short example, where to give feedback." Rule="$(_MSKit_PkgRules)#readme" /> - <_MSKit_PkgFinding Include="MSKIT_PKG004" Condition="'$(PackageTags)'==''" + <_MSKit_PkgFinding Include="MSKITPKG004" Condition="'$(PackageTags)'==''" Text="Package '$(PackageId)' has no PackageTags. Add a few search terms that are not already in the package id." Rule="$(_MSKit_PkgRules)#tags" /> - <_MSKit_PkgFinding Include="MSKIT_PKG005" Condition="'$(PackageIcon)'==''" + <_MSKit_PkgFinding Include="MSKITPKG005" Condition="'$(PackageIcon)'==''" Text="Package '$(PackageId)' has no icon. Set PackageIconPath to a 128x128 PNG or JPEG (the company layer of the kit sets one for every package)." Rule="$(_MSKit_PkgRules)#icon" /> - <_MSKit_PkgFinding Include="MSKIT_PKG006" Condition="'$(PackageLicenseExpression)'=='' AND '$(PackageLicenseFile)'==''" + <_MSKit_PkgFinding Include="MSKITPKG006" Condition="'$(PackageLicenseExpression)'=='' AND '$(PackageLicenseFile)'==''" Text="Package '$(PackageId)' has no licence. Without one nobody may use it. Set PackageLicenseExpression to an SPDX id (for example MIT)." Rule="$(_MSKit_PkgRules)#licensing" /> - <_MSKit_PkgFinding Include="MSKIT_PKG007" Condition="'$(PackageLicenseUrl)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG007" Condition="'$(PackageLicenseUrl)'!=''" Text="Package '$(PackageId)' uses the deprecated PackageLicenseUrl. Replace it with PackageLicenseExpression (an SPDX id) or PackageLicenseFile." Rule="$(_MSKit_PkgRules)#licensing" /> - <_MSKit_PkgFinding Include="MSKIT_PKG008" Condition="'$(PackageIconUrl)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG008" Condition="'$(PackageIconUrl)'!=''" Text="Package '$(PackageId)' uses the deprecated PackageIconUrl. Pack the image and point PackageIcon (or the kit's PackageIconPath) at it." Rule="$(_MSKit_PkgRules)#icon" /> - <_MSKit_PkgFinding Include="MSKIT_PKG009" Condition="'$(_MSKit_RelativeImages)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG009" Condition="'$(_MSKit_RelativeImages)'!=''" Text="The package README of '$(PackageId)' has relative images, which nuget.org does not render: $(_MSKit_RelativeImages). Use absolute https URLs from an allowed host." Rule="$(_MSKit_PkgReadmeRules)#allowed-domains-for-images-and-badges" /> - <_MSKit_PkgFinding Include="MSKIT_PKG010" Condition="'$(_MSKit_HtmlTags)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG010" Condition="'$(_MSKit_HtmlTags)'!=''" Text="The package README of '$(PackageId)' contains HTML, which nuget.org does not render: $(_MSKit_HtmlTags). Use Markdown instead." Rule="$(_MSKit_PkgReadmeRules)#supported-markdown-features" /> - <_MSKit_PkgFinding Include="MSKIT_PKG011" Condition="'$(_MSKit_Alerts)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG011" Condition="'$(_MSKit_Alerts)'!=''" Text="The package README of '$(PackageId)' uses GitHub alert blocks, which nuget.org shows as plain quotes: $(_MSKit_Alerts). Use a bold lead-in such as **Note:** instead." Rule="$(_MSKit_PkgReadmeRules)#supported-markdown-features" /> - <_MSKit_PkgFinding Include="MSKIT_PKG012" Condition="'$(_MSKit_DisallowedImages)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG012" Condition="'$(_MSKit_DisallowedImages)'!=''" Text="The package README of '$(PackageId)' loads images from hosts nuget.org blocks: $(_MSKit_DisallowedImages). Host them on an allowed domain (img.shields.io, raw.githubusercontent.com, ...)." Rule="$(_MSKit_PkgReadmeRules)#allowed-domains-for-images-and-badges" /> - <_MSKit_PkgFinding Include="MSKIT_PKG013" Condition="'$(_MSKit_PkgVersion)'!='' AND !$([System.Text.RegularExpressions.Regex]::IsMatch('$(_MSKit_PkgVersion)', '$(MSKit_SemVerRegex)'))" + <_MSKit_PkgFinding Include="MSKITPKG013" Condition="'$(_MSKit_PkgVersion)'!='' AND !$([System.Text.RegularExpressions.Regex]::IsMatch('$(_MSKit_PkgVersion)', '$(MSKit_SemVerRegex)'))" Text="Package '$(PackageId)' version '$(_MSKit_PkgVersion)' is not SemVer 2.0 (MAJOR.MINOR.PATCH[-prerelease][+metadata])." Rule="$(_MSKit_PkgRules)#package-version" /> - <_MSKit_PkgFinding Include="MSKIT_PKG014" Condition="'$(_MSKit_RepoUrlFinal)'=='' OR '$(PackageProjectUrl)'==''" + <_MSKit_PkgFinding Include="MSKITPKG014" Condition="'$(_MSKit_RepoUrlFinal)'=='' OR '$(PackageProjectUrl)'==''" Text="Package '$(PackageId)' has no repository or project URL. Set RepositoryUrl, or build from a git clone whose origin remote Source Link can read." Rule="$(_MSKit_PkgRules)#repository-type-and-url" /> - <_MSKit_PkgFinding Include="MSKIT_PKG015" Condition="'$(MSKit_PackageIconSourcePath)'!='' AND Exists('$(MSKit_PackageIconSourcePath)') AND (('$(_MSKit_IconFormat)'!='PNG' AND '$(_MSKit_IconFormat)'!='JPEG') OR '$(_MSKit_IconWidth)'!='$(MSKit_PackageIconSize)' OR '$(_MSKit_IconHeight)'!='$(MSKit_PackageIconSize)')" + <_MSKit_PkgFinding Include="MSKITPKG015" Condition="'$(MSKit_PackageIconSourcePath)'!='' AND Exists('$(MSKit_PackageIconSourcePath)') AND (('$(_MSKit_IconFormat)'!='PNG' AND '$(_MSKit_IconFormat)'!='JPEG') OR '$(_MSKit_IconWidth)'!='$(MSKit_PackageIconSize)' OR '$(_MSKit_IconHeight)'!='$(MSKit_PackageIconSize)')" Text="Package '$(PackageId)' icon is not a $(MSKit_PackageIconSize)x$(MSKit_PackageIconSize) PNG or JPEG (format: $(_MSKit_IconFormat), size: $(_MSKit_IconWidth)x$(_MSKit_IconHeight))." Rule="$(_MSKit_PkgRules)#icon" /> - <_MSKit_PkgFinding Include="MSKIT_PKG016" Condition="'$(PackageReleaseNotes)'==''" + <_MSKit_PkgFinding Include="MSKITPKG016" Condition="'$(PackageReleaseNotes)'==''" 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)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG017" Condition="'$(_MSKit_RelativeLinks)'!=''" Text="The package README of '$(PackageId)' has relative links, which break on nuget.org: $(_MSKit_RelativeLinks). Use absolute URLs." Rule="$(_MSKit_PkgReadmeRules)" /> - <_MSKit_PkgFinding Include="MSKIT_PKG018" Condition="'$(_MSKit_LicenseIsOpen)'=='True' AND $(Copyright.ToLowerInvariant().Contains('all rights reserved'))" + <_MSKit_PkgFinding Include="MSKITPKG018" Condition="'$(_MSKit_LicenseIsOpen)'=='True' AND $(Copyright.ToLowerInvariant().Contains('all rights reserved'))" Text="Package '$(PackageId)' is licensed '$(PackageLicenseExpression)' but its Copyright says 'all rights reserved' ('$(Copyright)'). Use 'Copyright (c) YEAR OWNER'." Rule="$(_MSKit_PkgRules)#copyright" /> - <_MSKit_PkgFinding Include="MSKIT_PKG019" Condition="'$(_MSKit_HasMermaid)'=='True'" + <_MSKit_PkgFinding Include="MSKITPKG019" Condition="'$(_MSKit_HasMermaid)'=='True'" Text="The package README of '$(PackageId)' contains a Mermaid diagram, which nuget.org shows as code. Link to the diagram on GitHub instead." Rule="$(_MSKit_PkgReadmeRules)#supported-markdown-features" /> @@ -114,11 +114,13 @@ diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.inspect.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.inspect.targets index bdb9dd4..061477d 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.inspect.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.inspect.targets @@ -1,6 +1,6 @@ - + The MSKITPKG checks then read the generated file. Full description: docs/package-readme.md. --> $(MSBuildThisFileDirectory)nuget.allowed-image-hosts.txt @@ -34,7 +34,7 @@ - @@ -117,25 +117,25 @@ - <_MSKit_ReadmeCode Include="MSKIT_PKG020;MSKIT_PKG021;MSKIT_PKG022" /> + <_MSKit_ReadmeCode Include="MSKITPKG020;MSKITPKG021;MSKITPKG022" /> <_MSKit_ReadmeSkip Include="$(MSKit_SkipPackageChecks);$(NoWarn)" /> <_MSKit_ReadmeCode Remove="@(_MSKit_ReadmeSkip)" /> <_MSKit_ReadmeCodes>;@(_MSKit_ReadmeCode); - + - + - + - - - + + + 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 0ef49d8..4d3b6d5 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt @@ -165,7 +165,7 @@ public sealed class MSKit_PackageAssets : Task private void GenerateReadme() { - var codes =new[] { "MSKIT_PKG020", "MSKIT_PKG021", "MSKIT_PKG022" }; + var codes =new[] { "MSKITPKG020", "MSKITPKG021", "MSKITPKG022" }; var findings = codes.ToDictionary(c => c, c => new List()); Action report = (code, text) => findings[code].Add(text.Replace("\r", " ").Replace("\n", " ")); @@ -238,7 +238,7 @@ public sealed class MSKit_PackageAssets : Task case "": break; default: - report("MSKIT_PKG020", display + ": MSKit_RepoProvider '" + provider + "' is not one of GitHub, GitLab, AzureDevOps, Bitbucket, Gitea; set MSKit_RepoBlobUrlTemplate and MSKit_RepoRawUrlTemplate instead."); + report("MSKITPKG020", display + ": MSKit_RepoProvider '" + provider + "' is not one of GitHub, GitLab, AzureDevOps, Bitbucket, Gitea; set MSKit_RepoBlobUrlTemplate and MSKit_RepoRawUrlTemplate instead."); break; } if (norm(BlobTemplate).Length > 0) { blob = norm(BlobTemplate); tree = blob.Contains("/blob/") ? blob.Replace("/blob/", "/tree/") : blob; } @@ -277,7 +277,7 @@ public sealed class MSKit_PackageAssets : Task if (!Uri.TryCreate(url.Trim('<', '>'), UriKind.Absolute, out u) || (u.Scheme != "https" && u.Scheme != "http")) return; var h = u.Host.ToLowerInvariant(); if (allowed.Contains(h) || (h == "github.com" && Regex.IsMatch(u.AbsolutePath, @"^/[^/]+/[^/]+/(actions/)?workflows/[^/]+/badge\.svg$", RegexOptions.IgnoreCase))) return; - report("MSKIT_PKG021", display + " line " + n + ": the image " + url + " comes from " + h + ", a host nuget.org does not show images from. Use an allowed host (nuget.allowed-image-hosts.txt in the kit) or point MSKit_RepoRawUrlTemplate at one."); + report("MSKITPKG021", display + " line " + n + ": the image " + url + " comes from " + h + ", a host nuget.org does not show images from. Use an allowed host (nuget.allowed-image-hosts.txt in the kit) or point MSKit_RepoRawUrlTemplate at one."); }; Func resolve = (target, isImage, n) => @@ -293,7 +293,7 @@ public sealed class MSKit_PackageAssets : Task var rp = combine(Uri.UnescapeDataString(p)); if (rp == null) { - report("MSKIT_PKG020", display + " line " + n + ": " + t + " points outside the repository and is left as it is."); + report("MSKITPKG020", display + " line " + n + ": " + t + " points outside the repository and is left as it is."); return target; } var isDir = Directory.Exists(Path.Combine(root, rp.Replace('/', Path.DirectorySeparatorChar))); @@ -361,25 +361,25 @@ public sealed class MSKit_PackageAssets : Task } if (skipOpen.IsMatch(line)) { - if (skipping) report("MSKIT_PKG020", display + " line " + n + ": nuget:skip opened again before line " + skipLine + "'s was closed."); + if (skipping) report("MSKITPKG020", display + " line " + n + ": nuget:skip opened again before line " + skipLine + "'s was closed."); skipping = true; skipLine = n; continue; } if (skipClose.IsMatch(line)) { - if (!skipping) report("MSKIT_PKG020", display + " line " + n + ": /nuget:skip has no matching nuget:skip."); + if (!skipping) report("MSKITPKG020", display + " line " + n + ": /nuget:skip has no matching nuget:skip."); skipping = false; continue; } var om = onlyOpen.Match(line); if (om.Success) { - if (inOnly) report("MSKIT_PKG020", display + " line " + n + ": nuget:only opened again before line " + onlyLine + "'s was closed."); + if (inOnly) report("MSKITPKG020", display + " line " + n + ": nuget:only opened again before line " + onlyLine + "'s was closed."); inOnly = true; onlyLine = n; keepOnly = Regex.Split(om.Groups[1].Value.Trim(), @"[\s,]+").Any(id => string.Equals(id, PackageId, StringComparison.OrdinalIgnoreCase)); continue; } if (onlyClose.IsMatch(line)) { - if (!inOnly) report("MSKIT_PKG020", display + " line " + n + ": /nuget:only has no matching nuget:only."); + if (!inOnly) report("MSKITPKG020", display + " line " + n + ": /nuget:only has no matching nuget:only."); inOnly = false; keepOnly = true; continue; } var fm = fenceRe.Match(line); @@ -393,10 +393,10 @@ public sealed class MSKit_PackageAssets : Task outLines.Add(rewriteLine(line, n)); outFence.Add(false); } - if (skipping) report("MSKIT_PKG020", display + " line " + skipLine + ": nuget:skip is never closed, so everything after it is left out."); - if (inOnly) report("MSKIT_PKG020", display + " line " + onlyLine + ": nuget:only is never closed."); + if (skipping) report("MSKITPKG020", display + " line " + skipLine + ": nuget:skip is never closed, so everything after it is left out."); + if (inOnly) report("MSKITPKG020", display + " line " + onlyLine + ": nuget:only is never closed."); if (!canRewrite && unresolved > 0) - report("MSKIT_PKG020", display + ": " + unresolved + " relative link(s) and image(s) stay relative because " + why + "."); + report("MSKITPKG020", display + ": " + unresolved + " relative link(s) and image(s) stay relative because " + why + "."); var title = norm(ReadmeTitle) == "auto" ? norm(PackageId) : norm(ReadmeTitle); if (title.Length > 0) @@ -449,7 +449,7 @@ public sealed class MSKit_PackageAssets : Task var visibility = norm(Visibility).ToLowerInvariant(); if (visibility == "private" || visibility == "internal") - report("MSKIT_PKG022", "The repository " + (repoUrl.Length > 0 ? repoUrl : "of " + PackageId) + " is " + visibility + ": the links in the package readme of " + PackageId + " will not open for people reading it on nuget.org. Publish from a public repository, or point MSKit_RepoBlobUrlTemplate and MSKit_RepoRawUrlTemplate at a public mirror."); + report("MSKITPKG022", "The repository " + (repoUrl.Length > 0 ? repoUrl : "of " + PackageId) + " is " + visibility + ": the links in the package readme of " + PackageId + " will not open for people reading it on nuget.org. Publish from a public repository, or point MSKit_RepoBlobUrlTemplate and MSKit_RepoRawUrlTemplate at a public mirror."); var result = new List(); var blank = true; diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing.XUnit.v3/audit/audit.tests.project.xunit.v3.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing.XUnit.v3/audit/audit.tests.project.xunit.v3.targets index febe8d5..adb4177 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing.XUnit.v3/audit/audit.tests.project.xunit.v3.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing.XUnit.v3/audit/audit.tests.project.xunit.v3.targets @@ -1,13 +1,13 @@ - + - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.internalsVisibleTo.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.internalsVisibleTo.targets index 8de8fe0..3164d5b 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.internalsVisibleTo.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.internalsVisibleTo.targets @@ -4,7 +4,7 @@ - @@ -12,7 +12,7 @@ - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.lib.project.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.lib.project.targets index 11cb07e..0d8e18e 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.lib.project.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.lib.project.targets @@ -1,35 +1,35 @@ - + - + - - + - - + - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.project.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.project.targets index 8075de2..5035f83 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.project.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.project.targets @@ -1,13 +1,13 @@ - - @@ -17,7 +17,7 @@ Condition="'$(_MSKit_TestsProjectCommonPropsImported)'=='True' AND '$(_MSKit_TestingFrameworkAtCommonPropsImport)'!='' AND '$(_MSKit_TestingFrameworkAtCommonPropsImport)'!='$(MSKit_TestingFramework)'"> - @@ -27,12 +27,12 @@ Condition="'$(_MSKit_TestsProjectCommonPropsImported)'=='True' AND '$(MSKit_TestingFramework_CommonPropsPath)'=='' AND '$(MSKit_TestingFramework)'!=''"> - - $([System.Text.RegularExpressions.Regex]::Replace($(_MSKit_CsprojText013), '<!--[\s\S]*?-->', '')) <_MSKit_HasDirectIsTestsProject>$([System.Text.RegularExpressions.Regex]::IsMatch($(_MSKit_CsprojText013), '<IsTestsProject\s*>')) - @@ -55,7 +55,7 @@ Condition="'$(MSKit_IsTestsProjectAutoDetected)'=='True' AND ('$(IsTestsLibProject)'=='True' OR '$(_MSKit_TestsLibProjectCommonPropsImported)'=='True') AND '$(MSKit_IsTestsLibProjectAutoDetected)'!='True'"> - @@ -65,7 +65,7 @@ Condition="('$(IsTestsProject)'=='True' OR '$(IsTestsLibProject)'=='True') AND '$(MSKit_TestingFramework)'!='' AND '$(MSKit_TestingFrameworkAttached)'!='true'"> - @@ -74,7 +74,7 @@ BeforeTargets="CoreCompile;Build" Condition="('$(IsTestsProject)'=='True' OR '$(IsTestsLibProject)'=='True') AND '$(MSKit_TestingFramework)'==''"> - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.lib.project.common.props b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.lib.project.common.props index 9685d6b..e280c2f 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.lib.project.common.props +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.lib.project.common.props @@ -1,7 +1,7 @@ + (MSKITTEST020 checks it). --> <_MSKit_TestingFrameworkAtLibCommonPropsImport>$(MSKit_TestingFramework) <_MSKit_TestsLibProjectCommonPropsImported>True diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.project.common.props b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.project.common.props index 72b358c..bc9dfbb 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.project.common.props +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.project.common.props @@ -1,7 +1,7 @@ + match. Set MSKit_TestingFramework before the import (MSKITTEST010 checks it). --> <_MSKit_TestingFrameworkAtCommonPropsImport>$(MSKit_TestingFramework) <_MSKit_TestsProjectCommonPropsImported>True diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.implicit.packages.duplicates.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.implicit.packages.duplicates.targets index b03a750..225b9e6 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.implicit.packages.duplicates.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.implicit.packages.duplicates.targets @@ -1,6 +1,6 @@ - @@ -25,7 +25,7 @@ AND $(_MSKit_ConsumerIdsStr.Contains(';%(PackageVersion.Identity);'))" /> - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.prerelease.packages.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.prerelease.packages.targets index 534e94f..e84b7bf 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.prerelease.packages.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.prerelease.packages.targets @@ -1,6 +1,6 @@ - @@ -18,10 +18,10 @@ <_MSKit_PrereleaseText>Prerelease $(MSKit_PrereleasePackagePrefix)* packages referenced on stable branch '$(MSKit_Branch)':%0A@(_MSKit_PrereleaseReferences->' %(Identity) %(Version)', '%0A')%0AFix: replace them with stable versions in Directory.Packages.props or the csproj. - - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.packages.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.packages.targets index 4fba85c..f1ad97e 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.packages.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.packages.targets @@ -1,6 +1,6 @@ - @@ -13,17 +13,17 @@ SkipGlobalRestriction="True" /> - - - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.reference.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.reference.targets index 6e84fa3..462ab83 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.reference.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.reference.targets @@ -1,6 +1,6 @@ - @@ -15,7 +15,7 @@ - @@ -26,7 +26,7 @@ <_MSKit_PackageReferenceNotAllowListed Include="@(PackageReference)" Condition=" '%(PackageReference.Allowed)'!='True' AND '@(PackageReference)'!='' AND '%(Identity)'!=''" /> - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.shared.properties.targets b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.shared.properties.targets index eeda662..d86f043 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.shared.properties.targets +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.shared.properties.targets @@ -30,29 +30,29 @@ <_MSKit_TFs_ProjNodeCount>@(_MSKit_TFs_NodeCheckXmlResult->Count()) - - - - - - - - - - @@ -87,7 +87,7 @@ True - - + - + @@ -17,13 +17,13 @@ - - + @@ -56,35 +56,35 @@ Valid placeholders: <_MSKit_UnknownPlaceholder Include="@(_MSKit_TplNameItem)" Exclude="@(_MSKit_ValidPlaceholder)" /> - - + - - - <_MSKit_ReleaseTagCore>$([System.Text.RegularExpressions.Regex]::Match('$(MSKit_ReleaseTag)', '^\d+\.\d+\.\d+').Value) - diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/twae.shared.init.props b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/twae.shared.init.props index ffddb18..072f863 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/twae.shared.init.props +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/twae.shared.init.props @@ -1,6 +1,6 @@ - + $(TreatWarningsAsErrors) diff --git a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/version.props b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/version.props index 6e356cf..83c5779 100644 --- a/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/version.props +++ b/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/version.props @@ -97,7 +97,7 @@ <_MSKit_Ph_versionTag>$(VersionTag) <_MSKit_Ph_releaseTag Condition="'$(MSKit_IsReleaseTagValid)'=='true'">$(MSKit_ReleaseTag) + error; ValidateReleaseTag then stops the build with MSKITVER006. --> <_MSKit_Ph_releaseTag Condition="'$(MSKit_IsReleaseTagValid)'!='true'">0.0.0-invalid-release-tag <_MSKit_Ph_prNumber>$(MSKit_PullRequestNumber) <_MSKit_Ph_buildNumber>$(MSKit_BuildNumber) diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.autodetect-mutex.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.autodetect-mutex.targets index 74fc36e..d0ef456 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.autodetect-mutex.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.autodetect-mutex.targets @@ -1,13 +1,13 @@ - + <_MSKit_AutoDetectedTypes>@(MSKit_AutoDetectedProjectType, ', ') - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.roslyn-satellites.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.roslyn-satellites.targets index d5b0b61..dd97fe2 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.roslyn-satellites.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/audit/audit.roslyn-satellites.targets @@ -1,13 +1,13 @@ - - @@ -16,7 +16,7 @@ BeforeTargets="CoreCompile;Build" Condition="'$(MSKit_IsCodeFixerAutoDetected)'=='True' AND '$(MSKit_CodeFixerSatelliteAttached)'!='true'"> - @@ -25,7 +25,7 @@ BeforeTargets="CoreCompile;Build" Condition="'$(MSKit_IsSourceGeneratorAutoDetected)'=='True' AND '$(MSKit_SourceGeneratorSatelliteAttached)'!='true'"> - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/core.common.props b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/core.common.props index cac50d6..f114686 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/core.common.props +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Core/core.common.props @@ -2,6 +2,7 @@ false + https://github.com/DragoAnt/MSBuildKit/blob/main/docs/reference/codes.md True diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets index 563bc1e..bf15e43 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/audit/audit.package.targets @@ -1,8 +1,8 @@ - @@ -29,7 +29,7 @@ - + @@ -47,61 +47,61 @@ - <_MSKit_PkgFinding Include="MSKIT_PKG001" Condition="'$(_MSKit_DescriptionIsPlaceholder)'=='True'" + <_MSKit_PkgFinding Include="MSKITPKG001" Condition="'$(_MSKit_DescriptionIsPlaceholder)'=='True'" Text="Package '$(PackageId)' has no real Description ('$(_MSKit_Description)'). nuget.org search shows it first: say what the package does and what sets it apart, in one or two sentences." Rule="$(_MSKit_PkgRules)#description" /> - <_MSKit_PkgFinding Include="MSKIT_PKG002" Condition="'$(_MSKit_DescriptionIsPlaceholder)'!='True' AND $(_MSKit_Description.Length) < $(MSKit_PackageDescriptionMinLength)" + <_MSKit_PkgFinding Include="MSKITPKG002" Condition="'$(_MSKit_DescriptionIsPlaceholder)'!='True' AND $(_MSKit_Description.Length) < $(MSKit_PackageDescriptionMinLength)" Text="Package '$(PackageId)' Description is $(_MSKit_Description.Length) characters ('$(_MSKit_Description)'); write at least $(MSKit_PackageDescriptionMinLength): what it does and for whom (MSKit_PackageDescriptionMinLength sets the bar)." Rule="$(_MSKit_PkgRules)#description" /> - <_MSKit_PkgFinding Include="MSKIT_PKG003" Condition="'$(PackageReadmeFile)'==''" + <_MSKit_PkgFinding Include="MSKITPKG003" Condition="'$(PackageReadmeFile)'==''" Text="Package '$(PackageId)' ships no README. Add package.readme.md next to the csproj: what it is, how to start, a short example, where to give feedback." Rule="$(_MSKit_PkgRules)#readme" /> - <_MSKit_PkgFinding Include="MSKIT_PKG004" Condition="'$(PackageTags)'==''" + <_MSKit_PkgFinding Include="MSKITPKG004" Condition="'$(PackageTags)'==''" Text="Package '$(PackageId)' has no PackageTags. Add a few search terms that are not already in the package id." Rule="$(_MSKit_PkgRules)#tags" /> - <_MSKit_PkgFinding Include="MSKIT_PKG005" Condition="'$(PackageIcon)'==''" - Text="Package '$(PackageId)' has no icon. Set PackageIconPath to a 128x128 PNG (the company layer of the kit sets one for every package)." + <_MSKit_PkgFinding Include="MSKITPKG005" Condition="'$(PackageIcon)'==''" + Text="Package '$(PackageId)' has no icon. Set PackageIconPath to a 128x128 PNG or JPEG (the company layer of the kit sets one for every package)." Rule="$(_MSKit_PkgRules)#icon" /> - <_MSKit_PkgFinding Include="MSKIT_PKG006" Condition="'$(PackageLicenseExpression)'=='' AND '$(PackageLicenseFile)'==''" + <_MSKit_PkgFinding Include="MSKITPKG006" Condition="'$(PackageLicenseExpression)'=='' AND '$(PackageLicenseFile)'==''" Text="Package '$(PackageId)' has no licence. Without one nobody may use it. Set PackageLicenseExpression to an SPDX id (for example MIT)." Rule="$(_MSKit_PkgRules)#licensing" /> - <_MSKit_PkgFinding Include="MSKIT_PKG007" Condition="'$(PackageLicenseUrl)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG007" Condition="'$(PackageLicenseUrl)'!=''" Text="Package '$(PackageId)' uses the deprecated PackageLicenseUrl. Replace it with PackageLicenseExpression (an SPDX id) or PackageLicenseFile." Rule="$(_MSKit_PkgRules)#licensing" /> - <_MSKit_PkgFinding Include="MSKIT_PKG008" Condition="'$(PackageIconUrl)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG008" Condition="'$(PackageIconUrl)'!=''" Text="Package '$(PackageId)' uses the deprecated PackageIconUrl. Pack the image and point PackageIcon (or the kit's PackageIconPath) at it." Rule="$(_MSKit_PkgRules)#icon" /> - <_MSKit_PkgFinding Include="MSKIT_PKG009" Condition="'$(_MSKit_RelativeImages)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG009" Condition="'$(_MSKit_RelativeImages)'!=''" Text="The package README of '$(PackageId)' has relative images, which nuget.org does not render: $(_MSKit_RelativeImages). Use absolute https URLs from an allowed host." Rule="$(_MSKit_PkgReadmeRules)#allowed-domains-for-images-and-badges" /> - <_MSKit_PkgFinding Include="MSKIT_PKG010" Condition="'$(_MSKit_HtmlTags)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG010" Condition="'$(_MSKit_HtmlTags)'!=''" Text="The package README of '$(PackageId)' contains HTML, which nuget.org does not render: $(_MSKit_HtmlTags). Use Markdown instead." Rule="$(_MSKit_PkgReadmeRules)#supported-markdown-features" /> - <_MSKit_PkgFinding Include="MSKIT_PKG011" Condition="'$(_MSKit_Alerts)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG011" Condition="'$(_MSKit_Alerts)'!=''" Text="The package README of '$(PackageId)' uses GitHub alert blocks, which nuget.org shows as plain quotes: $(_MSKit_Alerts). Use a bold lead-in such as **Note:** instead." Rule="$(_MSKit_PkgReadmeRules)#supported-markdown-features" /> - <_MSKit_PkgFinding Include="MSKIT_PKG012" Condition="'$(_MSKit_DisallowedImages)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG012" Condition="'$(_MSKit_DisallowedImages)'!=''" Text="The package README of '$(PackageId)' loads images from hosts nuget.org blocks: $(_MSKit_DisallowedImages). Host them on an allowed domain (img.shields.io, raw.githubusercontent.com, ...)." Rule="$(_MSKit_PkgReadmeRules)#allowed-domains-for-images-and-badges" /> - <_MSKit_PkgFinding Include="MSKIT_PKG013" Condition="'$(_MSKit_PkgVersion)'!='' AND !$([System.Text.RegularExpressions.Regex]::IsMatch('$(_MSKit_PkgVersion)', '$(MSKit_SemVerRegex)'))" + <_MSKit_PkgFinding Include="MSKITPKG013" Condition="'$(_MSKit_PkgVersion)'!='' AND !$([System.Text.RegularExpressions.Regex]::IsMatch('$(_MSKit_PkgVersion)', '$(MSKit_SemVerRegex)'))" Text="Package '$(PackageId)' version '$(_MSKit_PkgVersion)' is not SemVer 2.0 (MAJOR.MINOR.PATCH[-prerelease][+metadata])." Rule="$(_MSKit_PkgRules)#package-version" /> - <_MSKit_PkgFinding Include="MSKIT_PKG014" Condition="'$(_MSKit_RepoUrlFinal)'=='' OR '$(PackageProjectUrl)'==''" + <_MSKit_PkgFinding Include="MSKITPKG014" Condition="'$(_MSKit_RepoUrlFinal)'=='' OR '$(PackageProjectUrl)'==''" Text="Package '$(PackageId)' has no repository or project URL. Set RepositoryUrl, or build from a git clone whose origin remote Source Link can read." Rule="$(_MSKit_PkgRules)#repository-type-and-url" /> - <_MSKit_PkgFinding Include="MSKIT_PKG015" Condition="'$(MSKit_PackageIconSourcePath)'!='' AND Exists('$(MSKit_PackageIconSourcePath)') AND ('$(_MSKit_IconIsPng)'!='True' OR '$(_MSKit_IconWidth)'!='$(MSKit_PackageIconSize)' OR '$(_MSKit_IconHeight)'!='$(MSKit_PackageIconSize)')" - Text="Package '$(PackageId)' icon is not a $(MSKit_PackageIconSize)x$(MSKit_PackageIconSize) PNG (PNG: $(_MSKit_IconIsPng), size: $(_MSKit_IconWidth)x$(_MSKit_IconHeight))." + <_MSKit_PkgFinding Include="MSKITPKG015" Condition="'$(MSKit_PackageIconSourcePath)'!='' AND Exists('$(MSKit_PackageIconSourcePath)') AND (('$(_MSKit_IconFormat)'!='PNG' AND '$(_MSKit_IconFormat)'!='JPEG') OR '$(_MSKit_IconWidth)'!='$(MSKit_PackageIconSize)' OR '$(_MSKit_IconHeight)'!='$(MSKit_PackageIconSize)')" + Text="Package '$(PackageId)' icon is not a $(MSKit_PackageIconSize)x$(MSKit_PackageIconSize) PNG or JPEG (format: $(_MSKit_IconFormat), size: $(_MSKit_IconWidth)x$(_MSKit_IconHeight))." Rule="$(_MSKit_PkgRules)#icon" /> - <_MSKit_PkgFinding Include="MSKIT_PKG016" Condition="'$(PackageReleaseNotes)'==''" + <_MSKit_PkgFinding Include="MSKITPKG016" Condition="'$(PackageReleaseNotes)'==''" 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)'!=''" + <_MSKit_PkgFinding Include="MSKITPKG017" Condition="'$(_MSKit_RelativeLinks)'!=''" Text="The package README of '$(PackageId)' has relative links, which break on nuget.org: $(_MSKit_RelativeLinks). Use absolute URLs." Rule="$(_MSKit_PkgReadmeRules)" /> - <_MSKit_PkgFinding Include="MSKIT_PKG018" Condition="'$(_MSKit_LicenseIsOpen)'=='True' AND $(Copyright.ToLowerInvariant().Contains('all rights reserved'))" + <_MSKit_PkgFinding Include="MSKITPKG018" Condition="'$(_MSKit_LicenseIsOpen)'=='True' AND $(Copyright.ToLowerInvariant().Contains('all rights reserved'))" Text="Package '$(PackageId)' is licensed '$(PackageLicenseExpression)' but its Copyright says 'all rights reserved' ('$(Copyright)'). Use 'Copyright (c) YEAR OWNER'." Rule="$(_MSKit_PkgRules)#copyright" /> - <_MSKit_PkgFinding Include="MSKIT_PKG019" Condition="'$(_MSKit_HasMermaid)'=='True'" + <_MSKit_PkgFinding Include="MSKITPKG019" Condition="'$(_MSKit_HasMermaid)'=='True'" Text="The package README of '$(PackageId)' contains a Mermaid diagram, which nuget.org shows as code. Link to the diagram on GitHub instead." Rule="$(_MSKit_PkgReadmeRules)#supported-markdown-features" /> @@ -114,11 +114,13 @@ diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.inspect.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.inspect.targets index bdb9dd4..061477d 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.inspect.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.inspect.targets @@ -1,6 +1,6 @@ - + The MSKITPKG checks then read the generated file. Full description: docs/package-readme.md. --> $(MSBuildThisFileDirectory)nuget.allowed-image-hosts.txt @@ -34,7 +34,7 @@ - @@ -117,25 +117,25 @@ - <_MSKit_ReadmeCode Include="MSKIT_PKG020;MSKIT_PKG021;MSKIT_PKG022" /> + <_MSKit_ReadmeCode Include="MSKITPKG020;MSKITPKG021;MSKITPKG022" /> <_MSKit_ReadmeSkip Include="$(MSKit_SkipPackageChecks);$(NoWarn)" /> <_MSKit_ReadmeCode Remove="@(_MSKit_ReadmeSkip)" /> <_MSKit_ReadmeCodes>;@(_MSKit_ReadmeCode); - + - + - + - - - + + + diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.targets index 9b2c60d..b299d47 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.targets @@ -51,9 +51,9 @@ + packed as icon. (icon.png, icon.jpg) unless the project sets PackageIcon. --> - icon.png + icon$([System.IO.Path]::GetExtension('$(PackageIconPath)').ToLowerInvariant()) <_MSKit_PacksIcon>True @@ -63,7 +63,7 @@ - + diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt index d0d5ddf..4d3b6d5 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Packaging/package.tasks.cs.txt @@ -31,7 +31,7 @@ public sealed class MSKit_PackageAssets : Task [Output] public string HtmlTags { get; set; } [Output] public string Alerts { get; set; } [Output] public bool HasMermaid { get; set; } - [Output] public bool IconIsPng { get; set; } + [Output] public string IconFormat { get; set; } [Output] public int IconWidth { get; set; } [Output] public int IconHeight { get; set; } @@ -96,16 +96,18 @@ public sealed class MSKit_PackageAssets : Task if (!string.IsNullOrEmpty(IconPath) && File.Exists(IconPath)) { - var header = new byte[24]; - using (var stream = File.OpenRead(IconPath)) + var icon = File.ReadAllBytes(IconPath); + IconFormat = "unknown"; + if (icon.Length >= 24 && icon[0] == 0x89 && icon[1] == 0x50 && icon[2] == 0x4E && icon[3] == 0x47) { - var read = stream.Read(header, 0, header.Length); - IconIsPng = read == 24 && header[0] == 0x89 && header[1] == 0x50 && header[2] == 0x4E && header[3] == 0x47; + IconFormat = "PNG"; + IconWidth = BigEndian(icon, 16, 4); + IconHeight = BigEndian(icon, 20, 4); } - if (IconIsPng) + else if (icon.Length >= 4 && icon[0] == 0xFF && icon[1] == 0xD8) { - IconWidth = (header[16] << 24) | (header[17] << 16) | (header[18] << 8) | header[19]; - IconHeight = (header[20] << 24) | (header[21] << 16) | (header[22] << 8) | header[23]; + IconFormat = "JPEG"; + ReadJpegSize(icon); } } @@ -116,6 +118,31 @@ public sealed class MSKit_PackageAssets : Task Alerts = string.Join(", ", alerts.Distinct()); } + private static int BigEndian(byte[] bytes, int offset, int count) + { + var value = 0; + for (var i = 0; i < count; i++) value = (value << 8) | bytes[offset + i]; + return value; + } + + // Walks the JPEG segments to the first start-of-frame marker (SOF0..SOF15 except DHT, JPG, DAC). + private void ReadJpegSize(byte[] jpeg) + { + var i = 2; + while (i + 8 < jpeg.Length && jpeg[i] == 0xFF) + { + var marker = jpeg[i + 1]; + if (marker == 0xFF) { i++; continue; } + if (marker >= 0xC0 && marker <= 0xCF && marker != 0xC4 && marker != 0xC8 && marker != 0xCC) + { + IconHeight = BigEndian(jpeg, i + 5, 2); + IconWidth = BigEndian(jpeg, i + 7, 2); + return; + } + i += 2 + BigEndian(jpeg, i + 2, 2); + } + } + public string OutputPath { get; set; } public string FindingsBase { get; set; } public string ReleasesUrlPath { get; set; } @@ -138,7 +165,7 @@ public sealed class MSKit_PackageAssets : Task private void GenerateReadme() { - var codes =new[] { "MSKIT_PKG020", "MSKIT_PKG021", "MSKIT_PKG022" }; + var codes =new[] { "MSKITPKG020", "MSKITPKG021", "MSKITPKG022" }; var findings = codes.ToDictionary(c => c, c => new List()); Action report = (code, text) => findings[code].Add(text.Replace("\r", " ").Replace("\n", " ")); @@ -211,7 +238,7 @@ public sealed class MSKit_PackageAssets : Task case "": break; default: - report("MSKIT_PKG020", display + ": MSKit_RepoProvider '" + provider + "' is not one of GitHub, GitLab, AzureDevOps, Bitbucket, Gitea; set MSKit_RepoBlobUrlTemplate and MSKit_RepoRawUrlTemplate instead."); + report("MSKITPKG020", display + ": MSKit_RepoProvider '" + provider + "' is not one of GitHub, GitLab, AzureDevOps, Bitbucket, Gitea; set MSKit_RepoBlobUrlTemplate and MSKit_RepoRawUrlTemplate instead."); break; } if (norm(BlobTemplate).Length > 0) { blob = norm(BlobTemplate); tree = blob.Contains("/blob/") ? blob.Replace("/blob/", "/tree/") : blob; } @@ -250,7 +277,7 @@ public sealed class MSKit_PackageAssets : Task if (!Uri.TryCreate(url.Trim('<', '>'), UriKind.Absolute, out u) || (u.Scheme != "https" && u.Scheme != "http")) return; var h = u.Host.ToLowerInvariant(); if (allowed.Contains(h) || (h == "github.com" && Regex.IsMatch(u.AbsolutePath, @"^/[^/]+/[^/]+/(actions/)?workflows/[^/]+/badge\.svg$", RegexOptions.IgnoreCase))) return; - report("MSKIT_PKG021", display + " line " + n + ": the image " + url + " comes from " + h + ", a host nuget.org does not show images from. Use an allowed host (nuget.allowed-image-hosts.txt in the kit) or point MSKit_RepoRawUrlTemplate at one."); + report("MSKITPKG021", display + " line " + n + ": the image " + url + " comes from " + h + ", a host nuget.org does not show images from. Use an allowed host (nuget.allowed-image-hosts.txt in the kit) or point MSKit_RepoRawUrlTemplate at one."); }; Func resolve = (target, isImage, n) => @@ -266,7 +293,7 @@ public sealed class MSKit_PackageAssets : Task var rp = combine(Uri.UnescapeDataString(p)); if (rp == null) { - report("MSKIT_PKG020", display + " line " + n + ": " + t + " points outside the repository and is left as it is."); + report("MSKITPKG020", display + " line " + n + ": " + t + " points outside the repository and is left as it is."); return target; } var isDir = Directory.Exists(Path.Combine(root, rp.Replace('/', Path.DirectorySeparatorChar))); @@ -334,25 +361,25 @@ public sealed class MSKit_PackageAssets : Task } if (skipOpen.IsMatch(line)) { - if (skipping) report("MSKIT_PKG020", display + " line " + n + ": nuget:skip opened again before line " + skipLine + "'s was closed."); + if (skipping) report("MSKITPKG020", display + " line " + n + ": nuget:skip opened again before line " + skipLine + "'s was closed."); skipping = true; skipLine = n; continue; } if (skipClose.IsMatch(line)) { - if (!skipping) report("MSKIT_PKG020", display + " line " + n + ": /nuget:skip has no matching nuget:skip."); + if (!skipping) report("MSKITPKG020", display + " line " + n + ": /nuget:skip has no matching nuget:skip."); skipping = false; continue; } var om = onlyOpen.Match(line); if (om.Success) { - if (inOnly) report("MSKIT_PKG020", display + " line " + n + ": nuget:only opened again before line " + onlyLine + "'s was closed."); + if (inOnly) report("MSKITPKG020", display + " line " + n + ": nuget:only opened again before line " + onlyLine + "'s was closed."); inOnly = true; onlyLine = n; keepOnly = Regex.Split(om.Groups[1].Value.Trim(), @"[\s,]+").Any(id => string.Equals(id, PackageId, StringComparison.OrdinalIgnoreCase)); continue; } if (onlyClose.IsMatch(line)) { - if (!inOnly) report("MSKIT_PKG020", display + " line " + n + ": /nuget:only has no matching nuget:only."); + if (!inOnly) report("MSKITPKG020", display + " line " + n + ": /nuget:only has no matching nuget:only."); inOnly = false; keepOnly = true; continue; } var fm = fenceRe.Match(line); @@ -366,10 +393,10 @@ public sealed class MSKit_PackageAssets : Task outLines.Add(rewriteLine(line, n)); outFence.Add(false); } - if (skipping) report("MSKIT_PKG020", display + " line " + skipLine + ": nuget:skip is never closed, so everything after it is left out."); - if (inOnly) report("MSKIT_PKG020", display + " line " + onlyLine + ": nuget:only is never closed."); + if (skipping) report("MSKITPKG020", display + " line " + skipLine + ": nuget:skip is never closed, so everything after it is left out."); + if (inOnly) report("MSKITPKG020", display + " line " + onlyLine + ": nuget:only is never closed."); if (!canRewrite && unresolved > 0) - report("MSKIT_PKG020", display + ": " + unresolved + " relative link(s) and image(s) stay relative because " + why + "."); + report("MSKITPKG020", display + ": " + unresolved + " relative link(s) and image(s) stay relative because " + why + "."); var title = norm(ReadmeTitle) == "auto" ? norm(PackageId) : norm(ReadmeTitle); if (title.Length > 0) @@ -422,7 +449,7 @@ public sealed class MSKit_PackageAssets : Task var visibility = norm(Visibility).ToLowerInvariant(); if (visibility == "private" || visibility == "internal") - report("MSKIT_PKG022", "The repository " + (repoUrl.Length > 0 ? repoUrl : "of " + PackageId) + " is " + visibility + ": the links in the package readme of " + PackageId + " will not open for people reading it on nuget.org. Publish from a public repository, or point MSKit_RepoBlobUrlTemplate and MSKit_RepoRawUrlTemplate at a public mirror."); + report("MSKITPKG022", "The repository " + (repoUrl.Length > 0 ? repoUrl : "of " + PackageId) + " is " + visibility + ": the links in the package readme of " + PackageId + " will not open for people reading it on nuget.org. Publish from a public repository, or point MSKit_RepoBlobUrlTemplate and MSKit_RepoRawUrlTemplate at a public mirror."); var result = new List(); var blank = true; diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing.XUnit.v3/audit/audit.tests.project.xunit.v3.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing.XUnit.v3/audit/audit.tests.project.xunit.v3.targets index febe8d5..adb4177 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing.XUnit.v3/audit/audit.tests.project.xunit.v3.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing.XUnit.v3/audit/audit.tests.project.xunit.v3.targets @@ -1,13 +1,13 @@ - + - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.internalsVisibleTo.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.internalsVisibleTo.targets index 8de8fe0..3164d5b 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.internalsVisibleTo.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.internalsVisibleTo.targets @@ -4,7 +4,7 @@ - @@ -12,7 +12,7 @@ - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.lib.project.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.lib.project.targets index 11cb07e..0d8e18e 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.lib.project.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.lib.project.targets @@ -1,35 +1,35 @@ - + - + - - + - - + - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.project.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.project.targets index 8075de2..5035f83 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.project.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/audit/audit.tests.project.targets @@ -1,13 +1,13 @@ - - @@ -17,7 +17,7 @@ Condition="'$(_MSKit_TestsProjectCommonPropsImported)'=='True' AND '$(_MSKit_TestingFrameworkAtCommonPropsImport)'!='' AND '$(_MSKit_TestingFrameworkAtCommonPropsImport)'!='$(MSKit_TestingFramework)'"> - @@ -27,12 +27,12 @@ Condition="'$(_MSKit_TestsProjectCommonPropsImported)'=='True' AND '$(MSKit_TestingFramework_CommonPropsPath)'=='' AND '$(MSKit_TestingFramework)'!=''"> - - $([System.Text.RegularExpressions.Regex]::Replace($(_MSKit_CsprojText013), '<!--[\s\S]*?-->', '')) <_MSKit_HasDirectIsTestsProject>$([System.Text.RegularExpressions.Regex]::IsMatch($(_MSKit_CsprojText013), '<IsTestsProject\s*>')) - @@ -55,7 +55,7 @@ Condition="'$(MSKit_IsTestsProjectAutoDetected)'=='True' AND ('$(IsTestsLibProject)'=='True' OR '$(_MSKit_TestsLibProjectCommonPropsImported)'=='True') AND '$(MSKit_IsTestsLibProjectAutoDetected)'!='True'"> - @@ -65,7 +65,7 @@ Condition="('$(IsTestsProject)'=='True' OR '$(IsTestsLibProject)'=='True') AND '$(MSKit_TestingFramework)'!='' AND '$(MSKit_TestingFrameworkAttached)'!='true'"> - @@ -74,7 +74,7 @@ BeforeTargets="CoreCompile;Build" Condition="('$(IsTestsProject)'=='True' OR '$(IsTestsLibProject)'=='True') AND '$(MSKit_TestingFramework)'==''"> - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.lib.project.common.props b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.lib.project.common.props index 9685d6b..e280c2f 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.lib.project.common.props +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.lib.project.common.props @@ -1,7 +1,7 @@ + (MSKITTEST020 checks it). --> <_MSKit_TestingFrameworkAtLibCommonPropsImport>$(MSKit_TestingFramework) <_MSKit_TestsLibProjectCommonPropsImported>True diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.project.common.props b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.project.common.props index 72b358c..bc9dfbb 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.project.common.props +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit.Testing/tests.project.common.props @@ -1,7 +1,7 @@ + match. Set MSKit_TestingFramework before the import (MSKITTEST010 checks it). --> <_MSKit_TestingFrameworkAtCommonPropsImport>$(MSKit_TestingFramework) <_MSKit_TestsProjectCommonPropsImported>True diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.implicit.packages.duplicates.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.implicit.packages.duplicates.targets index b03a750..225b9e6 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.implicit.packages.duplicates.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.implicit.packages.duplicates.targets @@ -1,6 +1,6 @@ - @@ -25,7 +25,7 @@ AND $(_MSKit_ConsumerIdsStr.Contains(';%(PackageVersion.Identity);'))" /> - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.prerelease.packages.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.prerelease.packages.targets index 534e94f..e84b7bf 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.prerelease.packages.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.prerelease.packages.targets @@ -1,6 +1,6 @@ - @@ -18,10 +18,10 @@ <_MSKit_PrereleaseText>Prerelease $(MSKit_PrereleasePackagePrefix)* packages referenced on stable branch '$(MSKit_Branch)':%0A@(_MSKit_PrereleaseReferences->' %(Identity) %(Version)', '%0A')%0AFix: replace them with stable versions in Directory.Packages.props or the csproj. - - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.packages.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.packages.targets index 4fba85c..f1ad97e 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.packages.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.packages.targets @@ -1,6 +1,6 @@ - @@ -13,17 +13,17 @@ SkipGlobalRestriction="True" /> - - - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.reference.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.reference.targets index 6e84fa3..462ab83 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.reference.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.reference.targets @@ -1,6 +1,6 @@ - @@ -15,7 +15,7 @@ - @@ -26,7 +26,7 @@ <_MSKit_PackageReferenceNotAllowListed Include="@(PackageReference)" Condition=" '%(PackageReference.Allowed)'!='True' AND '@(PackageReference)'!='' AND '%(Identity)'!=''" /> - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.shared.properties.targets b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.shared.properties.targets index eeda662..d86f043 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.shared.properties.targets +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.shared.properties.targets @@ -30,29 +30,29 @@ <_MSKit_TFs_ProjNodeCount>@(_MSKit_TFs_NodeCheckXmlResult->Count()) - - - - - - - - - - @@ -87,7 +87,7 @@ True - - + - + @@ -17,13 +17,13 @@ - - + @@ -56,35 +56,35 @@ Valid placeholders: <_MSKit_UnknownPlaceholder Include="@(_MSKit_TplNameItem)" Exclude="@(_MSKit_ValidPlaceholder)" /> - - + - - - <_MSKit_ReleaseTagCore>$([System.Text.RegularExpressions.Regex]::Match('$(MSKit_ReleaseTag)', '^\d+\.\d+\.\d+').Value) - diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/twae.shared.init.props b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/twae.shared.init.props index ffddb18..072f863 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/twae.shared.init.props +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/twae.shared.init.props @@ -1,6 +1,6 @@ - + $(TreatWarningsAsErrors) diff --git a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/version.props b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/version.props index 6e356cf..83c5779 100644 --- a/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/version.props +++ b/manager/.toolkit/msbuild/DragoAnt.MSBuildKit/version.props @@ -97,7 +97,7 @@ <_MSKit_Ph_versionTag>$(VersionTag) <_MSKit_Ph_releaseTag Condition="'$(MSKit_IsReleaseTagValid)'=='true'">$(MSKit_ReleaseTag) + error; ValidateReleaseTag then stops the build with MSKITVER006. --> <_MSKit_Ph_releaseTag Condition="'$(MSKit_IsReleaseTagValid)'!='true'">0.0.0-invalid-release-tag <_MSKit_Ph_prNumber>$(MSKit_PullRequestNumber) <_MSKit_Ph_buildNumber>$(MSKit_BuildNumber) diff --git a/tests/codes.sh b/tests/codes.sh new file mode 100644 index 0000000..3f6c937 --- /dev/null +++ b/tests/codes.sh @@ -0,0 +1,23 @@ +# Codes: every code is spelled MSKIT, and every diagnostic links to its section of +# docs/reference/codes.md through MSKit_CodesHelpBaseUrl. The terminal logger prints the HelpLink as +# an OSC 8 hyperlink on the code, which is how the link is read back here. +# Sourced by tests/run.sh: uses its pass, bad, $out, $here, $lib, $fixtures, $clean_env and $ci_env. + +if grep -rn 'MSKIT[_]' "$here/kit" > "$out/codes-old-spelling.log"; then + bad "codes: the kit spells a code with an underscore (see $out/codes-old-spelling.log)"; head -n 5 "$out/codes-old-spelling.log" +else + pass "codes: no code in the kit is spelled with an underscore" +fi + +codes_url="https://github.com/DragoAnt/MSBuildKit/blob/main/docs/reference/codes.md" +$clean_env $ci_env GITHUB_EVENT_NAME=release GITHUB_REF_TYPE=tag GITHUB_REF_NAME=release-x GITHUB_REF=refs/tags/release-x \ + dotnet restore "$lib" -nologo -tl:on > "$out/codes-helplink-ver006.log" 2>&1 || true +grep -qF "]8;;$codes_url#mskitver006" "$out/codes-helplink-ver006.log" \ + && pass "codes: MSKITVER006 links to $codes_url#mskitver006" || bad "codes: MSKITVER006 has no HelpLink to its section (see $out/codes-helplink-ver006.log)" + +$clean_env dotnet pack "$fixtures/BadPackage/BadPackage.csproj" -c Release -nologo -tl:on -o "$out/codes-helplink-pkg" \ + -p:MSKit_PackageChecksAsErrors=False -p:MSKit_CodesHelpBaseUrl=https://codes.example/kit.md > "$out/codes-helplink-pkg.log" 2>&1 || true +for code in mskitpkg001 mskitpkg010; do + grep -qF "]8;;https://codes.example/kit.md#$code" "$out/codes-helplink-pkg.log" \ + && pass "codes: MSKit_CodesHelpBaseUrl moves the $code link" || bad "codes: the $code link ignores MSKit_CodesHelpBaseUrl (see $out/codes-helplink-pkg.log)" +done diff --git a/tests/docs.sh b/tests/docs.sh index 50c82c0..2aad5d2 100644 --- a/tests/docs.sh +++ b/tests/docs.sh @@ -5,7 +5,8 @@ dc_log="$out/docs-check.log" if sh "$here/tools/docs-check.sh" > "$dc_log" 2>&1; then pass "docs: $(tail -n 1 "$dc_log" | sed 's/^docs-check: //')" else bad "docs: tools/docs-check.sh found problems (see $dc_log)"; cat "$dc_log"; fi -# A copy with one property row, one code section, one name, one link and one anchor broken must fail on each. +# A copy with one property row, one code section, one name, one link, one anchor, two HelpLinks and +# the old code spelling in four places broken must fail on each. dc_copy() { rm -rf "$1"; mkdir -p "$1/kit/.toolkit" "$1/samples/MinimalLibrary" cp -R "$here/kit/.toolkit/msbuild" "$1/kit/.toolkit/msbuild" @@ -13,22 +14,22 @@ dc_copy() { for f in README.md CONTRIBUTING.md SECURITY.md CHANGELOG.md LICENSE; do cp "$here/$f" "$1/$f"; done mkdir -p "$1/tools"; cp "$here/tools/docs-check.sh" "$1/tools/docs-check.sh" } +u=_ dc_bad="$out/docs-check-broken" dc_copy "$dc_bad" +dc_kit="$dc_bad/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit" grep -v '^| `MSKit_SemVerRegex` |' "$here/docs/reference/properties.md" > "$dc_bad/docs/reference/properties.md" -sed 's/^### MSKITVER004$/### Gone/; s/^### MSKITPAP002$/### MSKIT_PAP002/' "$here/docs/reference/codes.md" > "$dc_bad/docs/reference/codes.md" -printf '\nSee `MSKit_NoSuchProperty`, `MSKIT_VER099`, [gone](./no-such-page.md), [anchor](./build.md#no-such-heading) and [bare](build.md).\n' >> "$dc_bad/docs/troubleshooting.md" +sed "s/^### MSKITVER004\$/### Gone/; s/^### MSKITPAP002\$/### MSKIT${u}PAP002/" "$here/docs/reference/codes.md" > "$dc_bad/docs/reference/codes.md" +printf '\nSee `MSKit_NoSuchProperty`, `MSKITVER099`, formerly `MSKIT%sVER006`, [gone](./no-such-page.md), [anchor](./build.md#no-such-heading) and [bare](build.md).\n' "$u" >> "$dc_bad/docs/troubleshooting.md" +sed "s/^## \[Unreleased\]\$/&\n\n- The MSKIT${u}PKG checks./" "$here/CHANGELOG.md" > "$dc_bad/CHANGELOG.md" +sed 's/ HelpLink="$(MSKit_CodesHelpBaseUrl)#mskitver006"//; s/#mskitver007"/#mskitver001"/' "$here/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.version.targets" > "$dc_kit/audit.version.targets" +sed "s/Code=\"MSKITRES002\"/Code=\"MSKIT${u}RES002\"/" "$here/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.restrict.packages.targets" > "$dc_kit/audit.restrict.packages.targets" sh "$dc_bad/tools/docs-check.sh" > "$out/docs-check-broken.log" 2>&1 && bad "docs: the check passed a broken copy (see $out/docs-check-broken.log)" for needle in "property MSKit_SemVerRegex" "code MSKITVER004" "write the heading as MSKITPAP002" "mentions MSKit_NoSuchProperty" \ - "mentions MSKITVER099" "no-such-page.md points at a missing file" "no-such-heading names a heading" "build.md must start with ./"; do - grep -qF "$needle" "$out/docs-check-broken.log" && pass "docs: the check reports '$needle'" || bad "docs: the check missed '$needle' (see $out/docs-check-broken.log)" + "mentions MSKITVER099" "no-such-page.md points at a missing file" "no-such-heading names a heading" "build.md must start with ./" \ + "MSKITVER006 has no HelpLink" "MSKITVER007 has HelpLink=" "HelpLink anchor #mskitver004 has no heading" \ + "docs/troubleshooting.md:|old spelling of MSKITVER006" "CHANGELOG.md:|old spelling of MSKITPKG" \ + "audit.restrict.packages.targets:|old spelling of MSKITRES002" "docs/reference/codes.md:|old spelling of MSKITPAP002"; do + where=${needle%%|*}; what=${needle#*|} + grep -F "$where" "$out/docs-check-broken.log" | grep -qF "$what" && pass "docs: the check reports '$needle'" || bad "docs: the check missed '$needle' (see $out/docs-check-broken.log)" done - -# The planned code rename (MSKIT_VER006 -> MSKITVER006) must not break the check. -dc_renamed="$out/docs-check-renamed" -dc_copy "$dc_renamed" -sed 's/MSKIT_VER006/MSKITVER006/g' "$here/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.version.targets" \ - > "$dc_renamed/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.version.targets" -grep -q 'Code="MSKITVER006"' "$dc_renamed/kit/.toolkit/msbuild/DragoAnt.MSBuildKit/audit/audit.version.targets" || bad "docs: the rename fixture did not rename MSKIT_VER006" -sh "$dc_renamed/tools/docs-check.sh" > "$out/docs-check-renamed.log" 2>&1 \ - && pass "docs: a code spelled without the underscore still matches its section" || { bad "docs: the renamed code broke the check (see $out/docs-check-renamed.log)"; cat "$out/docs-check-renamed.log"; } diff --git a/tests/fixtures/PackageChecks/BadPackage/BadPackage.csproj b/tests/fixtures/PackageChecks/BadPackage/BadPackage.csproj index 1bac119..9c2b721 100644 --- a/tests/fixtures/PackageChecks/BadPackage/BadPackage.csproj +++ b/tests/fixtures/PackageChecks/BadPackage/BadPackage.csproj @@ -1,6 +1,6 @@ - + missing.png https://example.com/icon.png diff --git a/tests/package-icon.sh b/tests/package-icon.sh index 0a42146..6e18a21 100644 --- a/tests/package-icon.sh +++ b/tests/package-icon.sh @@ -30,7 +30,7 @@ ic_quiet() { grep -q "$2" "$out/icon-$1.log" && bad "icon $1 reports $2 (see $ou ic_pack default Icons ic_icon default icon.png ic_entry default icon.png -ic_quiet default MSKIT_PKG015 +ic_quiet default MSKITPKG015 # A JPEG PackageIconPath keeps its extension. ic_pack jpg Icons -p:FixtureIcon=icon.jpg @@ -38,12 +38,12 @@ ic_icon jpg icon.jpg ic_entry jpg icon.jpg ic_no_entry jpg icon.png ic_quiet jpg NU5046 -ic_quiet jpg MSKIT_PKG015 +ic_quiet jpg MSKITPKG015 # A JPEG of the wrong size is still reported. ic_pack jpg-small Icons -p:FixtureIcon=small.jpg ic_icon jpg-small icon.jpg -ic_warns jpg-small MSKIT_PKG015 +ic_warns jpg-small MSKITPKG015 # An upper-case extension is lowercased. ic_pack upper Icons -p:FixtureIcon=ICON.PNG @@ -57,4 +57,4 @@ ic_pack own Own ic_icon own logo.png ic_entry own logo.png ic_no_entry own icon.png -ic_quiet own MSKIT_PKG015 +ic_quiet own MSKITPKG015 diff --git a/tests/package-readme.sh b/tests/package-readme.sh index 866943c..99eb5f3 100644 --- a/tests/package-readme.sh +++ b/tests/package-readme.sh @@ -60,7 +60,7 @@ 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_PKG016 MSKIT_PKG017 MSKIT_PKG020 MSKIT_PKG021 MSKIT_PKG022; do rf_quiet github $code; done +for code in MSKITPKG009 MSKITPKG012 MSKITPKG016 MSKITPKG017 MSKITPKG020 MSKITPKG021 MSKITPKG022; 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. @@ -97,17 +97,17 @@ rf_has gitlab "[the docs folder](https://gitlab.com/dragoant/sub/fixture/-/tree/ rf_has gitlab "![diagram](https://gitlab.com/dragoant/sub/fixture/-/raw/$sha/$rel/docs/diagram.png)" rf_has gitlab "[Release notes](https://gitlab.com/dragoant/sub/fixture/-/releases)" 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_quiet gitlab MSKITPKG021 +rf_quiet gitlab MSKITPKG017 +rf_quiet gitlab MSKITPKG016 rf_notes gitlab "https://gitlab.com/dragoant/sub/fixture/-/releases" rf_pack gitlab-again Observer $gl -rf_quiet gitlab-again MSKIT_PKG016 +rf_quiet gitlab-again MSKITPKG016 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_warns gitlab-no-releases MSKITPKG016 rf_pack gitlab-no-default Observer $gl -p:MSKit_DefaultReleaseNotes=False -rf_warns gitlab-no-default MSKIT_PKG016 +rf_warns gitlab-no-default MSKITPKG016 rf_pack gitlab-notes Observer $gl "-p:PackageReleaseNotes=See the changelog." rf_notes gitlab-notes "See the changelog." @@ -116,29 +116,29 @@ rf_pack gitlab-self Observer -p:RepositoryUrl=https://git.example.org/team/fixtu 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_quiet gitlab-self MSKITPKG016 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" -grep "warning MSKIT_PKG021" "$out/readme-gitlab-self.log" | grep -q "img.shields.io" \ +rf_warns gitlab-self MSKITPKG021 +grep "warning MSKITPKG021" "$out/readme-gitlab-self.log" | grep -q "line 11" \ + && pass "readme gitlab-self: MSKITPKG021 names the README line" || bad "readme gitlab-self: MSKITPKG021 does not name line 11" +grep "warning MSKITPKG021" "$out/readme-gitlab-self.log" | grep -q "img.shields.io" \ && bad "readme gitlab-self: an allowed image host was warned" || pass "readme gitlab-self: allowed image hosts are not warned" # An unknown host: links stay relative, and the render checks on the generated file catch them. 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_warns unknown MSKITPKG020 +rf_warns unknown MSKITPKG017 +rf_warns unknown MSKITPKG016 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_quiet unknown-releases MSKITPKG016 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 rf_has provider "[the guide](https://code.example.net/team/fixture/-/blob/$sha/$rel/docs/guide.md)" -rf_quiet provider MSKIT_PKG020 +rf_quiet provider MSKITPKG020 rf_pack override Observer $gh \ "-p:MSKit_RepoBlobUrlTemplate=https://src.example.net/{repoPath}/view/{commit}/{path}" \ "-p:MSKit_RepoRawUrlTemplate=https://raw.githubusercontent.com/mirror/{repo}/{commit}/{path}" \ @@ -150,7 +150,7 @@ rf_has override "[Issues](https://tracker.example.net/fixture)" # A private repository: the links will not open for package readers. rf_pack private Observer $gh -p:MSKit_RepositoryVisibility=private -rf_warns private MSKIT_PKG022 +rf_warns private MSKITPKG022 # Title (MSKit_PackageReadmeTitle): the first level-1 heading becomes the package id, per package. rf_first() { diff --git a/tests/run.sh b/tests/run.sh index cf521c9..e57fac4 100644 --- a/tests/run.sh +++ b/tests/run.sh @@ -49,11 +49,11 @@ explicit=$($clean_env $ci_env GITHUB_EVENT_NAME=release GITHUB_REF_TYPE=tag GITH if $clean_env $ci_env GITHUB_EVENT_NAME=release GITHUB_REF_TYPE=tag GITHUB_REF_NAME=release-x GITHUB_REF=refs/tags/release-x \ dotnet restore "$lib" -nologo > "$out/invalid-tag.log" 2>&1; then - bad "tag release-x: restore succeeded, expected MSKIT_VER006" -elif grep -q "MSKIT_VER006" "$out/invalid-tag.log"; then - pass "tag release-x -> restore fails with MSKIT_VER006" + bad "tag release-x: restore succeeded, expected MSKITVER006" +elif grep -q "MSKITVER006" "$out/invalid-tag.log"; then + pass "tag release-x -> restore fails with MSKITVER006" else - bad "tag release-x: restore failed without MSKIT_VER006 (see $out/invalid-tag.log)" + bad "tag release-x: restore failed without MSKITVER006 (see $out/invalid-tag.log)" fi $clean_env dotnet build "$sample/MinimalLibrary.slnx" -c Release -nologo > "$out/build.log" 2>&1 && pass "sample builds" || { bad "sample build (see $out/build.log)"; tail -n 30 "$out/build.log"; } @@ -93,7 +93,7 @@ fi $clean_env dotnet pack "$fixtures/PackageChecks.slnx" -c Release -nologo -o "$out/fixtures" -p:MSKit_PackageChecksAsErrors=False > "$out/checks.log" 2>&1 || true for code in 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019; do - grep -q "warning MSKIT_PKG$code" "$out/checks.log" && pass "check MSKIT_PKG$code fires" || bad "check MSKIT_PKG$code did not fire (see $out/checks.log)" + grep -q "warning MSKITPKG$code" "$out/checks.log" && pass "check MSKITPKG$code fires" || bad "check MSKITPKG$code did not fire (see $out/checks.log)" done grep -q "
" "$out/checks.log" && bad "HTML inside a code fence was reported" || pass "HTML inside a code fence is ignored" @@ -101,16 +101,17 @@ if $clean_env $ci_env GITHUB_EVENT_NAME=push GITHUB_REF_TYPE=branch GITHUB_REF_N dotnet pack "$fixtures/BadPackage/BadPackage.csproj" -c Release -nologo -o "$out/fixtures-ci" > "$out/checks-ci.log" 2>&1; then bad "the checks did not fail the CI pack" else - grep -q "error MSKIT_PKG001" "$out/checks-ci.log" && pass "checks are errors on CI" || bad "CI pack failed without MSKIT_PKG errors (see $out/checks-ci.log)" + grep -q "error MSKITPKG001" "$out/checks-ci.log" && pass "checks are errors on CI" || bad "CI pack failed without MSKITPKG errors (see $out/checks-ci.log)" fi $clean_env dotnet pack "$fixtures/BadPackage/BadPackage.csproj" -c Release -nologo -o "$out/fixtures-skip" \ "-p:MSKit_SkipPackageChecks=All" > "$out/checks-skip.log" 2>&1 || true -grep -q "MSKIT_PKG" "$out/checks-skip.log" && bad "MSKit_SkipPackageChecks=All did not silence the checks" || pass "MSKit_SkipPackageChecks=All silences the checks" +grep -q "MSKITPKG" "$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" . "$here/tests/package-icon.sh" +. "$here/tests/codes.sh" . "$here/tests/docs.sh" echo diff --git a/tests/tfm-constants.sh b/tests/tfm-constants.sh index e65e60e..a35c671 100644 --- a/tests/tfm-constants.sh +++ b/tests/tfm-constants.sh @@ -11,11 +11,11 @@ tfm_expect() { 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)" + [ "$expect" = ok ] && pass "tfm $name passes MSKITTEST005" || bad "tfm $name: expected MSKITTEST005, the check passed" + elif grep -q "MSKITTEST005" "$out/tfm-$name.log"; then + [ "$expect" = fail ] && pass "tfm $name fails with MSKITTEST005" || bad "tfm $name: false MSKITTEST005 (see $out/tfm-$name.log)" else - bad "tfm $name: the check failed without MSKIT_TEST005 (see $out/tfm-$name.log)" + bad "tfm $name: the check failed without MSKITTEST005 (see $out/tfm-$name.log)" fi } diff --git a/tools/docs-check.sh b/tools/docs-check.sh index f7bd11b..77b584e 100644 --- a/tools/docs-check.sh +++ b/tools/docs-check.sh @@ -1,9 +1,9 @@ #!/bin/sh # Keeps the documentation honest against the kit: every property and item the kit defines has a row -# in docs/reference/properties.md, every code it reports a section headed by the code id without the -# underscore in docs/reference/codes.md, every MSKit_ name and MSKIT_ code the docs mention exists in -# the kit, and every relative link resolves (anchors included). -# Usage: sh tools/docs-check.sh [--root DIR] [--list properties|items|codes] +# in docs/reference/properties.md, every code it reports a section headed by the code id in +# docs/reference/codes.md, every / a HelpLink to that section, every MSKit_ name and +# code the docs mention exists in the kit, no file spells a code the old way, and every link resolves. +# Usage: sh tools/docs-check.sh [--root DIR] [--list properties|items|codes|diagnostics] set -eu root=$(cd "$(dirname "$0")/.." && pwd) @@ -16,7 +16,7 @@ while [ $# -gt 0 ]; do *) echo "docs-check: unknown argument '$1'" >&2; exit 2 ;; esac done -case "$list" in ""|properties|items|codes) ;; *) echo "docs-check: --list takes properties, items or codes" >&2; exit 2 ;; esac +case "$list" in ""|properties|items|codes|diagnostics) ;; *) echo "docs-check: --list takes properties, items, codes or diagnostics" >&2; exit 2 ;; esac [ -d "$root/kit/.toolkit/msbuild" ] || { echo "docs-check: no kit at $root/kit/.toolkit/msbuild" >&2; exit 2; } work=$(mktemp -d) @@ -24,14 +24,14 @@ trap 'rm -rf "$work"' EXIT INT TERM cd "$root" # Kit inventory with XML comments removed, one process for every file: -# "P " property set, "I" item, "R" property read, "C" diagnostic code. -# A code is keyed by its id without the underscore (MSKIT_VER006 and MSKITVER006 are one code). +# "P " property set, "I" item, "R" property read, "C" diagnostic code, +# "W " a or task ("-" for a missing attribute). find kit/.toolkit/msbuild -type f \( -name '*.props' -o -name '*.targets' -o -name '*.cs.txt' \) -exec awk ' - FNR == 1 { incomment = 0; pg = 0; ig = 0 } + FNR == 1 { incomment = 0; pg = 0; ig = 0; inel = 0 } { sub(/\r$/, "") } FILENAME ~ /\.cs\.txt$/ { rest = $0 - while (match(rest, /"MSKIT_?[A-Z]+[0-9][0-9][0-9]"/)) { print "C", id(substr(rest, RSTART + 1, RLENGTH - 2)), FILENAME ":" FNR; rest = substr(rest, RSTART + RLENGTH) } + while (match(rest, /"MSKIT[A-Z]+[0-9][0-9][0-9]"/)) { print "C", substr(rest, RSTART + 1, RLENGTH - 2), FILENAME ":" FNR; rest = substr(rest, RSTART + RLENGTH) } next } { @@ -53,9 +53,17 @@ find kit/.toolkit/msbuild -type f \( -name '*.props' -o -name '*.targets' -o -na rest = out while (match(rest, /\$\(MSKit_[A-Za-z0-9_]+/)) { print "R", substr(rest, RSTART + 2, RLENGTH - 2), FILENAME ":" FNR; rest = substr(rest, RSTART + RLENGTH) } rest = out - while (match(rest, /MSKIT_?[A-Z]+[0-9][0-9][0-9]/)) { print "C", id(substr(rest, RSTART, RLENGTH)), FILENAME ":" FNR; rest = substr(rest, RSTART + RLENGTH) } + while (match(rest, /MSKIT[A-Z]+[0-9][0-9][0-9]/)) { print "C", substr(rest, RSTART, RLENGTH), FILENAME ":" FNR; rest = substr(rest, RSTART + RLENGTH) } + if (!inel && (match(out, /<(Warning|Error)[[:space:]\/>]/) || match(out, /<(Warning|Error)$/))) { inel = 1; el = substr(out, RSTART); elat = FILENAME ":" FNR } + else if (inel) el = el " " out + if (inel && (e = closed(el))) { el = substr(el, 1, e); print "W", elat, attr(el, "Code"), attr(el, "HelpLink"); inel = 0 } } - function id(c) { sub(/_/, "", c); return c }' {} + > "$work/raw" + function closed(s, i, c, q) { for (i = 1; i <= length(s); i++) { c = substr(s, i, 1); if (c == "\"") q = !q; else if (c == ">" && !q) return i }; return 0 } + function attr(s, name, v) { + if (!match(s, "[[:space:]]" name "=\"[^\"]*\"")) return "-" + v = substr(s, RSTART, RLENGTH); sub(/^[[:space:]]*[A-Za-z]+="/, "", v); sub(/"$/, "", v) + return v == "" ? "-" : v + }' {} + > "$work/raw" # Public names: MSKit_* (set or read) and Is* (set); never the kit's own _-prefixed state. # Each is listed with the first place that sets it, else the first place that reads it. @@ -66,6 +74,7 @@ awk -v dir="$work" ' la = a; sub(/^.*:/, "", la); lb = b; sub(/^.*:/, "", lb) return fa < fb || (fa == fb && la + 0 < lb + 0) } + $1 == "W" { print $2 "\t" $3 "\t" $4 > (dir "/diagnostics"); next } $1 == "C" { if (better($3, c[$2])) c[$2] = $3; next } $1 == "I" { if (better($3, i[$2])) i[$2] = $3; next } $1 == "P" && ($2 ~ /^MSKit_/ || $2 ~ /^Is[A-Z]/) { if (better($3, set[$2])) set[$2] = $3; next } @@ -76,10 +85,23 @@ awk -v dir="$work" ' for (n in set) print n "\t" set[n] "\t" (n in read ? "set, read" : "set") > (dir "/properties") for (n in read) if (!(n in set)) print n "\t" read[n] "\tread" > (dir "/properties") }' "$work/raw" -for k in properties items codes; do touch "$work/$k"; sort -o "$work/$k" "$work/$k"; done +for k in properties items codes diagnostics; do touch "$work/$k"; sort -o "$work/$k" "$work/$k"; done if [ -n "$list" ]; then cat "$work/$list"; exit 0; fi +# Codes are spelled MSKIT. The old spelling, an underscore after the prefix (a code or a +# family), may appear only as "formerly `...`" in the code reference and in released changelog sections. +if [ -e .git ]; then git ls-files -co --exclude-standard +else find . \( -name .git -o -name bin -o -name obj -o -name dist -o -name .claude -o -name node_modules -o -name .toolkit \) -prune \ + -o -type f -print | sed 's|^\./||'; find kit/.toolkit -type f; fi > "$work/files" +released=$(grep -n '^## \[[0-9]' CHANGELOG.md 2>/dev/null | head -n 1 | cut -d: -f1) +tr '\n' '\0' < "$work/files" | xargs -0 grep -nI 'MSKIT[_]' /dev/null 2>/dev/null \ + | awk -v released="${released:-0}" ' + { sub(/\r$/, ""); p = index($0, ":"); f = substr($0, 1, p - 1); rest = substr($0, p + 1); p = index(rest, ":"); ln = substr(rest, 1, p - 1); text = substr(rest, p + 1) } + f == "CHANGELOG.md" && released > 0 && ln + 0 >= released { next } + f == "docs/reference/codes.md" { gsub(/formerly `MSKIT[_][A-Z]+[0-9][0-9][0-9]`/, "", text) } + { while (match(text, /MSKIT[_][A-Z]*[0-9]*/)) { print f ":" ln "\t" substr(text, RSTART, RLENGTH); text = substr(text, RSTART + RLENGTH) } }' > "$work/oldspelling" || true + # Every Markdown file a reader sees, and every path in the repository for the link check. { for f in README.md CONTRIBUTING.md SECURITY.md; do [ -f "$f" ] && echo "$f"; done [ -d docs ] && find docs -type f -name '*.md' | sort; } > "$work/docs.lst" @@ -98,9 +120,9 @@ awk -v dir="$work" ' split($0, cell, "|"); c = cell[2] while (match(c, /`[^`]+`/)) { print "D\t" f "\t" substr(c, RSTART + 1, RLENGTH - 2); c = substr(c, RSTART + RLENGTH) } } - f == "docs/reference/codes.md" && /^#+[[:space:]]+`?MSKIT_?[A-Z]+[0-9][0-9][0-9]/ { - match($0, /MSKIT_?[A-Z]+[0-9][0-9][0-9]/); c = substr($0, RSTART, RLENGTH) - print (c ~ /^MSKIT_/ ? "U\t" f ":" FNR "\t" c : "D\t" f "\t" c) + f == "docs/reference/codes.md" && /^#+[[:space:]]+`?MSKIT[_]?[A-Z]+[0-9][0-9][0-9]/ { + match($0, /MSKIT[_]?[A-Z]+[0-9][0-9][0-9]/); c = substr($0, RSTART, RLENGTH) + print (c ~ /^MSKIT[_]/ ? "U\t" f ":" FNR "\t" c : "D\t" f "\t" c) } { line = $0; gsub(/`[^`]*`/, "", line) while (match(line, /\]\([^) ]+\)/)) { print "L\t" f "\t" FNR "\t" d "\t" substr(line, RSTART + 2, RLENGTH - 3); line = substr(line, RSTART + RLENGTH) } } @@ -109,7 +131,7 @@ awk -v dir="$work" ' rest = $0 while (match(rest, /MSKit_[A-Za-z0-9_]+[*<]?/)) { t = substr(rest, RSTART, RLENGTH); rest = substr(rest, RSTART + RLENGTH); if (t !~ /[*<]$/) print "N\t" f ":" FNR "\t" t } rest = $0 - while (match(rest, /MSKIT_?[A-Z]+[0-9][0-9][0-9]/)) { t = substr(rest, RSTART, RLENGTH); rest = substr(rest, RSTART + RLENGTH); sub(/_/, "", t); print "M\t" f ":" FNR "\t" t } + while (match(rest, /MSKIT[A-Z]+[0-9][0-9][0-9]/)) { t = substr(rest, RSTART, RLENGTH); rest = substr(rest, RSTART + RLENGTH); print "M\t" f ":" FNR "\t" t } }' $(cat "$work/docs.lst") > "$work/docs.tsv" awk -v dir="$work" -F'\t' ' @@ -125,6 +147,8 @@ awk -v dir="$work" -F'\t' ' function problem(m) { print "docs-check: " m; problems++ } FILENAME == dir "/properties" || FILENAME == dir "/items" { known[$1] = $2; what[$1] = (FILENAME == dir "/items" ? "item" : "property"); order[++n] = $1; next } FILENAME == dir "/codes" { code[$1] = $2; corder[++nc] = $1; next } + FILENAME == dir "/diagnostics" { dwhere[++nd] = $1; dcode[nd] = $2; dlink[nd] = $3; next } + FILENAME == dir "/oldspelling" { o = $2; sub(/_/, "", o); problem($1 ": " $2 " is the old spelling of " o); next } FILENAME == dir "/paths" { exists[$0] = 1; next } $1 == "S" { slug[$2 "#" $3] = 1; next } $1 == "D" { if ($2 == "docs/reference/properties.md") documented[$3] = 1; else documentedCode[$3] = 1; next } @@ -136,6 +160,16 @@ awk -v dir="$work" -F'\t' ' END { for (i = 1; i <= n; i++) if (!(order[i] in documented)) problem(what[order[i]] " " order[i] " (" known[order[i]] ") has no row in docs/reference/properties.md") for (i = 1; i <= nc; i++) if (!(corder[i] in documentedCode)) problem("code " corder[i] " (" code[corder[i]] ") has no section in docs/reference/codes.md") + for (i = 1; i <= nd; i++) { + c = dcode[i]; h = dlink[i] + if (c == "-") { problem(dwhere[i] ": a / without a Code"); continue } + if (c ~ /^MSKIT[A-Z]+[0-9][0-9][0-9]$/) { want = "$(MSKit_CodesHelpBaseUrl)#" tolower(c); anchor = tolower(c) } + else if (c ~ /^%\([A-Za-z_][A-Za-z0-9_.]*\)$/) { want = "$(MSKit_CodesHelpBaseUrl)#$([System.String]::Copy(\047" c "\047).ToLowerInvariant())"; anchor = "" } + else continue + if (h == "-") problem(dwhere[i] ": " c " has no HelpLink; set HelpLink=\"" want "\"") + else if (h != want) problem(dwhere[i] ": " c " has HelpLink=\"" h "\"; expected \"" want "\"") + if (anchor != "" && !(("docs/reference/codes.md#" anchor) in slug)) problem(dwhere[i] ": HelpLink anchor #" anchor " has no heading in docs/reference/codes.md") + } relative = 0 for (i = 1; i <= nl; i++) { split(links[i], l, "\t"); src = l[2]; ln = l[3]; base = l[4]; target = l[5] @@ -152,5 +186,5 @@ awk -v dir="$work" -F'\t' ' if (anchor != "" && dest ~ /\.md$/ && !((dest "#" anchor) in slug)) problem(src ":" ln ": link " target " names a heading that does not exist") } if (problems) { print "docs-check: " problems " problem(s)"; exit 1 } - printf "docs-check: %d properties and items, %d codes documented; %d relative links resolve\n", n, nc, relative - }' "$work/properties" "$work/items" "$work/codes" "$work/paths" "$work/docs.tsv" + printf "docs-check: %d properties and items, %d codes documented, %d diagnostics with a HelpLink; %d relative links resolve\n", n, nc, nd, relative + }' "$work/properties" "$work/items" "$work/codes" "$work/diagnostics" "$work/oldspelling" "$work/paths" "$work/docs.tsv"