diff --git a/.github/workflows/debug-pre-release.yml b/.github/workflows/debug-pre-release.yml index 2b8b5bd..4fbf6d7 100644 --- a/.github/workflows/debug-pre-release.yml +++ b/.github/workflows/debug-pre-release.yml @@ -168,10 +168,16 @@ jobs: # No CodesignKey/EnableCodeSigning -> the build applies only an ad-hoc signature # (all an internal test build needs; testers still have to clear the Gatekeeper # quarantine flag — see the release notes text in publish-release). - # Passing BOTH RIDs in a single RuntimeIdentifier value is how the .NET MAUI Mac - # Catalyst targets emit a universal (lipo'd x64 + arm64) binary. Release builds do - # this by default; a Debug build has to state it explicitly. See - # https://learn.microsoft.com/dotnet/maui/mac-catalyst/deployment/publish-unsigned + # A universal (lipo'd x64 + arm64) binary comes from the *plural* RuntimeIdentifiers + # property, NOT the singular RuntimeIdentifier: the .NET SDK validates a lone + # RuntimeIdentifier as ONE RID and rejects a `;`-list with + # "NETSDK1083: The specified RuntimeIdentifier 'maccatalyst-x64;maccatalyst-arm64' + # is not recognized". MAUI's Mac Catalyst targets only rewrite a `;`-list in the + # singular property into the plural one when it is set inside the .csproj (as MAUI + # does for Release builds); they can't touch it when it arrives as a command-line + # global property, so a Debug build has to pass RuntimeIdentifiers itself. See the + # dotnet/macios .NET 8 release notes ("set the RuntimeIdentifiers property + # (plural, don't confuse with RuntimeIdentifier)"). # The two RIDs MUST be joined with the escaped `%3B`, never a literal `;`: MSBuild's # own -p: switch parser treats `;` as a property-list delimiter (shell quoting only # stops the *shell* from splitting, not MSBuild), so a literal `;` makes it read @@ -183,7 +189,7 @@ jobs: -f ${{ env.TFM }} -c Debug -p:CreatePackage=false - -p:RuntimeIdentifier=maccatalyst-x64%3Bmaccatalyst-arm64 + -p:RuntimeIdentifiers=maccatalyst-x64%3Bmaccatalyst-arm64 # `ditto` is Apple's supported way to archive an .app bundle for transport — it # preserves the symlinks, permissions, and resource forks that a plain `zip` diff --git a/CLAUDE.md b/CLAUDE.md index 1147da5..49cf264 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -193,4 +193,4 @@ A misplaced `///` XML doc comment (e.g. attached to one parameter inside a multi `StageFright.App` (the Windows head, `WindowsPackageType=None`) can show two `PRI249: Invalid qualifier` warnings from `WinAppSdkGenerateProjectPriFile` naming `SORTABLE-LIST`/`THEME-SWITCHER` — these come from the Blazor.Bootstrap package's own static JS assets (`blazor.bootstrap.sortable-list.js`, `blazor.bootstrap.theme-switcher.js`), which WinAppSDK's PRI resource indexer misreads as the `name.qualifier-value.ext` convention used by qualified assets (e.g. `logo.scale-200.png`); the warning is benign (build still succeeds, both files still get served) but not suppressible via `NoWarn`/`MSBuildWarningsAsMessages` since the native `makepri.exe` tool embeds "PRI249" as free text, not as a structured MSBuild warning code. Fixed by adding a `_GenerateProjectPriConfigurationFiles`-scoped `BeforeTargets` hook in `StageFright.App.csproj` that populates WinAppSDK's own exclusion item (`_AppxLayoutAssetPackageFiles`) from the two files' `PackagingOutputs`/`PriOutputs` entries — it removes them from PRI's qualifier scan only, not from Blazor's own static-web-asset copy to `wwwroot`. If new Blazor.Bootstrap component JS ever reintroduces a dash-containing filename that trips the same warning, extend that same `Condition` rather than re-deriving the mechanism from scratch. -`.github/workflows/debug-pre-release.yml` (manual-only, `workflow_dispatch`; was `debug-msix-release.yml` before it grew a macOS job) builds **Debug**-configuration packages of the `dev` branch for two platforms and publishes them together as the single rolling `dev-debug-build` pre-release (constant asset filenames, never accumulates history): `StageFrightCommunity-dev-DEBUG.msix` (Windows, self-signed MSIX) and `StageFrightCommunity-dev-DEBUG-mac.zip` (macOS, an **unsigned, universal** Mac Catalyst `.app` — `-p:CreatePackage=false -p:RuntimeIdentifier=maccatalyst-x64%3Bmaccatalyst-arm64`, zipped with `ditto`, no signing secrets; the two RIDs are joined with the escaped `%3B`, never a literal `;` — MSBuild's `-p:` parser treats a literal `;` as a property-list delimiter and fails with `MSB1006: Property is not valid. Switch: maccatalyst-arm64`, and shell quoting does not prevent it (issue #366)). It is three jobs: `build-windows-msix` and `build-mac-app` run in parallel and each upload their package as a CI artifact; `publish-release` `needs:` both, downloads the artifacts, and does the single `gh release delete dev-debug-build --cleanup-tag` then `gh release create` with both assets — a full delete + recreate, *not* `gh release upload --clobber`, because GitHub "immutable releases" (GA Oct 2025) permanently block replacing/deleting *or adding* an asset once a release is published (`--clobber` fails with `HTTP 422: Cannot delete asset from an immutable release`) while deleting a whole release stays allowed; the delete + recreate works whether or not repo-level release immutability is enabled. Because `publish-release` needs both builds, a break on **either** platform's tooling means no release that run (the previous one stays intact) rather than a half-updated release. If a `dev-debug-build` release was already published as immutable, it must be deleted once by hand — disabling the repo setting does not retroactively unlock it. Only the Windows job needs repo secrets: `MSIX_CERT_BASE64` (a self-signed code-signing cert, base64-encoded PFX bytes) and `MSIX_CERT_PASSWORD`. The cert's Subject **must exactly match** `Identity/@Publisher` in `Platforms\Windows\Package.appxmanifest` (currently `CN=StageFright Community`) or MSIX packaging fails — if that Publisher value is ever changed, a matching new cert must be generated and the secret rotated, and vice versa. The Mac `.app` is only ad-hoc-signed, so testers must clear the Gatekeeper quarantine flag (`xattr -dr com.apple.quarantine "StageFright Community.app"`, or right-click → Open); note `Platforms/MacCatalyst/Info.plist` still carries the MAUI-template default `UIRequiredDeviceCapabilities` = `arm64`, which could keep the Intel slice of the universal build from launching on Intel Macs — revisit that key if Intel support actually matters. `StageFright.App.csproj`'s local/CI `Release`+`Debug` builds are otherwise untouched (Windows still unpackaged, `WindowsPackageType=None`) — the workflow passes `WindowsPackageType=Package`/signing and the Mac RIDs purely as `dotnet publish -p:` command-line overrides, never persisted to the project file; the only project-file change is an inert `RuntimeIdentifierOverride`→`RuntimeIdentifier` `PropertyGroup` (the documented workaround for [WindowsAppSDK#3337](https://github.com/microsoft/WindowsAppSDK/issues/3337)) that only activates when that property is explicitly passed on the command line, as the Windows job does. +`.github/workflows/debug-pre-release.yml` (manual-only, `workflow_dispatch`; was `debug-msix-release.yml` before it grew a macOS job) builds **Debug**-configuration packages of the `dev` branch for two platforms and publishes them together as the single rolling `dev-debug-build` pre-release (constant asset filenames, never accumulates history): `StageFrightCommunity-dev-DEBUG.msix` (Windows, self-signed MSIX) and `StageFrightCommunity-dev-DEBUG-mac.zip` (macOS, an **unsigned, universal** Mac Catalyst `.app` — `-p:CreatePackage=false -p:RuntimeIdentifiers=maccatalyst-x64%3Bmaccatalyst-arm64`, zipped with `ditto`, no signing secrets). Two RID gotchas here, both load-bearing: (1) it must be the **plural** `RuntimeIdentifiers` property — the singular `RuntimeIdentifier` is validated by the .NET SDK as a *single* RID and rejects a `;`-list with `NETSDK1083: The specified RuntimeIdentifier 'maccatalyst-x64;maccatalyst-arm64' is not recognized`; MAUI's Mac Catalyst targets only rewrite a `;`-list in the singular property into the plural one when it is set inside the `.csproj` (as MAUI does for Release), not when it arrives as a command-line global property, so a Debug CLI build has to pass the plural form itself. (2) The two RIDs are joined with the escaped `%3B`, never a literal `;` — MSBuild's `-p:` parser treats a literal `;` as a property-list delimiter and fails with `MSB1006: Property is not valid. Switch: maccatalyst-arm64`, and shell quoting does not prevent it (issue #366). It is three jobs: `build-windows-msix` and `build-mac-app` run in parallel and each upload their package as a CI artifact; `publish-release` `needs:` both, downloads the artifacts, and does the single `gh release delete dev-debug-build --cleanup-tag` then `gh release create` with both assets — a full delete + recreate, *not* `gh release upload --clobber`, because GitHub "immutable releases" (GA Oct 2025) permanently block replacing/deleting *or adding* an asset once a release is published (`--clobber` fails with `HTTP 422: Cannot delete asset from an immutable release`) while deleting a whole release stays allowed; the delete + recreate works whether or not repo-level release immutability is enabled. Because `publish-release` needs both builds, a break on **either** platform's tooling means no release that run (the previous one stays intact) rather than a half-updated release. If a `dev-debug-build` release was already published as immutable, it must be deleted once by hand — disabling the repo setting does not retroactively unlock it. Only the Windows job needs repo secrets: `MSIX_CERT_BASE64` (a self-signed code-signing cert, base64-encoded PFX bytes) and `MSIX_CERT_PASSWORD`. The cert's Subject **must exactly match** `Identity/@Publisher` in `Platforms\Windows\Package.appxmanifest` (currently `CN=StageFright Community`) or MSIX packaging fails — if that Publisher value is ever changed, a matching new cert must be generated and the secret rotated, and vice versa. The Mac `.app` is only ad-hoc-signed, so testers must clear the Gatekeeper quarantine flag (`xattr -dr com.apple.quarantine "StageFright Community.app"`, or right-click → Open); note `Platforms/MacCatalyst/Info.plist` still carries the MAUI-template default `UIRequiredDeviceCapabilities` = `arm64`, which could keep the Intel slice of the universal build from launching on Intel Macs — revisit that key if Intel support actually matters. `StageFright.App.csproj`'s local/CI `Release`+`Debug` builds are otherwise untouched (Windows still unpackaged, `WindowsPackageType=None`) — the workflow passes `WindowsPackageType=Package`/signing and the Mac RIDs purely as `dotnet publish -p:` command-line overrides, never persisted to the project file; the only project-file change is an inert `RuntimeIdentifierOverride`→`RuntimeIdentifier` `PropertyGroup` (the documented workaround for [WindowsAppSDK#3337](https://github.com/microsoft/WindowsAppSDK/issues/3337)) that only activates when that property is explicitly passed on the command line, as the Windows job does.