Skip to content

Commit

Permalink
Merge pull request #1289 from Barsik-sus/willbe_rollback_on_publish_fail
Browse files Browse the repository at this point in the history
READY: (willbe): Refactor commit operations and implement package version revert mecha…
  • Loading branch information
Wandalen committed May 6, 2024
2 parents f4e72d7 + 21104b9 commit 1867b48
Show file tree
Hide file tree
Showing 6 changed files with 322 additions and 10 deletions.
15 changes: 15 additions & 0 deletions module/move/willbe/src/entity/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,21 @@ pub( crate ) mod private

impl Manifest
{
/// Returns a mutable reference to the TOML document.
///
/// If the TOML document has not been loaded yet, this function will load it
/// by calling the `load` method. If loading fails, this function will panic.
///
/// # Returns
///
/// A mutable reference to the TOML document.
pub fn data( &mut self ) -> &mut toml_edit::Document
{
if self.manifest_data.is_none() { self.load().unwrap() }

self.manifest_data.as_mut().unwrap()
}

/// Returns path to `Cargo.toml`.
pub fn manifest_path( &self ) -> &AbsolutePath
{
Expand Down
47 changes: 38 additions & 9 deletions module/move/willbe/src/entity/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ mod private
use former::Former;
use workspace::WorkspacePackage;
use diff::crate_diff;
use version::version_revert;
use error_tools::for_app::Error;

///
Expand Down Expand Up @@ -302,15 +303,15 @@ mod private
pub commit : Option< process::Report >,
pub push : Option< process::Report >,
}

impl std::fmt::Display for ExtendedGitReport
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let Self { add, commit, push } = &self;
if let Some( add ) = add { writeln!( f, "{add}" )? }
if let Some( commit ) = commit { writeln!( f, "{commit}" )? }
if let Some( push ) = push { writeln!( f, "{push}" )? }

Ok( () )
}
}
Expand All @@ -324,7 +325,7 @@ mod private
pub dry : bool,
}

fn perform_git_operations( o : GitThingsOptions ) -> Result< ExtendedGitReport >
fn perform_git_commit( o : GitThingsOptions ) -> Result< ExtendedGitReport >
{
let mut report = ExtendedGitReport::default();
if o.items.is_empty() { return Ok( report ); }
Expand All @@ -341,8 +342,6 @@ mod private
report.add = Some( res );
let res = git::commit( &o.git_root, &o.message, o.dry ).map_err( | e | format_err!( "{report}\n{e}" ) )?;
report.commit = Some( res );
let res = git::push( &o.git_root, o.dry ).map_err( | e | format_err!( "{report}\n{e}" ) )?;
report.push = Some( res );

Ok( report )
}
Expand Down Expand Up @@ -452,12 +451,42 @@ mod private
report.get_info = Some( cargo::pack( pack ).map_err( | e | ( report.clone(), e ) )? );
// qqq : redundant field?
report.publish_required = true;
report.bump = Some( version::version_bump( version_bump ).map_err( | e | ( report.clone(), e ) )? );
let git = perform_git_operations( git_things ).map_err( | e | ( report.clone(), e ) )?;
let bump_report = version::version_bump( version_bump ).map_err( | e | ( report.clone(), e ) )?;
report.bump = Some( bump_report.clone() );
let git_root = git_things.git_root.clone();
let git = match perform_git_commit( git_things )
{
Ok( git ) => git,
Err( e ) =>
{
version_revert( &bump_report )
.map_err( | le |
(
report.clone(),
format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) )
))?;
return Err(( report, e ));
}
};
report.add = git.add;
report.commit = git.commit;
report.push = git.push;
report.publish = Some( cargo::publish( publish ).map_err( | e | ( report.clone(), e ) )? );
report.publish = match cargo::publish( publish )
{
Ok( publish ) => Some( publish ),
Err( e ) =>
{
git::reset( git_root.as_ref(), true, 1, false )
.map_err( | le |
(
report.clone(),
format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) )
))?;
return Err(( report, e ));
}
};

let res = git::push( &git_root, dry ).map_err( | e | ( report.clone(), e ) )?;
report.push = Some( res );

Ok( report )
}
Expand Down
67 changes: 67 additions & 0 deletions module/move/willbe/src/entity/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,71 @@ mod private

Ok( report )
}

