Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/winget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ jobs:
run: |
# Get installer info from release event
$assets = '${{ toJSON(github.event.release.assets) }}' | ConvertFrom-Json
$x64InstallerUrl = $assets | Where-Object -Property name -like '*x86_64-windows.zip' | Select-Object -ExpandProperty browser_download_url
$arm64InstallerUrl = $assets | Where-Object -Property name -like '*aarch64-windows.zip' | Select-Object -ExpandProperty browser_download_url
$x64InstallerUrl = $assets | Where-Object -Property name -like '*x86_64-windows-setup.exe' | Select-Object -ExpandProperty browser_download_url
$arm64InstallerUrl = $assets | Where-Object -Property name -like '*aarch64-windows-setup.exe' | Select-Object -ExpandProperty browser_download_url
$packageVersion = (${{ toJSON(github.event.release.tag_name) }}).Trim('v')

# Update package using wingetcreate
Expand Down
18 changes: 18 additions & 0 deletions .pipelines/nuget.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
NuGet config used by the official Windows release pipeline to restore
build-time tools (currently just Inno Setup) from an internal Azure
Artifacts feed. Microsoft CIs are not allowed to reach nuget.org or
jrsoftware.org directly; the feed below mirrors nuget.org through an
upstream source.

The feed must have a NuGet upstream pointing at https://api.nuget.org/v3/index.json
so that the `Tools.InnoSetup` package referenced by packages.config
can be transitively fetched and cached.
-->
<packageSources>
<clear />
<add key="Edit_PublicPackages" value="https://pkgs.dev.azure.com/microsoft/Dart/_packaging/Edit_PublicPackages/nuget/v3/index.json" />
</packageSources>
</configuration>
5 changes: 5 additions & 0 deletions .pipelines/packages.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<!-- nuget.exe install packages.config -ConfigFile nuget.config -OutputDirectory ../.tools -ExcludeVersion -->
<package id="Tools.InnoSetup" version="6.7.1" />
</packages>
150 changes: 127 additions & 23 deletions .pipelines/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ extends:
parameters:
featureFlags:
autoBaseline: false
networkisolation:
policy: Good
WindowsHostVersion:
Version: 2022
Network: R1
Expand Down Expand Up @@ -107,6 +109,11 @@ extends:
CARGO_TARGET_DIR: C:\cargo_target_dir
# RUSTC_BOOTSTRAP=1 is required to make panic-immediate-abort work.
RUSTC_BOOTSTRAP: 1
# `nuget install -ExcludeVersion` (see packages.config)
# restores Inno Setup here.
InnoSetupRoot: "$(Build.SourcesDirectory)\\.tools\\Tools.InnoSetup\\tools"
# Holds the uninstaller .e32 that ISCC embeds into every installer.
SignedUninstallerDir: "$(Build.SourcesDirectory)\\.signing"
steps:
# NOTE: Step objects have ordered keys and you MUST have "task" as the first key.
# Objects with ordered keys... lol
Expand All @@ -133,6 +140,28 @@ extends:
# fetching entirely prior to the build, and perform the build with the network disabled.
- script: cargo fetch --config .cargo/release-windows-ms.toml
displayName: Fetch crates
# Pull Inno Setup from the internal Azure Artifacts NuGet feed.
- task: NuGetAuthenticate@1
displayName: Authenticate with Azure Artifacts (nuget)
- task: NuGetCommand@2
displayName: Restore Inno Setup
inputs:
command: custom
arguments: >-
install $(Build.SourcesDirectory)/.pipelines/packages.config
-ConfigFile $(Build.SourcesDirectory)/.pipelines/nuget.config
-OutputDirectory $(Build.SourcesDirectory)/.tools
-ExcludeVersion
-NonInteractive
# Used for `ob_createvpack_version`, the installer version and all output file names.
- pwsh: |-
$cargoToml = Get-Content -Raw -LiteralPath crates/edit/Cargo.toml
$m = [regex]::Match($cargoToml, '(?m)^version\s*=\s*"([^"]+)"')
if (-not $m.Success) { throw 'Failed to extract version from crates/edit/Cargo.toml' }
$version = $m.Groups[1].Value
Write-Host "Edit version: $version"
Write-Host "##vso[task.setvariable variable=EditVersion]$version"
displayName: Set EditVersion
- ${{ each platform in parameters.buildPlatforms }}:
- script: cargo build --config .cargo/release-windows-ms.toml --frozen --release --target ${{platform}}
displayName: Build ${{platform}} Release
Expand All @@ -149,14 +178,6 @@ extends:
contents: |
*.exe
*.pdb
# Extract the version for `ob_createvpack_version`.
- script: |-
@echo off
for /f "tokens=3 delims=- " %%x in ('findstr /c:"version = " crates\edit\Cargo.toml') do (
echo ##vso[task.setvariable variable=EditVersion]%%~x
goto :EOF
)
displayName: "Set EditVersion"
- task: onebranch.pipeline.signing@1
displayName: "Sign files"
inputs:
Expand All @@ -166,19 +187,102 @@ extends:
search_root: "$(ob_createvpack_vpackdirectory)"
use_testsign: false
in_container: true

