jueves, 26 de enero de 2017

TestComplete y Git

En un grupo están trabajando con TestComplete, una herramienta que permite automatizar aplicaciones de escritorio (y muchas más cosas).
Estaban manteniendo las pruebas con versionado por directorios y decidimos moverlos a git.

La solución es sencilla, ya que TestComplete tiene integración con git.

Agregar en la raíz un archivo .gitignore con contenido
Log/

Luego se pueden seguir los pasos normales para subir un proyecto existente a un repo. Por ejemplo en GitHub.


¿Y que pasa si te olvidás del paso del .gitignore?

En ese caso, la subida de los logs puede tardar mucho tiempo, incluso dar timeout. En nuestro caso, contenido completo de la carpeta del proyecto con sus logs pesaba 500Mb!

¿Cómo borrar completamente algo de Git?

Quitar de la versión

En este caso, para borrar todos los directorios Log


find . -name Log -print
Tomar de la salida todos los directorios resultantes y armar lineas como la que está a continuación, que quitan los directorios del repo local, pero lo dejan fisicamente.
git rm -r --cached <directorio>/Log

Luego podés validar que estén borrados en Git.
Ahora si, agregá el .gitignore (como está indicado arriba).
Y comitear y subir al repo. 
git status
git commit -m ‘borrar logs’
git push

Validar que en repo remoto no esten los Logs.


Quitar de toda la historia

No es común querer modificar la historia de Git. Y la forma estandard brindada por git es lenta.
Usamos una herramienta llamada BFG.

git clone --mirror https://github.com/<user>/<repo> <repo>_mirror
cp -a <repo>_mirror/ <repo>_backup/
cd <repo>_mirror
java -jar ~/Downloads/bfg-1.12.14.jar --delete-folders Log
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push


En nuestro caso, pasamos de un repositorio de más de 1Gb a uno de 380Mb.

miércoles, 18 de enero de 2017

Desarrollo ágil de Software - stack Python

Soy uno de los facilitadores del curso Desarrollo Ágil de Software (DAS) de Kleer.
Lo solemos hacer con Ruby (alguna vez lo hemos dado en Java y C#).

Afortunadamente, hace poco lo hicimos en Telefonica I+D Chile y nos pidieron hacerlo con Python ¡Gracias!

Le comento mi experiencia y les dejo la referencia del ambiente https://github.com/jgabardini/csdpy, lo pueden reproducir en Linux (o la virtual de DAS con Mint)

Resumen de Stacks

En el ambiente Ruby, las herramientas son: bundle, rspec, cucumber, webrat/capybara, sinatra con erb.

En el ambiente Python: virtualenv y pip, behave, splinter, flask con jinja2. Además, usé un plugin de Jenkins: ShinningPanda.

Python

No hubo problemas porque la mayoría ya programaba en Python (había dos o tres personas sin conocimiento, pero que se sumaron rápido).
Algunos prefirieron usar sus ambientes, por los editores (sin usar la virtual). La virtual tiene Gedit, ellos usaban Visual Studio Code, vim, ....
Usé Python 3.4 (en vez de 2.7 que es el default en la virtual de DAS).
Para manejar versiones y ambientes use virtualenv y pip.

Unittests

Usé nosetests como test runner. Extrañé la sintaxis BDD (de rspec), pero ellos no 😉
Para el próximo (que por suerte es la semana que viene), daré instrucciones concretas sobre la estructura de directorios. Los desarrolladores Python NO tienen el mantra Convention over configuration, cada uno lo hace distinto si los dejas libres 🙌. Y explicaré las reglas de descubrimiento de pruebas de nosetests, eso hubiera ayudado (tests/xxx_test.py).

Flask

El código mínimo es un poco más largo que el de Sinatra y, como yo no tengo tanta práctica, no lo escribí de cero. Usé el código del repo csdpy desde el inicio.
Cuando falla el routing u otro error, no es tan amistoso como Sinatra, no muestra una página 500 con información de que falta.
Usar annotation para definir el routing, obliga a tener funciones por cada mapeo, y es natural que la misma función cubra varios métodos HTTP. Cometí muchos errores de nombre método duplicado, acostumbrado a los bloques de Ruby.
Los asistentes no tuvieron mucho problemas (o los resolvieron).
Nuevamente, Flask es menos prescriptivo que Sinatra. Yo propuse una estructura de directorios. 
El motor de templates, Jinja2, lo usé simplificado. Sin layout, bloques ni herencia. Es el motor usado en  Django.

Behave

Sigue bastante la idea de Cucumber, excepto que los pasos son distintos para cada palabra clave (Given/When/Then). En Cucumber, un paso está definido solo por el texto. En Behave los pasos se definen por la combinación palabra clave + texto. Tuve el mismo problemas con nombres de métodos repetidos que en routing de Flask.
No propone pasos con regex  "automáticas". Uno debe agregar los parámetros a mano.

Splinter

Usé Splinter que equivale a webrat/capybara. Pinta muy bien. Tiene una API muy parecida a WebDriver y puede usar los driver de WebDriver, o flask (me parece que inprocess, pero no lo encontré la documentación).


Configuración de Jenkins

Para correr tareas que requieren virtualenv, use un plugin ShinningPanda. Todas las tareas configuradas como shell.
Para que corra el behave tuve que agregar un package: behave-jenkins.

Conclusiones

Hacer la migración de Ruby a Python me llevó un día neto de trabajo. Bien sencillo.
Luego de 3 años de programar principalmente con Ruby, me sentí raro en Python. Me falta práctica. Por suerte, la semana que viene volvieron a pedirme, esta vez en Córdoba, que hagamos el curso en Python 😎