refactor: move git operations into seperate files

This commit is contained in:
Sam Chau
2024-09-03 20:17:40 +09:30
parent 623f510ff9
commit ec7430466f
8 changed files with 208 additions and 120 deletions

View File

@@ -0,0 +1,16 @@
# git/operations/commit.py
import git
import logging
logger = logging.getLogger(__name__)
def commit_changes(repo_path, files, message):
try:
repo = git.Repo(repo_path)
repo.index.add(files)
repo.index.commit(message)
return True, "Successfully committed changes."
except Exception as e:
logger.error(f"Error committing changes: {str(e)}", exc_info=True)
return False, f"Error committing changes: {str(e)}"

View File

@@ -0,0 +1,20 @@
# git/operations/delete.py
import os
import logging
logger = logging.getLogger(__name__)
def delete_file(repo_path, file_path):
try:
full_file_path = os.path.join(repo_path, file_path)
if os.path.exists(full_file_path):
os.remove(full_file_path)
message = f"File {file_path} has been deleted."
return True, message
else:
return False, "File does not exist."
except Exception as e:
logger.error(f"Error deleting file: {str(e)}", exc_info=True)
return False, f"Error deleting file: {str(e)}"

View File

@@ -0,0 +1,34 @@
# git/operations/operations.py
import git
from .stage import stage_files
from .commit import commit_changes
from .push import push_changes
from .revert import revert_file, revert_all
from .delete import delete_file
from .pull import pull_branch
class GitOperations:
def __init__(self, repo_path):
self.repo_path = repo_path
def stage(self, files):
return stage_files(self.repo_path, files)
def commit(self, files, message):
return commit_changes(self.repo_path, files, message)
def push(self, files, message):
return push_changes(self.repo_path, files, message)
def revert(self, file_path):
return revert_file(self.repo_path, file_path)
def revert_all(self):
return revert_all(self.repo_path)
def delete(self, file_path):
return delete_file(self.repo_path, file_path)
def pull(self, branch_name):
return pull_branch(self.repo_path, branch_name)

View File

@@ -0,0 +1,15 @@
# git/operations/pull.py
import git
import logging
logger = logging.getLogger(__name__)
def pull_branch(repo_path, branch_name):
try:
repo = git.Repo(repo_path)
repo.git.pull('origin', branch_name)
return True, f"Successfully pulled changes for branch {branch_name}."
except Exception as e:
logger.error(f"Error pulling branch: {str(e)}", exc_info=True)
return False, f"Error pulling branch: {str(e)}"

View File

@@ -0,0 +1,18 @@
# git/operations/push.py
import git
import logging
from .commit import commit_changes
logger = logging.getLogger(__name__)
def push_changes(repo_path, files, message):
try:
repo = git.Repo(repo_path)
commit_changes(repo_path, files, message)
origin = repo.remote(name='origin')
origin.push()
return True, "Successfully pushed changes."
except Exception as e:
logger.error(f"Error pushing changes: {str(e)}", exc_info=True)
return False, f"Error pushing changes: {str(e)}"

View File

@@ -0,0 +1,36 @@
# git/operations/revert.py
import git
import logging
logger = logging.getLogger(__name__)
def revert_file(repo_path, file_path):
try:
repo = git.Repo(repo_path)
staged_deletions = repo.index.diff("HEAD", R=True)
is_staged_for_deletion = any(d.a_path == file_path for d in staged_deletions)
if is_staged_for_deletion:
repo.git.reset("--", file_path)
repo.git.checkout('HEAD', "--", file_path)
message = f"File {file_path} has been restored and unstaged from deletion."
else:
repo.git.restore("--", file_path)
repo.git.restore('--staged', "--", file_path)
message = f"File {file_path} has been reverted."
return True, message
except Exception as e:
logger.error(f"Error reverting file: {str(e)}", exc_info=True)
return False, f"Error reverting file: {str(e)}"
def revert_all(repo_path):
try:
repo = git.Repo(repo_path)
repo.git.restore('--staged', '.')
repo.git.restore('.')
return True, "All changes have been reverted to the last commit."
except Exception as e:
logger.error(f"Error reverting all changes: {str(e)}", exc_info=True)
return False, f"Error reverting all changes: {str(e)}"

View File

@@ -0,0 +1,20 @@
# git/operations/stage.py
import git
import logging
logger = logging.getLogger(__name__)
def stage_files(repo_path, files):
try:
repo = git.Repo(repo_path)
if not files:
repo.git.add(A=True)
message = "All changes have been staged."
else:
repo.index.add(files)
message = "Specified files have been staged."
return True, message
except Exception as e:
logger.error(f"Error staging files: {str(e)}", exc_info=True)
return False, f"Error staging files: {str(e)}"

View File

@@ -15,6 +15,7 @@ from .git.authenticate import validate_git_token
from .git.status.status import get_git_status
from .git.status.diff import get_diff
from .git.branches.branches import Branch_Manager
from .git.operations.operations import GitOperations
from .settings_utils import load_settings, save_settings
logging.basicConfig(level=logging.DEBUG)
@@ -35,6 +36,7 @@ class SettingsManager:
self.repo_url = self.settings.get('gitRepo') if self.settings else None
self.repo_path = DB_DIR
self.branch_manager = Branch_Manager(self.repo_path)
self.git_operations = GitOperations(self.repo_path)
def clone_repository(self):
return clone_repository(self.repo_url, self.repo_path, self.settings["gitToken"])
@@ -58,32 +60,22 @@ class SettingsManager:
return self.branch_manager.get_current()
def stage_files(self, files):
try:
repo = git.Repo(self.repo_path)
for file_path in files:
repo.index.add([file_path])
return True, "Successfully staged files."
except Exception as e:
logger.error(f"Error staging files: {str(e)}", exc_info=True)
return False, f"Error staging files: {str(e)}"
return self.git_operations.stage(files)
def push_files(self, files, commit_message):
try:
repo = git.Repo(self.repo_path)
# Stage the files
self.stage_files(files)
return self.git_operations.push(files, commit_message)
# Commit the staged files
repo.index.commit(commit_message)
def revert_file(self, file_path):
return self.git_operations.revert(file_path)
# Push the commit to the remote repository
origin = repo.remote(name='origin')
origin.push()
def revert_all(self):
return self.git_operations.revert_all()
return True, "Successfully committed and pushed files."
except Exception as e:
logger.error(f"Error pushing files: {str(e)}", exc_info=True)
return False, f"Error pushing files: {str(e)}"
def delete_file(self, file_path):
return self.git_operations.delete(file_path)
def pull_branch(self, branch_name):
return self.git_operations.pull(branch_name)
settings_manager = SettingsManager()
@@ -198,27 +190,16 @@ def get_current_branch():
else:
return jsonify({'success': False, 'error': 'Failed to get current branch'}), 400
@bp.route('/stage', methods=['POST'])
def stage_files():
files = request.json.get('files', [])
try:
repo = git.Repo(settings_manager.repo_path)
if not files: # If no files are specified, stage all changes
repo.git.add(A=True) # This adds all changes to staging, including deletions
message = "All changes have been staged."
else:
for file_path in files:
# Staging a deleted file requires just adding the file path.
repo.git.add(file_path)
message = "Specified files have been staged."
success, message = settings_manager.stage_files(files)
if success:
return jsonify({'success': True, 'message': message}), 200
except Exception as e:
logger.error(f"Error staging files: {str(e)}", exc_info=True)
return jsonify({'success': False, 'error': f"Error staging files: {str(e)}"}), 400
else:
logger.error(f"Error staging files: {message}")
return jsonify({'success': False, 'error': message}), 400
def generate_commit_message(user_message, files):
@@ -239,111 +220,59 @@ def push_files():
files = request.json.get('files', [])
user_commit_message = request.json.get('commit_message', "Commit and push staged files")
logger.debug(f"Received request to push files: {files}")
try:
repo = git.Repo(settings_manager.repo_path)
# Instead of restaging the files, we directly commit the staged changes
staged_files = repo.index.diff("HEAD") # Get the list of staged files
if not staged_files:
return jsonify({'success': False, 'error': "No staged changes to commit."}), 400
# Generate the structured commit message
commit_message = generate_commit_message(user_commit_message, files)
# Commit the staged changes
repo.index.commit(commit_message)
# Push the commit to the remote repository
origin = repo.remote(name='origin')
origin.push()
commit_message = generate_commit_message(user_commit_message, files)
success, message = settings_manager.push_files(files, commit_message)
if success:
logger.debug("Successfully committed and pushed files")
return jsonify({'success': True, 'message': "Successfully committed and pushed files."}), 200
except Exception as e:
logger.error(f"Error pushing files: {str(e)}", exc_info=True)
return jsonify({'success': False, 'error': f"Error pushing files: {str(e)}"}), 400
return jsonify({'success': True, 'message': message}), 200
else:
logger.error(f"Error pushing files: {message}")
return jsonify({'success': False, 'error': message}), 400
@bp.route('/revert', methods=['POST'])
def revert_file():
file_path = request.json.get('file_path')
if not file_path:
return jsonify({'success': False, 'error': "File path is required."}), 400
try:
repo = git.Repo(settings_manager.repo_path)
# Check if the file is staged for deletion
staged_deletions = repo.index.diff("HEAD", R=True)
is_staged_for_deletion = any(d.a_path == file_path for d in staged_deletions)
if is_staged_for_deletion:
# If the file is staged for deletion, we need to unstage it and restore it
repo.git.reset("--", file_path) # Unstage the deletion
repo.git.checkout('HEAD', "--", file_path) # Restore the file from HEAD
message = f"File {file_path} has been restored and unstaged from deletion."
else:
# For other changes, use the existing revert logic
repo.git.restore("--", file_path)
repo.git.restore('--staged', "--", file_path)
message = f"File {file_path} has been reverted."
success, message = settings_manager.revert_file(file_path)
if success:
return jsonify({'success': True, 'message': message}), 200
except Exception as e:
logger.error(f"Error reverting file: {str(e)}", exc_info=True)
return jsonify({'success': False, 'error': f"Error reverting file: {str(e)}"}), 400
else:
logger.error(f"Error reverting file: {message}")
return jsonify({'success': False, 'error': message}), 400
@bp.route('/revert-all', methods=['POST'])
def revert_all():
try:
repo = git.Repo(settings_manager.repo_path)
# Revert all files to the state of the last commit
repo.git.restore('--staged', '.')
repo.git.restore('.')
return jsonify({'success': True, 'message': "All changes have been reverted to the last commit."}), 200
except Exception as e:
logger.error(f"Error reverting all changes: {str(e)}", exc_info=True)
return jsonify({'success': False, 'error': f"Error reverting all changes: {str(e)}"}), 400
success, message = settings_manager.revert_all()
if success:
return jsonify({'success': True, 'message': message}), 200
else:
logger.error(f"Error reverting all changes: {message}")
return jsonify({'success': False, 'error': message}), 400
@bp.route('/file', methods=['DELETE'])
def delete_file():
file_path = request.json.get('file_path')
if not file_path:
return jsonify({'success': False, 'error': "File path is required."}), 400
try:
full_file_path = os.path.join(settings_manager.repo_path, file_path)
if os.path.exists(full_file_path):
os.remove(full_file_path)
message = f"File {file_path} has been deleted."
return jsonify({'success': True, 'message': message}), 200
else:
return jsonify({'success': False, 'error': "File does not exist."}), 404
except Exception as e:
logger.error(f"Error deleting file: {str(e)}", exc_info=True)
return jsonify({'success': False, 'error': f"Error deleting file: {str(e)}"}), 400
success, message = settings_manager.delete_file(file_path)
if success:
return jsonify({'success': True, 'message': message}), 200
else:
logger.error(f"Error deleting file: {message}")
return jsonify({'success': False, 'error': message}), 400
@bp.route('/pull', methods=['POST'])
def pull_branch():
branch_name = request.json.get('branch')
try:
repo = git.Repo(settings_manager.repo_path)
repo.git.pull('origin', branch_name)
return jsonify({'success': True, 'message': f'Successfully pulled changes for branch {branch_name}.'}), 200
except Exception as e:
logger.error(f"Error pulling branch: {str(e)}", exc_info=True)
return jsonify({'success': False, 'error': f"Error pulling branch: {str(e)}"}), 400
success, message = settings_manager.pull_branch(branch_name)
if success:
return jsonify({'success': True, 'message': message}), 200
else:
logger.error(f"Error pulling branch: {message}")
return jsonify({'success': False, 'error': message}), 400
@bp.route('/diff', methods=['POST'])
def diff_file():