Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ jobs:
majorMinorPatch: ${{ steps.release_version.outputs.majorMinorPatch }}
isPrerelease: ${{ steps.release_version.outputs.isPrerelease }}
isStableCorrection: ${{ steps.release_version.outputs.isStableCorrection }}
isMsixAlpha: ${{ steps.release_version.outputs.isMsixAlpha }}
msixVersionInfo: ${{ steps.msix_preview.outputs.versionInfo }}
msixSourceVersion: ${{ steps.msix_preview.outputs.sourceVersion }}
steps:
Expand Down Expand Up @@ -235,9 +234,6 @@ jobs:
"majorMinorPatch=$majorMinorPatch" >> $env:GITHUB_OUTPUT
"isPrerelease=$($isPrerelease.ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT
"isStableCorrection=$($isStableCorrection.ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT
$isMsixAlpha = $isPrerelease -and ($env:GITHUB_REF -cmatch '^refs/tags/v(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)-alpha\.(?:0|[1-9]\d*)$')
"isMsixAlpha=$($isMsixAlpha.ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT

- name: Resolve MSIX preview version
id: msix_preview
if: ${{ !(github.repository == 'openclaw/openclaw-windows-node' && startsWith(github.ref, 'refs/tags/v') && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')) }}
Expand Down Expand Up @@ -1301,16 +1297,14 @@ jobs:
-Tag $env:RELEASE_TAG
-GitHubToken $env:GH_TOKEN

- name: Download alpha Store MSIX artifacts
if: needs.metadata.outputs.isMsixAlpha == 'true'
- name: Download Store MSIX release artifacts
uses: actions/download-artifact@v8
with:
pattern: openclaw-msix-store-unsigned-*
path: artifacts/msix-alpha
path: artifacts/msix-release

- name: Stage alpha Store MSIX release assets
if: needs.metadata.outputs.isMsixAlpha == 'true'
id: msix_alpha
- name: Stage Store MSIX release assets
id: msix_release
shell: pwsh
env:
RELEASE_VERSION: ${{ needs.metadata.outputs.semVer }}
Expand All @@ -1321,13 +1315,13 @@ jobs:
}
$env:MSIX_VERSION_INFO | Set-Content -LiteralPath "$env:RUNNER_TEMP\openclaw-msix-version.json" -Encoding utf8
$assets = .\scripts\Stage-StoreMsixReleaseAssets.ps1 `
-ArtifactDirectory 'artifacts\msix-alpha' `
-OutputDirectory 'msix-alpha-release' `
-ArtifactDirectory 'artifacts\msix-release' `
-OutputDirectory 'msix-release' `
-Version $env:RELEASE_VERSION `
-VersionInfoPath "$env:RUNNER_TEMP\openclaw-msix-version.json" `
-ExpectedSourceCommit $env:GITHUB_SHA
@('files<<MSIX_ALPHA_FILES'; $assets.Files; 'MSIX_ALPHA_FILES') >> $env:GITHUB_OUTPUT
@('notes<<MSIX_ALPHA_NOTES'; $assets.Notes; 'MSIX_ALPHA_NOTES') >> $env:GITHUB_OUTPUT
@('files<<MSIX_RELEASE_FILES'; $assets.Files; 'MSIX_RELEASE_FILES') >> $env:GITHUB_OUTPUT
@('notes<<MSIX_RELEASE_NOTES'; $assets.Notes; 'MSIX_RELEASE_NOTES') >> $env:GITHUB_OUTPUT

- name: Create Release
uses: softprops/action-gh-release@v3
Expand All @@ -1338,7 +1332,7 @@ jobs:
Output/OpenClawCompanion-Setup-arm64.exe
OpenClawTray-${{ needs.metadata.outputs.semVer }}-win-x64.zip
OpenClawTray-${{ needs.metadata.outputs.semVer }}-win-arm64.zip
${{ steps.msix_alpha.outputs.files }}
${{ steps.msix_release.outputs.files }}
fail_on_unmatched_files: true
prerelease: ${{ needs.metadata.outputs.isPrerelease }}
make_latest: ${{ needs.metadata.outputs.isPrerelease == 'true' && 'false' || 'true' }}
Expand All @@ -1351,7 +1345,7 @@ jobs:
- **Portable x64**: `OpenClawTray-${{ needs.metadata.outputs.semVer }}-win-x64.zip`
- **Portable ARM64**: `OpenClawTray-${{ needs.metadata.outputs.semVer }}-win-arm64.zip`

${{ steps.msix_alpha.outputs.notes }}
${{ steps.msix_release.outputs.notes }}

### Features
- 🦞 System tray integration with gateway status
Expand Down
44 changes: 20 additions & 24 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ infrastructure changes. Those fail-closed pull requests run the x64 publish
smoke only; ARM64 portable publish remains required on `main` and tags.
When either release-build lane is selected, CI also builds both architectures
of Dev-signed and unsigned Store MSIX **workflow artifacts**. CI Gate requires
that MSIX job to succeed. Canonical alpha releases also attach the unsigned
Store MSIX bundle, standalone packages, and metadata for manual Partner Center
submission.
Stable releases do not include MSIX assets; Dev-signed packages stay in Actions.
that MSIX job to succeed. Every tag release also attaches the unsigned Store
MSIX bundle, standalone packages, and metadata for manual Partner Center
submission. Dev-signed packages stay in Actions.

## Release checklist

Expand All @@ -37,8 +36,7 @@ Stable releases do not include MSIX assets; Dev-signed packages stay in Actions.
"Verify Release Binary Signing Policy", `
"OpenClaw.Tray.WinUI.exe", `
"build-msix:", `
"isMsixAlpha:", `
"Stage alpha Store MSIX release assets"
"Stage Store MSIX release assets"
```

3. Create a new stable, stable correction, or prerelease tag from `origin/main`.
Expand Down Expand Up @@ -174,7 +172,7 @@ Current release artifacts are:
- `OpenClawTray-<version>-win-x64.zip`
- `OpenClawTray-<version>-win-arm64.zip`

Canonical alpha releases additionally contain:
Every stable, correction, and prerelease additionally contains:

- `OpenClaw.msixbundle` (recommended Partner Center submission input)
- `OpenClaw-x64.msix` and `OpenClaw-arm64.msix`
Expand All @@ -184,19 +182,18 @@ Canonical alpha releases additionally contain:
These are **unsigned Store submission inputs, not installers**. Upload the
bundle to Partner Center for one architecture-selecting submission. The
standalone packages remain available for inspection or fallback. Microsoft
signs accepted Store submissions. The alpha release step checks both
signs accepted Store submissions. The release step checks both
architectures' clean source provenance, identity, version, and package hashes,
then proves that the bundle embeds those exact bytes. It fails rather than
publishing a partial or mismatched set.

Stable, stable-correction, and non-alpha prereleases retain the existing
EXE/ZIP asset set and do not receive MSIX download notes. Dev-signed tester
MSIX packages, public certificates, and instructions remain Actions artifacts
only. No production signing step is applied to the unsigned Store packages.
Dev-signed tester MSIX packages, public certificates, and instructions remain
Actions artifacts only. No production signing step is applied to the unsigned
Store packages.

Store distribution remains paused: automatic Partner Center submission,
Store-signed retrieval and publication, and official lifecycle acceptance
remain follow-up work in #1375. Alpha submission artifacts do not clear those
remain follow-up work in #1375. Release submission artifacts do not clear those
rollout gates.

Store versions still end in `.0`. Official tagged builds now reserve distinct
Expand Down Expand Up @@ -268,20 +265,20 @@ source commit/ref, package base, allocation kind, and reservation ref.
Preview candidates never reserve a number and can change between reruns;
they must not be treated as official Store submissions.

The alpha stager requires `-VersionInfoPath` for the exact reserved result. It
checks the app alpha version, source commit, reserved allocation, package
The release stager requires `-VersionInfoPath` for the exact reserved result. It
checks the app version, source commit, reserved allocation, package
version, and both architectures' metadata before copying any assets:

```powershell
.\scripts\Stage-StoreMsixReleaseAssets.ps1 `
-ArtifactDirectory 'artifacts\msix-alpha' `
-OutputDirectory 'msix-alpha-release' `
-ArtifactDirectory 'artifacts\msix-release' `
-OutputDirectory 'msix-release' `
-Version $appVersion -ExpectedSourceCommit $sourceCommit `
-VersionInfoPath $reservedVersionInfoPath
```

This does not change stable/alpha asset selection, bypass CI Gate or signing
approvals, move existing application tags, or automate Store submission.
This does not bypass CI Gate or signing approvals, move existing application
tags, or automate Store submission.

## Manual alpha releases

Expand Down Expand Up @@ -412,9 +409,8 @@ validation. Release tags cannot enter the `release` job until **CI Gate**
confirms classification, fast validation, tests, E2E, and release builds all
succeeded. The `build-msix` and `build-msix-bundle` jobs must also succeed
whenever release metadata is required. The release job downloads and attaches
its unsigned Store bundle, standalone packages, and metadata only for canonical
alpha tags. Stable releases and Dev tester distribution do not gain MSIX
release attachments.
its unsigned Store bundle, standalone packages, and metadata for every
canonical tag. Dev tester distribution stays workflow-only.

The release job should:

Expand All @@ -425,10 +421,10 @@ The release job should:
5. Create the portable x64 and ARM64 ZIPs.
6. Build Inno installers.
7. Sign installers.
8. For canonical alpha tags only, stage the validated unsigned Store MSIX
8. Stage the validated unsigned Store MSIX
bundle, standalone packages, and metadata.
9. Create a GitHub release whose prerelease flag matches the tag, with installer
and portable ZIP assets plus any gated alpha submission assets.
and portable ZIP assets plus the Store submission assets.

## Post-release verification

Expand Down
12 changes: 5 additions & 7 deletions scripts/Stage-StoreMsixReleaseAssets.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<#
.SYNOPSIS
Stages validated unsigned Store MSIX packages for an alpha GitHub release.
Stages validated unsigned Store MSIX packages for a GitHub release.
.DESCRIPTION
Checks both architectures' provenance and hashes, then verifies that the
multi-architecture bundle embeds those exact packages before copying files.
Expand All @@ -13,8 +13,7 @@ param(
[Parameter(Mandatory)][string]$ArtifactDirectory,
[Parameter(Mandatory)][string]$OutputDirectory,
[Parameter(Mandatory)]
[ValidatePattern('^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)-alpha\.(?:0|[1-9]\d*)$')]
[string]$Version,
[ValidateNotNullOrEmpty()][string]$Version,
[Parameter(Mandatory)][ValidatePattern('^[0-9a-fA-F]{40}$')][string]$ExpectedSourceCommit,
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$VersionInfoPath
)
Expand All @@ -27,7 +26,7 @@ $OutputDirectory = [IO.Path]::GetFullPath([IO.Path]::Combine($repositoryRoot, $O
if ((Test-Path -LiteralPath $OutputDirectory) -and
(-not (Test-Path -LiteralPath $OutputDirectory -PathType Container) -or
@(Get-ChildItem -LiteralPath $OutputDirectory -Force).Count -gt 0)) {
throw "The alpha release output directory must be absent or empty: $OutputDirectory"
throw "The release output directory must be absent or empty: $OutputDirectory"
}

[xml]$manifest = Get-Content -LiteralPath (Join-Path $repositoryRoot 'src\OpenClaw.Tray.WinUI\Package.appxmanifest') -Raw
Expand Down Expand Up @@ -163,7 +162,7 @@ $files += foreach ($package in $packages) {
[pscustomobject]@{
Files = @($files)
Notes = @"
### Unsigned Store submission packages (alpha only)
### Unsigned Store submission packages

OpenClaw.msixbundle is the recommended unsigned Partner Center submission
input. It contains the exact x64 and ARM64 packages selected by Windows.
Expand All @@ -174,7 +173,6 @@ this workflow does not submit or retrieve Store packages.

The Windows package version is $expectedVersion, reserved for $Version.
Different official tags share the app patch's packaging counter; reruns of
this tag reuse its reservation. Stable releases do not include these
experimental submission assets. Dev-signed tester downloads remain in Actions.
this tag reuse its reservation. Dev-signed tester downloads remain in Actions.
"@
}
30 changes: 14 additions & 16 deletions scripts/test-ci-workflow-contract.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -811,26 +811,24 @@ foreach ($token in @(
)) {
Assert-Contains -Text $releaseJob -Expected $token -Message "Tag release is missing '$token'."
}
$alphaDownload = Get-StepBlock -Text $releaseJob -Name 'Download alpha Store MSIX artifacts'
$alphaStage = Get-StepBlock -Text $releaseJob -Name 'Stage alpha Store MSIX release assets'
foreach ($step in @($alphaDownload, $alphaStage)) {
Assert-Contains -Text $step -Expected "if: needs.metadata.outputs.isMsixAlpha == 'true'" -Message "Store release assets must be alpha-only."
}
Assert-Contains -Text $alphaDownload -Expected 'pattern: openclaw-msix-store-unsigned-*' -Message "Alpha releases must use unsigned Store inputs."
Assert-NotContains -Text $alphaDownload -Unexpected 'openclaw-msix-dev-' -Message "Dev packages must stay workflow-only."
Assert-Contains -Text $alphaStage -Expected '-ExpectedSourceCommit $env:GITHUB_SHA' -Message "Release staging must bind artifacts to the tag's source."
Assert-Contains -Text $alphaStage -Expected '-Version $env:RELEASE_VERSION' -Message "Release staging must validate the alpha version."
Assert-Contains -Text $alphaStage -Expected '-VersionInfoPath "$env:RUNNER_TEMP\openclaw-msix-version.json"' -Message 'Release staging must require its exact reserved MSIX version.'
Assert-Contains -Text $alphaStage -Expected 'MSIX_VERSION_INFO: ${{ needs.reserve-msix-version.outputs.versionInfo }}' -Message 'Release staging must not accept a preview.'
$msixDownload = Get-StepBlock -Text $releaseJob -Name 'Download Store MSIX release artifacts'
$msixStage = Get-StepBlock -Text $releaseJob -Name 'Stage Store MSIX release assets'
foreach ($step in @($msixDownload, $msixStage)) {
Assert-NotContains -Text $step -Unexpected 'if:' -Message "Every tag release must publish Store MSIX assets."
}
Assert-Contains -Text $msixDownload -Expected 'pattern: openclaw-msix-store-unsigned-*' -Message "Tag releases must use unsigned Store inputs."
Assert-NotContains -Text $msixDownload -Unexpected 'openclaw-msix-dev-' -Message "Dev packages must stay workflow-only."
Assert-Contains -Text $msixStage -Expected '-ExpectedSourceCommit $env:GITHUB_SHA' -Message "Release staging must bind artifacts to the tag's source."
Assert-Contains -Text $msixStage -Expected '-Version $env:RELEASE_VERSION' -Message "Release staging must validate the release version."
Assert-Contains -Text $msixStage -Expected '-VersionInfoPath "$env:RUNNER_TEMP\openclaw-msix-version.json"' -Message 'Release staging must require its exact reserved MSIX version.'
Assert-Contains -Text $msixStage -Expected 'MSIX_VERSION_INFO: ${{ needs.reserve-msix-version.outputs.versionInfo }}' -Message 'Release staging must not accept a preview.'
$createRelease = Get-StepBlock -Text $releaseJob -Name 'Create Release'
Assert-Contains -Text $createRelease -Expected '${{ steps.msix_alpha.outputs.files }}' -Message "Only the gated alpha stage may add MSIX release files."
Assert-Contains -Text $createRelease -Expected '${{ steps.msix_alpha.outputs.notes }}' -Message "Only alpha release notes may mention MSIX downloads."
Assert-Contains -Text $createRelease -Expected '${{ steps.msix_release.outputs.files }}' -Message "Every tag release must add validated MSIX release files."
Assert-Contains -Text $createRelease -Expected '${{ steps.msix_release.outputs.notes }}' -Message "Every tag release must include MSIX submission notes."
Assert-Contains -Text $createRelease -Expected 'fail_on_unmatched_files: true' -Message "Missing release files must fail publication."
Assert-Contains -Text $createRelease -Expected "make_latest: `${{ needs.metadata.outputs.isPrerelease == 'true' && 'false' || 'true' }}" -Message "Alpha releases must not become Latest."
Assert-NotContains -Text $createRelease -Unexpected 'OpenClaw-x64.msix' -Message "MSIX must not be an unconditional stable release asset."
Assert-NotContains -Text $createRelease -Unexpected 'OpenClaw-arm64.msix' -Message "MSIX must not be an unconditional stable release asset."
Assert-Contains -Text $workflow -Expected "./scripts/test-msix-ci-artifacts.ps1" -Message "Fast validation must exercise the Dev artifact contracts."
Assert-Contains -Text $workflow -Expected "./scripts/test-msix-alpha-release.ps1" -Message "Fast validation must exercise alpha release staging."
Assert-Contains -Text $workflow -Expected "./scripts/test-msix-alpha-release.ps1" -Message "Fast validation must exercise Store release staging."
Assert-Contains -Text $workflow -Expected "./scripts/test-msix-versioning.ps1" -Message 'Fast validation must exercise allocation races and boundaries.'
Assert-Contains -Text $workflow -Expected "./scripts/test-msix-preview-source-version.ps1" -Message 'Fast validation must exercise latest-stable MSIX preview selection.'

Expand Down
Loading
Loading