- ${{ each platform in parameters.buildPlatforms }}:
- pwsh: |-
$Dest = New-Item -Type Directory "_staging/${env:RELEASE_NAME}"
Write-Host "Staging files from ${env:VPACK_ROOT} at $Dest"
Get-ChildItem "${env:VPACK_ROOT}\*" -Include *.exe, *.pdb | Copy-Item -Destination $Dest -Verbose
tar.exe -c -v --format=zip -f "$(ob_outputDirectory)\${env:RELEASE_NAME}.zip" -C _staging $env:RELEASE_NAME
env:
RELEASE_NAME: edit-$(EditVersion)-${{ replace(platform, 'pc-windows-msvc', 'windows') }}
${{ if eq(platform, 'i686-pc-windows-msvc') }}:
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/i386"
${{ elseif eq(platform, 'x86_64-pc-windows-msvc') }}:
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/amd64"
${{ else }}: # aarch64-pc-windows-msvc
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/arm64"
displayName: Produce ${{platform}} release archive
- pwsh: |-
$Dest = New-Item -Type Directory "_staging/${env:RELEASE_NAME}"
Write-Host "Staging files from ${env:VPACK_ROOT} at $Dest"
Get-ChildItem "${env:VPACK_ROOT}\*" -Include *.exe, *.pdb | Copy-Item -Destination $Dest -Verbose
tar.exe -c -v --format=zip -f "$(ob_outputDirectory)\${env:RELEASE_NAME}.zip" -C _staging $env:RELEASE_NAME
env:
RELEASE_NAME: edit-$(EditVersion)-${{ replace(platform, 'pc-windows-msvc', 'windows') }}
${{ if eq(platform, 'i686-pc-windows-msvc') }}:
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/i386"
${{ elseif eq(platform, 'x86_64-pc-windows-msvc') }}:
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/amd64"
${{ else }}: # aarch64-pc-windows-msvc
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/arm64"
displayName: Produce ${{platform}} release archive
# Run ISCC once to generate the uninstaller .e32 file.
# Rename .e32 → .exe so the signing task recognises the extension.
# The .e32 is arch-independent (confirmed: same hash for x64 and arm64).
# ISCC exits with code 1 because the file isn't signed yet.
- pwsh: |-
$iscc = Join-Path $env:InnoSetupRoot 'ISCC.exe'
if (-not (Test-Path -LiteralPath $iscc)) {
throw "ISCC.exe not found at $iscc"
}
New-Item -ItemType Directory -Force -Path $env:SIGNED_UNINSTALLER_DIR | Out-Null
$ErrorActionPreference = 'Continue'
& $iscc /Q `
"/DSignedUninstallerDir=$env:SIGNED_UNINSTALLER_DIR" `
"/DAppVersion=$env:EDIT_VERSION" `
"/DArchitecturesAllowed=x64os" `
"/DSource=$env:VPACK_ROOT\edit.exe" `
"/O$env:AGENT_TEMPDIRECTORY" `
/Fdummy `
assets\edit.iss
$ErrorActionPreference = 'Stop'
$e32 = Get-ChildItem "$env:SIGNED_UNINSTALLER_DIR\*.e32" | Select-Object -First 1
if (-not $e32) { throw 'ISCC did not produce an uninstaller; see its output above' }
Write-Host "Generated uninstaller: $($e32.Name)"
Rename-Item $e32.FullName ($e32.FullName -replace '\.e32$', '.exe')
exit 0
env:
EDIT_VERSION: $(EditVersion)
SIGNED_UNINSTALLER_DIR: $(SignedUninstallerDir)
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/amd64"
displayName: Generate unsigned uninstaller
- task: onebranch.pipeline.signing@1
displayName: Sign uninstaller
inputs:
command: sign
signing_profile: external_distribution
files_to_sign: "*.exe"
search_root: "$(SignedUninstallerDir)"
use_testsign: false
in_container: true
# Run ISCC a second time to create the actual installers.
- ${{ each platform in parameters.buildPlatforms }}:
- pwsh: |-
# ISCC only accepts the signed uninstaller under its original .e32 extension.
Get-ChildItem "$env:SIGNED_UNINSTALLER_DIR\*.exe" | ForEach-Object {
Rename-Item $_.FullName ($_.FullName -replace '\.exe$', '.e32')
}

$iscc = Join-Path $env:InnoSetupRoot 'ISCC.exe'
New-Item -ItemType Directory -Force -Path $env:OB_OUTPUTDIRECTORY | Out-Null
& $iscc `
/Q `
"/DSignedUninstallerDir=$env:SIGNED_UNINSTALLER_DIR" `
"/DAppVersion=$env:EDIT_VERSION" `
"/DArchitecturesAllowed=$env:ARCH" `
"/DSource=$env:VPACK_ROOT\edit.exe" `
"/O$env:OB_OUTPUTDIRECTORY" `
"/F$env:OUTPUT_BASENAME" `
assets\edit.iss
if ($LASTEXITCODE -ne 0) { throw "ISCC failed with exit code $LASTEXITCODE" }
Write-Host "Produced $env:OB_OUTPUTDIRECTORY\$env:OUTPUT_BASENAME.exe"
env:
EDIT_VERSION: $(EditVersion)
OB_OUTPUTDIRECTORY: $(ob_outputDirectory)
OUTPUT_BASENAME: edit-$(EditVersion)-${{ replace(platform, 'pc-windows-msvc', 'windows') }}-setup
SIGNED_UNINSTALLER_DIR: $(SignedUninstallerDir)
${{ if eq(platform, 'i686-pc-windows-msvc') }}:
ARCH: x86
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/i386"
${{ elseif eq(platform, 'x86_64-pc-windows-msvc') }}:
ARCH: x64os
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/amd64"
${{ else }}: # aarch64-pc-windows-msvc
ARCH: arm64
VPACK_ROOT: "$(ob_createvpack_vpackdirectory)/arm64"
displayName: Build ${{platform}} installer
- task: onebranch.pipeline.signing@1
displayName: Sign installers
inputs:
command: sign
signing_profile: external_distribution
files_to_sign: "edit-*.exe"
search_root: "$(ob_outputDirectory)"
use_testsign: false
in_container: true
35 changes: 35 additions & 0 deletions assets/build-windows-setup.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
$ErrorActionPreference = "Stop"
$PSNativeCommandUseErrorActionPreference = $true

Set-Location (Split-Path -Parent $PSScriptRoot)

$env:RUSTC_BOOTSTRAP = 1
$config = "./.cargo/release.toml"

if (Get-Command "msrustup" -ErrorAction SilentlyContinue) {
# The default C2/MSVC toolchain cannot compile this project.
$env:MSRUSTUP_TOOLCHAIN = "ms-prod@llvm"
$config = "./.cargo/release-windows-ms.toml"
}

# Extract the package version from Cargo.toml so we can stamp it into the installer.
$cargoToml = Get-Content -Raw -LiteralPath "crates/edit/Cargo.toml"
$versionMatch = [regex]::Match($cargoToml, '(?m)^version\s*=\s*"([^"]+)"')
if (!$versionMatch.Success) {
throw "Failed to extract version from crates/edit/Cargo.toml"
}
$version = $versionMatch.Groups[1].Value

cargo build --config $config --release --target aarch64-pc-windows-msvc
cargo build --config $config --release --target x86_64-pc-windows-msvc

$iscc = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
if (!(Test-Path $iscc)) {
$iscc = "$env:LocalAppData\Programs\Inno Setup 6\ISCC.exe"
if (!(Test-Path $iscc)) {
throw "Please install Inno Setup 6: https://jrsoftware.org/isdl.php"
}
}

& $iscc /DAppVersion=$version /DArchitecturesAllowed=arm64 /DSource=$PWD\target\aarch64-pc-windows-msvc\release\edit.exe /O$PWD\target /Fedit-$version-aarch64-windows-setup assets\edit.iss
& $iscc /DAppVersion=$version /DArchitecturesAllowed=x64os /DSource=$PWD\target\x86_64-pc-windows-msvc\release\edit.exe /O$PWD\target /Fedit-$version-x86_64-windows-setup assets\edit.iss
Loading
Loading