Skip to content

Support the .NET 11 SDK band and net11.0-tizen TFMs - #310

Open
Redth wants to merge 3 commits into
Samsung:net10.0from
Redth:redth-net11-tizen-workload
Open

Support the .NET 11 SDK band and net11.0-tizen TFMs#310
Redth wants to merge 3 commits into
Samsung:net10.0from
Redth:redth-net11-tizen-workload

Conversation

@Redth

@Redth Redth commented Aug 26, 2026

Copy link
Copy Markdown

Summary

Adds .NET 11 support to the tizen workload alongside .NET 10, and repairs two install scripts that were committed corrupt on this branch.

Base branch

This PR targets net10.0 because that is the active branch and it is already multi-band:
DOTNET_VERSION selects the SDK band at build time, and Versions.props carries per-major
arcade conditions. No net11.0 branch exists today, so net10.0 is the only branch this can
land on.

If you would rather follow the per-major branch convention (net8.0 / net9.0 / net10.0),
create a net11.0 branch and simply retarget this PR to it — no changes to the commits are
required
. The change set is additive and does not modify .NET 10 behaviour, so it applies
cleanly either way. Say the word and I'll switch the base.

Chosen TFM / API mapping

Primary TFM: net11.0-tizen11.0 → TizenFX API level 15Samsung.Tizen.Ref.API15 15.0.0.19396 (already published).

net11.0 combines with every declared platform version, so net11.0-tizen{8.0,9.0,10.0,10.1,11.0} all work.

No new reference or runtime pack is required. Ref packs ship ref/net8.0 assemblies resolved by explicit <File Path=…/> entries in data/FrameworkList.xml, so they're independent of the consuming project's .NET version. Samsung.Tizen.Ref.API16 does not exist and isn't needed.

SDK feature band: 11.0.100-preview.7 (latest .NET 11 SDK is 11.0.100-preview.7.26381.103, 2026-08-11).

Commit 1 — install script repair (independent of .NET 11)

Both installers were committed truncated mid-statement and NUL-padded, so the publicly curl'd installer could never complete:

  • workload-install.sh ended at for DOTNET_SDK in $INSTALLED_DOTNET_SD + 134 NUL bytes
  • workload-install.ps1 ended inside its catch block at Write-Host

validate-version-map.yml didn't catch it because Generate-InstallScripts.ps1 only compares the auto-generated version-map block — which was intact — so it reported OK for a file missing its tail. The generator now also asserts no NUL bytes and an expected final statement.

Also restores the SDK enumeration fix lost in the same regression: --update-all-workloads matched only ^6|^7, silently ignoring every installed .NET 8/9/10/11 SDK.

Commit 2 — .NET 11 support

File Change
build/Versions.props arcade 11.0.0-beta.26426.103 for 11.0 bands
NuGet.config add dotnet11; clear inherited disabledPackageSources
Samsung.Tizen.Sdk.targets add the net11.0 KnownRuntimePack (without it: NETSDK1082)
RuntimeList.xml add the .NET Runtime 11 row
template.json offer net11.0; default stays net10.0 while .NET 11 is preview
TizenApp1.csproj Tizen.UI.Components.Material referenced conditionally on the resolved platform version, with an actionable TIZENTMPL001 instead of an opaque NU1101
test-matrix.sh net11 rows; rows whose .NET major has no installed SDK are skipped, not failed, so the default .NET 10 run stays green
validate-workload-metadata.py new C5/C6 checks tying template/matrix .NET majors to KnownRuntimePack + RuntimeList.xml
test-version-band.sh new — asserts SDK version → feature band, and .sh/.ps1 parity
Makefile validate-metadata, test-version-band, aggregate check (no dotnet install needed)
build-matrix.yml non-blocking .NET 11 preview leg

version-map.json is deliberately not updated — it's a fallback cache of already published manifest versions, so an entry for an unreleased band would make the installer download a 404. Add it after the first release, as 10.0.300 was.

Validation performed

