add autocommit when create tag

This commit is contained in:
VALLONGOL 2025-04-18 13:29:55 +02:00
parent e3bf97eeb5
commit 96a916ca09
3 changed files with 161 additions and 45 deletions

View File

@ -6,7 +6,7 @@ import datetime
import tkinter as tk
from tkinter import messagebox, filedialog # Assicurati che filedialog sia importato
import logging
import re
# Rimosso zipfile, threading, queue
# Import application modules
@ -988,26 +988,97 @@ class GitSvnSyncApp:
if hasattr(self.main_frame, "update_tag_list"):
self.main_frame.update_tag_list(tags_data)
def _generate_next_tag_suggestion(self, svn_path):
"""
Generates a suggested tag name based on the latest tag matching v.X.X.X.X pattern.
Args:
svn_path (str): Path to the repository.
Returns:
str: The suggested tag name (e.g., "v.0.0.0.1" or incremented version).
"""
self.logger.debug("Generating next tag suggestion...")
default_suggestion = "v.0.0.0.1"
latest_valid_tag = None
tag_pattern = re.compile(r"^v\.(\d{1,2})\.(\d{1,2})\.(\d{1,2})\.(\d{1,2})$")
try:
# Ottieni i tag ordinati, dal più recente
# list_tags restituisce [(name, subject), ...]
tags_data = self.git_commands.list_tags(svn_path)
if not tags_data:
self.logger.debug("No existing tags found. Suggesting default.")
return default_suggestion
# Cerca il primo tag che corrisponde al pattern
for tag_name, _ in tags_data:
match = tag_pattern.match(tag_name)
if match:
latest_valid_tag = tag_name
self.logger.debug(f"Found latest tag matching pattern: {latest_valid_tag}")
break # Trovato il più recente, esci
if not latest_valid_tag:
self.logger.debug("No tags matched the pattern v.X.X.X.X. Suggesting default.")
return default_suggestion
# Estrai e incrementa i numeri
match = tag_pattern.match(latest_valid_tag) # Riesegui match per sicurezza
if not match: # Non dovrebbe succedere, ma controllo difensivo
self.logger.error(f"Internal error: Could not re-match tag {latest_valid_tag}")
return default_suggestion
v1, v2, v3, v4 = map(int, match.groups())
# Incrementa gestendo i riporti da 99 a 0
v4 += 1
if v4 > 99:
v4 = 0
v3 += 1
if v3 > 99:
v3 = 0
v2 += 1
if v2 > 99:
v2 = 0
v1 += 1
# Non mettiamo limiti a v1 per ora (può diventare > 99)
next_tag = f"v.{v1}.{v2}.{v3}.{v4}"
self.logger.debug(f"Generated suggestion: {next_tag}")
return next_tag
except Exception as e:
self.logger.error(f"Error generating tag suggestion: {e}", exc_info=True)
return default_suggestion # Ritorna il default in caso di errore
def create_tag(self):
"""Handles 'Create Tag' (Synchronous after dialog)."""
"""Handles 'Create Tag' (Synchronous after dialog), suggesting the next tag name."""
self.logger.info("--- Action Triggered: Create Tag ---")
svn_path = self._get_and_validate_svn_path("Create Tag")
if not svn_path:
return
# --- MODIFICA: Genera suggerimento PRIMA di aprire il dialogo ---
suggested_tag = self._generate_next_tag_suggestion(svn_path)
# --- FINE MODIFICA ---
# Ottieni input utente (Dialog sincrono)
dialog = CreateTagDialog(self.master)
# --- MODIFICA: Passa il suggerimento al Dialog ---
dialog = CreateTagDialog(self.master, suggested_tag_name=suggested_tag)
# --- FINE MODIFICA ---
tag_info = dialog.result
if tag_info:
tag_name, tag_message = tag_info
if (
not self.save_profile_settings()
): # Salva messaggio commit per pre-commit
# (Logica commit pre-tag e chiamata ad action_handler invariata)
if not self.save_profile_settings():
if not self.main_frame.ask_yes_no(
"Save Warning", "Could not save profile settings.\nContinue anyway?"
):
return
commit_message = self.main_frame.get_commit_message()
# Esecuzione sincrona
try:
success = self.action_handler.execute_create_tag(
svn_path, commit_message, tag_name, tag_message
@ -1016,7 +1087,7 @@ class GitSvnSyncApp:
self.main_frame.show_info("Success", f"Tag '{tag_name}' created.")
self.refresh_tag_list()
self.refresh_commit_history()
self.refresh_branch_list() # Aggiorna UI
self.refresh_branch_list()
except (GitCommandError, ValueError) as e:
self.logger.error(f"Failed create tag '{tag_name}': {e}", exc_info=True)
self.main_frame.show_error("Tag Error", f"Failed:\n{e}")

View File

@ -390,41 +390,74 @@ class ActionHandler:
self.logger.exception(f"Unexpected manual commit error: {e}")
raise Exception("Unexpected manual commit error") from e
def execute_create_tag(self, svn_path, commit_message, tag_name, tag_message):
"""Executes tag creation, including pre-commit using commit_message if needed."""
# (Keep original or improved version - no backup involved)
def execute_create_tag(self, svn_path, commit_message_ignored, tag_name, tag_message):
"""
Executes tag creation. Always attempts to commit staged changes using
the tag message before creating the annotated tag.
Args:
svn_path (str): Path to the repository.
commit_message_ignored (str): Commit message from GUI (IGNORED for this function).
tag_name (str): The name for the new tag.
tag_message (str): The annotation message for the tag (also used for the commit).
Returns:
bool: True if the tag was created successfully.
Raises:
ValueError: If tag_name or tag_message are empty/invalid (checked by GitCommands).
GitCommandError/Exception: If commit or tag creation fails.
"""
# 1. Validazione Input Essenziali
# La validità del formato tag_name sarà controllata da git_commands.create_tag
# Ma controlliamo che non siano vuoti qui, specialmente tag_message che serve per il commit.
if not tag_name or tag_name.isspace():
# Questo check è leggermente ridondante perché git lo bloccherebbe, ma è buona pratica validare prima.
raise ValueError("Tag name cannot be empty.")
if not tag_message or tag_message.isspace():
raise ValueError("Tag annotation message cannot be empty.")
# Fondamentale perché ora serve anche per il commit.
raise ValueError("Tag message cannot be empty (used for commit and tag).")
self.logger.info(f"Executing create tag '{tag_name}' for: {svn_path}")
try: # Pre-commit
has_changes = self.git_commands.git_status_has_changes(svn_path)
if has_changes:
self.logger.info("Uncommitted changes detected before tagging.")
if not commit_message or commit_message.isspace():
raise ValueError(
"Changes exist. Commit message required before tagging."
)
self.logger.info(f"Performing pre-tag commit: '{commit_message}'")
self.git_commands.git_commit(svn_path, commit_message)
self.logger.info("Attempting pre-tag commit using tag message...")
try:
# 2. Esegui Commit (con il messaggio del tag)
# La funzione git_commit in GitCommands dovrebbe già gestire:
# - Staging di tutte le modifiche ('git add .')
# - Esecuzione di 'git commit -m "tag_message"'
# - Gestione del caso "nothing to commit" (restituendo False)
# - Sollevare GitCommandError in caso di fallimento reale del commit
commit_made = self.git_commands.git_commit(svn_path, tag_message)
if commit_made:
self.logger.info(f"Pre-tag commit successful with message: '{tag_message}'")
else:
self.logger.info("No uncommitted changes detected.")
except (GitCommandError, ValueError) as e:
self.logger.error(f"Pre-tag commit error: {e}", exc_info=True)
raise e
except Exception as e:
self.logger.exception(f"Unexpected pre-tag commit error: {e}")
raise Exception("Unexpected pre-tag commit error") from e
try: # Create Tag
self.logger.info(f"Proceeding to create tag '{tag_name}'...")
self.logger.info("No changes detected; no pre-tag commit was necessary.")
# 3. Crea il Tag Annotato (usando lo stesso messaggio)
# Procedi indipendentemente dal fatto che il commit abbia effettivamente
# committato qualcosa, purché non abbia fallito.
self.logger.info(f"Creating annotated tag '{tag_name}'...")
# La funzione create_tag in GitCommands dovrebbe gestire:
# - Validazione del formato del tag_name (regex)
# - Esecuzione di 'git tag -a <tag_name> -m "tag_message"'
# - Gestione dell'errore "tag already exists"
self.git_commands.create_tag(svn_path, tag_name, tag_message)
self.logger.info(f"Tag '{tag_name}' created successfully.")
return True
return True # L'operazione complessiva è riuscita
except (GitCommandError, ValueError) as e:
self.logger.error(f"Failed create tag '{tag_name}': {e}", exc_info=True)
# Cattura errori specifici da commit o tag
# ValueError potrebbe venire dalla validazione iniziale o da git_commit
self.logger.error(f"Failed to commit or create tag '{tag_name}': {e}", exc_info=True)
# Rilancia l'errore specifico per essere gestito dalla GUI
raise e
except Exception as e:
self.logger.exception(f"Unexpected tag error: {e}")
raise Exception("Unexpected tag creation error") from e
# Cattura qualsiasi altro errore imprevisto
self.logger.exception(f"Unexpected error during commit/tag process for '{tag_name}': {e}")
# Rilancia un'eccezione generica ma informativa
raise Exception(f"Unexpected error creating tag '{tag_name}'") from e
def execute_checkout_tag(self, svn_path, tag_name):
"""Executes checkout for the specified tag after checking changes."""

32
gui.py
View File

@ -249,10 +249,14 @@ class GitignoreEditorWindow(tk.Toplevel):
# --- Create Tag Dialog ---
# (No changes needed here)
class CreateTagDialog(simpledialog.Dialog):
def __init__(self, parent, title="Create New Tag"):
def __init__(self, parent, title="Create New Tag", suggested_tag_name=""):
self.tag_name_var = tk.StringVar()
self.tag_message_var = tk.StringVar()
self.result = None
# --- MODIFICA: Memorizza il suggerimento ---
self.suggested_tag_name = suggested_tag_name
# --- FINE MODIFICA ---
# Chiamare super() alla fine o dopo aver inizializzato le variabili usate in body/validate
super().__init__(parent, title=title)
def body(self, master):
@ -264,6 +268,11 @@ class CreateTagDialog(simpledialog.Dialog):
)
self.name_entry = ttk.Entry(frame, textvariable=self.tag_name_var, width=40)
self.name_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
# --- MODIFICA: Imposta valore iniziale ---
if self.suggested_tag_name:
self.tag_name_var.set(self.suggested_tag_name)
# --- FINE MODIFICA ---
ttk.Label(frame, text="Tag Message:").grid(
row=1, column=0, padx=5, pady=5, sticky="w"
)
@ -271,24 +280,27 @@ class CreateTagDialog(simpledialog.Dialog):
frame, textvariable=self.tag_message_var, width=40
)
self.message_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
return self.name_entry
# Ritorna il widget che deve avere il focus iniziale
return self.name_entry # O self.message_entry se si preferisce
# La validazione del nome tag ora avviene in GitCommands.create_tag
# Manteniamo solo i controlli per non vuoto.
def validate(self):
name = self.tag_name_var.get().strip()
msg = self.tag_message_var.get().strip()
if not name:
messagebox.showwarning("Input Error", "Tag name empty.", parent=self)
messagebox.showwarning("Input Error", "Tag name cannot be empty.", parent=self)
return 0
if not msg:
messagebox.showwarning("Input Error", "Tag message empty.", parent=self)
return 0
pattern = r"^(?![./]|.*([./]{2,}|[.]$|\.lock$))[^ \t\n\r\f\v~^:?*[\\]+(?<!\.)$"
if not re.match(pattern, name):
messagebox.showwarning(
"Input Error", "Invalid tag name format.", parent=self
)
messagebox.showwarning("Input Error", "Tag message cannot be empty.", parent=self)
return 0
# Rimuovi il controllo regex da qui, verrà fatto da GitCommands
# pattern = r"^(?![./]|.*([./]{2,}|[.]$|\.lock$))[^ \t\n\r\f\v~^:?*[\\]+(?<!\.)$"
# if not re.match(pattern, name):
# messagebox.showwarning("Input Error", "Invalid tag name format.", parent=self)
# return 0
return 1
# --- FINE MODIFICA ---
def apply(self):
self.result = (