Compare commits

..
7 Commits
Author SHA1 Message Date
Junegunn Choi 14aacc115d Avoid second environment approval for msi job
- msi job used RELEASE_PAT only so that publishing would trigger
  winget.yml, which required approving the release environment again
- Publish with GITHUB_TOKEN instead and call winget.yml directly
- Skip winget for prerelease versions, as the released event did
2026-10-29 21:41:27 +09:00
Junegunn Choi 5853d57518 Add CHANGELOG entry for #4943 2026-10-26 20:29:14 +09:00
Junegunn Choi e19c2c4c6e Shorten MSI comments 2026-10-26 20:28:46 +09:00
Junegunn Choi 68ef9cf0d0 Skip MSI build for prerelease versions
- MSI versions cannot have a suffix such as -rc1, so wix build fails
- Release is still published
2026-10-26 20:27:47 +09:00
Junegunn Choi 243ccc325b Add MSIs to release checksum file 2026-10-26 20:27:22 +09:00
Junegunn Choi d7138593f2 Publish release only after MSI upload
- goreleaser creates a draft release
- msi job publishes it after uploading the MSIs
- Publishing triggers winget.yml, which previously ran before the MSIs
  existed and left them out of the manifest
- If the msi job fails, the release stays a draft
2026-10-26 20:26:50 +09:00
Marshall Porter 5b2936db82 Add WiX .msi installer alongside portable zip for Windows
winget currently only has a `portable` installer to offer for fzf, which
installs via a symlink into the WinGet Links folder. That link is created
by whoever runs winget, normally a non-elevated terminal, and Windows will
not let an elevated process follow a link that a less-privileged process
created ("The path cannot be traversed because it contains an untrusted
mount point"). An administrator's SSH session is elevated, so fzf, and the
shell integration that runs it at startup, fails there.

Build a real per-machine .msi with the WiX dotnet-tool CLI (this is a Go
project, so cargo-wix doesn't apply) from the goreleaser-built fzf.exe, for
amd64 and arm64 (WiX's -arch has no armv7 target). It installs to Program
Files with its own machine PATH entry, so there is no link. WiX only runs
on Windows, so the release job hands the Windows binaries to a new msi job
on windows-latest. The MSIs are built in both workflow modes, so a
workflow_dispatch validation run checks them, and uploaded alongside the
.zip on a tag push; the winget-releaser installers-regex also matches .msi.
WiX is pinned to 5.0.2, the last release that does not require accepting
its Open Source Maintenance Fee EULA.
2026-10-26 20:26:33 +09:00
5 changed files with 146 additions and 4 deletions

No files matched your search

+88
View File
@@ -18,6 +18,8 @@ jobs:
release:
runs-on: macos-latest
environment: release
outputs:
version: ${{ steps.ver.outputs.version }}
steps:
- uses: actions/checkout@v7
with:
@@ -74,3 +76,89 @@ jobs:
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
# For the msi job
- uses: actions/upload-artifact@v7
with:
name: windows-binaries
path: |
dist/*windows_amd64*/fzf.exe
dist/*windows_arm64*/fzf.exe
if-no-files-found: error
# winget's portable install runs fzf through a symlink that admin SSH
# sessions refuse to follow (#4943). The MSI installs a real file instead.
# WiX only runs on Windows.
msi:
needs: release
runs-on: windows-latest
env:
# MSI versions cannot have a suffix such as -rc1
BUILD_MSI: ${{ !contains(needs.release.outputs.version, '-') }}
steps:
- uses: actions/checkout@v7
- uses: actions/download-artifact@v8
if: env.BUILD_MSI == 'true'
with:
name: windows-binaries
path: dist
- uses: actions/setup-dotnet@v6
if: env.BUILD_MSI == 'true'
with:
dotnet-version: '8.0.x'
# WiX 6 and later fall under the Open Source Maintenance Fee
- name: Install WiX
if: env.BUILD_MSI == 'true'
run: dotnet tool install --global wix --version 5.0.2
- name: Build Windows MSI installers
if: env.BUILD_MSI == 'true'
shell: bash
run: |
set -e
V='${{ needs.release.outputs.version }}'
for pair in "amd64:x64" "arm64:arm64"; do
goarch="${pair%%:*}"
wixarch="${pair##*:}"
bindir=$(dirname "$(find dist -type f -iname fzf.exe -path "*windows_${goarch}*" | head -n1)")
wix build wix/main.wxs -arch "$wixarch" -d Version="$V" -d BinDir="$bindir" -o "dist/fzf-${V}-windows_${goarch}.msi"
done
ls -la dist/*.msi
- uses: actions/upload-artifact@v7
if: env.BUILD_MSI == 'true'
with:
name: windows-msi
path: dist/*.msi
- name: Upload MSI installers and publish release
if: github.event_name == 'push'
shell: bash
run: |
set -e
V='${{ needs.release.outputs.version }}'
if [[ $BUILD_MSI == true ]]; then
sums="fzf_${V}_checksums.txt"
# Drop MSI lines from a previous run of this job
gh release download "v$V" -p "$sums" -O - | grep -v '\.msi$' > "dist/$sums"
# sha256sum on Windows may print '<hash> *<name>'
(cd dist && sha256sum fzf-*.msi) | sed 's/ \*/ /' >> "dist/$sums"
gh release upload "v$V" dist/*.msi "dist/$sums" --clobber
fi
gh release edit "v$V" --draft=false
env:
GITHUB_TOKEN: ${{ github.token }}
# Called directly because a release published with GITHUB_TOKEN does not
# trigger other workflows
winget:
needs: [release, msi]
if: github.event_name == 'push' && !contains(needs.release.outputs.version, '-')
uses: ./.github/workflows/winget.yml
with:
release-tag: v${{ needs.release.outputs.version }}
secrets:
WINGET_TOKEN: ${{ secrets.WINGET_TOKEN }}
+10 -4
View File
@@ -1,7 +1,13 @@
name: Publish to Winget
on:
release:
types: [released]
workflow_call:
inputs:
release-tag:
type: string
required: true
secrets:
WINGET_TOKEN:
required: true
workflow_dispatch:
inputs:
release-tag:
@@ -16,6 +22,6 @@ jobs:
- uses: vedantmgoyal2009/winget-releaser@4ffc7888bffd451b357355dc214d43bb9f23917e # v2
with:
identifier: junegunn.fzf
release-tag: ${{ inputs.release-tag || github.event.release.tag_name }}
installers-regex: '-windows_(armv7|arm64|amd64)\.zip$'
release-tag: ${{ inputs.release-tag }}
installers-regex: '-windows_(armv7|arm64|amd64)\.(zip|msi)$'
token: ${{ secrets.WINGET_TOKEN }}
+2
View File
@@ -120,6 +120,8 @@ release:
owner: junegunn
name: fzf
prerelease: auto
# Published by the msi job in release.yml after it uploads the MSIs
draft: true
name_template: '{{ .Version }}'
snapshot:
+3
View File
@@ -29,6 +29,9 @@ CHANGELOG
- Fixed `--no-sort` being ignored in filter mode with `--sync`, `--tac`, or `--bench` (#4940) (@NavpreetSSidhu)
- Vim plugin: Fixed garbage text on screen in Neovim with `set title` when the fzf command contains ANSI escape sequences (#4941)
- Fixed `--walker=follow` skipping a symlink in one `--walker-root` when its target is an ancestor of another root (#4944) (@mabunemeh)
- Windows: Added `.msi` installers for amd64 and arm64, also offered through winget (#4943) (@meop)
- The portable package runs fzf through a symlink in the WinGet Links folder, which an administrator's SSH session refuses to follow
- The MSI installs `fzf.exe` under Program Files and adds it to the system PATH
- Fixed O(n^2) action parsing in `--listen`. A single ~1 MB request could block the server for ~30 s (@zachariah-mithani, AploSec)
0.74.5
+43
View File
@@ -0,0 +1,43 @@
<?xml version='1.0' encoding='utf-8'?>
<!--
Per-machine installer for fzf. See the msi job in .github/workflows/release.yml.
wix build main.wxs -arch <x64|arm64> -d Version=<ver> -d BinDir=<dir of fzf.exe>
-->
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Package
Name="fzf"
Manufacturer="junegunn"
Version="$(var.Version)"
UpgradeCode="C34C8C24-3E05-4D14-BD9A-439C3F6E9942"
Language="1033"
Scope="perMachine">
<SummaryInformation Description="fzf - a command-line fuzzy finder" Manufacturer="junegunn" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed. Setup will now exit." />
<MediaTemplate EmbedCab="yes" />
<StandardDirectory Id="ProgramFiles6432Folder">
<Directory Id="APPLICATIONFOLDER" Name="fzf">
<Directory Id="BinFolder" Name="bin" />
</Directory>
</StandardDirectory>
<Feature Id="Main" Title="fzf" Level="1" AllowAbsent="no">
<ComponentGroupRef Id="MainComponents" />
</Feature>
<ComponentGroup Id="MainComponents" Directory="BinFolder">
<Component Id="FzfBinary">
<File Id="FzfExe" Name="fzf.exe" Source="$(var.BinDir)\fzf.exe" KeyPath="yes" />
</Component>
<Component Id="LicenseFile" Directory="APPLICATIONFOLDER">
<File Id="License" Name="LICENSE" Source="LICENSE" KeyPath="yes" />
</Component>
<Component Id="PathEnv" Guid="8B7C2C6A-F4A0-4E3E-9E37-2E8F3E4E5B6A">
<Environment Id="PATH" Name="PATH" Value="[BinFolder]" Permanent="no" Part="last" Action="set" System="yes" />
</Component>
</ComponentGroup>
</Package>
</Wix>