Built the workload against the real .NET 11 preview SDK (11.0.100-preview.7.26381.103):

  • Samsung.NET.Sdk.Tizen.Manifest-11.0.100-preview.7 packs with the correct id, installs into sdk-manifests/11.0.100-preview.7/
  • dotnet new tizen --framework net11.0 + dotnet build produces com.companyname.TizenApp1-1.0.0.tpk for both net11.0-tizen11.0 and net11.0-tizen10.0
  • net11.0-tizen11.0 verified to resolve Samsung.Tizen.Ref.API15/15.0.0.19396
  • make check: 6/6 metadata checks, 36/36 version-band assertions, install-script drift + integrity all green
  • C5/C6 confirmed by negative test (removing the net11 KnownRuntimePack / RuntimeList row fails the build)

Not run locally: Samsung.Tizen.Ref.API13/14/15 packing, which needs Tizen.NET.API* from Samsung's GitHub Packages feed (403 without org membership). CI has secrets.GITHUB_TOKEN for this. The published equivalents were substituted to complete the end-to-end run.

External blockers (not fixable here, not faked)

  1. Samsung.NET.Sdk.Tizen.Manifest-11.0.100-preview.7 is unpublished. Needs a Release Workload run with net_sdk_version = 11.0.100-preview.7.26381.103. Until then workload-install.sh finds no manifest on an 11.x SDK.
  2. Tizen.UIExtensions.NUI (Samsung/Tizen.UIExtensions) — published 0.9.2 ships lib/net6.0-tizen7.0 + lib/tizen10.0. TFM compatibility is fine; the blocker is its dependency group pinning Microsoft.Maui.Graphics 6.0.300-rc.3.1336. Needs a release with lib/net11.0-tizen11.0 built against API15 and refreshed MAUI Graphics deps.
  3. Tizen.UI.Components.Material 1.0.0-rc.8 — ships only lib/net8.0-tizen10.0, never GA. Unusable below tizen10.0; handled in the template as described above.

Details, owners and expected artifact names in workload/docs/net11.md.

Redth and others added 2 commits August 26, 2026 15:09
…ression

Both installers were committed truncated mid-statement and NUL-padded, so the
publicly curl'd installer could never complete. workload-install.sh ended at

    for DOTNET_SDK in $INSTALLED_DOTNET_SD

followed by 134 NUL bytes, and workload-install.ps1 ended inside its catch
block at `Write-Host `. The final lines are restored from the intact copies on
main.

validate-version-map.yml did not catch this because Generate-InstallScripts.ps1
only compares the auto-generated version-map block, and that block was
untouched, so it reported "OK" for a file missing its tail. The generator now
also verifies each installer contains no NUL bytes and ends with its expected
final statement, and fails otherwise.

Also restores the SDK enumeration fix that was lost in the same regression.
--update-all-workloads matched only `^6|^7`, silently ignoring every installed
.NET 8/9/10/11 SDK. It now matches majors 6-9 and any two-or-more digit major,
so future majors need no further edit.

Finally, extracts the SDK-version to feature-band computation into
compute_target_version_band() delimited by BEGIN/END VERSION BAND DETECTION
markers. Behaviour is unchanged - MANIFEST_NAME was already equal to the plain
band in the fall-through case - but the logic is now testable in isolation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Adds .NET 11 support to the tizen workload alongside .NET 10. The primary
target framework is net11.0-tizen11.0, which maps to TizenFX API level 15 and
the already-published Samsung.Tizen.Ref.API15 targeting pack. No new reference
or runtime pack is required: ref packs ship ref/net8.0 assemblies resolved by
explicit paths in FrameworkList.xml, so they are independent of the consuming
project's .NET version.

Workload changes:
* Versions.props: arcade 11.0.0-beta.26426.103 for 11.0 bands.
* NuGet.config: add the dotnet11 source, and clear inherited
  disabledPackageSources so a developer with nuget.org disabled machine-wide
  does not get a confusing NU1101 for a source this file already lists.
* Samsung.Tizen.Sdk.targets: add the net11.0 KnownRuntimePack. Without it the
  SDK cannot resolve Samsung.NETCore.App.Runtime.tizen (NETSDK1082).
