2024-04-27 00:20:31 +03:00
|
|
|
use crate::{
|
|
|
|
error::Error,
|
2024-05-26 15:34:45 +03:00
|
|
|
ops::entry::{OperationKind, SnapshotDetails},
|
2024-04-27 00:20:31 +03:00
|
|
|
};
|
2024-05-24 11:40:52 +03:00
|
|
|
use std::{collections::HashMap, path::Path, sync::Arc};
|
2024-03-29 12:04:26 +03:00
|
|
|
|
|
|
|
use anyhow::Context;
|
|
|
|
use tokio::{sync::Semaphore, task::JoinHandle};
|
|
|
|
|
2024-03-31 00:25:36 +03:00
|
|
|
use super::{
|
|
|
|
branch::{BranchId, BranchOwnershipClaims},
|
2024-05-31 17:11:37 +03:00
|
|
|
target, target_to_base_branch, BaseBranch, Branch, RemoteBranchFile, VirtualBranchesHandle,
|
2024-03-31 00:25:36 +03:00
|
|
|
};
|
2024-03-31 00:27:56 +03:00
|
|
|
use crate::{
|
2024-05-07 16:15:25 +03:00
|
|
|
git, project_repository,
|
2024-03-31 00:27:56 +03:00
|
|
|
projects::{self, ProjectId},
|
|
|
|
users,
|
|
|
|
};
|
2024-03-31 00:25:36 +03:00
|
|
|
|
2024-03-29 12:04:26 +03:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Controller {
|
|
|
|
projects: projects::Controller,
|
|
|
|
users: users::Controller,
|
|
|
|
helper: git::credentials::Helper,
|
|
|
|
|
|
|
|
by_project_id: Arc<tokio::sync::Mutex<HashMap<ProjectId, ControllerInner>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Controller {
|
|
|
|
pub fn new(
|
|
|
|
projects: projects::Controller,
|
|
|
|
users: users::Controller,
|
|
|
|
helper: git::credentials::Helper,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
by_project_id: Arc::new(tokio::sync::Mutex::new(HashMap::new())),
|
|
|
|
|
|
|
|
projects,
|
|
|
|
users,
|
|
|
|
helper,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-29 11:47:11 +03:00
|
|
|
async fn inner(&self, project_id: ProjectId) -> ControllerInner {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.by_project_id
|
|
|
|
.lock()
|
|
|
|
.await
|
2024-05-29 11:47:11 +03:00
|
|
|
.entry(project_id)
|
2024-05-07 16:15:25 +03:00
|
|
|
.or_insert_with(|| ControllerInner::new(&self.projects, &self.users, &self.helper))
|
2024-03-29 12:04:26 +03:00
|
|
|
.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
message: &str,
|
|
|
|
ownership: Option<&BranchOwnershipClaims>,
|
|
|
|
run_hooks: bool,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<git::Oid, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.create_commit(project_id, branch_id, message, ownership, run_hooks)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn can_apply_remote_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
branch_name: &git::RemoteRefname,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<bool, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.can_apply_remote_branch(project_id, branch_name)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn can_apply_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<bool, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.can_apply_virtual_branch(project_id, branch_id)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn list_virtual_branches(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-04-17 08:14:43 +03:00
|
|
|
) -> Result<(Vec<super::VirtualBranch>, Vec<git::diff::FileDiff>), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.list_virtual_branches(project_id)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
create: &super::branch::BranchCreateRequest,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<BranchId, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.create_virtual_branch(project_id, create)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_virtual_branch_from_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
branch: &git::Refname,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<BranchId, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.create_virtual_branch_from_branch(project_id, branch)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2024-05-29 11:47:11 +03:00
|
|
|
pub async fn get_base_branch_data(&self, project_id: ProjectId) -> Result<BaseBranch, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.get_base_branch_data(project_id)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn list_remote_commit_files(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<Vec<RemoteBranchFile>, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.list_remote_commit_files(project_id, commit_oid)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn set_base_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
target_branch: &git::RemoteRefname,
|
2024-05-30 18:07:52 +03:00
|
|
|
) -> Result<BaseBranch, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.set_base_branch(project_id, target_branch)
|
|
|
|
}
|
|
|
|
|
2024-05-03 12:20:47 +03:00
|
|
|
pub async fn set_target_push_remote(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-03 12:20:47 +03:00
|
|
|
push_remote: &str,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.set_target_push_remote(project_id, push_remote)
|
|
|
|
}
|
|
|
|
|
2024-05-23 05:41:13 +03:00
|
|
|
pub async fn integrate_upstream_commits(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
2024-05-23 05:41:13 +03:00
|
|
|
.integrate_upstream_commits(project_id, branch_id)
|
2024-03-29 12:04:26 +03:00
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2024-06-01 14:11:53 +03:00
|
|
|
pub async fn update_base_branch(&self, project_id: ProjectId) -> Result<Vec<Branch>, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.update_base_branch(project_id)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
branch_update: super::branch::BranchUpdateRequest,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.update_virtual_branch(project_id, branch_update)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
pub async fn delete_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.delete_virtual_branch(project_id, branch_id)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn apply_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.apply_virtual_branch(project_id, branch_id)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn unapply_ownership(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
ownership: &BranchOwnershipClaims,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.unapply_ownership(project_id, ownership)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn reset_files(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
files: &Vec<String>,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.reset_files(project_id, files)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn amend(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-03-29 12:04:26 +03:00
|
|
|
ownership: &BranchOwnershipClaims,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<git::Oid, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
2024-04-29 16:03:01 +03:00
|
|
|
.amend(project_id, branch_id, commit_oid, ownership)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn move_commit_file(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
from_commit_oid: git::Oid,
|
|
|
|
to_commit_oid: git::Oid,
|
|
|
|
ownership: &BranchOwnershipClaims,
|
|
|
|
) -> Result<git::Oid, Error> {
|
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.move_commit_file(
|
|
|
|
project_id,
|
|
|
|
branch_id,
|
|
|
|
from_commit_oid,
|
|
|
|
to_commit_oid,
|
|
|
|
ownership,
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn undo_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
commit_oid: git::Oid,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.undo_commit(project_id, branch_id, commit_oid)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn insert_blank_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
commit_oid: git::Oid,
|
|
|
|
offset: i32,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.insert_blank_commit(project_id, branch_id, commit_oid, offset)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn reorder_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
commit_oid: git::Oid,
|
|
|
|
offset: i32,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.reorder_commit(project_id, branch_id, commit_oid, offset)
|
2024-03-29 12:04:26 +03:00
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn reset_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
target_commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.reset_virtual_branch(project_id, branch_id, target_commit_oid)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn unapply_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.unapply_virtual_branch(project_id, branch_id)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn push_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
with_force: bool,
|
2024-05-07 17:07:37 +03:00
|
|
|
askpass: Option<Option<BranchId>>,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.push_virtual_branch(project_id, branch_id, with_force, askpass)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn cherry_pick(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<Option<git::Oid>, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.cherry_pick(project_id, branch_id, commit_oid)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn list_remote_branches(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<Vec<super::RemoteBranch>, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.list_remote_branches(project_id)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_remote_branch_data(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
refname: &git::Refname,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<super::RemoteBranchData, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.get_remote_branch_data(project_id, refname)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn squash(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.squash(project_id, branch_id, commit_oid)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_commit_message(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
|
|
|
message: &str,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.update_commit_message(project_id, branch_id, commit_oid, message)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2024-05-28 11:14:35 +03:00
|
|
|
pub async fn fetch_from_remotes(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-07 17:07:37 +03:00
|
|
|
askpass: Option<String>,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<BaseBranch, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
2024-05-28 11:14:35 +03:00
|
|
|
.fetch_from_remotes(project_id, askpass)
|
2024-03-29 12:04:26 +03:00
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn move_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
target_branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
self.inner(project_id)
|
|
|
|
.await
|
|
|
|
.move_commit(project_id, target_branch_id, commit_oid)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
struct ControllerInner {
|
|
|
|
semaphore: Arc<Semaphore>,
|
|
|
|
|
|
|
|
projects: projects::Controller,
|
|
|
|
users: users::Controller,
|
|
|
|
helper: git::credentials::Helper,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ControllerInner {
|
|
|
|
pub fn new(
|
|
|
|
projects: &projects::Controller,
|
|
|
|
users: &users::Controller,
|
|
|
|
helper: &git::credentials::Helper,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
semaphore: Arc::new(Semaphore::new(1)),
|
|
|
|
projects: projects.clone(),
|
|
|
|
users: users.clone(),
|
|
|
|
helper: helper.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
message: &str,
|
|
|
|
ownership: Option<&BranchOwnershipClaims>,
|
|
|
|
run_hooks: bool,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<git::Oid, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, user| {
|
2024-05-24 01:35:31 +03:00
|
|
|
let snapshot_tree = project_repository.project().prepare_snapshot();
|
|
|
|
let result = super::commit(
|
2024-03-29 12:04:26 +03:00
|
|
|
project_repository,
|
|
|
|
branch_id,
|
|
|
|
message,
|
|
|
|
ownership,
|
|
|
|
user,
|
|
|
|
run_hooks,
|
|
|
|
)
|
2024-05-30 21:53:17 +03:00
|
|
|
.map_err(Into::into);
|
2024-05-24 01:35:31 +03:00
|
|
|
let _ = snapshot_tree.and_then(|snapshot_tree| {
|
|
|
|
project_repository.project().snapshot_commit_creation(
|
|
|
|
snapshot_tree,
|
2024-05-30 23:07:02 +03:00
|
|
|
result.as_ref().err(),
|
2024-05-24 01:35:31 +03:00
|
|
|
message.to_owned(),
|
2024-05-26 16:48:36 +03:00
|
|
|
None,
|
2024-05-24 01:35:31 +03:00
|
|
|
)
|
|
|
|
});
|
|
|
|
result
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn can_apply_remote_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
branch_name: &git::RemoteRefname,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<bool, Error> {
|
2024-03-31 22:52:56 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
2024-05-31 10:39:29 +03:00
|
|
|
super::is_remote_branch_mergeable(&project_repository, branch_name).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn can_apply_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<bool, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
2024-04-19 23:11:30 +03:00
|
|
|
super::is_virtual_branch_mergeable(&project_repository, branch_id).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn list_virtual_branches(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-04-17 08:14:43 +03:00
|
|
|
) -> Result<(Vec<super::VirtualBranch>, Vec<git::diff::FileDiff>), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-04-19 23:48:43 +03:00
|
|
|
super::list_virtual_branches(project_repository).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
create: &super::branch::BranchCreateRequest,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<BranchId, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-04-19 23:05:33 +03:00
|
|
|
let branch_id = super::create_virtual_branch(project_repository, create)?.id;
|
2024-03-29 12:04:26 +03:00
|
|
|
Ok(branch_id)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_virtual_branch_from_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
branch: &git::Refname,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<BranchId, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, user| {
|
2024-05-30 11:44:42 +03:00
|
|
|
super::create_virtual_branch_from_branch(project_repository, branch, user)
|
2024-05-31 11:03:22 +03:00
|
|
|
.map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-05-29 11:47:11 +03:00
|
|
|
pub fn get_base_branch_data(&self, project_id: ProjectId) -> Result<BaseBranch, Error> {
|
2024-03-31 22:52:56 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
2024-04-21 10:10:37 +03:00
|
|
|
Ok(super::get_base_branch_data(&project_repository)?)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn list_remote_commit_files(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<Vec<RemoteBranchFile>, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
2024-04-17 07:59:13 +03:00
|
|
|
super::list_remote_commit_files(&project_repository.git_repository, commit_oid)
|
2024-05-31 11:03:22 +03:00
|
|
|
.map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_base_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
target_branch: &git::RemoteRefname,
|
2024-05-30 18:07:52 +03:00
|
|
|
) -> Result<BaseBranch, Error> {
|
2024-03-31 22:52:56 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::SetBaseBranch));
|
2024-05-30 18:07:52 +03:00
|
|
|
Ok(super::set_base_branch(&project_repository, target_branch)?)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-05-03 12:20:47 +03:00
|
|
|
pub fn set_target_push_remote(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-03 12:20:47 +03:00
|
|
|
push_remote: &str,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
2024-05-30 18:07:52 +03:00
|
|
|
Ok(super::set_target_push_remote(
|
|
|
|
&project_repository,
|
|
|
|
push_remote,
|
|
|
|
)?)
|
2024-05-03 12:20:47 +03:00
|
|
|
}
|
|
|
|
|
2024-05-23 05:41:13 +03:00
|
|
|
pub async fn integrate_upstream_commits(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, user| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::MergeUpstream));
|
2024-05-23 12:48:56 +03:00
|
|
|
super::integrate_upstream_commits(project_repository, branch_id, user)
|
|
|
|
.map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-06-01 14:11:53 +03:00
|
|
|
pub async fn update_base_branch(&self, project_id: ProjectId) -> Result<Vec<Branch>, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, user| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::UpdateWorkspaceBase));
|
2024-05-23 12:49:34 +03:00
|
|
|
super::update_base_branch(project_repository, user).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
branch_update: super::branch::BranchUpdateRequest,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-04-19 23:23:24 +03:00
|
|
|
super::update_branch(project_repository, branch_update)?;
|
2024-03-29 12:04:26 +03:00
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn delete_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-08 01:00:18 +03:00
|
|
|
super::delete_branch(project_repository, branch_id)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn apply_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, user| {
|
2024-05-30 23:31:16 +03:00
|
|
|
let snapshot_tree = project_repository.project().prepare_snapshot();
|
|
|
|
let result =
|
2024-05-31 16:46:04 +03:00
|
|
|
super::apply_branch(project_repository, branch_id, user).map_err(Into::into);
|
2024-05-30 23:31:16 +03:00
|
|
|
|
|
|
|
let _ = snapshot_tree.and_then(|snapshot_tree| {
|
|
|
|
project_repository
|
|
|
|
.project()
|
2024-05-31 00:44:58 +03:00
|
|
|
.snapshot_branch_applied(snapshot_tree, result.as_ref())
|
2024-05-30 23:31:16 +03:00
|
|
|
});
|
|
|
|
result.map(|_| ())
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn unapply_ownership(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
ownership: &BranchOwnershipClaims,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::DiscardHunk));
|
2024-05-23 12:50:06 +03:00
|
|
|
super::unapply_ownership(project_repository, ownership).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn reset_files(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
ownership: &Vec<String>,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::DiscardFile));
|
2024-05-23 12:50:34 +03:00
|
|
|
super::reset_files(project_repository, ownership).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn amend(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-03-29 12:04:26 +03:00
|
|
|
ownership: &BranchOwnershipClaims,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<git::Oid, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::AmendCommit));
|
2024-05-31 10:39:29 +03:00
|
|
|
Ok(super::amend(
|
|
|
|
project_repository,
|
|
|
|
branch_id,
|
|
|
|
commit_oid,
|
|
|
|
ownership,
|
|
|
|
)?)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-04-29 16:03:01 +03:00
|
|
|
pub async fn move_commit_file(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
from_commit_oid: git::Oid,
|
|
|
|
to_commit_oid: git::Oid,
|
|
|
|
ownership: &BranchOwnershipClaims,
|
|
|
|
) -> Result<git::Oid, Error> {
|
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-23 12:52:27 +03:00
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::MoveCommitFile));
|
2024-05-23 12:52:27 +03:00
|
|
|
super::move_commit_file(
|
2024-04-29 16:03:01 +03:00
|
|
|
project_repository,
|
|
|
|
branch_id,
|
|
|
|
from_commit_oid,
|
|
|
|
to_commit_oid,
|
|
|
|
ownership,
|
|
|
|
)
|
2024-05-31 11:03:22 +03:00
|
|
|
.map_err(Into::into)
|
2024-04-29 16:03:01 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn undo_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
commit_oid: git::Oid,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-31 00:59:30 +03:00
|
|
|
let snapshot_tree = project_repository.project().prepare_snapshot();
|
|
|
|
let result: Result<(), Error> =
|
2024-05-31 11:03:22 +03:00
|
|
|
super::undo_commit(project_repository, branch_id, commit_oid).map_err(Into::into);
|
2024-05-31 00:59:30 +03:00
|
|
|
let _ = snapshot_tree.and_then(|snapshot_tree| {
|
|
|
|
project_repository.project().snapshot_commit_undo(
|
|
|
|
snapshot_tree,
|
|
|
|
result.as_ref(),
|
|
|
|
commit_oid,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
result
|
2024-04-29 16:03:01 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn insert_blank_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
commit_oid: git::Oid,
|
|
|
|
offset: i32,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
|
|
|
self.with_verify_branch(project_id, |project_repository, user| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::InsertBlankCommit));
|
2024-05-23 12:53:16 +03:00
|
|
|
super::insert_blank_commit(project_repository, branch_id, commit_oid, user, offset)
|
2024-05-31 11:03:22 +03:00
|
|
|
.map_err(Into::into)
|
2024-04-29 16:03:01 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn reorder_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-29 16:03:01 +03:00
|
|
|
commit_oid: git::Oid,
|
|
|
|
offset: i32,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::ReorderCommit));
|
2024-05-23 12:54:03 +03:00
|
|
|
super::reorder_commit(project_repository, branch_id, commit_oid, offset)
|
2024-05-31 11:03:22 +03:00
|
|
|
.map_err(Into::into)
|
2024-04-29 16:03:01 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-03-29 12:04:26 +03:00
|
|
|
pub async fn reset_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
target_commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::UndoCommit));
|
2024-05-23 12:54:46 +03:00
|
|
|
super::reset_branch(project_repository, branch_id, target_commit_oid)
|
2024-05-31 11:03:22 +03:00
|
|
|
.map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn unapply_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-31 00:44:58 +03:00
|
|
|
let snapshot_tree = project_repository.project().prepare_snapshot();
|
|
|
|
let result = super::unapply_branch(project_repository, branch_id).map_err(Into::into);
|
|
|
|
let _ = snapshot_tree.and_then(|snapshot_tree| {
|
|
|
|
project_repository
|
|
|
|
.project()
|
|
|
|
.snapshot_branch_unapplied(snapshot_tree, result.as_ref())
|
|
|
|
});
|
|
|
|
result.map(|_| ())
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn push_virtual_branch(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
with_force: bool,
|
2024-05-07 17:07:37 +03:00
|
|
|
askpass: Option<Option<BranchId>>,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
let helper = self.helper.clone();
|
2024-05-29 11:47:11 +03:00
|
|
|
self.with_verify_branch_async(project_id, move |project_repository, _| {
|
2024-03-31 22:52:56 +03:00
|
|
|
Ok(super::push(
|
2024-03-29 12:04:26 +03:00
|
|
|
project_repository,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id,
|
2024-03-29 12:04:26 +03:00
|
|
|
with_force,
|
|
|
|
&helper,
|
|
|
|
askpass,
|
2024-03-31 22:52:56 +03:00
|
|
|
)?)
|
2024-03-29 12:04:26 +03:00
|
|
|
})?
|
|
|
|
.await
|
2024-04-01 16:57:09 +03:00
|
|
|
.map_err(Error::from_err)?
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn cherry_pick(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<Option<git::Oid>, Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::CherryPick));
|
2024-05-31 11:03:22 +03:00
|
|
|
super::cherry_pick(project_repository, branch_id, commit_oid).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn list_remote_branches(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<Vec<super::RemoteBranch>, Error> {
|
2024-03-31 22:52:56 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
2024-04-21 10:16:14 +03:00
|
|
|
Ok(super::list_remote_branches(&project_repository)?)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_remote_branch_data(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-03-29 12:04:26 +03:00
|
|
|
refname: &git::Refname,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<super::RemoteBranchData, Error> {
|
2024-03-31 22:52:56 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
2024-04-21 10:16:14 +03:00
|
|
|
Ok(super::get_branch_data(&project_repository, refname)?)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn squash(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::SquashCommit));
|
2024-05-31 11:03:22 +03:00
|
|
|
super::squash(project_repository, branch_id, commit_oid).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_commit_message(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
|
|
|
message: &str,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, _| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::UpdateCommitMessage));
|
2024-05-23 12:58:13 +03:00
|
|
|
super::update_commit_message(project_repository, branch_id, commit_oid, message)
|
2024-05-31 11:03:22 +03:00
|
|
|
.map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-05-28 11:14:35 +03:00
|
|
|
pub async fn fetch_from_remotes(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-07 17:07:37 +03:00
|
|
|
askpass: Option<String>,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<BaseBranch, Error> {
|
2024-03-31 22:52:56 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let mut project_repository = project_repository::Repository::open(&project)?;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-05-24 15:58:56 +03:00
|
|
|
let remotes = project_repository.remotes()?;
|
2024-05-31 17:11:37 +03:00
|
|
|
let fetch_results: Vec<Result<(), _>> = remotes
|
2024-05-24 15:58:56 +03:00
|
|
|
.iter()
|
2024-05-31 17:11:37 +03:00
|
|
|
.map(|remote| project_repository.fetch(remote, &self.helper, askpass.clone()))
|
2024-05-24 15:58:56 +03:00
|
|
|
.collect();
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-05-24 15:58:56 +03:00
|
|
|
let project_data_last_fetched = if fetch_results.iter().any(Result::is_err) {
|
|
|
|
projects::FetchResult::Error {
|
2024-05-24 11:40:52 +03:00
|
|
|
timestamp: std::time::SystemTime::now(),
|
2024-05-24 15:58:56 +03:00
|
|
|
error: fetch_results
|
|
|
|
.iter()
|
|
|
|
.filter_map(|result| match result {
|
|
|
|
Ok(_) => None,
|
|
|
|
Err(error) => Some(error.to_string()),
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n"),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
projects::FetchResult::Fetched {
|
2024-05-24 11:40:52 +03:00
|
|
|
timestamp: std::time::SystemTime::now(),
|
2024-05-24 15:58:56 +03:00
|
|
|
}
|
2024-03-29 12:04:26 +03:00
|
|
|
};
|
|
|
|
|
2024-05-24 15:58:56 +03:00
|
|
|
let default_target = default_target(&project_repository.project().gb_dir())?;
|
|
|
|
|
2024-05-06 17:01:06 +03:00
|
|
|
// if we have a push remote, let's fetch from this too
|
|
|
|
if let Some(push_remote) = &default_target.push_remote_name {
|
2024-05-31 17:11:37 +03:00
|
|
|
if let Err(err) = project_repository.fetch(push_remote, &self.helper, askpass.clone()) {
|
|
|
|
tracing::warn!(?err, "fetch from push-remote failed");
|
|
|
|
}
|
2024-05-06 17:01:06 +03:00
|
|
|
}
|
|
|
|
|
2024-03-29 12:04:26 +03:00
|
|
|
let updated_project = self
|
|
|
|
.projects
|
|
|
|
.update(&projects::UpdateRequest {
|
2024-05-29 11:47:11 +03:00
|
|
|
id: project_id,
|
2024-03-29 12:04:26 +03:00
|
|
|
project_data_last_fetched: Some(project_data_last_fetched),
|
|
|
|
..Default::default()
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
.context("failed to update project")?;
|
|
|
|
|
|
|
|
project_repository.set_project(&updated_project);
|
|
|
|
|
|
|
|
let base_branch = target_to_base_branch(&project_repository, &default_target)
|
|
|
|
.context("failed to convert target to base branch")?;
|
|
|
|
|
|
|
|
Ok(base_branch)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn move_commit(
|
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-05-29 12:07:36 +03:00
|
|
|
target_branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
commit_oid: git::Oid,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<(), Error> {
|
2024-03-29 12:04:26 +03:00
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
|
2024-04-21 10:26:34 +03:00
|
|
|
self.with_verify_branch(project_id, |project_repository, user| {
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::MoveCommit));
|
2024-05-23 12:59:26 +03:00
|
|
|
super::move_commit(project_repository, target_branch_id, commit_oid, user)
|
2024-05-30 21:53:17 +03:00
|
|
|
.map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ControllerInner {
|
2024-03-31 22:52:56 +03:00
|
|
|
fn with_verify_branch<T>(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-04-21 10:26:34 +03:00
|
|
|
action: impl FnOnce(&project_repository::Repository, Option<&users::User>) -> Result<T, Error>,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<T, Error> {
|
2024-03-31 22:52:56 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
|
|
|
let user = self.users.get_user()?;
|
2024-05-31 11:03:22 +03:00
|
|
|
super::integration::verify_branch(&project_repository)?;
|
2024-04-21 10:26:34 +03:00
|
|
|
action(&project_repository, user.as_ref())
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-03-31 22:52:56 +03:00
|
|
|
fn with_verify_branch_async<T: Send + 'static>(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-05-29 11:47:11 +03:00
|
|
|
project_id: ProjectId,
|
2024-04-21 10:26:34 +03:00
|
|
|
action: impl FnOnce(&project_repository::Repository, Option<&users::User>) -> Result<T, Error>
|
2024-03-29 12:04:26 +03:00
|
|
|
+ Send
|
|
|
|
+ 'static,
|
2024-04-01 16:57:09 +03:00
|
|
|
) -> Result<JoinHandle<Result<T, Error>>, Error> {
|
2024-03-31 22:52:56 +03:00
|
|
|
let project = self.projects.get(project_id)?;
|
|
|
|
let project_repository = project_repository::Repository::open(&project)?;
|
|
|
|
let user = self.users.get_user()?;
|
2024-05-31 11:03:22 +03:00
|
|
|
super::integration::verify_branch(&project_repository)?;
|
2024-03-29 12:04:26 +03:00
|
|
|
Ok(tokio::task::spawn_blocking(move || {
|
2024-04-21 10:26:34 +03:00
|
|
|
action(&project_repository, user.as_ref())
|
2024-03-29 12:04:26 +03:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
2024-04-21 10:26:34 +03:00
|
|
|
|
2024-05-21 11:16:37 +03:00
|
|
|
fn default_target(base_path: &Path) -> anyhow::Result<target::Target> {
|
|
|
|
VirtualBranchesHandle::new(base_path).get_default_target()
|
2024-04-21 10:26:34 +03:00
|
|
|
}
|