Skip to content

fix(brew): update Homebrew before non-interactive installs#43

Merged
ChangeHow merged 1 commit into
mainfrom
fix/homebrew-ask-compatibility
Jul 12, 2026
Merged

fix(brew): update Homebrew before non-interactive installs#43
ChangeHow merged 1 commit into
mainfrom
fix/homebrew-ask-compatibility

Conversation

@ChangeHow

Copy link
Copy Markdown
Owner

问题

旧版 Homebrew 不支持 brew install --no-ask,导致选中的软件全部安装失败。

修复

  • 检测到 Homebrew 后,首次安装软件前执行一次非交互 brew update
  • 更新失败立即终止,避免继续产生部分安装状态
  • 更新成功后统一使用最新版支持的 brew install --no-ask
  • curl bootstrap、Zsh bootstrap、CLI/App 安装和 benchmark 使用相同语义

验证

  • npm test(231 tests passed)
  • git diff --check

@github-actions

Copy link
Copy Markdown

Zsh startup benchmark

Ubuntu 24.04 with Linuxbrew, atuin, fnm, fzf, zoxide, zinit, and the shipped plugins. Lower is better.

Warm startup (daily use)

Command Mean [ms] Min [ms] Max [ms] Relative
current (c9fc0b4) 75.2 ± 0.6 74.6 76.8 1.00
main (4b0e035) 75.9 ± 2.4 74.5 84.9 1.01 ± 0.03
previous commit (4b0e035) 76.1 ± 1.6 74.9 80.9 1.01 ± 0.02

Cache-miss startup

Completion and tool-init caches are removed before every run; installed tools and plugins remain.

Command Mean [ms] Min [ms] Max [ms] Relative
current (c9fc0b4) 586.4 ± 2.9 583.5 593.1 1.00
main (4b0e035) 586.9 ± 2.6 582.9 590.8 1.00 ± 0.01
previous commit (4b0e035) 592.9 ± 5.9 585.6 603.8 1.01 ± 0.01

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a mechanism to ensure brew update is run before installing Homebrew packages, while tracking the update state to avoid redundant executions. This logic is implemented across install.sh, src/steps/bootstrap.js, and src/utils/shell.js, with corresponding test updates. The review feedback highlights a potential issue with test isolation and redundant updates due to the module-level global state. It suggests exporting a helper function setHomebrewUpdated to allow resetting the state in tests and updating it in bootstrap.js after the initial update.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/utils/shell.js
}
}

let homebrewUpdated = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

为了支持在其他模块和测试中更新或重置 homebrewUpdated 的状态,建议导出一个 setHomebrewUpdated 辅助函数。

这样做有两个主要好处:

  1. 避免重复更新:在 src/steps/bootstrap.js 中执行 brew update 后,可以将其设置为 true,从而避免后续调用 brewInstall 时再次触发缓慢的 brew update
  2. 测试隔离:在单元测试中,可以在 beforeEach 中将其重置为 false,防止测试用例之间共享全局状态导致测试不稳定。
let homebrewUpdated = false;

export function setHomebrewUpdated(value) {
  homebrewUpdated = value;
}

Comment thread src/steps/bootstrap.js
Comment on lines 137 to 139
if (manager === "brew") {
await runStream("brew install --no-ask zsh");
await runStream("env -u HOMEBREW_ASK brew update && brew install --no-ask zsh");
} else if (manager === "apt-get") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在成功执行 brew update 并安装 Zsh 后,建议调用 setHomebrewUpdated(true)

这样可以确保后续通过 brewInstall 安装其他软件时,不会再次触发冗余且缓慢的 brew update,从而显著提升整体安装效率。

注意

  1. 需要在文件顶部导入 setHomebrewUpdated
    import { commandExists, run, runStream, setHomebrewUpdated } from "../utils/shell.js";
  2. 需要在 tests/bootstrap.test.jsshell.js 模块 mock 中添加 setHomebrewUpdated: vi.fn(),以避免测试报错。
Suggested change
if (manager === "brew") {
await runStream("brew install --no-ask zsh");
await runStream("env -u HOMEBREW_ASK brew update && brew install --no-ask zsh");
} else if (manager === "apt-get") {
if (manager === "brew") {
await runStream("env -u HOMEBREW_ASK brew update && brew install --no-ask zsh");
setHomebrewUpdated(true);
} else if (manager === "apt-get") {

Comment thread tests/shell.test.js

expect(brewInstall("ghostty", { cask: true })).toBe(true);
expect(execSync).toHaveBeenCalledWith("brew install --no-ask --cask ghostty", { stdio: "inherit" });
expect(execSync.mock.calls.filter(([command]) => command.includes("brew update"))).toHaveLength(1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

由于 homebrewUpdatedsrc/utils/shell.js 中的模块级全局变量,它会在不同的测试用例之间共享。

在当前测试中,第一个 brewInstall("jq") 会将 homebrewUpdated 设为 true。这会导致后续的测试(例如 "propagates Ctrl-C from Homebrew installs")在调用 brewInstall 时直接跳过 brewUpdate()

为了保证测试的隔离性,建议在 beforeEach 中重置该状态:

  1. 在文件顶部导入 setHomebrewUpdated
    import { brewInstall, runStream, setHomebrewUpdated } from "../src/utils/shell.js";
  2. beforeEach 中重置状态:
    beforeEach(() => {
      vi.clearAllMocks();
      setHomebrewUpdated(false);
    });

@ChangeHow
ChangeHow merged commit 4a52135 into main Jul 12, 2026
2 checks passed
@ChangeHow
ChangeHow deleted the fix/homebrew-ask-compatibility branch July 12, 2026 13:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant