bundle-windows.ps1

  1[CmdletBinding()]
  2Param(
  3    [Parameter()][Alias('i')][switch]$Install,
  4    [Parameter()][Alias('h')][switch]$Help,
  5    [Parameter()][string]$Name
  6)
  7
  8. "$PSScriptRoot/lib/workspace.ps1"
  9
 10# https://stackoverflow.com/questions/57949031/powershell-script-stops-if-program-fails-like-bash-set-o-errexit
 11$ErrorActionPreference = 'Stop'
 12$PSNativeCommandUseErrorActionPreference = $true
 13
 14$buildSuccess = $false
 15
 16if ($Help) {
 17    Write-Output "Usage: test.ps1 [-Install] [-Help]"
 18    Write-Output "Build the installer for Windows.\n"
 19    Write-Output "Options:"
 20    Write-Output "  -Install, -i  Run the installer after building."
 21    Write-Output "  -Help, -h     Show this help message."
 22    exit 0
 23}
 24
 25Push-Location -Path crates/zed
 26$channel = Get-Content "RELEASE_CHANNEL"
 27$env:ZED_RELEASE_CHANNEL = $channel
 28$env:RELEASE_CHANNEL = $channel
 29Pop-Location
 30
 31function CheckEnvironmentVariables {
 32    $requiredVars = @(
 33        'ZED_WORKSPACE', 'RELEASE_VERSION', 'ZED_RELEASE_CHANNEL',
 34        'AZURE_TENANT_ID', 'AZURE_CLIENT_ID', 'AZURE_CLIENT_SECRET',
 35        'ACCOUNT_NAME', 'CERT_PROFILE_NAME', 'ENDPOINT',
 36        'FILE_DIGEST', 'TIMESTAMP_DIGEST', 'TIMESTAMP_SERVER'
 37    )
 38
 39    foreach ($var in $requiredVars) {
 40        if (-not (Test-Path "env:$var")) {
 41            Write-Error "$var is not set"
 42            exit 1
 43        }
 44    }
 45}
 46
 47function PrepareForBundle {
 48    if (Test-Path "$innoDir") {
 49        Remove-Item -Path "$innoDir" -Recurse -Force
 50    }
 51    New-Item -Path "$innoDir" -ItemType Directory -Force
 52    Copy-Item -Path "$env:ZED_WORKSPACE\crates\zed\resources\windows\*" -Destination "$innoDir" -Recurse -Force
 53    New-Item -Path "$innoDir\make_appx" -ItemType Directory -Force
 54    New-Item -Path "$innoDir\appx" -ItemType Directory -Force
 55    New-Item -Path "$innoDir\bin" -ItemType Directory -Force
 56    New-Item -Path "$innoDir\tools" -ItemType Directory -Force
 57}
 58
 59function GenerateLicenses {
 60    $oldErrorActionPreference = $ErrorActionPreference
 61    $ErrorActionPreference = 'Continue'
 62    . $PSScriptRoot/generate-licenses.ps1
 63    $ErrorActionPreference = $oldErrorActionPreference
 64}
 65
 66function BuildZedAndItsFriends {
 67    Write-Output "Building Zed and its friends, for channel: $channel"
 68    # Build zed.exe, cli.exe and auto_update_helper.exe
 69    cargo build --release --package zed --package cli --package auto_update_helper
 70    Copy-Item -Path ".\target\release\zed.exe" -Destination "$innoDir\Zed.exe" -Force
 71    Copy-Item -Path ".\target\release\cli.exe" -Destination "$innoDir\cli.exe" -Force
 72    Copy-Item -Path ".\target\release\auto_update_helper.exe" -Destination "$innoDir\auto_update_helper.exe" -Force
 73    # Build explorer_command_injector.dll
 74    switch ($channel) {
 75        "stable" {
 76            cargo build --release --features stable --no-default-features --package explorer_command_injector
 77        }
 78        "preview" {
 79            cargo build --release --features preview --no-default-features --package explorer_command_injector
 80        }
 81        default {
 82            cargo build --release --package explorer_command_injector
 83        }
 84    }
 85    Copy-Item -Path ".\target\release\explorer_command_injector.dll" -Destination "$innoDir\zed_explorer_command_injector.dll" -Force
 86}
 87
 88function ZipZedAndItsFriendsDebug {
 89    $items = @(
 90        ".\target\release\zed.pdb",
 91        ".\target\release\cli.pdb",
 92        ".\target\release\auto_update_helper.pdb",
 93        ".\target\release\explorer_command_injector.pdb"
 94    )
 95
 96    Compress-Archive -Path $items -DestinationPath ".\target\release\zed-$env:RELEASE_VERSION-$env:ZED_RELEASE_CHANNEL.dbg.zip" -Force
 97}
 98
 99
