Skip to content

Commit

Permalink
Branching: Rebase (#1225)
Browse files Browse the repository at this point in the history
* init

* remove redundant check

* rename and list

* remove quotes from branch list

* remove unused code

* cleanup some code

* remove database prompt

* sanitize new branch name, handle drop case

* remove rebase and merge for now

* generic parameter names

* fix create

* rebase

* don't assume source branch is up to date

* add --force to drop & rename

* missing brackets

* missing space too :D

* fix borrow for --force on drop

* working rebase

* quote source_branch

* quote old_name & new_name in rename

* fixes

* rustfmt

* clippy

* rustfmt

* fix the config settings tests

* unify ConnectionOptions database and branch reading

* Add a few docs and a minor hint update

* debug

* remove edgedb.auto.toml

* update to non-edgedb.auto.toml

* fix cleanup of temp branch

* remove unused import

---------

Co-authored-by: Aljaž Mur Eržen <[email protected]>
  • Loading branch information
quinchs and aljazerzen authored Mar 5, 2024
1 parent 9dd2217 commit 73e34e6
Show file tree
Hide file tree
Showing 13 changed files with 382 additions and 8 deletions.
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ members = [
[package]
name = "edgedb-cli"
license = "MIT/Apache-2.0"
version = "4.2.0-dev"
version = "4.2.1-dev"
authors = ["EdgeDB Inc. <[email protected]>"]
edition = "2018"

Expand Down Expand Up @@ -48,7 +48,7 @@ serde_path_to_error = "0.1.3"
serde_str = {git="https://github.com/tailhook/serde-str"}
serde_millis = "0.1.1"
dirs = "4"
uuid = {version="1.1.2", features=["serde"]}
uuid = {version="1.1.2", features=["serde", "v4", "fast-rng"]}
prettytable-rs = {version="0.10.0", default-features=false}
tempfile = "3.1.0"
codespan-reporting = "0.11"
Expand Down
70 changes: 70 additions & 0 deletions src/branch/connections.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::ops::Deref;
use uuid::Uuid;
use crate::connect::Connection;
use crate::options::Options;
use crate::print;

pub struct BranchConnection<'a> {
pub connection: Connection,
branch_name: String,
is_temp: bool,
options: &'a Options
}

impl BranchConnection<'_> {
pub async fn clean(self) -> anyhow::Result<()> {
if self.is_temp {
let mut branch = get_connection_that_is_not(
&self.branch_name,
self.options,
&mut self.options.create_connector().await?.connect().await?
).await?;

print::completion(branch.connection.execute(&format!("drop branch {} force", self.branch_name), &()).await?);

// should never happen, but just to make sure
if branch.is_temp {
anyhow::bail!("Cannot create a temp branch to remove a temp branch");
}
}

Ok(())
}
}


pub async fn get_connection_to_modify<'a>(branch: &String, options: &'a Options, connection: &mut Connection) -> anyhow::Result<BranchConnection<'a>> {
match get_connection_that_is_not(branch, options, connection).await {
Ok(connection) => Ok(connection),
Err(_) => {
let temp_name = Uuid::new_v4().to_string();
connection.execute(&format!("create empty branch {}", temp_name), &()).await?;
Ok(BranchConnection {
connection: options.create_connector().await?.database(&temp_name)?.connect().await?,
options,
branch_name: temp_name,
is_temp: true
})
}
}
}

pub async fn get_connection_that_is_not<'a>(target_branch: &String, options: &'a Options, connection: &mut Connection) -> anyhow::Result<BranchConnection<'a>> {
let branches: Vec<String> = connection.query(
"SELECT (SELECT sys::Database FILTER NOT .builtin).name",
&(),
).await?;

for branch in &branches {
if branch != target_branch {
return Ok(BranchConnection {
connection: options.create_connector().await?.database(branch)?.connect().await?,
branch_name: branch.deref().to_string(),
is_temp: false,
options
})
}
}

anyhow::bail!("Cannot find other branches to use");
}
3 changes: 2 additions & 1 deletion src/branch/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::branch::context::Context;
use crate::branch::option::{BranchCommand, Command};
use crate::branch::{create, drop, list, rename, switch, wipe};
use crate::branch::{create, drop, list, rebase, rename, switch, wipe};
use crate::connect::Connection;
use crate::options::Options;

