diff --git a/.agents/skills/sdk-configuration-reference/SKILL.md b/.agents/skills/sdk-configuration-reference/SKILL.md deleted file mode 100644 index 7e60ecbd..00000000 --- a/.agents/skills/sdk-configuration-reference/SKILL.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -name: sdk-configuration-reference -description: "Use when configuring Purview.DotNetProjectSdk through Directory.Build.props or a .csproj, especially for NamespacePrefix, version detection, testing framework selection, telemetry, repo bootstrapping, and embedded agent-skill settings." ---- - -# Purview.DotNetProjectSdk configuration reference - -Use this skill when a task asks what can be configured in `Purview.DotNetProjectSdk`, where a property must be set, or which defaults the SDK applies automatically. - -## First rule: know where a property must be set - -Set repo-wide bootstrap properties **before** importing the SDK in `Directory.Build.props` when the value must affect `Sdk.props` evaluation. - -Common pre-import properties: - -- `NamespacePrefix` -- `UsePackageJsonVersion` -- `RootPackageJson` -- Repo-wide testing framework selection properties when you want every project to inherit them - -If a property changes behavior in `Sdk.targets` instead, it can usually be set later (for example in a project file), but prefer repo-wide defaults in `Directory.Build.props` unless the scenario is intentionally project-specific. - -## Version detection settings - -These properties control package/app version resolution from `package.json`: - -- `UsePackageJsonVersion` — default `true`; supported values: `true`, `false`, `Strict` -- `RootPackageJson` — explicit path to the `package.json` to read -- `EnableVersionDetectionCache` — default `true`; enables local caching of resolved version data -- `VersionDetectionCacheFile` — optional explicit cache file path -- `VersionDetectionLogEnabled` — default `false`; set to `true` to log the detected package version - -Behavior rules: - -1. If `RootPackageJson` is set, the SDK uses that path. -2. Otherwise it tries to discover the repo root from CI variables, `.git`, or a nearby `package.json`. -3. When version detection succeeds, both `Version` and `PackageVersion` are set from the `version` field. -4. `UsePackageJsonVersion=Strict` should be treated as “fail if discovery/resolution cannot succeed”. - -## Core identity and build settings - -These are the most important configurable properties exposed by the SDK: - -- `NamespacePrefix` — required unless `DisableNamespacePrefixCheck=true` -- `DisableNamespacePrefixCheck` — default `false` -- `TargetFramework` — defaults to `net10.0` when neither `TargetFramework` nor `TargetFrameworks` is set; projects explicitly declaring `IsRoslynComponent=true` default to `netstandard2.0` -- `IsRoslynComponent` — when explicitly `true`, applies source-generator defaults: a single `netstandard2.0` target, `LangVersion=latest`, `Nullable=enable`, `TreatWarningsAsErrors=true`, extended analyzer rules, disabled SourceLink and untracked-source embedding, no dependency file, compiler-generated output under the framework-specific intermediate directory, telemetry exclusion, excluded normal build output, `IncludeSymbols=false` (no `.symbols.nupkg`/`.snupkg` by default — the PDB ships in `analyzers/dotnet/cs/`), and `PrivateAssets=all` applied to `Microsoft.CodeAnalysis.*` / `Microsoft.CodeAnalysis.Analyzers` references. Packable Roslyn components automatically pack the built analyzer assembly and PDB into `analyzers/dotnet/cs/` -- `PackProjectReferencedSourceGenerators` — default `true`; packable projects automatically include analyzer `ProjectReference` outputs and runtime dependencies under `analyzers/dotnet/cs/`. Set it to `false` globally or use `Pack="false"` on one analyzer reference to opt out. -- `EnableAssemblyNameGeneration` — default `true`; when `true`, `AssemblyName` and default `PackageId` follow the fully evaluated `RootNamespace`. Set `false` before the SDK import to use the standard project-name behaviour -- `DisableProjectFileNamingConventionCheck` — default `false`; disables the directory-name/file-name match validation -- `DisableGenerateAssemblyInfoClass` — default `false`; disables generated `AssemblyInfo` -- `DisableAutoInternalsVisibleTo` — default `false`; disables automatic friend assembly generation -- `AutoIncludeUsings` — default `true`; controls SDK-added global usings -- `SourceLinkPackageName` — default `Microsoft.SourceLink.GitHub` -- `DisableSourceLink` — default `false` - -## Telemetry and package-related settings - -- `ExcludePurviewTelemetry` — default `false`; removes `Purview.Telemetry.SourceGenerator` -- `ExcludeMSTelemetryExtension` — default `false`; removes `Microsoft.Extensions.Telemetry.Abstractions`, only relevant if `ExcludePurviewTelemetry` is also `true` -- `IsPackable` — defaults to `false` if not set elsewhere -- `PackageTags`, `IncludeSource`, `IncludeSymbols`, `PublishRepositoryUrl`, `SymbolPackageFormat` — standard pack-related settings the SDK participates in for packable projects -- Packable-project defaults (only applied when the consuming project has not supplied a value): `GenerateDocumentationFile=true`, `IncludeSymbols=true`, `SymbolPackageFormat=snupkg`, `PublishRepositoryUrl=true`, `EmbedUntrackedSources=true`, `DebugType=portable`. Portable PDBs are delivered through the `.snupkg`; the normal `.nupkg` does not receive PDB files unless the project opts in explicitly. Roslyn components default `IncludeSymbols=false` and ship their PDB inside `analyzers/dotnet/cs/` instead -- If the repo root is discoverable, the repository-root `README.md` is packed automatically (and registered via `PackageReadmeFile`) when the file exists and `PackageReadmeFile` was not configured explicitly - -## Test framework settings - -The SDK supports opinionated testing defaults and validation. - -Primary settings: - -- `TestingFramework` — default `TUnit`; supported values: `TUnit`, `Xunit`, `None` -- `SubstituteFramework` — default `TUnitMocks`; supported values: `TUnitMocks`, `NSubstitute`, `None` -- `TestDataFramework` — default `Bogus`; supported values: `Bogus`, `None` - -Related toggles and derived settings: - -- `CollectCoverage` — defaults to `true` for detected test projects -- `EnableStaticNativeInstrumentation` — defaults to `false` for test projects -- `EnableDynamicNativeInstrumentation` — defaults to `false` for test projects -- `TestingPlatformDotnetTestSupport`, `UseMicrosoftTestingPlatformRunner`, `EnableMicrosoftTestingPlatform` — enabled automatically for TUnit test projects - -## Repo bootstrap and developer-experience settings - -These settings control the SDK’s repo-level helper file bootstrapping: - -- `DisableAutoCopySdkFiles` — default `false`; master switch for SDK-managed repo file copying -- `BootstrapEditorConfigToRepoRoot` — default `true` -- `RepositoryEditorConfigFilePath` — optional override for the destination `.editorconfig` -- `BootstrapGlobalJsonToRepoRoot` — default `true` -- `RepositoryGlobalJsonFilePath` — optional override for the destination `global.json` -- `PurviewDotNetProjectSdkVersionForGlobalJson` — defaults to detected SDK package version, fallback `1.0.0` -- `PurviewAutoSdkPack` — default `true`; when `true`, automatically packs the `Sdk/` folder contents into the NuGet package with the correct root-level paths -- `EnableAgentFolderInPackage` — default `true`; copies the bundled `.agents/**` folder from the SDK NuGet package into the consuming repo’s `.agents/` -- `AgentPackDestinationFolder` — default `.agents`; repo-relative destination folder that receives copied agent content as `$(AgentPackDestinationFolder)/**` - -**Hard requirement:** This SDK must pack the contents of `Sdk/` into the NuGet package so that downstream consumers of `Purview.DotNetProjectSdk` receive the same `Sdk/**` files. The `PurviewAutoSdkPack` feature (default `true`) is the mechanism that delivers this for standard consuming projects. When a project is packable, the SDK automatically adds `Sdk/**/*` as package content with the correct root-level paths: - -- `Sdk/.agents/**` → `.agents/**` -- `Sdk/.github/**` → `.github/**` -- `Sdk/build/**` → `build/**` -- `Sdk/buildTransitive/**` → `buildTransitive/**` -- `Sdk/buildMultiTargeting/**` → `buildMultiTargeting/**` -- `Sdk/*.md`, `Sdk/*.png`, `Sdk/*.jpg`, etc. → package root -- everything else under `Sdk/` → `Sdk/` - -The SDK injects a `.gitignore` file into each second-level folder under `Sdk/.agents` during packaging with the following content: - -```text[.gitignore] -# Ignore all files -* - -# Don't ignore directories, so Git can traverse them -!*/ - -# Keep this file -!.gitignore -``` - -This lets consuming repos keep the agent folder structure discoverable while ignoring the copied content in Git. - -## Important derived properties you can inspect - -When explaining SDK behavior, prefer these derived values over guessing: - -- `PurviewLogicalProjectName` -- `PurviewNamespacePrefix` -- `PurviewProjectShortName` -- `PurviewTestType` -- `RootNamespace` -- `AssemblyName` -- `PackageVersion` -- `TestingType` -- `TargetProjectName` -- `RepoRoot` -- `RootPackageJson` - -## Compiler-visible properties - -The SDK exports many properties for analyzers and source generators through `build_property.`. When authoring analyzers or generators, prefer those exported properties instead of re-deriving SDK behavior manually. - -Especially relevant exported properties include: - -- `UsePackageJsonVersion`, `RootPackageJson`, `RepoRoot`, `Version`, `PackageVersion` -- `NamespacePrefix`, `DisableNamespacePrefixCheck` -- `TestingFramework`, `SubstituteFramework`, `TestDataFramework` -- `ExcludePurviewTelemetry`, `ExcludeMSTelemetryExtension` -- `EnableAssemblyNameGeneration`, `DisableAutoInternalsVisibleTo`, `DisableGenerateAssemblyInfoClass` -- `IsCSharpProject`, `IsTestProject`, `IsSharedTestingProject`, `IsSharedProject` -- `TestingType`, `TargetProjectName` -- `IsContainerProject`, `IsSdkProject`, `SdkProjectName`, `IsWebProject`, `IsWebSdkProject`, `IsWorkerSdkProject`, `IsAspireHostProject`, `IsCLIProject` -- `EditorConfigFilePath`, `RepositoryEditorConfigFilePath`, `BootstrapEditorConfigToRepoRoot` -- `RepositoryGlobalJsonFilePath`, `BootstrapGlobalJsonToRepoRoot`, `DisableAutoCopySdkFiles` -- `PurviewDotNetProjectSdkVersionForGlobalJson`, `CurrentYear`, `AutoGeneratedAssemblyInfoFile` - -## Guidance for edits - -When changing SDK configuration: - -1. Preserve existing defaults unless the task explicitly changes product behavior. -2. Keep README, SDK property declarations, validation, and any shipped skills aligned. -3. If you add a new user-facing property, update both the configuration docs and the bundled skills. -4. If the property affects import-time behavior, document that it must be set before the SDK import. diff --git a/.agents/skills/sdk-project-behavior-and-detection/SKILL.md b/.agents/skills/sdk-project-behavior-and-detection/SKILL.md deleted file mode 100644 index bb275831..00000000 --- a/.agents/skills/sdk-project-behavior-and-detection/SKILL.md +++ /dev/null @@ -1,199 +0,0 @@ ---- -name: sdk-project-behavior-and-detection -description: "Use when explaining why Purview.DotNetProjectSdk classified a project as test, shared, CLI, web, Aspire host, or container, or when reasoning about auto-added packages, project references, namespaces, and naming conventions." ---- - -# Purview.DotNetProjectSdk project behavior and detection - -Use this skill when a task asks **why** the SDK applied a behavior automatically, or when adding/moving projects in a repo that relies on Purview’s naming and project-type inference. - -## Project-type detection rules - -The SDK infers behavior from project names, project contents, and SDK declarations. - -### Test detection - -A project is treated as a test project when its name ends with `*Test` or `*Tests` and the suffix before `Test(s)` matches a supported testing type such as: - -- `Unit` -- `Integration` -- `E2E` -- `EndToEnd` -- `Acceptance` -- `Functional` -- `Performance` -- `Load` -- `Smoke` -- `Stress` -- `Regression` -- `Security` -- `Chaos` -- `Scenario` -- `System` -- `Threat` -- `BlackBox` -- `WhiteBox` -- `Accessibility` -- `Interactive` -- `Environment` -- `Architecture` -- `Contract` - -Derived properties: - -- `IsTestProject=true` -- `TestingType=` -- `PurviewTestType=Tests` -- `TargetProjectName=` - -### Shared project detection - -The SDK recognizes shared project names exactly. These are not generic substring matches. - -Shared project names: - -- `Shared` -- `SharedFramework` -- `SharedInfrastructure` -- `SharedInfra` -- `SharedUtilities` -- `SharedUtils` -- `SharedLibrary` -- `SharedLib` -- `SharedHelpers` - -Shared testing project names: - -- `SharedTestingFramework` -- `SharedTestingInfrastructure` -- `SharedTestingInfra` -- `SharedTestingUtilities` -- `SharedTestingUtils` -- `SharedTestingLibrary` -- `SharedTestingLib` -- `SharedTestingHelpers` - -Derived flags: - -- `IsSharedProject` -- `IsSharedTestingProject` - -### SDK/content-based detection - -- `IsSdkProject` / `SdkProjectName` come from parsing the project/import `Sdk="..."` declaration -- `IsWebSdkProject=true` for `Microsoft.NET.Sdk.Web` -- `IsWorkerSdkProject=true` for `Microsoft.NET.Sdk.Worker` -- `IsAspireHostProject=true` when the SDK starts with `Aspire.Sdk.Host` or `Aspire.AppHost.Sdk` -- `IsContainerProject=true` when `Dockerfile`, `dockerfile`, or `Dockerfile.dev` exists in the project directory -- `IsCLIProject=true` when the project name ends with `CLI`, `Console`, `CommandLine`, `QuickStart`, or `QuickStarts` - -## Namespace and identity behavior - -The SDK derives the project identity from `NamespacePrefix` and the project name. - -Key behavior: - -1. `PurviewLogicalProjectName` is built from `NamespacePrefix` plus the project name, with deduplication when the project name already starts with the namespace tail. -2. `RootNamespace` defaults to `PurviewLogicalProjectName`. -3. Known suffixes are stripped from `RootNamespace`, including shared/shared-testing names and common segments like `Core`, `EF`, `Shared`, `ClientShared`, and `ServiceDefaults`. -4. Test suffixes are removed from `RootNamespace`, so `Acme.Api.UnitTests` still maps back to `Acme.Api`. -5. `AssemblyName` and `PackageId` default to the fully evaluated `RootNamespace` (the canonical default public name). Test/shared-testing projects keep their detected suffix in `AssemblyName`/`PackageId` so test assemblies stay distinct. Explicit `AssemblyName`/`PackageId` values always win. -6. The naming defaults are applied during `Sdk.props` evaluation (before the Microsoft SDK computes `TargetName`), so the compiled output name always matches `AssemblyName`. - -Do not hand-author alternate namespace conventions unless the repository explicitly opts out of the SDK defaults. - -## Automatic project references - -The SDK adds project references based on layout conventions. - -### Non-test projects - -For ordinary non-test, non-shared projects, it automatically looks for sibling shared projects: - -- `../Shared*/Shared*.csproj` - -It also removes accidental self/shared-testing matches. - -### Test projects - -For detected test projects, it attempts these target-project paths in order when they exist: - -- `../$(TargetProjectName)/$(TargetProjectName).csproj` -- `../../$(TargetProjectName)/$(TargetProjectName).csproj` -- `../src/$(TargetProjectName)/$(TargetProjectName).csproj` -- `../../src/$(TargetProjectName)/$(TargetProjectName).csproj` - -It also adds sibling shared-testing project references via: - -- `../SharedTesting*/SharedTesting*.csproj` - -This is why consistent naming and placement matter so much in repos that use the SDK. - -## Automatic framework/package behavior - -### For non-test C# projects - -- Adds SourceLink unless `DisableSourceLink=true` -- Adds Purview telemetry packages unless `ExcludePurviewTelemetry=true` -- Generates documentation files (`GenerateDocumentationFile=true`) unless explicitly disabled -- Generates `InternalsVisibleTo` attributes unless `DisableAutoInternalsVisibleTo=true` - -### For packable projects - -- Defaults `GenerateDocumentationFile`, `IncludeSymbols`, `SymbolPackageFormat=snupkg`, `PublishRepositoryUrl`, `EmbedUntrackedSources`, `IncludeSource`, and `DebugType=portable` — only when the consuming project has not supplied a value -- Delivers portable PDBs via the `.snupkg`; the normal `.nupkg` does not receive PDBs unless the project opts in explicitly -- Packs the repository-root `README.md` (registered via `PackageReadmeFile`) when the file exists and `PackageReadmeFile` is unset; skips when a README is already being packed -- Non-packable projects (including web apps) default `WarnOnPackingNonPackableProject=false` so solution-wide pack operations skip them silently - -### For Roslyn component (analyzer/source-generator) projects - -- Defaults a single `netstandard2.0` target, `LangVersion=latest`, `Nullable=enable`, `TreatWarningsAsErrors=true`, extended analyzer rules, disabled SourceLink, and excluded normal build output (`IncludeBuildOutput=false`) -- Defaults `IncludeSymbols=false` — no `.symbols.nupkg` or `.snupkg` is produced by default; the analyzer PDB ships inside the main `.nupkg` under `analyzers/dotnet/cs/` beside the analyzer assembly -- Packable Roslyn components automatically pack the built analyzer assembly (and PDB) into `analyzers/dotnet/cs/`; `SymbolPackageFormat` defaults to the modern `snupkg` if symbols are explicitly opted into -- `Microsoft.CodeAnalysis.*` and `Microsoft.CodeAnalysis.Analyzers` references are defaulted to `PrivateAssets=all` (development-only dependencies) so they never leak into the packed nuspec - -### For test and shared-testing projects - -- Applies test-friendly `NoWarn` defaults -- Marks projects as not packable/publishable -- Adds substitute/test-data/testing packages based on `SubstituteFramework`, `TestDataFramework`, and `TestingFramework` -- For TUnit test projects, enables Microsoft.Testing.Platform integration properties automatically -- For shared-testing projects, skips the runnable test package and marks them with a skip/category pattern appropriate to the selected test framework - -### For special project types - -- CLI projects default to `OutputType=Exe` and include `appsettings*.json` as content -- Container projects enable `InvariantGlobalization`, `PublishAot`, Linux Docker defaults, and container tooling package references -- Web SDK projects get `Microsoft.AspNetCore.OpenApi.Generated` added to `InterceptorsNamespaces` unless marked as a separate web-project mode -- Aspire host projects default to `OutputType=Exe` - -## How to reason about surprising behavior - -If the SDK “did something unexpected”, inspect these values first: - -- `MSBuildProjectName` -- `NamespacePrefix` -- `PurviewLogicalProjectName` -- `RootNamespace` -- `TestingType` -- `TargetProjectName` -- `SdkProjectName` -- `IsTestProject` -- `IsSharedProject` -- `IsSharedTestingProject` -- `IsContainerProject` -- `IsCLIProject` -- `IsWebSdkProject` -- `IsAspireHostProject` - -Prefer explaining behavior from these computed properties rather than from assumptions about folder names alone. - -## Guidance for structural changes - -When adding or moving projects in a repo using this SDK: - -1. Keep the `.csproj` filename equal to its containing directory name unless the repo explicitly disables that validation. -2. Preserve established `src/` and `tests/`-style layouts whenever possible. -3. Use test project suffixes intentionally so auto-detection and auto-references work. -4. Keep shared helpers in exact shared/shared-testing names if you want the corresponding SDK behavior. -5. If you change a naming rule in the SDK, update the README and the shipped skills together. diff --git a/Directory.Packages.props b/Directory.Packages.props index fb543837..ece5b75c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,7 +10,7 @@ Consumers on net48 or net8+ built with VS 2022 17.14+ or .NET 10+ SDK are fully supported. --> 4.14.0 1.65.51 - 1.0.0-prerelease.29 + 1.0.0-prerelease.30 3.2.8 diff --git a/global.json b/global.json index 99327e7c..b38e7fec 100644 --- a/global.json +++ b/global.json @@ -5,8 +5,7 @@ "allowPrerelease": false }, "msbuild-sdks": { - "Purview.DotNetProjectSdk": "1.0.0-prerelease.45", - "Aspire.AppHost.Sdk": "13.2.0" + "Purview.DotNetProjectSdk": "1.0.0-prerelease.46" }, "test": { "runner": "Microsoft.Testing.Platform" diff --git a/package.json b/package.json index dad549c2..8116fefc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "purview-telemetry-sourcegenerator", - "version": "5.0.0-prerelease.2", + "version": "5.0.0-prerelease.3", "description": "Generates [`ActivitySource`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.activitysource), [`ILogger`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger), and [`Metrics`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.metrics) based on interface methods.", "readme": "README.md", "repository": { diff --git a/samples/SampleApp.Net48/Directory.Build.props b/samples/SampleApp.Net48/Directory.Build.props index abbf5ef2..49f0130f 100644 --- a/samples/SampleApp.Net48/Directory.Build.props +++ b/samples/SampleApp.Net48/Directory.Build.props @@ -18,11 +18,11 @@ CA1812: WeatherService is instantiated via DI, not directly. CA5394: Random is fine for simulation / demo purposes. CS1574: cref resolution differences in net48 XML doc comments (in generated code). - CS8618/CS8625: the generator's injected attribute templates initialize non-nullable - members with null when compiled under net8+/net10-style nullable settings. + CS8618: the sample's WeatherForecast DTO declares a non-nullable Summary that is + populated before use (sample-code relaxation; not from generated code). TSG3022: Activity? vs Activity — net48 disables nullable, so Activity is used here. --> - $(NoWarn);CA1031;CA1303;CA1515;CA1812;CA2007;CA2201;CA5394;CS1574;CS8618;CS8625;TSG3022; + $(NoWarn);CA1031;CA1303;CA1515;CA1812;CA2007;CA2201;CA5394;CS1574;CS8618;TSG3022; diff --git a/samples/SampleApp/Directory.Build.props b/samples/SampleApp/Directory.Build.props index 9b7237b2..4bd2c4a8 100644 --- a/samples/SampleApp/Directory.Build.props +++ b/samples/SampleApp/Directory.Build.props @@ -13,11 +13,9 @@ CA1724: sample type names intentionally shadow well-known namespaces. CA2007: fire-and-forget async calls are fine for the sample workflow. CA2201: simulated failures raise generic exception types. - CS8618/CS8625: the generator's injected attribute templates (with #nullable enable) - initialize non-nullable members with null under net8+/net10. TSG2008: the sample intentionally demonstrates a large ExpandEnumerable limit; source-generator diagnostics are not suppressible with #pragma, so it's NoWarn'd. --> - $(NoWarn);CA1031;CA1515;CA1724;CA2007;CA2201;CS8618;CS8625;TSG2008; + $(NoWarn);CA1031;CA1515;CA1724;CA2007;CA2201;TSG2008; diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 597b5004..a3bbd31a 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,17 +1,3 @@ - - - - - <_ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))" /> - - - - - - diff --git a/src/src/SourceGenerator.Refactorings/SourceGenerator.Refactorings.csproj b/src/src/SourceGenerator.Refactorings/SourceGenerator.Refactorings.csproj index 51f68849..fb9caf5d 100644 --- a/src/src/SourceGenerator.Refactorings/SourceGenerator.Refactorings.csproj +++ b/src/src/SourceGenerator.Refactorings/SourceGenerator.Refactorings.csproj @@ -1,6 +1,5 @@ - netstandard2.0 true false true @@ -8,8 +7,8 @@ Visual Studio code refactorings for the Purview Telemetry source generator. - - + + diff --git a/src/src/SourceGenerator/Emitters/GeneratedTypesEmitter.cs b/src/src/SourceGenerator/Emitters/GeneratedTypesEmitter.cs index f21a1308..3469e521 100644 --- a/src/src/SourceGenerator/Emitters/GeneratedTypesEmitter.cs +++ b/src/src/SourceGenerator/Emitters/GeneratedTypesEmitter.cs @@ -18,8 +18,8 @@ static class GeneratedTypesEmitter [TypeLibrary.TelemetryShared.ExcludeAttribute] = (writer, type) => WriteSimpleAttribute(writer, type, AttributeTargets.Method, includeSuppressMessage: false), [TypeLibrary.TelemetryShared.TelemetryGenerationAttribute] = WriteTelemetryGenerationAttribute, - [TypeLibrary.TelemetryShared.TargetsEnum] = WriteTargetsEnum, - [TypeLibrary.TelemetryShared.NamingConventionEnum] = WriteNamingConventionEnum, + [TypeLibrary.TelemetryShared.Targets] = WriteTargetsEnum, + [TypeLibrary.TelemetryShared.NamingConvention] = WriteNamingConventionEnum, [TypeLibrary.TelemetryShared.ExcludeTargetsAttribute] = WriteExcludeTargetsAttribute, // Activities [TypeLibrary.Activities.BaggageAttribute] = WriteTagLikeAttribute, @@ -72,7 +72,7 @@ public static void EmitAll(IncrementalGeneratorPostInitializationContext context foreach (var type in TypeLibrary.GetAllGeneratedTypes()) { CodeWriter writer = new(settings); - writer.WriteAutoGeneratedHeader(); + WriteMarkerFileHeader(writer); Emit(writer, type); @@ -80,6 +80,24 @@ public static void EmitAll(IncrementalGeneratorPostInitializationContext context } } + /// + /// Writes the header for marker-attribute files. Nullable annotations are only enabled on modern + /// targets — the injected templates declare plain string members for + /// NET48_OR_GREATER/PURVIEW_TELEMETRY_NON_NULLABLE consumers — and CS8625 is + /// suppressed because optional string parameters intentionally default to . + /// + static void WriteMarkerFileHeader(CodeWriter writer) + { + writer.WriteAutoGeneratedHeader(nullableDirective: NullableDirectiveMode.Disable); + writer + .WriteLine("#if !NET48_OR_GREATER && !PURVIEW_TELEMETRY_NON_NULLABLE") + .WriteLine("#nullable enable") + .WriteLine("#endif") + .NewLine() + .WriteLine("#pragma warning disable CS8625") + .NewLine(); + } + static void Emit(CodeWriter writer, TypeIdentity type) { if (!Emitters.TryGetValue(type, out var emit)) @@ -304,7 +322,7 @@ static void WriteTagLikeAttribute(CodeWriter writer, TypeIdentity type) static void WriteTelemetryGenerationAttribute(CodeWriter writer, TypeIdentity type) { - var namingConvention = TypeLibrary.TelemetryShared.NamingConventionEnum; + var namingConvention = TypeLibrary.TelemetryShared.NamingConvention; EmitAttribute( writer, @@ -403,7 +421,7 @@ static void WriteTelemetryGenerationAttribute(CodeWriter writer, TypeIdentity ty static void WriteExcludeTargetsAttribute(CodeWriter writer, TypeIdentity type) { - var targets = TypeLibrary.TelemetryShared.TargetsEnum; + var targets = TypeLibrary.TelemetryShared.Targets; EmitAttribute( writer, @@ -828,7 +846,7 @@ static void WriteLogAttribute(CodeWriter writer, TypeIdentity type) ); WriteNullableStringProperty(body, "MessageTemplate"); WritePublicProperty(body, "EventId", PurviewTypeLibrary.System.Int32.MakeNullable(writer)); - WritePublicProperty(body, "Name", PurviewTypeLibrary.System.String.MakeNullable(writer)); + WriteNullableStringProperty(body, "Name"); WritePublicProperty(body, "GenerationMode", TypeLibrary.Logging.LoggerGenerationMode.AsTypeReference()); }, wrapInExcludeLoggingGuard: true @@ -1218,12 +1236,12 @@ static void WriteTargetsEnum(CodeWriter writer, TypeIdentity type) .WriteEnum( new(type.Name, TypeDeclarationAccessibility.Public) { - Attributes = [new AttributeDeclarationOptions(new TypeIdentity("FlagsAttribute", "System"))], + Attributes = [new(new TypeIdentity("FlagsAttribute", "System"))], }, - new("None", 0), - new("Activities", 1), - new("Logging", 2), - new("Metrics", 4), + new("None", 0, "No telemetry targets are excluded."), + new("Activities", 1, "Excludes activity (tracing) targets."), + new("Logging", 2, "Excludes logging targets."), + new("Metrics", 4, "Excludes metrics targets."), new("All", "Activities | Logging | Metrics") ); } @@ -1233,7 +1251,11 @@ static void WriteNamingConventionEnum(CodeWriter writer, TypeIdentity type) writer .WriteFileScopedNamespace(TypeLibrary.PurviewTelemetryNamespace) .XmlSummary("Determines the naming convention used for generated telemetry names.") - .WriteEnum(new(type.Name, TypeDeclarationAccessibility.Public), new("Legacy", 0), new("OpenTelemetry", 1)); + .WriteEnum( + new(type.Name, TypeDeclarationAccessibility.Public), + new("Legacy", 0, "Uses the legacy naming convention for generated telemetry names."), + new("OpenTelemetry", 1, "Uses the OpenTelemetry naming convention for generated telemetry names.") + ); } static void WriteLogPrefixTypeEnum(CodeWriter writer, TypeIdentity type) @@ -1244,11 +1266,11 @@ static void WriteLogPrefixTypeEnum(CodeWriter writer, TypeIdentity type) .XmlSummary("Determines the mode used to generate or override the prefix for the log entry.") .WriteEnum( new(type.Name, TypeDeclarationAccessibility.Public), - new("Default", 0), - new("Interface", 1), - new("Class", 2), - new("Custom", 3), - new("TrimmedClassName", 4) + new("Default", 0, "Uses the default log prefix."), + new("Interface", 1, "Uses the interface name as the log prefix."), + new("Class", 2, "Uses the class name as the log prefix."), + new("Custom", 3, "Uses a custom log prefix."), + new("TrimmedClassName", 4, "Uses the trimmed class name as the log prefix.") ); writer.WriteLine("#endif"); @@ -1261,7 +1283,12 @@ static void WriteLoggerGenerationModeEnum(CodeWriter writer, TypeIdentity type) writer .WriteFileScopedNamespace(TypeLibrary.PurviewTelemetryNamespace) .XmlSummary("Controls the generation mode used for log methods.") - .WriteEnum(new(type.Name, TypeDeclarationAccessibility.Public), new("Auto", 0), new("V1", 1), new("V2", 2)); + .WriteEnum( + new(type.Name, TypeDeclarationAccessibility.Public), + new("Auto", 0, "Automatically selects the log generation mode."), + new("V1", 1, "Uses the first-generation log implementation."), + new("V2", 2, "Uses the second-generation log implementation.") + ); writer.WriteLine("#endif"); } @@ -1271,6 +1298,10 @@ static void WriteMeterNameGenerationTypeEnum(CodeWriter writer, TypeIdentity typ writer .WriteFileScopedNamespace(TypeLibrary.PurviewTelemetryNamespace) .XmlSummary("Determines how meter names are generated when not explicitly specified.") - .WriteEnum(new(type.Name, TypeDeclarationAccessibility.Public), new("OpenTelemetry", 0), new("DotNet", 1)); + .WriteEnum( + new(type.Name, TypeDeclarationAccessibility.Public), + new("OpenTelemetry", 0, "Generates meter names using the OpenTelemetry convention."), + new("DotNet", 1, "Generates meter names using the .NET convention.") + ); } } diff --git a/src/src/SourceGenerator/Helpers/TypeLibrary.cs b/src/src/SourceGenerator/Helpers/TypeLibrary.cs index 29e33175..233be40b 100644 --- a/src/src/SourceGenerator/Helpers/TypeLibrary.cs +++ b/src/src/SourceGenerator/Helpers/TypeLibrary.cs @@ -321,11 +321,8 @@ public static class TelemetryShared nameof(TelemetryGenerationAttribute), PurviewTelemetryNamespace ); - public static readonly TypeIdentity TargetsEnum = new(nameof(TargetsEnum), PurviewTelemetryNamespace); - public static readonly TypeIdentity NamingConventionEnum = new( - nameof(NamingConventionEnum), - PurviewTelemetryNamespace - ); + public static readonly TypeIdentity Targets = new(nameof(Targets), PurviewTelemetryNamespace); + public static readonly TypeIdentity NamingConvention = new(nameof(NamingConvention), PurviewTelemetryNamespace); public static readonly TypeIdentity ExcludeTargetsAttribute = new( nameof(ExcludeTargetsAttribute), PurviewTelemetryNamespace @@ -336,8 +333,8 @@ public static ImmutableArray GetGeneratedTypes() => TagAttribute, ExcludeAttribute, TelemetryGenerationAttribute, - TargetsEnum, - NamingConventionEnum, + Targets, + NamingConvention, ExcludeTargetsAttribute, ]; } diff --git a/src/src/SourceGenerator/Sdk/assets/images/purview-logo.jpg b/src/src/SourceGenerator/Sdk/assets/images/purview-logo.jpg deleted file mode 120000 index 452118b3..00000000 --- a/src/src/SourceGenerator/Sdk/assets/images/purview-logo.jpg +++ /dev/null @@ -1 +0,0 @@ -../../../../../../assets/images/purview-logo.jpg \ No newline at end of file diff --git a/src/src/SourceGenerator/SourceGenerator.csproj b/src/src/SourceGenerator/SourceGenerator.csproj index 1a622775..5578ba7d 100644 --- a/src/src/SourceGenerator/SourceGenerator.csproj +++ b/src/src/SourceGenerator/SourceGenerator.csproj @@ -1,12 +1,19 @@  - netstandard2.0 true true - - + + true + false + true + snupkg + + false + $(NoWarn);IDE0005;EnableGenerateDocumentationFile; Purview Telemetry Source Generator .NET Source Generator for interface-based telemetry generating tracing, logs, and metrics. @@ -21,8 +28,8 @@ logs;log;logger;logging;source-generator;high-performance-logging;otel;open-telemetry;telemetry;traces;tracing;metric;metrics;meter;meters;instrumentation;instruments;events;distributed-traces;distributed-tracing;melt;dotnet;aspnet; - - + + @@ -40,8 +47,8 @@ into analyzers/dotnet/cs; only the refactorings assembly is added here. --> - - + Excludes logging targets.") + .Because("the public enum members must carry XML summaries so CS1591 is not raised"); + } + public static IEnumerable BasicGenericParameters { get