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
210 changes: 210 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
name: Package

# Produces the framework NuGet (.nupkg + .snupkg) and the agent skill kit
# (reactor-skill-kit-<version>.zip with bin/x64 + bin/arm64).
#
# Versions come from MinVer (see "Resolve version" step). Both PR and main
# builds get the same MinVer-computed version; they differ by sha in build
# metadata and by workflow run ID. Tag pushes (`v*`) get the tag's version
# verbatim and additionally create a GitHub Release with the assets attached.
# This is the interim distribution path described in
# docs/specs/022-packaging-and-distribution.md §3 (Phase P0) while the
# internal Microsoft NuGet feed is being plumbed through.
#
# Both x64 and arm64 mur binaries are produced on every run so reviewers can
# install either against a feature branch.

on:
pull_request:
paths-ignore:
- 'docs/guide/**' # auto-generated; see CLAUDE.md memory note
push:
# No paths-ignore on push: tag pushes must always run regardless of what
# changed in the tagged commit, and main pushes are infrequent enough
# that running on doc-only changes isn't a real cost.
branches: [main]
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version to pack (e.g. 0.1.0-preview.1). When dispatched manually, no Release is created.'
required: true
type: string

permissions:
contents: write # required for creating Releases

# ─── Version strategy ───────────────────────────────────────────────────────
# Versions come from MinVer (commit-height past the latest `v*` tag). Pattern:
#
# - Past tag `v0.1.0-experimental.1` by N commits → `0.1.0-experimental.1.N+<sha7>`
# - Exactly at a tag → that tag's version
# - No tags yet → `0.1.0-experimental.0.<height>+<sha7>` (defaults below)
#
# Bootstrap once: `git tag v0.1.0-experimental.0 && git push --tags`. After
# that, every commit gets a unique, ordered version with zero coordination —
# height strictly increases as commits land. Bump to a new milestone by
# tagging (e.g. `v0.1.0-experimental.1`); MinVer takes it from there.
#
# Tag pushes (`v*`) produce a clean version and create a GitHub Release.
# Pushes to main and PR builds get the same MinVer-computed version (they
# differ by sha → unique workflow artifacts; the .nupkg filename may collide
# across PR pushes from the same merge base, which is acceptable for the
# experimental channel).

jobs:
package:
name: Pack (x64 + arm64)
runs-on: windows-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # MinVer needs full history to find the latest v* tag

- name: Setup .NET
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
with:
dotnet-version: 9.0.x

- name: Install minver-cli
run: dotnet tool install --global minver-cli --version 5.0.0

- name: Resolve version
id: version
shell: pwsh
run: |
$eventName = '${{ github.event_name }}'
if ($eventName -eq 'workflow_dispatch') {
$version = '${{ inputs.version }}'
} else {
# MinVer flags:
# -t v tag prefix
# -p experimental.0 default prerelease identifiers — flags pre-P1 builds as experimental
# -m 0.1 minimum major.minor when no tag (so untagged → 0.1.x)
$version = (& minver -t v -p experimental.0 -m 0.1).Trim()
}
if (-not $version) { throw "Could not resolve version" }
"version=$version" >> $env:GITHUB_OUTPUT
$isTag = '${{ github.ref }}'.StartsWith('refs/tags/v')
"is_tag=$($isTag.ToString().ToLower())" >> $env:GITHUB_OUTPUT
Write-Host "Version: $version (event=$eventName, isTag=$isTag)"

- name: Restore
run: dotnet restore Reactor.sln

- name: Build framework + analyzers
run: dotnet build Reactor.sln --no-restore --configuration Release -p:Platform=x64

- name: Pack framework NuGet
run: >
dotnet pack src/Reactor/Reactor.csproj
--no-build --configuration Release
-p:Version=${{ steps.version.outputs.version }}
-p:Platform=x64
-o artifacts/nupkg

# Framework-dependent: the consumer's machine supplies the .NET 9
# runtime — saves ~70 MB per RID. install-skill-kit.ps1 checks for it
# and errors out with an install hint if it's missing. See spec 022 §6.
- name: Publish mur (win-x64)
run: >
dotnet publish src/Reactor.Cli/Reactor.Cli.csproj
--configuration Release
--runtime win-x64
--self-contained false
-p:Platform=x64
-p:Version=${{ steps.version.outputs.version }}
-o artifacts/mur/x64

- name: Publish mur (win-arm64)
run: >
dotnet publish src/Reactor.Cli/Reactor.Cli.csproj
--configuration Release
--runtime win-arm64
--self-contained false
-p:Platform=ARM64
-p:Version=${{ steps.version.outputs.version }}
-o artifacts/mur/arm64

- name: Assemble skill kit
shell: pwsh
run: |
$version = '${{ steps.version.outputs.version }}'
$stage = 'artifacts/kit-stage/reactor'
New-Item -ItemType Directory -Force -Path $stage | Out-Null
New-Item -ItemType Directory -Force -Path "$stage/bin/x64" | Out-Null
New-Item -ItemType Directory -Force -Path "$stage/bin/arm64" | Out-Null

Copy-Item SKILL.md $stage
Copy-Item -Recurse skills $stage
Copy-Item artifacts/mur/x64/* "$stage/bin/x64/" -Recurse
Copy-Item artifacts/mur/arm64/* "$stage/bin/arm64/" -Recurse
Copy-Item tools/install-skill-kit.ps1 "$stage/install-skill-kit.ps1"

New-Item -ItemType Directory -Force -Path artifacts/kit | Out-Null
$zip = "artifacts/kit/reactor-skill-kit-$version.zip"
# Archive the `reactor` folder itself (not its contents) so the zip
# contains a single top-level `reactor/` folder. Extracting the zip
# gives the directory layout install-skill-kit.ps1 expects.
Compress-Archive -Path artifacts/kit-stage/reactor -DestinationPath $zip -Force
Write-Host "Kit: $zip"

- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: release-${{ steps.version.outputs.version }}
path: |
artifacts/nupkg/*
artifacts/kit/*.zip
retention-days: 30

- name: Create GitHub Release
if: steps.version.outputs.is_tag == 'true'
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
with:
name: Reactor ${{ steps.version.outputs.version }}
tag_name: ${{ github.ref_name }}
draft: false
prerelease: ${{ contains(steps.version.outputs.version, '-') }}
generate_release_notes: true
files: |
artifacts/nupkg/*.nupkg
artifacts/nupkg/*.snupkg
artifacts/kit/*.zip
body: |
**Reactor ${{ steps.version.outputs.version }}**

> 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.

## Two assets

### `Microsoft.UI.Reactor.${{ steps.version.outputs.version }}.nupkg` — the framework

Drop into a folder and add a NuGet source pointing at it:

```xml
<!-- nuget.config -->
<configuration>
<packageSources>
<add key="reactor-local" value="C:\path\to\folder\with\nupkg" />
</packageSources>
</configuration>
```

Then in your `.csproj`:

```xml
<PackageReference Include="Microsoft.UI.Reactor" Version="${{ steps.version.outputs.version }}" />
```

### `reactor-skill-kit-${{ steps.version.outputs.version }}.zip` — agent skill bundle + `mur` CLI

Extract, then run:

```powershell
cd reactor
.\install-skill-kit.ps1
```

Installs to `~/.claude/skills/reactor/` and adds `bin/<arch>` to your user PATH. After a new shell, `mur --version` should resolve.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,6 @@ health/
# Publish profiles
*.pubxml

selfhost/

# Stress/perf publish logs
tests/stress_perf/publish_log*.txt

Expand Down
Loading
Loading