100function UploadToSentry {
101    if (-not (Get-Command "sentry-cli" -ErrorAction SilentlyContinue)) {
102        Write-Output "sentry-cli not found. skipping sentry upload."
103        Write-Output "install with: 'winget install -e --id=Sentry.sentry-cli'"
104        return
105    }
106    if (-not (Test-Path "env:SENTRY_AUTH_TOKEN")) {
107        Write-Output "missing SENTRY_AUTH_TOKEN. skipping sentry upload."
108        return
109    }
110    Write-Output "Uploading zed debug symbols to sentry..."
111    sentry-cli debug-files upload --include-sources --wait -p zed -o zed-dev .\target\release\
112}
113
114function MakeAppx {
115    switch ($channel) {
116        "stable" {
117            $manifestFile = "$env:ZED_WORKSPACE\crates\explorer_command_injector\AppxManifest.xml"
118        }
119        "preview" {
120            $manifestFile = "$env:ZED_WORKSPACE\crates\explorer_command_injector\AppxManifest-Preview.xml"
121        }
122        default {
123            $manifestFile = "$env:ZED_WORKSPACE\crates\explorer_command_injector\AppxManifest-Nightly.xml"
124        }
125    }
126    Copy-Item -Path "$manifestFile" -Destination "$innoDir\make_appx\AppxManifest.xml"
127    # Add makeAppx.exe to Path
128    $sdk = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64"
129    $env:Path += ';' + $sdk
130    makeAppx.exe pack /d "$innoDir\make_appx" /p "$innoDir\zed_explorer_command_injector.appx" /nv
131}
132
133function SignZedAndItsFriends {
134    $files = "$innoDir\Zed.exe,$innoDir\cli.exe,$innoDir\auto_update_helper.exe,$innoDir\zed_explorer_command_injector.dll,$innoDir\zed_explorer_command_injector.appx"
135    & "$innoDir\sign.ps1" $files
136}
137
138function DownloadAMDGpuServices {
139    # If you update the AGS SDK version, please also update the version in `crates/gpui/src/platform/windows/directx_renderer.rs`
140    $url = "https://codeload.github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/zip/refs/tags/v6.3.0"
141    $zipPath = ".\AGS_SDK_v6.3.0.zip"
142    # Download the AGS SDK zip file
143    Invoke-WebRequest -Uri $url -OutFile $zipPath
144    # Extract the AGS SDK zip file
145    Expand-Archive -Path $zipPath -DestinationPath "." -Force
146}
147
148function DownloadConpty {
149    $url = "https://www.nuget.org/api/v2/package/CI.Microsoft.Windows.Console.ConPTY/1.22.250314001"
150    $zipPath = ".\conpty.zip"
151    Invoke-WebRequest -Uri $url -OutFile $zipPath
152    Expand-Archive -Path $zipPath -DestinationPath ".\conpty" -Force
153}
154
155function CollectFiles {
156    Move-Item -Path "$innoDir\zed_explorer_command_injector.appx" -Destination "$innoDir\appx\zed_explorer_command_injector.appx" -Force
157    Move-Item -Path "$innoDir\zed_explorer_command_injector.dll" -Destination "$innoDir\appx\zed_explorer_command_injector.dll" -Force
158    Move-Item -Path "$innoDir\cli.exe" -Destination "$innoDir\bin\zed.exe" -Force
159    Move-Item -Path "$innoDir\zed.sh" -Destination "$innoDir\bin\zed" -Force
160    Move-Item -Path "$innoDir\auto_update_helper.exe" -Destination "$innoDir\tools\auto_update_helper.exe" -Force
161    Move-Item -Path ".\AGS_SDK-6.3.0\ags_lib\lib\amd_ags_x64.dll" -Destination "$innoDir\amd_ags_x64.dll" -Force
162    Move-Item -Path ".\conpty\build\native\runtimes\x64\OpenConsole.exe" -Destination "$innoDir\OpenConsole.exe" -Force
163    Move-Item -Path ".\conpty\runtimes\win10-x64\native\conpty.dll" -Destination "$innoDir\conpty.dll" -Force
164}
165
166function BuildInstaller {
167    $issFilePath = "$innoDir\zed.iss"
168    switch ($channel) {
169        "stable" {
170            $appId = "{{2DB0DA96-CA55-49BB-AF4F-64AF36A86712}"
171            $appIconName = "app-icon"
172            $appName = "Zed"
173            $appDisplayName = "Zed"
174            $appSetupName = "Zed-x86_64"
175            # The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
176            $appMutex = "Zed-Stable-Instance-Mutex"
177            $appExeName = "Zed"
178            $regValueName = "Zed"
179            $appUserId = "ZedIndustries.Zed"
180            $appShellNameShort = "Z&ed"
181            $appAppxFullName = "ZedIndustries.Zed_1.0.0.0_neutral__japxn1gcva8rg"
182        }
183        "preview" {
184            $appId = "{{F70E4811-D0E2-4D88-AC99-D63752799F95}"
185            $appIconName = "app-icon-preview"
186            $appName = "Zed Preview"
187            $appDisplayName = "Zed Preview"
188            $appSetupName = "Zed-x86_64"
189            # The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
190            $appMutex = "Zed-Preview-Instance-Mutex"
191            $appExeName = "Zed"
192            $regValueName = "ZedPreview"
193            $appUserId = "ZedIndustries.Zed.Preview"
194            $appShellNameShort = "Z&ed Preview"
195            $appAppxFullName = "ZedIndustries.Zed.Preview_1.0.0.0_neutral__japxn1gcva8rg"
196        }
197        "nightly" {
198            $appId = "{{1BDB21D3-14E7-433C-843C-9C97382B2FE0}"
199            $appIconName = "app-icon-nightly"
200            $appName = "Zed Nightly"
201            $appDisplayName = "Zed Nightly"
202            $appSetupName = "Zed-x86_64"
203            # The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
204            $appMutex = "Zed-Nightly-Instance-Mutex"
205            $appExeName = "Zed"
206            $regValueName = "ZedNightly"
207            $appUserId = "ZedIndustries.Zed.Nightly"
208            $appShellNameShort = "Z&ed Editor Nightly"
209            $appAppxFullName = "ZedIndustries.Zed.Nightly_1.0.0.0_neutral__japxn1gcva8rg"
210        }
211        "dev" {
212            $appId = "{{8357632E-24A4-4F32-BA97-E575B4D1FE5D}"
213            $appIconName = "app-icon-dev"
214            $appName = "Zed Dev"
215            $appDisplayName = "Zed Dev"
216            $appSetupName = "Zed-x86_64"
217            # The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
218            $appMutex = "Zed-Dev-Instance-Mutex"
219            $appExeName = "Zed"
220            $regValueName = "ZedDev"
221            $appUserId = "ZedIndustries.Zed.Dev"
222            $appShellNameShort = "Z&ed Dev"
223            $appAppxFullName = "ZedIndustries.Zed.Dev_1.0.0.0_neutral__japxn1gcva8rg"
224        }
225        default {
226            Write-Error "can't bundle installer for $channel."
227            exit 1
228        }
229    }
230
231    # Windows runner 2022 default has iscc in PATH, https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md
232    # Currently, we are using Windows 2022 runner.
233    # Windows runner 2025 doesn't have iscc in PATH for now, https://github.com/actions/runner-images/issues/11228
234    $innoSetupPath = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
235
236    $definitions = @{
237        "AppId"          = $appId
238        "AppIconName"    = $appIconName
239        "OutputDir"      = "$env:ZED_WORKSPACE\target"
240        "AppSetupName"   = $appSetupName
241        "AppName"        = $appName
242        "AppDisplayName" = $appDisplayName
243        "RegValueName"   = $regValueName
244        "AppMutex"       = $appMutex
245        "AppExeName"     = $appExeName
246        "ResourcesDir"   = "$innoDir"
247        "ShellNameShort" = $appShellNameShort
248        "AppUserId"      = $appUserId
249        "Version"        = "$env:RELEASE_VERSION"
250        "SourceDir"      = "$env:ZED_WORKSPACE"
251        "AppxFullName"   = $appAppxFullName
252    }
253
254    $signTool = "powershell.exe -ExecutionPolicy Bypass -File $innoDir\sign.ps1 `$f"
255
256    $defs = @()
257    foreach ($key in $definitions.Keys) {
258        $defs += "/d$key=`"$($definitions[$key])`""
259    }
260
261    $innoArgs = @($issFilePath) + $defs + "/sDefaultsign=`"$signTool`""
262
263    # Execute Inno Setup
264    Write-Host "🚀 Running Inno Setup: $innoSetupPath $innoArgs"
265    $process = Start-Process -FilePath $innoSetupPath -ArgumentList $innoArgs -NoNewWindow -Wait -PassThru
266
267    if ($process.ExitCode -eq 0) {
268        Write-Host "✅ Inno Setup successfully compiled the installer"
269        Write-Output "SETUP_PATH=target/$appSetupName.exe" >> $env:GITHUB_ENV
270        $script:buildSuccess = $true
271    }
272    else {
273        Write-Host "❌ Inno Setup failed: $($process.ExitCode)"
274        $script:buildSuccess = $false
275    }
276}
277
278ParseZedWorkspace
279$innoDir = "$env:ZED_WORKSPACE\inno"
280$debugArchive = ".\target\release\zed-$env:RELEASE_VERSION-$env:ZED_RELEASE_CHANNEL.dbg.zip"
281$debugStoreKey = "$env:ZED_RELEASE_CHANNEL/zed-$env:RELEASE_VERSION-$env:ZED_RELEASE_CHANNEL.dbg.zip"
282
283CheckEnvironmentVariables
284PrepareForBundle
285GenerateLicenses
286BuildZedAndItsFriends
287MakeAppx
288SignZedAndItsFriends
289ZipZedAndItsFriendsDebug
290DownloadAMDGpuServices
291DownloadConpty
292CollectFiles
293BuildInstaller
294
295UploadToSentry
296
297if ($buildSuccess) {
298    Write-Output "Build successful"
299    if ($Install) {
300        Write-Output "Installing Zed..."
301        Start-Process -FilePath "$env:ZED_WORKSPACE/target/ZedEditorUserSetup-x64-$env:RELEASE_VERSION.exe"
302    }
303    exit 0
304}
305else {
306    Write-Output "Build failed"
307    exit 1
308}