diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f28d72e..f778647 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,8 +125,10 @@ jobs: # # They are not merely decorative. The samples, and only the samples, caught # the CommunityToolkit.Maui / Microsoft.Maui.Essentials version conflict and - # the Android minSdk 21 break during the .NET 10 upgrade. Skip them for a - # patch bump; do not skip them for anything that moves a major. + # the Android minSdk 21 break during the .NET 10 upgrade. Skip them by hand + # for a patch bump you have reason to trust; do not skip them for anything + # that moves a major. The dependency bot never applies the label, because + # these jobs are the only MAUI app coverage its pull requests get. samples: name: Sample apps (${{ matrix.project }}) if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-samples') }} diff --git a/.github/workflows/dependency-update.lock.yml b/.github/workflows/dependency-update.lock.yml index 2a2f25f..bdee82e 100644 --- a/.github/workflows/dependency-update.lock.yml +++ b/.github/workflows/dependency-update.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5a185ee6552756f4f3bda31b98def58ce695928921edb46c97e7d93531fcdced","body_hash":"2f89223b78269fd08d35e0803910748976203fb2b088b3d56ce1ebcf053f4aaa","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-5"} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5a185ee6552756f4f3bda31b98def58ce695928921edb46c97e7d93531fcdced","body_hash":"1e72d01a2b6a09b3a647c261f3d68e9de393c9aad7250361d622d917feff01c9","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-5"} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-dotnet","sha":"9a946fdbd5fb07b82b2f5a4466058b876ab72bb2","version":"v5.3.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]} # ___ _ _ # / _ \ | | (_) diff --git a/.github/workflows/dependency-update.md b/.github/workflows/dependency-update.md index 5515a24..0a51e5e 100644 --- a/.github/workflows/dependency-update.md +++ b/.github/workflows/dependency-update.md @@ -52,6 +52,48 @@ Every package version in this repository lives in `Directory.Packages.props`. Central package management is enabled, so **that is the only file whose versions you should edit**. Do not add `Version=` attributes to any `.csproj`. +## The shell you have + +Only allowlisted commands run: `dotnet`, `git status` and `git diff` from this +workflow's `tools.bash` list, the `git` commands needed to branch and commit, and +a few read-only basics (`cat`, `ls`, `grep`, `head`, `tail`, `sort`, `uniq`, `wc`, +`echo`, `printf`). A command line that +contains anything else is refused as a whole with "Permission denied", even when +the rest of it is allowed. That refusal is the allowlist, **not a network block**: +nuget.org is reachable through `dotnet`. + +- Do not use `curl`, `wget`, `cd`, `timeout`, `xargs`, `sed`, `awk` or scripts. + The working directory is already the repository root, so `cd` is never needed. +- Run each `dotnet` command on its own line, exactly as written in this file. +- If a command is refused, drop the part that is not on the list and run it again + before concluding anything. Do not report the task as incomplete because of a + refused `curl`. + +## How to find newer versions + +``` +dotnet restore Stellar.slnf +dotnet list Stellar.slnf package --outdated +dotnet list Stellar.slnf package --outdated --highest-minor +``` + +The first listing shows the newest stable version of each package; the second shows +the newest within the current major, which is the one to use for any package a rule +below holds on its current major line. + +`Stellar.slnf` leaves out the MAUI projects, so those packages do not appear in +either listing. Look each of them up by id instead (`Microsoft.Maui.Controls`, +`Microsoft.AspNetCore.Components.WebView.Maui`, `ReactiveUI.Maui.Reactive`, +`CommunityToolkit.Maui`, `CommunityToolkit.Maui.Markup`, `CommunityToolkit.Mvvm`, +`Mopups`): + +``` +dotnet package search Microsoft.Maui.Controls --exact-match --source https://api.nuget.org/v3/index.json +``` + +That prints every published version; take the highest one without a prerelease +suffix. + ## Rules about what may be updated These are not suggestions. Each one exists because taking the newest version @@ -67,13 +109,15 @@ they would just get no generated code. For analyzers and generators the referenc is a compatibility floor, not a version to maximise. Leave it alone. **Keep ReactiveUI on the 24.x line.** This covers every `ReactiveUI.*.Reactive` -package and `ReactiveUI.SourceGenerators`. ReactiveUI 25 moves binding onto a +package. `ReactiveUI.SourceGenerators` is versioned separately and stays on 3.x: +ReactiveUI 25 bundles 4.x and the two move together. ReactiveUI 25 moves binding onto a source generator: `Bind` calls through private view fields, which is how Stellar views are written, get no generated binding and throw at run time, and the `ICreatesCustomizedCommandRebinding` extension point that `Stellar.Maui/MauiCommandRebinding.cs` implements no longer exists. Minor and patch -updates within 24.x are fine. Do not attempt the move to 25 yourself — note in the -pull request body that it is available and leave the versions unchanged. +updates within 24.x (and within 3.x for the generators) are fine. Do not attempt +the move to 25 or later yourself — note in the pull request body that it is +available and leave the versions unchanged. **Keep the packages a ReactiveUI update depends on in step with it.** `CentralPackageTransitivePinningEnabled` is on, so when a ReactiveUI package @@ -117,10 +161,10 @@ one. Apply the `dependencies` label to every pull request you open. -Also apply `skip-samples` **only when the batch contains at least one major version -bump**. That label makes CI skip the two MAUI sample app builds, which take about -twelve minutes. Batches of patch and minor updates must not carry it, so those get -the full sample coverage. +**Never apply `skip-samples`.** That label makes CI skip the two MAUI sample app +builds. You cannot build the MAUI projects here, so those jobs are the only thing +that tests your update against a MAUI app head, and they are what catches version +conflicts that `Stellar.slnf` cannot see. The label is for a person to add by hand. ## The pull request diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml index f14ce38..8f4760b 100644 --- a/.github/workflows/nuget.yml +++ b/.github/workflows/nuget.yml @@ -1,5 +1,9 @@ -# This workflow will build a .NET project -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net +# Packs every package on a version tag and publishes them to nuget.org. +# +# Packing and publishing are separate jobs on purpose. nuget.org versions cannot +# be replaced, so a release that publishes some packages and then fails leaves a +# version that can never be completed: v2.1.3 shipped four of eleven packages +# that way. Nothing is pushed until every package has built and packed. name: .NET @@ -8,10 +12,18 @@ on: tags: - 'v**' +permissions: + contents: read + jobs: - build: - runs-on: macos-26 + pack: + name: Pack ${{ matrix.name }} + # Same image and Xcode as the MAUI jobs in ci.yml, so a release is packed on + # the toolchain pull requests were validated on. Move the two together. + runs-on: xcode-27 strategy: + # Let every package finish so one failure reports all of them at once. + fail-fast: false matrix: include: - name: Stellar @@ -57,7 +69,7 @@ jobs: dotnet-version: '10.x' - uses: maxim-lobanov/setup-xcode@v1.7.0 with: - xcode-version: latest-stable + xcode-version: '27.0' - name: Install MAUI Workloads run: dotnet workload install maui --ignore-failed-sources - name: Semver Parse @@ -67,5 +79,30 @@ jobs: run: dotnet build ${{ matrix.project }} - name: Pack ${{ matrix.name }} run: dotnet pack --configuration Release /p:AssemblyVersion=${{ steps.version.outputs.major }}.${{ steps.version.outputs.minor }}.${{ steps.version.outputs.patch }} /p:Version=${{ steps.version.outputs.major }}.${{ steps.version.outputs.minor }}.${{ steps.version.outputs.patch }} ${{ matrix.project }} - - name: Publish ${{ matrix.name }} - run: dotnet nuget push ${{ matrix.output }}/*.nupkg -k ${{ secrets.NUGET_TOKEN }} -s https://api.nuget.org/v3/index.json + - name: Upload ${{ matrix.name }} + uses: actions/upload-artifact@v7 + with: + name: nupkg-${{ matrix.name }} + path: ${{ matrix.output }}/*.nupkg + if-no-files-found: error + + publish: + name: Publish to nuget.org + needs: pack + runs-on: ubuntu-latest + steps: + - uses: actions/setup-dotnet@v6 + with: + dotnet-version: '10.x' + - uses: actions/download-artifact@v8 + with: + pattern: nupkg-* + path: packages + merge-multiple: true + - name: List packages + run: ls -l packages + # --skip-duplicate so that re-running this job after a partial push (a + # nuget.org outage, say) finishes the release instead of failing on the + # packages that already went up. + - name: Publish + run: dotnet nuget push "packages/*.nupkg" -k ${{ secrets.NUGET_TOKEN }} -s https://api.nuget.org/v3/index.json --skip-duplicate diff --git a/Directory.Packages.props b/Directory.Packages.props index 6e1d690..6f33ee5 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -26,7 +26,16 @@ new Primitives engine as the default packages, but keeps System.Reactive 7 types (Unit, IScheduler, Subject) at the API boundary, which Stellar's public API is built on. System.Reactive is referenced directly because the - default ReactiveUI packages no longer pull it in transitively. --> + default ReactiveUI packages no longer pull it in transitively. + + Held on 24.x (and ReactiveUI.SourceGenerators on 3.x) on purpose. ReactiveUI + 25 moves binding onto a source generator: Bind calls through private view + fields, which is how Stellar views are written, get no generated binding and + throw at run time, and the ICreatesCustomizedCommandRebinding extension point + behind Stellar.Maui's MauiCommandRebinding is gone. Moving is a breaking + release, not a version bump. ReactiveUI.Maui.Reactive also sets the floor for + Microsoft.Maui.Controls and Microsoft.Extensions.*; with transitive pinning + on, raise those with it or restore fails with NU1109. -->