Skip to content

Commit 3fa03d1

Browse files
authored
Merge pull request mouredev#6789 from cdryampi/main
mouredev#43 - Python
2 parents bef2e73 + dee4e23 commit 3fa03d1

File tree

1 file changed

+347
-0
lines changed

1 file changed

+347
-0
lines changed
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
# /*
2+
# * EJERCICIO:
3+
# * ¡Me voy de viaje al GitHub Universe 2024 de San Francisco!
4+
# *
5+
# * Desarrolla un CLI (Command Line Interface) que permita
6+
# * interactuar con Git y GitHub de manera real desde terminal.
7+
# *
8+
# * El programa debe permitir las siguientes opciones:
9+
# * 1. Establecer el directorio de trabajo
10+
# * 2. Crear un nuevo repositorio
11+
# * 3. Crear una nueva rama
12+
# * 4. Cambiar de rama
13+
# * 5. Mostrar ficheros pendientes de hacer commit
14+
# * 6. Hacer commit (junto con un add de todos los ficheros)
15+
# * 7. Mostrar el historial de commits
16+
# * 8. Eliminar rama
17+
# * 9. Establecer repositorio remoto
18+
# * 10. Hacer pull
19+
# * 11. Hacer push
20+
# * 12. Salir
21+
# *
22+
# * Puedes intentar controlar los diferentes errores.
23+
# */
24+
25+
import os
26+
import subprocess
27+
import http.client
28+
from urllib.parse import urlparse
29+
30+
31+
class Directory:
32+
__PATH_DIRECTORY = None
33+
34+
def __init__(self) -> None:
35+
self.__PATH_DIRECTORY = os.getcwd()
36+
37+
def select_folder(self) -> None:
38+
"""Selecciona una ruta válida"""
39+
while self.__PATH_DIRECTORY is None:
40+
route = input("Introduce una ruta o presiona 0 para usar la carpeta actual:\n")
41+
self.check_folder(route)
42+
43+
def check_folder(self, route) -> bool:
44+
"""Establece una carpeta por defecto si no se ha seleccionado ninguna."""
45+
if route == '0':
46+
self.__PATH_DIRECTORY = os.getcwd()
47+
print("Hemos asignado la carpeta por defecto.")
48+
return True
49+
elif os.path.isdir(route):
50+
self.__PATH_DIRECTORY = route
51+
print(f"Nueva ruta establecida: {self.__PATH_DIRECTORY}")
52+
return True
53+
else:
54+
print("La ruta no es válida.")
55+
return False
56+
57+
def clear_path(self) -> None:
58+
self.__PATH_DIRECTORY = None
59+
60+
def get_path(self) -> str:
61+
return self.__PATH_DIRECTORY if self.__PATH_DIRECTORY else "No se ha establecido una ruta."
62+
63+
64+
class CLIControl:
65+
def __init__(self):
66+
self.__DIRECTORY = Directory()
67+
self.__SUBPROCESS = subprocess
68+
self.__CURRENT_BRANCH = None
69+
70+
def is_git_initialized(self) -> bool:
71+
"""Verificar si .git existe en el directorio actual"""
72+
directory_path = self.__DIRECTORY.get_path()
73+
74+
# Asegurarse de que la ruta esté configurada
75+
if not directory_path or directory_path == "Aún no se ha establecido una ruta.":
76+
print("No se ha establecido un directorio de trabajo válido.")
77+
return False
78+
79+
git_path = os.path.join(directory_path, '.git')
80+
81+
# Debug: Imprimir la ruta donde se está buscando la carpeta .git
82+
print(f"Verificando si existe .git en la ruta: {git_path}")
83+
84+
if os.path.isdir(git_path):
85+
return True
86+
else:
87+
print("Git no está inicializado en este directorio. Utiliza un directorio con un repositorio Git.")
88+
return False
89+
90+
91+
def create_repository(self):
92+
"""Crear un repositorio Git en el directorio actual"""
93+
if not self.is_git_initialized():
94+
resultado = self.__SUBPROCESS.run(
95+
["git", "init"],
96+
capture_output=True,
97+
text=True,
98+
cwd=self.__DIRECTORY.get_path()
99+
)
100+
print(resultado.stdout)
101+
else:
102+
print("Ya hay un repositorio Git en el directorio.")
103+
104+
def create_branch(self, branch_name):
105+
"""Crear una nueva rama"""
106+
if self.is_git_initialized():
107+
resultado = self.__SUBPROCESS.run(
108+
["git", "branch", branch_name],
109+
capture_output=True,
110+
text=True,
111+
cwd=self.__DIRECTORY.get_path()
112+
)
113+
# Verificar si la creación de la rama fue exitosa
114+
if resultado.returncode == 0:
115+
print(f"La rama '{branch_name}' ha sido creada con éxito.")
116+
else:
117+
print("Error al crear la rama:")
118+
print(resultado.stderr)
119+
120+
def select_folder_CLI(self):
121+
"""Limpiar todo y volver a pedir carpeta"""
122+
self.__DIRECTORY.clear_path()
123+
self.__DIRECTORY.select_folder()
124+
self.__CURRENT_BRANCH = None
125+
126+
def status(self):
127+
"""Mostrar archivos pendientes de commit"""
128+
if self.is_git_initialized():
129+
resultado = self.__SUBPROCESS.run(
130+
["git", "status"],
131+
capture_output=True,
132+
text=True,
133+
cwd=self.__DIRECTORY.get_path()
134+
)
135+
print(resultado.stdout)
136+
137+
def commit_git(self, msg='Commit desde CLI'):
138+
"""Agregar y hacer commit de todos los cambios"""
139+
if self.is_git_initialized():
140+
self.__SUBPROCESS.run(["git", "add", "."], cwd=self.__DIRECTORY.get_path())
141+
resultado = self.__SUBPROCESS.run(
142+
["git", "commit", "-m", msg],
143+
capture_output=True,
144+
text=True,
145+
cwd=self.__DIRECTORY.get_path()
146+
)
147+
print(resultado.stdout)
148+
149+
def log(self):
150+
"""Mostrar historial de commits"""
151+
if self.is_git_initialized():
152+
resultado = self.__SUBPROCESS.run(
153+
["git", "log", "--oneline"],
154+
capture_output=True,
155+
text=True,
156+
cwd=self.__DIRECTORY.get_path()
157+
)
158+
print(resultado.stdout)
159+
160+
def delete_branch(self):
161+
"""Eliminar la rama actual"""
162+
if self.is_git_initialized():
163+
# Por si acaso llamamos a la función para seleccionar rama para no eliminar la rama sin querer.
164+
self.select_remote_or_local_branch()
165+
if self.__CURRENT_BRANCH:
166+
resultado = self.__SUBPROCESS.run(
167+
["git", "branch", "-d", self.__CURRENT_BRANCH],
168+
capture_output=True,
169+
text=True,
170+
cwd=self.__DIRECTORY.get_path()
171+
)
172+
print(resultado.stdout)
173+
self.__CURRENT_BRANCH = None
174+
else:
175+
print("Selecciona una rama primero.")
176+
177+
def add_remote(self, url_remote):
178+
"""Establecer un repositorio remoto"""
179+
if self.is_git_initialized():
180+
resultado = self.__SUBPROCESS.run(
181+
["git", "remote", "add", "origin", url_remote],
182+
capture_output=True,
183+
text=True,
184+
cwd=self.__DIRECTORY.get_path()
185+
)
186+
print(resultado.stdout)
187+
188+
def select_remote_or_local_branch(self):
189+
"""Función para seleccionar una rama local o remota"""
190+
if self.is_git_initialized():
191+
resultado = self.__SUBPROCESS.run(
192+
["git", "branch", "-a"],
193+
capture_output=True,
194+
text=True,
195+
cwd=self.__DIRECTORY.get_path()
196+
)
197+
198+
# Obtiene la lista de ramas y elimina líneas en blanco
199+
branches = [branch.strip() for branch in resultado.stdout.splitlines() if branch.strip()]
200+
201+
# Muestra las opciones al usuario de forma numerada
202+
print("Selecciona la rama que deseas utilizar:")
203+
for idx, branch in enumerate(branches, 1):
204+
print(f"{idx}. {branch}")
205+
206+
# Verifica la elección del usuario
207+
while True:
208+
try:
209+
choice = int(input("Introduce el número de la rama: "))
210+
if 1 <= choice <= len(branches):
211+
selected_branch = branches[choice - 1].replace("*", "").strip()
212+
self.__CURRENT_BRANCH = selected_branch
213+
print(f"Has seleccionado la rama: {self.__CURRENT_BRANCH}")
214+
break
215+
else:
216+
print("Número fuera de rango. Por favor, selecciona un número válido.")
217+
except ValueError:
218+
print("Entrada no válida. Por favor, introduce un número.")
219+
220+
def check_url_github(self, url) -> bool:
221+
"""Comprueba si la URL devuelve un estado 200 o un estado 301 usando http.client."""
222+
parsed_url = urlparse(url)
223+
connection = http.client.HTTPConnection(parsed_url.netloc)
224+
try:
225+
connection.request("GET", parsed_url.path or "/")
226+
response = connection.getresponse()
227+
228+
# Verificar el estado
229+
if response.status == 200 or response.status == 301:
230+
print(f"Conexión exitosa a {url} (Estado 200).")
231+
return True
232+
else:
233+
print(f"Error: estado {response.status} en {url}.")
234+
return False
235+
except Exception as e:
236+
print(f"Hubo un problema con la solicitud: {e}")
237+
return False
238+
finally:
239+
connection.close()
240+
241+
def git_pull(self):
242+
"""Hacer pull de la rama actual"""
243+
if self.is_git_initialized():
244+
resultado = self.__SUBPROCESS.run(
245+
["git", "pull"],
246+
capture_output=True,
247+
text=True,
248+
cwd=self.__DIRECTORY.get_path()
249+
)
250+
print(resultado.stdout)
251+
252+
def git_push(self):
253+
"""Hacer push de la rama actual"""
254+
if self.is_git_initialized():
255+
# Asegúrate de que haya una rama seleccionada
256+
if self.__CURRENT_BRANCH:
257+
print(f"Intentando hacer push a la rama '{self.__CURRENT_BRANCH}' en el remoto 'origin'...")
258+
259+
# Comprueba si el remoto 'origin' está configurado
260+
remote_check = self.__SUBPROCESS.run(
261+
["git", "remote", "-v"],
262+
capture_output=True,
263+
text=True,
264+
cwd=self.__DIRECTORY.get_path()
265+
)
266+
if 'origin' not in remote_check.stdout:
267+
print("El remoto 'origin' no está configurado. Por favor, agrega un repositorio remoto.")
268+
return
269+
270+
# Realiza el push
271+
resultado = self.__SUBPROCESS.run(
272+
["git", "push", "-u", "origin", self.__CURRENT_BRANCH],
273+
capture_output=True,
274+
text=True,
275+
cwd=self.__DIRECTORY.get_path()
276+
)
277+
278+
# Verifica la salida y los errores
279+
if resultado.returncode == 0:
280+
print("Push exitoso:")
281+
print(resultado.stdout)
282+
else:
283+
print("Error al hacer push:")
284+
print(resultado.stderr)
285+
else:
286+
print("Selecciona una rama primero.")
287+
288+
289+
def menu(self):
290+
"""Menú interactivo"""
291+
while True:
292+
print("\nSelecciona una opción:")
293+
print("1. Establecer directorio de trabajo")
294+
print("2. Crear repositorio")
295+
print("3. Crear rama")
296+
print("4. Cambiar de rama")
297+
print("5. Mostrar ficheros pendientes de commit")
298+
print("6. Hacer commit")
299+
print("7. Mostrar historial de commits")
300+
print("8. Eliminar rama")
301+
print("9. Establecer repositorio remoto")
302+
print("10. Hacer pull")
303+
print("11. Hacer push")
304+
print("12. Salir")
305+
306+
opcion = input("Opción: ")
307+
match opcion:
308+
case '1':
309+
self.select_folder_CLI()
310+
case '2':
311+
self.create_repository()
312+
case '3':
313+
branch_name = input("Nombre de la nueva rama: ")
314+
self.create_branch(branch_name)
315+
case '4':
316+
self.select_remote_or_local_branch()
317+
case '5':
318+
self.status()
319+
case '6':
320+
msg = input("Mensaje de commit: ")
321+
self.commit_git(msg)
322+
case '7':
323+
self.log()
324+
case '8':
325+
self.delete_branch()
326+
case '9':
327+
url = input("URL del repositorio remoto: ")
328+
if self.check_url_github(url):
329+
self.add_remote(url)
330+
else:
331+
print("URL no válida. No se ha establecido el remoto.")
332+
case '10':
333+
self.git_pull()
334+
case '11':
335+
self.git_push()
336+
case '12':
337+
print("Saliendo...")
338+
break
339+
case _:
340+
print("Opción no válida.")
341+
342+
def main():
343+
cli = CLIControl()
344+
cli.menu()
345+
346+
if __name__ == '__main__':
347+
main()

0 commit comments

Comments
 (0)