mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-21 16:41:32 +03:00
Merge pull request #3746 from gitbutlerapp/push-gb-data-improvements-by-user
remove unused gb_data flush / push / fetch functions
This commit is contained in:
commit
29e8d9f8b8
@ -19,8 +19,6 @@ pub trait Watchers {
|
|||||||
fn watch(&self, project: &Project) -> anyhow::Result<()>;
|
fn watch(&self, project: &Project) -> anyhow::Result<()>;
|
||||||
/// Stop watching filesystem changes.
|
/// Stop watching filesystem changes.
|
||||||
async fn stop(&self, id: ProjectId);
|
async fn stop(&self, id: ProjectId);
|
||||||
async fn fetch_gb_data(&self, id: ProjectId) -> anyhow::Result<()>;
|
|
||||||
async fn push_gb_data(&self, id: ProjectId) -> anyhow::Result<()>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -169,28 +167,6 @@ impl Controller {
|
|||||||
error => UpdateError::Other(error.into()),
|
error => UpdateError::Other(error.into()),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Some(watchers) = &self.watchers {
|
|
||||||
if let Some(api) = &project.api {
|
|
||||||
if api.sync {
|
|
||||||
if let Err(error) = watchers.fetch_gb_data(project.id).await {
|
|
||||||
tracing::error!(
|
|
||||||
project_id = %project.id,
|
|
||||||
?error,
|
|
||||||
"failed to post fetch project event"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(error) = watchers.push_gb_data(project.id).await {
|
|
||||||
tracing::error!(
|
|
||||||
project_id = %project.id,
|
|
||||||
?error,
|
|
||||||
"failed to post push project event"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(updated)
|
Ok(updated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,14 +191,4 @@ impl gitbutler_core::projects::Watchers for Watchers {
|
|||||||
async fn stop(&self, id: ProjectId) {
|
async fn stop(&self, id: ProjectId) {
|
||||||
Watchers::stop(self, id).await
|
Watchers::stop(self, id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_gb_data(&self, id: ProjectId) -> Result<()> {
|
|
||||||
self.post(gitbutler_watcher::Action::FetchGitbutlerData(id))
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn push_gb_data(&self, id: ProjectId) -> Result<()> {
|
|
||||||
self.post(gitbutler_watcher::Action::PushGitbutlerData(id))
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,7 @@ use gitbutler_core::{projects::ProjectId, sessions};
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum InternalEvent {
|
pub(super) enum InternalEvent {
|
||||||
// From public action API
|
// From public action API
|
||||||
Flush(ProjectId, sessions::Session),
|
|
||||||
CalculateVirtualBranches(ProjectId),
|
CalculateVirtualBranches(ProjectId),
|
||||||
FetchGitbutlerData(ProjectId),
|
|
||||||
PushGitbutlerData(ProjectId),
|
|
||||||
|
|
||||||
// From file monitor
|
// From file monitor
|
||||||
GitFilesChange(ProjectId, Vec<PathBuf>),
|
GitFilesChange(ProjectId, Vec<PathBuf>),
|
||||||
@ -24,20 +21,14 @@ pub(super) enum InternalEvent {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Flush(ProjectId, sessions::Session),
|
|
||||||
CalculateVirtualBranches(ProjectId),
|
CalculateVirtualBranches(ProjectId),
|
||||||
FetchGitbutlerData(ProjectId),
|
|
||||||
PushGitbutlerData(ProjectId),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Action {
|
impl Action {
|
||||||
/// Return the action's associated project id.
|
/// Return the action's associated project id.
|
||||||
pub fn project_id(&self) -> ProjectId {
|
pub fn project_id(&self) -> ProjectId {
|
||||||
match self {
|
match self {
|
||||||
Action::FetchGitbutlerData(project_id)
|
Action::CalculateVirtualBranches(project_id) => *project_id,
|
||||||
| Action::Flush(project_id, _)
|
|
||||||
| Action::CalculateVirtualBranches(project_id)
|
|
||||||
| Action::PushGitbutlerData(project_id) => *project_id,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,10 +36,7 @@ impl Action {
|
|||||||
impl From<Action> for InternalEvent {
|
impl From<Action> for InternalEvent {
|
||||||
fn from(value: Action) -> Self {
|
fn from(value: Action) -> Self {
|
||||||
match value {
|
match value {
|
||||||
Action::Flush(a, b) => InternalEvent::Flush(a, b),
|
|
||||||
Action::CalculateVirtualBranches(v) => InternalEvent::CalculateVirtualBranches(v),
|
Action::CalculateVirtualBranches(v) => InternalEvent::CalculateVirtualBranches(v),
|
||||||
Action::FetchGitbutlerData(v) => InternalEvent::FetchGitbutlerData(v),
|
|
||||||
Action::PushGitbutlerData(v) => InternalEvent::PushGitbutlerData(v),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,12 +44,6 @@ impl From<Action> for InternalEvent {
|
|||||||
impl Display for InternalEvent {
|
impl Display for InternalEvent {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
InternalEvent::FetchGitbutlerData(pid) => {
|
|
||||||
write!(f, "FetchGitbutlerData({})", pid,)
|
|
||||||
}
|
|
||||||
InternalEvent::Flush(project_id, session) => {
|
|
||||||
write!(f, "Flush({}, {})", project_id, session.id)
|
|
||||||
}
|
|
||||||
InternalEvent::GitFilesChange(project_id, paths) => {
|
InternalEvent::GitFilesChange(project_id, paths) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -79,7 +61,6 @@ impl Display for InternalEvent {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
InternalEvent::CalculateVirtualBranches(pid) => write!(f, "VirtualBranch({})", pid),
|
InternalEvent::CalculateVirtualBranches(pid) => write!(f, "VirtualBranch({})", pid),
|
||||||
InternalEvent::PushGitbutlerData(pid) => write!(f, "PushGitbutlerData({})", pid),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
mod calculate_deltas;
|
mod calculate_deltas;
|
||||||
mod index;
|
mod index;
|
||||||
mod push_project_to_gitbutler;
|
|
||||||
|
|
||||||
|
use std::path;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{path, time};
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use gitbutler_core::ops::entry::{OperationType, SnapshotDetails};
|
use gitbutler_core::ops::entry::{OperationType, SnapshotDetails};
|
||||||
use gitbutler_core::ops::oplog::Oplog;
|
use gitbutler_core::ops::oplog::Oplog;
|
||||||
use gitbutler_core::projects::ProjectId;
|
use gitbutler_core::projects::ProjectId;
|
||||||
use gitbutler_core::sessions::SessionId;
|
use gitbutler_core::sessions::SessionId;
|
||||||
use gitbutler_core::virtual_branches::VirtualBranches;
|
use gitbutler_core::virtual_branches::VirtualBranches;
|
||||||
use gitbutler_core::{
|
use gitbutler_core::{
|
||||||
assets, deltas, gb_repository, git, project_repository, projects, reader, sessions, users,
|
assets, deltas, git, project_repository, projects, reader, sessions, users, virtual_branches,
|
||||||
virtual_branches,
|
|
||||||
};
|
};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
@ -69,12 +67,8 @@ impl Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handle the events that come in from the filesystem, or the public API.
|
/// Handle the events that come in from the filesystem, or the public API.
|
||||||
#[instrument(skip(self, now), fields(event = %event), err(Debug))]
|
#[instrument(skip(self), fields(event = %event), err(Debug))]
|
||||||
pub(super) async fn handle(
|
pub(super) async fn handle(&self, event: events::InternalEvent) -> Result<()> {
|
||||||
&self,
|
|
||||||
event: events::InternalEvent,
|
|
||||||
now: time::SystemTime,
|
|
||||||
) -> Result<()> {
|
|
||||||
match event {
|
match event {
|
||||||
events::InternalEvent::ProjectFilesChange(project_id, path) => {
|
events::InternalEvent::ProjectFilesChange(project_id, path) => {
|
||||||
self.recalculate_everything(path, project_id).await
|
self.recalculate_everything(path, project_id).await
|
||||||
@ -85,20 +79,6 @@ impl Handler {
|
|||||||
.await
|
.await
|
||||||
.context("failed to handle git file change event"),
|
.context("failed to handle git file change event"),
|
||||||
|
|
||||||
events::InternalEvent::PushGitbutlerData(project_id) => self
|
|
||||||
.push_gb_data(project_id)
|
|
||||||
.context("failed to push gitbutler data"),
|
|
||||||
|
|
||||||
events::InternalEvent::FetchGitbutlerData(project_id) => self
|
|
||||||
.fetch_gb_data(project_id, now)
|
|
||||||
.await
|
|
||||||
.context("failed to fetch gitbutler data"),
|
|
||||||
|
|
||||||
events::InternalEvent::Flush(project_id, session) => self
|
|
||||||
.flush_session(project_id, &session)
|
|
||||||
.await
|
|
||||||
.context("failed to handle flush session event"),
|
|
||||||
|
|
||||||
events::InternalEvent::CalculateVirtualBranches(project_id) => self
|
events::InternalEvent::CalculateVirtualBranches(project_id) => self
|
||||||
.calculate_virtual_branches(project_id)
|
.calculate_virtual_branches(project_id)
|
||||||
.await
|
.await
|
||||||
@ -127,40 +107,6 @@ impl Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn flush_session(
|
|
||||||
&self,
|
|
||||||
project_id: ProjectId,
|
|
||||||
session: &sessions::Session,
|
|
||||||
) -> Result<()> {
|
|
||||||
let project = self
|
|
||||||
.projects
|
|
||||||
.get(&project_id)
|
|
||||||
.context("failed to get project")?;
|
|
||||||
let user = self.users.get_user()?;
|
|
||||||
let project_repository =
|
|
||||||
project_repository::Repository::open(&project).context("failed to open repository")?;
|
|
||||||
let gb_repo = gb_repository::Repository::open(
|
|
||||||
&self.local_data_dir,
|
|
||||||
&project_repository,
|
|
||||||
user.as_ref(),
|
|
||||||
)
|
|
||||||
.context("failed to open repository")?;
|
|
||||||
|
|
||||||
let session = gb_repo
|
|
||||||
.flush_session(&project_repository, session, user.as_ref())
|
|
||||||
.context(format!("failed to flush session {}", session.id))?;
|
|
||||||
|
|
||||||
self.index_session(project_id, session)?;
|
|
||||||
|
|
||||||
let push_gb_data = tokio::task::spawn_blocking({
|
|
||||||
let this = self.clone();
|
|
||||||
move || this.push_gb_data(project_id)
|
|
||||||
});
|
|
||||||
self.push_project_to_gitbutler(project_id, 1000).await?;
|
|
||||||
push_gb_data.await??;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self, project_id))]
|
#[instrument(skip(self, project_id))]
|
||||||
async fn calculate_virtual_branches(&self, project_id: ProjectId) -> Result<()> {
|
async fn calculate_virtual_branches(&self, project_id: ProjectId) -> Result<()> {
|
||||||
match self
|
match self
|
||||||
@ -183,97 +129,6 @@ impl Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NOTE: this is an honest non-async function, and it should stay that way to avoid
|
|
||||||
/// dealing with git2 repositories across await points, which aren't `Send`.
|
|
||||||
fn push_gb_data(&self, project_id: ProjectId) -> Result<()> {
|
|
||||||
let user = self.users.get_user()?;
|
|
||||||
let project = self.projects.get(&project_id)?;
|
|
||||||
let project_repository =
|
|
||||||
project_repository::Repository::open(&project).context("failed to open repository")?;
|
|
||||||
let gb_repo = gb_repository::Repository::open(
|
|
||||||
&self.local_data_dir,
|
|
||||||
&project_repository,
|
|
||||||
user.as_ref(),
|
|
||||||
)
|
|
||||||
.context("failed to open repository")?;
|
|
||||||
|
|
||||||
gb_repo
|
|
||||||
.push(user.as_ref())
|
|
||||||
.context("failed to push gb repo")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fetch_gb_data(&self, project_id: ProjectId, now: time::SystemTime) -> Result<()> {
|
|
||||||
let user = self.users.get_user()?;
|
|
||||||
let project = self
|
|
||||||
.projects
|
|
||||||
.get(&project_id)
|
|
||||||
.context("failed to get project")?;
|
|
||||||
|
|
||||||
if !project.api.as_ref().map(|api| api.sync).unwrap_or_default() {
|
|
||||||
bail!("sync disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
let project_repository =
|
|
||||||
project_repository::Repository::open(&project).context("failed to open repository")?;
|
|
||||||
let gb_repo = gb_repository::Repository::open(
|
|
||||||
&self.local_data_dir,
|
|
||||||
&project_repository,
|
|
||||||
user.as_ref(),
|
|
||||||
)
|
|
||||||
.context("failed to open repository")?;
|
|
||||||
|
|
||||||
let sessions_before_fetch = gb_repo
|
|
||||||
.get_sessions_iterator()?
|
|
||||||
.filter_map(Result::ok)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let policy = backoff::ExponentialBackoffBuilder::new()
|
|
||||||
.with_max_elapsed_time(Some(time::Duration::from_secs(10 * 60)))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let fetch_result = backoff::retry(policy, || {
|
|
||||||
gb_repo.fetch(user.as_ref()).map_err(|err| match err {
|
|
||||||
gb_repository::RemoteError::Network => backoff::Error::permanent(err),
|
|
||||||
err @ gb_repository::RemoteError::Other(_) => {
|
|
||||||
tracing::warn!(%project_id, ?err, will_retry = true, "failed to fetch project data");
|
|
||||||
backoff::Error::transient(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let fetch_result = match fetch_result {
|
|
||||||
Ok(()) => projects::FetchResult::Fetched { timestamp: now },
|
|
||||||
Err(backoff::Error::Permanent(gb_repository::RemoteError::Network)) => {
|
|
||||||
projects::FetchResult::Error {
|
|
||||||
timestamp: now,
|
|
||||||
error: "network error".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
tracing::error!(%project_id, ?error, will_retry=false, "failed to fetch gitbutler data");
|
|
||||||
projects::FetchResult::Error {
|
|
||||||
timestamp: now,
|
|
||||||
error: error.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.projects
|
|
||||||
.update(&projects::UpdateRequest {
|
|
||||||
id: project_id,
|
|
||||||
gitbutler_data_last_fetched: Some(fetch_result),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.context("failed to update fetched result")?;
|
|
||||||
|
|
||||||
let sessions_after_fetch = gb_repo.get_sessions_iterator()?.filter_map(Result::ok);
|
|
||||||
let new_sessions = sessions_after_fetch.filter(|s| !sessions_before_fetch.contains(s));
|
|
||||||
for session in new_sessions {
|
|
||||||
self.index_session(project_id, session)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self, paths, project_id), fields(paths = paths.len()))]
|
#[instrument(skip(self, paths, project_id), fields(paths = paths.len()))]
|
||||||
async fn recalculate_everything(
|
async fn recalculate_everything(
|
||||||
&self,
|
&self,
|
||||||
@ -337,30 +192,6 @@ impl Handler {
|
|||||||
"logs/HEAD" => {
|
"logs/HEAD" => {
|
||||||
self.emit_app_event(Change::GitActivity(project.id))?;
|
self.emit_app_event(Change::GitActivity(project.id))?;
|
||||||
}
|
}
|
||||||
"GB_FLUSH" => {
|
|
||||||
let user = self.users.get_user()?;
|
|
||||||
let project_repository = open_projects_repository()?;
|
|
||||||
let gb_repo = gb_repository::Repository::open(
|
|
||||||
&self.local_data_dir,
|
|
||||||
&project_repository,
|
|
||||||
user.as_ref(),
|
|
||||||
)
|
|
||||||
.context("failed to open repository")?;
|
|
||||||
|
|
||||||
let gb_flush_path = project.path.join(".git/GB_FLUSH");
|
|
||||||
if gb_flush_path.exists() {
|
|
||||||
if let Err(err) = std::fs::remove_file(&gb_flush_path) {
|
|
||||||
tracing::error!(%project_id, path = %gb_flush_path.display(), "GB_FLUSH file delete error: {err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(current_session) = gb_repo
|
|
||||||
.get_current_session()
|
|
||||||
.context("failed to get current session")?
|
|
||||||
{
|
|
||||||
self.flush_session(project.id, ¤t_session).await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"HEAD" => {
|
"HEAD" => {
|
||||||
let project_repository = open_projects_repository()?;
|
let project_repository = open_projects_repository()?;
|
||||||
let head_ref = project_repository
|
let head_ref = project_repository
|
||||||
|
@ -1,219 +0,0 @@
|
|||||||
use std::time;
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
|
||||||
use gitbutler_core::id::Id;
|
|
||||||
use gitbutler_core::{
|
|
||||||
gb_repository,
|
|
||||||
git::{self, Oid, Repository},
|
|
||||||
project_repository,
|
|
||||||
projects::{self, CodePushState, ProjectId},
|
|
||||||
users,
|
|
||||||
};
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
impl super::Handler {
|
|
||||||
pub async fn push_project_to_gitbutler(
|
|
||||||
&self,
|
|
||||||
project_id: ProjectId,
|
|
||||||
batch_size: usize,
|
|
||||||
) -> Result<()> {
|
|
||||||
let project = self
|
|
||||||
.projects
|
|
||||||
.get(&project_id)
|
|
||||||
.context("failed to get project")?;
|
|
||||||
|
|
||||||
if !project.is_sync_enabled() || !project.has_code_url() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let user = self.users.get_user()?;
|
|
||||||
let project_repository =
|
|
||||||
project_repository::Repository::open(&project).context("failed to open repository")?;
|
|
||||||
let gb_code_last_commit = project
|
|
||||||
.gitbutler_code_push_state
|
|
||||||
.as_ref()
|
|
||||||
.map(|state| &state.id)
|
|
||||||
.copied();
|
|
||||||
let gb_repository = gb_repository::Repository::open(
|
|
||||||
&self.local_data_dir,
|
|
||||||
&project_repository,
|
|
||||||
user.as_ref(),
|
|
||||||
)?;
|
|
||||||
let default_target = gb_repository
|
|
||||||
.default_target()
|
|
||||||
.context("failed to open gb repo")?
|
|
||||||
.context("failed to get default target")?;
|
|
||||||
|
|
||||||
let target_changed = gb_code_last_commit.map_or(true, |id| id != default_target.sha);
|
|
||||||
if target_changed {
|
|
||||||
match self
|
|
||||||
.push_target(
|
|
||||||
&project_repository,
|
|
||||||
&default_target,
|
|
||||||
gb_code_last_commit,
|
|
||||||
project_id,
|
|
||||||
user.as_ref(),
|
|
||||||
batch_size,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(()) => {}
|
|
||||||
Err(project_repository::RemoteError::Network) => return Ok(()),
|
|
||||||
Err(err) => return Err(err).context("failed to push"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || -> Result<()> {
|
|
||||||
match push_all_refs(&project_repository, user.as_ref(), project_id) {
|
|
||||||
Ok(()) => Ok(()),
|
|
||||||
Err(project_repository::RemoteError::Network) => Ok(()),
|
|
||||||
Err(err) => Err(err).context("failed to push"),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
// make sure last push time is updated
|
|
||||||
self.update_project(project_id, default_target.sha).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Currently required to make functionality testable without requiring a `Handler` with all of its state.
|
|
||||||
impl super::Handler {
|
|
||||||
async fn update_project(
|
|
||||||
&self,
|
|
||||||
project_id: Id<projects::Project>,
|
|
||||||
id: Oid,
|
|
||||||
) -> Result<(), project_repository::RemoteError> {
|
|
||||||
self.projects
|
|
||||||
.update(&projects::UpdateRequest {
|
|
||||||
id: project_id,
|
|
||||||
gitbutler_code_push_state: Some(CodePushState {
|
|
||||||
id,
|
|
||||||
timestamp: time::SystemTime::now(),
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.context("failed to update last push")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn push_target(
|
|
||||||
&self,
|
|
||||||
project_repository: &project_repository::Repository,
|
|
||||||
default_target: &gitbutler_core::virtual_branches::target::Target,
|
|
||||||
gb_code_last_commit: Option<Oid>,
|
|
||||||
project_id: Id<projects::Project>,
|
|
||||||
user: Option<&users::User>,
|
|
||||||
batch_size: usize,
|
|
||||||
) -> Result<(), project_repository::RemoteError> {
|
|
||||||
let ids = batch_rev_walk(
|
|
||||||
&project_repository.git_repository,
|
|
||||||
batch_size,
|
|
||||||
default_target.sha,
|
|
||||||
gb_code_last_commit,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
tracing::info!(
|
|
||||||
%project_id,
|
|
||||||
batches=%ids.len(),
|
|
||||||
"batches left to push",
|
|
||||||
);
|
|
||||||
|
|
||||||
let id_count = ids.len();
|
|
||||||
for (idx, id) in ids.iter().enumerate().rev() {
|
|
||||||
let refspec = format!("+{}:refs/push-tmp/{}", id, project_id);
|
|
||||||
|
|
||||||
project_repository.push_to_gitbutler_server(user, &[&refspec])?;
|
|
||||||
self.update_project(project_id, *id).await?;
|
|
||||||
|
|
||||||
tracing::info!(
|
|
||||||
%project_id,
|
|
||||||
i = id_count.saturating_sub(idx),
|
|
||||||
total = id_count,
|
|
||||||
"project batch pushed",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
project_repository.push_to_gitbutler_server(
|
|
||||||
user,
|
|
||||||
&[&format!("+{}:refs/{}", default_target.sha, project_id)],
|
|
||||||
)?;
|
|
||||||
|
|
||||||
//TODO: remove push-tmp ref
|
|
||||||
tracing::info!(
|
|
||||||
%project_id,
|
|
||||||
"project target ref fully pushed",
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_all_refs(
|
|
||||||
project_repository: &project_repository::Repository,
|
|
||||||
user: Option<&users::User>,
|
|
||||||
project_id: Id<projects::Project>,
|
|
||||||
) -> Result<(), project_repository::RemoteError> {
|
|
||||||
let gb_references = collect_refs(project_repository)?;
|
|
||||||
let all_refs: Vec<_> = gb_references
|
|
||||||
.iter()
|
|
||||||
.filter(|r| {
|
|
||||||
matches!(
|
|
||||||
r,
|
|
||||||
git::Refname::Remote(_) | git::Refname::Virtual(_) | git::Refname::Local(_)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map(|r| format!("+{}:{}", r, r))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let all_refs: Vec<_> = all_refs.iter().map(String::as_str).collect();
|
|
||||||
let anything_pushed = project_repository.push_to_gitbutler_server(user, &all_refs)?;
|
|
||||||
if anything_pushed {
|
|
||||||
tracing::info!(
|
|
||||||
%project_id,
|
|
||||||
"refs pushed",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_refs(
|
|
||||||
project_repository: &project_repository::Repository,
|
|
||||||
) -> anyhow::Result<Vec<git::Refname>> {
|
|
||||||
Ok(project_repository
|
|
||||||
.git_repository
|
|
||||||
.references_glob("refs/*")?
|
|
||||||
.flatten()
|
|
||||||
.filter_map(|r| r.name())
|
|
||||||
.collect::<Vec<_>>())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn batch_rev_walk(
|
|
||||||
repo: &Repository,
|
|
||||||
batch_size: usize,
|
|
||||||
from: Oid,
|
|
||||||
until: Option<Oid>,
|
|
||||||
) -> Result<Vec<Oid>> {
|
|
||||||
let mut revwalk = repo.revwalk().context("failed to create revwalk")?;
|
|
||||||
revwalk
|
|
||||||
.push(from.into())
|
|
||||||
.context(format!("failed to push {}", from))?;
|
|
||||||
if let Some(oid) = until {
|
|
||||||
revwalk
|
|
||||||
.hide(oid.into())
|
|
||||||
.context(format!("failed to hide {}", oid))?;
|
|
||||||
}
|
|
||||||
let mut oids = Vec::new();
|
|
||||||
oids.push(from);
|
|
||||||
|
|
||||||
let from = from.into();
|
|
||||||
for batch in &revwalk.chunks(batch_size) {
|
|
||||||
let Some(oid) = batch.last() else { continue };
|
|
||||||
let oid = oid.context("failed to get oid")?;
|
|
||||||
if oid != from {
|
|
||||||
oids.push(oid.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(oids)
|
|
||||||
}
|
|
@ -12,7 +12,6 @@ mod handler;
|
|||||||
pub use handler::Handler;
|
pub use handler::Handler;
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::time;
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use gitbutler_core::projects::ProjectId;
|
use gitbutler_core::projects::ProjectId;
|
||||||
@ -92,7 +91,7 @@ pub fn watch_in_background(
|
|||||||
// as well, so nothing can really be done here.
|
// as well, so nothing can really be done here.
|
||||||
task::spawn_blocking(move || {
|
task::spawn_blocking(move || {
|
||||||
futures::executor::block_on(async move {
|
futures::executor::block_on(async move {
|
||||||
handler.handle(event, time::SystemTime::now()).await.ok();
|
handler.handle(event).await.ok();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
use gitbutler_core::projects;
|
|
||||||
|
|
||||||
use crate::handler::support::Fixture;
|
|
||||||
use crate::handler::test_remote_repository;
|
|
||||||
use gitbutler_testsupport::Case;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn fetch_success() -> anyhow::Result<()> {
|
|
||||||
let mut fixture = Fixture::default();
|
|
||||||
{
|
|
||||||
let handler = fixture.new_handler();
|
|
||||||
let Case { project, .. } = &fixture.new_case();
|
|
||||||
let (cloud, _tmp) = test_remote_repository()?;
|
|
||||||
let api_project = projects::ApiProject {
|
|
||||||
name: "test-sync".to_string(),
|
|
||||||
description: None,
|
|
||||||
repository_id: "123".to_string(),
|
|
||||||
git_url: cloud.path().to_str().unwrap().to_string(),
|
|
||||||
code_git_url: None,
|
|
||||||
created_at: 0_i32.to_string(),
|
|
||||||
updated_at: 0_i32.to_string(),
|
|
||||||
sync: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
fixture
|
|
||||||
.projects
|
|
||||||
.update(&projects::UpdateRequest {
|
|
||||||
id: project.id,
|
|
||||||
api: Some(api_project.clone()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
handler
|
|
||||||
.fetch_gb_data(project.id, SystemTime::now())
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
assert_eq!(fixture.events().len(), 0);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn fetch_fail_no_sync() {
|
|
||||||
let mut fixture = Fixture::default();
|
|
||||||
{
|
|
||||||
let handler = fixture.new_handler();
|
|
||||||
let Case { project, .. } = &fixture.new_case();
|
|
||||||
let res = handler.fetch_gb_data(project.id, SystemTime::now()).await;
|
|
||||||
|
|
||||||
assert_eq!(&res.unwrap_err().to_string(), "sync disabled");
|
|
||||||
}
|
|
||||||
assert_eq!(fixture.events().len(), 0);
|
|
||||||
}
|
|
@ -1,5 +1,3 @@
|
|||||||
use tempfile::TempDir;
|
|
||||||
|
|
||||||
mod support {
|
mod support {
|
||||||
use gitbutler_core::{assets, deltas, git, sessions, virtual_branches};
|
use gitbutler_core::{assets, deltas, git, sessions, virtual_branches};
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
@ -87,15 +85,5 @@ mod support {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use gitbutler_testsupport::init_opts_bare;
|
|
||||||
|
|
||||||
fn test_remote_repository() -> anyhow::Result<(git2::Repository, TempDir)> {
|
|
||||||
let tmp = tempfile::tempdir()?;
|
|
||||||
let repo_a = git2::Repository::init_opts(&tmp, &init_opts_bare())?;
|
|
||||||
Ok((repo_a, tmp))
|
|
||||||
}
|
|
||||||
|
|
||||||
mod calculate_delta;
|
mod calculate_delta;
|
||||||
mod fetch_gitbutler_data;
|
|
||||||
mod git_file_change;
|
mod git_file_change;
|
||||||
mod push_project_to_gitbutler;
|
|
||||||
|
@ -1,383 +0,0 @@
|
|||||||
use std::{collections::HashMap, path::PathBuf};
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use gitbutler_core::{git, project_repository::LogUntil, projects};
|
|
||||||
|
|
||||||
use crate::handler::support::Fixture;
|
|
||||||
use crate::handler::test_remote_repository;
|
|
||||||
use gitbutler_testsupport::{virtual_branches::set_test_target, Case};
|
|
||||||
|
|
||||||
fn log_walk(repo: &git2::Repository, head: git::Oid) -> Vec<git::Oid> {
|
|
||||||
let mut walker = repo.revwalk().unwrap();
|
|
||||||
walker.push(head.into()).unwrap();
|
|
||||||
walker.map(|oid| oid.unwrap().into()).collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn push_error() -> Result<()> {
|
|
||||||
let mut fixture = Fixture::default();
|
|
||||||
let handler = fixture.new_handler();
|
|
||||||
let Case { project, .. } = &fixture.new_case();
|
|
||||||
|
|
||||||
let api_project = projects::ApiProject {
|
|
||||||
name: "test-sync".to_string(),
|
|
||||||
description: None,
|
|
||||||
repository_id: "123".to_string(),
|
|
||||||
git_url: String::new(),
|
|
||||||
code_git_url: Some(String::new()),
|
|
||||||
created_at: 0_i32.to_string(),
|
|
||||||
updated_at: 0_i32.to_string(),
|
|
||||||
sync: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
fixture
|
|
||||||
.projects
|
|
||||||
.update(&projects::UpdateRequest {
|
|
||||||
id: project.id,
|
|
||||||
api: Some(api_project.clone()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let res = handler.push_project_to_gitbutler(project.id, 100).await;
|
|
||||||
let err = res.unwrap_err();
|
|
||||||
assert_eq!(err.to_string(), "failed to get default target");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn push_simple() -> Result<()> {
|
|
||||||
let mut fixture = Fixture::default();
|
|
||||||
let handler = fixture.new_handler();
|
|
||||||
let Case {
|
|
||||||
project,
|
|
||||||
gb_repository,
|
|
||||||
project_repository,
|
|
||||||
..
|
|
||||||
} = &fixture.new_case_with_files(HashMap::from([(PathBuf::from("test.txt"), "test")]));
|
|
||||||
|
|
||||||
fixture.sign_in();
|
|
||||||
set_test_target(project_repository).unwrap();
|
|
||||||
|
|
||||||
let target_id = gb_repository.default_target().unwrap().unwrap().sha;
|
|
||||||
let reference = project_repository.l(target_id, LogUntil::End).unwrap();
|
|
||||||
let (cloud_code, _tmp) = test_remote_repository()?;
|
|
||||||
let api_project = projects::ApiProject {
|
|
||||||
name: "test-sync".to_string(),
|
|
||||||
description: None,
|
|
||||||
repository_id: "123".to_string(),
|
|
||||||
git_url: String::new(),
|
|
||||||
code_git_url: Some(cloud_code.path().to_str().unwrap().to_string()),
|
|
||||||
created_at: 0_i32.to_string(),
|
|
||||||
updated_at: 0_i32.to_string(),
|
|
||||||
sync: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
fixture
|
|
||||||
.projects
|
|
||||||
.update(&projects::UpdateRequest {
|
|
||||||
id: project.id,
|
|
||||||
api: Some(api_project.clone()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
cloud_code.find_commit(target_id.into()).unwrap_err();
|
|
||||||
|
|
||||||
{
|
|
||||||
handler
|
|
||||||
.push_project_to_gitbutler(project.id, 10)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
cloud_code.find_commit(target_id.into()).unwrap();
|
|
||||||
|
|
||||||
let pushed = log_walk(&cloud_code, target_id);
|
|
||||||
assert_eq!(reference.len(), pushed.len());
|
|
||||||
assert_eq!(reference, pushed);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
fixture
|
|
||||||
.projects
|
|
||||||
.get(&project.id)
|
|
||||||
.unwrap()
|
|
||||||
.gitbutler_code_push_state
|
|
||||||
.unwrap()
|
|
||||||
.id,
|
|
||||||
target_id
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn push_remote_ref() -> Result<()> {
|
|
||||||
let mut fixture = Fixture::default();
|
|
||||||
let handler = fixture.new_handler();
|
|
||||||
let Case {
|
|
||||||
project,
|
|
||||||
project_repository,
|
|
||||||
..
|
|
||||||
} = &fixture.new_case();
|
|
||||||
|
|
||||||
fixture.sign_in();
|
|
||||||
set_test_target(project_repository).unwrap();
|
|
||||||
|
|
||||||
let (cloud_code, _tmp) = test_remote_repository()?;
|
|
||||||
let cloud_code: git::Repository = cloud_code.into();
|
|
||||||
|
|
||||||
let (remote_repo, _tmp) = test_remote_repository()?;
|
|
||||||
let remote_repo: git::Repository = remote_repo.into();
|
|
||||||
|
|
||||||
let last_commit = create_initial_commit(&remote_repo);
|
|
||||||
|
|
||||||
remote_repo
|
|
||||||
.reference(
|
|
||||||
&git::Refname::Local(git::LocalRefname::new("refs/heads/testbranch", None)),
|
|
||||||
last_commit,
|
|
||||||
false,
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut remote = project_repository
|
|
||||||
.git_repository
|
|
||||||
.remote("tr", &remote_repo.path().to_str().unwrap().parse().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
remote
|
|
||||||
.fetch(&["+refs/heads/*:refs/remotes/tr/*"], None)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
project_repository
|
|
||||||
.git_repository
|
|
||||||
.find_commit(last_commit)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let api_project = projects::ApiProject {
|
|
||||||
name: "test-sync".to_string(),
|
|
||||||
description: None,
|
|
||||||
repository_id: "123".to_string(),
|
|
||||||
git_url: String::new(),
|
|
||||||
code_git_url: Some(cloud_code.path().to_str().unwrap().to_string()),
|
|
||||||
created_at: 0_i32.to_string(),
|
|
||||||
updated_at: 0_i32.to_string(),
|
|
||||||
sync: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
fixture
|
|
||||||
.projects
|
|
||||||
.update(&projects::UpdateRequest {
|
|
||||||
id: project.id,
|
|
||||||
api: Some(api_project.clone()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
{
|
|
||||||
handler
|
|
||||||
.push_project_to_gitbutler(project.id, 10)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
cloud_code.find_commit(last_commit).unwrap();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_initial_commit(repo: &git::Repository) -> git::Oid {
|
|
||||||
let signature = git::Signature::now("test", "test@email.com").unwrap();
|
|
||||||
|
|
||||||
let mut index = repo.index().unwrap();
|
|
||||||
let oid = index.write_tree().unwrap();
|
|
||||||
|
|
||||||
repo.commit(
|
|
||||||
None,
|
|
||||||
&signature,
|
|
||||||
&signature,
|
|
||||||
"initial commit",
|
|
||||||
&repo.find_tree(oid).unwrap(),
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_test_commits(repo: &git::Repository, commits: usize) -> git::Oid {
|
|
||||||
let signature = git::Signature::now("test", "test@email.com").unwrap();
|
|
||||||
|
|
||||||
let mut last = None;
|
|
||||||
|
|
||||||
for i in 0..commits {
|
|
||||||
let mut index = repo.index().unwrap();
|
|
||||||
let oid = index.write_tree().unwrap();
|
|
||||||
let head = repo.head().unwrap();
|
|
||||||
|
|
||||||
last = Some(
|
|
||||||
repo.commit(
|
|
||||||
Some(&head.name().unwrap()),
|
|
||||||
&signature,
|
|
||||||
&signature,
|
|
||||||
format!("commit {i}").as_str(),
|
|
||||||
&repo.find_tree(oid).unwrap(),
|
|
||||||
&[&repo
|
|
||||||
.find_commit(repo.refname_to_id("HEAD").unwrap())
|
|
||||||
.unwrap()],
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
last.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn push_batches() -> Result<()> {
|
|
||||||
let mut fixture = Fixture::default();
|
|
||||||
let handler = fixture.new_handler();
|
|
||||||
let Case {
|
|
||||||
project,
|
|
||||||
gb_repository,
|
|
||||||
project_repository,
|
|
||||||
..
|
|
||||||
} = &fixture.new_case();
|
|
||||||
|
|
||||||
fixture.sign_in();
|
|
||||||
|
|
||||||
{
|
|
||||||
let head: git::Oid = project_repository
|
|
||||||
.get_head()
|
|
||||||
.unwrap()
|
|
||||||
.peel_to_commit()
|
|
||||||
.unwrap()
|
|
||||||
.id();
|
|
||||||
|
|
||||||
let reference = project_repository.l(head, LogUntil::End).unwrap();
|
|
||||||
assert_eq!(reference.len(), 2);
|
|
||||||
|
|
||||||
let head = create_test_commits(&project_repository.git_repository, 10);
|
|
||||||
|
|
||||||
let reference = project_repository.l(head, LogUntil::End).unwrap();
|
|
||||||
assert_eq!(reference.len(), 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_test_target(project_repository).unwrap();
|
|
||||||
|
|
||||||
let target_id = gb_repository.default_target().unwrap().unwrap().sha;
|
|
||||||
let reference = project_repository.l(target_id, LogUntil::End).unwrap();
|
|
||||||
let (cloud_code, _tmp) = test_remote_repository()?;
|
|
||||||
|
|
||||||
let api_project = projects::ApiProject {
|
|
||||||
name: "test-sync".to_string(),
|
|
||||||
description: None,
|
|
||||||
repository_id: "123".to_string(),
|
|
||||||
git_url: String::new(),
|
|
||||||
code_git_url: Some(cloud_code.path().to_str().unwrap().to_string()),
|
|
||||||
created_at: 0_i32.to_string(),
|
|
||||||
updated_at: 0_i32.to_string(),
|
|
||||||
sync: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
fixture
|
|
||||||
.projects
|
|
||||||
.update(&projects::UpdateRequest {
|
|
||||||
id: project.id,
|
|
||||||
api: Some(api_project.clone()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
{
|
|
||||||
handler
|
|
||||||
.push_project_to_gitbutler(project.id, 2)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
cloud_code.find_commit(target_id.into()).unwrap();
|
|
||||||
|
|
||||||
let pushed = log_walk(&cloud_code, target_id);
|
|
||||||
assert_eq!(reference.len(), pushed.len());
|
|
||||||
assert_eq!(reference, pushed);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
fixture
|
|
||||||
.projects
|
|
||||||
.get(&project.id)
|
|
||||||
.unwrap()
|
|
||||||
.gitbutler_code_push_state
|
|
||||||
.unwrap()
|
|
||||||
.id,
|
|
||||||
target_id
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn push_again_no_change() -> Result<()> {
|
|
||||||
let mut fixture = Fixture::default();
|
|
||||||
let handler = fixture.new_handler();
|
|
||||||
let Case {
|
|
||||||
project,
|
|
||||||
gb_repository,
|
|
||||||
project_repository,
|
|
||||||
..
|
|
||||||
} = &fixture.new_case_with_files(HashMap::from([(PathBuf::from("test.txt"), "test")]));
|
|
||||||
|
|
||||||
fixture.sign_in();
|
|
||||||
|
|
||||||
set_test_target(project_repository).unwrap();
|
|
||||||
let target_id = gb_repository.default_target().unwrap().unwrap().sha;
|
|
||||||
let reference = project_repository.l(target_id, LogUntil::End).unwrap();
|
|
||||||
let (cloud_code, _tmp) = test_remote_repository()?;
|
|
||||||
|
|
||||||
let api_project = projects::ApiProject {
|
|
||||||
name: "test-sync".to_string(),
|
|
||||||
description: None,
|
|
||||||
repository_id: "123".to_string(),
|
|
||||||
git_url: String::new(),
|
|
||||||
code_git_url: Some(cloud_code.path().to_str().unwrap().to_string()),
|
|
||||||
created_at: 0_i32.to_string(),
|
|
||||||
updated_at: 0_i32.to_string(),
|
|
||||||
sync: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
fixture
|
|
||||||
.projects
|
|
||||||
.update(&projects::UpdateRequest {
|
|
||||||
id: project.id,
|
|
||||||
api: Some(api_project.clone()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
cloud_code.find_commit(target_id.into()).unwrap_err();
|
|
||||||
|
|
||||||
{
|
|
||||||
handler
|
|
||||||
.push_project_to_gitbutler(project.id, 10)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
cloud_code.find_commit(target_id.into()).unwrap();
|
|
||||||
|
|
||||||
let pushed = log_walk(&cloud_code, target_id);
|
|
||||||
assert_eq!(reference.len(), pushed.len());
|
|
||||||
assert_eq!(reference, pushed);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
fixture
|
|
||||||
.projects
|
|
||||||
.get(&project.id)
|
|
||||||
.unwrap()
|
|
||||||
.gitbutler_code_push_state
|
|
||||||
.unwrap()
|
|
||||||
.id,
|
|
||||||
target_id
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user