Use git config --global user.email
for email address in automatic Co-authored-by
(#32624)
Release Notes: - Automatic population of `Co-authored-by` now uses `git config --global user.email` --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com> Co-authored-by: Conrad <conrad@zed.dev>
This commit is contained in:
parent
e56a027bea
commit
7d708c14e4
24 changed files with 188 additions and 69 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -6162,6 +6162,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"askpass",
|
"askpass",
|
||||||
"buffer_diff",
|
"buffer_diff",
|
||||||
|
"call",
|
||||||
"chrono",
|
"chrono",
|
||||||
"collections",
|
"collections",
|
||||||
"command_palette_hooks",
|
"command_palette_hooks",
|
||||||
|
|
|
@ -269,7 +269,6 @@ async fn test_channel_messages(cx: &mut TestAppContext) {
|
||||||
github_login: "nathansobo".into(),
|
github_login: "nathansobo".into(),
|
||||||
avatar_url: "http://avatar.com/nathansobo".into(),
|
avatar_url: "http://avatar.com/nathansobo".into(),
|
||||||
name: None,
|
name: None,
|
||||||
email: None,
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -323,7 +322,6 @@ async fn test_channel_messages(cx: &mut TestAppContext) {
|
||||||
github_login: "maxbrunsfeld".into(),
|
github_login: "maxbrunsfeld".into(),
|
||||||
avatar_url: "http://avatar.com/maxbrunsfeld".into(),
|
avatar_url: "http://avatar.com/maxbrunsfeld".into(),
|
||||||
name: None,
|
name: None,
|
||||||
email: None,
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -368,7 +366,6 @@ async fn test_channel_messages(cx: &mut TestAppContext) {
|
||||||
github_login: "as-cii".into(),
|
github_login: "as-cii".into(),
|
||||||
avatar_url: "http://avatar.com/as-cii".into(),
|
avatar_url: "http://avatar.com/as-cii".into(),
|
||||||
name: None,
|
name: None,
|
||||||
email: None,
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1887,8 +1887,16 @@ mod tests {
|
||||||
.set_entity(&entity3, &mut cx.to_async());
|
.set_entity(&entity3, &mut cx.to_async());
|
||||||
drop(subscription3);
|
drop(subscription3);
|
||||||
|
|
||||||
server.send(proto::JoinProject { project_id: 1 });
|
server.send(proto::JoinProject {
|
||||||
server.send(proto::JoinProject { project_id: 2 });
|
project_id: 1,
|
||||||
|
committer_name: None,
|
||||||
|
committer_email: None,
|
||||||
|
});
|
||||||
|
server.send(proto::JoinProject {
|
||||||
|
project_id: 2,
|
||||||
|
committer_name: None,
|
||||||
|
committer_email: None,
|
||||||
|
});
|
||||||
done_rx1.recv().await.unwrap();
|
done_rx1.recv().await.unwrap();
|
||||||
done_rx2.recv().await.unwrap();
|
done_rx2.recv().await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,6 @@ pub struct User {
|
||||||
pub github_login: String,
|
pub github_login: String,
|
||||||
pub avatar_uri: SharedUri,
|
pub avatar_uri: SharedUri,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub email: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -58,6 +57,8 @@ pub struct Collaborator {
|
||||||
pub replica_id: ReplicaId,
|
pub replica_id: ReplicaId,
|
||||||
pub user_id: UserId,
|
pub user_id: UserId,
|
||||||
pub is_host: bool,
|
pub is_host: bool,
|
||||||
|
pub committer_name: Option<String>,
|
||||||
|
pub committer_email: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for User {
|
impl PartialOrd for User {
|
||||||
|
@ -881,7 +882,6 @@ impl User {
|
||||||
github_login: message.github_login,
|
github_login: message.github_login,
|
||||||
avatar_uri: message.avatar_url.into(),
|
avatar_uri: message.avatar_url.into(),
|
||||||
name: message.name,
|
name: message.name,
|
||||||
email: message.email,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -912,6 +912,8 @@ impl Collaborator {
|
||||||
replica_id: message.replica_id as ReplicaId,
|
replica_id: message.replica_id as ReplicaId,
|
||||||
user_id: message.user_id as UserId,
|
user_id: message.user_id as UserId,
|
||||||
is_host: message.is_host,
|
is_host: message.is_host,
|
||||||
|
committer_name: message.committer_name,
|
||||||
|
committer_email: message.committer_email,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,9 @@ CREATE TABLE "project_collaborators" (
|
||||||
"connection_server_id" INTEGER NOT NULL REFERENCES servers (id) ON DELETE CASCADE,
|
"connection_server_id" INTEGER NOT NULL REFERENCES servers (id) ON DELETE CASCADE,
|
||||||
"user_id" INTEGER NOT NULL,
|
"user_id" INTEGER NOT NULL,
|
||||||
"replica_id" INTEGER NOT NULL,
|
"replica_id" INTEGER NOT NULL,
|
||||||
"is_host" BOOLEAN NOT NULL
|
"is_host" BOOLEAN NOT NULL,
|
||||||
|
"committer_name" VARCHAR,
|
||||||
|
"committer_email" VARCHAR
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX "index_project_collaborators_on_project_id" ON "project_collaborators" ("project_id");
|
CREATE INDEX "index_project_collaborators_on_project_id" ON "project_collaborators" ("project_id");
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
alter table project_collaborators
|
||||||
|
add column committer_name varchar;
|
||||||
|
alter table project_collaborators
|
||||||
|
add column committer_email varchar;
|
|
@ -751,6 +751,8 @@ pub struct ProjectCollaborator {
|
||||||
pub user_id: UserId,
|
pub user_id: UserId,
|
||||||
pub replica_id: ReplicaId,
|
pub replica_id: ReplicaId,
|
||||||
pub is_host: bool,
|
pub is_host: bool,
|
||||||
|
pub committer_name: Option<String>,
|
||||||
|
pub committer_email: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectCollaborator {
|
impl ProjectCollaborator {
|
||||||
|
@ -760,6 +762,8 @@ impl ProjectCollaborator {
|
||||||
replica_id: self.replica_id.0 as u32,
|
replica_id: self.replica_id.0 as u32,
|
||||||
user_id: self.user_id.to_proto(),
|
user_id: self.user_id.to_proto(),
|
||||||
is_host: self.is_host,
|
is_host: self.is_host,
|
||||||
|
committer_name: self.committer_name.clone(),
|
||||||
|
committer_email: self.committer_email.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,8 @@ impl Database {
|
||||||
user_id: collaborator.user_id.to_proto(),
|
user_id: collaborator.user_id.to_proto(),
|
||||||
replica_id: collaborator.replica_id.0 as u32,
|
replica_id: collaborator.replica_id.0 as u32,
|
||||||
is_host: false,
|
is_host: false,
|
||||||
|
committer_name: None,
|
||||||
|
committer_email: None,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
})
|
||||||
|
@ -225,6 +227,8 @@ impl Database {
|
||||||
user_id: collaborator.user_id.to_proto(),
|
user_id: collaborator.user_id.to_proto(),
|
||||||
replica_id: collaborator.replica_id.0 as u32,
|
replica_id: collaborator.replica_id.0 as u32,
|
||||||
is_host: false,
|
is_host: false,
|
||||||
|
committer_name: None,
|
||||||
|
committer_email: None,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
},
|
||||||
|
@ -261,6 +265,8 @@ impl Database {
|
||||||
replica_id: db_collaborator.replica_id.0 as u32,
|
replica_id: db_collaborator.replica_id.0 as u32,
|
||||||
user_id: db_collaborator.user_id.to_proto(),
|
user_id: db_collaborator.user_id.to_proto(),
|
||||||
is_host: false,
|
is_host: false,
|
||||||
|
committer_name: None,
|
||||||
|
committer_email: None,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
collaborator_ids_to_remove.push(db_collaborator.id);
|
collaborator_ids_to_remove.push(db_collaborator.id);
|
||||||
|
@ -390,6 +396,8 @@ impl Database {
|
||||||
replica_id: row.replica_id.0 as u32,
|
replica_id: row.replica_id.0 as u32,
|
||||||
user_id: row.user_id.to_proto(),
|
user_id: row.user_id.to_proto(),
|
||||||
is_host: false,
|
is_host: false,
|
||||||
|
committer_name: None,
|
||||||
|
committer_email: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -739,7 +739,6 @@ impl Database {
|
||||||
),
|
),
|
||||||
github_login: user.github_login,
|
github_login: user.github_login,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
email: user.email_address,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
proto::ChannelMember {
|
proto::ChannelMember {
|
||||||
|
|
|
@ -98,7 +98,9 @@ impl Database {
|
||||||
user_id: ActiveValue::set(participant.user_id),
|
user_id: ActiveValue::set(participant.user_id),
|
||||||
replica_id: ActiveValue::set(ReplicaId(replica_id)),
|
replica_id: ActiveValue::set(ReplicaId(replica_id)),
|
||||||
is_host: ActiveValue::set(true),
|
is_host: ActiveValue::set(true),
|
||||||
..Default::default()
|
id: ActiveValue::NotSet,
|
||||||
|
committer_name: ActiveValue::Set(None),
|
||||||
|
committer_email: ActiveValue::Set(None),
|
||||||
}
|
}
|
||||||
.insert(&*tx)
|
.insert(&*tx)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -784,13 +786,27 @@ impl Database {
|
||||||
project_id: ProjectId,
|
project_id: ProjectId,
|
||||||
connection: ConnectionId,
|
connection: ConnectionId,
|
||||||
user_id: UserId,
|
user_id: UserId,
|
||||||
|
committer_name: Option<String>,
|
||||||
|
committer_email: Option<String>,
|
||||||
) -> Result<TransactionGuard<(Project, ReplicaId)>> {
|
) -> Result<TransactionGuard<(Project, ReplicaId)>> {
|
||||||
self.project_transaction(project_id, |tx| async move {
|
self.project_transaction(project_id, move |tx| {
|
||||||
let (project, role) = self
|
let committer_name = committer_name.clone();
|
||||||
.access_project(project_id, connection, Capability::ReadOnly, &tx)
|
let committer_email = committer_email.clone();
|
||||||
.await?;
|
async move {
|
||||||
self.join_project_internal(project, user_id, connection, role, &tx)
|
let (project, role) = self
|
||||||
|
.access_project(project_id, connection, Capability::ReadOnly, &tx)
|
||||||
|
.await?;
|
||||||
|
self.join_project_internal(
|
||||||
|
project,
|
||||||
|
user_id,
|
||||||
|
committer_name,
|
||||||
|
committer_email,
|
||||||
|
connection,
|
||||||
|
role,
|
||||||
|
&tx,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -799,6 +815,8 @@ impl Database {
|
||||||
&self,
|
&self,
|
||||||
project: project::Model,
|
project: project::Model,
|
||||||
user_id: UserId,
|
user_id: UserId,
|
||||||
|
committer_name: Option<String>,
|
||||||
|
committer_email: Option<String>,
|
||||||
connection: ConnectionId,
|
connection: ConnectionId,
|
||||||
role: ChannelRole,
|
role: ChannelRole,
|
||||||
tx: &DatabaseTransaction,
|
tx: &DatabaseTransaction,
|
||||||
|
@ -822,7 +840,9 @@ impl Database {
|
||||||
user_id: ActiveValue::set(user_id),
|
user_id: ActiveValue::set(user_id),
|
||||||
replica_id: ActiveValue::set(replica_id),
|
replica_id: ActiveValue::set(replica_id),
|
||||||
is_host: ActiveValue::set(false),
|
is_host: ActiveValue::set(false),
|
||||||
..Default::default()
|
id: ActiveValue::NotSet,
|
||||||
|
committer_name: ActiveValue::set(committer_name),
|
||||||
|
committer_email: ActiveValue::set(committer_email),
|
||||||
}
|
}
|
||||||
.insert(tx)
|
.insert(tx)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -1026,6 +1046,8 @@ impl Database {
|
||||||
user_id: collaborator.user_id,
|
user_id: collaborator.user_id,
|
||||||
replica_id: collaborator.replica_id,
|
replica_id: collaborator.replica_id,
|
||||||
is_host: collaborator.is_host,
|
is_host: collaborator.is_host,
|
||||||
|
committer_name: collaborator.committer_name,
|
||||||
|
committer_email: collaborator.committer_email,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
worktrees,
|
worktrees,
|
||||||
|
|
|
@ -553,6 +553,8 @@ impl Database {
|
||||||
user_id: collaborator.user_id,
|
user_id: collaborator.user_id,
|
||||||
replica_id: collaborator.replica_id,
|
replica_id: collaborator.replica_id,
|
||||||
is_host: collaborator.is_host,
|
is_host: collaborator.is_host,
|
||||||
|
committer_name: collaborator.committer_name.clone(),
|
||||||
|
committer_email: collaborator.committer_email.clone(),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
worktrees: reshared_project.worktrees.clone(),
|
worktrees: reshared_project.worktrees.clone(),
|
||||||
|
@ -857,6 +859,8 @@ impl Database {
|
||||||
user_id: collaborator.user_id,
|
user_id: collaborator.user_id,
|
||||||
replica_id: collaborator.replica_id,
|
replica_id: collaborator.replica_id,
|
||||||
is_host: collaborator.is_host,
|
is_host: collaborator.is_host,
|
||||||
|
committer_name: collaborator.committer_name,
|
||||||
|
committer_email: collaborator.committer_email,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ pub struct Model {
|
||||||
pub user_id: UserId,
|
pub user_id: UserId,
|
||||||
pub replica_id: ReplicaId,
|
pub replica_id: ReplicaId,
|
||||||
pub is_host: bool,
|
pub is_host: bool,
|
||||||
|
pub committer_name: Option<String>,
|
||||||
|
pub committer_email: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
|
|
|
@ -126,12 +126,16 @@ async fn test_channel_buffers(db: &Arc<Database>) {
|
||||||
peer_id: Some(rpc::proto::PeerId { id: 1, owner_id }),
|
peer_id: Some(rpc::proto::PeerId { id: 1, owner_id }),
|
||||||
replica_id: 0,
|
replica_id: 0,
|
||||||
is_host: false,
|
is_host: false,
|
||||||
|
committer_name: None,
|
||||||
|
committer_email: None,
|
||||||
},
|
},
|
||||||
rpc::proto::Collaborator {
|
rpc::proto::Collaborator {
|
||||||
user_id: b_id.to_proto(),
|
user_id: b_id.to_proto(),
|
||||||
peer_id: Some(rpc::proto::PeerId { id: 2, owner_id }),
|
peer_id: Some(rpc::proto::PeerId { id: 2, owner_id }),
|
||||||
replica_id: 1,
|
replica_id: 1,
|
||||||
is_host: false,
|
is_host: false,
|
||||||
|
committer_name: None,
|
||||||
|
committer_email: None,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
db::{
|
db::{
|
||||||
self, BufferId, Capability, Channel, ChannelId, ChannelRole, ChannelsForUser,
|
self, BufferId, Capability, Channel, ChannelId, ChannelRole, ChannelsForUser,
|
||||||
CreatedChannelMessage, Database, InviteMemberResult, MembershipUpdated, MessageId,
|
CreatedChannelMessage, Database, InviteMemberResult, MembershipUpdated, MessageId,
|
||||||
NotificationId, Project, ProjectId, RejoinedProject, RemoveChannelMemberResult, ReplicaId,
|
NotificationId, ProjectId, RejoinedProject, RemoveChannelMemberResult,
|
||||||
RespondToChannelInvite, RoomId, ServerId, UpdatedChannelMessage, User, UserId,
|
RespondToChannelInvite, RoomId, ServerId, UpdatedChannelMessage, User, UserId,
|
||||||
},
|
},
|
||||||
executor::Executor,
|
executor::Executor,
|
||||||
|
@ -1890,28 +1890,16 @@ async fn join_project(
|
||||||
|
|
||||||
let db = session.db().await;
|
let db = session.db().await;
|
||||||
let (project, replica_id) = &mut *db
|
let (project, replica_id) = &mut *db
|
||||||
.join_project(project_id, session.connection_id, session.user_id())
|
.join_project(
|
||||||
|
project_id,
|
||||||
|
session.connection_id,
|
||||||
|
session.user_id(),
|
||||||
|
request.committer_name.clone(),
|
||||||
|
request.committer_email.clone(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
drop(db);
|
drop(db);
|
||||||
tracing::info!(%project_id, "join remote project");
|
tracing::info!(%project_id, "join remote project");
|
||||||
join_project_internal(response, session, project, replica_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
trait JoinProjectInternalResponse {
|
|
||||||
fn send(self, result: proto::JoinProjectResponse) -> Result<()>;
|
|
||||||
}
|
|
||||||
impl JoinProjectInternalResponse for Response<proto::JoinProject> {
|
|
||||||
fn send(self, result: proto::JoinProjectResponse) -> Result<()> {
|
|
||||||
Response::<proto::JoinProject>::send(self, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn join_project_internal(
|
|
||||||
response: impl JoinProjectInternalResponse,
|
|
||||||
session: Session,
|
|
||||||
project: &mut Project,
|
|
||||||
replica_id: &ReplicaId,
|
|
||||||
) -> Result<()> {
|
|
||||||
let collaborators = project
|
let collaborators = project
|
||||||
.collaborators
|
.collaborators
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1939,6 +1927,8 @@ fn join_project_internal(
|
||||||
replica_id: replica_id.0 as u32,
|
replica_id: replica_id.0 as u32,
|
||||||
user_id: guest_user_id.to_proto(),
|
user_id: guest_user_id.to_proto(),
|
||||||
is_host: false,
|
is_host: false,
|
||||||
|
committer_name: request.committer_name.clone(),
|
||||||
|
committer_email: request.committer_email.clone(),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2567,7 +2557,6 @@ async fn get_users(
|
||||||
id: user.id.to_proto(),
|
id: user.id.to_proto(),
|
||||||
avatar_url: format!("https://github.com/{}.png?size=128", user.github_login),
|
avatar_url: format!("https://github.com/{}.png?size=128", user.github_login),
|
||||||
github_login: user.github_login,
|
github_login: user.github_login,
|
||||||
email: user.email_address,
|
|
||||||
name: user.name,
|
name: user.name,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -2601,7 +2590,6 @@ async fn fuzzy_search_users(
|
||||||
avatar_url: format!("https://github.com/{}.png?size=128", user.github_login),
|
avatar_url: format!("https://github.com/{}.png?size=128", user.github_login),
|
||||||
github_login: user.github_login,
|
github_login: user.github_login,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
email: user.email_address,
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
response.send(proto::UsersResponse { users })?;
|
response.send(proto::UsersResponse { users })?;
|
||||||
|
|
|
@ -1610,6 +1610,8 @@ async fn test_following_across_workspaces(cx_a: &mut TestAppContext, cx_b: &mut
|
||||||
.root(cx_a)
|
.root(cx_a)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
executor.run_until_parked();
|
||||||
|
|
||||||
workspace_a_project_b.update(cx_a2, |workspace, cx| {
|
workspace_a_project_b.update(cx_a2, |workspace, cx| {
|
||||||
assert_eq!(workspace.project().read(cx).remote_id(), Some(project_b_id));
|
assert_eq!(workspace.project().read(cx).remote_id(), Some(project_b_id));
|
||||||
assert!(workspace.is_being_followed(client_b.peer_id().unwrap()));
|
assert!(workspace.is_being_followed(client_b.peer_id().unwrap()));
|
||||||
|
|
|
@ -1876,7 +1876,6 @@ async fn test_active_call_events(
|
||||||
github_login: "user_a".to_string(),
|
github_login: "user_a".to_string(),
|
||||||
avatar_uri: "avatar_a".into(),
|
avatar_uri: "avatar_a".into(),
|
||||||
name: None,
|
name: None,
|
||||||
email: None,
|
|
||||||
}),
|
}),
|
||||||
project_id: project_a_id,
|
project_id: project_a_id,
|
||||||
worktree_root_names: vec!["a".to_string()],
|
worktree_root_names: vec!["a".to_string()],
|
||||||
|
@ -1896,7 +1895,6 @@ async fn test_active_call_events(
|
||||||
github_login: "user_b".to_string(),
|
github_login: "user_b".to_string(),
|
||||||
avatar_uri: "avatar_b".into(),
|
avatar_uri: "avatar_b".into(),
|
||||||
name: None,
|
name: None,
|
||||||
email: None,
|
|
||||||
}),
|
}),
|
||||||
project_id: project_b_id,
|
project_id: project_b_id,
|
||||||
worktree_root_names: vec!["b".to_string()]
|
worktree_root_names: vec!["b".to_string()]
|
||||||
|
|
|
@ -1218,7 +1218,6 @@ mod tests {
|
||||||
avatar_uri: "avatar_fgh".into(),
|
avatar_uri: "avatar_fgh".into(),
|
||||||
id: 103,
|
id: 103,
|
||||||
name: None,
|
name: None,
|
||||||
email: None,
|
|
||||||
}),
|
}),
|
||||||
nonce: 5,
|
nonce: 5,
|
||||||
mentions: vec![(ranges[0].clone(), 101), (ranges[1].clone(), 102)],
|
mentions: vec![(ranges[0].clone(), 101), (ranges[1].clone(), 102)],
|
||||||
|
@ -1274,7 +1273,6 @@ mod tests {
|
||||||
avatar_uri: "avatar_fgh".into(),
|
avatar_uri: "avatar_fgh".into(),
|
||||||
id: 103,
|
id: 103,
|
||||||
name: None,
|
name: None,
|
||||||
email: None,
|
|
||||||
}),
|
}),
|
||||||
nonce: 5,
|
nonce: 5,
|
||||||
mentions: Vec::new(),
|
mentions: Vec::new(),
|
||||||
|
@ -1323,7 +1321,6 @@ mod tests {
|
||||||
avatar_uri: "avatar_fgh".into(),
|
avatar_uri: "avatar_fgh".into(),
|
||||||
id: 103,
|
id: 103,
|
||||||
name: None,
|
name: None,
|
||||||
email: None,
|
|
||||||
}),
|
}),
|
||||||
nonce: 5,
|
nonce: 5,
|
||||||
mentions: Vec::new(),
|
mentions: Vec::new(),
|
||||||
|
|
|
@ -26,8 +26,8 @@ use std::{
|
||||||
};
|
};
|
||||||
use sum_tree::MapSeekTarget;
|
use sum_tree::MapSeekTarget;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use util::ResultExt;
|
|
||||||
use util::command::{new_smol_command, new_std_command};
|
use util::command::{new_smol_command, new_std_command};
|
||||||
|
use util::{ResultExt, paths};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub use askpass::{AskPassDelegate, AskPassResult, AskPassSession};
|
pub use askpass::{AskPassDelegate, AskPassResult, AskPassSession};
|
||||||
|
@ -508,6 +508,50 @@ pub struct GitRepositoryCheckpoint {
|
||||||
pub commit_sha: Oid,
|
pub commit_sha: Oid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GitCommitter {
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub email: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_git_committer(cx: &AsyncApp) -> GitCommitter {
|
||||||
|
if cfg!(any(feature = "test-support", test)) {
|
||||||
|
return GitCommitter {
|
||||||
|
name: None,
|
||||||
|
email: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let git_binary_path =
|
||||||
|
if cfg!(target_os = "macos") && option_env!("ZED_BUNDLE").as_deref() == Some("true") {
|
||||||
|
cx.update(|cx| {
|
||||||
|
cx.path_for_auxiliary_executable("git")
|
||||||
|
.context("could not find git binary path")
|
||||||
|
.log_err()
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let git = GitBinary::new(
|
||||||
|
git_binary_path.unwrap_or(PathBuf::from("git")),
|
||||||
|
paths::home_dir().clone(),
|
||||||
|
cx.background_executor().clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.background_spawn(async move {
|
||||||
|
let name = git.run(["config", "--global", "user.name"]).await.log_err();
|
||||||
|
let email = git
|
||||||
|
.run(["config", "--global", "user.email"])
|
||||||
|
.await
|
||||||
|
.log_err();
|
||||||
|
GitCommitter { name, email }
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
impl GitRepository for RealGitRepository {
|
impl GitRepository for RealGitRepository {
|
||||||
fn reload_index(&self) {
|
fn reload_index(&self) {
|
||||||
if let Ok(mut index) = self.repository.lock().index() {
|
if let Ok(mut index) = self.repository.lock().index() {
|
||||||
|
|
|
@ -21,6 +21,7 @@ agent_settings.workspace = true
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
askpass.workspace = true
|
askpass.workspace = true
|
||||||
buffer_diff.workspace = true
|
buffer_diff.workspace = true
|
||||||
|
call.workspace = true
|
||||||
chrono.workspace = true
|
chrono.workspace = true
|
||||||
collections.workspace = true
|
collections.workspace = true
|
||||||
command_palette_hooks.workspace = true
|
command_palette_hooks.workspace = true
|
||||||
|
|
|
@ -148,6 +148,7 @@ impl CommitModal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
git_panel.set_modal_open(true, cx);
|
git_panel.set_modal_open(true, cx);
|
||||||
|
git_panel.load_local_committer(cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
let dock = workspace.dock_at_position(git_panel.position(window, cx));
|
let dock = workspace.dock_at_position(git_panel.position(window, cx));
|
||||||
|
|
|
@ -20,8 +20,9 @@ use editor::{
|
||||||
use futures::StreamExt as _;
|
use futures::StreamExt as _;
|
||||||
use git::blame::ParsedCommitMessage;
|
use git::blame::ParsedCommitMessage;
|
||||||
use git::repository::{
|
use git::repository::{
|
||||||
Branch, CommitDetails, CommitOptions, CommitSummary, DiffType, FetchOptions, PushOptions,
|
Branch, CommitDetails, CommitOptions, CommitSummary, DiffType, FetchOptions, GitCommitter,
|
||||||
Remote, RemoteCommandOutput, ResetMode, Upstream, UpstreamTracking, UpstreamTrackingStatus,
|
PushOptions, Remote, RemoteCommandOutput, ResetMode, Upstream, UpstreamTracking,
|
||||||
|
UpstreamTrackingStatus, get_git_committer,
|
||||||
};
|
};
|
||||||
use git::status::StageStatus;
|
use git::status::StageStatus;
|
||||||
use git::{Amend, ToggleStaged, repository::RepoPath, status::FileStatus};
|
use git::{Amend, ToggleStaged, repository::RepoPath, status::FileStatus};
|
||||||
|
@ -358,6 +359,8 @@ pub struct GitPanel {
|
||||||
context_menu: Option<(Entity<ContextMenu>, Point<Pixels>, Subscription)>,
|
context_menu: Option<(Entity<ContextMenu>, Point<Pixels>, Subscription)>,
|
||||||
modal_open: bool,
|
modal_open: bool,
|
||||||
show_placeholders: bool,
|
show_placeholders: bool,
|
||||||
|
local_committer: Option<GitCommitter>,
|
||||||
|
local_committer_task: Option<Task<()>>,
|
||||||
_settings_subscription: Subscription,
|
_settings_subscription: Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +523,8 @@ impl GitPanel {
|
||||||
update_visible_entries_task: Task::ready(()),
|
update_visible_entries_task: Task::ready(()),
|
||||||
width: None,
|
width: None,
|
||||||
show_placeholders: false,
|
show_placeholders: false,
|
||||||
|
local_committer: None,
|
||||||
|
local_committer_task: None,
|
||||||
context_menu: None,
|
context_menu: None,
|
||||||
workspace: workspace.weak_handle(),
|
workspace: workspace.weak_handle(),
|
||||||
modal_open: false,
|
modal_open: false,
|
||||||
|
@ -2250,6 +2255,19 @@ impl GitPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_local_committer(&mut self, cx: &Context<Self>) {
|
||||||
|
if self.local_committer_task.is_none() {
|
||||||
|
self.local_committer_task = Some(cx.spawn(async move |this, cx| {
|
||||||
|
let committer = get_git_committer(cx).await;
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.local_committer = Some(committer);
|
||||||
|
cx.notify()
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn potential_co_authors(&self, cx: &App) -> Vec<(String, String)> {
|
fn potential_co_authors(&self, cx: &App) -> Vec<(String, String)> {
|
||||||
let mut new_co_authors = Vec::new();
|
let mut new_co_authors = Vec::new();
|
||||||
let project = self.project.read(cx);
|
let project = self.project.read(cx);
|
||||||
|
@ -2272,34 +2290,38 @@ impl GitPanel {
|
||||||
let Some(participant) = room.remote_participant_for_peer_id(*peer_id) else {
|
let Some(participant) = room.remote_participant_for_peer_id(*peer_id) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if participant.can_write() && participant.user.email.is_some() {
|
if !participant.can_write() {
|
||||||
let email = participant.user.email.clone().unwrap();
|
continue;
|
||||||
|
}
|
||||||
new_co_authors.push((
|
if let Some(email) = &collaborator.committer_email {
|
||||||
participant
|
let name = collaborator
|
||||||
.user
|
.committer_name
|
||||||
.name
|
.clone()
|
||||||
.clone()
|
.or_else(|| participant.user.name.clone())
|
||||||
.unwrap_or_else(|| participant.user.github_login.clone()),
|
.unwrap_or_else(|| participant.user.github_login.clone());
|
||||||
email,
|
new_co_authors.push((name.clone(), email.clone()))
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !project.is_local() && !project.is_read_only(cx) {
|
if !project.is_local() && !project.is_read_only(cx) {
|
||||||
if let Some(user) = room.local_participant_user(cx) {
|
if let Some(local_committer) = self.local_committer(room, cx) {
|
||||||
if let Some(email) = user.email.clone() {
|
new_co_authors.push(local_committer);
|
||||||
new_co_authors.push((
|
|
||||||
user.name
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| user.github_login.clone()),
|
|
||||||
email.clone(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new_co_authors
|
new_co_authors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn local_committer(&self, room: &call::Room, cx: &App) -> Option<(String, String)> {
|
||||||
|
let user = room.local_participant_user(cx)?;
|
||||||
|
let committer = self.local_committer.as_ref()?;
|
||||||
|
let email = committer.email.clone()?;
|
||||||
|
let name = committer
|
||||||
|
.name
|
||||||
|
.clone()
|
||||||
|
.or_else(|| user.name.clone())
|
||||||
|
.unwrap_or_else(|| user.github_login.clone());
|
||||||
|
Some((name, email))
|
||||||
|
}
|
||||||
|
|
||||||
fn toggle_fill_co_authors(
|
fn toggle_fill_co_authors(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &ToggleFillCoAuthors,
|
_: &ToggleFillCoAuthors,
|
||||||
|
@ -4244,8 +4266,9 @@ impl Render for GitPanel {
|
||||||
let has_write_access = self.has_write_access(cx);
|
let has_write_access = self.has_write_access(cx);
|
||||||
|
|
||||||
let has_co_authors = room.map_or(false, |room| {
|
let has_co_authors = room.map_or(false, |room| {
|
||||||
room.read(cx)
|
self.load_local_committer(cx);
|
||||||
.remote_participants()
|
let room = room.read(cx);
|
||||||
|
room.remote_participants()
|
||||||
.values()
|
.values()
|
||||||
.any(|remote_participant| remote_participant.can_write())
|
.any(|remote_participant| remote_participant.can_write())
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,6 +26,7 @@ mod environment;
|
||||||
use buffer_diff::BufferDiff;
|
use buffer_diff::BufferDiff;
|
||||||
use context_server_store::ContextServerStore;
|
use context_server_store::ContextServerStore;
|
||||||
pub use environment::{EnvironmentErrorMessage, ProjectEnvironmentEvent};
|
pub use environment::{EnvironmentErrorMessage, ProjectEnvironmentEvent};
|
||||||
|
use git::repository::get_git_committer;
|
||||||
use git_store::{Repository, RepositoryId};
|
use git_store::{Repository, RepositoryId};
|
||||||
pub mod search_history;
|
pub mod search_history;
|
||||||
mod yarn;
|
mod yarn;
|
||||||
|
@ -1323,9 +1324,12 @@ impl Project {
|
||||||
),
|
),
|
||||||
EntitySubscription::DapStore(client.subscribe_to_entity::<DapStore>(remote_id)?),
|
EntitySubscription::DapStore(client.subscribe_to_entity::<DapStore>(remote_id)?),
|
||||||
];
|
];
|
||||||
|
let committer = get_git_committer(&cx).await;
|
||||||
let response = client
|
let response = client
|
||||||
.request_envelope(proto::JoinProject {
|
.request_envelope(proto::JoinProject {
|
||||||
project_id: remote_id,
|
project_id: remote_id,
|
||||||
|
committer_email: committer.email,
|
||||||
|
committer_name: committer.name,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
Self::from_join_project_response(
|
Self::from_join_project_response(
|
||||||
|
|
|
@ -189,6 +189,8 @@ message UpdateProject {
|
||||||
|
|
||||||
message JoinProject {
|
message JoinProject {
|
||||||
uint64 project_id = 1;
|
uint64 project_id = 1;
|
||||||
|
optional string committer_email = 2;
|
||||||
|
optional string committer_name = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message JoinProjectResponse {
|
message JoinProjectResponse {
|
||||||
|
|
|
@ -7,10 +7,10 @@ message PeerId {
|
||||||
}
|
}
|
||||||
|
|
||||||
message User {
|
message User {
|
||||||
|
reserved 4;
|
||||||
uint64 id = 1;
|
uint64 id = 1;
|
||||||
string github_login = 2;
|
string github_login = 2;
|
||||||
string avatar_url = 3;
|
string avatar_url = 3;
|
||||||
optional string email = 4;
|
|
||||||
optional string name = 5;
|
optional string name = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,4 +24,6 @@ message Collaborator {
|
||||||
uint32 replica_id = 2;
|
uint32 replica_id = 2;
|
||||||
uint64 user_id = 3;
|
uint64 user_id = 3;
|
||||||
bool is_host = 4;
|
bool is_host = 4;
|
||||||
|
optional string committer_name = 5;
|
||||||
|
optional string committer_email = 6;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue