verify user is on gitbutler/integration

This commit is contained in:
Nikita Galaiko 2023-08-08 16:25:59 +02:00 committed by GitButler
parent c15c0d8982
commit 5876bc8ed3
4 changed files with 96 additions and 47 deletions

View File

@ -12,6 +12,7 @@ pub enum Code {
Conflicting, Conflicting,
ProjectCreateFailed, ProjectCreateFailed,
GitAutenticationFailed, GitAutenticationFailed,
InvalidHead,
} }
impl fmt::Display for Code { impl fmt::Display for Code {
@ -22,6 +23,7 @@ impl fmt::Display for Code {
Code::FetchFailed => write!(f, "errors.fetch"), Code::FetchFailed => write!(f, "errors.fetch"),
Code::Conflicting => write!(f, "errors.conflict"), Code::Conflicting => write!(f, "errors.conflict"),
Code::GitAutenticationFailed => write!(f, "errors.git.authentication"), Code::GitAutenticationFailed => write!(f, "errors.git.authentication"),
Code::InvalidHead => write!(f, "errors.git.head"),
Code::ProjectCreateFailed => write!(f, "errors.projects.create"), Code::ProjectCreateFailed => write!(f, "errors.projects.create"),
} }
} }
@ -74,8 +76,15 @@ impl From<virtual_branches::controller::Error> for Error {
message: "Project is in conflicting state. Resolve all conflicts and try again." message: "Project is in conflicting state. Resolve all conflicts and try again."
.to_string(), .to_string(),
}, },
virtual_branches::controller::Error::LockError(_) => Error::Unknown, virtual_branches::controller::Error::DetachedHead => Error::UserError {
virtual_branches::controller::Error::Other(e) => Error::from(e), code: Code::InvalidHead,
message: format!("Project in detached head state. Please checkout {0} to continue.", virtual_branches::GITBUTLER_INTEGRATION_REFERENCE),
},
virtual_branches::controller::Error::InvalidHead(head_name) => Error::UserError {
code: Code::InvalidHead,
message: format!("Project is on {0}. Please checkout {1} to continue.", head_name, virtual_branches::GITBUTLER_INTEGRATION_REFERENCE),
},
e => Error::from(e),
} }
} }
} }

View File

@ -1,4 +1,3 @@
use anyhow::Context;
use futures::future::join_all; use futures::future::join_all;
use tauri::{AppHandle, Manager}; use tauri::{AppHandle, Manager};
use timed::timed; use timed::timed;
@ -19,8 +18,7 @@ pub async fn commit_virtual_branch(
.state::<Controller>() .state::<Controller>()
.create_commit(project_id, branch, message) .create_commit(project_id, branch, message)
.await .await
.context("failed to create commit")?; .map_err(Into::into)
Ok(())
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
@ -29,12 +27,11 @@ pub async fn list_virtual_branches(
handle: tauri::AppHandle, handle: tauri::AppHandle,
project_id: &str, project_id: &str,
) -> Result<Vec<super::VirtualBranch>, Error> { ) -> Result<Vec<super::VirtualBranch>, Error> {
let branches = handle handle
.state::<Controller>() .state::<Controller>()
.list_virtual_branches(project_id) .list_virtual_branches(project_id)
.await .await
.context("failed to list virtual branches")?; .map_err(Into::into)
Ok(branches)
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
@ -48,8 +45,7 @@ pub async fn create_virtual_branch(
.state::<Controller>() .state::<Controller>()
.create_virtual_branch(project_id, &branch) .create_virtual_branch(project_id, &branch)
.await .await
.context("failed to create virtual branch")?; .map_err(Into::into)
Ok(())
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
@ -59,12 +55,11 @@ pub async fn create_virtual_branch_from_branch(
project_id: &str, project_id: &str,
branch: branch::Name, branch: branch::Name,
) -> Result<String, Error> { ) -> Result<String, Error> {
let branch_id = handle handle
.state::<Controller>() .state::<Controller>()
.create_virtual_branch_from_branch(project_id, &branch) .create_virtual_branch_from_branch(project_id, &branch)
.await .await
.context("failed to create virtual branch from branch")?; .map_err(Into::into)
Ok(branch_id)
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
@ -74,10 +69,7 @@ pub async fn get_base_branch_data(
project_id: &str, project_id: &str,
) -> Result<Option<super::BaseBranch>, Error> { ) -> Result<Option<super::BaseBranch>, Error> {
let controller = handle.state::<Controller>(); let controller = handle.state::<Controller>();
let target = match controller let target = match controller.get_base_branch_data(project_id)? {
.get_base_branch_data(project_id)
.context("failed to get base branch data")?
{
None => return Ok(None), None => return Ok(None),
Some(target) => target, Some(target) => target,
}; };
@ -148,23 +140,21 @@ pub async fn set_base_branch(
project_id: &str, project_id: &str,
branch: &str, branch: &str,
) -> Result<super::BaseBranch, Error> { ) -> Result<super::BaseBranch, Error> {
let controller = handle.state::<Controller>(); handle
let target = controller .state::<Controller>()
.set_base_branch(project_id, branch) .set_base_branch(project_id, branch)
.await .await
.context("failed to get target data")?; .map_err(Into::into)
Ok(target)
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
#[tauri::command(async)] #[tauri::command(async)]
pub async fn update_base_branch(handle: tauri::AppHandle, project_id: &str) -> Result<(), Error> { pub async fn update_base_branch(handle: tauri::AppHandle, project_id: &str) -> Result<(), Error> {
let controller = handle.state::<Controller>(); handle
controller .state::<Controller>()
.update_base_branch(project_id) .update_base_branch(project_id)
.await .await
.context("failed to update base branch")?; .map_err(Into::into)
Ok(())
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
@ -174,12 +164,11 @@ pub async fn update_virtual_branch(
project_id: &str, project_id: &str,
branch: super::branch::BranchUpdateRequest, branch: super::branch::BranchUpdateRequest,
) -> Result<(), Error> { ) -> Result<(), Error> {
let controller = handle.state::<Controller>(); handle
controller .state::<Controller>()
.update_virtual_branch(project_id, branch) .update_virtual_branch(project_id, branch)
.await .await
.context("failed to update virtual branch")?; .map_err(Into::into)
Ok(())
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
@ -189,12 +178,11 @@ pub async fn delete_virtual_branch(
project_id: &str, project_id: &str,
branch_id: &str, branch_id: &str,
) -> Result<(), Error> { ) -> Result<(), Error> {
let controller = handle.state::<Controller>(); handle
controller .state::<Controller>()
.delete_virtual_branch(project_id, branch_id) .delete_virtual_branch(project_id, branch_id)
.await .await
.context("failed to update virtual branch")?; .map_err(Into::into)
Ok(())
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
@ -204,12 +192,11 @@ pub async fn apply_branch(
project_id: &str, project_id: &str,
branch: &str, branch: &str,
) -> Result<(), Error> { ) -> Result<(), Error> {
let controller = handle.state::<Controller>(); handle
controller .state::<Controller>()
.apply_virtual_branch(project_id, branch) .apply_virtual_branch(project_id, branch)
.await .await
.context("failed to apply branch")?; .map_err(Into::into)
Ok(())
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
@ -219,12 +206,11 @@ pub async fn unapply_branch(
project_id: &str, project_id: &str,
branch: &str, branch: &str,
) -> Result<(), Error> { ) -> Result<(), Error> {
let controller = handle.state::<Controller>(); handle
controller .state::<Controller>()
.unapply_virtual_branch(project_id, branch) .unapply_virtual_branch(project_id, branch)
.await .await
.context("failed to unapply branch")?; .map_err(Into::into)
Ok(())
} }
#[timed(duration(printer = "debug!"))] #[timed(duration(printer = "debug!"))]
@ -237,6 +223,6 @@ pub async fn push_virtual_branch(
handle handle
.state::<Controller>() .state::<Controller>()
.push_virtual_branch(project_id, branch_id) .push_virtual_branch(project_id, branch_id)
.await?; .await
Ok(()) .map_err(Into::into)
} }

View File

@ -21,6 +21,10 @@ pub struct Controller {
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
#[error("detached head detected, go back to gitbutler/integration to continue")]
DetachedHead,
#[error("unexpected head {0}, go back to gitbutler/integration to continue")]
InvalidHead(String),
#[error("failed to open project repository")] #[error("failed to open project repository")]
PushError(#[from] project_repository::Error), PushError(#[from] project_repository::Error),
#[error("project is in a conflicted state")] #[error("project is in a conflicted state")]
@ -67,6 +71,7 @@ impl Controller {
.as_ref() .as_ref()
.try_into() .try_into()
.context("failed to open project repository")?; .context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
super::commit(&gb_repository, &project_repository, branch, message) super::commit(&gb_repository, &project_repository, branch, message)
@ -92,6 +97,7 @@ impl Controller {
.as_ref() .as_ref()
.try_into() .try_into()
.context("failed to open project repository")?; .context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
super::list_virtual_branches(&gb_repository, &project_repository) super::list_virtual_branches(&gb_repository, &project_repository)
@ -117,6 +123,7 @@ impl Controller {
.as_ref() .as_ref()
.try_into() .try_into()
.context("failed to open project repository")?; .context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
if conflicts::is_resolving(&project_repository) { if conflicts::is_resolving(&project_repository) {
@ -148,6 +155,7 @@ impl Controller {
.as_ref() .as_ref()
.try_into() .try_into()
.context("failed to open project repository")?; .context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
let branch_id = super::create_virtual_branch_from_branch( let branch_id = super::create_virtual_branch_from_branch(
@ -179,6 +187,7 @@ impl Controller {
.as_ref() .as_ref()
.try_into() .try_into()
.context("failed to open project repository")?; .context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
let base_branch = super::get_base_branch_data(&gb_repository, &project_repository)?; let base_branch = super::get_base_branch_data(&gb_repository, &project_repository)?;
Ok(base_branch) Ok(base_branch)
@ -222,6 +231,7 @@ impl Controller {
.as_ref() .as_ref()
.try_into() .try_into()
.context("failed to open project repository")?; .context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
super::update_base_branch(&gb_repository, &project_repository) super::update_base_branch(&gb_repository, &project_repository)
@ -236,8 +246,20 @@ impl Controller {
project_id: &str, project_id: &str,
branch_update: super::branch::BranchUpdateRequest, branch_update: super::branch::BranchUpdateRequest,
) -> Result<(), Error> { ) -> Result<(), Error> {
let project = self
.projects_storage
.get_project(project_id)
.context("failed to get project")?
.context("project not found")?;
self.with_lock(project_id, || { self.with_lock(project_id, || {
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
let project_repository = project
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
super::update_branch(&gb_repository, branch_update) super::update_branch(&gb_repository, branch_update)
}) })
.await?; .await?;
@ -250,8 +272,19 @@ impl Controller {
project_id: &str, project_id: &str,
branch_id: &str, branch_id: &str,
) -> Result<(), Error> { ) -> Result<(), Error> {
let project = self
.projects_storage
.get_project(project_id)
.context("failed to get project")?
.context("project not found")?;
self.with_lock(project_id, || { self.with_lock(project_id, || {
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
let project_repository = project
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
super::delete_branch(&gb_repository, branch_id) super::delete_branch(&gb_repository, branch_id)
}) })
.await?; .await?;
@ -275,6 +308,7 @@ impl Controller {
.as_ref() .as_ref()
.try_into() .try_into()
.context("failed to open project repository")?; .context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
super::apply_branch(&gb_repository, &project_repository, branch_id) super::apply_branch(&gb_repository, &project_repository, branch_id)
}) })
@ -299,6 +333,7 @@ impl Controller {
.as_ref() .as_ref()
.try_into() .try_into()
.context("failed to open project repository")?; .context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
super::unapply_branch(&gb_repository, &project_repository, branch_id) super::unapply_branch(&gb_repository, &project_repository, branch_id)
}) })
@ -328,6 +363,7 @@ impl Controller {
.as_ref() .as_ref()
.try_into() .try_into()
.context("failed to open project repository")?; .context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?; let gb_repository = self.open_gb_repository(project_id)?;
super::push(&project_repository, &gb_repository, branch_id, &private_key).map_err(|e| { super::push(&project_repository, &gb_repository, branch_id, &private_key).map_err(|e| {
@ -361,4 +397,15 @@ impl Controller {
.context("failed to open repository") .context("failed to open repository")
.map_err(Error::Other) .map_err(Error::Other)
} }
fn verify_branch(
&self,
project_repository: &project_repository::Repository,
) -> Result<(), Error> {
match project_repository.get_head().map_err(Error::Other)?.name() {
None => Err(Error::DetachedHead),
Some(super::vbranch::GITBUTLER_INTEGRATION_REFERENCE) => Ok(()),
Some(head_name) => Err(Error::InvalidHead(head_name.to_string())),
}
}
} }

View File

@ -1670,6 +1670,8 @@ fn get_virtual_branches(
Ok(applied_virtual_branches) Ok(applied_virtual_branches)
} }
pub const GITBUTLER_INTEGRATION_REFERENCE: &str = "refs/heads/gitbutler/integration";
pub fn update_gitbutler_integration( pub fn update_gitbutler_integration(
gb_repository: &gb_repository::Repository, gb_repository: &gb_repository::Repository,
project_repository: &project_repository::Repository, project_repository: &project_repository::Repository,
@ -1682,8 +1684,12 @@ pub fn update_gitbutler_integration(
let repo = &project_repository.git_repository; let repo = &project_repository.git_repository;
// write the currrent target sha to a temp branch as a parent // write the currrent target sha to a temp branch as a parent
let my_ref = "refs/heads/gitbutler/integration"; repo.reference(
repo.reference(my_ref, target.sha, true, "update target")?; GITBUTLER_INTEGRATION_REFERENCE,
target.sha,
true,
"update target",
)?;
// get commit object from target.sha // get commit object from target.sha
let target_commit = repo.find_commit(target.sha)?; let target_commit = repo.find_commit(target.sha)?;
@ -1693,7 +1699,7 @@ pub fn update_gitbutler_integration(
let mut prev_head = head.name().unwrap().to_string(); let mut prev_head = head.name().unwrap().to_string();
let mut prev_sha = head.target().unwrap().to_string(); let mut prev_sha = head.target().unwrap().to_string();
let integration_file = repo.path().join("integration"); let integration_file = repo.path().join("integration");
if prev_head != my_ref { if prev_head != GITBUTLER_INTEGRATION_REFERENCE {
// we are moving from a regular branch to our gitbutler integration branch, save the original // we are moving from a regular branch to our gitbutler integration branch, save the original
// write a file to .git/integration with the previous head and name // write a file to .git/integration with the previous head and name
let mut file = std::fs::File::create(integration_file)?; let mut file = std::fs::File::create(integration_file)?;
@ -1713,7 +1719,8 @@ pub fn update_gitbutler_integration(
} }
// commit index to temp head for the merge // commit index to temp head for the merge
repo.set_head(my_ref).context("failed to set head")?; repo.set_head(GITBUTLER_INTEGRATION_REFERENCE)
.context("failed to set head")?;
// get all virtual branches, we need to try to update them all // get all virtual branches, we need to try to update them all
let applied_virtual_branches = get_virtual_branches(gb_repository, Some(true))?; let applied_virtual_branches = get_virtual_branches(gb_repository, Some(true))?;