Browse Source

Add offline dmg tooling and Homebrew cask template

The macOS CI artifact is an unsigned zipped ILSpy.app; the signed
distribution channel is a dmg the release manager creates offline with
create-dmg.ps1 (codesign and notarization stay optional parameters, so
no signing secrets ever live in CI). Distribution via Homebrew uses a
tap repository holding only a cask file that points at the dmg attached
to the GitHub release; the cask template and per-release update steps
are documented next to the scripts.

Assisted-by: Claude:claude-fable-5:Claude Code
pull/3404/head
Christoph Wille 4 weeks ago
parent
commit
b20bb452c2
  1. 26
      BuildTools/packaging/homebrew/README.md
  2. 16
      BuildTools/packaging/homebrew/ilspy.rb
  3. 27
      BuildTools/packaging/macos/README.md
  4. 65
      BuildTools/packaging/macos/create-dmg.ps1

26
BuildTools/packaging/homebrew/README.md

@ -0,0 +1,26 @@
# Homebrew cask distribution
ILSpy is distributed for macOS via a Homebrew *tap*: a separate repository named
`icsharpcode/homebrew-ilspy` containing nothing but the cask file at `Casks/ilspy.rb`.
Users then install with:
```
brew install --cask icsharpcode/ilspy/ilspy
```
The tap holds no secrets and runs no CI. Signing and notarization happen offline
(see `../macos/README.md`); the cask merely points at the signed dmg attached to the
GitHub release.
## Per-release update (manual)
1. Create the dmg and attach it to the GitHub release (`../macos/README.md`).
2. In the tap repo, edit `Casks/ilspy.rb`:
- `version` — the release version (must match the dmg file name and release tag,
see the `url` line).
- `sha256` — printed by `create-dmg.ps1`, or `shasum -a 256 ILSpy-<version>.dmg`.
3. Commit and push. `brew upgrade --cask ilspy` picks it up immediately; there is no
review process for casks in your own tap.
`ilspy.rb` in this directory is the template for the tap's cask file. If the release
tag or dmg naming scheme ever changes, adjust the `url` line accordingly.

16
BuildTools/packaging/homebrew/ilspy.rb

@ -0,0 +1,16 @@
# Template for the ILSpy Homebrew cask. The live copy belongs in the tap repository
# (icsharpcode/homebrew-ilspy) at Casks/ilspy.rb; see README.md next to this file.
cask "ilspy" do
version "REPLACE_ME" # e.g. 11.0.0.8948
sha256 "REPLACE_ME" # printed by create-dmg.ps1, or: shasum -a 256 ILSpy-<version>.dmg
url "https://github.com/icsharpcode/ILSpy/releases/download/v#{version}/ILSpy-#{version}.dmg"
name "ILSpy"
desc ".NET assembly browser and decompiler"
homepage "https://github.com/icsharpcode/ILSpy"
depends_on macos: ">= :big_sur"
depends_on arch: :arm64
app "ILSpy.app"
end

27
BuildTools/packaging/macos/README.md

@ -0,0 +1,27 @@
# macOS release flow
CI (the `macOS` job in `build-ilspy.yml`) produces an **unsigned** zipped `ILSpy.app`
artifact. All signing happens offline on the release manager's machine; no signing
secrets exist in any CI.
Users who run the unsigned zip directly must clear the quarantine flag once:
`xattr -dr com.apple.quarantine ILSpy.app`. The dmg below is the signed distribution
channel that avoids this.
## Creating the release dmg
1. Download the `ILSpy macOS arm64 <version> (Release)` artifact from the build run on
the release commit and unzip it.
2. Build, sign, and notarize the dmg (see `create-dmg.ps1` for parameter details):
```
./create-dmg.ps1 -AppPath ./ILSpy.app -Version <version> `
-SigningIdentity 'Developer ID Application: <name> (<team>)' `
-Notarize -NotaryProfile <notarytool profile>
```
Omit `-SigningIdentity`/`-Notarize` to produce an unsigned dmg for local testing.
3. Attach `ILSpy-<version>.dmg` to the manually created GitHub release. The dmg file
name must match the URL pattern in the Homebrew cask (`../homebrew/ilspy.rb`).
4. Update the Homebrew cask with the new version and the sha256 the script printed
(see `../homebrew/README.md`).

65
BuildTools/packaging/macos/create-dmg.ps1

@ -0,0 +1,65 @@
#!/usr/bin/env pwsh
# Build (and optionally sign + notarize) the ILSpy dmg for distribution.
#
# This is an OFFLINE release-manager tool: it is never called from CI, because no signing
# happens in CI. Typical flow:
# 1. Download the 'ILSpy macOS arm64 ...' artifact from the build workflow and unzip it.
# 2. ./create-dmg.ps1 -AppPath ./ILSpy.app -Version 11.0.0.8948 `
# -SigningIdentity 'Developer ID Application: ...' -Notarize -NotaryProfile ilspy
# (omit -SigningIdentity for an unsigned smoke-test dmg)
# 3. Attach the dmg to the GitHub release; use the printed sha256 for the Homebrew cask
# (see ../homebrew/README.md).
#
# -NotaryProfile names credentials stored once via:
# xcrun notarytool store-credentials <profile> --apple-id <id> --team-id <team>
param(
[Parameter(Mandatory)]
[string]$AppPath,
[Parameter(Mandatory)]
[string]$Version,
[string]$OutputPath,
[string]$SigningIdentity,
[switch]$Notarize,
[string]$NotaryProfile
)
$ErrorActionPreference = 'Stop'
$PSNativeCommandUseErrorActionPreference = $true
if (-not $IsMacOS) {
throw 'This script needs macOS (codesign, hdiutil, notarytool).'
}
if ($Notarize -and -not $NotaryProfile) {
throw '-Notarize requires -NotaryProfile (a notarytool keychain profile name).'
}
$AppPath = (Resolve-Path $AppPath).Path
if (-not (Test-Path "$AppPath/Contents/Info.plist")) {
throw "$AppPath does not look like an .app bundle."
}
if (-not $OutputPath) {
$OutputPath = "ILSpy-$Version.dmg"
}
if ($SigningIdentity) {
codesign --force --deep --options runtime --timestamp --sign $SigningIdentity $AppPath
}
$stagingDir = Join-Path ([IO.Path]::GetTempPath()) 'ilspy-dmg'
Remove-Item -Recurse -Force $stagingDir -ErrorAction Ignore
New-Item -ItemType Directory $stagingDir | Out-Null
Copy-Item $AppPath $stagingDir -Recurse
ln -s /Applications (Join-Path $stagingDir 'Applications')
Remove-Item $OutputPath -ErrorAction Ignore
hdiutil create -volname "ILSpy $Version" -srcfolder $stagingDir -ov -format UDZO $OutputPath
if ($SigningIdentity) {
codesign --sign $SigningIdentity $OutputPath
}
if ($Notarize) {
xcrun notarytool submit $OutputPath --keychain-profile $NotaryProfile --wait
xcrun stapler staple $OutputPath
}
Write-Host "created $OutputPath"
Write-Host "sha256 (for the Homebrew cask):"
shasum -a 256 $OutputPath
Loading…
Cancel
Save