Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
[CmdletBinding()]
|
|
|
|
|
param(
|
|
|
|
|
[AllowEmptyString()]
|
|
|
|
|
[string]$VersionOverride = "",
|
|
|
|
|
|
feat(release): automate draft preview release preparation (#49797)
## Summary of the Pull Request
Adds a `Prepare Preview Release` custom agent that autonomously turns a
successful PowerToys Azure DevOps release-candidate build into a
complete GitHub draft prerelease for final human review.
The implementation extends the existing `release-note-generation` skill
instead of duplicating it. It adds exact-build metadata resolution,
published-release baseline selection, semantic PR deltas across `main`
and `stable`, release asset validation, idempotent draft-only release
updates, and final draft verification.
## PR Checklist
- [x] **Communication:** The autonomous preview-release design was
reviewed and approved before implementation
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** N/A; no end-user-facing strings were added
- [x] **Dev docs:** Added preview scenario, delta, draft safety, and
reporting references
## Detailed Description of the Pull Request / Additional comments
- Adds `.github/agents/prepare-preview-release.agent.md` with a
no-mid-run-decision workflow and a strict prohibition on publishing
releases.
- Extends `.github/skills/release-note-generation/SKILL.md` with
stable/preview scenario routing while preserving the existing
stable-release workflow.
- Adds canonical scripts under
`.github/skills/release-note-generation/scripts/` to:
- Resolve and validate ADO build metadata.
- Select the latest published stable or preview baseline before build
queue time.
- Calculate same-lineage or branch-transition PR deltas using PR
numbers, cherry-pick provenance, and patch-ID equivalence.
- Collect normalized PR metadata and create `release-manifest.json`.
- Download and validate installers, symbols, and GPO assets, including
hashes, signatures, and ZIP contents.
- Create or update draft prereleases while preserving human text outside
managed markers.
- Verify draft flags, immutable target commit, body markers, and
uploaded assets.
- Updates `.pipelines/resolveBuildMetadata.ps1` and
`.pipelines/v2/release.yml` with explicit `auto`, `preview-release`, and
`stable-release` intent handling so preview candidates can be built from
either `main` or `stable`.
- Adds `.pipelines/writeReleaseMetadata.ps1` so each signed build
artifact records its resolved version, channel, intent, source branch,
and immutable source commit.
- Keeps release publication outside the agent: the automation can only
create or update a draft prerelease.
## Validation Steps Performed
- `Invoke-Pester` for:
- `.pipelines/tests/resolveBuildMetadata.Tests.ps1`
- `.pipelines/tests/writeReleaseMetadata.Tests.ps1`
-
`.github/skills/release-note-generation/tests/preview-release.Tests.ps1`
- 37 tests passed, covering stable-branch preview intent, metadata
contracts, baseline selection, same-lineage and branch-transition
deltas, patch-ID equivalence, managed-body preservation, and
published-release refusal.
- Parsed all added or modified PowerShell scripts with the PowerShell
AST parser.
- Parsed the modified pipeline YAML files with `ConvertFrom-Yaml`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
Copilot-Session: e9f79ac2-9a7b-4083-834c-0d87e8c83bfd
Copilot-Session: 1ecea747-b313-49a1-9969-543c01ba1be8
2026-08-17 14:47:18 +08:00
|
|
|
[ValidateSet("auto", "preview-release", "stable-release")]
|
|
|
|
|
[string]$ReleaseIntent = "auto",
|
|
|
|
|
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
[string]$SourceBranch = $env:BUILD_SOURCEBRANCH,
|
|
|
|
|
|
|
|
|
|
[string]$BuildReason = $env:BUILD_REASON,
|
|
|
|
|
|
|
|
|
|
[string]$BuildNumber = $env:BUILD_BUILDNUMBER,
|
|
|
|
|
|
|
|
|
|
[AllowEmptyString()]
|
|
|
|
|
[string]$BuildDate = "",
|
|
|
|
|
|
|
|
|
|
[AllowEmptyString()]
|
|
|
|
|
[string]$DailyVersionSequence = "",
|
|
|
|
|
|
|
|
|
|
[string]$VersionPropsPath = (Join-Path $PSScriptRoot "..\src\Version.props")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
|
|
2026-08-07 15:34:29 +08:00
|
|
|
$VersionOverride = $VersionOverride.Trim()
|
|
|
|
|
if ($VersionOverride.Equals("auto", [StringComparison]::OrdinalIgnoreCase)) {
|
|
|
|
|
$VersionOverride = ""
|
|
|
|
|
}
|
|
|
|
|
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
function Get-BuildStamp {
|
|
|
|
|
param([string]$PipelineBuildNumber)
|
|
|
|
|
|
|
|
|
|
if ([string]::IsNullOrWhiteSpace($PipelineBuildNumber)) {
|
|
|
|
|
$now = Get-Date
|
|
|
|
|
return [pscustomobject]@{
|
|
|
|
|
Date = $now.Date
|
|
|
|
|
Revision = 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($PipelineBuildNumber -notmatch "_(?<yearMonth>\d{4})\.(?<day>\d{2})(?<revision>\d{3})(?:-.+)?$") {
|
|
|
|
|
throw "Build number '$PipelineBuildNumber' does not end with the expected _YYMM.DDNNN pattern"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$date = [datetime]::ParseExact(
|
|
|
|
|
"20$($matches["yearMonth"])$($matches["day"])",
|
|
|
|
|
"yyyyMMdd",
|
|
|
|
|
[Globalization.CultureInfo]::InvariantCulture)
|
|
|
|
|
}
|
|
|
|
|
catch {
|
|
|
|
|
throw "Build number '$PipelineBuildNumber' contains an invalid date"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$revision = [int]::Parse($matches["revision"])
|
|
|
|
|
if ($revision -lt 1 -or $revision -gt 99) {
|
|
|
|
|
throw "Build number '$PipelineBuildNumber' has daily revision '$revision'; canonical versions support revisions 001 through 099"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [pscustomobject]@{
|
|
|
|
|
Date = $date
|
|
|
|
|
Revision = $revision
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Test-VersionParts {
|
|
|
|
|
param([Parameter(Mandatory)][string[]]$Parts)
|
|
|
|
|
|
|
|
|
|
foreach ($part in $Parts) {
|
|
|
|
|
$value = [int]::Parse($part)
|
|
|
|
|
if ($value -lt 0 -or $value -gt [UInt16]::MaxValue) {
|
|
|
|
|
throw "Version component '$value' is outside the supported Windows version range 0-65535"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-VersionDate {
|
|
|
|
|
param(
|
|
|
|
|
[AllowEmptyString()][string]$DateOverride,
|
|
|
|
|
[Parameter(Mandatory)]$BuildStamp
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if ([string]::IsNullOrWhiteSpace($DateOverride)) {
|
|
|
|
|
return $BuildStamp.Date
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return [datetime]::ParseExact(
|
|
|
|
|
$DateOverride,
|
|
|
|
|
"yyyyMMdd",
|
|
|
|
|
[Globalization.CultureInfo]::InvariantCulture)
|
|
|
|
|
}
|
|
|
|
|
catch {
|
|
|
|
|
throw "Build date '$DateOverride' must use the yyyyMMdd format"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-ReleaseTrainMetadata {
|
|
|
|
|
param([Parameter(Mandatory)][string]$Path)
|
|
|
|
|
|
|
|
|
|
[xml]$versionProps = Get-Content -LiteralPath $Path
|
|
|
|
|
$releaseTrain = [string]$versionProps.Project.PropertyGroup.ReleaseTrainVersion
|
|
|
|
|
if ($releaseTrain -notmatch "^(?<major>\d+)\.(?<minor>\d+)$") {
|
|
|
|
|
throw "ReleaseTrainVersion in '$Path' must use the major.minor format"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Test-VersionParts -Parts @($matches["major"], $matches["minor"])
|
|
|
|
|
if ([int]::Parse($matches["major"]) -gt 255 -or [int]::Parse($matches["minor"]) -gt 255) {
|
|
|
|
|
throw "ReleaseTrainVersion in '$Path' must keep major and minor within the MSI-supported range 0-255"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$epochText = [string]$versionProps.Project.PropertyGroup.ReleaseTrainEpoch
|
|
|
|
|
try {
|
|
|
|
|
$epoch = [datetime]::ParseExact(
|
|
|
|
|
$epochText,
|
|
|
|
|
"yyyy-MM-dd",
|
|
|
|
|
[Globalization.CultureInfo]::InvariantCulture)
|
|
|
|
|
}
|
|
|
|
|
catch {
|
|
|
|
|
throw "ReleaseTrainEpoch in '$Path' must use the yyyy-MM-dd format"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($epoch.Month -ne 1 -or $epoch.Day -ne 1) {
|
|
|
|
|
throw "ReleaseTrainEpoch in '$Path' must be January 1 of the active epoch year"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [pscustomobject]@{
|
|
|
|
|
Version = $releaseTrain
|
|
|
|
|
Epoch = $epoch
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-ReleaseVersion {
|
|
|
|
|
param(
|
|
|
|
|
[Parameter(Mandatory)][string]$ReleaseTrain,
|
|
|
|
|
[Parameter(Mandatory)][datetime]$Epoch,
|
|
|
|
|
[Parameter(Mandatory)]$BuildStamp,
|
|
|
|
|
[Parameter(Mandatory)][int]$DailySequence
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if ($BuildStamp.Date -lt $Epoch) {
|
|
|
|
|
throw "Build date '$($BuildStamp.Date.ToString("yyyy-MM-dd"))' is before ReleaseTrainEpoch '$($Epoch.ToString("yyyy-MM-dd"))'"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($DailySequence -lt 1 -or $DailySequence -gt 9) {
|
|
|
|
|
throw "Daily release sequence '$DailySequence' is outside the YDDDB-supported range 1-9"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$yearOffset = $BuildStamp.Date.Year - $Epoch.Year
|
|
|
|
|
if ($yearOffset -gt 6) {
|
|
|
|
|
throw "Release train year offset '$yearOffset' exceeds the MSI-safe YDDDB range 0-6; advance the release train and reset ReleaseTrainEpoch"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$thirdComponentText = "{0}{1:D3}{2}" -f $yearOffset, $BuildStamp.Date.DayOfYear, $DailySequence
|
|
|
|
|
$thirdComponent = [int]::Parse($thirdComponentText)
|
|
|
|
|
if ($thirdComponent -gt [UInt16]::MaxValue) {
|
|
|
|
|
throw "Generated version component '$thirdComponent' exceeds 65535; advance the release train and reset ReleaseTrainEpoch"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "$ReleaseTrain.$thirdComponent.0"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-PrivateVersion {
|
|
|
|
|
param(
|
|
|
|
|
[Parameter(Mandatory)][datetime]$Epoch,
|
|
|
|
|
[Parameter(Mandatory)]$BuildStamp
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$extendedDay = ($BuildStamp.Date - $Epoch).Days + 1
|
|
|
|
|
if ($extendedDay -lt 1) {
|
|
|
|
|
throw "Build date '$($BuildStamp.Date.ToString("yyyy-MM-dd"))' is before ReleaseTrainEpoch '$($Epoch.ToString("yyyy-MM-dd"))'"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$thirdComponent = ($extendedDay * 100) + $BuildStamp.Revision
|
|
|
|
|
if ($thirdComponent -gt [UInt16]::MaxValue) {
|
|
|
|
|
throw "Generated private version component '$thirdComponent' exceeds 65535"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "0.0.$thirdComponent.0"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-ReleaseDailySequence {
|
|
|
|
|
param([AllowEmptyString()][string]$Sequence)
|
|
|
|
|
|
|
|
|
|
if ([string]::IsNullOrWhiteSpace($Sequence)) {
|
|
|
|
|
throw "DailyVersionSequence is required for main and stable builds"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($Sequence -notmatch "^\d+$") {
|
|
|
|
|
throw "Daily release sequence '$Sequence' must be numeric"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [int]::Parse($Sequence)
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-07 15:34:29 +08:00
|
|
|
function Get-AutomaticReleaseVersion {
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
param(
|
|
|
|
|
[Parameter(Mandatory)][string]$ReleaseTrain,
|
2026-08-07 15:34:29 +08:00
|
|
|
[Parameter(Mandatory)][datetime]$Epoch,
|
|
|
|
|
[Parameter(Mandatory)]$BuildStamp,
|
|
|
|
|
[Parameter(Mandatory)][AllowEmptyString()][string]$DateOverride,
|
|
|
|
|
[Parameter(Mandatory)][AllowEmptyString()][string]$DailySequence
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$releaseBuildStamp = [pscustomobject]@{
|
|
|
|
|
Date = Get-VersionDate -DateOverride $DateOverride -BuildStamp $BuildStamp
|
|
|
|
|
Revision = $BuildStamp.Revision
|
|
|
|
|
}
|
|
|
|
|
$releaseDailySequence = Get-ReleaseDailySequence -Sequence $DailySequence
|
|
|
|
|
return Get-ReleaseVersion -ReleaseTrain $ReleaseTrain -Epoch $Epoch -BuildStamp $releaseBuildStamp -DailySequence $releaseDailySequence
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-PreviewVersionOverride {
|
|
|
|
|
param(
|
|
|
|
|
[Parameter(Mandatory)][string]$ReleaseTrain,
|
|
|
|
|
[AllowEmptyString()][string]$Override
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$inputVersion = $Override.Trim()
|
|
|
|
|
if ($inputVersion.EndsWith("-preview", [StringComparison]::OrdinalIgnoreCase)) {
|
|
|
|
|
$inputVersion = $inputVersion.Substring(0, $inputVersion.Length - "-preview".Length)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([string]::IsNullOrWhiteSpace($inputVersion)) {
|
2026-08-07 15:34:29 +08:00
|
|
|
return $null
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($inputVersion -match "^(?<major>\d+)\.(?<minor>\d+)$") {
|
|
|
|
|
if ($inputVersion -ne $ReleaseTrain) {
|
|
|
|
|
throw "Preview version base '$inputVersion' does not match ReleaseTrainVersion '$ReleaseTrain'"
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-07 15:34:29 +08:00
|
|
|
return $null
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($inputVersion -notmatch "^(?<major>\d+)\.(?<minor>\d+)\.(?<revision>\d+)\.(?<build>\d+)$") {
|
|
|
|
|
throw "Preview version override must be major.minor or major.minor.YDDDB.0, optionally followed by -preview"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ("$($matches["major"]).$($matches["minor"])" -ne $ReleaseTrain) {
|
|
|
|
|
throw "Preview version '$inputVersion' does not match ReleaseTrainVersion '$ReleaseTrain'"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([int]::Parse($matches["build"]) -ne 0) {
|
|
|
|
|
throw "Preview version '$inputVersion' must use 0 for the fourth component"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Test-VersionParts -Parts @($matches["major"], $matches["minor"], $matches["revision"], $matches["build"])
|
|
|
|
|
$parts = @($matches["major"], $matches["minor"], $matches["revision"], $matches["build"])
|
|
|
|
|
return ($parts | ForEach-Object { [int]::Parse($_) }) -join "."
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-MsiSafeVersionOverride {
|
|
|
|
|
param(
|
|
|
|
|
[Parameter(Mandatory)][string]$Override,
|
|
|
|
|
[Parameter(Mandatory)][string]$VersionKind
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$inputVersion = $Override.Trim()
|
|
|
|
|
if ($inputVersion -notmatch "^(?<major>\d+)\.(?<minor>\d+)\.(?<revision>\d+)(?:\.(?<build>\d+))?$") {
|
|
|
|
|
throw "$VersionKind version override must be numeric major.minor.patch or major.minor.patch.build"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$parts = @($matches["major"], $matches["minor"], $matches["revision"])
|
|
|
|
|
if ($matches["build"]) {
|
|
|
|
|
$parts += $matches["build"]
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$parts += "0"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Test-VersionParts -Parts $parts
|
|
|
|
|
if ([int]::Parse($parts[0]) -gt 255 -or [int]::Parse($parts[1]) -gt 255) {
|
|
|
|
|
throw "$VersionKind version '$inputVersion' must keep major and minor within the MSI-supported range 0-255"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([int]::Parse($parts[3]) -ne 0) {
|
|
|
|
|
throw "$VersionKind version '$inputVersion' must use 0 for the fourth component"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ($parts | ForEach-Object { [int]::Parse($_) }) -join "."
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-07 15:34:29 +08:00
|
|
|
function Get-StableVersionOverride {
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
param(
|
2026-08-07 15:34:29 +08:00
|
|
|
[Parameter(Mandatory)][AllowEmptyString()][string]$Override
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if ([string]::IsNullOrWhiteSpace($Override)) {
|
2026-08-07 15:34:29 +08:00
|
|
|
return $null
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Get-MsiSafeVersionOverride -Override $Override -VersionKind "Stable"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$isMain = $SourceBranch -eq "refs/heads/main"
|
|
|
|
|
$isStable = $SourceBranch -eq "refs/heads/stable"
|
|
|
|
|
$isScheduled = $BuildReason -eq "Schedule"
|
|
|
|
|
|
feat(release): automate draft preview release preparation (#49797)
## Summary of the Pull Request
Adds a `Prepare Preview Release` custom agent that autonomously turns a
successful PowerToys Azure DevOps release-candidate build into a
complete GitHub draft prerelease for final human review.
The implementation extends the existing `release-note-generation` skill
instead of duplicating it. It adds exact-build metadata resolution,
published-release baseline selection, semantic PR deltas across `main`
and `stable`, release asset validation, idempotent draft-only release
updates, and final draft verification.
## PR Checklist
- [x] **Communication:** The autonomous preview-release design was
reviewed and approved before implementation
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** N/A; no end-user-facing strings were added
- [x] **Dev docs:** Added preview scenario, delta, draft safety, and
reporting references
## Detailed Description of the Pull Request / Additional comments
- Adds `.github/agents/prepare-preview-release.agent.md` with a
no-mid-run-decision workflow and a strict prohibition on publishing
releases.
- Extends `.github/skills/release-note-generation/SKILL.md` with
stable/preview scenario routing while preserving the existing
stable-release workflow.
- Adds canonical scripts under
`.github/skills/release-note-generation/scripts/` to:
- Resolve and validate ADO build metadata.
- Select the latest published stable or preview baseline before build
queue time.
- Calculate same-lineage or branch-transition PR deltas using PR
numbers, cherry-pick provenance, and patch-ID equivalence.
- Collect normalized PR metadata and create `release-manifest.json`.
- Download and validate installers, symbols, and GPO assets, including
hashes, signatures, and ZIP contents.
- Create or update draft prereleases while preserving human text outside
managed markers.
- Verify draft flags, immutable target commit, body markers, and
uploaded assets.
- Updates `.pipelines/resolveBuildMetadata.ps1` and
`.pipelines/v2/release.yml` with explicit `auto`, `preview-release`, and
`stable-release` intent handling so preview candidates can be built from
either `main` or `stable`.
- Adds `.pipelines/writeReleaseMetadata.ps1` so each signed build
artifact records its resolved version, channel, intent, source branch,
and immutable source commit.
- Keeps release publication outside the agent: the automation can only
create or update a draft prerelease.
## Validation Steps Performed
- `Invoke-Pester` for:
- `.pipelines/tests/resolveBuildMetadata.Tests.ps1`
- `.pipelines/tests/writeReleaseMetadata.Tests.ps1`
-
`.github/skills/release-note-generation/tests/preview-release.Tests.ps1`
- 37 tests passed, covering stable-branch preview intent, metadata
contracts, baseline selection, same-lineage and branch-transition
deltas, patch-ID equivalence, managed-body preservation, and
published-release refusal.
- Parsed all added or modified PowerShell scripts with the PowerShell
AST parser.
- Parsed the modified pipeline YAML files with `ConvertFrom-Yaml`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
Copilot-Session: e9f79ac2-9a7b-4083-834c-0d87e8c83bfd
Copilot-Session: 1ecea747-b313-49a1-9969-543c01ba1be8
2026-08-17 14:47:18 +08:00
|
|
|
if ($ReleaseIntent -eq "stable-release" -and -not $isStable) {
|
|
|
|
|
throw "Stable release intent is only supported from refs/heads/stable"
|
|
|
|
|
}
|
|
|
|
|
if ($ReleaseIntent -eq "preview-release" -and -not ($isMain -or $isStable)) {
|
|
|
|
|
throw "Preview release intent is only supported from refs/heads/main or refs/heads/stable"
|
|
|
|
|
}
|
|
|
|
|
if ($isScheduled -and $isStable -and $ReleaseIntent -ne "preview-release") {
|
|
|
|
|
throw "Scheduled stable builds must explicitly use preview-release intent"
|
|
|
|
|
}
|
|
|
|
|
if ($isScheduled -and -not ($isMain -or $isStable)) {
|
|
|
|
|
throw "Scheduled release builds are only supported from refs/heads/main or refs/heads/stable"
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$releaseMetadata = Get-ReleaseTrainMetadata -Path $VersionPropsPath
|
|
|
|
|
$releaseTrain = $releaseMetadata.Version
|
|
|
|
|
$buildStamp = Get-BuildStamp -PipelineBuildNumber $BuildNumber
|
|
|
|
|
|
|
|
|
|
if ($isMain) {
|
|
|
|
|
if ($isScheduled -and -not [string]::IsNullOrWhiteSpace($VersionOverride)) {
|
|
|
|
|
throw "Scheduled main builds must use the checked-in ReleaseTrainVersion and cannot specify a version override"
|
|
|
|
|
}
|
|
|
|
|
|
feat(release): automate draft preview release preparation (#49797)
## Summary of the Pull Request
Adds a `Prepare Preview Release` custom agent that autonomously turns a
successful PowerToys Azure DevOps release-candidate build into a
complete GitHub draft prerelease for final human review.
The implementation extends the existing `release-note-generation` skill
instead of duplicating it. It adds exact-build metadata resolution,
published-release baseline selection, semantic PR deltas across `main`
and `stable`, release asset validation, idempotent draft-only release
updates, and final draft verification.
## PR Checklist
- [x] **Communication:** The autonomous preview-release design was
reviewed and approved before implementation
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** N/A; no end-user-facing strings were added
- [x] **Dev docs:** Added preview scenario, delta, draft safety, and
reporting references
## Detailed Description of the Pull Request / Additional comments
- Adds `.github/agents/prepare-preview-release.agent.md` with a
no-mid-run-decision workflow and a strict prohibition on publishing
releases.
- Extends `.github/skills/release-note-generation/SKILL.md` with
stable/preview scenario routing while preserving the existing
stable-release workflow.
- Adds canonical scripts under
`.github/skills/release-note-generation/scripts/` to:
- Resolve and validate ADO build metadata.
- Select the latest published stable or preview baseline before build
queue time.
- Calculate same-lineage or branch-transition PR deltas using PR
numbers, cherry-pick provenance, and patch-ID equivalence.
- Collect normalized PR metadata and create `release-manifest.json`.
- Download and validate installers, symbols, and GPO assets, including
hashes, signatures, and ZIP contents.
- Create or update draft prereleases while preserving human text outside
managed markers.
- Verify draft flags, immutable target commit, body markers, and
uploaded assets.
- Updates `.pipelines/resolveBuildMetadata.ps1` and
`.pipelines/v2/release.yml` with explicit `auto`, `preview-release`, and
`stable-release` intent handling so preview candidates can be built from
either `main` or `stable`.
- Adds `.pipelines/writeReleaseMetadata.ps1` so each signed build
artifact records its resolved version, channel, intent, source branch,
and immutable source commit.
- Keeps release publication outside the agent: the automation can only
create or update a draft prerelease.
## Validation Steps Performed
- `Invoke-Pester` for:
- `.pipelines/tests/resolveBuildMetadata.Tests.ps1`
- `.pipelines/tests/writeReleaseMetadata.Tests.ps1`
-
`.github/skills/release-note-generation/tests/preview-release.Tests.ps1`
- 37 tests passed, covering stable-branch preview intent, metadata
contracts, baseline selection, same-lineage and branch-transition
deltas, patch-ID equivalence, managed-body preservation, and
published-release refusal.
- Parsed all added or modified PowerShell scripts with the PowerShell
AST parser.
- Parsed the modified pipeline YAML files with `ConvertFrom-Yaml`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
Copilot-Session: e9f79ac2-9a7b-4083-834c-0d87e8c83bfd
Copilot-Session: 1ecea747-b313-49a1-9969-543c01ba1be8
2026-08-17 14:47:18 +08:00
|
|
|
$intent = if ($isScheduled -or $ReleaseIntent -eq "preview-release") { "preview-release" } else { "preview-validation" }
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
$channel = "preview"
|
2026-08-07 15:34:29 +08:00
|
|
|
$version = Get-PreviewVersionOverride -ReleaseTrain $releaseTrain -Override $VersionOverride
|
|
|
|
|
if ($null -eq $version) {
|
|
|
|
|
$version = Get-AutomaticReleaseVersion `
|
|
|
|
|
-ReleaseTrain $releaseTrain `
|
|
|
|
|
-Epoch $releaseMetadata.Epoch `
|
|
|
|
|
-BuildStamp $buildStamp `
|
|
|
|
|
-DateOverride $BuildDate `
|
|
|
|
|
-DailySequence $DailyVersionSequence
|
|
|
|
|
}
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
$allowPublicSymbols = $false
|
feat(release): automate draft preview release preparation (#49797)
## Summary of the Pull Request
Adds a `Prepare Preview Release` custom agent that autonomously turns a
successful PowerToys Azure DevOps release-candidate build into a
complete GitHub draft prerelease for final human review.
The implementation extends the existing `release-note-generation` skill
instead of duplicating it. It adds exact-build metadata resolution,
published-release baseline selection, semantic PR deltas across `main`
and `stable`, release asset validation, idempotent draft-only release
updates, and final draft verification.
## PR Checklist
- [x] **Communication:** The autonomous preview-release design was
reviewed and approved before implementation
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** N/A; no end-user-facing strings were added
- [x] **Dev docs:** Added preview scenario, delta, draft safety, and
reporting references
## Detailed Description of the Pull Request / Additional comments
- Adds `.github/agents/prepare-preview-release.agent.md` with a
no-mid-run-decision workflow and a strict prohibition on publishing
releases.
- Extends `.github/skills/release-note-generation/SKILL.md` with
stable/preview scenario routing while preserving the existing
stable-release workflow.
- Adds canonical scripts under
`.github/skills/release-note-generation/scripts/` to:
- Resolve and validate ADO build metadata.
- Select the latest published stable or preview baseline before build
queue time.
- Calculate same-lineage or branch-transition PR deltas using PR
numbers, cherry-pick provenance, and patch-ID equivalence.
- Collect normalized PR metadata and create `release-manifest.json`.
- Download and validate installers, symbols, and GPO assets, including
hashes, signatures, and ZIP contents.
- Create or update draft prereleases while preserving human text outside
managed markers.
- Verify draft flags, immutable target commit, body markers, and
uploaded assets.
- Updates `.pipelines/resolveBuildMetadata.ps1` and
`.pipelines/v2/release.yml` with explicit `auto`, `preview-release`, and
`stable-release` intent handling so preview candidates can be built from
either `main` or `stable`.
- Adds `.pipelines/writeReleaseMetadata.ps1` so each signed build
artifact records its resolved version, channel, intent, source branch,
and immutable source commit.
- Keeps release publication outside the agent: the automation can only
create or update a draft prerelease.
## Validation Steps Performed
- `Invoke-Pester` for:
- `.pipelines/tests/resolveBuildMetadata.Tests.ps1`
- `.pipelines/tests/writeReleaseMetadata.Tests.ps1`
-
`.github/skills/release-note-generation/tests/preview-release.Tests.ps1`
- 37 tests passed, covering stable-branch preview intent, metadata
contracts, baseline selection, same-lineage and branch-transition
deltas, patch-ID equivalence, managed-body preservation, and
published-release refusal.
- Parsed all added or modified PowerShell scripts with the PowerShell
AST parser.
- Parsed the modified pipeline YAML files with `ConvertFrom-Yaml`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
Copilot-Session: e9f79ac2-9a7b-4083-834c-0d87e8c83bfd
Copilot-Session: 1ecea747-b313-49a1-9969-543c01ba1be8
2026-08-17 14:47:18 +08:00
|
|
|
$shouldPublishPreview = $intent -eq "preview-release"
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
}
|
|
|
|
|
elseif ($isStable) {
|
feat(release): automate draft preview release preparation (#49797)
## Summary of the Pull Request
Adds a `Prepare Preview Release` custom agent that autonomously turns a
successful PowerToys Azure DevOps release-candidate build into a
complete GitHub draft prerelease for final human review.
The implementation extends the existing `release-note-generation` skill
instead of duplicating it. It adds exact-build metadata resolution,
published-release baseline selection, semantic PR deltas across `main`
and `stable`, release asset validation, idempotent draft-only release
updates, and final draft verification.
## PR Checklist
- [x] **Communication:** The autonomous preview-release design was
reviewed and approved before implementation
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** N/A; no end-user-facing strings were added
- [x] **Dev docs:** Added preview scenario, delta, draft safety, and
reporting references
## Detailed Description of the Pull Request / Additional comments
- Adds `.github/agents/prepare-preview-release.agent.md` with a
no-mid-run-decision workflow and a strict prohibition on publishing
releases.
- Extends `.github/skills/release-note-generation/SKILL.md` with
stable/preview scenario routing while preserving the existing
stable-release workflow.
- Adds canonical scripts under
`.github/skills/release-note-generation/scripts/` to:
- Resolve and validate ADO build metadata.
- Select the latest published stable or preview baseline before build
queue time.
- Calculate same-lineage or branch-transition PR deltas using PR
numbers, cherry-pick provenance, and patch-ID equivalence.
- Collect normalized PR metadata and create `release-manifest.json`.
- Download and validate installers, symbols, and GPO assets, including
hashes, signatures, and ZIP contents.
- Create or update draft prereleases while preserving human text outside
managed markers.
- Verify draft flags, immutable target commit, body markers, and
uploaded assets.
- Updates `.pipelines/resolveBuildMetadata.ps1` and
`.pipelines/v2/release.yml` with explicit `auto`, `preview-release`, and
`stable-release` intent handling so preview candidates can be built from
either `main` or `stable`.
- Adds `.pipelines/writeReleaseMetadata.ps1` so each signed build
artifact records its resolved version, channel, intent, source branch,
and immutable source commit.
- Keeps release publication outside the agent: the automation can only
create or update a draft prerelease.
## Validation Steps Performed
- `Invoke-Pester` for:
- `.pipelines/tests/resolveBuildMetadata.Tests.ps1`
- `.pipelines/tests/writeReleaseMetadata.Tests.ps1`
-
`.github/skills/release-note-generation/tests/preview-release.Tests.ps1`
- 37 tests passed, covering stable-branch preview intent, metadata
contracts, baseline selection, same-lineage and branch-transition
deltas, patch-ID equivalence, managed-body preservation, and
published-release refusal.
- Parsed all added or modified PowerShell scripts with the PowerShell
AST parser.
- Parsed the modified pipeline YAML files with `ConvertFrom-Yaml`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
Copilot-Session: e9f79ac2-9a7b-4083-834c-0d87e8c83bfd
Copilot-Session: 1ecea747-b313-49a1-9969-543c01ba1be8
2026-08-17 14:47:18 +08:00
|
|
|
if ($ReleaseIntent -eq "preview-release") {
|
|
|
|
|
$intent = "preview-release"
|
|
|
|
|
$channel = "preview"
|
|
|
|
|
$version = Get-PreviewVersionOverride -ReleaseTrain $releaseTrain -Override $VersionOverride
|
|
|
|
|
$allowPublicSymbols = $false
|
|
|
|
|
$shouldPublishPreview = $true
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$intent = "stable-release"
|
|
|
|
|
$channel = "stable"
|
|
|
|
|
$version = Get-StableVersionOverride -Override $VersionOverride
|
|
|
|
|
$allowPublicSymbols = $true
|
|
|
|
|
$shouldPublishPreview = $false
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
}
|
|
|
|
|
|
2026-08-07 15:34:29 +08:00
|
|
|
if ($null -eq $version) {
|
|
|
|
|
$version = Get-AutomaticReleaseVersion `
|
|
|
|
|
-ReleaseTrain $releaseTrain `
|
|
|
|
|
-Epoch $releaseMetadata.Epoch `
|
|
|
|
|
-BuildStamp $buildStamp `
|
|
|
|
|
-DateOverride $BuildDate `
|
|
|
|
|
-DailySequence $DailyVersionSequence
|
|
|
|
|
}
|
Add preview release versioning and update channel support (#49414)
## Summary
- Publish scheduled `main` builds as GitHub prereleases while keeping
manual `main` runs as preview validation builds.
- Add an opt-in Settings switch for prerelease update checks; stable
updates remain the default.
- Use one MSI-safe version across bundles, MSI packages, binaries,
symbols, and package manifests.
- Prevent preview releases from triggering Microsoft Store, WinGet, or
public-symbol publication.
- Label preview builds explicitly in Settings, update notifications, and
What's New.
## Build intent
| Source | Trigger | Intent |
| --- | --- | --- |
| `main` | Scheduled | Publish a preview release |
| `main` | Manual | Validate a preview build without publishing |
| `stable` | Manual | Produce a stable release |
| Other branches | Any supported trigger | Produce a private validation
build |
## MSI-safe release versioning
Windows Installer compares only `major.minor.build` and ignores the
fourth version component. Preview and stable release builds therefore
use:
```text
major.minor.YDDDB.0
```
- `Y`: zero-based number of calendar years since `ReleaseTrainEpoch`.
- `DDD`: three-position calendar day of year.
- `B`: daily release sequence `1-9`.
- The fourth component is always `0`.
With `ReleaseTrainVersion=0.100` and `ReleaseTrainEpoch=2026-01-01`:
```text
0.100.2111.0 = July 30, 2026, release build 1
0.100.3659.0 = December 31, 2026, release build 9
0.100.10011.0 = January 1, 2027, release build 1
```
The allocator formats `DDD` as exactly three digits before converting
the MSI component to its numeric representation. Leading zeros may not
be displayed because Windows version components are numeric; decoding
remains positional:
```text
B = component % 10
DDD = (component / 10) % 1000
Y = component / 10000
```
`ReleaseTrainVersion` and `ReleaseTrainEpoch` are checked in under
`src/Version.props`. The epoch remains January 1 of the active epoch
year and advances on the first release-train minor change in a new year.
## Daily release counter
Azure DevOps persists the daily sequence server-side using a counter
keyed as `release-YYYYMMDD`.
- `main` and `stable` share the same daily counter.
- Other branches do not evaluate or consume the release counter.
- Failed or canceled `main`/`stable` runs may leave gaps.
- The build fails when the daily sequence exceeds `9`.
- The counter date and encoded `YDDD` date both use
`pipeline.startTime`.
Private branches retain independent `0.0.<extended-day><NN>.0`
validation versions.
## Update behavior
- Stable users continue to query GitHub's stable latest-release path.
- Users who explicitly enable preview updates can select newer GitHub
prereleases.
- Preview releases and notifications are labeled as PowerToys Preview.
- What's New separates preview entries from stable release history and
hides previews by default.
## Validation
- 17 Pester tests cover `main`, `stable`, private branches, year
rollover, epoch reset, monotonicity, override validation, sequence
limits, and date alignment.
- Version propagation verified `0.100.2111.0` in `Version.props` and all
affected AppX/MSIX manifests.
- Azure DevOps pipeline dry-runs succeeded for both `refs/heads/main`
and `refs/heads/stable`.
- The affected native version project builds successfully.
- PR CI is green for x64, ARM64, Command Palette SDK, dependency review,
telemetry detection, and CLA.
## Remaining end-to-end checks
- Install two locally or officially produced installers with consecutive
MSI-visible `YDDDB` versions and verify the upgrade preserves binaries,
package registrations, hardlinks, and shell integrations.
- On the first natural post-merge `main` or `stable` run, verify the
production counter value and resolved version in the release logs.
## Local GPO verification
Validated locally with the signed `v0.100.2171` build from Azure DevOps
build
[153961073](https://microsoft.visualstudio.com/Dart/_build/results?buildId=153961073).
These checks cover the administrative-template integration and Settings
behavior.
### Policy enabled: preview updates are disabled
With `PreviewUpdatesDisabled=1`, **Include prerelease updates** is
forced off and locked, and Settings displays the
managed-by-your-organization notice.

### Policy removed: the user preference is preserved
After removing `PreviewUpdatesDisabled` and restarting PowerToys, the
previously selected preview-update preference is restored and editable.
The policy suppresses the preference without overwriting it.

### Group Policy Editor
After importing the updated ADMX/ADML templates, **Disable preview build
updates** appears under **Microsoft PowerToys > Installer and Updates**.
The policy dialog documents that **Enabled** blocks preview updates,
while **Disabled** or **Not Configured** leaves the choice available to
the user.

---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ad8b7909-0472-4464-bdee-deaeca726f94
Copilot-Session: 8e04a72e-3b0f-4ac4-8156-d04ea9b8bb85
2026-08-06 23:45:11 +08:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$intent = "private-validation"
|
|
|
|
|
$channel = "private"
|
|
|
|
|
$version = if ([string]::IsNullOrWhiteSpace($VersionOverride)) {
|
|
|
|
|
Get-PrivateVersion -Epoch $releaseMetadata.Epoch -BuildStamp $buildStamp
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Get-MsiSafeVersionOverride -Override $VersionOverride -VersionKind "Private"
|
|
|
|
|
}
|
|
|
|
|
$allowPublicSymbols = $false
|
|
|
|
|
$shouldPublishPreview = $false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Test-VersionParts -Parts ($version -split "\.")
|
|
|
|
|
|
|
|
|
|
Write-Host "Resolved build intent: $intent"
|
|
|
|
|
Write-Host "Resolved release channel: $channel"
|
|
|
|
|
Write-Host "Resolved version: $version"
|
|
|
|
|
|
|
|
|
|
[pscustomobject]@{
|
|
|
|
|
Intent = $intent
|
|
|
|
|
Channel = $channel
|
|
|
|
|
Version = $version
|
|
|
|
|
AllowPublicSymbols = $allowPublicSymbols
|
|
|
|
|
ShouldPublishPreview = $shouldPublishPreview
|
|
|
|
|
}
|