Compare commits

...

2 Commits

Author SHA1 Message Date
Claude Bot
f6fe97aa7d Improve error message when git is not installed
When installing git dependencies without git installed, show a clear
error message directly where the error occurs.

Before:
  error: FileNotFound cloning repository for git+https://...

After:
  error: Git is not installed. Install Git to clone repository for "package"

    Learn more: https://git-scm.com/downloads

The fix checks for FileNotFound errors in repository.zig at each git
command invocation (fetch, clone, checkout, log) and logs the helpful
message right there, rather than propagating a custom error type.
2025-10-13 17:02:34 +00:00
Claude Bot
59dd5086e7 Improve error message when git is not installed
When a user tries to install a git dependency but doesn't have git
installed, Bun now provides a clear, actionable error message.

Before:
  error: FileNotFound cloning repository for git+https://...

After:
  error: Git is not installed. Install git to clone repository for <package>

    Learn more: https://git-scm.com/downloads

The improved message:
- States the problem clearly ("Git is not installed")
- Tells the user what to do ("Install git")
- Provides a helpful link to git-scm.com/downloads
- Prevents users from thinking "Bun is buggy" when git is missing

The fix works by detecting FileNotFound errors when executing git
commands and returning a specific GitNotFound error that displays
this helpful message.
2025-10-13 16:40:17 +00:00
2 changed files with 117 additions and 49 deletions

View File

@@ -724,16 +724,26 @@ pub fn runTasks(
url,
);
} else if (log_level != .silent) {
manager.log.addErrorFmt(
null,
logger.Loc.Empty,
manager.allocator,
"{s} cloning repository for <b>{s}<r>",
.{
@errorName(err),
name,
},
) catch |e| bun.handleOom(e);
if (err == error.GitNotFound) {
manager.log.addErrorFmt(
null,
logger.Loc.Empty,
manager.allocator,
"Git is not installed. Install Git to clone repository for <b>{s}<r>\n\n Learn more: https://git-scm.com/downloads",
.{name},
) catch |e| bun.handleOom(e);
} else {
manager.log.addErrorFmt(
null,
logger.Loc.Empty,
manager.allocator,
"{s} cloning repository for <b>{s}<r>",
.{
@errorName(err),
name,
},
) catch |e| bun.handleOom(e);
}
}
continue;
}
@@ -798,16 +808,26 @@ pub fn runTasks(
if (task.status == .fail) {
const err = task.err orelse error.Failed;
manager.log.addErrorFmt(
null,
logger.Loc.Empty,
manager.allocator,
"{s} checking out repository for <b>{s}<r>",
.{
@errorName(err),
alias.slice(),
},
) catch |e| bun.handleOom(e);
if (err == error.GitNotFound) {
manager.log.addErrorFmt(
null,
logger.Loc.Empty,
manager.allocator,
"Git is not installed. Install Git to checkout repository for <b>{s}<r>\n\n Learn more: https://git-scm.com/downloads",
.{alias.slice()},
) catch |e| bun.handleOom(e);
} else {
manager.log.addErrorFmt(
null,
logger.Loc.Empty,
manager.allocator,
"{s} checking out repository for <b>{s}<r>",
.{
@errorName(err),
alias.slice(),
},
) catch |e| bun.handleOom(e);
}
continue;
}

View File

@@ -498,13 +498,23 @@ pub const Repository = extern struct {
env,
&[_]string{ "git", "-C", path, "fetch", "--quiet" },
) catch |err| {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"\"git fetch\" for \"{s}\" failed",
.{name},
) catch unreachable;
if (err == error.FileNotFound) {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"Git is not installed. Install Git to clone repository for \"{s}\"\n\n Learn more: https://git-scm.com/downloads",
.{name},
) catch unreachable;
} else {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"\"git fetch\" for \"{s}\" failed",
.{name},
) catch unreachable;
}
return err;
};
break :fetch dir;
@@ -522,7 +532,15 @@ pub const Repository = extern struct {
url,
target,
}) catch |err| {
if (err == error.RepositoryNotFound or attempt > 1) {
if (err == error.FileNotFound) {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"Git is not installed. Install Git to clone repository for \"{s}\"\n\n Learn more: https://git-scm.com/downloads",
.{name},
) catch unreachable;
} else if (err == error.RepositoryNotFound or attempt > 1) {
log.addErrorFmt(
null,
logger.Loc.Empty,
@@ -561,13 +579,23 @@ pub const Repository = extern struct {
else
&[_]string{ "git", "-C", path, "log", "--format=%H", "-1" },
) catch |err| {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"no commit matching \"{s}\" found for \"{s}\" (but repository exists)",
.{ committish, name },
) catch unreachable;
if (err == error.FileNotFound) {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"Git is not installed. Install Git to use git dependencies\n\n Learn more: https://git-scm.com/downloads",
.{},
) catch unreachable;
} else {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"no commit matching \"{s}\" found for \"{s}\" (but repository exists)",
.{ committish, name },
) catch unreachable;
}
return err;
}, " \t\r\n");
}
@@ -599,26 +627,46 @@ pub const Repository = extern struct {
try bun.getFdPath(.fromStdDir(repo_dir), &final_path_buf),
target,
}) catch |err| {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"\"git clone\" for \"{s}\" failed",
.{name},
) catch unreachable;
if (err == error.FileNotFound) {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"Git is not installed. Install Git to use git dependencies\n\n Learn more: https://git-scm.com/downloads",
.{},
) catch unreachable;
} else {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"\"git clone\" for \"{s}\" failed",
.{name},
) catch unreachable;
}
return err;
};
const folder = Path.joinAbsString(PackageManager.get().cache_directory_path, &.{folder_name}, .auto);
_ = exec(allocator, env, &[_]string{ "git", "-C", folder, "checkout", "--quiet", resolved }) catch |err| {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"\"git checkout\" for \"{s}\" failed",
.{name},
) catch unreachable;
if (err == error.FileNotFound) {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"Git is not installed. Install Git to use git dependencies\n\n Learn more: https://git-scm.com/downloads",
.{},
) catch unreachable;
} else {
log.addErrorFmt(
null,
logger.Loc.Empty,
allocator,
"\"git checkout\" for \"{s}\" failed",
.{name},
) catch unreachable;
}
return err;
};
var dir = try bun.openDir(cache_dir, folder_name);