Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions .agents/prompts/sdk-diagnose-agent-folder-copy.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,27 @@ destination in a consuming repository.
3. Check `EnableAgentFolderInPackage` is not set to `false` anywhere in the build (project file,
`Directory.Build.props`, or command-line `-p:` overrides).
4. Confirm the destination folder: default is `.agents` at the repo root, overridable per-build with
`-p:AgentPackDestinationFolder=<folder>`.
`-p:AgentPackDestinationFolder=<folder>`, and the source defaults to the package-level `.agents`
folder (override with `PurviewAgentFolderSourcePath`).
5. Verify repo-root discovery succeeded: explicit `RepoRoot`, then a nearby `AGENTS.md`, then source-control
root metadata.
6. Re-run the build and confirm the destination folder now contains the copied files (including the
6. If the destination looks stale or incomplete, inspect the change-detection manifest
(`<repo root>/.purview/agent-sync.cache`). It lists the files the SDK believes it already mirrored; a
matching entry with a present destination file means the sync was skipped as up to date. Delete the
manifest (or the affected destination file) to force a fresh copy.
7. Retry notices are demoted to low-importance messages, so a healthy build shows no `MSB3026` warnings.
A copy that still fails after every retry is reported as an error naming the source, destination and
OS error - search the build log for `The Purview SDK could not copy`. Temporarily set
`PurviewAgentFolderCopyRetries` / `PurviewAgentFolderCopyRetryDelayMilliseconds` to retry longer, and
`PurviewSuppressCopyRetryWarnings=false` to see every retry attempt.
8. Re-run the build and confirm the destination folder now contains the copied files (including the
generated `.gitignore` for skill/prompt/agent subfolders).

## Suggested output

- A short root-cause explanation (missing import, disabled flag, wrong destination override, or repo-root
discovery miss).
- A short root-cause explanation (missing import, disabled flag, wrong destination override, repo-root
discovery miss, or a destination held open by another process).
- The exact command used to reproduce/verify the fix (for example
`dotnet build <project> -p:AgentPackDestinationFolder=<folder>`).
- Confirmation that the expected files exist at the resolved destination path.
- Confirmation that the expected files exist at the resolved destination path, plus whether the
manifest skipped the sync (in which case the content was already up to date).
30 changes: 30 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Configuration for GitHub's automatically generated release notes.
# The shared Purview release pipeline creates the GitHub release and uses these
# categories to group merged pull requests.
changelog:
exclude:
labels:
- ignore-for-release
- skip-changelog
categories:
- title: Features
labels:
- feature
- enhancement
- title: Fixes
labels:
- bug
- fix
- title: Documentation
labels:
- docs
- documentation
- title: Build and tooling
labels:
- build
- ci
- dependencies
- chore
- title: Other Changes
labels:
- "*"
72 changes: 72 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Changelog

All notable changes to `Purview.Aspire.ResourceKit` are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0] - 2026-09-29

The first stable release of `Purview.Aspire.ResourceKit`.

### Added

- **Host kits** — `[HostKit]` marks the single host kit per compilation and generates the host base
class, per-resource properties, typed host and resource options, and an AppHost extension method
(`Add<HostKit>()`, for example `AddAspireResourceKit()`).
- **Resource kits** — `[ResourceDefinition]` and `[ResourceDefinition<TResource>]` mark resource kit
classes; the generator emits the `sealed partial` skeleton, the `ResourceKitBase<TResource>` base,
and the constructor/options wiring.
- **Predictable lifecycle** — `Build`/`BuildResource(...)` constructs each resource and
`Configure`/`ConfigureResource()` wires resources together afterwards.
- **Enablement** — `IsEnabled` (persisted toggle, usually from generated options) and
`IsResourceEnabled(builder)` (runtime hook) decide participation before resource construction.
- **Typed options** — generated `sealed partial` host and resource option types that bind from
configuration, can be extended with partial classes, and are registered with `ValidateOnStart()`.
- **`OptionsHelper`** — strongly typed assignment expressions plus binder-style flattening
(`Assign`, `AsEnvironmentVariables`, `Environment`, `Override`, `Ignore`, `PathFor`,
`SectionNameFor`) for tests and scenario toggles.
- **Project resources** — first-class support for `AddProject<T>()`, including Aspire-generated
`Projects.*` metadata types, with dedicated generator and analyzer validation.
- **Diagnostics SG0001–SG0020** — model validation reported by the bundled analyzer, an IDE code fix
("Split into separate assignments") for SG0020, and automatic `CS8618` suppression for
non-nullable `IResourceBuilder<T>` properties.
- **Bundled agent skill** — `aspire-apphost-to-resourcekit`, auto-installed into consuming
repositories under `.agents/skills/**` on build (opt out with
`<EnableAgentFolderInPackage>false</EnableAgentFolderInPackage>`).

