mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
add Publication scripts for Microsoft Store and WinGet template
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
# Publication Setup
|
||||
|
||||
This folder contains tools to help you prepare your CmdPal extension for publication to the Microsoft Store and WinGet.
|
||||
|
||||
## Files and Folders in this Directory
|
||||
|
||||
### Scripts
|
||||
|
||||
- **`one-time-store-pubishing-setup.ps1`** - Configure your project for Microsoft Store publishing (run once)
|
||||
- **`build-msix-bundles.ps1`** - Build MSIX packages and create bundles for Store submission
|
||||
- **`one-time-winget-publishing-setup.ps1`** - Configure your project for WinGet publishing (run once)
|
||||
|
||||
### Resource Folders
|
||||
|
||||
- **`microsoft-store-resources/`** - Contains files used for Microsoft Store publishing:
|
||||
- `bundle_mapping.txt` - Auto-generated file that maps MSIX files for bundle creation
|
||||
|
||||
- **`winget-resources/`** - Contains templates and scripts for WinGet publishing:
|
||||
- `build-exe.ps1` - Script to build standalone EXE installer
|
||||
- `setup-template.iss` - Inno Setup installer template
|
||||
- `release-extension.yml` - GitHub Actions workflow template (moved to `.github/workflows/` during setup)
|
||||
- `Backups/` - Backup copies of configuration files (created during setup)
|
||||
|
||||
## Microsoft Store Quick Start
|
||||
|
||||
1. Open PowerShell and navigate to the Publication folder:
|
||||
|
||||
```powershell
|
||||
cd <YourProject>\Publication
|
||||
```
|
||||
|
||||
2. Run the one-time setup script:
|
||||
|
||||
```powershell
|
||||
.\one-time-store-pubishing-setup.ps1
|
||||
```
|
||||
|
||||
3. Follow the prompts to enter your Microsoft Store information from Partner Center:
|
||||
- Package Identity Name
|
||||
- Publisher Certificate
|
||||
- Display Name
|
||||
- Publisher Display Name
|
||||
|
||||
The script will update your `Package.appxmanifest` with Store-specific values.
|
||||
|
||||
4. Once configured, build your bundle:
|
||||
|
||||
```powershell
|
||||
.\build-msix-bundles.ps1
|
||||
```
|
||||
|
||||
This script will:
|
||||
- Build x64 and ARM64 MSIX packages
|
||||
- Automatically update `microsoft-store-resources\bundle_mapping.txt` with correct paths
|
||||
- Create a combined MSIX bundle
|
||||
- Display the bundle location when complete
|
||||
|
||||
5. Upload the resulting `.msixbundle` file from `microsoft-store-resources\` to Partner Center
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### makeappx.exe not found
|
||||
|
||||
The build script requires the Windows SDK. Install it via:
|
||||
|
||||
- Visual Studio Installer (Individual Components → Windows SDK)
|
||||
- [Standalone Windows SDK](https://developer.microsoft.com/windows/downloads/windows-sdk/)
|
||||
|
||||
### Build errors
|
||||
|
||||
Ensure you have:
|
||||
|
||||
- .NET 9.0 SDK installed
|
||||
- Windows SDK 10.0.26100.0 or compatible version
|
||||
- No other instances of Visual Studio building the project
|
||||
|
||||
### Bundle creation fails
|
||||
|
||||
Check that:
|
||||
|
||||
- Both x64 and ARM64 builds completed successfully
|
||||
- `microsoft-store-resources\bundle_mapping.txt` paths are correct (auto-updated by script)
|
||||
- No file locks on the MSIX files
|
||||
|
||||
## WinGet Quick Start
|
||||
|
||||
1. Open PowerShell and navigate to the Publication folder:
|
||||
|
||||
```powershell
|
||||
cd <YourProject>\Publication
|
||||
```
|
||||
|
||||
2. Run the one-time setup script:
|
||||
|
||||
```powershell
|
||||
.\one-time-winget-publishing-setup.ps1
|
||||
```
|
||||
|
||||
3. Follow the prompts to enter:
|
||||
- GitHub Repository URL (where releases will be published)
|
||||
- Developer/Publisher Name
|
||||
|
||||
The script will:
|
||||
- Configure `winget-resources\build-exe.ps1` with your extension details
|
||||
- Configure `winget-resources\setup-template.iss` with your extension information
|
||||
- Move `release-extension.yml` to `.github\workflows\` in your repository root
|
||||
|
||||
4. Commit and push changes to GitHub:
|
||||
|
||||
```powershell
|
||||
git add .
|
||||
git commit -m "Configure extension for WinGet publishing"
|
||||
git push
|
||||
```
|
||||
|
||||
5. Trigger the GitHub Action to build and release:
|
||||
|
||||
```powershell
|
||||
gh workflow run release-extension.yml --ref main -f "release_notes=**First Release of <ExtensionName> Extension for Command Palette**
|
||||
|
||||
The inaugural release of the <ExtensionName> for Command Palette..."
|
||||
```
|
||||
|
||||
Or create a release manually through the GitHub web interface.
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Command Palette Extension Publishing Documentation](https://learn.microsoft.com/en-us/windows/powertoys/command-palette/publish-extension)
|
||||
- [Microsoft Store Publishing Guide](https://learn.microsoft.com/windows/apps/publish/)
|
||||
@@ -1,72 +0,0 @@
|
||||
# Publication Setup
|
||||
|
||||
This folder contains tools to help you prepare your CmdPal extension for publication to the Microsoft Store.
|
||||
|
||||
## Files in this Folder
|
||||
|
||||
- **`one-time-store-pubishing-setup.ps1`** - Configure your project for Microsoft Store publishing
|
||||
- **`build-msix-bundles.ps1`** - Automated script to build MSIX packages and create bundles
|
||||
- **`bundle_mapping.txt`** - Auto-generated mapping file for MSIX bundle creation (updated by build script)
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Open PowerShell and navigate to the Publication folder:
|
||||
|
||||
```powershell
|
||||
cd <YourProject>\Publication
|
||||
```
|
||||
|
||||
2. Run the one-time setup script:
|
||||
|
||||
```powershell
|
||||
.\one-time-store-pubishing-setup.ps1
|
||||
```
|
||||
|
||||
3. Follow the prompts to enter your Microsoft Store information from Partner Center:
|
||||
- Package Identity Name
|
||||
- Publisher Certificate
|
||||
- Display Name
|
||||
- Publisher Display Name
|
||||
|
||||
4. Once configured, build your bundle:
|
||||
|
||||
```powershell
|
||||
.\build-msix-bundles.ps1
|
||||
```
|
||||
|
||||
- Build x64 and ARM64 MSIX packages
|
||||
- Automatically update `bundle_mapping.txt` with the correct paths
|
||||
- Create a combined MSIX bundle
|
||||
- Display the bundle location when complete
|
||||
|
||||
5. Upload the resulting `.msixbundle` file to Partner Center
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### makeappx.exe not found
|
||||
|
||||
The build script requires the Windows SDK. Install it via:
|
||||
|
||||
- Visual Studio Installer (Individual Components → Windows SDK)
|
||||
- [Standalone Windows SDK](https://developer.microsoft.com/windows/downloads/windows-sdk/)
|
||||
|
||||
### Build errors
|
||||
|
||||
Ensure you have:
|
||||
|
||||
- .NET 9.0 SDK installed
|
||||
- Windows SDK 10.0.26100.0 or compatible version
|
||||
- No other instances of Visual Studio building the project
|
||||
|
||||
### Bundle creation fails
|
||||
|
||||
Check that:
|
||||
|
||||
- Both x64 and ARM64 builds completed successfully
|
||||
- `bundle_mapping.txt` paths are correct (auto-updated by script)
|
||||
- No file locks on the MSIX files
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Command Palette Extension Publishing Documentation](https://learn.microsoft.com/en-us/windows/powertoys/command-palette/publish-extension)
|
||||
- [Microsoft Store Publishing Guide](https://learn.microsoft.com/windows/apps/publish/)
|
||||
@@ -10,7 +10,7 @@ Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " CmdPal Extension MSIX Bundle Builder" -ForegroundColor Cyan
|
||||
Write-Host " CmdPal Extension MSIX Builder" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
@@ -70,6 +70,52 @@ catch {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Ask user what to build
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Build Options" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "What would you like to build?" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " [1] x64 MSIX only" -ForegroundColor White
|
||||
Write-Host " [2] ARM64 MSIX only" -ForegroundColor White
|
||||
Write-Host " [3] Complete Bundle (x64 + ARM64 + Bundle file)" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "Enter your choice (1-3): " -ForegroundColor Yellow -NoNewline
|
||||
$buildChoice = Read-Host
|
||||
Write-Host ""
|
||||
|
||||
# Validate choice
|
||||
if ($buildChoice -notmatch '^[1-3]$') {
|
||||
Write-Host "ERROR: Invalid choice. Please enter 1, 2, or 3." -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Determine what to build
|
||||
$buildX64 = $false
|
||||
$buildARM64 = $false
|
||||
$createBundle = $false
|
||||
|
||||
switch ($buildChoice) {
|
||||
"1" {
|
||||
$buildX64 = $true
|
||||
Write-Host "Building: x64 MSIX only" -ForegroundColor Cyan
|
||||
}
|
||||
"2" {
|
||||
$buildARM64 = $true
|
||||
Write-Host "Building: ARM64 MSIX only" -ForegroundColor Cyan
|
||||
}
|
||||
"3" {
|
||||
$buildX64 = $true
|
||||
$buildARM64 = $true
|
||||
$createBundle = $true
|
||||
Write-Host "Building: Complete Bundle (x64 + ARM64 + Bundle)" -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# Clean previous builds (optional)
|
||||
Write-Host "Do you want to clean previous builds? (Y/N): " -ForegroundColor Yellow -NoNewline
|
||||
$cleanBuilds = Read-Host
|
||||
@@ -88,16 +134,19 @@ if ($cleanBuilds -match '^[Yy]') {
|
||||
}
|
||||
}
|
||||
|
||||
# Clean old bundles in Publication folder
|
||||
$oldBundles = Get-ChildItem $PSScriptRoot -Filter "*.msixbundle" -ErrorAction SilentlyContinue
|
||||
if ($oldBundles) {
|
||||
foreach ($bundle in $oldBundles) {
|
||||
try {
|
||||
Remove-Item $bundle.FullName -Force -ErrorAction Stop
|
||||
Write-Host " [OK] Removed old bundle: $($bundle.Name)" -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Host " [WARNING] Could not remove $($bundle.Name): $($_.Exception.Message)" -ForegroundColor Yellow
|
||||
# Clean old bundles in microsoft-store-resources folder
|
||||
$microsoftStoreResourcesPath = Join-Path $PSScriptRoot "microsoft-store-resources"
|
||||
if (Test-Path $microsoftStoreResourcesPath) {
|
||||
$oldBundles = Get-ChildItem $microsoftStoreResourcesPath -Filter "*.msixbundle" -ErrorAction SilentlyContinue
|
||||
if ($oldBundles) {
|
||||
foreach ($bundle in $oldBundles) {
|
||||
try {
|
||||
Remove-Item $bundle.FullName -Force -ErrorAction Stop
|
||||
Write-Host " [OK] Removed old bundle: $($bundle.Name)" -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Host " [WARNING] Could not remove $($bundle.Name): $($_.Exception.Message)" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,316 +157,414 @@ else {
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Build x64 MSIX
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Step 1: Building x64 MSIX Package" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Running: dotnet build (x64)..." -ForegroundColor Yellow
|
||||
Write-Host "This may take a few seconds" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
# Track built files for summary
|
||||
$builtFiles = @()
|
||||
$x64Msix = $null
|
||||
$arm64Msix = $null
|
||||
|
||||
Push-Location $projectRoot
|
||||
try {
|
||||
$buildOutput = & dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=x64 -p:AppxPackageDir="AppPackages\x64\" 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
# Build x64 MSIX (if requested)
|
||||
if ($buildX64) {
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Building x64 MSIX Package" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Running: dotnet build (x64)..." -ForegroundColor Yellow
|
||||
Write-Host "This may take a few seconds" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Push-Location $projectRoot
|
||||
try {
|
||||
$buildOutput = & dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=x64 -p:AppxPackageDir="AppPackages\x64\" 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: x64 build failed with exit code $LASTEXITCODE" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Build output:" -ForegroundColor Gray
|
||||
$buildOutput | ForEach-Object { Write-Host " $_" -ForegroundColor Gray }
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
Pop-Location
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " [SUCCESS] x64 build completed" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: x64 build failed with exit code $LASTEXITCODE" -ForegroundColor Red
|
||||
}
|
||||
catch {
|
||||
Write-Host ""
|
||||
Write-Host "Build output:" -ForegroundColor Gray
|
||||
$buildOutput | ForEach-Object { Write-Host " $_" -ForegroundColor Gray }
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
Write-Host "ERROR: x64 build failed: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " [SUCCESS] x64 build completed" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: x64 build failed: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Build ARM64 MSIX
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Step 2: Building ARM64 MSIX Package" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Running: dotnet build (ARM64)..." -ForegroundColor Yellow
|
||||
Write-Host "This may take a few seconds" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Push-Location $projectRoot
|
||||
try {
|
||||
$buildOutput = & dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=ARM64 -p:AppxPackageDir="AppPackages\ARM64\" 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: ARM64 build failed with exit code $LASTEXITCODE" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Build output:" -ForegroundColor Gray
|
||||
$buildOutput | ForEach-Object { Write-Host " $_" -ForegroundColor Gray }
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
# Build ARM64 MSIX (if requested)
|
||||
if ($buildARM64) {
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Building ARM64 MSIX Package" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Running: dotnet build (ARM64)..." -ForegroundColor Yellow
|
||||
Write-Host "This may take a few seconds" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Push-Location $projectRoot
|
||||
try {
|
||||
$buildOutput = & dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=ARM64 -p:AppxPackageDir="AppPackages\ARM64\" 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: ARM64 build failed with exit code $LASTEXITCODE" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Build output:" -ForegroundColor Gray
|
||||
$buildOutput | ForEach-Object { Write-Host " $_" -ForegroundColor Gray }
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
Pop-Location
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " [SUCCESS] ARM64 build completed" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: ARM64 build failed: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " [SUCCESS] ARM64 build completed" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: ARM64 build failed: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Locate MSIX files
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Step 3: Locating MSIX Files" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
Push-Location $projectRoot
|
||||
try {
|
||||
$msixFiles = Get-ChildItem "AppPackages" -Recurse -Filter "*.msix" -ErrorAction SilentlyContinue
|
||||
|
||||
if (-not $msixFiles) {
|
||||
# Try alternate location
|
||||
Write-Host " MSIX files not found in AppPackages, checking bin folder..." -ForegroundColor Yellow
|
||||
$msixFiles = Get-ChildItem "bin" -Recurse -Filter "*.msix" -ErrorAction SilentlyContinue
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
if (-not $msixFiles -or $msixFiles.Count -lt 2) {
|
||||
Write-Host "ERROR: Could not find both x64 and ARM64 MSIX files" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Expected files:" -ForegroundColor Gray
|
||||
Write-Host " - ${packageName}_${packageVersion}_x64.msix" -ForegroundColor Gray
|
||||
Write-Host " - ${packageName}_${packageVersion}_arm64.msix" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Locate MSIX files (if bundle creation is needed or for summary)
|
||||
if ($createBundle -or $buildX64 -or $buildARM64) {
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Locating MSIX Files" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
Push-Location $projectRoot
|
||||
try {
|
||||
$msixFiles = Get-ChildItem "AppPackages" -Recurse -Filter "*.msix" -ErrorAction SilentlyContinue
|
||||
|
||||
if (-not $msixFiles) {
|
||||
# Try alternate location
|
||||
Write-Host " MSIX files not found in AppPackages, checking bin folder..." -ForegroundColor Yellow
|
||||
$msixFiles = Get-ChildItem "bin" -Recurse -Filter "*.msix" -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
if ($buildX64 -and $buildARM64 -and $createBundle -and (-not $msixFiles -or $msixFiles.Count -lt 2)) {
|
||||
Write-Host "ERROR: Could not find both x64 and ARM64 MSIX files" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Expected files:" -ForegroundColor Gray
|
||||
Write-Host " - ${packageName}_${packageVersion}_x64.msix" -ForegroundColor Gray
|
||||
Write-Host " - ${packageName}_${packageVersion}_arm64.msix" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
if ($msixFiles) {
|
||||
Write-Host "Found files:" -ForegroundColor Yellow
|
||||
$msixFiles | ForEach-Object { Write-Host " - $($_.FullName)" -ForegroundColor Gray }
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($msixFiles) {
|
||||
Write-Host "Found files:" -ForegroundColor Yellow
|
||||
$msixFiles | ForEach-Object { Write-Host " - $($_.FullName)" -ForegroundColor Gray }
|
||||
Write-Host " Found MSIX files:" -ForegroundColor Green
|
||||
$msixFiles | ForEach-Object {
|
||||
$relativePath = $_.FullName -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
Write-Host " [OK] $relativePath" -ForegroundColor White
|
||||
}
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Find specific x64 and ARM64 files
|
||||
if ($buildX64) {
|
||||
$x64Msix = $msixFiles | Where-Object { $_.Name -match "_x64\.msix$" } | Select-Object -First 1
|
||||
if ($x64Msix) {
|
||||
$builtFiles += $x64Msix.FullName
|
||||
}
|
||||
}
|
||||
|
||||
if ($buildARM64) {
|
||||
$arm64Msix = $msixFiles | Where-Object { $_.Name -match "_arm64\.msix$" } | Select-Object -First 1
|
||||
if ($arm64Msix) {
|
||||
$builtFiles += $arm64Msix.FullName
|
||||
}
|
||||
}
|
||||
|
||||
# Validate files for bundle creation
|
||||
if ($createBundle) {
|
||||
if (-not $x64Msix) {
|
||||
Write-Host "ERROR: Could not find x64 MSIX file" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not $arm64Msix) {
|
||||
Write-Host "ERROR: Could not find ARM64 MSIX file" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " Found MSIX files:" -ForegroundColor Green
|
||||
$msixFiles | ForEach-Object {
|
||||
$relativePath = $_.FullName -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
Write-Host " [OK] $relativePath" -ForegroundColor White
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# Find specific x64 and ARM64 files
|
||||
$x64Msix = $msixFiles | Where-Object { $_.Name -match "_x64\.msix$" } | Select-Object -First 1
|
||||
$arm64Msix = $msixFiles | Where-Object { $_.Name -match "_arm64\.msix$" } | Select-Object -First 1
|
||||
|
||||
if (-not $x64Msix) {
|
||||
Write-Host "ERROR: Could not find x64 MSIX file" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not $arm64Msix) {
|
||||
Write-Host "ERROR: Could not find ARM64 MSIX file" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Update bundle_mapping.txt
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Step 4: Updating bundle_mapping.txt" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
$bundleMappingPath = Join-Path $PSScriptRoot "bundle_mapping.txt"
|
||||
|
||||
# Get relative paths from project root
|
||||
$x64RelativePath = $x64Msix.FullName -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
$arm64RelativePath = $arm64Msix.FullName -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
|
||||
# Create bundle mapping content
|
||||
$line1 = "`"$x64RelativePath`" `"$($x64Msix.Name)`""
|
||||
$line2 = "`"$arm64RelativePath`" `"$($arm64Msix.Name)`""
|
||||
$bundleMappingContent = "[Files]`r`n$line1`r`n$line2"
|
||||
|
||||
try {
|
||||
Set-Content -Path $bundleMappingPath -Value $bundleMappingContent -NoNewline -ErrorAction Stop
|
||||
Write-Host " [SUCCESS] bundle_mapping.txt updated" -ForegroundColor Green
|
||||
# Create bundle (if requested)
|
||||
if ($createBundle) {
|
||||
# Update bundle_mapping.txt
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Updating bundle_mapping.txt" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Content:" -ForegroundColor Gray
|
||||
Write-Host " [Files]" -ForegroundColor DarkGray
|
||||
Write-Host (' "' + $x64RelativePath + '" "' + $x64Msix.Name + '"') -ForegroundColor DarkGray
|
||||
Write-Host (' "' + $arm64RelativePath + '" "' + $arm64Msix.Name + '"') -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host " [ERROR] Could not update bundle_mapping.txt: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host " Continuing with bundle creation..." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Find makeappx.exe
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Step 5: Creating MSIX Bundle" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
$microsoftStoreResourcesPath = Join-Path $PSScriptRoot "microsoft-store-resources"
|
||||
$bundleMappingPath = Join-Path $microsoftStoreResourcesPath "bundle_mapping.txt"
|
||||
|
||||
Write-Host "Locating makeappx.exe..." -ForegroundColor Yellow
|
||||
# Ensure microsoft-store-resources directory exists
|
||||
if (-not (Test-Path $microsoftStoreResourcesPath)) {
|
||||
Write-Host " Creating microsoft-store-resources folder..." -ForegroundColor Yellow
|
||||
try {
|
||||
New-Item -Path $microsoftStoreResourcesPath -ItemType Directory -Force | Out-Null
|
||||
Write-Host " [OK] Folder created" -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Host " [ERROR] Could not create folder: $($_.Exception.Message)" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
$arch = switch ($env:PROCESSOR_ARCHITECTURE) {
|
||||
"AMD64" { "x64" }
|
||||
"x86" { "x86" }
|
||||
"ARM64" { "arm64" }
|
||||
default { "x64" }
|
||||
}
|
||||
# Get relative paths from project root
|
||||
$x64RelativePath = $x64Msix.FullName -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
$arm64RelativePath = $arm64Msix.FullName -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
|
||||
Write-Host " Detected architecture: $arch" -ForegroundColor Gray
|
||||
# Create bundle mapping content
|
||||
$line1 = "`"$x64RelativePath`" `"$($x64Msix.Name)`""
|
||||
$line2 = "`"$arm64RelativePath`" `"$($arm64Msix.Name)`""
|
||||
$bundleMappingContent = "[Files]`r`n$line1`r`n$line2"
|
||||
|
||||
$makeappxPath = Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\$arch\makeappx.exe" -ErrorAction SilentlyContinue |
|
||||
Sort-Object Name -Descending |
|
||||
Select-Object -First 1
|
||||
|
||||
if (-not $makeappxPath) {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: makeappx.exe not found" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "makeappx.exe is part of the Windows SDK." -ForegroundColor Yellow
|
||||
Write-Host "Please install the Windows SDK from:" -ForegroundColor Yellow
|
||||
Write-Host " https://developer.microsoft.com/windows/downloads/windows-sdk/" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Or ensure the Windows SDK is installed with Visual Studio." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " [OK] Found: $($makeappxPath.FullName)" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Create bundle
|
||||
$bundleFileName = "${packageName}_${packageVersion}_Bundle.msixbundle"
|
||||
$bundleOutputPath = Join-Path $PSScriptRoot $bundleFileName
|
||||
|
||||
Write-Host "Creating bundle: $bundleFileName" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Push-Location $projectRoot
|
||||
try {
|
||||
# Use the bundle_mapping.txt file
|
||||
$bundleMappingRelative = Join-Path "Publication" "bundle_mapping.txt"
|
||||
|
||||
$makeappxArgs = @(
|
||||
"bundle",
|
||||
"/v",
|
||||
"/f", $bundleMappingRelative,
|
||||
"/p", $bundleOutputPath
|
||||
)
|
||||
|
||||
Write-Host " Running: makeappx $($makeappxArgs -join ' ')" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
$bundleOutput = & $makeappxPath.FullName $makeappxArgs 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
try {
|
||||
Set-Content -Path $bundleMappingPath -Value $bundleMappingContent -NoNewline -ErrorAction Stop
|
||||
Write-Host " [SUCCESS] bundle_mapping.txt updated" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: Bundle creation failed with exit code $LASTEXITCODE" -ForegroundColor Red
|
||||
Write-Host " Content:" -ForegroundColor Gray
|
||||
Write-Host " [Files]" -ForegroundColor DarkGray
|
||||
Write-Host (' "' + $x64RelativePath + '" "' + $x64Msix.Name + '"') -ForegroundColor DarkGray
|
||||
Write-Host (' "' + $arm64RelativePath + '" "' + $arm64Msix.Name + '"') -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
Write-Host "Output:" -ForegroundColor Gray
|
||||
$bundleOutput | ForEach-Object { Write-Host " $_" -ForegroundColor Gray }
|
||||
}
|
||||
catch {
|
||||
Write-Host " [ERROR] Could not update bundle_mapping.txt: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host " Continuing with bundle creation..." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Find makeappx.exe
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Creating MSIX Bundle" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Locating makeappx.exe..." -ForegroundColor Yellow
|
||||
|
||||
$arch = switch ($env:PROCESSOR_ARCHITECTURE) {
|
||||
"AMD64" { "x64" }
|
||||
"x86" { "x86" }
|
||||
"ARM64" { "arm64" }
|
||||
default { "x64" }
|
||||
}
|
||||
|
||||
Write-Host " Detected architecture: $arch" -ForegroundColor Gray
|
||||
|
||||
$makeappxPath = Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\$arch\makeappx.exe" -ErrorAction SilentlyContinue |
|
||||
Sort-Object Name -Descending |
|
||||
Select-Object -First 1
|
||||
|
||||
if (-not $makeappxPath) {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: makeappx.exe not found" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "makeappx.exe is part of the Windows SDK." -ForegroundColor Yellow
|
||||
Write-Host "Please install the Windows SDK from:" -ForegroundColor Yellow
|
||||
Write-Host " https://developer.microsoft.com/windows/downloads/windows-sdk/" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Or ensure the Windows SDK is installed with Visual Studio." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " [OK] Found: $($makeappxPath.FullName)" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Create bundle
|
||||
$bundleFileName = "${packageName}_${packageVersion}_Bundle.msixbundle"
|
||||
$bundleOutputPath = Join-Path $microsoftStoreResourcesPath $bundleFileName
|
||||
|
||||
Write-Host "Creating bundle: $bundleFileName" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Push-Location $projectRoot
|
||||
try {
|
||||
# Use absolute path to bundle_mapping.txt
|
||||
$bundleMappingAbsolute = Join-Path $microsoftStoreResourcesPath "bundle_mapping.txt"
|
||||
|
||||
# Verify the mapping file exists
|
||||
if (-not (Test-Path $bundleMappingAbsolute)) {
|
||||
Write-Host "ERROR: bundle_mapping.txt not found at: $bundleMappingAbsolute" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
$makeappxArgs = @(
|
||||
"bundle",
|
||||
"/v",
|
||||
"/f", "`"$bundleMappingAbsolute`"",
|
||||
"/p", "`"$bundleOutputPath`""
|
||||
)
|
||||
|
||||
Write-Host " Running: makeappx bundle /v /f `"$bundleMappingAbsolute`" /p `"$bundleOutputPath`"" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Run makeappx with proper quoting
|
||||
$bundleOutput = & $makeappxPath.FullName bundle /v /f $bundleMappingAbsolute /p $bundleOutputPath 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: Bundle creation failed with exit code $LASTEXITCODE" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Output:" -ForegroundColor Gray
|
||||
$bundleOutput | ForEach-Object { Write-Host " $_" -ForegroundColor Gray }
|
||||
Write-Host ""
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " [SUCCESS] Bundle created" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: Bundle creation failed: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " [SUCCESS] Bundle created" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: Bundle creation failed: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Pop-Location
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Verify bundle was created
|
||||
if (-not (Test-Path $bundleOutputPath)) {
|
||||
Write-Host "ERROR: Bundle file was not created at expected location" -ForegroundColor Red
|
||||
Write-Host " Expected: $bundleOutputPath" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
# Verify bundle was created
|
||||
if (-not (Test-Path $bundleOutputPath)) {
|
||||
Write-Host "ERROR: Bundle file was not created at expected location" -ForegroundColor Red
|
||||
Write-Host " Expected: $bundleOutputPath" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Get bundle file info
|
||||
$bundleFile = Get-Item $bundleOutputPath
|
||||
$bundleSize = "{0:N2} MB" -f ($bundleFile.Length / 1MB)
|
||||
# Add bundle to built files
|
||||
$builtFiles += $bundleOutputPath
|
||||
}
|
||||
|
||||
# Final Summary
|
||||
Write-Host "================================================================" -ForegroundColor Green
|
||||
Write-Host " BUILD COMPLETED SUCCESSFULLY!" -ForegroundColor Green
|
||||
Write-Host "================================================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Display what was built
|
||||
if ($buildChoice -eq "1") {
|
||||
Write-Host "Built: x64 MSIX Package" -ForegroundColor Cyan
|
||||
}
|
||||
elseif ($buildChoice -eq "2") {
|
||||
Write-Host "Built: ARM64 MSIX Package" -ForegroundColor Cyan
|
||||
}
|
||||
elseif ($buildChoice -eq "3") {
|
||||
Write-Host "Built: Complete Bundle (x64 + ARM64 + Bundle file)" -ForegroundColor Cyan
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Package Information:" -ForegroundColor Yellow
|
||||
Write-Host " Name: $packageName" -ForegroundColor White
|
||||
Write-Host " Version: $packageVersion" -ForegroundColor White
|
||||
Write-Host " Size: $bundleSize" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "MSIX Bundle Location:" -ForegroundColor Yellow
|
||||
Write-Host " $bundleOutputPath" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Individual MSIX Files:" -ForegroundColor Yellow
|
||||
Write-Host " x64: $($x64Msix.FullName)" -ForegroundColor White
|
||||
Write-Host " ARM64: $($arm64Msix.FullName)" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
# Display built files
|
||||
Write-Host "Built Files:" -ForegroundColor Yellow
|
||||
if ($x64Msix) {
|
||||
$x64Size = "{0:N2} MB" -f ((Get-Item $x64Msix.FullName).Length / 1MB)
|
||||
Write-Host " [x64 MSIX]" -ForegroundColor Cyan
|
||||
Write-Host " Location: $($x64Msix.FullName)" -ForegroundColor White
|
||||
Write-Host " Size: $x64Size" -ForegroundColor White
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
if ($arm64Msix) {
|
||||
$arm64Size = "{0:N2} MB" -f ((Get-Item $arm64Msix.FullName).Length / 1MB)
|
||||
Write-Host " [ARM64 MSIX]" -ForegroundColor Cyan
|
||||
Write-Host " Location: $($arm64Msix.FullName)" -ForegroundColor White
|
||||
Write-Host " Size: $arm64Size" -ForegroundColor White
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
if ($createBundle -and (Test-Path $bundleOutputPath)) {
|
||||
$bundleSize = "{0:N2} MB" -f ((Get-Item $bundleOutputPath).Length / 1MB)
|
||||
Write-Host " [MSIX Bundle]" -ForegroundColor Cyan
|
||||
Write-Host " Location: $bundleOutputPath" -ForegroundColor White
|
||||
Write-Host " Size: $bundleSize" -ForegroundColor White
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "================================================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Display appropriate next steps based on what was built
|
||||
Write-Host "Next Steps:" -ForegroundColor Cyan
|
||||
Write-Host " 1. Test the bundle by installing it locally" -ForegroundColor Gray
|
||||
Write-Host " 2. Upload to Microsoft Store Partner Center or" -ForegroundColor Gray
|
||||
Write-Host " 3. Distribute via WinGet" -ForegroundColor Gray
|
||||
if ($createBundle) {
|
||||
Write-Host " 1. Test the bundle by installing it locally" -ForegroundColor Gray
|
||||
Write-Host " 2. Upload the bundle to Microsoft Store Partner Center" -ForegroundColor Gray
|
||||
Write-Host " 3. Or distribute via other channels" -ForegroundColor Gray
|
||||
}
|
||||
else {
|
||||
Write-Host " 1. Test the MSIX package by installing it locally" -ForegroundColor Gray
|
||||
if ($buildX64) {
|
||||
Write-Host " 2. Build ARM64 package (option 2) or complete bundle (option 3)" -ForegroundColor Gray
|
||||
}
|
||||
else {
|
||||
Write-Host " 2. Build x64 package (option 1) or complete bundle (option 3)" -ForegroundColor Gray
|
||||
}
|
||||
Write-Host " 3. Or distribute this individual package" -ForegroundColor Gray
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
|
||||
@@ -435,6 +435,28 @@ Write-Host ""
|
||||
Write-Host " Summary: " -NoNewline -ForegroundColor Cyan
|
||||
Write-Host "$($foundAssets.Count) of $($requiredAssets.Count) assets found" -ForegroundColor White
|
||||
|
||||
# Auto-fix: Copy StoreLogo.scale-100.png to StoreLogo.png if needed
|
||||
$storeLogoPath = Join-Path $assetsPath "StoreLogo.png"
|
||||
$storeLogoScaledPath = Join-Path $assetsPath "StoreLogo.scale-100.png"
|
||||
|
||||
if (-not (Test-Path $storeLogoPath) -and (Test-Path $storeLogoScaledPath)) {
|
||||
Write-Host ""
|
||||
Write-Host " [AUTO-FIX] Creating StoreLogo.png from StoreLogo.scale-100.png..." -ForegroundColor Cyan
|
||||
try {
|
||||
Copy-Item $storeLogoScaledPath -Destination $storeLogoPath -Force -ErrorAction Stop
|
||||
Write-Host " [SUCCESS] StoreLogo.png created successfully" -ForegroundColor Green
|
||||
|
||||
# Update the missing/found counts
|
||||
$missingAssets = $missingAssets | Where-Object { $_.Name -ne "StoreLogo.png" }
|
||||
if ($foundAssets -notcontains "StoreLogo.png") {
|
||||
$foundAssets += "StoreLogo.png"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " [ERROR] Could not copy file: $($_.Exception.Message)" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
if ($missingAssets.Count -gt 0) {
|
||||
Write-Host ""
|
||||
Write-Host " [WARNING] $($missingAssets.Count) asset(s) missing" -ForegroundColor Yellow
|
||||
@@ -793,5 +815,15 @@ else {
|
||||
Write-Host " All configuration and assets are in place." -ForegroundColor Green
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host "Next Steps:" -ForegroundColor Cyan
|
||||
Write-Host " 1. Build MSIX bundles by running:" -ForegroundColor Gray
|
||||
Write-Host " .\build-msix-bundles.ps1" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " 2. Upload the bundle to Microsoft Store Partner Center" -ForegroundColor Gray
|
||||
Write-Host " (Located in Publication\ folder after build)" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
Write-Host " 3. Follow submission instructions at:" -ForegroundColor Gray
|
||||
Write-Host " https://learn.microsoft.com/windows/powertoys/command-palette/publish-extension" -ForegroundColor DarkCyan
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
@@ -0,0 +1,512 @@
|
||||
# One-Time WinGet Publication Setup Script for CmdPal Extension
|
||||
# This script collects information and updates files needed for WinGet publication via EXE installer
|
||||
# Version: 1.0
|
||||
|
||||
#Requires -Version 5.1
|
||||
|
||||
|
||||
# Enable strict mode for better error detection
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " WinGet Publication Setup (EXE Installer)" -ForegroundColor Cyan
|
||||
Write-Host " CmdPal Extension Publisher" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Path to the project files
|
||||
$publicationRoot = $PSScriptRoot
|
||||
$projectRoot = Split-Path -Parent $publicationRoot
|
||||
$projectName = Split-Path -Leaf $projectRoot
|
||||
$wingetResourcesPath = Join-Path $PSScriptRoot "winget-resources"
|
||||
|
||||
Write-Host "Validating project structure..." -ForegroundColor Cyan
|
||||
Write-Host " Publication Root: $publicationRoot" -ForegroundColor Gray
|
||||
Write-Host " Project Root: $projectRoot" -ForegroundColor Gray
|
||||
Write-Host " Project Name: $projectName" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Verify required files exist
|
||||
$csprojPath = Join-Path $projectRoot "$projectName.csproj"
|
||||
$manifestPath = Join-Path $projectRoot "Package.appxmanifest"
|
||||
$extensionCsPath = Join-Path $projectRoot "$projectName.cs"
|
||||
|
||||
$buildExePath = Join-Path $wingetResourcesPath "build-exe.ps1"
|
||||
$setupTemplatePath = Join-Path $wingetResourcesPath "setup-template.iss"
|
||||
$releaseYmlPath = Join-Path $wingetResourcesPath "release-extension.yml"
|
||||
|
||||
if (-not (Test-Path $csprojPath)) {
|
||||
Write-Host "ERROR: Could not find .csproj file at: $csprojPath" -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path $manifestPath)) {
|
||||
Write-Host "ERROR: Could not find Package.appxmanifest at: $manifestPath" -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path $buildExePath)) {
|
||||
Write-Host "ERROR: Could not find build-exe.ps1 at: $buildExePath" -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path $setupTemplatePath)) {
|
||||
Write-Host "ERROR: Could not find setup-template.iss at: $setupTemplatePath" -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path $releaseYmlPath)) {
|
||||
Write-Host "ERROR: Could not find release-extension.yml at: $releaseYmlPath" -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " [OK] All required files found" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Create backup directory
|
||||
$backupDir = Join-Path $wingetResourcesPath "Backups"
|
||||
if (-not (Test-Path $backupDir)) {
|
||||
try {
|
||||
New-Item -Path $backupDir -ItemType Directory -Force | Out-Null
|
||||
Write-Host "Created backup directory: $backupDir" -ForegroundColor Gray
|
||||
}
|
||||
catch {
|
||||
Write-Host "WARNING: Could not create backup directory. Proceeding without backups." -ForegroundColor Yellow
|
||||
$backupDir = $null
|
||||
}
|
||||
}
|
||||
|
||||
# Create timestamped backups
|
||||
if ($backupDir) {
|
||||
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
||||
try {
|
||||
Copy-Item $buildExePath -Destination (Join-Path $backupDir "build-exe.ps1.$timestamp.bak") -Force
|
||||
Copy-Item $setupTemplatePath -Destination (Join-Path $backupDir "setup-template.iss.$timestamp.bak") -Force
|
||||
Copy-Item $releaseYmlPath -Destination (Join-Path $backupDir "release-extension.yml.$timestamp.bak") -Force
|
||||
Write-Host "Backups created: $timestamp" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host "WARNING: Could not create backup files. Proceeding anyway." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
}
|
||||
}
|
||||
|
||||
# Read existing project information
|
||||
Write-Host "Reading project information..." -ForegroundColor Cyan
|
||||
try {
|
||||
[xml]$manifest = Get-Content $manifestPath -ErrorAction Stop
|
||||
$packageName = $manifest.Package.Identity.Name
|
||||
$packageVersion = $manifest.Package.Identity.Version
|
||||
$displayName = $manifest.Package.Properties.DisplayName
|
||||
$publisherDisplayName = $manifest.Package.Properties.PublisherDisplayName
|
||||
|
||||
Write-Host " Current Package Name: $packageName" -ForegroundColor White
|
||||
Write-Host " Current Version: $packageVersion" -ForegroundColor White
|
||||
Write-Host " Current Display Name: $displayName" -ForegroundColor White
|
||||
Write-Host " Current Publisher: $publisherDisplayName" -ForegroundColor White
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host "ERROR: Could not read Package.appxmanifest: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Extract GUID/CLSID from extension class
|
||||
Write-Host "Reading extension GUID..." -ForegroundColor Cyan
|
||||
try {
|
||||
$extensionCsContent = Get-Content $extensionCsPath -Raw -ErrorAction Stop
|
||||
if ($extensionCsContent -match '\[Guid\("([A-F0-9-]+)"\)\]') {
|
||||
$extensionGuid = $Matches[1]
|
||||
Write-Host " Extension GUID: $extensionGuid" -ForegroundColor White
|
||||
Write-Host ""
|
||||
}
|
||||
else {
|
||||
Write-Host "ERROR: Could not find GUID in $projectName.cs" -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host "ERROR: Could not read $projectName.cs: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "This script will configure your extension for WinGet publication using EXE installer." -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "The following information will be collected:" -ForegroundColor White
|
||||
Write-Host " - GitHub Repository URL (for releases)" -ForegroundColor Gray
|
||||
Write-Host " - Developer/Publisher Name" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "The script will update:" -ForegroundColor Yellow
|
||||
Write-Host " - build-exe.ps1 (build script)" -ForegroundColor Gray
|
||||
Write-Host " - setup-template.iss (Inno Setup installer script)" -ForegroundColor Gray
|
||||
Write-Host " - release-extension.yml (GitHub Actions workflow)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Function to validate URL
|
||||
function Test-GitHubUrl {
|
||||
param([string]$url)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($url)) { return $false }
|
||||
if ($url -notmatch '^https://github\.com/[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+/?$') { return $false }
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
# Function to validate developer name
|
||||
function Test-DeveloperName {
|
||||
param([string]$name)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($name)) { return $false }
|
||||
if ($name.Length -lt 1 -or $name.Length -gt 256) { return $false }
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
# Prompt to continue
|
||||
Write-Host "Do you want to continue? (Y/N): " -ForegroundColor Yellow -NoNewline
|
||||
$continue = Read-Host
|
||||
if ($continue -notmatch '^[Yy]') {
|
||||
Write-Host ""
|
||||
Write-Host "Setup cancelled by user." -ForegroundColor Yellow
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 0
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# Collect GitHub Repository URL
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Step 1: GitHub Repository URL" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Enter your GitHub repository URL:" -ForegroundColor Yellow
|
||||
Write-Host " This is where your extension's releases will be published." -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " Format: https://github.com/username/repository" -ForegroundColor DarkGray
|
||||
Write-Host " Example: https://github.com/johndoe/MyAwesomeExtension" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
|
||||
$githubRepoUrl = ""
|
||||
$maxAttempts = 3
|
||||
$attempt = 0
|
||||
|
||||
do {
|
||||
$attempt++
|
||||
Write-Host "GitHub Repository URL" -NoNewline -ForegroundColor Yellow
|
||||
if ($attempt -gt 1) {
|
||||
Write-Host " (Attempt $attempt of $maxAttempts)" -NoNewline -ForegroundColor Red
|
||||
}
|
||||
Write-Host ": " -NoNewline -ForegroundColor Yellow
|
||||
$githubRepoUrl = Read-Host
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($githubRepoUrl)) {
|
||||
Write-Host " [ERROR] GitHub Repository URL cannot be empty." -ForegroundColor Red
|
||||
Write-Host ""
|
||||
}
|
||||
elseif (-not (Test-GitHubUrl $githubRepoUrl)) {
|
||||
Write-Host " [ERROR] Invalid GitHub URL format." -ForegroundColor Red
|
||||
Write-Host " Please use format: https://github.com/username/repository" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
}
|
||||
else {
|
||||
Write-Host " [OK] GitHub Repository URL accepted: $githubRepoUrl" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
break
|
||||
}
|
||||
|
||||
if ($attempt -ge $maxAttempts) {
|
||||
Write-Host ""
|
||||
Write-Host "Maximum attempts reached. Please try again with a valid GitHub URL." -ForegroundColor Red
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
} while ($true)
|
||||
|
||||
# Collect Developer Name
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Step 2: Developer/Publisher Name" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Enter your developer or publisher name:" -ForegroundColor Yellow
|
||||
Write-Host " This will appear in the EXE installer as the publisher." -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " IMPORTANT: If you published to Microsoft Store, this should match" -ForegroundColor Yellow
|
||||
Write-Host " the PublisherDisplayName from your Store configuration." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " Example: John Doe" -ForegroundColor DarkGray
|
||||
Write-Host " Example: Contoso Software" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
Write-Host " Current value from manifest: $publisherDisplayName" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
$developerName = ""
|
||||
$attempt = 0
|
||||
|
||||
do {
|
||||
$attempt++
|
||||
Write-Host "Developer Name" -NoNewline -ForegroundColor Yellow
|
||||
if ($attempt -gt 1) {
|
||||
Write-Host " (Attempt $attempt of $maxAttempts)" -NoNewline -ForegroundColor Red
|
||||
}
|
||||
Write-Host " [press Enter to use default]: " -NoNewline -ForegroundColor Yellow
|
||||
$input = Read-Host
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($input)) {
|
||||
$developerName = $publisherDisplayName
|
||||
Write-Host " [OK] Using default: $developerName" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
break
|
||||
}
|
||||
elseif (-not (Test-DeveloperName $input)) {
|
||||
Write-Host " [ERROR] Invalid developer name." -ForegroundColor Red
|
||||
Write-Host ""
|
||||
}
|
||||
else {
|
||||
$developerName = $input
|
||||
Write-Host " [OK] Developer name accepted: $developerName" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
break
|
||||
}
|
||||
|
||||
if ($attempt -ge $maxAttempts) {
|
||||
Write-Host ""
|
||||
Write-Host "Maximum attempts reached. Using default: $publisherDisplayName" -ForegroundColor Yellow
|
||||
$developerName = $publisherDisplayName
|
||||
Write-Host ""
|
||||
break
|
||||
}
|
||||
} while ($true)
|
||||
|
||||
# Update files
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Updating Configuration Files..." -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Update build-exe.ps1
|
||||
Write-Host "[1/3] Updating build-exe.ps1..." -ForegroundColor Cyan
|
||||
try {
|
||||
$buildExeContent = Get-Content $buildExePath -Raw -ErrorAction Stop
|
||||
|
||||
# Update ExtensionName default value
|
||||
$buildExeContent = $buildExeContent -replace '\[string\]\$ExtensionName = "UPDATE"', "[string]`$ExtensionName = `"$projectName`""
|
||||
|
||||
# Update Version default value
|
||||
$buildExeContent = $buildExeContent -replace '\[string\]\$Version = "UPDATE"', "[string]`$Version = `"$packageVersion`""
|
||||
|
||||
Set-Content -Path $buildExePath -Value $buildExeContent -NoNewline -ErrorAction Stop
|
||||
Write-Host " [SUCCESS] build-exe.ps1 updated" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host " [ERROR] Could not update build-exe.ps1: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Update setup-template.iss
|
||||
Write-Host "[2/3] Updating setup-template.iss..." -ForegroundColor Cyan
|
||||
try {
|
||||
$setupTemplateContent = Get-Content $setupTemplatePath -Raw -ErrorAction Stop
|
||||
|
||||
# Update version
|
||||
$setupTemplateContent = $setupTemplateContent -replace '#define AppVersion ".*"', "#define AppVersion `"$packageVersion`""
|
||||
|
||||
# Update AppId GUID
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'AppId=\{\{GUID-HERE\}\}', "AppId={{$extensionGuid}}"
|
||||
|
||||
# Update AppName (DISPLAY_NAME)
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'AppName=DISPLAY_NAME', "AppName=$displayName"
|
||||
|
||||
# Update AppPublisher (DEVELOPER_NAME)
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'AppPublisher=DEVELOPER_NAME', "AppPublisher=$developerName"
|
||||
|
||||
# Update DefaultDirName (EXTENSION_NAME)
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'DefaultDirName=\{autopf\}\\EXTENSION_NAME', "DefaultDirName={autopf}\$projectName"
|
||||
|
||||
# Update OutputBaseFilename (EXTENSION_NAME)
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'OutputBaseFilename=EXTENSION_NAME-Setup', "OutputBaseFilename=$projectName-Setup"
|
||||
|
||||
# Update Icon name (DISPLAY_NAME)
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'Name: "\{group\}\\DISPLAY_NAME"', "Name: `"{group}\$displayName`""
|
||||
|
||||
# Update Icon filename (EXTENSION_NAME)
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'Filename: "\{app\}\\EXTENSION_NAME\.exe"', "Filename: `"{app}\$projectName.exe`""
|
||||
|
||||
# Update Registry CLSID entries
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'CLSID\\CLSID-HERE', "CLSID\{{$extensionGuid}}"
|
||||
$setupTemplateContent = $setupTemplateContent -replace '\{\{CLSID-HERE\}\}', "{{$extensionGuid}}"
|
||||
|
||||
# Update Registry ValueData (EXTENSION_NAME)
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'ValueData: "EXTENSION_NAME"', "ValueData: `"$projectName`""
|
||||
|
||||
# Update LocalServer32 ValueData
|
||||
$setupTemplateContent = $setupTemplateContent -replace 'ValueData: "\{app\}\\EXTENSION_NAME\.exe', "ValueData: `"{app}\$projectName.exe"
|
||||
|
||||
Set-Content -Path $setupTemplatePath -Value $setupTemplateContent -NoNewline -ErrorAction Stop
|
||||
Write-Host " [SUCCESS] setup-template.iss updated" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host " [ERROR] Could not update setup-template.iss: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Update release-extension.yml
|
||||
Write-Host "[3/3] Updating release-extension.yml..." -ForegroundColor Cyan
|
||||
try {
|
||||
$releaseYmlContent = Get-Content $releaseYmlPath -Raw -ErrorAction Stop
|
||||
|
||||
# Update workflow name
|
||||
$releaseYmlContent = $releaseYmlContent -replace 'name: CmdPal Extension - Build EXE Installer', "name: $displayName - Build EXE Installer"
|
||||
|
||||
# Update environment variables with actual values
|
||||
$releaseYmlContent = $releaseYmlContent -replace "DISPLAY_NAME: \$\{\{ vars\.DISPLAY_NAME \|\| 'DISPLAY_NAME' \}\}", "DISPLAY_NAME: `${{ vars.DISPLAY_NAME || '$displayName' }}"
|
||||
$releaseYmlContent = $releaseYmlContent -replace "EXTENSION_NAME: \$\{\{ vars\.EXTENSION_NAME \|\| 'EXTENSION_NAME' \}\}", "EXTENSION_NAME: `${{ vars.EXTENSION_NAME || '$projectName' }}"
|
||||
$releaseYmlContent = $releaseYmlContent -replace "FOLDER_NAME: \$\{\{ vars\.FOLDER_NAME \|\| 'FOLDER_NAME' \}\}", "FOLDER_NAME: `${{ vars.FOLDER_NAME || '$projectName' }}"
|
||||
$releaseYmlContent = $releaseYmlContent -replace "GITHUB_REPO_URL: \$\{\{ vars\.GITHUB_REPO_URL \|\| 'GITHUB_REPO_URL' \}\}", "GITHUB_REPO_URL: `${{ vars.GITHUB_REPO_URL || '$githubRepoUrl' }}"
|
||||
|
||||
Set-Content -Path $releaseYmlPath -Value $releaseYmlContent -NoNewline -ErrorAction Stop
|
||||
Write-Host " [SUCCESS] release-extension.yml updated" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host " [ERROR] Could not update release-extension.yml: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Display summary
|
||||
Write-Host "================================================================" -ForegroundColor Green
|
||||
Write-Host " CONFIGURATION SUMMARY" -ForegroundColor White
|
||||
Write-Host "================================================================" -ForegroundColor Green
|
||||
Write-Host " Extension Name:" -ForegroundColor Gray
|
||||
Write-Host " $projectName" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " Display Name:" -ForegroundColor Gray
|
||||
Write-Host " $displayName" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " Version:" -ForegroundColor Gray
|
||||
Write-Host " $packageVersion" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " Developer:" -ForegroundColor Gray
|
||||
Write-Host " $developerName" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " Extension GUID:" -ForegroundColor Gray
|
||||
Write-Host " $extensionGuid" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " GitHub Repository:" -ForegroundColor Gray
|
||||
Write-Host " $githubRepoUrl" -ForegroundColor White
|
||||
Write-Host "================================================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Display modified files
|
||||
Write-Host "Updated Files:" -ForegroundColor Yellow
|
||||
$buildExeRelative = $buildExePath -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
$setupTemplateRelative = $setupTemplatePath -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
$releaseYmlRelative = $releaseYmlPath -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
Write-Host " [OK] $buildExeRelative" -ForegroundColor Green
|
||||
Write-Host " [OK] $setupTemplateRelative" -ForegroundColor Green
|
||||
Write-Host " [OK] $releaseYmlRelative" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
if ($backupDir) {
|
||||
Write-Host "Backup Location:" -ForegroundColor Yellow
|
||||
$backupRelative = $backupDir -replace [regex]::Escape($projectRoot + "\"), ""
|
||||
Write-Host " $backupRelative" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Move files to correct locations
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host " Moving Files to Correct Locations" -ForegroundColor Cyan
|
||||
Write-Host "================================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "The following file will be moved:" -ForegroundColor Yellow
|
||||
Write-Host " - release-extension.yml → .github/workflows/ (2 levels up)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "The following files will remain in winget-resources:" -ForegroundColor Yellow
|
||||
Write-Host " - build-exe.ps1" -ForegroundColor Gray
|
||||
Write-Host " - setup-template.iss" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Calculate destination paths
|
||||
# From: TemplateCmdPalExtension/Publication/winget-resources/
|
||||
# release-extension.yml → TemplateCmdPalExtension/.github/workflows/ (2 levels up from Publication)
|
||||
|
||||
# GitHub workflows directory (2 levels up from Publication)
|
||||
$solutionRoot = Split-Path -Parent $projectRoot
|
||||
$githubWorkflowsDir = Join-Path $solutionRoot ".github\workflows"
|
||||
$releaseYmlDestination = Join-Path $githubWorkflowsDir "release-extension.yml"
|
||||
|
||||
Write-Host "Destination:" -ForegroundColor Yellow
|
||||
Write-Host " release-extension.yml → $releaseYmlDestination" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Move release-extension.yml
|
||||
Write-Host "Moving release-extension.yml..." -ForegroundColor Cyan
|
||||
try {
|
||||
if (-not (Test-Path $githubWorkflowsDir)) {
|
||||
Write-Host " Creating .github/workflows directory..." -ForegroundColor Gray
|
||||
New-Item -Path $githubWorkflowsDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
if (Test-Path $releaseYmlDestination) {
|
||||
Write-Host " [WARNING] Destination file exists, overwriting..." -ForegroundColor Yellow
|
||||
}
|
||||
Move-Item $releaseYmlPath -Destination $releaseYmlDestination -Force -ErrorAction Stop
|
||||
Write-Host " [SUCCESS] Moved to: $releaseYmlDestination" -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Host " [ERROR] Could not move release-extension.yml: $($_.Exception.Message)" -ForegroundColor Red
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# Verify file was moved
|
||||
Write-Host "Verifying file..." -ForegroundColor Cyan
|
||||
|
||||
if (Test-Path $releaseYmlDestination) {
|
||||
Write-Host " [OK] release-extension.yml exists at destination" -ForegroundColor Green
|
||||
}
|
||||
else {
|
||||
Write-Host " [ERROR] release-extension.yml NOT found at destination" -ForegroundColor Red
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# Final instructions
|
||||
Write-Host "================================================================" -ForegroundColor Green
|
||||
Write-Host " Setup Completed Successfully!" -ForegroundColor Green
|
||||
Write-Host "================================================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "Files have been configured:" -ForegroundColor Yellow
|
||||
Write-Host " Updated (in winget-resources):" -ForegroundColor Cyan
|
||||
Write-Host " $buildExePath" -ForegroundColor White
|
||||
Write-Host " $setupTemplatePath" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " Moved to GitHub workflows:" -ForegroundColor Cyan
|
||||
Write-Host " $releaseYmlDestination" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "Next Steps:" -ForegroundColor Cyan
|
||||
Write-Host " 1. Review the configured files to ensure correctness" -ForegroundColor Gray
|
||||
Write-Host " 2. Add and commit files and push to Github" -ForegroundColor Gray
|
||||
Write-Host " 3. Follow instructions at https://learn.microsoft.com//windows/powertoys/command-palette/publish-extension" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
@@ -0,0 +1,114 @@
|
||||
# TEMPLATE: PowerShell Build Script for Command Palette Extensions
|
||||
#
|
||||
# To use this template for a new extension:
|
||||
# 1. Copy this file to your extension's project folder as "build-exe.ps1"
|
||||
# 2. Update in param():
|
||||
# - EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension)
|
||||
# - VERSION with your extension version (e.g., 0.0.1.0)
|
||||
|
||||
|
||||
|
||||
param(
|
||||
[string]$ExtensionName = "UPDATE", # Change to your extension name
|
||||
[string]$Configuration = "Release",
|
||||
[string]$Version = "UPDATE", # Change to your version
|
||||
[string[]]$Platforms = @("x64", "arm64")
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "Building $ExtensionName EXE installer..." -ForegroundColor Green
|
||||
Write-Host "Version: $Version" -ForegroundColor Yellow
|
||||
Write-Host "Platforms: $($Platforms -join ', ')" -ForegroundColor Yellow
|
||||
|
||||
# Get the project directory (two levels up from winget-resources)
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$ProjectDir = Split-Path -Parent (Split-Path -Parent $ScriptDir)
|
||||
$ProjectFile = "$ProjectDir\$ExtensionName.csproj"
|
||||
|
||||
Write-Host "Script directory: $ScriptDir" -ForegroundColor Cyan
|
||||
Write-Host "Project directory: $ProjectDir" -ForegroundColor Cyan
|
||||
|
||||
# Clean previous builds
|
||||
Write-Host "Cleaning previous builds..." -ForegroundColor Yellow
|
||||
if (Test-Path "$ProjectDir\bin") {
|
||||
Remove-Item -Path "$ProjectDir\bin" -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
if (Test-Path "$ProjectDir\obj") {
|
||||
Remove-Item -Path "$ProjectDir\obj" -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
# Restore packages
|
||||
Write-Host "Restoring NuGet packages..." -ForegroundColor Yellow
|
||||
dotnet restore $ProjectFile
|
||||
|
||||
# Build for each platform
|
||||
foreach ($Platform in $Platforms) {
|
||||
Write-Host "`n=== Building $Platform ===" -ForegroundColor Cyan
|
||||
|
||||
# Build and publish
|
||||
Write-Host "Building and publishing $Platform application..." -ForegroundColor Yellow
|
||||
dotnet publish $ProjectFile `
|
||||
--configuration $Configuration `
|
||||
--runtime "win-$Platform" `
|
||||
--self-contained true `
|
||||
--output "$ProjectDir\bin\$Configuration\win-$Platform\publish"
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "Build failed for $Platform with exit code: $LASTEXITCODE"
|
||||
continue
|
||||
}
|
||||
# Check if files were published
|
||||
$publishDir = "$ProjectDir\bin\$Configuration\win-$Platform\publish"
|
||||
$fileCount = (Get-ChildItem -Path $publishDir -Recurse -File).Count
|
||||
Write-Host "✅ Published $fileCount files to $publishDir" -ForegroundColor Green
|
||||
|
||||
# Create platform-specific setup script
|
||||
Write-Host "Creating installer script for $Platform..." -ForegroundColor Yellow
|
||||
$setupTemplate = Get-Content "$ScriptDir\setup-template.iss" -Raw
|
||||
|
||||
# Update version
|
||||
$setupScript = $setupTemplate -replace '#define AppVersion ".*"', "#define AppVersion `"$Version`""
|
||||
|
||||
# Update output filename to include platform suffix
|
||||
$setupScript = $setupScript -replace 'OutputBaseFilename=(.*?)\{#AppVersion\}', "OutputBaseFilename=`$1{#AppVersion}-$Platform"
|
||||
|
||||
# Update source path for the platform
|
||||
$setupScript = $setupScript -replace 'Source: "bin\\Release\\win-x64\\publish', "Source: `"bin\Release\win-$Platform\publish"
|
||||
|
||||
# Add architecture settings after [Setup] section
|
||||
if ($Platform -eq "arm64") {
|
||||
$setupScript = $setupScript -replace '(\[Setup\][^\[]*)(MinVersion=)', "`$1ArchitecturesAllowed=arm64`r`nArchitecturesInstallIn64BitMode=arm64`r`n`$2"
|
||||
} else {
|
||||
$setupScript = $setupScript -replace '(\[Setup\][^\[]*)(MinVersion=)', "`$1ArchitecturesAllowed=x64compatible`r`nArchitecturesInstallIn64BitMode=x64compatible`r`n`$2"
|
||||
}
|
||||
|
||||
$setupScript | Out-File -FilePath "$ProjectDir\setup-$Platform.iss" -Encoding UTF8
|
||||
|
||||
# Create installer with Inno Setup
|
||||
Write-Host "Creating $Platform installer with Inno Setup..." -ForegroundColor Yellow
|
||||
$InnoSetupPath = "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe"
|
||||
if (-not (Test-Path $InnoSetupPath)) {
|
||||
$InnoSetupPath = "${env:ProgramFiles}\Inno Setup 6\iscc.exe"
|
||||
}
|
||||
|
||||
if (Test-Path $InnoSetupPath) {
|
||||
& $InnoSetupPath "$ProjectDir\setup-$Platform.iss"
|
||||
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
$installer = Get-ChildItem "$ProjectDir\bin\$Configuration\installer\*-$Platform.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if ($installer) {
|
||||
$sizeMB = [math]::Round($installer.Length / 1MB, 2)
|
||||
Write-Host "✅ Created $Platform installer: $($installer.Name) ($sizeMB MB)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Warning "Installer file not found for $Platform"
|
||||
}
|
||||
} else {
|
||||
Write-Warning "Inno Setup failed for $Platform with exit code: $LASTEXITCODE"
|
||||
}
|
||||
} else {
|
||||
Write-Warning "Inno Setup not found at expected locations"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`n🎉 Build completed successfully!" -ForegroundColor Green
|
||||
@@ -0,0 +1,127 @@
|
||||
# TEMPLATE: Extension EXE Installer Build and Release Workflow
|
||||
#
|
||||
# To use this template for a new extension:
|
||||
# 1. Copy this file to a new workflow file (e.g., release-myextension-exe.yml)
|
||||
# 2. Update Global constants with your data:
|
||||
# - GITHUB_REPO_URL with your GitHub repository URL (e.g., https://github.com/yourusername/YourRepository)
|
||||
# - DISPLAY_NAME with your display name (e.g., My Extension)
|
||||
# - EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension)
|
||||
# - FOLDER_NAME with your project folder name (e.g., CmdPalMyExtension)
|
||||
|
||||
name: CmdPal Extension - Build EXE Installer
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version number (leave empty to auto-detect)'
|
||||
required: false
|
||||
type: string
|
||||
release_notes:
|
||||
description: 'What is new in this version'
|
||||
required: false
|
||||
default: 'New release with latest updates and improvements.'
|
||||
type: string
|
||||
|
||||
|
||||
# Global constants: UPDATE THESE, example; DISPLAY_NAME: ${{ vars.DISPLAY_NAME || 'CmdPal Name' }}
|
||||
env:
|
||||
DISPLAY_NAME: ${{ vars.DISPLAY_NAME || 'DISPLAY_NAME' }}
|
||||
EXTENSION_NAME: ${{ vars.EXTENSION_NAME || 'EXTENSION_NAME' }}
|
||||
FOLDER_NAME: ${{ vars.FOLDER_NAME || 'FOLDER_NAME' }}
|
||||
GITHUB_REPO_URL: ${{ vars.GITHUB_REPO_URL || 'GITHUB_REPO_URL' }}
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-2022
|
||||
permissions:
|
||||
contents: write
|
||||
actions: read
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET 9
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.0.x'
|
||||
|
||||
- name: Install Inno Setup
|
||||
run: choco install innosetup -y --no-progress
|
||||
shell: pwsh
|
||||
|
||||
- name: Get version from project
|
||||
id: version
|
||||
run: |
|
||||
if ("${{ github.event.inputs.version }}" -ne "") {
|
||||
$version = "${{ github.event.inputs.version }}"
|
||||
} else {
|
||||
$projectFile = "${{ env.FOLDER_NAME }}/${{ env.EXTENSION_NAME }}.csproj"
|
||||
$xml = [xml](Get-Content $projectFile)
|
||||
$version = $xml.Project.PropertyGroup.AppxPackageVersion | Select-Object -First 1
|
||||
if (-not $version) { throw "Version not found in project file" }
|
||||
}
|
||||
echo "VERSION=$version" >> $env:GITHUB_OUTPUT
|
||||
Write-Host "Using version: $version"
|
||||
shell: pwsh
|
||||
|
||||
- name: Build EXE installers (x64 and ARM64)
|
||||
run: |
|
||||
Set-Location "${{ env.FOLDER_NAME }}/Publication/winget-resources"
|
||||
.\build-exe.ps1 -Version "${{ steps.version.outputs.VERSION }}" -Platforms @("x64", "arm64")
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload x64 installer artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.EXTENSION_NAME }}-x64-installer
|
||||
path: ${{ env.FOLDER_NAME }}/bin/Release/installer/*-x64.exe
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload ARM64 installer artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.EXTENSION_NAME }}-arm64-installer
|
||||
path: ${{ env.FOLDER_NAME }}/bin/Release/installer/*-arm64.exe
|
||||
if-no-files-found: warn
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ env.EXTENSION_NAME }}-v${{ steps.version.outputs.VERSION }}
|
||||
name: "${{ env.DISPLAY_NAME }} v${{ steps.version.outputs.VERSION }}"
|
||||
body: |
|
||||
## 🎯 ${{ env.DISPLAY_NAME }} ${{ steps.version.outputs.VERSION }}
|
||||
|
||||
## What's New
|
||||
${{ github.event.inputs.release_notes }}
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
Download the installer for your system architecture:
|
||||
|
||||
- **x64 (Intel/AMD)**: `${{ env.DISPLAY_NAME }}-Setup-${{ steps.version.outputs.VERSION }}-x64.exe`
|
||||
- **ARM64 (Windows on ARM)**: `${{ env.DISPLAY_NAME }}-Setup-${{ steps.version.outputs.VERSION }}-arm64.exe`
|
||||
|
||||
1. Download the appropriate installer from the Assets section below
|
||||
2. Run the installer with administrator privileges
|
||||
3. The extension will be registered and available in Command Palette
|
||||
|
||||
|
||||
## 🔗 More Information
|
||||
|
||||
Repository: ${{ env.GITHUB_REPO_URL }}
|
||||
files: ${{ env.FOLDER_NAME }}/bin/Release/installer/*.exe
|
||||
draft: false
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build summary
|
||||
run: |
|
||||
Write-Host "🎉 ${{ env.DISPLAY_NAME }} Release Complete!" -ForegroundColor Green
|
||||
Write-Host "Version: ${{ steps.version.outputs.VERSION }}" -ForegroundColor Yellow
|
||||
Write-Host "📁 Installer uploaded to GitHub Release" -ForegroundColor Green
|
||||
shell: pwsh
|
||||
@@ -0,0 +1,36 @@
|
||||
; TEMPLATE: Inno Setup Script for Command Palette Extensions
|
||||
;
|
||||
; To use this template for a new extension:
|
||||
; 1. Copy this file to your extension's project folder as "setup-template.iss"
|
||||
; 2. Replace EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension)
|
||||
; 3. Replace DISPLAY_NAME with your extension's display name (e.g., My Extension)
|
||||
; 4. Replace DEVELOPER_NAME with your name (e.g., Your Name Here)
|
||||
; 5. Replace CLSID-HERE with extensions CLSID
|
||||
; 6. Update the default version to match your project file
|
||||
|
||||
#define AppVersion "0.0.1.0"
|
||||
|
||||
[Setup]
|
||||
AppId={{GUID-HERE}}
|
||||
AppName=DISPLAY_NAME
|
||||
AppVersion={#AppVersion}
|
||||
AppPublisher=DEVELOPER_NAME
|
||||
DefaultDirName={autopf}\EXTENSION_NAME
|
||||
OutputDir=bin\Release\installer
|
||||
OutputBaseFilename=EXTENSION_NAME-Setup-{#AppVersion}
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
MinVersion=10.0.19041
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Files]
|
||||
Source: "bin\Release\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\DISPLAY_NAME"; Filename: "{app}\EXTENSION_NAME.exe"
|
||||
|
||||
[Registry]
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}"; ValueData: "EXTENSION_NAME"
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}\LocalServer32"; ValueData: "{app}\EXTENSION_NAME.exe -RegisterProcessAsComServer"
|
||||
Reference in New Issue
Block a user