Expand All @@ -20,6 +20,7 @@ pub async fn branch_main(options: &Options, cmd: &BranchCommand) -> anyhow::Resu
Command::Wipe(wipe) => wipe::main(wipe, &context, &mut connection).await,
Command::List(list) => list::main(list, &context, &mut connection).await,
Command::Rename(rename) => rename::main(rename, &context, &mut connection).await,
Command::Rebase(rebase) => rebase::main(rebase, &context, &mut connection, &options).await,
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/branch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ mod context;
mod create;
mod drop;
mod list;
mod rebase;
mod connections;
pub mod main;
pub mod option;
mod rename;
Expand Down
6 changes: 6 additions & 0 deletions src/branch/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub enum Command {
Switch(Switch),
Rename(Rename),
List(List),
Rebase(Rebase)
}

#[derive(clap::Args, Debug, Clone)]
Expand Down Expand Up @@ -62,3 +63,8 @@ pub struct Rename {
}
#[derive(clap::Args, Debug, Clone)]
pub struct List {}

#[derive(clap::Args, Debug, Clone)]
pub struct Rebase {
pub target_branch: String
}
73 changes: 73 additions & 0 deletions src/branch/rebase.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use colorful::Colorful;
use uuid::Uuid;
use crate::branch::context::Context;
use crate::branch::option::Rebase;
use crate::connect::Connection;
use crate::migrations::branch::{do_rebase, get_diverging_migrations};
use crate::options::Options;
use crate::{migrations, print};
use crate::branch::connections::get_connection_to_modify;

pub async fn main(options: &Rebase, context: &Context, connection: &mut Connection, cli_opts: &Options) -> anyhow::Result<()> {
let temp_branch = clone_target_branch(&options.target_branch, connection).await?;

let mut temp_branch_connection = cli_opts.create_connector().await?.database(&temp_branch)?.connect().await?;

match rebase(&temp_branch, &mut temp_branch_connection, connection, context, cli_opts).await {
Err(e) => {
print::error(e);

let mut rename_connection = get_connection_to_modify(&temp_branch, cli_opts, connection).await?;
let result = rename_connection.connection.execute(&format!("drop branch {} force", edgeql_parser::helpers::quote_name(&temp_branch)), &()).await?;

print::completion(result);

rename_connection.clean().await
}
Ok(_) => anyhow::Ok(())
}
}

async fn rebase(branch: &String, source_connection: &mut Connection, target_connection: &mut Connection, context: &Context, cli_opts: &Options) -> anyhow::Result<()> {
let migrations = get_diverging_migrations(source_connection, target_connection).await?;

let migration_context = migrations::Context::for_project(&context.project_config)?;
do_rebase(source_connection, &migration_context, migrations).await?;

// drop old feature branch
let status = source_connection.execute(&format!("drop branch {} force", edgeql_parser::helpers::quote_name(&context.branch)), &()).await?;

print::completion(status);

// rename temp branch to feature
eprintln!("Recreating branch {}...", &context.branch.clone().light_gray());
rename_temp_to_feature(branch, &context.branch, cli_opts, source_connection).await?;

anyhow::Ok(())
}

async fn rename_temp_to_feature(temp_branch: &String, feature_branch: &String, options: &Options, connection: &mut Connection) -> anyhow::Result<()> {
let mut rename_connection = get_connection_to_modify(&temp_branch, options, connection).await?;

let status = rename_connection.connection.execute(&format!(
"alter branch {} force rename to {}",
edgeql_parser::helpers::quote_name(&temp_branch),
edgeql_parser::helpers::quote_name(&feature_branch)
), &()).await?;

print::completion(status);

rename_connection.clean().await?;

Ok(())
}

async fn clone_target_branch(branch: &String, connection: &mut Connection) -> anyhow::Result<String> {
let temp_branch_name = Uuid::new_v4().to_string();

let status = connection.execute(&format!("create data branch {} from {}", edgeql_parser::helpers::quote_name(&temp_branch_name), edgeql_parser::helpers::quote_name(branch)), &()).await?;

print::completion(status);

Ok(temp_branch_name)
}
2 changes: 2 additions & 0 deletions src/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use fs_err as fs;

use edgedb_tokio::Config;
use edgedb_tokio::credentials::Credentials;
use serde::Deserialize;
use serde_json::Deserializer;

use crate::platform::{config_dir, tmp_file_name};
use crate::question;
Expand Down
Loading

0 comments on commit 73e34e6

Please sign in to comment.