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
8 changes: 0 additions & 8 deletions .agents/skills/telemetry-sourcegenerator-design/.gitignore

This file was deleted.

8 changes: 0 additions & 8 deletions .agents/skills/telemetry-sourcegenerator-migration/.gitignore

This file was deleted.

This file was deleted.

34 changes: 34 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,37 @@ When changing release behaviour, grep the consuming repositories' `docs/wiki/Rel
- "The workflow does not publish to NuGet" — `release-mode: NuGet` runs `PublishNuGetModule` and pushes to `NuGet:FeedUrl`.
- "The shared pipeline does not mark the GitHub release with the prerelease flag" — `Release:MarkPrerelease` defaults to `true`.
- "…and attaches the package artifacts" — assets are attached only when the caller passes `upload-artifacts: true`, which no consumer currently does.

## Agent skills

Authored skills live in the repository-root `skills/` folder. **Nothing packs them into a NuGet
package** - `Purview.BuildSdk` 1.0.6 removed skill packaging and the build-time `.agents/` mirror
outright. The skills CLI clones the *git* repository and only discovers a root `skills/` folder, so
that is the one delivery route.

`.agents/skills/` is the CLI's install location for skills from **other** repositories, and is
gitignored. This repository's own skills are never installed into it - that would leave two copies to
drift apart. Read them at their authored path, `skills/<name>/SKILL.md`.

```bash
npx skills add purview-dev/build
```

| Skill | Answers |
| -- | -- |
| `skills/purview-build-adoption/` | wiring the pipeline into a repository: the workflows, the action, local use, the two version axes |
| `skills/purview-build-configuration/` | where `purview-build.json` is found, precedence, every setting, the secrets |
| `skills/purview-build-pipeline/` | what each module does, its dependencies, and why it was skipped |
| `skills/purview-build-pack-validation/` | the package rules, the target-framework token, and `RequireExplicitContent` |
| `skills/purview-build-release-eligibility/` | the `REL0nn` rules, the built-in policies, and the three release models |

Every skill carries the `purview-build` prefix. Skills install into one flat directory per agent,
shared with every skill a developer has installed from anywhere, so an unprefixed name collides and
the loser is whichever installed second.

`src/tests/Repository.UnitTests/SkillTests.cs` validates them on every test run through
`Purview.Skills.Testing`. The `[InheritsTests]` attribute there is load-bearing - TUnit does not walk
base types during discovery, so without it the run is green and nothing is checked.

