Compare commits

..
17 Commits
Author SHA1 Message Date
Junegunn Choi ab9a552f5b Re-order CHANGELOG 2026-11-06 10:39:01 +09:00
Junegunn Choi a38beb544f Merge remote-tracking branch 'origin/master' into winget-msi 2026-11-06 10:37:26 +09:00
Junegunn Choi b5c054ee18 Document draft release flow in RELEASE.md 2026-11-05 22:55:33 +09:00
Junegunn Choi 3dd8e03ddc Fail msi job when release is already published
- Re-run would replace published MSIs with new builds, whose hashes
  differ from a winget manifest that may already be merged
- Also stops winget job from submitting again
2026-11-05 22:55:16 +09:00
Junegunn Choi 02d8843869 Remove make release
- Release workflow replaced it
- With draft releases, it would push master while the release was still
  a draft, so install scripts would point at assets not yet public
2026-11-05 22:55:01 +09:00
Junegunn Choi c076805825 Note how to switch existing winget installs to MSI 2026-11-04 16:02:58 +09:00
Junegunn Choi 398b66342d Drop armv7 from winget installer regex
- No Windows armv7 build since 0.73.1
2026-11-04 16:02:58 +09:00
Junegunn Choi fa30c5a278 Fix wix build path in usage comment
- Source="LICENSE" resolves from repository root, where CI runs it
2026-11-04 16:02:58 +09:00
Junegunn Choi e279faac50 Replace existing draft when retrying release job
- goreleaser looks up the release by tag, which does not return drafts
- A retry created a second draft for the same tag, and msi job could
  publish either one
2026-11-03 13:51:47 +09:00
Junegunn Choi 386c3e9ea9 Limit winget workflow token to read access
- winget-releaser passes github.token to cargo-bins/cargo-binstall@main
- Token had contents: write from release.yml, and repository default
  (write) when run by hand
2026-11-03 13:51:37 +09:00
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
10 changed files with 12 additions and 43 deletions

No files matched your search