* RuntimeList.xml: add the .NET Runtime 11 FileList row.
* template.json: offer net11.0; the default stays net10.0 because .NET 11 is
  still a preview SDK.
* TizenApp1.csproj: Tizen.UI.Components.Material ships assets for the tizen
  10.0 band only, so reference it conditionally on the resolved platform
  version and raise an actionable TIZENTMPL001 below that, instead of an
  opaque NU1101.

Verification:
* test-matrix.sh: add net11.0-tizen11.0 and net11.0-tizen10.0 rows. Rows whose
  .NET major has no installed SDK are now skipped rather than failed, so the
  default .NET 10 run stays green.
* validate-workload-metadata.py: new checks C5/C6 tying every .NET major
  offered by the template or exercised by the matrix to a KnownRuntimePack and
  a RuntimeList.xml row.
* test-version-band.sh: new test asserting the SDK version to feature band
  mapping (11.0.100-preview.7.26381.103 -> 11.0.100-preview.7) and that
  workload-install.sh and workload-install.ps1 agree.
* Makefile: add validate-metadata, test-version-band and an aggregate check
  target that need no dotnet install.
* build-matrix.yml: add a non-blocking .NET 11 preview leg.

Validated by building the workload against 11.0.100-preview.7.26381.103:
Samsung.NET.Sdk.Tizen.Manifest-11.0.100-preview.7 packs correctly, installs,
and `dotnet new tizen --framework net11.0` builds a .tpk for both
net11.0-tizen11.0 (resolving Samsung.Tizen.Ref.API15/15.0.0.19396) and
net11.0-tizen10.0.

version-map.json is deliberately not updated: it is a fallback cache of
already-published manifest versions, so an entry for an unreleased band would
make the installer download a 404. See workload/docs/net11.md for the mapping
and the external blockers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Redth

Redth commented Aug 26, 2026

Copy link
Copy Markdown
Author

Maintainer action required: approve fork workflows

GitHub created all required PR runs, but they are in action_required and can only be approved by a repository administrator:

Please use Approve and run workflows on these runs. Until then, the PR has no CI status even though the .NET 11 manifest pack/install/template/build/TPK chain was validated locally as described in the PR.

Code review:
* test-matrix.sh required an exact SDK/TFM major match, so the .NET 10 job skipped
  every net8/net9/net11 row and built nothing. An SDK builds its own major and all
  earlier ones, so rows are now skipped only when NEWER than the newest installed
  SDK. Pinned by a new `--self-test` mode that needs no dotnet install.
* build-matrix.yml made .NET 11 unconditionally advisory and build-workload.yml
  always used the Versions.props default. Both now switch on a net11.0 branch or a
  PR into one: the .NET 11 leg blocks and the workload builds against
  $(DotNet11SdkVersion), a new SSOT in Versions.props that the workflows grep.
  Check C7 fails if a workflow hardcodes a different .NET 11 SDK.
* The template read $(TargetPlatformVersion) in the project body, which the SDK has
  not yet inferred from the TFM at that point. net11.0-tizen9.0 therefore fell back
  to 10.0, pulled in an incompatible Tizen.UI.Components.Material and never raised
  TIZENTMPL001. The platform version is now parsed from $(TargetFramework), and the
  target re-checks the authoritative value. Verified end to end: tizen9.0 now errors
  with the real resolved version, tizen11.0 builds.
* Both installers swallowed per-SDK failures and exited 0 after printing DONE. They
  now track failures and exit non-zero; --update-all-workloads still visits the
  remaining SDKs but the overall run fails.

MSBuild review:
* workload-install.ps1 built its fallback prefix from a fixed length
  ($ManifestBaseName.Length + 2), so '...Manifest-11.0.100-preview.7' became
  '...Manifest-1' and matched the 10.x entries, installing a .NET 10 manifest into
  an 11.x band. Both installers now constrain the fallback to the same major.minor
  family and fail closed.
