add autocommit when create tag
This commit is contained in:
parent
e3bf97eeb5
commit
96a916ca09
@ -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
|
||||
@ -987,27 +987,98 @@ class GitSvnSyncApp:
|
||||
# Aggiorna GUI in ogni caso (anche con lista vuota o errore)
|
||||
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}")
|
||||
|
||||
@ -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
32
gui.py
@ -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 = (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user