Skip to content

Commit 69e6856

Browse files
Spec 022 P0 — release-asset distribution + skill kit (#131)
* feat(packaging): wire P0 release-asset distribution (spec 022) Interim distribution path while the internal Microsoft NuGet feed is being plumbed through. Tag-driven GitHub Releases plus per-PR/main artifacts so reviewers can install any commit's build. - src/Reactor/Reactor.csproj: enable IsPackable, add packaging metadata, bundle Reactor.Analyzers.dll + Reactor.Localization.Generator.dll into analyzers/dotnet/cs/ so consumers get them transitively. - src/Reactor.Analyzers/Reactor.Analyzers.csproj: IsPackable=false (now bundled into the framework package, no longer ships standalone). - src/Reactor.Cli/Reactor.Cli.csproj: replace the bootstrap pattern with MirrorBinForSelfhost — copies the built mur.exe to <repo>/bin/<arch>/ matching the deployed kit layout. Guarded on concrete Platform so AnyCPU sln-config translation doesn't pollute with bin/anycpu/. - Delete src/Reactor.Cli/BOOTSTRAP-SKILL.md (stale, mentioned patch.exe). - .github/workflows/release.yml: triggers on PR / push-to-main / v* tag / workflow_dispatch. Packs the framework, publishes mur win-x64 and win-arm64 self-contained, assembles reactor-skill-kit-<version>.zip with SKILL.md + skills/ + bin/{x64,arm64}/mur.exe + install script, uploads as workflow artifacts. Tag pushes also create a GitHub Release. - Versioning: minver-cli with -t v -p experimental.0 -m 0.1. Bootstrap with `git tag v0.1.0-experimental.0 && git push --tags`. - tools/install-skill-kit.ps1: ships inside the kit zip; copies the kit to ~/.claude/skills/reactor/ and prepends bin/<arch> to user PATH. - skills/devtools.md: add "Getting mur on your PATH" section covering selfhost (MirrorBinForSelfhost build target) and deployed (kit installer). - .gitignore: drop selfhost/ entry — directory no longer regenerated. - docs/specs/022-packaging-and-distribution.md: status updated to P0 in flight, §3 rollout phases gain P0 (interim release assets), §4.4 documents the skill kit layout / PATH strategy / bootstrap pattern retirement, §8 rewritten for MinVer + commit-height versioning, §14 implementation phases reorganized — most original P1 work absorbed into P0. Local verification: dotnet build Reactor.sln -c Release → 0 errors dotnet test Reactor.Tests → 6836 passed dotnet test Reactor.SelfTests → 639 passed dotnet pack Reactor.csproj → produces .nupkg with bundled analyzer + source-gen DLLs Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(packaging): make mur framework-dependent (~70 MB/RID smaller) Sample apps and bench/perf projects stay self-contained via the Directory.Build.props default — they're sensitive to the WinUI SDK version and bundling makes it easier to test across versions during dev. The mur CLI is not WinUI-bound and benefits more from the size win. - release.yml: --self-contained false on both publish-mur steps. - install-skill-kit.ps1: detect missing .NET 9 runtime and warn with a winget install hint rather than letting mur fail opaquely on first run. - spec 022 §6 updated to document the framework-dependent choice and the sample-apps / tools split. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(packaging): address PR #131 review feedback 7 comments from copilot-pull-request-reviewer, all valid: 1. release.yml header: stale comments referenced the old `0.0.0-pr.<num>` / `0.0.0-main.<sha>` scheme from the daily-patch design. Rewritten to describe MinVer behavior. 2. spec §14 P0 step 4: same stale version description; updated to MinVer. 3. release.yml triggers: - PR `paths-ignore` narrowed from `docs/**` + `**.md` to just `docs/guide/**` so updates to SKILL.md / skills/*.md / docs/specs produce a fresh kit. - Removed `paths-ignore` from `push:` entirely so tag pushes always run regardless of what changed in the tagged commit (paths-ignore filter applies to all events under push:, no per-trigger override). 4. skills/devtools.md: tightened the selfhost note — the MirrorBinForSelfhost target is gated on Platform=x64/ARM64, so the blanket "every build mirrors" claim was wrong. Document the platform requirement and note that AnyCPU sln-config translations skip it. 5. Reactor.csproj: added an `AssertAnalyzerDllsExist` target with `BeforeTargets="Pack"` that errors clearly with a build-first hint if the analyzer / source-generator DLLs are missing. Avoids opaque pack-time failures for anyone running `dotnet pack src/Reactor` without a prior `dotnet build Reactor.sln`. 6. install-skill-kit.ps1: added safety guards before the `Remove-Item -Recurse -Force`. Refuses to install into: - the extracted kit itself or any parent of it - drive root, user profile, system root, Program Files, Desktop/Documents/Downloads - any path < 12 chars With a clear error message pointing at the default `-Path`. 7. release.yml `Compress-Archive` comment: clarified that the command archives the `reactor` folder itself (producing a single top-level folder in the zip), not "the parent" — the original wording was misleading. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 35917e1 commit 69e6856

9 files changed

Lines changed: 557 additions & 127 deletions

File tree

.github/workflows/release.yml

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
name: Package
2+
3+
# Produces the framework NuGet (.nupkg + .snupkg) and the agent skill kit
4+
# (reactor-skill-kit-<version>.zip with bin/x64 + bin/arm64).
5+
#
6+
# Versions come from MinVer (see "Resolve version" step). Both PR and main
7+
# builds get the same MinVer-computed version; they differ by sha in build
8+
# metadata and by workflow run ID. Tag pushes (`v*`) get the tag's version
9+
# verbatim and additionally create a GitHub Release with the assets attached.
10+
# This is the interim distribution path described in
11+
# docs/specs/022-packaging-and-distribution.md §3 (Phase P0) while the
12+
# internal Microsoft NuGet feed is being plumbed through.
13+
#
14+
# Both x64 and arm64 mur binaries are produced on every run so reviewers can
15+
# install either against a feature branch.
16+
17+
on:
18+
pull_request:
19+
paths-ignore:
20+
- 'docs/guide/**' # auto-generated; see CLAUDE.md memory note
21+
push:
22+
# No paths-ignore on push: tag pushes must always run regardless of what
23+
# changed in the tagged commit, and main pushes are infrequent enough
24+
# that running on doc-only changes isn't a real cost.
25+
branches: [main]
26+
tags:
27+
- 'v*'
28+
workflow_dispatch:
29+
inputs:
30+
version:
31+
description: 'Version to pack (e.g. 0.1.0-preview.1). When dispatched manually, no Release is created.'
32+
required: true
33+
type: string
34+
35+
permissions:
36+
contents: write # required for creating Releases
37+
38+
# ─── Version strategy ───────────────────────────────────────────────────────
39+
# Versions come from MinVer (commit-height past the latest `v*` tag). Pattern:
40+
#
41+
# - Past tag `v0.1.0-experimental.1` by N commits → `0.1.0-experimental.1.N+<sha7>`
42+
# - Exactly at a tag → that tag's version
43+
# - No tags yet → `0.1.0-experimental.0.<height>+<sha7>` (defaults below)
44+
#
45+
# Bootstrap once: `git tag v0.1.0-experimental.0 && git push --tags`. After
46+
# that, every commit gets a unique, ordered version with zero coordination —
47+
# height strictly increases as commits land. Bump to a new milestone by
48+
# tagging (e.g. `v0.1.0-experimental.1`); MinVer takes it from there.
49+
#
50+
# Tag pushes (`v*`) produce a clean version and create a GitHub Release.
51+
# Pushes to main and PR builds get the same MinVer-computed version (they
52+
# differ by sha → unique workflow artifacts; the .nupkg filename may collide
53+
# across PR pushes from the same merge base, which is acceptable for the
54+
# experimental channel).
55+
56+
jobs:
57+
package:
58+
name: Pack (x64 + arm64)
59+
runs-on: windows-latest
60+
steps:
61+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
62+
with:
63+
fetch-depth: 0 # MinVer needs full history to find the latest v* tag
64+
65+
- name: Setup .NET
66+
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
67+
with:
68+
dotnet-version: 9.0.x
69+
70+
- name: Install minver-cli
71+
run: dotnet tool install --global minver-cli --version 5.0.0
72+
73+
- name: Resolve version
74+
id: version
75+
shell: pwsh
76+
run: |
77+
$eventName = '${{ github.event_name }}'
78+
if ($eventName -eq 'workflow_dispatch') {
79+
$version = '${{ inputs.version }}'
80+
} else {
81+
# MinVer flags:
82+
# -t v tag prefix
83+
# -p experimental.0 default prerelease identifiers — flags pre-P1 builds as experimental
84+
# -m 0.1 minimum major.minor when no tag (so untagged → 0.1.x)
85+
$version = (& minver -t v -p experimental.0 -m 0.1).Trim()
86+
}
87+
if (-not $version) { throw "Could not resolve version" }
88+
"version=$version" >> $env:GITHUB_OUTPUT
89+
$isTag = '${{ github.ref }}'.StartsWith('refs/tags/v')
90+
"is_tag=$($isTag.ToString().ToLower())" >> $env:GITHUB_OUTPUT
91+
Write-Host "Version: $version (event=$eventName, isTag=$isTag)"
92+
93+
- name: Restore
94+
run: dotnet restore Reactor.sln
95+
96+
- name: Build framework + analyzers
97+
run: dotnet build Reactor.sln --no-restore --configuration Release -p:Platform=x64
98+
99+
- name: Pack framework NuGet
100+
run: >
101+
dotnet pack src/Reactor/Reactor.csproj
102+
--no-build --configuration Release
103+
-p:Version=${{ steps.version.outputs.version }}
104+
-p:Platform=x64
105+
-o artifacts/nupkg
106+
107+
# Framework-dependent: the consumer's machine supplies the .NET 9
108+
# runtime — saves ~70 MB per RID. install-skill-kit.ps1 checks for it
109+
# and errors out with an install hint if it's missing. See spec 022 §6.
110+
- name: Publish mur (win-x64)
111+
run: >
112+
dotnet publish src/Reactor.Cli/Reactor.Cli.csproj
113+
--configuration Release
114+
--runtime win-x64
115+
--self-contained false
116+
-p:Platform=x64
117+
-p:Version=${{ steps.version.outputs.version }}
118+
-o artifacts/mur/x64
119+
120+
- name: Publish mur (win-arm64)
121+
run: >
122+
dotnet publish src/Reactor.Cli/Reactor.Cli.csproj
123+
--configuration Release
124+
--runtime win-arm64
125+
--self-contained false
126+
-p:Platform=ARM64
127+
-p:Version=${{ steps.version.outputs.version }}
128+
-o artifacts/mur/arm64
129+
130+
- name: Assemble skill kit
131+
shell: pwsh
132+
run: |
133+
$version = '${{ steps.version.outputs.version }}'
134+
$stage = 'artifacts/kit-stage/reactor'
135+
New-Item -ItemType Directory -Force -Path $stage | Out-Null
136+
New-Item -ItemType Directory -Force -Path "$stage/bin/x64" | Out-Null
137+
New-Item -ItemType Directory -Force -Path "$stage/bin/arm64" | Out-Null
138+
139+
Copy-Item SKILL.md $stage
140+
Copy-Item -Recurse skills $stage
141+
Copy-Item artifacts/mur/x64/* "$stage/bin/x64/" -Recurse
142+
Copy-Item artifacts/mur/arm64/* "$stage/bin/arm64/" -Recurse
143+
Copy-Item tools/install-skill-kit.ps1 "$stage/install-skill-kit.ps1"
144+
145+
New-Item -ItemType Directory -Force -Path artifacts/kit | Out-Null
146+
$zip = "artifacts/kit/reactor-skill-kit-$version.zip"
147+
# Archive the `reactor` folder itself (not its contents) so the zip
148+
# contains a single top-level `reactor/` folder. Extracting the zip
149+
# gives the directory layout install-skill-kit.ps1 expects.
150+
Compress-Archive -Path artifacts/kit-stage/reactor -DestinationPath $zip -Force
151+
Write-Host "Kit: $zip"
152+
153+
- name: Upload artifact
154+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
155+
with:
156+
name: release-${{ steps.version.outputs.version }}
157+
path: |
158+
artifacts/nupkg/*
159+
artifacts/kit/*.zip
160+
retention-days: 30
161+
162+
- name: Create GitHub Release
163+
if: steps.version.outputs.is_tag == 'true'
164+
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
165+
with:
166+
name: Reactor ${{ steps.version.outputs.version }}
167+
tag_name: ${{ github.ref_name }}
168+
draft: false
169+
prerelease: ${{ contains(steps.version.outputs.version, '-') }}
170+
generate_release_notes: true
171+
files: |
172+
artifacts/nupkg/*.nupkg
173+
artifacts/nupkg/*.snupkg
174+
artifacts/kit/*.zip
175+
body: |
176+
**Reactor ${{ steps.version.outputs.version }}**
177+
178+
> Interim distribution — see [spec 022](https://github.com/microsoft/microsoft-ui-reactor/blob/main/docs/specs/022-packaging-and-distribution.md) for the rollout plan.
179+
180+
## Two assets
181+
182+
### `Microsoft.UI.Reactor.${{ steps.version.outputs.version }}.nupkg` — the framework
183+
184+
Drop into a folder and add a NuGet source pointing at it:
185+
186+
```xml
187+
<!-- nuget.config -->
188+
<configuration>
189+
<packageSources>
190+
<add key="reactor-local" value="C:\path\to\folder\with\nupkg" />
191+
</packageSources>
192+
</configuration>
193+
```
194+
195+
Then in your `.csproj`:
196+
197+
```xml
198+
<PackageReference Include="Microsoft.UI.Reactor" Version="${{ steps.version.outputs.version }}" />
199+
```
200+
201+
### `reactor-skill-kit-${{ steps.version.outputs.version }}.zip` — agent skill bundle + `mur` CLI
202+
203+
Extract, then run:
204+
205+
```powershell
206+
cd reactor
207+
.\install-skill-kit.ps1
208+
```
209+
210+
Installs to `~/.claude/skills/reactor/` and adds `bin/<arch>` to your user PATH. After a new shell, `mur --version` should resolve.

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,6 @@ health/
200200
# Publish profiles
201201
*.pubxml
202202

203-
selfhost/
204-
205203
# Stress/perf publish logs
206204
tests/stress_perf/publish_log*.txt
207205

0 commit comments

Comments
 (0)