ci: automate Microsoft Store updates

This commit is contained in:
2026-07-30 19:12:50 +02:00
parent 4ce124da7c
commit caaa9a472d
3 changed files with 130 additions and 12 deletions

View File

@@ -246,6 +246,114 @@ jobs:
retention-days: 90 retention-days: 90
compression-level: 0 compression-level: 0
publish-microsoft-store:
name: Submit Microsoft Store update
needs:
- preflight
- linux
- windows
- macos
- play-closed-testing
runs-on: windows-2025
timeout-minutes: 30
environment: microsoft-store
permissions:
contents: read
steps:
- name: Download Windows Store package
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: vnidrop-${{ needs.preflight.outputs.version }}-windows-store-x64
path: build/release/windows
- name: Validate Microsoft Store configuration
id: store-package
shell: pwsh
env:
AZURE_AD_TENANT_ID: ${{ secrets.AZURE_AD_TENANT_ID }}
AZURE_AD_APPLICATION_CLIENT_ID: ${{ secrets.AZURE_AD_APPLICATION_CLIENT_ID }}
AZURE_AD_APPLICATION_SECRET: ${{ secrets.AZURE_AD_APPLICATION_SECRET }}
SELLER_ID: ${{ secrets.SELLER_ID }}
MICROSOFT_STORE_PRODUCT_ID: ${{ vars.MICROSOFT_STORE_PRODUCT_ID }}
run: |
$configuration = @{
AZURE_AD_TENANT_ID = $env:AZURE_AD_TENANT_ID
AZURE_AD_APPLICATION_CLIENT_ID = $env:AZURE_AD_APPLICATION_CLIENT_ID
AZURE_AD_APPLICATION_SECRET = $env:AZURE_AD_APPLICATION_SECRET
SELLER_ID = $env:SELLER_ID
MICROSOFT_STORE_PRODUCT_ID = $env:MICROSOFT_STORE_PRODUCT_ID
}
foreach ($entry in $configuration.GetEnumerator()) {
if ([string]::IsNullOrWhiteSpace($entry.Value) -or $entry.Value -eq "REPLACE_ME") {
throw "Missing Microsoft Store configuration: $($entry.Key)"
}
}
if ($env:MICROSOFT_STORE_PRODUCT_ID -ne "9NJ5Q0FG7TGL") {
throw "Unexpected Microsoft Store product ID: $env:MICROSOFT_STORE_PRODUCT_ID"
}
$packages = @(
Get-ChildItem build/release/windows -File -Filter *.msixupload -Recurse
)
if ($packages.Count -ne 1) {
throw "Expected exactly one msixupload package, found $($packages.Count)"
}
"path=$($packages[0].FullName)" >> $env:GITHUB_OUTPUT
- name: Set up Microsoft Store Developer CLI
uses: microsoft/microsoft-store-apppublisher@15abd1c50fcc164b19cb240fb04ef3c49bf715a2 # v1.1
with:
version: v0.3.9
- name: Authenticate and verify Store access
shell: pwsh
env:
AZURE_AD_TENANT_ID: ${{ secrets.AZURE_AD_TENANT_ID }}
AZURE_AD_APPLICATION_CLIENT_ID: ${{ secrets.AZURE_AD_APPLICATION_CLIENT_ID }}
AZURE_AD_APPLICATION_SECRET: ${{ secrets.AZURE_AD_APPLICATION_SECRET }}
SELLER_ID: ${{ secrets.SELLER_ID }}
MICROSOFT_STORE_PRODUCT_ID: ${{ vars.MICROSOFT_STORE_PRODUCT_ID }}
run: |
msstore settings --enableTelemetry false
if ($LASTEXITCODE -ne 0) {
throw "Failed to disable Microsoft Store CLI telemetry"
}
msstore reconfigure `
--tenantId "$env:AZURE_AD_TENANT_ID" `
--sellerId "$env:SELLER_ID" `
--clientId "$env:AZURE_AD_APPLICATION_CLIENT_ID" `
--clientSecret "$env:AZURE_AD_APPLICATION_SECRET"
if ($LASTEXITCODE -ne 0) {
throw "Microsoft Store authentication failed"
}
msstore apps get "$env:MICROSOFT_STORE_PRODUCT_ID"
if ($LASTEXITCODE -ne 0) {
throw "The Microsoft Store application is not accessible"
}
- name: Publish package to Microsoft Store
shell: pwsh
env:
MICROSOFT_STORE_PRODUCT_ID: ${{ vars.MICROSOFT_STORE_PRODUCT_ID }}
STORE_PACKAGE: ${{ steps.store-package.outputs.path }}
run: |
msstore publish "$env:STORE_PACKAGE" `
--appId "$env:MICROSOFT_STORE_PRODUCT_ID"
if ($LASTEXITCODE -ne 0) {
throw "Microsoft Store package publication failed"
}
- name: Summarize Store submission
shell: pwsh
env:
VERSION: ${{ needs.preflight.outputs.version }}
MICROSOFT_STORE_PRODUCT_ID: ${{ vars.MICROSOFT_STORE_PRODUCT_ID }}
run: |
"### Microsoft Store submission" >> $env:GITHUB_STEP_SUMMARY
"- App version: $env:VERSION" >> $env:GITHUB_STEP_SUMMARY
"- Product ID: $env:MICROSOFT_STORE_PRODUCT_ID" >> $env:GITHUB_STEP_SUMMARY
"- Package submitted for certification" >> $env:GITHUB_STEP_SUMMARY
publish-github: publish-github:
name: Publish coordinated GitHub Release name: Publish coordinated GitHub Release
needs: needs:
@@ -254,6 +362,7 @@ jobs:
- windows - windows
- macos - macos
- play-closed-testing - play-closed-testing
- publish-microsoft-store
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
timeout-minutes: 20 timeout-minutes: 20
permissions: permissions:

View File

@@ -13,19 +13,23 @@ Platform workflows upload private workflow artifacts. After every native build
passes, the release pipeline: passes, the release pipeline:
1. stages the signed AAB as a draft on the configured Play closed-test track; 1. stages the signed AAB as a draft on the configured Play closed-test track;
2. downloads the universal APK signed by Play; 2. submits the unsigned `.msixupload` package to Microsoft Store certification;
3. verifies and assembles the public artifacts; 3. downloads the universal APK signed by Play;
4. generates checksums and GitHub build-provenance attestations; 4. verifies and assembles the public artifacts;
5. creates exactly one GitHub Release; 5. generates checksums and GitHub build-provenance attestations;
6. updates the Homebrew cask. 6. creates exactly one GitHub Release;
7. updates the Homebrew cask.
Public GitHub Release assets are the DEB, RPM, notarized DMG, Sparkle appcast, Public GitHub Release assets are the DEB, RPM, notarized DMG, Sparkle appcast,
Play-signed universal APK, checksum file, and release manifest. Play-signed universal APK, checksum file, and release manifest.
The unsigned Microsoft `.msixupload` and upload-signed Android AAB remain The unsigned Microsoft `.msixupload` and upload-signed Android AAB remain
private workflow artifacts. Partner Center submission stays manual until the private workflow artifacts. The protected `microsoft-store` GitHub Environment
first Microsoft Store release is certified. The Play release remains a draft supplies the Partner Center credentials and Store product ID used to submit the
on a closed-testing track; this pipeline cannot publish to production. Windows package. Microsoft publishes the update after certification; the job
does not change Store listings, pricing, or availability. The Play release
remains a draft on a closed-testing track; this pipeline cannot publish it to
production.
To release, prepare and merge the new product version. Android, Microsoft Store, To release, prepare and merge the new product version. Android, Microsoft Store,
and Apple build/package versions are derived automatically: and Apple build/package versions are derived automatically:

View File

@@ -74,16 +74,21 @@ Use this restricted-capability justification in Submission options:
> Rust and JVM libraries and needs normal user-level filesystem and network > Rust and JVM libraries and needs normal user-level filesystem and network
> access to transfer user-selected files directly between devices. > access to transfer user-selected files directly between devices.
After the first release is certified and live, Store publication can be added After the first release is certified and live, the coordinated release
as a separate protected job. Keep its Partner Center credentials in a GitHub workflow submits the generated `.msixupload` from a separate protected job.
Environment, not in this build job: Keep its Partner Center credentials in the `microsoft-store` GitHub
Environment, not in the build job:
- AZURE_AD_TENANT_ID - AZURE_AD_TENANT_ID
- AZURE_AD_APPLICATION_CLIENT_ID - AZURE_AD_APPLICATION_CLIENT_ID
- AZURE_AD_APPLICATION_SECRET - AZURE_AD_APPLICATION_SECRET
- SELLER_ID - SELLER_ID
The Store ID is a non-secret variable. Set `MICROSOFT_STORE_PRODUCT_ID` to `9NJ5Q0FG7TGL` as a non-secret variable in
the same environment. The publishing job validates the product ID,
authenticates with the pinned Microsoft Store Developer CLI, verifies access to
the product, and submits only the package for certification. Existing listings,
pricing, and availability are preserved.
## Manual build on Windows ## Manual build on Windows