Desde el punto de vista técnico, es posible agregar algunos ganchos de empuje previos / posteriores que ejecutarán pruebas unitarias antes de permitir que se fusionen algunos compromisos específicos con la rama predeterminada remota.
Mi pregunta es: ¿es mejor mantener las pruebas unitarias en el canal de compilación (por lo tanto, introducir confirmaciones rotas para el repositorio) o es mejor simplemente no permitir que se produzcan confirmaciones "malas".
Me doy cuenta de que no estoy limitado con estas dos opciones. Por ejemplo, puedo permitir que todos los commits se ramifiquen y prueben antes de empujar merge commit a repo. Pero si tiene que elegir exactamente entre estas dos soluciones, ¿cuál elegirá y por qué razones exactas?
Respuestas:
No, no lo es, por dos razones:
Velocidad
Los commits deben ser rápidos. Una confirmación que tarda 500 ms., Por ejemplo, es demasiado lenta y alentará a los desarrolladores a comprometerse con más moderación. Dado que en cualquier proyecto más grande que Hello World, tendrá docenas o cientos de pruebas, tomará demasiado tiempo ejecutarlas durante el precompromiso.
Por supuesto, las cosas empeoran para proyectos más grandes con miles de pruebas que se ejecutan durante minutos en una arquitectura distribuida, o semanas o meses en una sola máquina.
La peor parte es que no hay mucho que puedas hacer para hacerlo más rápido. Los pequeños proyectos de Python que tienen, por ejemplo, cien pruebas unitarias, tardan al menos un segundo en ejecutarse en un servidor promedio, pero a menudo mucho más tiempo. Para una aplicación C #, tendrá un promedio de cuatro y cinco segundos, debido al tiempo de compilación.
A partir de ese momento, puede pagar $ 10 000 adicionales por un mejor servidor que reducirá el tiempo, pero no mucho, o ejecutar pruebas en varios servidores, lo que solo ralentizará las cosas.
Ambos pagan bien cuando tiene miles de pruebas (así como pruebas funcionales, de sistema y de integración), lo que permite ejecutarlas en cuestión de minutos en lugar de semanas, pero esto no lo ayudará en proyectos a pequeña escala.
Lo que puedes hacer, en cambio, es:
Aliente a los desarrolladores a ejecutar pruebas fuertemente relacionadas con el código que modificaron localmente antes de realizar una confirmación. Posiblemente no puedan ejecutar miles de pruebas unitarias, pero pueden ejecutar cinco de diez.
Asegúrese de que encontrar pruebas relevantes y ejecutarlas sea realmente fácil (y rápido). Visual Studio, por ejemplo, puede detectar qué pruebas pueden verse afectadas por los cambios realizados desde la última ejecución. Otros IDEs / plataformas / idiomas / marcos pueden tener una funcionalidad similar.
Mantenga el compromiso lo más rápido posible. Hacer cumplir las reglas de estilo está bien, porque a menudo, es el único lugar para hacerlo, y porque tales controles a menudo son increíblemente rápidos. Hacer análisis estático está bien tan pronto como se mantenga rápido, lo cual rara vez es el caso. Ejecutar pruebas unitarias no está bien.
Ejecute pruebas unitarias en su servidor de integración continua.
Asegúrese de que los desarrolladores estén informados automáticamente cuando rompan la compilación (o cuando fallaron las pruebas unitarias, que es prácticamente lo mismo si considera un compilador como una herramienta que verifica algunos de los posibles errores que puede introducir en su código).
Por ejemplo, ir a una página web para verificar las últimas compilaciones no es una solución. Deben ser informados automáticamente . Mostrar una ventana emergente o enviar un SMS son dos ejemplos de cómo pueden ser informados.
Asegúrese de que los desarrolladores entiendan que romper la compilación (o las pruebas de regresión fallidas) no está bien, y que tan pronto como suceda, su principal prioridad es solucionarlo. No importa si están trabajando en una función de alta prioridad que su jefe pidió enviar para mañana: fallaron la compilación, deberían arreglarla.
Seguridad
El servidor que aloja el repositorio no debe ejecutar código personalizado, como pruebas unitarias, especialmente por razones de seguridad. ¿Esas razones ya se explicaron en el corredor de CI en el mismo servidor de GitLab?
Si, por otro lado, su idea es iniciar un proceso en el servidor de compilación desde el enlace previo a la confirmación, entonces disminuirá aún más las confirmaciones.
fuente
Déjame ser el que no esté de acuerdo con mis compañeros de respuesta.
Esto se conoce como check-ins cerrados en el mundo TFS, y espero en otros lugares. Cuando intenta registrarse en una sucursal con el check-in cerrado, el conjunto de estanterías se envía al servidor, lo que garantiza que sus cambios se compilen y se pasen las pruebas unitarias especificadas (léase: todas). Si no lo hacen, te notifica que eres un mono malo que rompió la construcción. Si lo hacen, los cambios pasan al control de fuente (¡sí!).
En mi experiencia, los registros privados son uno de los procesos más importantes para realizar pruebas unitarias exitosas y, por extensión, la calidad del software.
¿Por qué?
Y, por supuesto, está el beneficio que mencionó originalmente: cuando ha cerrado los registros y un conjunto sólido de pruebas, cada conjunto de cambios es "estable". Guarda todos esos gastos generales (y el potencial de error) de "¿cuándo fue la última compilación correcta?" - Todas las compilaciones son lo suficientemente buenas como para desarrollarlas.
Sí, lleva tiempo construir y ejecutar las pruebas. En mi experiencia, 5-10 minutos para una aplicación C # de buen tamaño y ~ 5k pruebas unitarias. Y eso no me importa. Sí, las personas deben registrarse con frecuencia. Pero también deben actualizar sus tareas con frecuencia, o revisar su correo electrónico, u obtener un café o docenas de otras cosas que "no funcionan en código" que componen el trabajo de un ingeniero de software para ocupar ese tiempo. Verificar el código incorrecto es mucho más costoso que 5-10 minutos.
fuente
Los commits deben correr rápido. Cuando confirmo un código, quiero que sea enviado al servidor. No quiero esperar unos minutos mientras ejecuta una batería de pruebas. Soy responsable de lo que envío al servidor y no necesito que nadie me cuide con ganchos de compromiso.
Dicho esto, una vez que llega al servidor, debe analizarse, probarse la unidad y construirse de inmediato (o dentro de un corto período de tiempo). Esto me alertaría sobre el hecho de que las pruebas unitarias están rotas, o no se compiló, o hice un desastre mostrado por las herramientas de análisis estático disponibles. Cuanto más rápido se haga esto (la construcción y el análisis), más rápido será mi respuesta y más rápido podré solucionarlo (los pensamientos no han desaparecido por completo de mi cerebro).
Entonces, no, no ponga pruebas y cosas así en commit hooks en el cliente. Si debe hacerlo, póngalos en el servidor en una confirmación posterior (porque no tiene un servidor de CI) o en el servidor de compilación de CI y avíseme adecuadamente a los problemas con el código. Pero, en primer lugar, no bloquee la confirmación.
También debo señalar que con algunas interpretaciones de Test Driven Development, uno debe verificar una prueba unitaria que se rompa primero . Esto demuestra y documenta que el error está presente. Luego, un registro posterior sería el código que corrige la prueba unitaria. La prevención de cualquier registro hasta que se aprueben las pruebas unitarias reduciría el valor efectivo de registrar una prueba unitaria que no documenta el problema.
Relacionado: ¿Debería realizarme pruebas unitarias para detectar defectos conocidos? y ¿Cuál es el valor de verificar en las pruebas unitarias fallidas?
fuente
Commits should run fast.
¿Cuáles son los beneficios de esto? Tengo curiosidad porque actualmente utilizamos registros cerrados. Por lo general, mis registros son una acumulación de aproximadamente una hora de trabajo, por lo que esperar 5 minutos no es gran cosa. De hecho, me he dado cuenta que sus normalmente los momentos en los que estoy en una carrera que la acumulación de validación es más útil para la captura de errores tontos (como resultado de correr)catching silly mistakes (as a result of rushing)
exactamente. apresurarse en general es una mala práctica en ingeniería de software. Robert C. Martin recomienda escribir código como hacer una cirugía youtube.com/watch?v=p0O1VVqRSK0En principio, creo que tiene sentido evitar que las personas realicen cambios en la línea principal que rompen la construcción. Es decir, el proceso para realizar cambios en la rama principal de su repositorio debe requerir asegurarse de que todas las pruebas aún pasen. Romper la construcción es simplemente demasiado costoso en términos de tiempo perdido para todos los ingenieros en el proyecto para hacer cualquier otra cosa.
Sin embargo, la solución particular de commit hooks no es un buen plan.
fuente
Breaking the build is simply too costly in terms of lost time for all engineers on the project
Sugeriría usar algún tipo de herramienta de notificación de compilación para evitar que todos los ingenieros terminen perdiendo tiempo en cada compilación rotaNo, no debería, como han señalado otras respuestas.
Si desea tener una base de código que garantice que no fallarán las pruebas, podría desarrollar en ramas de características y hacer solicitudes de extracción en maestro. Luego puede definir condiciones previas para aceptar esas solicitudes de extracción. El beneficio es que puede presionar muy rápido y las pruebas se ejecutan en segundo plano.
fuente
Tener que esperar a que la compilación y las pruebas sean exitosas en cada compromiso con la rama principal es realmente horrible, creo que todos están de acuerdo con esto.
Pero hay otras formas de lograr una rama principal consistente. Aquí hay una sugerencia, un poco similar en el sentido de los registros cerrados en TFS, pero que es generalizable a cualquier sistema de control de versiones con ramas, aunque usaré principalmente términos git:
Tenga una rama provisional en la que solo pueda realizar fusiones entre sus ramas de desarrollo y la rama principal
Configure un enlace que inicie o ponga en cola una compilación y pruebe las confirmaciones realizadas en la rama provisional, pero eso no hace que el confirmador espere
En una compilación y pruebas exitosas, haga que la rama principal avance automáticamente si está actualizada
Nota: no combine automáticamente en la rama principal, porque la combinación probada, si no es una combinación directa desde el punto de vista de la rama principal, puede fallar cuando se combina en la rama principal con confirmaciones intermedias
Como consecuencia:
Prohíba los compromisos humanos con la rama principal, automáticamente si puede, pero también como parte del proceso oficial si hay una laguna o si no es técnicamente factible hacer cumplir esto.
Al menos, puedes asegurarte de que nadie lo haga involuntariamente o sin malicia, una vez que sea una regla básica. No deberías intentar hacerlo, nunca.
Tendrás que elegir entre:
Una sola rama de preparación, que hará que las fusiones de otro modo exitosas realmente fallen si falla una fusión anterior pero no compilada y no probada
Al menos, sabrá qué combinación falló y haga que alguien la corrija, pero las combinaciones intermedias no son trivialmente rastreables (por el sistema de control de versiones) para los resultados de otras compilaciones y pruebas.
Puede ver la anotación de archivo (o culpar), pero a veces un cambio en un archivo (por ejemplo, configuración) generará errores en lugares inesperados. Sin embargo, este es un evento bastante raro.
Múltiples ramas intermedias, que permitirán que las fusiones exitosas no conflictivas lleguen a la rama principal
Incluso en el caso de que alguna otra rama provisional tenga fusiones no conflictivas . La trazabilidad es un poco mejor, al menos en el caso de que una fusión no esperara un cambio que afecte a otra fusión. Pero, de nuevo, esto es lo suficientemente raro como para no preocuparse todos los días o todas las semanas.
Para tener fusiones no conflictivas la mayor parte del tiempo, es importante dividir las ramas de puesta en escena con sensatez, por ejemplo, por equipo, por capa o por componente / proyecto / sistema / solución (lo que sea que lo nombre).
Si mientras tanto, la rama principal se reenvió a otra fusión, debe volver a fusionarse. Con suerte, esto no es un problema con fusiones no conflictivas o con muy pocos conflictos.
En comparación con los registros cerrados, la ventaja aquí es que tiene la garantía de una rama principal que funciona, porque la rama principal solo puede avanzar, no fusionar automáticamente sus cambios con lo que se haya comprometido en el medio. Entonces el tercer punto es la diferencia esencial.
fuente
Prefiero que las "pruebas unitarias aprobadas" sean una puerta para enviar el código. Sin embargo, para que funcione, necesitará algunas cosas.
Necesitará un marco de compilación que almacena en caché los artefactos.
Necesitará un marco de prueba que almacena en caché el estado de prueba de las ejecuciones de prueba (exitosas), con cualquier artefacto (s) dado.
De esa manera, los registros con las pruebas unitarias aprobadas serán rápidos (verificación cruzada desde la fuente hasta el artefacto que fue construido cuando el desarrollador verificó las pruebas antes del registro), aquellos con pruebas unitarias fallidas serán bloqueados y los desarrolladores que convenientemente, olvide verificar las compilaciones antes de confirmar, se le recomendará que recuerde hacerlo la próxima vez, porque el ciclo de compilación y prueba es largo.
fuente
Diría que depende del proyecto y del alcance de las pruebas automatizadas que se ejecutan en el "commit".
Si las pruebas que desea ejecutar en el desencadenador de check-in son realmente rápidas, o si el flujo de trabajo del desarrollador forzará algún trabajo administrativo después de tal check-in de todos modos, creo que no debería importar mucho y obligar a los desarrolladores a verificar solo en cosas que ejecutan absolutamente las pruebas más básicas. (Supongo que solo ejecutaría las pruebas más básicas en dicho disparador).
Y creo que, si la velocidad / el flujo de trabajo lo permiten, es bueno no enviar cambios a otros desarrolladores que no pasan las pruebas, y solo se sabe si fallan si los ejecuta.
Escribe "commit ... to remote branch" en la pregunta, lo que implicaría que esto no es (a) algo que un desarrollador hace cada pocos minutos, por lo que una pequeña espera puede ser muy aceptable, y (b) que después Tal confirmación de los cambios en el código puede afectar a otros desarrolladores, por lo que pueden ser necesarios controles adicionales.
Puedo estar de acuerdo con las otras respuestas en "no hagas que tus desarrolladores tomen los pulgares mientras esperan" para tal operación.
fuente
Las confirmaciones rotas no deben permitirse en el tronco , porque el tronco es lo que puede entrar en producción. Por lo tanto, debe asegurarse de que haya una puerta de enlace que deben pasar antes de estar en el enlace troncal . Sin embargo, las confirmaciones rotas pueden estar totalmente bien en un repositorio siempre que no esté en el tronco.
Por otro lado, exigir a los desarrolladores que esperen / solucionen problemas antes de enviar cambios al repositorio tiene una serie de inconvenientes.
Algunos ejemplos:
fuente