Skip to content

Commit

Permalink
Add squash command
Browse files Browse the repository at this point in the history
  • Loading branch information
rfst committed Jan 15, 2024
1 parent a6ff64a commit 98d9386
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/mobt/Controllers/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from mobt.Controllers.next import next
from mobt.Controllers.start import start
from mobt.Controllers.wip_commit import wip_commit
from mobt.Controllers.squash import squash


@click.group()
Expand Down Expand Up @@ -47,3 +48,4 @@ def cli(verbose, silent):
cli.add_command(next, 'next')
cli.add_command(done, 'done')
cli.add_command(wip_commit, 'commit')
cli.add_command(squash, 'squash')
39 changes: 39 additions & 0 deletions src/mobt/Controllers/squash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import click

from mobt import echo
from mobt.GitCli.BranchName import BranchName


@click.command()
@click.argument('branch_name', required=False)
@click.option(
'--push',
'-p',
help='Push the squashed commit to the remote [Will force push].',
)
@click.option(
'--message',
'-m',
help='Optional. Message used for the last commit.',
)
@click.option(
'--do-not-try-to-rebase',
'-R',
is_flag=True,
help='Rebase all changes after squashing. If the rebase fails, the mob will be ended as usual, but the rebase '
'will be aborted.',
)
@click.pass_context
def squash(ctx, branch_name: BranchName = None, push: bool = False, message: str = None, do_not_try_to_rebase: bool = False) -> None:
"""
Squash all the commits.
All git hooks will be executed for this final commit.
Before squashing, it will try to rebase the changes on top of the main branch. This behavior
can be changed with the `--do-not-try-to-rebase` option.
"""
from mobt.di import di
from mobt.MobApp.SquashBranch import SquashBranch
di.get(SquashBranch).squash(branch_name=branch_name, message=message, do_not_try_to_rebase=do_not_try_to_rebase, push=push)

echo(f'Done!', fg='green')
68 changes: 68 additions & 0 deletions src/mobt/MobApp/SquashBranch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import logging
from dataclasses import dataclass
from typing import Optional

from git import GitError
from injector import inject

from mobt.EventSystem.EventManager import EventManager
from mobt.GitCli.BranchName import BranchName
from mobt.GitCli.Exceptions import WorkingDirectoryNotClean
from mobt.GitCli.GitCliWithAutoRollback import GitCliWithAutoRollback
from mobt.MobApp.Exceptions import CurrentBranchIsNotMobBranch, HeadIsDetached
from mobt.MobApp.MobAppRelevantOperationHappened import MobAppRelevantOperationHappened
from mobt.MobException import MobException
from mobt.SessionSettings.Exceptions import SessionSettingsNotFound
from mobt.SessionSettings.SessionSettingsService import SessionSettingsService


@inject
@dataclass
class SquashBranch:
git: GitCliWithAutoRollback
event_manager: EventManager
session_settings_services: SessionSettingsService

def squash(self, branch_name: Optional[BranchName], message: str = None, do_not_try_to_rebase: bool = False, push: bool = False):
if not branch_name:
branch_name = self.git.current_branch()
if not branch_name:
raise HeadIsDetached.create()

try:
self.git.fetch_all()

if branch_name != self.git.current_branch():
try:
self.git.fail_if_dirty()
except WorkingDirectoryNotClean as e:
self.event_manager.dispatch_event(
MobAppRelevantOperationHappened(
human_log=f"Can't checkout {branch_name} because working directory is dirty.",
level=logging.ERROR,
)
)
raise e

self.git.checkout(branch_name)

self.git.pull_with_rebase()
self.git.commit_all('WIP: Mob squash! Session file deleted.', skip_hooks=True)
self.git.squash_all(message or 'Mob Squash all and execute hooks.', skip_hooks=False)
if not do_not_try_to_rebase:
try:
self.git.with_manual_roll_back().rebase(log_undoing_git_commands_title=False)
except GitError:
human_log = f" > Can't auto-rebase back on top of main branch. You should do it manually."

self.event_manager.dispatch_event(
MobAppRelevantOperationHappened(human_log=human_log, level=logging.WARNING)
)

if push:
self.git.push(force=True)
except Exception as e:
self.git.undo()
if isinstance(e, GitError):
e = MobException(str(e))
raise e

0 comments on commit 98d9386

Please sign in to comment.