A relative link from one `SKILL.md` into another skill's folder is a rule violation: only a skill's
own folder is installed with it. Name the other skill in prose instead.
5 changes: 4 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<RoslynVersion>5.9.0</RoslynVersion>
<TUnitVersion>1.72.16</TUnitVersion>
<!-- Floor set by Purview.Skills.Testing 1.0.6, which depends on TUnit.Assertions/TUnit.Core 1.75.0. -->
<TUnitVersion>1.75.0</TUnitVersion>
<DotNetRuntimeVersion>10.0.12</DotNetRuntimeVersion>
<MSExtensionVersion>10.10.0</MSExtensionVersion>
<ModularPipelinesVersion>3.2.8</ModularPipelinesVersion>
Expand All @@ -17,6 +18,8 @@
<PackageVersion Include="TUnit.Core" Version="$(TUnitVersion)" />
<PackageVersion Include="TUnit.Aspire" Version="$(TUnitVersion)" />
<PackageVersion Include="TUnit.Mocks" Version="$(TUnitVersion)" />
<!-- The Agent Skills conformance rule set, shipped alongside Purview.BuildSdk. -->
<PackageVersion Include="Purview.Skills.Testing" Version="1.0.6" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="$(RoslynVersion)" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(RoslynVersion)" />
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="$(RoslynVersion)" />
Expand Down
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.5"
"Purview.BuildSdk": "1.0.6"
},
"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": "build",
"version": "0.5.3",
"version": "0.5.4",
"description": "Shared build/test/release pipeline for the purview-dev organisation, packaged as a pinned .NET tool with a GitHub composite action and reusable workflows.",
"license": "MIT",
"author": {
Expand Down
146 changes: 146 additions & 0 deletions skills/purview-build-adoption/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
---
name: purview-build-adoption
description: >-
Use when wiring Purview.Build into a repository - choosing the reusable workflow or the composite
action, pinning the workflow ref versus the tool version, running the pipeline locally as a dotnet
tool, and what a consuming repository has to add before anything will run.
metadata:
product: Purview.Build
repository: purview-dev/build
---

# Adopting Purview.Build

`Purview.Build` is a pipeline tool consumed from a repository that owns its own configuration. The
pipeline code lives in `purview-dev/build`; a consumer references a reusable workflow or the
composite action — or runs the tool locally — and configures it with `.config/purview-build.json`.

A consuming repository needs exactly three things: a `purview-build.json`, a `version` field in the
root `package.json`, and a workflow that calls one of the entry points below. No copied pipeline
project, no package-source credentials.

## Two independent version axes

Get this wrong and you run new tool code through old workflow inputs.

| Axis | What it selects | How |
| --- | --- | --- |
| `@ref` on the workflow or action reference | the **workflow/action code** | `@main` for latest, a release tag (`@v0.2.0`) for reproducibility. There is no `@latest`, and the `@ref` is **required** for a cross-repository reference. |
| the `build-version` input | the installed **tool** | omit it for the latest stable from nuget.org; pin an exact version (`build-version: 0.2.0`) for reproducibility. |

Pin both, or neither. Pinning one and floating the other is the mismatch.

## Reusable workflow — the usual choice

```yaml
# .github/workflows/pr.yml
name: PR
on:
pull_request:
branches: [main]
jobs:
build:
uses: purview-dev/build/.github/workflows/purview-build.yml@main
secrets: inherit
```

```yaml
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
concurrency:
# Callers own release serialisation; the reusable workflow defines no concurrency group.
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
release:
uses: purview-dev/build/.github/workflows/purview-release.yml@main
with:
release-mode: NuGet
secrets: inherit
```

The release caller's **trigger** is what picks your release model:

| Model | Trigger | Policy |
| --- | --- | --- |
| A — release on `main` | `push: branches: [main]` | `ReleaseOnMain` (the default) |
| B — main-as-head, release branch | `push: branches: [release]` | `ReleaseOnMain` |
| C — per-line release branches | `push: branches: ['release/**']` plus `workflow_dispatch` | `TrunkReservesMinor` |

```yaml
jobs:
release:
uses: purview-dev/build/.github/workflows/purview-release.yml@main
with:
release-mode: NuGet
eligibility-policy: TrunkReservesMinor
secrets: inherit
```

The reusable release workflow asks the tool to evaluate eligibility and reads the verdict: an
already-released version **skips** and the job finishes green; a policy violation **fails** the job
naming the rule. Merging `main` into `release` therefore releases exactly once.

## Composite action — when you need surrounding steps

```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: purview-dev/build/.github/actions/purview-build@main
env:
Build__TestFilter: "/*/*/*/*[Category=Unit]"
```

`build-version` is optional here too.

## Locally

```shell
dotnet new tool-manifest # only if there is no .config/dotnet-tools.json
dotnet tool install Purview.Build
dotnet purview-build
```

It is an ordinary .NET local tool: the manifest pins the version, and `dotnet tool restore` installs
it. Most repositories wrap it in `just` recipes:

```just
pipeline-pr: dotnet purview-build
pipeline-pack-validate: dotnet purview-build --Build:RunPack=true --Build:ValidatePack=true --Release:Mode=None
```

Before running anything destructive, two commands tell you what *would* happen:

```shell
dotnet purview-build --help # usage, probe order, and the resolved config path
dotnet purview-build release-explain # the release decision, without running a module
```

## Releasing a consuming repository

Bump the `version` field in the root `package.json`, and merge the validated pull request into the
release head. **The pipeline owns tagging (`v{version}`) and the GitHub release** — never push a
release tag by hand.

## A setting that will not take effect

Precedence is **command line > environment variables > `purview-build.json` > defaults**. Because
environment variables outrank the JSON file, an *empty* forwarded variable silently erases a
configured value. That is why the reusable workflows forward every optional input only when the
caller actually provided it, and why `WorkflowParityTests` asserts that no optional input is mapped
straight into `env:` without an `if [ -n … ]` guard.

If a `purview-build.json` setting appears to be ignored, check for an environment variable of the
same name first.

## Related skills

`purview-build-configuration` for the full `purview-build.json` reference and the secrets,
`purview-build-pipeline` for the modules and their order, `purview-build-pack-validation` for the
package rules, and `purview-build-release-eligibility` for the `REL0nn` rules and the three models.
Loading
Loading