* DOTNET_VERSION was cached in .tmp/dotnet-version.config whose only prerequisite
  was Versions.props. The cache was always newer, so make never regenerated it and a
  newly-passed DOTNET_VERSION was ignored - silently building the previous band. It
  is now resolved immediately, and DOTNET_DESTDIR plus the install stamp are
  band-scoped.
* PackageTargetFallback now covers the full (.NET major x platform) cross-product.
  A missing entry makes FixupNuGetReferences leave a package on its netstandard2.x
  assets; net11.0-tizen11.0 was absent. Check C8 keeps it in sync with
  KnownRuntimePack x TizenSdkSupportedTargetPlatformVersion.
* release-workload.yml no longer builds with continue-on-error and no longer pushes
  a glob over whatever is on disk. It cleans first, fails on build error, stages to
  an isolated directory and verifies the expected manifest exists before pushing.
* test-version-band.sh now extracts the real Get-TargetVersionBand from
  workload-install.ps1 instead of reimplementing it, so sh/ps1 drift is actually
  detectable, and also checks Config.mk producer parity.
* Config.mk did not round the feature band for stable non-6 versions: 10.0.404
  produced band '10.0.404' while the installers looked for '10.0.400'. Fixed, with
  producer/consumer parity tests.
* MSI staging copied only Ref.API11/12/13; API14 and API15 were missing and API15 is
  the targeting pack for net11.0-tizen11.0. Now stages every Ref pack.
* workload-install.sh had its shebang below a comment block, so direct execution did
  not reliably use bash. Moved to the first line.
* make check now gates on pwsh with an actionable message instead of failing with
  'command not found'; SKIP_PWSH_CHECKS=1 opts out.

RuntimeList.xml (multiple root elements) is left as-is: proven not to be XML-parsed.
Replacing the installed pack's copy with non-XML text still builds a
net11.0-tizen11.0 project with an explicit RuntimeIdentifier - the path that resolves
runtime pack assets and the one MAUI takes. Documented in workload/docs/net11.md.

Validation on 11.0.100-preview.7.26381.103: full matrix 6/6 pass, 0 skipped
(net8.0-tizen10.0/10.1/11.0, net9.0-tizen10.0, net11.0-tizen11.0, net11.0-tizen10.0).
make check: C1-C8, 11 self-test, 61 version-band, 13 template-condition, 4
install-failure assertions, plus install-script drift and integrity.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Redth

Redth commented Aug 26, 2026

Copy link
Copy Markdown
Author

Review fixes pushed — 9cdce68

