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