mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-28 20:15:20 +03:00
consider force push preference when updating commit message
This commit is contained in:
parent
dae28410c0
commit
0bb1b786ff
@ -246,6 +246,8 @@ pub enum SquashError {
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum UpdateCommitMessageError {
|
||||
#[error("force push not allowed")]
|
||||
ForcePushNotAllowed(ForcePushNotAllowedError),
|
||||
#[error("empty message")]
|
||||
EmptyMessage,
|
||||
#[error("default target not set")]
|
||||
@ -263,6 +265,7 @@ pub enum UpdateCommitMessageError {
|
||||
impl From<UpdateCommitMessageError> for Error {
|
||||
fn from(value: UpdateCommitMessageError) -> Self {
|
||||
match value {
|
||||
UpdateCommitMessageError::ForcePushNotAllowed(error) => error.into(),
|
||||
UpdateCommitMessageError::EmptyMessage => Error::UserError {
|
||||
message: "Commit message can not be empty".to_string(),
|
||||
code: crate::error::Code::Branches,
|
||||
|
@ -2837,18 +2837,17 @@ pub fn squash(
|
||||
.parent(0)
|
||||
.context("failed to find parent commit")?;
|
||||
|
||||
if branch
|
||||
.upstream_head
|
||||
.map_or_else(
|
||||
|| Ok(vec![]),
|
||||
|upstream_head| {
|
||||
project_repository.l(
|
||||
upstream_head,
|
||||
project_repository::LogUntil::Commit(default_target.sha),
|
||||
)
|
||||
},
|
||||
)?
|
||||
.contains(&parent_commit.id())
|
||||
let pushed_commit_oids = branch.upstream_head.map_or_else(
|
||||
|| Ok(vec![]),
|
||||
|upstream_head| {
|
||||
project_repository.l(
|
||||
upstream_head,
|
||||
project_repository::LogUntil::Commit(default_target.sha),
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
if pushed_commit_oids.contains(&parent_commit.id())
|
||||
&& !project_repository.project().ok_with_force_push
|
||||
{
|
||||
// squashing into a pushed commit will cause a force push that is not allowed
|
||||
@ -3025,6 +3024,26 @@ pub fn update_commit_message(
|
||||
return Err(errors::UpdateCommitMessageError::CommitNotFound(commit_oid));
|
||||
}
|
||||
|
||||
let pushed_commit_oids = branch.upstream_head.map_or_else(
|
||||
|| Ok(vec![]),
|
||||
|upstream_head| {
|
||||
project_repository.l(
|
||||
upstream_head,
|
||||
project_repository::LogUntil::Commit(default_target.sha),
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
if pushed_commit_oids.contains(&commit_oid) && !project_repository.project().ok_with_force_push
|
||||
{
|
||||
// updating the message of a pushed commit will cause a force push that is not allowed
|
||||
return Err(errors::UpdateCommitMessageError::ForcePushNotAllowed(
|
||||
errors::ForcePushNotAllowedError {
|
||||
project_id: project_repository.project().id,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let target_commit = project_repository
|
||||
.git_repository
|
||||
.find_commit(commit_oid)
|
||||
|
@ -4383,6 +4383,121 @@ mod update_commit_message {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn forcepush_allowed() {
|
||||
let Test {
|
||||
repository,
|
||||
project_id,
|
||||
controller,
|
||||
projects,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
projects
|
||||
.update(&projects::UpdateRequest {
|
||||
id: project_id,
|
||||
ok_with_force_push: Some(true),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
.create_virtual_branch(&project_id, &branch::BranchCreateRequest::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let commit_one_oid = {
|
||||
fs::write(repository.path().join("file one.txt"), "").unwrap();
|
||||
controller
|
||||
.create_commit(&project_id, &branch_id, "commit one", None)
|
||||
.await
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
controller
|
||||
.push_virtual_branch(&project_id, &branch_id, false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
controller
|
||||
.update_commit_message(
|
||||
&project_id,
|
||||
&branch_id,
|
||||
commit_one_oid,
|
||||
"commit one updated",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch = controller
|
||||
.list_virtual_branches(&project_id)
|
||||
.await
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.find(|b| b.id == branch_id)
|
||||
.unwrap();
|
||||
|
||||
let descriptions = branch
|
||||
.commits
|
||||
.iter()
|
||||
.map(|c| c.description.clone())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(descriptions, vec!["commit one updated"]);
|
||||
assert!(branch.requires_force);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn forcepush_forbidden() {
|
||||
let Test {
|
||||
repository,
|
||||
project_id,
|
||||
controller,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
.create_virtual_branch(&project_id, &branch::BranchCreateRequest::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let commit_one_oid = {
|
||||
fs::write(repository.path().join("file one.txt"), "").unwrap();
|
||||
controller
|
||||
.create_commit(&project_id, &branch_id, "commit one", None)
|
||||
.await
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
controller
|
||||
.push_virtual_branch(&project_id, &branch_id, false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(
|
||||
controller
|
||||
.update_commit_message(
|
||||
&project_id,
|
||||
&branch_id,
|
||||
commit_one_oid,
|
||||
"commit one updated",
|
||||
)
|
||||
.await
|
||||
.unwrap_err(),
|
||||
ControllerError::Action(errors::UpdateCommitMessageError::ForcePushNotAllowed(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn root() {
|
||||
let Test {
|
||||
|
Loading…
Reference in New Issue
Block a user