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,
ProjectCreateFailed,
GitAutenticationFailed,
InvalidHead,
}
impl fmt::Display for Code {
@ -22,6 +23,7 @@ impl fmt::Display for Code {
Code::FetchFailed => write!(f, "errors.fetch"),
Code::Conflicting => write!(f, "errors.conflict"),
Code::GitAutenticationFailed => write!(f, "errors.git.authentication"),
Code::InvalidHead => write!(f, "errors.git.head"),
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."
.to_string(),
},
virtual_branches::controller::Error::LockError(_) => Error::Unknown,
virtual_branches::controller::Error::Other(e) => Error::from(e),
virtual_branches::controller::Error::DetachedHead => Error::UserError {
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 tauri::{AppHandle, Manager};
use timed::timed;
@ -19,8 +18,7 @@ pub async fn commit_virtual_branch(
.state::<Controller>()
.create_commit(project_id, branch, message)
.await
.context("failed to create commit")?;
Ok(())
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
@ -29,12 +27,11 @@ pub async fn list_virtual_branches(
handle: tauri::AppHandle,
project_id: &str,
) -> Result<Vec<super::VirtualBranch>, Error> {
let branches = handle
handle
.state::<Controller>()
.list_virtual_branches(project_id)
.await
.context("failed to list virtual branches")?;
Ok(branches)
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
@ -48,8 +45,7 @@ pub async fn create_virtual_branch(
.state::<Controller>()
.create_virtual_branch(project_id, &branch)
.await
.context("failed to create virtual branch")?;
Ok(())
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
@ -59,12 +55,11 @@ pub async fn create_virtual_branch_from_branch(
project_id: &str,
branch: branch::Name,
) -> Result<String, Error> {
let branch_id = handle
handle
.state::<Controller>()
.create_virtual_branch_from_branch(project_id, &branch)
.await
.context("failed to create virtual branch from branch")?;
Ok(branch_id)
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
@ -74,10 +69,7 @@ pub async fn get_base_branch_data(
project_id: &str,
) -> Result<Option<super::BaseBranch>, Error> {
let controller = handle.state::<Controller>();
let target = match controller
.get_base_branch_data(project_id)
.context("failed to get base branch data")?
{
let target = match controller.get_base_branch_data(project_id)? {
None => return Ok(None),
Some(target) => target,
};
@ -148,23 +140,21 @@ pub async fn set_base_branch(
project_id: &str,
branch: &str,
) -> Result<super::BaseBranch, Error> {
let controller = handle.state::<Controller>();
let target = controller
handle
.state::<Controller>()
.set_base_branch(project_id, branch)
.await
.context("failed to get target data")?;
Ok(target)
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
#[tauri::command(async)]
pub async fn update_base_branch(handle: tauri::AppHandle, project_id: &str) -> Result<(), Error> {
let controller = handle.state::<Controller>();
controller
handle
.state::<Controller>()
.update_base_branch(project_id)
.await
.context("failed to update base branch")?;
Ok(())
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
@ -174,12 +164,11 @@ pub async fn update_virtual_branch(
project_id: &str,
branch: super::branch::BranchUpdateRequest,
) -> Result<(), Error> {
let controller = handle.state::<Controller>();
controller
handle
.state::<Controller>()
.update_virtual_branch(project_id, branch)
.await
.context("failed to update virtual branch")?;
Ok(())
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
@ -189,12 +178,11 @@ pub async fn delete_virtual_branch(
project_id: &str,
branch_id: &str,
) -> Result<(), Error> {
let controller = handle.state::<Controller>();
controller
handle
.state::<Controller>()
.delete_virtual_branch(project_id, branch_id)
.await
.context("failed to update virtual branch")?;
Ok(())
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
@ -204,12 +192,11 @@ pub async fn apply_branch(
project_id: &str,
branch: &str,
) -> Result<(), Error> {
let controller = handle.state::<Controller>();
controller
handle
.state::<Controller>()
.apply_virtual_branch(project_id, branch)
.await
.context("failed to apply branch")?;
Ok(())
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
@ -219,12 +206,11 @@ pub async fn unapply_branch(
project_id: &str,
branch: &str,
) -> Result<(), Error> {
let controller = handle.state::<Controller>();
controller
handle
.state::<Controller>()
.unapply_virtual_branch(project_id, branch)
.await
.context("failed to unapply branch")?;
Ok(())
.map_err(Into::into)
}
#[timed(duration(printer = "debug!"))]
@ -237,6 +223,6 @@ pub async fn push_virtual_branch(
handle
.state::<Controller>()
.push_virtual_branch(project_id, branch_id)
.await?;
Ok(())
.await
.map_err(Into::into)
}

View File

@ -21,6 +21,10 @@ pub struct Controller {
#[derive(Debug, thiserror::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")]
PushError(#[from] project_repository::Error),
#[error("project is in a conflicted state")]
@ -67,6 +71,7 @@ impl Controller {
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?;
super::commit(&gb_repository, &project_repository, branch, message)
@ -92,6 +97,7 @@ impl Controller {
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?;
super::list_virtual_branches(&gb_repository, &project_repository)
@ -117,6 +123,7 @@ impl Controller {
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?;
if conflicts::is_resolving(&project_repository) {
@ -148,6 +155,7 @@ impl Controller {
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?;
let branch_id = super::create_virtual_branch_from_branch(
@ -179,6 +187,7 @@ impl Controller {
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?;
let base_branch = super::get_base_branch_data(&gb_repository, &project_repository)?;
Ok(base_branch)
@ -222,6 +231,7 @@ impl Controller {
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?;
super::update_base_branch(&gb_repository, &project_repository)
@ -236,8 +246,20 @@ impl Controller {
project_id: &str,
branch_update: super::branch::BranchUpdateRequest,
) -> 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, || {
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)
})
.await?;
@ -250,8 +272,19 @@ impl Controller {
project_id: &str,
branch_id: &str,
) -> 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, || {
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)
})
.await?;
@ -275,6 +308,7 @@ impl Controller {
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?;
super::apply_branch(&gb_repository, &project_repository, branch_id)
})
@ -299,6 +333,7 @@ impl Controller {
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?;
super::unapply_branch(&gb_repository, &project_repository, branch_id)
})
@ -328,6 +363,7 @@ impl Controller {
.as_ref()
.try_into()
.context("failed to open project repository")?;
self.verify_branch(&project_repository)?;
let gb_repository = self.open_gb_repository(project_id)?;
super::push(&project_repository, &gb_repository, branch_id, &private_key).map_err(|e| {
@ -361,4 +397,15 @@ impl Controller {
.context("failed to open repository")
.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)
}
pub const GITBUTLER_INTEGRATION_REFERENCE: &str = "refs/heads/gitbutler/integration";
pub fn update_gitbutler_integration(
gb_repository: &gb_repository::Repository,
project_repository: &project_repository::Repository,
@ -1682,8 +1684,12 @@ pub fn update_gitbutler_integration(
let repo = &project_repository.git_repository;
// write the currrent target sha to a temp branch as a parent
let my_ref = "refs/heads/gitbutler/integration";
repo.reference(my_ref, target.sha, true, "update target")?;
repo.reference(
GITBUTLER_INTEGRATION_REFERENCE,
target.sha,
true,
"update target",
)?;
// get commit object from 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_sha = head.target().unwrap().to_string();
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
// write a file to .git/integration with the previous head and name
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
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
let applied_virtual_branches = get_virtual_branches(gb_repository, Some(true))?;