/// Reverts the version of a package in the provided `ExtendedBumpReport`.
///
/// # Arguments
///
/// * `report` - The `ExtendedBumpReport` containing the bump information.
///
/// # Returns
///
/// Returns `Ok(())` if the version is reverted successfully. Returns `Err` with an error message if there is any issue with reverting the version.
pub fn version_revert( report : &ExtendedBumpReport ) -> Result< () >
{
let Some( name ) = report.name.as_ref() else { return Ok( () ) };
let Some( old_version ) = report.old_version.as_ref() else { return Ok( () ) };
let Some( new_version ) = report.new_version.as_ref() else { return Ok( () ) };

let dependencies = | item_maybe_with_dependencies : &mut toml_edit::Item |
{
if let Some( dependency ) = item_maybe_with_dependencies.get_mut( "dependencies" ).and_then( | ds | ds.get_mut( name ) )
{
if let Some( current_version ) = dependency.get( "version" ).and_then( | v | v.as_str() ).map( | v | v.to_string() )
{
let version = &mut dependency[ "version" ];
if let Some( current_version ) = current_version.strip_prefix( '~' )
{
if current_version != new_version { return Err( format_err!( "The current version of the package does not match the expected one. Expected: `{new_version}` Current: `{}`", version.as_str().unwrap_or_default() ) ); }
*version = value( format!( "~{}", old_version ) );
}
else
{
if version.as_str().unwrap() != new_version { return Err( format_err!( "The current version of the package does not match the expected one. Expected: `{new_version}` Current: `{}`", version.as_str().unwrap_or_default() ) ); }
*version = value( old_version.clone() );
}
}
}

Ok( () )
};

for path in &report.changed_files
{
let mut manifest = manifest::open( path.clone() )?;
let data = manifest.data();
if let Some( workspace ) = data.get_mut( "workspace" )
{
dependencies( workspace )?;
}
if let Some( package ) = data.get_mut( "package" )
{
if package.get_mut( "name" ).unwrap().as_str().unwrap() == name
{
let version = &mut package[ "version" ];
if version.as_str().unwrap() != new_version { return Err( format_err!( "The current version of the package does not match the expected one. Expected: `{new_version}` Current: `{}`", version.as_str().unwrap_or_default() ) ); }
*version = value( old_version.clone() );
}
else
{
dependencies( package )?;
}
}
manifest.store()?;
}

Ok( () )
}
}

//
Expand All @@ -321,4 +386,6 @@ crate::mod_interface!
protected use ExtendedBumpReport;
/// Bumps the version of a package and its dependencies.
protected use version_bump;
/// Reverts the version of a package.
protected use version_revert;
}
53 changes: 53 additions & 0 deletions module/move/willbe/src/tool/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,58 @@ mod private
.run().map_err( | report | err!( report.to_string() ) )
}
}

/// This function is a wrapper around the `git reset` command.
///
/// # Args :
///
/// - `path`: The path to the directory on which the `git reset` command will be executed.
/// - `hard`: A boolean indicating whether to perform a hard reset or not.
/// - `commits_count`: The number of commits to reset(at least 1).
/// - `dry`: A boolean indicating whether to execute the command in dry-run mode or not.
///
/// # Returns :
/// This function returns a `Result` containing a `Report` if the command is executed successfully. The `Report` contains the command executed, the output
// git reset command wrapper
pub fn reset< P >( path : P, hard : bool, commits_count : usize, dry : bool ) -> Result< Report >
where
P : AsRef< Path >,
{
if commits_count < 1 { return Err( err!( "Cannot reset, the count of commits must be greater than 0" ) ) }
let ( program, args ) =
(
"git",
Some( "reset" )
.into_iter()
.chain( if hard { Some( "--hard" ) } else { None } )
.map( String::from )
.chain( Some( format!( "HEAD~{}", commits_count ) ) )
.collect::< Vec< _ > >()
);

if dry
{
Ok
(
Report
{
command : format!( "{program} {}", args.join( " " ) ),
out : String::new(),
err : String::new(),
current_path : path.as_ref().to_path_buf(),
error : Ok( () ),
}
)
}
else
{
Run::former()
.bin_path( program )
.args( args.into_iter().map( OsString::from ).collect::< Vec< _ > >() )
.current_path( path.as_ref().to_path_buf() )
.run().map_err( | report | err!( report.to_string() ) )
}
}

/// Retrieves the remote URL of a Git repository.
///
Expand Down Expand Up @@ -169,5 +221,6 @@ crate::mod_interface!
protected use add;
protected use commit;
protected use push;
protected use reset;
protected use ls_remote_url;
}
1 change: 1 addition & 0 deletions module/move/willbe/src/tool/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ pub( crate ) mod private
.path( package.crate_dir().absolute_path().as_ref().to_path_buf() )
.option_temp_path( temp_path.clone() )
.dry( false )
.allow_dirty( true )
.form()
)?;
if publish_need( package, temp_path.clone() ).unwrap()
Expand Down
Loading

0 comments on commit 1867b48

Please sign in to comment.