All four code-review findings and all ten MSBuild-review findings are addressed. One item (#14) is reported as provably non-applicable with evidence rather than changed.

Code review

# Fix
1 test-matrix.sh required an exact SDK/TFM major match, so the .NET 10 job skipped every net8/net9/net11 row and built nothing. Rows are now skipped only when newer than the newest installed SDK. New --self-test mode pins it with no dotnet install (11 assertions).
2 .NET 11 was unconditionally advisory and build-workload.yml always used the .NET 10 default. Both now switch on a net11.0 branch / PR-into-one: the leg blocks and the build uses $(DotNet11SdkVersion) — a new SSOT in Versions.props that the workflows grep. Check C7 fails if a workflow hardcodes a different version.
3 Confirmed and fixed. The template read $(TargetPlatformVersion) in the project body, before the SDK infers it from the TFM. Probe output was TPV='' resolved='10.0' material='True' for net11.0-tizen9.0 — exactly as reported. Now parsed from $(TargetFramework), with the target re-checking the authoritative value. Verified: net11.0-tizen9.0error TIZENTMPL001 ... (resolved TargetPlatformVersion: 9.0), net11.0-tizen11.0 builds. 13 evaluation regression tests added.
4 Both installers now track per-SDK failures and exit non-zero; --update-all-workloads still visits remaining SDKs but the run fails. 4 tests, including "must not print DONE on failure".

MSBuild review

# Fix
5 Fixed. $ManifestBaseName.Length + 2 truncated ...Manifest-11.0.100-preview.7 to ...Manifest-1, matching 10.x entries. Both installers now constrain fallback to the same major.minor family and fail closed. Parity-tested.
6 Root cause was deeper than paths: DOTNET_VERSION was cached in .tmp/dotnet-version.config whose only prerequisite was Versions.props. The cache was always newer, so make never regenerated it and a newly-passed DOTNET_VERSION was ignored. Now resolved immediately; DOTNET_DESTDIR and the install stamp are band-scoped. Band-switching in one tree is tested.
7 PackageTargetFallback now covers the full 30-entry (.NET major × platform) cross-product. Confirmed via FixupNuGetReferences: a missing entry leaves a package on its netstandard2.x assets — net11.0-tizen11.0 was absent. Check C8 keeps it in sync with KnownRuntimePack × TizenSdkSupportedTargetPlatformVersion.
8 release-workload.yml: no continue-on-error, make clean first, stage to an isolated dir, verify the expected manifest exists, push explicit staged paths. Band is computed by reusing the installer's own function so the release can't disagree with it.
9 test-version-band.sh now extracts the real Get-TargetVersionBand from workload-install.ps1 (same BEGIN/END markers as bash) instead of reimplementing it, so drift is genuinely detectable.
10 Confirmed: Config.mk did not round stable non-6 bands — 10.0.40410.0.404 while installers looked for 10.0.400. Fixed; producer/consumer parity now asserted across all 18 version cases.
11 MSI staging copied only Ref.API11/12/13. Now stages every Ref.API* — API15 is the targeting pack for net11.0-tizen11.0.
12 Shebang moved to line 1.
13 make check gates on pwsh with an actionable message; SKIP_PWSH_CHECKS=1 opts out.

#14RuntimeList.xml: proven not XML-parsed, left unchanged

The file does have multiple root elements. I checked the consumer contract empirically rather than assuming:

  1. Microsoft.NET.Build.Tasks.dll does contain RuntimeListNotFound / absoluteRuntimeListPath, so the SDK can read a runtime pack's RuntimeList.xml — a static grep alone would have been misleading.
  2. So I tested the path that actually resolves runtime pack assets: a net11.0-tizen11.0 build with an explicit RuntimeIdentifier=tizen-x86 (what MAUI takes via EnableImplicitRuntimeIdentifiers). Built clean.
  3. Decisive test: replaced the installed pack's RuntimeList.xml with the literal text <<< THIS IS NOT XML AT ALL &&& >>> and rebuilt the same RID-specific project → Build succeeded. 0 Error(s).

Samsung.NETCore.App.Runtime.tizen is a placeholder pack whose only payload is lib/net6.0-tizen/_._, so nothing reads the file. Making it well-formed would need a non-standard wrapper root or splitting the pack per .NET version — more risk than the malformed file carries while unread. C6 parses it line-wise, matching how it's produced. Documented in workload/docs/net11.md with the revisit criteria.

Validation on 11.0.100-preview.7.26381.103

Full matrix 6/6 pass, 0 skippednet8.0-tizen10.0, net8.0-tizen10.1, net8.0-tizen11.0, net9.0-tizen10.0, net11.0-tizen11.0, net11.0-tizen10.0.

make check: C1–C8, 11 self-test, 61 version-band (bash ↔ PowerShell ↔ Config.mk, fallback family, band isolation), 13 template-condition, 4 install-failure assertions, plus version-map drift and install-script integrity. Docs updated to describe the corrected behaviour.

Unrelated observation

tizen.myget.org now returns HTTP 401 to anonymous clients (.../api/v3/index.json). It remains a push target in build-workload.yml's deploy job. I have not touched it — removing a publishing destination is a maintainer call — but it's noted in workload/docs/net11.md in case any docs still point consumers there for restore.

@Redth

Redth commented Aug 26, 2026

Copy link
Copy Markdown
Author

Updated workflow approval request for head 9cdce68

The review-fix push created replacement runs, all currently action_required:

Please approve these newer runs; the earlier links target superseded head b847341.

@Redth

Redth commented Aug 27, 2026

Copy link
Copy Markdown
Author

Merge-readiness validation at head 9cdce68 (clean-tree re-run)

Re-validated from a fully cleaned tree. No code changes were needed — head is unchanged at 9cdce68 and the existing approval request still points at the current run IDs.

Manifest ID / version — .NET 11 supported, old bands unaffected

Built the manifest package for three bands from the clean tree:

DOTNET_VERSION Produced package
11.0.100-preview.7.26381.103 Samsung.NET.Sdk.Tizen.Manifest-11.0.100-preview.7.10.0.123.nupkg
10.0.100 Samsung.NET.Sdk.Tizen.Manifest-10.0.100.10.0.123.nupkg

The .NET 11 manifest declares Samsung.Tizen.Ref.API1515.0.0.19396, the targeting pack for net11.0-tizen11.0.

Diffed the 10.0 build against the actually-published Samsung.NET.Sdk.Tizen.Manifest-10.0.100 10.0.123 from nuget.org:

  • package id: identical
  • WorkloadManifest.targets: byte-identical
  • WorkloadManifest.json: differs only by the additive Samsung.Tizen.Ref.API14 / API15 pack entries — introduced by base-branch commit 44d7bdf, which predates this branch point. git diff 5e13077 HEAD -- .../WorkloadManifest.in.json is empty; this PR does not touch that file.

Feature-band change: proven non-regressive

The Config.mk rounding fix (finding #10) changes the manifest package ID, so I verified it against every one of the 37 bands in version-map.json, comparing the pre-change logic (reconstructed from base commit 5e13077) with the current one:

identical: 37   differing: 0

It differs only for non-round patch versions, where the new value is the correct one:

input old (producer) new (producer) installer (consumer) expects
9.0.304 9.0.304 9.0.300 9.0.300
10.0.404 10.0.404 10.0.400 10.0.400
8.0.421 8.0.421 8.0.400 8.0.400

End-to-end, both bands, one tree

Band dotnet workload list Matrix
11.0.100-preview.7 tizen 10.0.123/11.0.100-preview.7 6/6 pass, 0 skipped
10.0.100 tizen 10.0.123/10.0.100 4 pass, 0 fail, 2 skipped (net11 rows only)

The 10.0 run is the direct refutation of finding #1: net8/net9 rows now build on a .NET 10 SDK and only the genuinely-unbuildable net11 rows skip. Previously every row skipped and the job built nothing.

Both SDKs coexist under out/dotnet-10.0.100 and out/dotnet-11.0.100-preview.7, confirming the band-isolation fix (#6).

make check on the clean tree: C1–C8 plus 89 assertions (11 self-test, 61 version-band, 13 template-condition, 4 install-failure), version-map drift and install-script integrity — all green.

Pre-existing issue found (NOT introduced here, NOT fixed here)

The .NET 9 band cannot be built on this branch, independent of these changes:

error: Unable to find package Microsoft.DotNet.SharedFramework.Sdk with version (= 9.0.0-beta.25065.2)

Evidence it is pre-existing:

  • the pin was added by commit 86fcc19 (2025-11-19), long before this branch;
  • git diff 5e13077 HEAD -- workload/build/Versions.props shows my edits are purely additive (the 11.0 block + DotNet11SdkVersion) and do not touch the 9.0 pin;
  • 9.0.0-beta.25065.2 exists for Microsoft.DotNet.Arcade.Sdk but not for Microsoft.DotNet.SharedFramework.Sdk on dotnet-eng (nearest real versions present in both: 9.0.0-beta.25058.5, 9.0.0-beta.25077.4).

Only the 9.0 pin is affected — 8.0, 10.0 and 11.0 all resolve.

I have not changed it: it is outside this PR's scope, and I cannot validate a 9.0 pack-output comparison precisely because the band doesn't build today. Flagging it because one consequence of finding #8's fix is relevant: with continue-on-error removed from release-workload.yml, a release run for the 9.0 band will now fail loudly instead of silently proceeding to the push step. That is the intended behaviour, but it means this latent breakage becomes visible.

Remaining blocker

Only maintainer approval of the fork workflow runs. All three remain action_required at the run IDs listed in the previous comment; no new runs were created because the head did not change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant