Detailed changes
@@ -526,6 +526,7 @@ impl GitRepository for FakeGitRepository {
_message: gpui::SharedString,
_name_and_email: Option<(gpui::SharedString, gpui::SharedString)>,
_options: CommitOptions,
+ _askpass: AskPassDelegate,
_env: Arc<HashMap<String, String>>,
) -> BoxFuture<'_, Result<()>> {
unimplemented!()
@@ -491,6 +491,7 @@ pub trait GitRepository: Send + Sync {
message: SharedString,
name_and_email: Option<(SharedString, SharedString)>,
options: CommitOptions,
+ askpass: AskPassDelegate,
env: Arc<HashMap<String, String>>,
) -> BoxFuture<'_, Result<()>>;
@@ -1630,41 +1631,39 @@ impl GitRepository for RealGitRepository {
message: SharedString,
name_and_email: Option<(SharedString, SharedString)>,
options: CommitOptions,
+ ask_pass: AskPassDelegate,
env: Arc<HashMap<String, String>>,
) -> BoxFuture<'_, Result<()>> {
let working_directory = self.working_directory();
let git_binary_path = self.any_git_binary_path.clone();
- self.executor
- .spawn(async move {
- let mut cmd = new_smol_command(git_binary_path);
- cmd.current_dir(&working_directory?)
- .envs(env.iter())
- .args(["commit", "--quiet", "-m"])
- .arg(&message.to_string())
- .arg("--cleanup=strip");
+ let executor = self.executor.clone();
+ async move {
+ let mut cmd = new_smol_command(git_binary_path);
+ cmd.current_dir(&working_directory?)
+ .envs(env.iter())
+ .args(["commit", "--quiet", "-m"])
+ .arg(&message.to_string())
+ .arg("--cleanup=strip")
+ .stdout(smol::process::Stdio::piped())
+ .stderr(smol::process::Stdio::piped());
- if options.amend {
- cmd.arg("--amend");
- }
+ if options.amend {
+ cmd.arg("--amend");
+ }
- if options.signoff {
- cmd.arg("--signoff");
- }
+ if options.signoff {
+ cmd.arg("--signoff");
+ }
- if let Some((name, email)) = name_and_email {
- cmd.arg("--author").arg(&format!("{name} <{email}>"));
- }
+ if let Some((name, email)) = name_and_email {
+ cmd.arg("--author").arg(&format!("{name} <{email}>"));
+ }
- let output = cmd.output().await?;
+ run_git_command(env, ask_pass, cmd, &executor).await?;
- anyhow::ensure!(
- output.status.success(),
- "Failed to commit:\n{}",
- String::from_utf8_lossy(&output.stderr)
- );
- Ok(())
- })
- .boxed()
+ Ok(())
+ }
+ .boxed()
}
fn push(
@@ -2469,8 +2468,17 @@ mod tests {
use super::*;
use gpui::TestAppContext;
+ fn disable_git_global_config() {
+ unsafe {
+ std::env::set_var("GIT_CONFIG_GLOBAL", "");
+ std::env::set_var("GIT_CONFIG_SYSTEM", "");
+ }
+ }
+
#[gpui::test]
async fn test_checkpoint_basic(cx: &mut TestAppContext) {
+ disable_git_global_config();
+
cx.executor().allow_parking();
let repo_dir = tempfile::tempdir().unwrap();
@@ -2486,6 +2494,7 @@ mod tests {
cx.executor(),
)
.unwrap();
+
repo.stage_paths(vec![repo_path("file")], Arc::new(HashMap::default()))
.await
.unwrap();
@@ -2493,6 +2502,7 @@ mod tests {
"Initial commit".into(),
None,
CommitOptions::default(),
+ AskPassDelegate::new(&mut cx.to_async(), |_, _, _| {}),
Arc::new(checkpoint_author_envs()),
)
.await
@@ -2519,6 +2529,7 @@ mod tests {
"Commit after checkpoint".into(),
None,
CommitOptions::default(),
+ AskPassDelegate::new(&mut cx.to_async(), |_, _, _| {}),
Arc::new(checkpoint_author_envs()),
)
.await
@@ -2556,6 +2567,8 @@ mod tests {
#[gpui::test]
async fn test_checkpoint_empty_repo(cx: &mut TestAppContext) {
+ disable_git_global_config();
+
cx.executor().allow_parking();
let repo_dir = tempfile::tempdir().unwrap();
@@ -2600,6 +2613,8 @@ mod tests {
#[gpui::test]
async fn test_compare_checkpoints(cx: &mut TestAppContext) {
+ disable_git_global_config();
+
cx.executor().allow_parking();
let repo_dir = tempfile::tempdir().unwrap();
@@ -2639,6 +2654,8 @@ mod tests {
#[gpui::test]
async fn test_checkpoint_exclude_binary_files(cx: &mut TestAppContext) {
+ disable_git_global_config();
+
cx.executor().allow_parking();
let repo_dir = tempfile::tempdir().unwrap();
@@ -2669,6 +2686,7 @@ mod tests {
"Initial commit".into(),
None,
CommitOptions::default(),
+ AskPassDelegate::new(&mut cx.to_async(), |_, _, _| {}),
Arc::new(checkpoint_author_envs()),
)
.await
@@ -1585,6 +1585,7 @@ impl GitPanel {
return;
}
+ let askpass = self.askpass_delegate("git commit", window, cx);
let commit_message = self.custom_or_suggested_commit_message(window, cx);
let Some(mut message) = commit_message else {
@@ -1599,7 +1600,7 @@ impl GitPanel {
let task = if self.has_staged_changes() {
// Repository serializes all git operations, so we can just send a commit immediately
let commit_task = active_repository.update(cx, |repo, cx| {
- repo.commit(message.into(), None, options, cx)
+ repo.commit(message.into(), None, options, askpass, cx)
});
cx.background_spawn(async move { commit_task.await? })
} else {
@@ -1621,7 +1622,7 @@ impl GitPanel {
cx.spawn(async move |_, cx| {
stage_task.await?;
let commit_task = active_repository.update(cx, |repo, cx| {
- repo.commit(message.into(), None, options, cx)
+ repo.commit(message.into(), None, options, askpass, cx)
})?;
commit_task.await?
})
@@ -1957,6 +1957,15 @@ impl GitStore {
) -> Result<proto::Ack> {
let repository_id = RepositoryId::from_proto(envelope.payload.repository_id);
let repository_handle = Self::repository_for_request(&this, repository_id, &mut cx)?;
+ let askpass_id = envelope.payload.askpass_id;
+
+ let askpass = make_remote_delegate(
+ this,
+ envelope.payload.project_id,
+ repository_id,
+ askpass_id,
+ &mut cx,
+ );
let message = SharedString::from(envelope.payload.message);
let name = envelope.payload.name.map(SharedString::from);
@@ -1972,6 +1981,7 @@ impl GitStore {
amend: options.amend,
signoff: options.signoff,
},
+ askpass,
cx,
)
})?
@@ -4216,9 +4226,12 @@ impl Repository {
message: SharedString,
name_and_email: Option<(SharedString, SharedString)>,
options: CommitOptions,
+ askpass: AskPassDelegate,
_cx: &mut App,
) -> oneshot::Receiver<Result<()>> {
let id = self.id;
+ let askpass_delegates = self.askpass_delegates.clone();
+ let askpass_id = util::post_inc(&mut self.latest_askpass_id);
self.send_job(Some("git commit".into()), move |git_repo, _cx| async move {
match git_repo {
@@ -4228,10 +4241,15 @@ impl Repository {
..
} => {
backend
- .commit(message, name_and_email, options, environment)
+ .commit(message, name_and_email, options, askpass, environment)
.await
}
RepositoryState::Remote { project_id, client } => {
+ askpass_delegates.lock().insert(askpass_id, askpass);
+ let _defer = util::defer(|| {
+ let askpass_delegate = askpass_delegates.lock().remove(&askpass_id);
+ debug_assert!(askpass_delegate.is_some());
+ });
let (name, email) = name_and_email.unzip();
client
.request(proto::Commit {
@@ -4244,6 +4262,7 @@ impl Repository {
amend: options.amend,
signoff: options.signoff,
}),
+ askpass_id,
})
.await
.context("sending commit request")?;
@@ -347,6 +347,7 @@ message Commit {
string message = 6;
optional CommitOptions options = 7;
reserved 8;
+ uint64 askpass_id = 9;
message CommitOptions {
bool amend = 1;