-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add dotnetup preview release-strategy-plan.md
#54735
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
nagilson
wants to merge
18
commits into
dotnet:release/dnup
Choose a base branch
from
nagilson:nagilson-dotnetup-release-cycle
base: release/dnup
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+241
−0
Open
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
cd8e4b7
Add `dotnetup` `preview` `release-strategy-plan.md`
nagilson 31b2cf2
Add the very important requirement
nagilson 81ccd67
fix release plan typo
nagilson 9dd8e51
Add context that we might not be able to only support latest
nagilson 4db89cf
Consider that the method to bump the patch versions was bogus
nagilson 931f3e3
be more specific about the preview property
nagilson 59b67c2
caveat about tests for existing release repoint
nagilson 40066b2
Consider arcade rollout timing in plan
nagilson a95b65a
mention azdo task rollout timeframe
nagilson 40cc61e
Add retention investigation and GitHub Release compliance appendices
nagilson a26d366
compliance requirements should not be ai generated
nagilson 9072e7e
remove unneeded section on compliance
nagilson 0fb7716
Merge branch 'release/dnup' into nagilson-dotnetup-release-cycle
nagilson debfe51
remove sample yaml
nagilson f92e512
add a nice to have that we probably cant have
nagilson 960b831
Remove phase 4 for simplification
nagilson a6351b5
Simplify github releases appendix
nagilson a2ed00a
address copilot nits
nagilson File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
241 changes: 241 additions & 0 deletions
241
documentation/general/dotnetup/designs/dotnetup-release-strategy.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,241 @@ | ||
| # dotnetup `Preview` Release Strategy | ||
|
|
||
| `dotnetup` ships today as a small internal preview built daily from the tip of the internal CI pipeline. SDK `main` consumes that daily build. | ||
|
|
||
| The problem: every daily change reaches every CI consumer, so we cannot let an SDK servicing/release branch depend on a *stable* dotnetup without it being broken by an unrelated daily change once we remove the `.NET Install Script` fallback. | ||
|
|
||
| --- | ||
|
|
||
| ## 1. Requirements | ||
|
|
||
| ### Decisions: preview / phase 1 | ||
|
|
||
| **Must have** | ||
| - Allow others to download prior releases, even when unsupported (the intent is to let customers roll back without our intervention). Prior versions are downloadable today as immutable per-version `ci.dot.net` URLs; the underlying `dotnetbuilds` blob retention window has no formal retention policy for these artifacts, however. | ||
| - Easy rollback or re-release when something goes wrong. | ||
| - Develop features without risk of them reaching a stable release. | ||
| - Preview consumption / telemetry on a dev branch to confirm stability before promoting to stable. | ||
| - Only support 'latest' preview to reduce maintenance burden and move fast. | ||
| - Compliance with MSFT policy. | ||
|
|
||
| **Nice to have** | ||
| - No PRs required to bump minor versions. | ||
| - Automated changelog notes. | ||
| - Only maintain one branch at a time. | ||
| - Minimal manual maintenance effort burdens to release. | ||
|
|
||
| **Not necessary** | ||
| - Truly supporting multiple dotnetup versions simultaneously. | ||
| - Backporting. | ||
|
|
||
| ### Decisions: public / stable preview | ||
|
|
||
| **Additional must have** | ||
| - CDN routing for high-scale / geolocation downloads (`builds.dotnet.microsoft.com`). | ||
| (`ci.dot.net` likely cannot serve a large public download swath.) | ||
|
|
||
| **Additional nice to have** | ||
| - `dotnetup` inclusion in a `json` manifest (likely required for automatic updates). | ||
|
|
||
| --- | ||
|
|
||
| ## 2. Assumptions | ||
|
|
||
| - `ci.dot.net` could not scale to the full potential dotnetup customer base, even though it is fronted by Azure Front Door over blob storage. | ||
| - `stable` needs to scale beyond `ci.dot.net`; `preview` may not (external customers should not build production CI on top of a preview product). | ||
| - GitHub Releases may provide scalable / CDN-like downloads (works for dotnet diagnostics). | ||
| - `aka.ms` has no Azure Front Door / `x-cache` / Akamai layer of its own. It is a Kestrel app serving a `301` redirect, which is sufficient for `preview` and `daily`. | ||
| - `ci.dot.net` per-version build URLs persist long enough for `dotnetup` rollback needs. See [Retention investigation](#appendix-a-retention-investigation-dotnetbuildscidotnet) below. | ||
|
|
||
| ### Verified infrastructure facts | ||
|
|
||
| - The aka.ms daily links are `301` redirects served by **Kestrel** (no CDN of their own): | ||
|
|
||
| `https://aka.ms/dotnet/dotnetup/daily/dotnetup-win-x64.exe` → | ||
|
|
||
| ``` | ||
| https://ci.dot.net/public/dotnetup/0.1.4-preview.4.26303.1/dotnetup-win-x64.exe | ||
| ``` | ||
|
|
||
| `https://aka.ms/dotnet/dotnetup/daily/dotnetup-win-x64.exe.sha512` → | ||
|
|
||
|
|
||
| ``` | ||
| https://ci.dot.net/public-checksums/dotnetup/0.1.4-preview.4.26303.1/dotnetup-win-x64.exe.sha512 | ||
| ``` | ||
|
|
||
| - Both resolved explicit-version URLs return `200` (binary = 16,143,696 bytes; checksum = 128 bytes). | ||
| - `ci.dot.net` fronts `dotnetbuilds.blob.core.windows.net` via **Azure Front Door** | ||
| (`x-azure-ref` present, `X-Cache: TCP_MISS`, `Cache-Control: public, max-age=604800` = 7 days, | ||
| `x-ms-blob-type: BlockBlob`). dotnetup daily already lands here today. | ||
| - `builds.dotnet.microsoft.com` fronts `dotnetcli.blob.core.windows.net` via **Akamai** (`Akamai-GRN` present, no `x-azure-ref`). Reaching it requires a promotion (copy) from `dotnetbuilds` → `dotnetcli`, gated by the release team's staging process. The account→CDN mapping is encoded in Arcade's `PublishingConstants.cs`. | ||
|
|
||
| - dotnetup's Arcade channel, with `targetFeeds: DotNetToolsFeeds` publishes installers/checksums to `dotnetbuilds/public` and | ||
| `dotnetbuilds/public-checksums`. i.e. we are **already in staging**. | ||
|
|
||
| - The versioned blob layout `dotnetup/$(DotnetupVersion)/dotnetup-$(TargetRid)$(_DotnetupNativeExt)` | ||
| is set in [eng/Publishing.props](../../../../eng/Publishing.props) (`SetDotnetupBlobPaths`). | ||
|
|
||
| - The install scripts default to `Quality=daily` and resolve `https://aka.ms/dotnet/dotnetup/<quality>` | ||
| ([scripts/get-dotnetup.sh](../../../../scripts/get-dotnetup.sh), | ||
| [scripts/get-dotnetup.ps1](../../../../scripts/get-dotnetup.ps1)). | ||
|
|
||
| --- | ||
|
|
||
| ## 3. Comparisons | ||
|
|
||
| - **aspire** — owns its own download site (`aspire.dev`) plus npm, WinGet, other packages, and GitHub Releases. Includes rich channel identity (stable / staging / daily / local / pr), release branches, and SHA-derived staging feeds. Promotion is *manual*: the release pipeline is queued against a selected build, extracts its BAR ID, and runs `darc add-build-to-channel`. Product SemVer is hand-authored in `eng/Versions.props`, not auto-bumped. | ||
| ([release-process.md](https://github.com/microsoft/aspire/blob/main/docs/release-process.md)) | ||
| - **az cli** — `dev` branch is an `edge` build via `aka.ms`. Official uses WinGet, MSI, and ZIP (served from Microsoft-hosted blob storage behind `aka.ms` links) plus Microsoft package feeds. | ||
| ([docs](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?pivots=zip)) | ||
| - **gh cli** — WinGet, Homebrew, custom Linux package feed. **Stable releases only**; no daily/edge channel. "Build from source" is for contributors, not a distribution channel. | ||
|
|
||
| Takeaway: dotnetup's ideal is the *lighter half* of Aspire's model. i.e. Separate daily from a blessed selector with immutable versioned artifacts. | ||
|
|
||
| --- | ||
|
|
||
| ## 4. Versions Policy | ||
|
|
||
| | Channel | Version shape | Meaning | | ||
| |----------|---------------|---------| | ||
| | daily | `0.x.y` | Moving, as-is, built from active development tip. No stability promise. | | ||
| | preview | `0.x.y` | Blessed internal preview. The latest supported version. | | ||
| | stable | `1.0.0` | Public, CDN-scaled release (future). | | ||
|
|
||
| Explicit immutable version selectors remain downloadable for historical acquisition and rollback. | ||
| These are real, working URLs today — verified `200` on 2026-06-11, e.g.: | ||
|
|
||
| - `https://ci.dot.net/public/dotnetup/0.1.4-preview.4.26303.1/dotnetup-win-x64.exe` | ||
| - `https://ci.dot.net/public-checksums/dotnetup/0.1.4-preview.4.26303.1/dotnetup-win-x64.exe.sha512` | ||
|
|
||
|
|
||
| --- | ||
|
|
||
| ## 5. Plan (phased) | ||
|
|
||
| ### Phase 0 — Current | ||
|
|
||
| Daily channel available. `aka.ms/dotnet/dotnetup/daily/...` points at the latest published daily | ||
| build on `ci.dot.net`. SDK `main` consumes daily. No tags, no GitHub Release, no blessed selector. | ||
| The dotnetup CI pipeline ([.vsts-dnup-ci.yml](../../../../.vsts-dnup-ci.yml)) triggers on the | ||
| `dnup`, `release/dnup`, and `release/dotnetup` branches today. | ||
|
|
||
| ### Phase 1 — Blessed `preview` selector | ||
|
|
||
| 1. **Maintain one branch: `release/dnup`.** | ||
| 2. **Expose both `/daily/` and `/preview/` URLs.** Daily keeps tracking the moving tip; preview resolves to a 'blessed' build. (But still not 'blessed' to actually tell external customers to use in production.) | ||
| 3. **Change which `/daily/` build `/preview/` points at via an explicit process** | ||
| Implement a `release` pipeline that lets an operator select a set of dotnetup release artifacts from a prior daily pipeline run. | ||
| 4. **The release pipeline:** | ||
| - Bumps the patch version by 1 off of the last tagged preview patch version using global `msbuild` parameters. Coordinate to push a PR via maestro or via actions that bumps the version in the real branch. Produce the preview versioned dotnetup `tag`. | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recognize this happens via a vendor in the SDK and we could utilize that strategy instead of trying to be fancy. It does make me very sad we need PRs to bump the patch number. |
||
| - Pushes that tag onto the commit from the selected daily pipeline run. | ||
| - Sets `preview` version metadata property `PreReleaseVersionLabel` as a global property override using the same methodology as the .NET SDK. | ||
| - Runs tests on that branch. | ||
| - On pass: repins the `/preview/` `aka.ms` url (only if `test` run is not enabled), and creates the GitHub Release with change notes. | ||
|
nagilson marked this conversation as resolved.
|
||
|
|
||
| **Recovery — if only a simple revert is needed:** | ||
| 1. Re-run the `release` pipeline against an existing tag and repoint the `/preview/` URL. Allow skipping tests if needed (break-glass.) | ||
| Archival CI URLs exist per version and are confirmed live today, e.g. | ||
| `https://ci.dot.net/public/dotnetup/0.1.4-preview.4.26303.1/dotnetup-win-x64.exe` and its | ||
| `.../public-checksums/dotnetup/0.1.4-preview.4.26303.1/dotnetup-win-x64.exe.sha512` sidecar. | ||
| **Open (low risk):** No formal retention/TTL policy is documented for `dotnetbuilds` blobs — see | ||
| [Retention investigation](#appendix-a-retention-investigation-dotnetbuildscidotnet). Empirical evidence shows | ||
| non-promoted preview builds from 4+ years ago remain accessible, and dotnetup builds are never | ||
| subject to promotion-cleanup. We consider the rollback-via-repoint strategy safe for practical | ||
| timescales, though confirming definitively requires Azure portal access from dnceng. | ||
|
|
||
| **Recovery — fix needed (e.g. security patch on an old branch):** | ||
| 1. Check out the tagged commit. | ||
| 2. Create `release/dnup/<tag-version>/hotfix-x.y.z` off the tag. | ||
| 3. Open an internal PR with the fix into that branch and get approval. | ||
| 4. Run the release pipeline (which runs tests) and repoint the selector. | ||
|
|
||
| This phase allows a public preview. I view arcade rollout as valid around this time once we see stabilization of the public preview, but also potential arcade rollout with a fallback during `preview`. | ||
|
|
||
| In this phase, before public preview we'd remove the fallback to the .NET Install Script, but keep the fallback on the `daily` dotnetup builds, and keep `release/dnup` using the `daily` dotnetup builds to build. (This prevents a broken `dotnetup` from preventing us from shipping a new `dotnetup`.) | ||
|
|
||
| ### Phase 2 — Stable on `builds.dotnet.microsoft.com` (tentative) | ||
|
|
||
| Migrate to `stable` versioning as well. Confirm whether it is actually feasible and correct to only support a latest version if it becomes a 'released' product. | ||
|
|
||
| Host a `stable` URL on `builds.dotnet.microsoft.com` by coordinating with the release team to use their promotion pipeline — we already push to `dotnetbuilds`, so this is a copy/promote from | ||
|
nagilson marked this conversation as resolved.
|
||
| `dotnetbuilds` → `dotnetcli` plus storage write permissions granted by the release/dnceng team. | ||
|
|
||
| Similar release process, through coordination. Possibly automate `preview` releases at this point. Required to rollout to any azdo task. | ||
|
|
||
| ### Phase 3 — Package-manager acquisition (tentative) | ||
|
|
||
| Linux Package Manager Feed / WinGet / Homebrew / etc. Needs discussion with partners. | ||
|
|
||
| --- | ||
|
|
||
| ## Appendix A: Retention Investigation (`dotnetbuilds`/`ci.dot.net`) | ||
|
|
||
| *Investigated 2026-06-12.* | ||
|
|
||
| ### Summary | ||
|
|
||
| There is **no documented retention policy** for `dotnetbuilds.blob.core.windows.net` / `ci.dot.net`. | ||
| Arcade's `PublishingConstants.cs` `TargetChannelConfig` has no `retentionDays`, `expirationDays`, or | ||
| `lifecyclePolicy` field. No retention documentation exists in `dotnet/arcade` or `dotnet/dnceng`. | ||
| Any Azure Blob lifecycle policy would be configured in the Azure portal (not in public repos). | ||
|
|
||
| ### Empirical HTTP probe results (2026-06-12) | ||
|
|
||
| | Build | Age | `ci.dot.net` | `builds.dotnet.microsoft.com` | Explanation | | ||
| |-------|-----|:---:|:---:|---| | ||
| | .NET 6.0 preview 1 (Mar 2021) | ~5 yr | ❌ 404 | ✅ 200 | **Promoted** to dotnetcli, cleaned from dotnetbuilds | | ||
| | .NET 6.0 preview 7 (Aug 2021) | ~5 yr | ❌ 404 | ✅ 200 | Promoted | | ||
| | .NET 7.0 preview 1 (Feb 2022) | ~4.3 yr | ✅ 200 | — | Never promoted; still on staging | | ||
| | .NET 7.0 preview 3–7 (Mar–Jul 2022) | ~4 yr | ✅ 200 | — | Never promoted | | ||
| | .NET 7.0 RC1/RC2 (Sep–Oct 2022) | ~4 yr | ❌ 404 | ✅ 200 | Promoted | | ||
| | .NET 7.0 GA (Nov 2022) | ~4 yr | ❌ 404 | ✅ 200 | Promoted | | ||
| | .NET 8.0 preview 1 (Feb 2023) | ~3.3 yr | ✅ 200 | — | Never promoted | | ||
| | .NET 9.0 preview 1 (Feb 2024) | ~2.3 yr | ✅ 200 | — | Never promoted | | ||
| | dotnetup 0.1.4-preview (Jun 2026) | current | ✅ 200 | — | DotNetToolsFeeds; never promoted | | ||
|
|
||
| ### Interpretation | ||
|
|
||
| The 404s on `ci.dot.net` are **not** from age-based TTL deletion. They are the result of a | ||
| deliberate **promotion workflow**: once a build graduates from staging (`dotnetbuilds`) to production | ||
| (`dotnetcli` / `builds.dotnet.microsoft.com`), the staging copy is cleaned up. | ||
|
|
||
| Since dotnetup uses `DotNetToolsFeeds` (which only targets `dotnetbuilds/public`), its builds are | ||
| **never subject to promotion-cleanup**. Non-promoted preview/daily builds from as far back as | ||
| Feb 2022 (~4.3 years) remain accessible at this time. | ||
|
|
||
| ### Conclusion for dotnetup rollback | ||
|
|
||
| We consider the rollback-via-repoint strategy (pointing `/preview/` at an older versioned URL) safe | ||
| for practical timescales. The risk of silent blob deletion is low but cannot be formally ruled out | ||
| without Azure portal access from the dnceng team. | ||
|
|
||
| --- | ||
|
|
||
| ## Appendix B: Automated GitHub Releases | ||
|
|
||
| Automated GitHub Release creation from CI is compliant with Microsoft policy and is established | ||
| practice across the dotnet org. Arcade does not provide a shared release stage; each repo | ||
| implements its own using one of the patterns below. | ||
|
|
||
| ### Precedent in the dotnet org | ||
|
|
||
| | Repo | Pattern | Auth | Human gate | | ||
| |---|---|---|---| | ||
| | dotnet/aspire | AzDO dispatches GitHub Actions via `aspire-repo-bot` App | GitHub App token | AzDO approval stage | | ||
| | dotnet/dotnet-monitor | AzDO pipeline runs `gh release create` | KeyVault-backed `dotnet-bot` PAT | `ManualValidation@1` | | ||
| | dotnet/android-native-tools | AzDO `GitHubRelease@1` task | AzDO service connection | `ManualValidation@0` | | ||
| | cli/cli | GitHub Actions `workflow_dispatch` | `GITHUB_TOKEN` | `production` environment approval | | ||
| | microsoft/mcp | AzDO job runs `gh release create` + upload | GitHub App token | Pipeline stage gate | | ||
|
|
||
| ### dotnetup approach | ||
|
|
||
| dotnetup uses the `dotnet-monitor` pattern: an AzDO pipeline stage runs `gh release create --draft` | ||
| with a KeyVault-backed PAT, gated by `ManualValidation@1`. | ||
|
|
||
| - No GitHub App or cross-system dispatch to set up — a single pipeline stage on existing 1ES/dnceng | ||
| infrastructure. | ||
| - `--draft` ensures a release is never published without a manual confirmation on GitHub. | ||
| - `ManualValidation@1` runs on a `pool: server` job with no agent cost. | ||
| - For `preview`, the manual gate may be dropped since the channel is internal, reducing release to a | ||
| single pipeline run. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.