Build and Publish WinUI3 App #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Upload | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version number (e.g., 1.0.0.1)' | |
| required: true | |
| type: string | |
| prerelease: | |
| description: 'If pre_release' | |
| required: true | |
| type: boolean | |
| env: | |
| DOTNET_VERSION: '8.0.x' | |
| jobs: | |
| build-and-package: | |
| name: Build and Package | |
| runs-on: windows-2022 | |
| env: | |
| Solution_Name: RailGo.sln | |
| SigningKey_Path: SigningKey.pfx | |
| APPLICATION_ID: 9NTRZ0DMCKGZ | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v3 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install .NET Core | |
| uses: actions/setup-dotnet@v3 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Setup MSBuild.exe | |
| uses: microsoft/setup-msbuild@v1 | |
| - name: Install StoreBroker | |
| shell: pwsh | |
| run: | | |
| Write-Output "Installing StoreBroker module..." | |
| Install-Module -Name StoreBroker -Force -AllowClobber -Scope CurrentUser | |
| Import-Module StoreBroker | |
| Write-Output "StoreBroker installed successfully" | |
| - name: Restore the application | |
| run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration | |
| env: | |
| Configuration: Release | |
| - name: Update Manifest Version | |
| shell: pwsh | |
| run: | | |
| $AppxManifestPath = "RailGo/Package.appxmanifest" | |
| $newVersion = "${{ github.event.inputs.version }}" | |
| Write-Output "Setting new version: $newVersion" | |
| [xml]$xmlMSIX = Get-Content $AppxManifestPath | |
| $identityNode = $xmlMSIX.Package.Identity | |
| $identityNode.Version = $newVersion | |
| $xmlMSIX.Save($AppxManifestPath) | |
| - name: Create the MSIX Package | |
| run: msbuild $env:Solution_Name /p:AppxBundlePlatforms="$env:Appx_Bundle_Platforms" /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:Appx_Package_Build_Mode /p:AppxBundle=$env:Appx_Bundle /p:AppxPackageDir="$env:Appx_Package_Dir" /p:GenerateAppxPackageOnBuild=true /p:AppxPackageSigningEnabled=false | |
| env: | |
| Appx_Bundle: Always | |
| Appx_Bundle_Platforms: x86|x64|ARM64 | |
| Appx_Package_Build_Mode: SideloadOnly | |
| Appx_Package_Dir: AppxPackages\ | |
| Configuration: Release | |
| - name: Sign .msix | |
| shell: pwsh | |
| run: | | |
| # Get signtool.exe | |
| $signtool = Get-ChildItem -Path "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\signtool.exe" | Select-Object -First 1 | |
| # Get File | |
| $msixFile = Get-ChildItem -Path "RailGo/AppxPackages" -Recurse -Filter "*.msix" | Sort-Object LastWriteTime -Descending | Select-Object -First 1 | |
| if (-not $msixFile) { | |
| throw "No MSIX file found" | |
| } | |
| Write-Output "Signing file: $($msixFile.FullName)" | |
| # Sign .msix | |
| $pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.SIGNING_CERT }}") | |
| [IO.File]::WriteAllBytes("${{ env.SigningKey_Path }}", $pfx_cert_byte) | |
| & $signtool sign /f "${{ env.SigningKey_Path }}" /fd SHA256 /td SHA256 "$($msixFile.FullName)" | |
| Remove-Item "${{ env.SigningKey_Path }}" | |
| Write-Output "File signed successfully" | |
| - name: Upload to Microsoft Store using StoreBroker (Manual Package Cleanup) | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| # Import StoreBroker module | |
| Import-Module StoreBroker | |
| # Find signed MSIX file | |
| Write-Output "Looking for signed MSIX file..." | |
| $msixFile = Get-ChildItem -Path "RailGo/AppxPackages" -Recurse -Filter "*.msix" | Sort-Object LastWriteTime -Descending | Select-Object -First 1 | |
| if (-not $msixFile) { | |
| throw "No signed MSIX file found" | |
| } | |
| Write-Output "Found MSIX file: $($msixFile.FullName)" | |
| Write-Output "File size: $([math]::Round($msixFile.Length / 1MB, 2)) MB" | |
| # Setup authentication | |
| Write-Output "Setting up StoreBroker authentication..." | |
| $clientId = "${{ secrets.AZURE_CLIENT_ID }}" | |
| $clientSecret = "${{ secrets.AZURE_CLIENT_SECRET }}" | |
| $tenantId = "${{ secrets.AZURE_TENANT_ID }}" | |
| # Create credentials | |
| $securePassword = ConvertTo-SecureString $clientSecret -AsPlainText -Force | |
| $credential = New-Object System.Management.Automation.PSCredential($clientId, $securePassword) | |
| # Set StoreBroker authentication | |
| Set-StoreBrokerAuthentication -TenantId $tenantId -Credential $credential | |
| # Create output directory | |
| $outPath = "SubmissionPackage" | |
| if (Test-Path $outPath) { | |
| Remove-Item $outPath -Recurse -Force | |
| } | |
| New-Item -ItemType Directory -Path $outPath -Force | |
| # Create basic submission configuration | |
| Write-Output "Creating submission configuration..." | |
| $configContent = @" | |
| { | |
| "targetPublishMode": "Manual", | |
| "targetPublishDate": "", | |
| "notesForReviewer": "Automated submission via GitHub Actions - Version ${{ github.event.inputs.version }}", | |
| "applicationCategory": "Productivity", | |
| "pricing": { | |
| "trialPeriod": "NoFreeTrial", | |
| "marketSpecificPricings": {}, | |
| "sales": [] | |
| }, | |
| "visibility": "Public", | |
| "allowTargetFutureDeviceFamilies": { | |
| "Desktop": true, | |
| "Mobile": false, | |
| "Holographic": false, | |
| "Xbox": false | |
| }, | |
| "allowMicrosoftDecideAppAvailabilityToFutureDeviceFamilies": true, | |
| "languages": ["en-US"] | |
| } | |
| "@ | |
| $configContent | Out-File -FilePath "$outPath\submission.json" -Encoding UTF8 | |
| # Use StoreBroker to create submission package | |
| Write-Output "Creating submission package..." | |
| try { | |
| New-SubmissionPackage -ConfigPath "$outPath\submission.json" -AppxPath $msixFile.FullName -OutPath $outPath -OutName "package" | |
| Write-Output "Submission package created successfully" | |
| } catch { | |
| Write-Error "Failed to create submission package: $($_.Exception.Message)" | |
| exit 1 | |
| } | |
| # Manual method: delete old packages first, then add new package | |
| Write-Output "Starting manual package cleanup and update process..." | |
| # 1. Create new submission (clone current published submission) | |
| Write-Output "Step 1: Creating new submission..." | |
| $submission = New-ApplicationSubmission -AppId "${{ env.APPLICATION_ID }}" -Force | |
| Write-Output "New submission created with ID: $($submission.id)" | |
| # 2. Show all current packages in submission | |
| Write-Output "Step 2: Current packages in submission:" | |
| if ($submission.applicationPackages -and $submission.applicationPackages.Count -gt 0) { | |
| for ($i = 0; $i -lt $submission.applicationPackages.Count; $i++) { | |
| $package = $submission.applicationPackages[$i] | |
| Write-Output " Package [$i]: $($package.fileName) - Status: $($package.fileStatus)" | |
| } | |
| # 3. Mark all old packages for deletion | |
| Write-Output "Step 3: Marking all existing packages for deletion..." | |
| foreach ($package in $submission.applicationPackages) { | |
| $package.fileStatus = 'PendingDelete' | |
| Write-Output " Marked for deletion: $($package.fileName)" | |
| } | |
| } else { | |
| Write-Output " No existing packages found in submission" | |
| } | |
| # 4. Parse new package info and add to submission | |
| Write-Output "Step 4: Adding new package to submission..." | |
| $packageJsonPath = Join-Path $outPath "package.json" | |
| if (Test-Path $packageJsonPath) { | |
| $packageJson = Get-Content $packageJsonPath -Encoding UTF8 | ConvertFrom-Json | |
| # Add new package | |
| if ($packageJson.applicationPackages -and $packageJson.applicationPackages.Count -gt 0) { | |
| foreach ($newPackage in $packageJson.applicationPackages) { | |
| $submission.applicationPackages += $newPackage | |
| Write-Output " Added new package: $($newPackage.fileName)" | |
| } | |
| } else { | |
| Write-Error "No application packages found in package.json" | |
| exit 1 | |
| } | |
| } else { | |
| Write-Error "package.json not found at: $packageJsonPath" | |
| exit 1 | |
| } | |
| # 5. Update submission | |
| Write-Output "Step 5: Updating submission with changes..." | |
| Set-ApplicationSubmission -AppId "${{ env.APPLICATION_ID }}" -UpdatedSubmission $submission | |
| Write-Output "Submission updated successfully" | |
| # 6. Upload package file | |
| Write-Output "Step 6: Uploading package file..." | |
| $packageZipPath = Join-Path $outPath "package.zip" | |
| if (Test-Path $packageZipPath) { | |
| Set-SubmissionPackage -PackagePath $packageZipPath -UploadUrl $submission.fileUploadUrl | |
| Write-Output "Package file uploaded successfully" | |
| } else { | |
| Write-Error "Package zip file not found at: $packageZipPath" | |
| exit 1 | |
| } | |
| # 7. Commit submission | |
| Write-Output "Step 7: Committing submission..." | |
| Complete-ApplicationSubmission -AppId "${{ env.APPLICATION_ID }}" -SubmissionId $submission.id | |
| Write-Output "Submission committed successfully" | |
| Write-Output "" | |
| Write-Output "Successfully uploaded to Microsoft Store!" | |
| Write-Output "Submission ID: $($submission.id)" | |
| Write-Output "File: $($msixFile.Name)" | |
| Write-Output "All previous packages have been marked for deletion" | |
| Write-Output "New package has been added" | |
| Write-Output "Visit Partner Center to complete: https://partner.microsoft.com/dashboard" | |
| env: | |
| AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} | |
| AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} | |
| AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} |