diff --git a/backend/app/__init__.py b/backend/app/__init__.py index f09ae5b..47b5ce4 100644 --- a/backend/app/__init__.py +++ b/backend/app/__init__.py @@ -4,7 +4,7 @@ from .regex import bp as regex_bp from .format import bp as format_bp from .settings import bp as settings_bp from .profile import bp as profile_bp -from .git.unlink_repo import repo_bp +from .git import bp as git_bp import os REGEX_DIR = os.path.join('data', 'db', 'regex_patterns') @@ -14,17 +14,17 @@ PROFILE_DIR = os.path.join('data', 'db', 'profiles') def create_app(): app = Flask(__name__) CORS(app, resources={r"/*": {"origins": "*"}}) - + # Initialize directories to avoid issues with non-existing directories initialize_directories() - + # Register Blueprints app.register_blueprint(regex_bp) app.register_blueprint(format_bp) app.register_blueprint(settings_bp) app.register_blueprint(profile_bp) - app.register_blueprint(repo_bp) - + app.register_blueprint(git_bp) + return app def initialize_directories(): diff --git a/backend/app/format.py b/backend/app/format.py index 5a4c9b7..6efad9a 100644 --- a/backend/app/format.py +++ b/backend/app/format.py @@ -39,8 +39,10 @@ def handle_format(id): saved_data = save_format(data) return jsonify(saved_data) elif request.method == 'DELETE': + logger.info("Received request to delete format with ID: %d", id) result = delete_format(id) if "error" in result: + logger.error("Error deleting format: %s", result['error']) return jsonify(result), 400 return jsonify(result), 200 diff --git a/backend/app/git/__init__.py b/backend/app/git/__init__.py new file mode 100644 index 0000000..d787683 --- /dev/null +++ b/backend/app/git/__init__.py @@ -0,0 +1,172 @@ +from flask import Blueprint, request, jsonify +from .status.status import get_git_status +from .status.diff import get_diff +from .branches.branches import Branch_Manager +from .operations.operations import GitOperations +from .unlink_repo import unlink_repository +import logging + +logger = logging.getLogger(__name__) + +bp = Blueprint('git', __name__, url_prefix='/git') + +# Assume these are set up elsewhere, perhaps in a config file +REPO_PATH = '/app/data/db' +branch_manager = Branch_Manager(REPO_PATH) +git_operations = GitOperations(REPO_PATH) + +@bp.route('/status', methods=['GET']) +def get_status(): + logger.debug("Received request for git status") + success, message = get_git_status(REPO_PATH) + if success: + logger.debug("Successfully retrieved git status") + return jsonify({'success': True, 'data': message}), 200 + else: + logger.error(f"Failed to retrieve git status: {message}") + return jsonify({'success': False, 'error': message}), 400 + +@bp.route('/branch', methods=['POST']) +def create_branch(): + branch_name = request.json.get('name') + base_branch = request.json.get('base', 'main') + logger.debug(f"Received request to create branch {branch_name} from {base_branch}") + success, result = branch_manager.create(branch_name, base_branch) + if success: + logger.debug(f"Successfully created branch: {branch_name}") + return jsonify({'success': True, **result}), 200 + else: + logger.error(f"Failed to create branch: {result}") + return jsonify({'success': False, 'error': result}), 400 + +@bp.route('/branches', methods=['GET']) +def get_branches(): + logger.debug("Received request for branches") + success, result = branch_manager.get_all() + if success: + logger.debug("Successfully retrieved branches") + return jsonify({'success': True, 'data': result}), 200 + else: + logger.error(f"Failed to retrieve branches: {result}") + return jsonify({'success': False, 'error': result}), 400 + +@bp.route('/checkout', methods=['POST']) +def checkout_branch(): + branch_name = request.json.get('branch') + logger.debug(f"Received request to checkout branch: {branch_name}") + success, result = branch_manager.checkout(branch_name) + if success: + logger.debug(f"Successfully checked out branch: {branch_name}") + return jsonify({'success': True, **result}), 200 + else: + logger.error(f"Failed to checkout branch: {result}") + return jsonify({'success': False, 'error': result}), 400 + +@bp.route('/branch/', methods=['DELETE']) +def delete_branch(branch_name): + logger.debug(f"Received request to delete branch: {branch_name}") + success, result = branch_manager.delete(branch_name) + if success: + logger.debug(f"Successfully deleted branch: {branch_name}") + return jsonify({'success': True, **result}), 200 + else: + logger.error(f"Failed to delete branch: {result}") + return jsonify({'success': False, 'error': result}), 400 + +@bp.route('/push', methods=['POST']) +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}") + commit_message = generate_commit_message(user_commit_message, files) + success, message = git_operations.push(files, commit_message) + if success: + logger.debug("Successfully committed and pushed files") + 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 + success, message = git_operations.revert(file_path) + if success: + return jsonify({'success': True, 'message': message}), 200 + else: + logger.error(f"Error reverting file: {message}") + return jsonify({'success': False, 'error': message}), 400 + +@bp.route('/revert-all', methods=['POST']) +def revert_all(): + success, message = git_operations.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 + success, message = git_operations.delete(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') + success, message = git_operations.pull(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(): + file_path = request.json.get('file_path') + try: + diff = get_diff(REPO_PATH, file_path) + logger.debug(f"Diff for file {file_path}: {diff}") + return jsonify({'success': True, 'diff': diff if diff else ""}), 200 + except Exception as e: + logger.error(f"Error getting diff for file {file_path}: {str(e)}", exc_info=True) + return jsonify({'success': False, 'error': f"Error getting diff for file: {str(e)}"}), 400 + +@bp.route('/stage', methods=['POST']) +def handle_stage_files(): + files = request.json.get('files', []) + success, message = git_operations.stage(files) + if success: + return jsonify({'success': True, 'message': message}), 200 + else: + return jsonify({'success': False, 'error': message}), 400 + +@bp.route('/unlink', methods=['POST']) +def unlink_repo(): + success, message = unlink_repository(REPO_PATH) + if success: + return jsonify({'success': True, 'message': message}), 200 + else: + return jsonify({'success': False, 'error': message}), 400 + +def generate_commit_message(user_message, files): + file_changes = [] + for file in files: + if 'regex_patterns' in file: + file_changes.append(f"Update regex pattern: {file.split('/')[-1]}") + elif 'custom_formats' in file: + file_changes.append(f"Update custom format: {file.split('/')[-1]}") + else: + file_changes.append(f"Update: {file}") + + commit_message = f"{user_message}\n\nChanges:\n" + "\n".join(file_changes) + return commit_message \ No newline at end of file diff --git a/backend/app/git/branches/get.py b/backend/app/git/branches/get.py index 7497a1f..8d8a130 100644 --- a/backend/app/git/branches/get.py +++ b/backend/app/git/branches/get.py @@ -2,6 +2,7 @@ import git import logging +from flask import Blueprint, jsonify logger = logging.getLogger(__name__) diff --git a/backend/app/git/unlink_repo.py b/backend/app/git/unlink_repo.py index 8481aea..ab0d025 100644 --- a/backend/app/git/unlink_repo.py +++ b/backend/app/git/unlink_repo.py @@ -24,12 +24,4 @@ def unlink_repository(settings_manager): return True, "Repository successfully unlinked" except Exception as e: logger.error(f"Error unlinking repository: {str(e)}", exc_info=True) - return False, f"Error unlinking repository: {str(e)}" - -@repo_bp.route('/unlink', methods=['POST']) -def unlink_repo(): - success, message = unlink_repository(repo_bp.settings_manager) - if success: - return jsonify({'success': True, 'message': message}), 200 - else: - return jsonify({'success': False, 'error': message}), 400 \ No newline at end of file + return False, f"Error unlinking repository: {str(e)}" \ No newline at end of file diff --git a/backend/app/settings.py b/backend/app/settings.py index bbfac2b..ec9f0fe 100644 --- a/backend/app/settings.py +++ b/backend/app/settings.py @@ -2,20 +2,9 @@ import os import yaml import git from flask import Blueprint, request, jsonify -from git.exc import GitCommandError, InvalidGitRepositoryError -import shutil -import subprocess import logging -from datetime import datetime -import json -import requests -from .git.unlink_repo import repo_bp, unlink_repository from .git.clone_repo import clone_repository 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,51 +24,12 @@ class SettingsManager: self.settings = load_settings() 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"]) - - def get_git_status(self): - return get_git_status(self.repo_path) - - def get_branches(self): - return self.branch_manager.get_all() - - def create_branch(self, branch_name, base_branch='main'): - return self.branch_manager.create(branch_name, base_branch) - - def checkout_branch(self, branch_name): - return self.branch_manager.checkout(branch_name) - - def delete_branch(self, branch_name): - return self.branch_manager.delete(branch_name) - - def get_current_branch(self): - return self.branch_manager.get_current() - - def stage_files(self, files): - return self.git_operations.stage(files) - - def push_files(self, files, commit_message): - return self.git_operations.push(files, commit_message) - - def revert_file(self, file_path): - return self.git_operations.revert(file_path) - - def revert_all(self): - return self.git_operations.revert_all() - - 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() -repo_bp.settings_manager = settings_manager @bp.route('', methods=['GET']) def handle_settings(): @@ -121,166 +71,4 @@ def update_settings(): return jsonify({"error": message}), 400 except Exception as e: logger.exception("Unexpected error in update_settings") - return jsonify({"error": f"Failed to update settings: {str(e)}"}), 500 - -@bp.route('/status', methods=['GET']) -def get_status(): - logger.debug("Received request for git status") - success, message = settings_manager.get_git_status() - if success: - logger.debug("Successfully retrieved git status") - return jsonify({'success': True, 'data': message}), 200 - else: - logger.error(f"Failed to retrieve git status: {message}") - return jsonify({'success': False, 'error': message}), 400 - -# Update the route handlers -@bp.route('/branch', methods=['POST']) -def create_branch(): - branch_name = request.json.get('name') - base_branch = request.json.get('base', 'main') - logger.debug(f"Received request to create branch {branch_name} from {base_branch}") - success, result = settings_manager.create_branch(branch_name, base_branch) - if success: - logger.debug(f"Successfully created branch: {branch_name}") - return jsonify({'success': True, **result}), 200 - else: - logger.error(f"Failed to create branch: {result}") - return jsonify({'success': False, 'error': result}), 400 - -@bp.route('/branches', methods=['GET']) -def get_branches(): - logger.debug("Received request for branches") - success, result = settings_manager.get_branches() - if success: - logger.debug("Successfully retrieved branches") - return jsonify({'success': True, 'data': result}), 200 - else: - logger.error(f"Failed to retrieve branches: {result}") - return jsonify({'success': False, 'error': result}), 400 - -@bp.route('/checkout', methods=['POST']) -def checkout_branch(): - branch_name = request.json.get('branch') - logger.debug(f"Received request to checkout branch: {branch_name}") - success, result = settings_manager.checkout_branch(branch_name) - if success: - logger.debug(f"Successfully checked out branch: {branch_name}") - return jsonify({'success': True, **result}), 200 - else: - logger.error(f"Failed to checkout branch: {result}") - return jsonify({'success': False, 'error': result}), 400 - -@bp.route('/branch/', methods=['DELETE']) -def delete_branch(branch_name): - logger.debug(f"Received request to delete branch: {branch_name}") - success, result = settings_manager.delete_branch(branch_name) - if success: - logger.debug(f"Successfully deleted branch: {branch_name}") - return jsonify({'success': True, **result}), 200 - else: - logger.error(f"Failed to delete branch: {result}") - return jsonify({'success': False, 'error': result}), 400 - -@bp.route('/current-branch', methods=['GET']) -def get_current_branch(): - current_branch = settings_manager.get_current_branch() - if current_branch: - return jsonify({'success': True, 'current_branch': current_branch}), 200 - 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', []) - success, message = settings_manager.stage_files(files) - if success: - return jsonify({'success': True, 'message': message}), 200 - else: - logger.error(f"Error staging files: {message}") - return jsonify({'success': False, 'error': message}), 400 - - -def generate_commit_message(user_message, files): - file_changes = [] - for file in files: - if 'regex_patterns' in file: - file_changes.append(f"Update regex pattern: {file.split('/')[-1]}") - elif 'custom_formats' in file: - file_changes.append(f"Update custom format: {file.split('/')[-1]}") - else: - file_changes.append(f"Update: {file}") - - commit_message = f"{user_message}\n\nChanges:\n" + "\n".join(file_changes) - return commit_message - -@bp.route('/push', methods=['POST']) -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}") - 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': 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 - success, message = settings_manager.revert_file(file_path) - if success: - return jsonify({'success': True, 'message': message}), 200 - else: - logger.error(f"Error reverting file: {message}") - return jsonify({'success': False, 'error': message}), 400 - - -@bp.route('/revert-all', methods=['POST']) -def revert_all(): - 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 - 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') - 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(): - file_path = request.json.get('file_path') - try: - diff = get_diff(settings_manager.repo_path, file_path) - logger.debug(f"Diff for file {file_path}: {diff}") - return jsonify({'success': True, 'diff': diff if diff else ""}), 200 - except Exception as e: - logger.error(f"Error getting diff for file {file_path}: {str(e)}", exc_info=True) - return jsonify({'success': False, 'error': f"Error getting diff for file: {str(e)}"}), 400 + return jsonify({"error": f"Failed to update settings: {str(e)}"}), 500 \ No newline at end of file diff --git a/frontend/src/api/api.js b/frontend/src/api/api.js index aef7bca..47b2ebb 100644 --- a/frontend/src/api/api.js +++ b/frontend/src/api/api.js @@ -122,7 +122,7 @@ export const saveSettings = async (settings) => { export const getGitStatus = async () => { try { - const response = await axios.get(`${API_BASE_URL}/settings/status`); + const response = await axios.get(`${API_BASE_URL}/git/status`); return response.data; } catch (error) { console.error('Error fetching Git status:', error); @@ -132,7 +132,7 @@ export const getGitStatus = async () => { export const getBranches = async () => { try { - const response = await axios.get(`${API_BASE_URL}/settings/branches`); + const response = await axios.get(`${API_BASE_URL}/git/branches`); return response.data; } catch (error) { console.error('Error fetching branches:', error); @@ -142,7 +142,7 @@ export const getBranches = async () => { export const checkoutBranch = async (branchName) => { try { - const response = await axios.post(`${API_BASE_URL}/settings/checkout`, { branch: branchName }); + const response = await axios.post(`${API_BASE_URL}/git/checkout`, { branch: branchName }); return response.data; } catch (error) { console.error('Error checking out branch:', error); @@ -152,7 +152,7 @@ export const checkoutBranch = async (branchName) => { export const createBranch = async (branchName, baseBranch) => { try { - const response = await axios.post(`${API_BASE_URL}/settings/branch`, { name: branchName, base: baseBranch }); + const response = await axios.post(`${API_BASE_URL}/git/branch`, { name: branchName, base: baseBranch }); return response.data; } catch (error) { console.error('Error creating branch:', error); @@ -162,7 +162,7 @@ export const createBranch = async (branchName, baseBranch) => { export const deleteBranch = async (branchName) => { try { - const response = await axios.delete(`${API_BASE_URL}/settings/branch/${branchName}`); + const response = await axios.delete(`${API_BASE_URL}/git/branch/${branchName}`); return response.data; } catch (error) { console.error('Error deleting branch:', error); @@ -172,7 +172,7 @@ export const deleteBranch = async (branchName) => { export const addFiles = async (files) => { try { - const response = await axios.post(`${API_BASE_URL}/settings/stage`, { files }); + const response = await axios.post(`${API_BASE_URL}/git/stage`, { files }); return response.data; } catch (error) { console.error('Error staging files:', error); @@ -182,7 +182,7 @@ export const addFiles = async (files) => { export const pushFiles = async (files, commitMessage) => { try { - const response = await axios.post(`${API_BASE_URL}/settings/push`, { + const response = await axios.post(`${API_BASE_URL}/git/push`, { files, commit_message: commitMessage }); @@ -195,10 +195,9 @@ export const pushFiles = async (files, commitMessage) => { export const revertFile = async (filePath) => { try { - const response = await axios.post(`${API_BASE_URL}/settings/revert`, { + const response = await axios.post(`${API_BASE_URL}/git/revert`, { file_path: filePath }); - return response.data; } catch (error) { console.error('Error reverting file:', error); @@ -208,8 +207,7 @@ export const revertFile = async (filePath) => { export const revertAll = async () => { try { - const response = await axios.post(`${API_BASE_URL}/settings/revert-all`); - + const response = await axios.post(`${API_BASE_URL}/git/revert-all`); return response.data; } catch (error) { console.error('Error reverting all changes:', error); @@ -219,7 +217,7 @@ export const revertAll = async () => { export const deleteFile = async (filePath) => { try { - const response = await axios.delete(`${API_BASE_URL}/settings/file`, { + const response = await axios.delete(`${API_BASE_URL}/git/file`, { data: { file_path: filePath }, }); return response.data; @@ -231,7 +229,7 @@ export const deleteFile = async (filePath) => { export const pullBranch = async (branchName) => { try { - const response = await axios.post(`${API_BASE_URL}/settings/pull`, { branch: branchName }); + const response = await axios.post(`${API_BASE_URL}/git/pull`, { branch: branchName }); return response.data; } catch (error) { console.error('Error pulling branch:', error); @@ -241,7 +239,7 @@ export const pullBranch = async (branchName) => { export const getDiff = async (filePath) => { try { - const response = await axios.post(`${API_BASE_URL}/settings/diff`, { file_path: filePath }); + const response = await axios.post(`${API_BASE_URL}/git/diff`, { file_path: filePath }); return response.data; } catch (error) { console.error('Error fetching diff:', error); @@ -291,7 +289,7 @@ export const deleteProfile = async (id) => { export const unlinkRepo = async () => { try { - const response = await axios.post(`${API_BASE_URL}/repository/unlink`); + const response = await axios.post(`${API_BASE_URL}/git/unlink`); return response.data; } catch (error) { console.error('Error unlinking repository:', error);