add autocommit when create tag
This commit is contained in:
parent
e3bf97eeb5
commit
96a916ca09
@ -6,7 +6,7 @@ import datetime
|
|||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import messagebox, filedialog # Assicurati che filedialog sia importato
|
from tkinter import messagebox, filedialog # Assicurati che filedialog sia importato
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
# Rimosso zipfile, threading, queue
|
# Rimosso zipfile, threading, queue
|
||||||
|
|
||||||
# Import application modules
|
# Import application modules
|
||||||
@ -988,26 +988,97 @@ class GitSvnSyncApp:
|
|||||||
if hasattr(self.main_frame, "update_tag_list"):
|
if hasattr(self.main_frame, "update_tag_list"):
|
||||||
self.main_frame.update_tag_list(tags_data)
|
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):
|
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 ---")
|
self.logger.info("--- Action Triggered: Create Tag ---")
|
||||||
svn_path = self._get_and_validate_svn_path("Create Tag")
|
svn_path = self._get_and_validate_svn_path("Create Tag")
|
||||||
if not svn_path:
|
if not svn_path:
|
||||||
return
|
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)
|
# 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
|
tag_info = dialog.result
|
||||||
|
|
||||||
if tag_info:
|
if tag_info:
|
||||||
tag_name, tag_message = tag_info
|
tag_name, tag_message = tag_info
|
||||||
if (
|
# (Logica commit pre-tag e chiamata ad action_handler invariata)
|
||||||
not self.save_profile_settings()
|
if not self.save_profile_settings():
|
||||||
): # Salva messaggio commit per pre-commit
|
|
||||||
if not self.main_frame.ask_yes_no(
|
if not self.main_frame.ask_yes_no(
|
||||||
"Save Warning", "Could not save profile settings.\nContinue anyway?"
|
"Save Warning", "Could not save profile settings.\nContinue anyway?"
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
commit_message = self.main_frame.get_commit_message()
|
commit_message = self.main_frame.get_commit_message()
|
||||||
# Esecuzione sincrona
|
|
||||||
try:
|
try:
|
||||||
success = self.action_handler.execute_create_tag(
|
success = self.action_handler.execute_create_tag(
|
||||||
svn_path, commit_message, tag_name, tag_message
|
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.main_frame.show_info("Success", f"Tag '{tag_name}' created.")
|
||||||
self.refresh_tag_list()
|
self.refresh_tag_list()
|
||||||
self.refresh_commit_history()
|
self.refresh_commit_history()
|
||||||
self.refresh_branch_list() # Aggiorna UI
|
self.refresh_branch_list()
|
||||||
except (GitCommandError, ValueError) as e:
|
except (GitCommandError, ValueError) as e:
|
||||||
self.logger.error(f"Failed create tag '{tag_name}': {e}", exc_info=True)
|
self.logger.error(f"Failed create tag '{tag_name}': {e}", exc_info=True)
|
||||||
self.main_frame.show_error("Tag Error", f"Failed:\n{e}")
|
self.main_frame.show_error("Tag Error", f"Failed:\n{e}")
|
||||||
|
|||||||
@ -390,41 +390,74 @@ class ActionHandler:
|
|||||||
self.logger.exception(f"Unexpected manual commit error: {e}")
|
self.logger.exception(f"Unexpected manual commit error: {e}")
|
||||||
raise Exception("Unexpected manual commit error") from e
|
raise Exception("Unexpected manual commit error") from e
|
||||||
|
|
||||||
def execute_create_tag(self, svn_path, commit_message, tag_name, tag_message):
|
def execute_create_tag(self, svn_path, commit_message_ignored, tag_name, tag_message):
|
||||||
"""Executes tag creation, including pre-commit using commit_message if needed."""
|
"""
|
||||||
# (Keep original or improved version - no backup involved)
|
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():
|
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}")
|
self.logger.info(f"Executing create tag '{tag_name}' for: {svn_path}")
|
||||||
try: # Pre-commit
|
self.logger.info("Attempting pre-tag commit using tag message...")
|
||||||
has_changes = self.git_commands.git_status_has_changes(svn_path)
|
|
||||||
if has_changes:
|
try:
|
||||||
self.logger.info("Uncommitted changes detected before tagging.")
|
# 2. Esegui Commit (con il messaggio del tag)
|
||||||
if not commit_message or commit_message.isspace():
|
# La funzione git_commit in GitCommands dovrebbe già gestire:
|
||||||
raise ValueError(
|
# - Staging di tutte le modifiche ('git add .')
|
||||||
"Changes exist. Commit message required before tagging."
|
# - Esecuzione di 'git commit -m "tag_message"'
|
||||||
)
|
# - Gestione del caso "nothing to commit" (restituendo False)
|
||||||
self.logger.info(f"Performing pre-tag commit: '{commit_message}'")
|
# - Sollevare GitCommandError in caso di fallimento reale del commit
|
||||||
self.git_commands.git_commit(svn_path, commit_message)
|
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:
|
else:
|
||||||
self.logger.info("No uncommitted changes detected.")
|
self.logger.info("No changes detected; no pre-tag commit was necessary.")
|
||||||
except (GitCommandError, ValueError) as e:
|
|
||||||
self.logger.error(f"Pre-tag commit error: {e}", exc_info=True)
|
# 3. Crea il Tag Annotato (usando lo stesso messaggio)
|
||||||
raise e
|
# Procedi indipendentemente dal fatto che il commit abbia effettivamente
|
||||||
except Exception as e:
|
# committato qualcosa, purché non abbia fallito.
|
||||||
self.logger.exception(f"Unexpected pre-tag commit error: {e}")
|
self.logger.info(f"Creating annotated tag '{tag_name}'...")
|
||||||
raise Exception("Unexpected pre-tag commit error") from e
|
# La funzione create_tag in GitCommands dovrebbe gestire:
|
||||||
try: # Create Tag
|
# - Validazione del formato del tag_name (regex)
|
||||||
self.logger.info(f"Proceeding to create tag '{tag_name}'...")
|
# - 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.git_commands.create_tag(svn_path, tag_name, tag_message)
|
||||||
self.logger.info(f"Tag '{tag_name}' created successfully.")
|
self.logger.info(f"Tag '{tag_name}' created successfully.")
|
||||||
return True
|
return True # L'operazione complessiva è riuscita
|
||||||
|
|
||||||
except (GitCommandError, ValueError) as e:
|
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
|
raise e
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.exception(f"Unexpected tag error: {e}")
|
# Cattura qualsiasi altro errore imprevisto
|
||||||
raise Exception("Unexpected tag creation error") from e
|
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):
|
def execute_checkout_tag(self, svn_path, tag_name):
|
||||||
"""Executes checkout for the specified tag after checking changes."""
|
"""Executes checkout for the specified tag after checking changes."""
|
||||||
|
|||||||
32
gui.py
32
gui.py
@ -249,10 +249,14 @@ class GitignoreEditorWindow(tk.Toplevel):
|
|||||||
# --- Create Tag Dialog ---
|
# --- Create Tag Dialog ---
|
||||||
# (No changes needed here)
|
# (No changes needed here)
|
||||||
class CreateTagDialog(simpledialog.Dialog):
|
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_name_var = tk.StringVar()
|
||||||
self.tag_message_var = tk.StringVar()
|
self.tag_message_var = tk.StringVar()
|
||||||
self.result = None
|
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)
|
super().__init__(parent, title=title)
|
||||||
|
|
||||||
def body(self, master):
|
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 = ttk.Entry(frame, textvariable=self.tag_name_var, width=40)
|
||||||
self.name_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
|
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(
|
ttk.Label(frame, text="Tag Message:").grid(
|
||||||
row=1, column=0, padx=5, pady=5, sticky="w"
|
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
|
frame, textvariable=self.tag_message_var, width=40
|
||||||
)
|
)
|
||||||
self.message_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
|
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):
|
def validate(self):
|
||||||
name = self.tag_name_var.get().strip()
|
name = self.tag_name_var.get().strip()
|
||||||
msg = self.tag_message_var.get().strip()
|
msg = self.tag_message_var.get().strip()
|
||||||
if not name:
|
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
|
return 0
|
||||||
if not msg:
|
if not msg:
|
||||||
messagebox.showwarning("Input Error", "Tag message empty.", parent=self)
|
messagebox.showwarning("Input Error", "Tag message cannot be 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
|
|
||||||
)
|
|
||||||
return 0
|
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
|
return 1
|
||||||
|
# --- FINE MODIFICA ---
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
self.result = (
|
self.result = (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user