### Changed

- Host wiring is generated from attributes by default; the manual `HostKitBase<THostKit>` /
`ResourceKitBase<THostKit, TResource>` composition pattern remains fully supported for teams that
want explicit control.

### Diagnostics

| ID | Severity | Description |
| --- | --- | --- |
| SG0001 | Error | Class must be `partial` |
| SG0002 | Info | No resources defined for the host kit |
| SG0003 | Warning | No host kit defined (but resources exist) |
| SG0004 | Error | Multiple `[HostKit]` classes defined |
| SG0005 | Error | Duplicate resource property name |
| SG0006 | Error | Resource must derive from the expected generated base |
| SG0007 | Error | Resource name could not be derived and no `Name` was specified |
| SG0008 | Error | Explicit `PropertyName` is not a valid C# identifier |
| SG0009 | Error | Missing `IServiceCollection` type dependency |
| SG0010 | Error | Missing configuration binder dependency |
| SG0011 | Error | Missing options configuration extensions dependency |
| SG0012 | Error | Non-empty constructors are not supported on attributed classes |
| SG0013 | Error | Mixed `ResourceDefinition` attribute usage on one class |
| SG0014 | Error | Non-generic `ResourceDefinition` requires an explicit compatible base |
| SG0015 | Error | Generic `ResourceDefinition<TResource>` must not declare an explicit base |
| SG0016 | Error | No Aspire resource type could be inferred/found |
| SG0017 | Warning | `IResourceBuilder<T>` property is never assigned (execution-only) |
| SG0018 | Warning | Project resource kit does not add the declared project via `AddProject<T>()` (execution-only) |
| SG0019 | Warning | Project resource kit explicit base does not use `ProjectResource` (execution-only) |
| SG0020 | Error | `OptionsHelper.Assign` action sets more than one property path |

SG0001–SG0016 block generation; SG0017–SG0019 are execution-only warnings that never block
generation, so a resource kit with incomplete wiring is still generated.

[1.0.0]: https://github.com/purview-dev/aspire-resourcekit/releases/tag/v1.0.0
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<RoslynVersion>5.9.0</RoslynVersion>
<TUnitVersion>1.68.17</TUnitVersion>
<PurviewSourceGeneratorFrameworkVersion>1.0.0-prerelease.54</PurviewSourceGeneratorFrameworkVersion>
<PurviewTelemetryVersion>5.0.0-prerelease.19</PurviewTelemetryVersion>
<PurviewTelemetryVersion>5.0.0</PurviewTelemetryVersion>
<DotNetRuntimeVersion>10.0.12</DotNetRuntimeVersion>
<MSExtensionVersion>10.10.0</MSExtensionVersion>
<OTelVersion>1.19.0</OTelVersion>
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

If your AppHost is getting bigger, this helps you keep resource setup maintainable and discoverable by moving composition into focused resource classes and generating the plumbing for you.

> [!NOTE]
> `Purview.Aspire.ResourceKit` 1.0.0 is the first stable release. See the [changelog](CHANGELOG.md) and [release notes](docs/wiki/Release-Notes.md).

> [!TIP]
> **Lifecycle quick links**
>
Expand Down Expand Up @@ -62,7 +65,7 @@ The extension method name is generated from your host metadata; in this reposito
>
> `<EnableAgentFolderInPackage>false</EnableAgentFolderInPackage>`

## Lifecycle mental model (early cheat sheet)
## Lifecycle mental model

ResourceKit has two layers of lifecycle methods:

Expand Down Expand Up @@ -94,6 +97,9 @@ From your `[HostKit]` and `[ResourceDefinition]` declarations, ResourceKit gener
- [Configuration and options](docs/wiki/Configuration-and-Options.md)
- [Diagnostics and troubleshooting](docs/wiki/Diagnostics.md)
- [Examples: generated vs manual](docs/wiki/Examples.md)
- [Release notes](docs/wiki/Release-Notes.md)
- [Versioning and compatibility](docs/wiki/Versioning.md)
- [Changelog](CHANGELOG.md)
- NuGet package deep dive (API and generator behavior): [`src/src/ResourceKit/Sdk/README.md`](src/src/ResourceKit/Sdk/README.md)
- Workspace notes for contributors: [`src/README.md`](src/README.md)

Expand Down
13 changes: 13 additions & 0 deletions docs/wiki/Contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ The repository carries agent skills and prompt workflows under `.agents/`. Consu
on source generators, tests, the project SDK, or conventional commits. AGENTS.md is the canonical
agent guidance and references `.agents/` for reusable workflows.

## Releases

Releases are produced by the shared pipeline when a version bump is merged to `main`; see
[Release Flow](Release-Flow.md). When preparing a release:

1. Update `package.json` (the authoritative version) and align `global.json` and
`Directory.Packages.props` with stable dependency versions.
2. Move new diagnostics from `src/src/SourceGeneration/AnalyzerReleases.Unshipped.md` into
`src/src/SourceGeneration/AnalyzerReleases.Shipped.md` under the released version, leaving the
unshipped file empty.
3. Add a [`CHANGELOG.md`](../../CHANGELOG.md) entry and update the wiki [release notes](Release-Notes.md).
4. Validate with `just lint-check` and `just pipeline-pack-validate` before merging.

## Pull requests

Pull requests target `main` and are validated by `.github/workflows/pr.yml`, which delegates to the
Expand Down
2 changes: 2 additions & 0 deletions docs/wiki/Home.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ moving composition into focused resource classes and generating the plumbing for
- [Source Generator Behaviors](Source-Generator-Behaviors.md)
- [Contributing](Contributing.md)
- [Release Flow](Release-Flow.md)
- [Release Notes](Release-Notes.md)
- [Versioning](Versioning.md)

## Why teams use it

Expand Down
39 changes: 39 additions & 0 deletions docs/wiki/Release-Flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,45 @@ Prerelease versions (any SemVer containing a hyphen, for example `1.0.0-prerelea
through the same push-to-`main` flow. The `v<version>` tag and GitHub release are still created and
packages published; the shared pipeline does not mark the GitHub release with the prerelease flag.

## Stable release preparation

A stable release (for example `1.0.0`) follows the same push-to-`main` flow, but requires version
preparation before the merge:

1. Set `package.json` `version` to the stable version (for example `1.0.0`).
2. Align the build SDK in `global.json` and the centrally-managed package versions in
`Directory.Packages.props` with their stable releases.
3. Move every entry from `src/src/SourceGeneration/AnalyzerReleases.Unshipped.md` into
`src/src/SourceGeneration/AnalyzerReleases.Shipped.md` under the released version, and leave the
unshipped file empty (see below).
4. Add the release to `CHANGELOG.md` and update the [release notes](Release-Notes.md) page.
5. Validate locally (`just lint-check` and `just pipeline-pack-validate`) before merging to `main`.

The GitHub release is created with automatically generated notes, grouped by the categories in
`.github/release.yml`.

## Analyzer release tracking

`src/src/SourceGeneration` ships public diagnostics (`SG0001`–`SG0020`), so it maintains the Roslyn
release tracking files:

- `AnalyzerReleases.Shipped.md` — rules that have shipped in a released version.
- `AnalyzerReleases.Unshipped.md` — rules added or changed since the last release.

`Microsoft.CodeAnalysis.Analyzers` automatically adds these files as analyzer additional files when
they exist in the project directory, so they are validated during the build (Roslyn components build
with `TreatWarningsAsErrors`). Add new rules to the *unshipped* file while developing, and move them
into the *shipped* file as part of a release. See [Contributing](Contributing.md) for the day-to-day
workflow.

## Build-time dependencies

Some centrally-managed packages are build/analysis-time only (consumed with `PrivateAssets`), for
example `Purview.Telemetry.SourceGenerator`, which `Purview.BuildSdk` injects into every non-test C#
project, and `Purview.SourceGeneratorFramework`. They never flow to consumers of the NuGet package,
but the repository cannot restore unless the pinned version exists on a configured feed. A stable
release therefore requires the pinned versions to be resolvable before merging to `main`.

## NuGet publishing

NuGet publishing uses the shared workflow's API-key path with the organization `NUGET__APIKEY` secret
Expand Down
43 changes: 43 additions & 0 deletions docs/wiki/Release-Notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Release notes

Stable release history for `Purview.Aspire.ResourceKit`, with the highlights that matter when you
upgrade from the `1.0.0-prerelease.*` line. The full, machine-readable history lives in
[`CHANGELOG.md`](https://github.com/purview-dev/aspire-resourcekit/blob/main/CHANGELOG.md) and on
the [GitHub releases page](https://github.com/purview-dev/aspire-resourcekit/releases).

## 1.0.0

The first stable release. The public surface that shipped during the prerelease line is now frozen
under [semantic versioning](Versioning.md).

### Highlights

- **Attributes drive generation** — `[HostKit]` and `[ResourceDefinition]` /
`[ResourceDefinition<TResource>]` produce the host kit, resource kit skeletons, typed options, and
the AppHost extension method. See [Attributes Reference](Attributes-Reference.md) and
[Generated Output](Generated-Output.md).
- **Deterministic lifecycle** — `Build`/`BuildResource(...)` constructs resources, then
`Configure`/`ConfigureResource()` wires them together. See
[Lifecycle: Build vs Configure](Lifecycle-Build-Configure.md).
- **Declarative enablement** — `IsEnabled` and `IsResourceEnabled(builder)`. See
[Enablement](Enablement.md).
- **Typed, extendable options** — generated `sealed partial` options bound from configuration. See
[Configuration and Options](Configuration-and-Options.md).
- **Test-friendly overrides** — `OptionsHelper` for args, environment variables, and flattening. See
[OptionsHelper](OptionsHelper.md) and [Testing with ResourceKit](Testing-with-ResourceKit.md).
- **Project resources** — first-class `AddProject<T>()` support with SG0018/SG0019 validation. See
[Project Resources](Project-Resources.md).
- **Diagnostics SG0001–SG0020** with an IDE code fix for SG0020. See [Diagnostics](Diagnostics.md).
- **Bundled agent skill** — `aspire-apphost-to-resourcekit` auto-installs into `.agents/skills/**`.
See [Bundled Agent Skills](Agent-Skills.md).

### Upgrade notes

- No public API changes are required when moving from `1.0.0-prerelease.*` to `1.0.0`.
- Pin `Purview.Aspire.ResourceKit` to `1.0.0` (or a later compatible `1.x`).

## See also

- [Versioning and compatibility](Versioning.md)
- [Release flow](Release-Flow.md)
- [Getting Started](Getting-Started.md)
50 changes: 50 additions & 0 deletions docs/wiki/Versioning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Versioning and compatibility

`Purview.Aspire.ResourceKit` follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
(`MAJOR.MINOR.PATCH`). The release version is authoritative in `package.json`; the release pipeline
tags the commit `v<version>` and publishes matching NuGet packages.

## What the version numbers mean

- **MAJOR** — a breaking change to the public surface (see below).
- **MINOR** — additive, backwards-compatible functionality.
- **PATCH** — backwards-compatible fixes and documentation updates.

## Prereleases

Prereleases use a hyphenated suffix (for example `1.0.0-prerelease.41`) and ship through the same
push-to-`main` pipeline. They are published so consumers can validate upcoming changes early; they
carry no stability guarantee. `1.0.0` is the first stable release.

## What counts as a breaking change

Once a version is stable, the following are treated as public contracts:

- The attributes `[HostKit]`, `[ResourceDefinition]`, and `[ResourceDefinition<TResource>]`,
including their named arguments (`Name`, `PropertyName`, `ExtensionMethodName`, `GenerateOptions`).
- The runtime types and members consumed by AppHost code (`HostKitBase`, `ResourceKitBase`,
`OptionsHelper`, and the `IResourceBuilder`/`WithEnvironment` extensions).
- The names and shapes of generated members (`BuildResource`, `ConfigureResource`,
`IsResourceEnabled`, generated host properties, generated options types, and the generated
`Add<HostKit>()` extension method).
- The diagnostic IDs `SG0001`–`SG0020`, their meanings, and their severities.

Renaming or removing any of these requires a MAJOR version and a documented migration path.

### Not covered

- The exact text of generated code and diagnostic messages.
- Files generated into a consuming repository (for example the copied `.agents/skills/**` folder).
- Build-time-only dependencies consumed through `PrivateAssets` (they never flow to consumers).

## Diagnostics as contracts

Diagnostic IDs are stable identifiers. New rules are introduced in the *unshipped* analyzer release
tracking file and only become part of a released version when they move into the *shipped* file as
part of a release. See [Contributing](Contributing.md) and [Release flow](Release-Flow.md) for the
release-time procedure.

## See also

- [Release notes](Release-Notes.md)
- [Release flow](Release-Flow.md)
4 changes: 3 additions & 1 deletion docs/wiki/_Sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@
- [Bundled Agent Skills](Agent-Skills.md)
- [Source Generator Behaviors](Source-Generator-Behaviors.md)
- [Contributing](Contributing.md)
- [Release Flow](Release-Flow.md)
- [Release Flow](Release-Flow.md)
- [Release Notes](Release-Notes.md)
- [Versioning](Versioning.md)
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"allowPrerelease": false
},
"msbuild-sdks": {
"Purview.BuildSdk": "1.0.0-prerelease.60"
"Purview.BuildSdk": "1.0.0"
},
"test": {
"runner": "Microsoft.Testing.Platform"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "purview-aspire-resourcekit",
"version": "1.0.0-prerelease.41",
"version": "1.0.0",
"keywords": [],
"homepage": "https://purview.dev/projects/aspire-resourcekit/",
"bugs": {
Expand Down
2 changes: 2 additions & 0 deletions src/src/ResourceKit/Sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,5 @@ For [troubleshooting guidance](https://purview.dev/docs/aspire-resourcekit/diagn

- [Homepage](https://purview.dev/projects/aspire-resourcekit/)
- [Documentation](https://purview.dev/docs/aspire-resourcekit/)
- [Changelog](https://github.com/purview-dev/aspire-resourcekit/blob/main/CHANGELOG.md)
- [Release notes](https://github.com/purview-dev/aspire-resourcekit/releases)
Loading
Loading