-1
View File
@@ -30,7 +30,6 @@ CHANGELOG
```
- Fixed `--no-sort` being ignored in filter mode with `--sync`, `--tac`, or `--bench` (#4940) (@NavpreetSSidhu)
- Fixed `--walker=follow` skipping a symlink in one `--walker-root` when its target is an ancestor of another root (#4944) (@mabunemeh)
- Fixed data races in the preview and the search result cache (#4947)
- Fixed O(n^2) action parsing in `--listen`. A single ~1 MB request could block the server for ~30 s (@zachariah-mithani, AploSec)
- Windows
- Fixed `--with-shell` on Windows not detecting cmd, PowerShell, and pwsh, which made fzf quote commands and entries for a POSIX shell (#4936) (@vimkim)
+3 -3
View File
@@ -22,7 +22,7 @@ triggered by a tag push.
3. Verify file consistency, sign the tag, and push the tag.
```sh
make tag VERSION=0.75.0
make tag VERSION=0.74.5
```
`make tag` runs `prerelease` first (checks that the version
@@ -54,8 +54,8 @@ The release stays a draft. Do not push `master` until it is published.
- Publish without MSIs and submit to winget by hand:
```sh
gh release edit v0.75.0 --draft=false
gh workflow run winget.yml -f release-tag=v0.75.0
gh release edit v0.74.5 --draft=false
gh workflow run winget.yml -f release-tag=v0.74.5
```
## Testing the workflow
+1 -1
View File
@@ -2,7 +2,7 @@
set -u
version=0.75.0
version=0.74.5
auto_completion=
key_bindings=
update_config=2
+1 -1
View File
@@ -1,4 +1,4 @@
$version="0.75.0"
$version="0.74.5"
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
+1 -1
View File
@@ -11,7 +11,7 @@ import (
"github.com/junegunn/fzf/src/protector"
)
var version = "0.75"
var version = "0.74"
var revision = "devel"
//go:embed shell/key-bindings.bash
+1 -1
View File
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
..
.TH fzf\-tmux 1 "Nov 2026" "fzf 0.75.0" "fzf\-tmux - open fzf in tmux split pane"
.TH fzf\-tmux 1 "Oct 2026" "fzf 0.74.5" "fzf\-tmux - open fzf in tmux split pane"
.SH NAME
fzf\-tmux - open fzf in tmux split pane
+1 -1
View File
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
..
.TH fzf 1 "Nov 2026" "fzf 0.75.0" "fzf - a command-line fuzzy finder"
.TH fzf 1 "Oct 2026" "fzf 0.74.5" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
+1 -5
View File
@@ -137,17 +137,13 @@ func (m *Matcher) Loop() {
m.scanMutex.Lock()
result = m.scan(request)
m.scanMutex.Unlock()
// Not on a cached merger, which the terminal may be reading. It
// already has the same value.
if result.merger != nil {
result.merger.final = request.final
}
}
if !result.cancelled {
if result.cacheable() {
m.mergerCache[patternString] = result
}
result.merger.final = request.final
m.eventBox.Set(EvtSearchFin, result)
}
}
+3 -20
View File
@@ -843,8 +843,6 @@ type previewRequest struct {
list [3][]*Item // current, select, and all matched items
env []string
query string
lastAction actionType
prompt string
}
type previewResult struct {
@@ -6460,8 +6458,6 @@ func (t *Terminal) Loop() error {
var commandTemplate string
var env []string
var query string
var lastAction actionType
var prompt string
initialOffset := 0
t.previewBox.Wait(func(events *util.Events) {
for req, value := range *events {
@@ -6476,8 +6472,6 @@ func (t *Terminal) Loop() error {
items = request.list
env = request.env
query = request.query
lastAction = request.lastAction
prompt = request.prompt
requested = true
}
}
@@ -6492,18 +6486,7 @@ func (t *Terminal) Loop() error {
version++
// We don't display preview window if no match
if items[0] != nil {
// Not t.replacePlaceholder, which reads fields the main loop writes
command, tempFiles := replacePlaceholder(replacePlaceholderParams{
template: commandTemplate,
stripAnsi: t.ansi,
delimiter: t.delimiter,
printsep: t.printsep,
query: query,
allItems: items,
lastAction: lastAction,
prompt: prompt,
executor: t.executor,
})
command, tempFiles := t.replacePlaceholder(commandTemplate, false, query, items)
cmd := t.executor.ExecCommand(command, true)
cmd.Env = env
@@ -6636,7 +6619,7 @@ func (t *Terminal) Loop() error {
if len(command) > 0 && t.canPreview() {
_, list := t.buildPlusList(command, false)
t.cancelPreview()
t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.evaluateScrollOffset(), list, t.environForPreview(), string(t.input), t.lastAction, t.promptString})
t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.evaluateScrollOffset(), list, t.environForPreview(), string(t.input)})
}
}
@@ -7251,7 +7234,7 @@ func (t *Terminal) Loop() error {
if valid {
t.cancelPreview()
t.previewBox.Set(reqPreviewEnqueue,
previewRequest{t.previewOpts.command, t.evaluateScrollOffset(), list, t.environForPreview(), string(t.input), t.lastAction, t.promptString})
previewRequest{t.previewOpts.command, t.evaluateScrollOffset(), list, t.environForPreview(), string(t.input)})
}
} else {
// Discard the preview content so that it won't accidentally appear
-9
View File
@@ -640,15 +640,6 @@ class TestPreview < TestInteractive
end
end
def test_preview_action_and_prompt
tmux.send_keys %(seq 100 | #{FZF} --preview 'echo [$FZF_ACTION/$FZF_PROMPT/{q}]' --bind 'space:change-prompt(foo> )'), :Enter
tmux.until { |lines| assert lines.any_include?('[start/> /]') }
tmux.send_keys '1'
tmux.until { |lines| assert lines.any_include?('[char/> /1]') }
tmux.send_keys :Space, '2'
tmux.until { |lines| assert lines.any_include?('[char/foo> /12]') }
end
def test_preview_wrap_sign_between_ansi_fragments
tmux.send_keys %(seq 1 | #{FZF} --preview 'echo -e "\\x1b[33m1234567890 \\x1b[mhello"; echo -e "\\x1b[33m1234567890 \\x1b[mhello"' --preview-window 10,wrap-word), :Enter
tmux.until do |lines|