En Mi Local Funciona

Technical thoughts, stories and ideas

Integración Continua de una App iOS con Travis CI

Publicado por Ignacio Sánchez Ginés el

DevOpsQAEntrega ContinuaiOS

Cada vez es más importante contar con un sistema automatizado de Integración Continua que nos permita ahorrar tiempo en los desarrollos y centrarnos en lo realmente importante, la funcionalidad de nuestra aplicación.

Travis CI es un sistema de Integración Continua especialmente diseñado para construir y testear proyectos en Github de forma automática.

Se integra de forma sencilla: Nos logamos en Travis, le permitimos la conexión contra nuestros repositorios en Github y activamos uno a uno la construcción automática en los repositorios que nos interesen.

Travis Enable Repository

La integración se hace usando webhooks, de forma transparente para nosotros. Cada vez que hagamos un push en nuestro repositorio, Travis será notificado y comenzará con la ejecución de nuestro job.

Travis nos ofrece una máquina virtual basada en OS X que se instancia en cada ejecución, por lo que tendremos un entorno limpio y aséptico en cada build.

Actualmente soporta sistemas Ubuntu y OS X. Entre los lenguajes y tecnologías soportados se encuentran: Java, JavaScript, Node.js, iOS, PHP, Python, Ruby, C/C++, C#, Go, entre otros.

Para este post he preparado un repositorio con una aplicación iOS de ejemplo hecha en Swift, junto con un test unitario.

He creado dos ramas. En una de ellas, nice-feature, el test pasa sin problemas y en la otra, bad-feature, no.

Travis Github Branches

Para que Travis compile nuestro repositorio con todas sus ramas debemos preparar un fichero YAML llamado .travis.yml y ubicarlo en la raíz del repositorio.

El ciclo de vida de un build en Travis consta de dos etapas: install y script. Cada etapa tiene varias sub etapas:

  • Fase de install:

    • before_install
    • install
  • Fase de script:

    • before_script
    • script
    • after_success / after_failure
    • before_deploy
    • deploy
    • after_deploy
    • after_script

En la fase de install podemos preparar el entorno para la ejecución de nuestro build. En la fase de script es dónde realizamos las tareas que se ejecutarán en el build.

Por ejemplo:

before_install:  
  - brew update
  - brew install sdl2
script:  
  - xcodebuild -project "MyProject.xcodeproj" -scheme "MyProject" -destination "platform=iOS Simulator,name=iPhone 6s,OS=9.2" clean build

Este fichero de configuración instala la librería SDL2 antes de ejecutar nuestro script de construcción con xcodebuild. Como ves, Travis ya está configurado para utilizar Brew.

Para testing de proyectos iOS, Travis tiene preconfigurada la herramienta xctool, que facilita el uso con respecto a xcodebuild. Si omitimos la fase de script, Travis la generará por nosotros con la configuración de xctool que le indiquemos.

Este es el fichero de configuración .travis.yml que estoy usando en el repositorio de ejemplo y que usa xctool de forma implícita:

language: objective-c  
osx_image: xcode7.2  
xcode_project: TravisExample.xcodeproj  
xcode_scheme: TravisExample  
xcode_sdk: iphonesimulator9.2  

Aunque hemos puesto language: objective-c nuestro código Swift compilará sin problemas. Únicamente le estamos diciendo a Travis que tiene que usar una máquina basada en OS X.

Si en lugar de un project queremos construir un workspace utilizaremos el parámetro xcode_workspace en su lugar.

Para que todo funcione es necesario que nuestro scheme esté compartido. Esto lo debemos configurar en Xcode, desde el menú Product > Scheme > Manage Schemes.

Xcode Shared Scheme Build

Una vez puesto el fichero .travis.yml en la raíz del repositorio y una vez hemos activado el repositorio en Travis, cada vez que hagamos un push en el repositorio, Travis lo construirá independientemente de la rama en la que estemos trabajando.

Travis Build

Además, podemos indicarle a Travis que construya también todos los Pull Request. Esto nos da una información muy valiosa de cara a la aceptación de los mismos.

Travis Enable Pull Request

He preparado dos Pull Request y Travis los ha construido. Uno de ellos viene de la rama que funciona bien. Podemos ver cómo Travis la ha construido sin problemas.

Travis Pull Request OK

El otro Pull Request, en cambio, viene de la rama donde los test estaban fallando.

Travis Pull Request KO

Ojo, para poder ver esta información debemos estar logados en Github.

De cara a la configuración del job tenemos varias versiones de Xcode para elegir:

  • osx_image: xcode7.3 (Xcode 7.3 - OS X 10.11)
  • osx_image: xcode7.2 (Xcode 7.2 - OS X 10.11)
  • osx_image: xcode7.1 (Xcode 7.1 - OS X 10.10)
  • osx_image: xcode7 (Xcode 7 - OS X 10.10)
  • osx_image: xcode6.4 (Xcode 6.4 - OS X 10.10)

Para especificar un SDK utilizaremos el parámetro xcode_sdk con este formato: iphonesimulatorX.Y donde X.Y es la versión que queremos usar.

Hay más configuraciones que podemos gestionar para compilar una App de tvOS o incluso de watchOS. Más información aquí.

Otro punto interesante es el uso de CocoaPods para la gestión de las dependencias. Si Travis ve un fichero Podfile en la raiz del repositorio ejecutará el comando pod install.

Una de las características más interesantes de Travis es la capacidad de lanzar builds paralelos con multitud de configuraciones y sistemas a la vez, por ejemplo, en DEBUG y en RELEASE, en diferentes SDKs, o incluso con diferentes sistemas operativos si así lo deseamos.

Para ello tenemos los Build Matrix. Por ejemplo, podemos pasar un array de valores para xcode_sdk y Travis lanzará nuestro job en todas sus permutaciones:

language: objective-c  
osx_image: xcode7.2  
xcode_project: TravisExample.xcodeproj  
xcode_scheme: TravisExample  
xcode_sdk:  
  - iphonesimulator9.2
  - iphonesimulator9.1
  - appletvsimulator9.0

En la versión gratuita, Travis encolará todos estos jobs, mientras que en la versión de pago podríamos lanzarlos en paralelo.

Otra cosa interesante son los deploys. Travis puede desplegar binarios en mucho sitios. Está integrado con Amazon S3, Heroku, Rackspace, Github Releases, AWS CodeDeploy, OpenShift y con muchos otros.

Por ejemplo, si queremos que para cada tag se haga una Release en Github y se adjunte un binario, esto sería lo que pondríamos en nuestro .travis.yml:

deploy:  
  provider: releases
  api_key: "GITHUB OAUTH TOKEN"
  file: "FILE TO UPLOAD"
  skip_cleanup: true
  on:
    tags: true

Como veis, Travis CI es potente, útil y gratis :) Y lo mejor es que no acaba aquí, con él podemos construir y probar prácticamente cualquier tipo de desarrollo que tengamos en Github.