chore: first version
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
---
|
||||
name: publish-extension
|
||||
description: >-
|
||||
Publish your Command Palette extension to the Microsoft Store or WinGet.
|
||||
Use when asked to publish, distribute, release, deploy to store,
|
||||
create MSIX packages, submit to WinGet, set up CI/CD for releases,
|
||||
or automate builds with GitHub Actions.
|
||||
---
|
||||
|
||||
# Publish Your Command Palette Extension
|
||||
|
||||
Guide for distributing your Command Palette extension through the Microsoft Store, WinGet, or both.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- Publishing your extension to the Microsoft Store
|
||||
- Submitting your extension to WinGet for `winget install` discovery
|
||||
- Setting up GitHub Actions to automate builds and releases
|
||||
- Creating MSIX packages for Store submission
|
||||
- Creating EXE installers for WinGet submission
|
||||
|
||||
## Publishing Options
|
||||
|
||||
| Channel | Package Format | Discovery | Auto-Updates |
|
||||
|---------|---------------|-----------|--------------|
|
||||
| Microsoft Store | MSIX bundle | Store app, `ms-windows-store://` link | Yes |
|
||||
| WinGet | EXE installer | `winget install`, CmdPal browse | Yes (via manifest) |
|
||||
|
||||
**Recommendation**: Publish to both for maximum reach. WinGet enables direct discovery from within Command Palette.
|
||||
|
||||
## Workflows
|
||||
|
||||
### Microsoft Store Publishing
|
||||
See [store-publishing.md](references/store-publishing.md) for the complete step-by-step guide.
|
||||
|
||||
**Summary:**
|
||||
1. Register for Partner Center
|
||||
2. Update `Package.appxmanifest` and `.csproj` with Partner Center identity
|
||||
3. Build MSIX for x64 and ARM64
|
||||
4. Create MSIX bundle
|
||||
5. Submit to Partner Center
|
||||
|
||||
### WinGet Publishing
|
||||
See [winget-publishing.md](references/winget-publishing.md) for the complete step-by-step guide.
|
||||
|
||||
**Summary:**
|
||||
1. Switch project to unpackaged mode
|
||||
2. Create Inno Setup installer script
|
||||
3. Build EXE installers
|
||||
4. Submit manifest via `wingetcreate new`
|
||||
5. Optionally automate with GitHub Actions
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Visual Studio](https://visualstudio.microsoft.com/) with C# and WinUI workloads
|
||||
- [Partner Center account](https://partner.microsoft.com/dashboard/home) (for Store publishing)
|
||||
- [GitHub CLI](https://cli.github.com/) (for WinGet publishing)
|
||||
- [WingetCreate](https://github.com/microsoft/winget-create) — `winget install Microsoft.WingetCreate`
|
||||
- [Inno Setup](https://jrsoftware.org/isdl.php) (for WinGet EXE packaging)
|
||||
|
||||
## Important Notes
|
||||
|
||||
- Your extension's CLSID (the `[Guid("...")]` in your main .cs file) must be unique and consistent across all files
|
||||
- WinGet manifests must include the `windows-commandpalette-extension` tag for CmdPal discovery
|
||||
- MSIX packages require both x64 and ARM64 builds for Store submission
|
||||
- WindowsAppSdk must be listed as a dependency in WinGet manifests
|
||||
@@ -0,0 +1,169 @@
|
||||
# Microsoft Store Publishing Guide
|
||||
|
||||
Complete step-by-step guide for publishing your Command Palette extension to the Microsoft Store.
|
||||
|
||||
## Step 1: Set Up Microsoft Store
|
||||
|
||||
1. Go to [Partner Center](https://partner.microsoft.com/dashboard/home)
|
||||
2. Navigate to **Apps and Games** → **New product** → **MSIX or PWA app**
|
||||
3. Reserve your app name (e.g., `My Extension for Command Palette`)
|
||||
4. Once created, go to **Product Management** → **Product Identity**
|
||||
5. Copy these three values — you'll need them in the next step:
|
||||
|
||||
| Partner Center Field | Where It Goes |
|
||||
|---------------------|---------------|
|
||||
| **Package/Identity/Name** | `Package.appxmanifest` → `Identity Name` and `.csproj` → `AppxPackageIdentityName` |
|
||||
| **Package/Identity/Publisher** | `Package.appxmanifest` → `Identity Publisher` and `.csproj` → `AppxPackagePublisher` |
|
||||
| **Package/Properties/PublisherDisplayName** | `Package.appxmanifest` → `Properties PublisherDisplayName` |
|
||||
|
||||
## Step 2: Prepare the Extension
|
||||
|
||||
### Update `Package.appxmanifest`
|
||||
|
||||
Replace the placeholder identity values with your Partner Center values:
|
||||
|
||||
```xml
|
||||
<Identity
|
||||
Name="YOUR_PACKAGE_IDENTITY_NAME_HERE"
|
||||
Publisher="YOUR_PACKAGE_IDENTITY_PUBLISHER_HERE"
|
||||
Version="0.0.1.0" />
|
||||
```
|
||||
|
||||
And update the publisher display name:
|
||||
|
||||
```xml
|
||||
<Properties>
|
||||
<DisplayName>Your Extension Name</DisplayName>
|
||||
<PublisherDisplayName>YOUR_PUBLISHER_DISPLAY_NAME_HERE</PublisherDisplayName>
|
||||
<!-- ... -->
|
||||
</Properties>
|
||||
```
|
||||
|
||||
### Update `.csproj`
|
||||
|
||||
Add or update the following properties in your `.csproj` file:
|
||||
|
||||
```xml
|
||||
<PropertyGroup>
|
||||
<AppxPackageIdentityName>YOUR_PACKAGE_IDENTITY_NAME_HERE</AppxPackageIdentityName>
|
||||
<AppxPackagePublisher>YOUR_PACKAGE_IDENTITY_PUBLISHER_HERE</AppxPackagePublisher>
|
||||
<AppxPackageVersion>0.0.1.0</AppxPackageVersion>
|
||||
</PropertyGroup>
|
||||
```
|
||||
|
||||
### Update Image Assets ItemGroup
|
||||
|
||||
Ensure all image assets are included in the package by updating the `ItemGroup`:
|
||||
|
||||
```xml
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\**\*.png" />
|
||||
</ItemGroup>
|
||||
```
|
||||
|
||||
> **Tip:** The `Assets` folder should contain your Store logos and extension icons at the required sizes (44x44, 150x150, etc.). You can generate these from a single high-resolution image.
|
||||
|
||||
## Step 3: Build MSIX Packages
|
||||
|
||||
Build for both x64 and ARM64 architectures:
|
||||
|
||||
```powershell
|
||||
# x64 build
|
||||
dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=x64 -p:AppxPackageDir="AppPackages\x64\"
|
||||
|
||||
# ARM64 build
|
||||
dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=ARM64 -p:AppxPackageDir="AppPackages\ARM64\"
|
||||
```
|
||||
|
||||
Verify the MSIX files were created:
|
||||
|
||||
```powershell
|
||||
dir AppPackages -Recurse -Filter "*.msix"
|
||||
```
|
||||
|
||||
You should see two `.msix` files, one for each architecture.
|
||||
|
||||
## Step 4: Create MSIX Bundle
|
||||
|
||||
### Create the bundle mapping file
|
||||
|
||||
Create a file named `bundle_mapping.txt` that maps each MSIX to its architecture:
|
||||
|
||||
```text
|
||||
[Files]
|
||||
"AppPackages\x64\YourExtension_0.0.1.0_x64\YourExtension_0.0.1.0_x64.msix" "YourExtension_0.0.1.0_x64.msix"
|
||||
"AppPackages\ARM64\YourExtension_0.0.1.0_ARM64\YourExtension_0.0.1.0_ARM64.msix" "YourExtension_0.0.1.0_ARM64.msix"
|
||||
```
|
||||
|
||||
> **Note:** Update the paths and filenames to match your actual build output. Check the `AppPackages` directory structure after building.
|
||||
|
||||
### Run makeappx
|
||||
|
||||
```powershell
|
||||
makeappx bundle /f bundle_mapping.txt /p YourExtension_0.0.1.0_Bundle.msixbundle
|
||||
```
|
||||
|
||||
> **Tip:** `makeappx.exe` is included with the Windows SDK. If it's not in your PATH, find it at:
|
||||
> `C:\Program Files (x86)\Windows Kits\10\bin\<version>\x64\makeappx.exe`
|
||||
|
||||
## Step 5: Submit to Partner Center
|
||||
|
||||
1. Go to [Partner Center](https://partner.microsoft.com/dashboard/home)
|
||||
2. Navigate to your app → **Start a new submission**
|
||||
3. In **Packages**, upload your `.msixbundle` file
|
||||
4. In **Store Listings** → **Description**, include a note like:
|
||||
|
||||
> `YourExtension` integrates with the Windows Command Palette to provide [describe your extension's functionality]. Requires PowerToys with Command Palette enabled.
|
||||
|
||||
5. In **Notes for certification**, add testing instructions:
|
||||
|
||||
> This extension requires Microsoft PowerToys (available from the Microsoft Store or https://github.com/microsoft/PowerToys) with the Command Palette feature enabled. To test:
|
||||
> 1. Install PowerToys and enable Command Palette
|
||||
> 2. Install this extension
|
||||
> 3. Open Command Palette (Win+Alt+Space by default)
|
||||
> 4. Search for [your extension's commands]
|
||||
|
||||
6. Set **Availability** and pricing as appropriate
|
||||
7. Click **Submit for certification**
|
||||
|
||||
Certification typically takes 1–3 business days.
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
Before submitting, verify:
|
||||
|
||||
- [ ] Partner Center identity values match exactly in both `Package.appxmanifest` and `.csproj`
|
||||
- [ ] `AppxPackageVersion` is set correctly and incremented from any previous submission
|
||||
- [ ] Both x64 and ARM64 MSIX files are built successfully
|
||||
- [ ] MSIX bundle is created without errors
|
||||
- [ ] Extension installs and runs correctly from the MSIX package locally
|
||||
- [ ] Store listing includes clear description mentioning Command Palette integration
|
||||
- [ ] Testing instructions mention the PowerToys/Command Palette prerequisite
|
||||
- [ ] All required Store logos and screenshots are provided
|
||||
- [ ] Privacy policy URL is set (if your extension accesses network or user data)
|
||||
|
||||
## Store-Only Discovery Limitations
|
||||
|
||||
> **Important:** Command Palette cannot currently search for extensions published only to the Microsoft Store via its built-in browse experience. Users can find Store-published extensions through:
|
||||
>
|
||||
> - Direct Store link shared by the developer
|
||||
> - The Store's extension tag URL:
|
||||
> ```
|
||||
> ms-windows-store://assoc/?Tags=AppExtension-com.microsoft.commandpalette
|
||||
> ```
|
||||
> - Searching the Store app directly
|
||||
>
|
||||
> For discoverability within Command Palette's browse experience, also publish to WinGet.
|
||||
> See [winget-publishing.md](winget-publishing.md) for details.
|
||||
|
||||
## Updating Your Extension
|
||||
|
||||
To publish an update:
|
||||
|
||||
1. Increment the version in `.csproj` (`AppxPackageVersion`) and `Package.appxmanifest`
|
||||
2. Rebuild MSIX packages for both architectures
|
||||
3. Recreate the MSIX bundle with updated filenames
|
||||
4. Create a new submission in Partner Center and upload the new bundle
|
||||
5. Submit for certification
|
||||
|
||||
The Store will automatically update users who have installed your extension.
|
||||
@@ -0,0 +1,413 @@
|
||||
# WinGet Publishing Guide
|
||||
|
||||
Complete step-by-step guide for publishing your Command Palette extension to WinGet for `winget install` discovery and installation.
|
||||
|
||||
## Why WinGet?
|
||||
|
||||
Publishing to WinGet enables:
|
||||
|
||||
- Users to install via `winget install YourPublisher.YourExtension`
|
||||
- Discovery directly inside Command Palette's built-in browse experience
|
||||
- Automatic update detection via WinGet manifests
|
||||
|
||||
## Step 1: Prepare the Project for Unpackaged Distribution
|
||||
|
||||
WinGet distribution uses an unpackaged (EXE-based) build instead of MSIX.
|
||||
|
||||
### Update `.csproj`
|
||||
|
||||
Remove any existing `<PublishProfile>` property and add unpackaged mode:
|
||||
|
||||
```xml
|
||||
<PropertyGroup>
|
||||
<!-- Remove or comment out this line if present: -->
|
||||
<!-- <PublishProfile>win-$(Platform)</PublishProfile> -->
|
||||
|
||||
<!-- Add this for unpackaged distribution: -->
|
||||
<WindowsPackageType>None</WindowsPackageType>
|
||||
</PropertyGroup>
|
||||
```
|
||||
|
||||
### Note Your CLSID
|
||||
|
||||
Find the `[Guid("...")]` attribute in your main `.cs` file (e.g., `SampleExtension.cs`):
|
||||
|
||||
```csharp
|
||||
[Guid("YOUR-GUID-HERE")]
|
||||
public sealed partial class SampleExtension : IExtension
|
||||
```
|
||||
|
||||
You'll need this exact GUID for the installer script. It must match across all files.
|
||||
|
||||
## Step 2: Create Installer Scripts
|
||||
|
||||
### Inno Setup Script: `setup-template.iss`
|
||||
|
||||
Create this file in your project root. Replace all `TODO` placeholders with your values:
|
||||
|
||||
```iss
|
||||
; Inno Setup script for Command Palette extension
|
||||
|
||||
#define MyAppName "TODO_YOUR_EXTENSION_NAME"
|
||||
#define MyAppVersion "TODO_YOUR_VERSION"
|
||||
#define MyAppPublisher "TODO_YOUR_PUBLISHER_NAME"
|
||||
#define MyAppURL "TODO_YOUR_PROJECT_URL"
|
||||
#define MyAppCLSID "TODO_YOUR_CLSID_WITH_BRACES"
|
||||
; Example CLSID: {12345678-1234-1234-1234-123456789012}
|
||||
|
||||
[Setup]
|
||||
AppId={#MyAppCLSID}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
AppPublisherURL={#MyAppURL}
|
||||
DefaultDirName={autopf}\{#MyAppName}
|
||||
OutputBaseFilename={#MyAppName}_{#MyAppVersion}_{#SetupSetting("ArchitecturesAllowed")}
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
PrivilegesRequired=lowest
|
||||
OutputDir=Installer
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Files]
|
||||
Source: "publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[Registry]
|
||||
; Register the COM server for Command Palette discovery
|
||||
Root: HKCU; Subkey: "Software\Classes\CLSID\{#MyAppCLSID}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppName}"; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "Software\Classes\CLSID\{#MyAppCLSID}\InprocServer32"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppName}.dll"; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "Software\Classes\CLSID\{#MyAppCLSID}\InprocServer32"; ValueType: string; ValueName: "ThreadingModel"; ValueData: "Both"; Flags: uninsdeletekey
|
||||
|
||||
[UninstallDelete]
|
||||
Type: filesandordirs; Name: "{app}"
|
||||
```
|
||||
|
||||
> **Important:** The `AppId` must use your CLSID wrapped in braces. The registry entries register your extension's COM server so Command Palette can discover it.
|
||||
|
||||
### Build Script: `build-exe.ps1`
|
||||
|
||||
Create this PowerShell script in your project root:
|
||||
|
||||
```powershell
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Builds EXE installers for x64 and ARM64 using dotnet publish and Inno Setup.
|
||||
.DESCRIPTION
|
||||
Publishes the project for both architectures, then runs Inno Setup to create
|
||||
EXE installers suitable for WinGet submission.
|
||||
#>
|
||||
|
||||
param(
|
||||
[string]$Configuration = "Release",
|
||||
[string]$Version = "0.0.1"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$projectName = (Get-ChildItem -Filter "*.csproj" | Select-Object -First 1).BaseName
|
||||
if (-not $projectName) {
|
||||
Write-Error "No .csproj file found in the current directory."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$architectures = @("x64", "arm64")
|
||||
|
||||
foreach ($arch in $architectures) {
|
||||
Write-Host "`n=== Building $arch ===" -ForegroundColor Cyan
|
||||
|
||||
# Publish
|
||||
Write-Host "Publishing for $arch..."
|
||||
dotnet publish -c $Configuration -r "win-$arch" -o "publish" --self-contained=false
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "dotnet publish failed for $arch"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Create installer
|
||||
Write-Host "Creating installer for $arch..."
|
||||
$issFile = "setup-template.iss"
|
||||
if (-not (Test-Path $issFile)) {
|
||||
Write-Error "Inno Setup script not found: $issFile"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$archFlag = if ($arch -eq "arm64") { "arm64" } else { "x64" }
|
||||
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" `
|
||||
/DMyAppVersion="$Version" `
|
||||
/DArchitecturesAllowed="$archFlag" `
|
||||
$issFile
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Inno Setup failed for $arch"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Clean publish directory for next architecture
|
||||
Remove-Item -Recurse -Force "publish" -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "=== $arch complete ===" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host "`nInstallers created in the 'Installer' directory:" -ForegroundColor Cyan
|
||||
Get-ChildItem -Path "Installer" -Filter "*.exe" | ForEach-Object { Write-Host " $_" }
|
||||
```
|
||||
|
||||
## Step 3: Build EXE Installers
|
||||
|
||||
Run the build script from your project directory:
|
||||
|
||||
```powershell
|
||||
.\build-exe.ps1
|
||||
```
|
||||
|
||||
This produces two EXE files in the `Installer` directory:
|
||||
|
||||
```
|
||||
Installer\YourExtension_0.0.1_x64.exe
|
||||
Installer\YourExtension_0.0.1_arm64.exe
|
||||
```
|
||||
|
||||
Verify both installers work by running them locally and confirming your extension appears in Command Palette.
|
||||
|
||||
## Step 4: Create a GitHub Release
|
||||
|
||||
Tag your repository with the version and create a release with the EXE files:
|
||||
|
||||
```powershell
|
||||
# Tag the release
|
||||
git tag -a v0.0.1 -m "Release v0.0.1"
|
||||
git push origin v0.0.1
|
||||
|
||||
# Create release and upload assets (requires GitHub CLI)
|
||||
gh release create v0.0.1 `
|
||||
"Installer\YourExtension_0.0.1_x64.exe" `
|
||||
"Installer\YourExtension_0.0.1_arm64.exe" `
|
||||
--title "v0.0.1" `
|
||||
--notes "Initial release of YourExtension for Command Palette."
|
||||
```
|
||||
|
||||
After creating the release, copy the download URLs for both EXE files — you'll need them for the WinGet submission.
|
||||
|
||||
## Step 5: Submit to WinGet
|
||||
|
||||
Use `wingetcreate` to generate a WinGet manifest and submit a pull request:
|
||||
|
||||
```powershell
|
||||
wingetcreate new "<URL_TO_x64.exe>" "<URL_TO_arm64.exe>"
|
||||
```
|
||||
|
||||
`wingetcreate` will interactively prompt you for:
|
||||
|
||||
| Prompt | Example Value |
|
||||
|--------|---------------|
|
||||
| **PackageIdentifier** | `YourPublisher.YourExtension` |
|
||||
| **PackageVersion** | `0.0.1` |
|
||||
| **PackageLocale** | `en-US` |
|
||||
| **Publisher** | `Your Name` |
|
||||
| **PackageName** | `YourExtension for Command Palette` |
|
||||
| **License** | `MIT` |
|
||||
| **ShortDescription** | `A Command Palette extension that does X` |
|
||||
|
||||
After answering all prompts, `wingetcreate` will create a PR against the [winget-pkgs](https://github.com/microsoft/winget-pkgs) repository.
|
||||
|
||||
## Step 6: Add the Command Palette Tag (CRITICAL)
|
||||
|
||||
> **This step is required for your extension to appear in Command Palette's browse experience.**
|
||||
|
||||
After `wingetcreate` generates the manifest files, you **must** edit each `.locale.*.yaml` file to add the Command Palette tag.
|
||||
|
||||
In every locale YAML file (e.g., `YourPublisher.YourExtension.locale.en-US.yaml`), add:
|
||||
|
||||
```yaml
|
||||
Tags:
|
||||
- windows-commandpalette-extension
|
||||
```
|
||||
|
||||
Example of a complete locale file with the tag:
|
||||
|
||||
```yaml
|
||||
# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.6.0.schema.json
|
||||
PackageIdentifier: YourPublisher.YourExtension
|
||||
PackageVersion: 0.0.1
|
||||
PackageLocale: en-US
|
||||
Publisher: Your Name
|
||||
PackageName: YourExtension for Command Palette
|
||||
License: MIT
|
||||
ShortDescription: A Command Palette extension that does X
|
||||
Tags:
|
||||
- windows-commandpalette-extension
|
||||
ManifestType: defaultLocale
|
||||
ManifestVersion: 1.6.0
|
||||
```
|
||||
|
||||
Without this tag, Command Palette will not discover your extension in its browse experience.
|
||||
|
||||
## Step 7: Ensure WindowsAppSdk Dependency
|
||||
|
||||
Your WinGet manifest must declare a dependency on the Windows App SDK so it gets installed automatically. In the `installer.yaml` manifest file, add:
|
||||
|
||||
```yaml
|
||||
Dependencies:
|
||||
PackageDependencies:
|
||||
- PackageIdentifier: Microsoft.WindowsAppRuntime.1.7
|
||||
MinimumVersion: 7001.632.252.0
|
||||
```
|
||||
|
||||
> **Note:** Update the version number to match the Windows App SDK version your project targets. Check your `.csproj` for the `WindowsAppSDK` package version.
|
||||
|
||||
## Step 8: GitHub Actions Automation (Optional)
|
||||
|
||||
Automate your build, release, and WinGet submission process with GitHub Actions.
|
||||
|
||||
### Release Workflow: `.github/workflows/release-extension.yml`
|
||||
|
||||
```yaml
|
||||
name: Release Extension
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
PROJECT_NAME: YourExtension
|
||||
DOTNET_VERSION: '9.0.x'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x64, arm64]
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||
|
||||
- name: Install Inno Setup
|
||||
run: choco install innosetup -y --no-progress
|
||||
|
||||
- name: Detect version
|
||||
id: version
|
||||
run: |
|
||||
$tag = "${{ github.ref_name }}" -replace '^v', ''
|
||||
echo "VERSION=$tag" >> $env:GITHUB_OUTPUT
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
dotnet publish -c Release -r win-${{ matrix.arch }} -o publish --self-contained=false
|
||||
|
||||
- name: Create installer
|
||||
run: |
|
||||
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" `
|
||||
/DMyAppVersion="${{ steps.version.outputs.VERSION }}" `
|
||||
/DArchitecturesAllowed="${{ matrix.arch }}" `
|
||||
setup-template.iss
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: installer-${{ matrix.arch }}
|
||||
path: Installer/*.exe
|
||||
|
||||
release:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
merge-multiple: true
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: artifacts/*.exe
|
||||
generate_release_notes: true
|
||||
|
||||
winget-update:
|
||||
needs: release
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Detect version
|
||||
id: version
|
||||
run: |
|
||||
$tag = "${{ github.ref_name }}" -replace '^v', ''
|
||||
echo "VERSION=$tag" >> $env:GITHUB_OUTPUT
|
||||
|
||||
- name: Update WinGet manifest
|
||||
run: |
|
||||
$baseUrl = "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}"
|
||||
wingetcreate update YourPublisher.YourExtension `
|
||||
--version ${{ steps.version.outputs.VERSION }} `
|
||||
--urls "$baseUrl/${{ env.PROJECT_NAME }}_${{ steps.version.outputs.VERSION }}_x64.exe" "$baseUrl/${{ env.PROJECT_NAME }}_${{ steps.version.outputs.VERSION }}_arm64.exe" `
|
||||
--submit `
|
||||
--token ${{ secrets.WINGET_PAT }}
|
||||
```
|
||||
|
||||
### Required Secrets
|
||||
|
||||
| Secret | Description |
|
||||
|--------|-------------|
|
||||
| `WINGET_PAT` | GitHub Personal Access Token with `public_repo` scope, used by `wingetcreate` to submit PRs to `microsoft/winget-pkgs` |
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Push a version tag** (e.g., `git tag v0.0.2 && git push origin v0.0.2`)
|
||||
2. **Build job** runs in parallel for x64 and ARM64, creating EXE installers
|
||||
3. **Release job** creates a GitHub Release and uploads the EXE files
|
||||
4. **WinGet update job** automatically submits an updated manifest to `winget-pkgs`
|
||||
|
||||
> **Note:** The `winget-update` job uses `wingetcreate update` (not `new`) because it assumes you've already submitted your initial manifest manually. For the first submission, follow Steps 5–7 above.
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
Before submitting to WinGet, verify:
|
||||
|
||||
- [ ] `.csproj` has `<WindowsPackageType>None</WindowsPackageType>` set
|
||||
- [ ] CLSID in `setup-template.iss` matches the `[Guid("...")]` in your main `.cs` file
|
||||
- [ ] Both x64 and ARM64 EXE installers build successfully
|
||||
- [ ] Installer registers the COM server correctly (check `HKCU\Software\Classes\CLSID\{your-clsid}`)
|
||||
- [ ] Extension appears in Command Palette after installing via EXE
|
||||
- [ ] Extension is removed from Command Palette after uninstalling
|
||||
- [ ] GitHub Release contains both EXE files with correct download URLs
|
||||
- [ ] WinGet manifest includes `windows-commandpalette-extension` tag
|
||||
- [ ] WinGet manifest includes `WindowsAppRuntime` dependency
|
||||
- [ ] `winget validate` passes on all manifest files
|
||||
|
||||
## Updating Your Extension on WinGet
|
||||
|
||||
For subsequent releases:
|
||||
|
||||
```powershell
|
||||
wingetcreate update YourPublisher.YourExtension `
|
||||
--version "0.0.2" `
|
||||
--urls "<URL_TO_NEW_x64.exe>" "<URL_TO_NEW_arm64.exe>" `
|
||||
--submit
|
||||
```
|
||||
|
||||
Or simply push a new version tag if you've set up the GitHub Actions workflow above.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| Extension not appearing in CmdPal browse | Verify the `windows-commandpalette-extension` tag is in your locale YAML |
|
||||
| COM registration fails | Check that the CLSID matches exactly and registry paths are correct |
|
||||
| `wingetcreate` validation errors | Run `winget validate --manifest <path>` and fix reported issues |
|
||||
| Installer doesn't run silently | Add `/VERYSILENT /SUPPRESSMSGBOXES` flags for silent install support |
|
||||
| Missing WindowsAppSdk at runtime | Ensure the `PackageDependencies` section is in your installer manifest |
|
||||
Reference in New Issue
Block a user