Github Actions + Laravel

Hace un tiempo les conté por acá cómo configurar Travis para poder crear un ambiente de integración continua en un proyecto de Laravel.

Y como saben también, hace un tiempo estuve jugando con Github Actions para correr los tests de un proyecto de Rails.

En este post les voy a contar como hacer para configurar Github Actions para ejecutar los tests de Laravel.

El Proyecto

El año pasado en Programación Web II – TUPAR, la materia en la que soy docente, hicimos un proyecto de ejemplo en Laravel, al cual le configuramos Github Actions, para generar un ambiente de Continuous Integration (CI).

El proyecto es muy sencillo, una To Do List, que tiene usuarios comunes y usuarios que son manager. Está todo en este repo de Github.

En cuanto a los tests, tiene bastantes Unit tests y Feature Tests. Tambien agregamos un test de Dusk (browser test) muy sencillo, solo entra y mira el titulo de la página. Este último es solo a efectos de poder ejecutar este tipo de test “visuales” en un ambiente de CI.

¿Qué vamos a configurar?

En principio queremos que corran los unit y feature tests. Luego vamos a crear otro workflow para que corran los tests de Dusk y por último crear uno que nos haga un análisis estático de código.

A su vez, vamos a configurar Codecov, para poder ver visualmente el coverage que tenemos.

Unit Tests y Feature Tests

Si miramos un poco el proyecto, vamos a ver que estamos usando docker-compose para tener varios containers:

  • App: Es donde tenemos PHP
  • Web: El servidor web Nginx
  • Database: La base de datos Postgres
  • Adminer: App para poder acceder a la base.
  • Selenium: Donde vamos a tener Chrome para ejecutar los Dusk Tests

Mirando esto lo primero que vamos a necesitar para correr Unit y Feature tests es una base de datos. Por lo tanto en nuestra acción vamos a necesitar un servicio de Postgres corriendo.

Configurar Postgres

Cuando agregamos el servicio de Postgres, tenemos que configurar el usuario, la password y el nombre de la base de datos. También mapeamos el puerto de Postgres al mismo puerto de la máquina host. De esta forma, donde en el container que genera Github, vamos a poder usar la base de datos.

Un dato importante acá es la variable de entorno DB_HOST. Usen 127.0.0.1, en lugar de localhost. (Alguna vez esto me trajo problemas)

Con respecto al servicio de Postgres se agrega una línea más, que sirve para saber si el servicio está listo para atender requests. No es completamente necesario, pero puede arreglarte algún que otro lío.

Steps

Luego, lo que tenemos que agregar son los steps que vamos a necesitar.

  1. Hacer checkout del codigo, este paso nos va a traer el código al container donde se van a ejecutar los tests.
  2. Crear el .env de Laravel para que la solución funcione. Aca es importante que tengamos un .env.example en nuestro proyecto con todo pre-configurado. Esto nos sirve tanto para usarlo en Github Actions o también para cualquier miembro de nuestro equipo pueda crearse un .env muy rapido y facil. Hay que recordar siempre de hacer los ajustes en ese archivo además de en nuestro .env, ya que este último archivo no se commitea en el repo.
  3. Instalar las dependencias usando composer
  4. Generar una key para que nuestra app funcione. Esta key es la que se usa para todo lo que tenga que ver con encripción en nuestra app.
  5. Actualizamos permisos de carpetas donde van a crearse algunos archivos, para que cualquier usuario pueda escribir.
  6. Ejecutamos los tests
  7. Subimos los resultados a Codecov.

name: Laravel
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
laravel-tests:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:9.6
env:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: thisisasecretpassword
POSTGRES_DB: tasks_test
ports:
5432:5432
options: –health-cmd pg_isready –health-interval 10s –health-timeout 5s –health-retries 5
env:
DB_USERNAME: myuser
DB_PASSWORD: thisisasecretpassword
DB_HOST: 127.0.0.1
steps:
uses: actions/checkout@v2
name: Copy .env
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
name: Install Dependencies
run: composer install -q –no-ansi –no-interaction –no-scripts –no-progress –prefer-dist
name: Generate key
run: php artisan key:generate
name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache
name: Execute tests (Unit and Feature tests) via PHPUnit
run: vendor/bin/phpunit –coverage-clover=coverage.xml
uses: codecov/codecov-action@v1
view raw laravel.yml hosted with ❤ by GitHub

Dusk Tests

GitHub - JoseVte/laravel-dusk-5.1

Para los Dusk Tests, qué son los que corren en el browser, vamos a tener que agregar algunas partes más.

En primer lugar, tenemos que agregar la variable de entorno APP_URL, para que cuando ejecutemos los tests, Dusk sepa dónde tiene que ir a abrir la app en el browser.

Steps

La primer diferencia con el workflow de la sección anterior es que como tenemos una configuración para ejecutar Dusk localmente, lo que tenemos que hacer es borrarla para que no interfiera con la configuración en Github Actions.

Luego los steps son prácticamente los mismos, se suman estos:

  • Ejecutar las migraciones, esto nos va a permitir que nuestra app funcione correctamente.
  • Actualizar el Plugin de Chrome, con este paso actualizamos el binario que vamos a usar de Chrome.
  • Le damos más permisos a la carpeta de binarios de Dusk para que se puedan ejecutar.
  • Levantamos el server de artisan para poder acceder a nuestra app. Redirigimos toda la salida a /dev/null para que no interfiera con el output de nuestros tests. Es muy importante el & del final, para poder ejecutar en paralelo los siguientes steps.
  • Ejecutamos Chrome, también agregamos el & al final.
  • Ejecutamos los tests de Dusk
name: Dusk Tests
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
dusk-tests:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:9.6
env:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: thisisasecretpassword
POSTGRES_DB: laravel
ports:
5432:5432
options: –health-cmd pg_isready –health-interval 10s –health-timeout 5s –health-retries 5
env:
DB_USERNAME: myuser
DB_PASSWORD: thisisasecretpassword
APP_URL: http://127.0.0.1:8000
steps:
uses: actions/checkout@v2
name: Copy .env
run: php -r "copy('.env.example', '.env');"
name: Remove .env.dusk.local
run: rm .env.dusk.local
name: Install Dependencies
run: composer install -q –no-ansi –no-interaction –no-scripts –no-progress –prefer-dist
name: Generate key
run: php artisan key:generate
name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache
name: Run Migrations
run: php artisan migrate
name: Upgrade Chrome Driver
run: php artisan dusk:chrome-driver `/opt/google/chrome/chrome –version | cut -d " " -f3 | cut -d "." -f1`
name: Change permissions to dusk
run: chmod -R 0755 vendor/laravel/dusk/bin/
name: Run Laravel Server
run: php artisan serve > /dev/null 2>&1 &
name: Start Chrome Driver
run: ./vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &
name: Execute dusk tests
run: php artisan dusk
view raw dusk.yml hosted with ❤ by GitHub

Análisis estático de código (Phan)

Por último, podemos crear otro workflow para chequear el estilo de código que tenemos.

Este es mucho más sencillo, porque al ser un análisis estático de código, no necesitamos tener la app corriendo. Solo necesitamos ejecutar Phan

name: Static Code Analysis
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
code-analysis:
runs-on: ubuntu-latest
steps:
uses: actions/checkout@v2
name: Install Dependencies
run: composer install -q –no-ansi –no-interaction –no-scripts –no-progress –prefer-dist
name: Run Phan
run: vendor/bin/phan –no-progress-bar –allow-polyfill-parser –output-mode checkstyle | vendor/bin/cs2pr –graceful-warnings –colorize | true
view raw static.yml hosted with ❤ by GitHub

Espero que les sirva y puedan usarlo en sus proyectos Laravel.

Github Actions + Rails

Integración y Distribución Continua (CI/CD) con GitHub Actions - Thinking  In Swift

En este post quería mostrarles un poco de la potencia y lo fácil que es usar Github Actions, pero primero…

¿Qué es Github Actions?

Si leemos lo que dice la web nos encontramos con esto:

Automatiza, personaliza y ejecuta tus flujos de trabajo de desarrollo de software directamente en tu repositorio con GitHub Actions. Puedes descubrir, crear y compartir acciones para realizar cualquier trabajo que quieras, incluido CI/CD, y combinar acciones en un flujo de trabajo completamente personalizado.

Pagina de Github Actions

En definitiva nos permite automatizar cosas en nuestro Repo. No solo continuous integration, sino manejo de issues en el repo, darle la bienvenida a los nuevos usuarios, y muchísimas cosas más.

Hubo un hackaton creado en Dev.to para que los devs puedan crear acciones en diferentes categorías. Algunas de las cosas que surgieron fueron muy locas.

Se pueden hacer mil cosas, desde jugar a un juego a mandar un mensaje por telegram. Nosotros lo vamos a usar para tener un ambiente de CI en nuestra aplicación Rails.

¿Qué vamos a hacer?

Vamos a partir de un proyecto de Rails que hice hace algún tiempo que se llama Beer API.

Esta aplicación es una Api muy sencilla que hice para hacer algunas pruebas de diferentes frontends, con diferentes tecnologías, usando la misma API.

Este proyecto tiene corriendo algunos tests de Rspec.

Workflow en Github Actions

Lo primero que tenemos que hacer en nuestro proyecto de Github es hacer click en Actions.

Ahora buscamos en la sección Continuous integration workflows la acción que más nos convenga. En este caso Ruby y hacemos click en Set up this workflow.

Esto nos abre un editor con un archivo pre-creado.

Modifiquemos el workflow

name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
rspec:
name: Rspec
runs-on: ubuntu-latest
services:
postgres:
image: postgres:11
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
5432:5432
options: –health-cmd pg_isready –health-interval 10s –health-timeout 5s –health-retries 5
env:
POSTGRES_HOST: 127.0.0.1
steps:
uses: actions/checkout@v2
uses: actions/setup-ruby@v1
with:
ruby-version: 2.7.2
name: Install Dependencies
run: |
gem install bundler
bundle install
name: Run Migrations
run: bundle exec rails db:create db:migrate RAILS_ENV=test
name: Run Rspec
run: bundle exec rspec
view raw main.yml hosted with ❤ by GitHub

Como yo no necesitaba la estrategia de Matrix, para probar esta api en múltiples versiones de Ruby, borre todo lo relacionado a eso y solo deje una Ruby 2.7.

Lo primero que hice fue cambiar el name por CI (acronimo para Continuous Integration).

Luego en la sección de jobs cree uno que se llama rspec, que tiene el servicio de postgres. Esto lo que va a hacer es levantar un container con Postgres, para que desde el container donde se ejecutan los tests pueda usarlo y ejecutarlos usando una base de datos.

Agregué una sección de options, esto sirve para que los tests ejecuten recién cuando el servicio de la base de datos esté funcionando y no nos fallen los tests porque no se puede conectar. Esto es una configuración que es necesaria para evitar fallas del CI aleatorias.

Luego en la sección env, configuré el host donde va a correr postgres, en este caso 127.0.0.1. En esto tuve algún problema, si no lo ponia o si ponia localhost, por eso les recomiendo agregarlo.

Por último la sección de steps, los primeros son los que vienen por default (el de setup de ruby es un poco distinto porque no uso la matrix) y después agregue:

  • Install Dependencies: Ejecuto bundle install para traer todas las gemas que necesito.
  • Run Migrations: Creo la base de datos y ejecuto las migraciones
  • Run rspec: Ejecuto los tests.

Más Jobs

En este mismo workflow yo podría poner múltiples jobs, en el caso de Beer API, agregué un job que corre Rubocop, para el estilo del código.

Para eso en la sección de jobs agregue uno nuevo que se llama rubocop con la siguiente configuración.

jobs:
rubocop:
name: Rubocop
runs-on: ubuntu-18.04
steps:
uses: actions/checkout@v1
uses: actions/setup-ruby@v1
with:
ruby-version: 2.7.2
name: Install Rubocop
run: |
gem install rubocop
gem install rubocop-rails
gem install rubocop-rspec
name: Run Rubocop
run: rubocop
view raw main.yml hosted with ❤ by GitHub

Para verlo funcionando solo nos queda hacer commit de nuestro archivo de configuración y listo.

Ahora cada vez que se abra un Pull Request, o haga un Merge a main, se van a ejecutar los tests y además el chequeo estático de la sintaxis.

Espero que les sirva para tener mejores prácticas en sus proyectos.

Nos leemos.

Travis CI + Laravel

En una de las materias que doy en la facultad (Programación Web II – TUPAR), estamos continuando un proyecto para los Bomberos de Trenque Lauquen.

Es un proyecto que comenzaron unos alumnos como trabajo de fin de carrera. Es una aplicación web para administrar el cuartel: materiales, vehículos, bomberos, asistencias, promociones de personal, etc. Si bien aún esta en Alpha, es un buen proyecto para aplicar muchísimos de los conceptos de Programación Web.

Este año decidimos enseñar Docker y Laravel, y uno de los conceptos claves que queremos que los alumnos aprendan es la calidad de código, hacer unit test e integration tests, probar un poco de TDD y tener la experiencia de usar un ambiente de Integración Continua.

La idea de este post es poder poner en forma de tutorial como configurar Travis-CI, para hacer el build de una aplicación escrita en Laravel, con tests de unidad y tests de integración.

Laravel y Testing

Laravel es un framework de PHP, según su página web: The PHP Framework For Web Artisans.

Tiene muchas features muy interesantes, como las migrations, el comando artisan, los templates de Blade, Eloquent, y más.

Uno de los puntos fuertes es lo bien integrado que está con la creación de test alrededor de la solución.

Obviamente que para los tests de unidad, usa PHPUnit, que ya está más que probado y es el standard de la industria. Pero para los tests de integración, usa Dusk, que es una herramienta que automatiza los browser tests y esta integrada con Artisan para correr.

Configurando de Travis

Lo primero que vamos a hacer es crear el archivo travis.yml, este es el archivo que le dice a Travis como tiene que crear el container para poder ejecutar los tests de nuestra aplicación.

.env.travis

No Description

Hasta llegar a este archivo terminado tuve unas cuantas luchas. En primer lugar seguí la explicación de la documentación oficial, sin ninguna suerte. Después de buscar mucho en Google, encontré a un post en Japones, en el cual @sutara_lumpur, explicaba como el había hecho para configurarlo y tenia un repo en Github con la solución andando.

Obviamente le agradecí como corresponde:

Ignacio Jonas on Twitter

@sutara_lumpur Thanks for your code on how to configure @travisci to run #lareveldusk.

Vamos a explicar un poco que dice este archivo, las partes que a mi me generaron más dudas, hay algunas partes que se auto-explican.

  • sudo: required : Para poder ejecutar Chrome necesitamos permisos de root en el container.
  • dist: trusty : Como necesitamos ejecutar Chrome, entonces nuestro container tiene que ser un Linux, en este caso Ubuntu Trusty.
  • services : Vamos a necesitar una base de datos para probar nuestra aplicación, en este caso Postgres.
  • addons:  Necesitamos que nuestro container tenga Chrome instalado, para correr los test de integración.
  • install: Ejecutamos composer install para que instale todas las dependencias.
  • before script:
    • Creamos la base de datos, el nombre tiene que coincidir con lo que luego pongamos en el .env.travis.
    • Creamos el archivo .env, copiando el archivo .env.travis con toda la configuración.
    • Generamos la key para que nuestra aplicación Laravel funcione.
    • Migramos la base de datos y además le cargamos los datos. En este punto podemos obviar el –seed, si es que vamos a regenerar la base por cada test que ejecute.
  • script
    • Ejecutamos Chrome y lo ponemos a escuchar en un puerto, en nuestro caso 9222, este puerto tiene que coincidir con el puerto que usemos en DuskTestCase.php
    • Levantamos el server para poder acceder a nuestra aplicación usando artisan, redirigir el output a /dev/null es opcional. De esta forma nos queda mas limpio el log de Travis.
    • Ejecutamos los tests de integración.
    • Ejecutamos los tests de unidad, y generamos el archivo de coverage
  • after_success
    • Creamos el reporte de coverage.

Ya tenemos nuestro archivo de configuración de Travis. Ahora creemos nuestro archivo .env.travis.

APP_ENV=testing
APP_DEBUG=true
APP_KEY=
APP_URL=http://localhost:8000
DB_CONNECTION=pgsql
DB_HOST=localhost
DB_PORT=5432
DB_DATABASE=bomberos_test
DB_USERNAME=postgres
DB_PASSWORD=
CACHE_DRIVER=array
SESSION_DRIVER=file
QUEUE_DRIVER=sync
TRAVIS=true
CHROME_HOST=http://localhost:9515

view raw
.env.travis
hosted with ❤ by GitHub

Este archivo, en nuestro caso, es casi una copia de el .env que tenemos en nuestra maquina local. La diferencia son:

  • DB_DATABASE: Ahora apunta a la base de datos que creamos en Travis.
  • DB_USER: Es el usuario de la base de datos del container de Travis.
  • DB_PASSWORD: Es vacío, porque el default password del usuario postgres en Travis es vacío.
  • TRAVIS: Es para indicar que estamos corriendo en Travis, esto me va a servir para hacer algunos cambios en el archivo DuskTestCase.php.
  • CHROME_HOST: Es la URL donde escucha Chrome.

Por último, hacemos un pequeño cambio en el archivo DuskTestCase.php

Este cambio nos ayuda a poder ejecutar los tests tanto en el ambiente de desarrollo como en Travis.

<?php
...
protected function driver()
{
$options_array = env('TRAVIS', false) ? ['–disable-gpu','–headless','–window-size=1100,600'] : [];
$options = (new ChromeOptions)->addArguments($options_array);
return RemoteWebDriver::create(
env('CHROME_HOST', 'http://selenium:4444/wd/hub'), DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY, $options
)
);
}
?>

view raw
DuskTestCase.php
hosted with ❤ by GitHub

En nuestro caso tenemos un ambiente de desarrollo en Docker, en el cual tenemos los siguientes containers:

  • app: Corremos PHP.
  • web: Corremos el Server (nginx).
  • database: Corremos Postgres.
  • adminer: Corremos adminer, para poder administrar la Base de Datos.
  • selenium: Corremos Chrome y dentro de este container corremos los test de integración.

Para correr los Tests de Integración, tenemos que usar la URL http://selenium:4444/wd/hub y si pasamos las options de headless, disable-gpu, etc. se hace muy lento, al punto de fallar por timeout.

Una vez que subimos estos cambios y configuramos Travis para que integre nuestro repositorios, la aplicación buildea.

 

Y tenemos el reporte de coverage, de lo que cubren los test de unidad. Como vemos es de un 3%, muy poco, pero ahora que lo podemos medir, lo podemos mejorar.

Espero que les sirva, nos estamos leyendo.

Travis CI – Integración Continua fácil!

 

Hace poco estuve trabajando en un proyecto en Ruby, el cual tenía configurado Travis como servicio de integración continua.

Me llamo muchísimo la atención lo sencilla que es la configuración y la buena documentación que tiene. Con un simple archivo .yml y unas pocas líneas tenemos configurado nuestro servidor de integración continua, que incluso puede correr nuestra suite de tests en diferentes versiones de Ruby paralelamente.

large_Mascot-fullcolor-png

Travis tiene soporte para multiples lenguajes, yo solo lo probé con Ruby, pero estoy seguro que voy a seguir haciendo algunas pruebas más con algún otro lenguaje como PHP, C# o Go.

Una última característica genial es que es gratis para proyectos Open Source.

Como funciona Travis CI

Tenemos que tener una cuenta de Github y entrar a travis-ci.org. Autorizamos a Travis a acceder a nuestros repositorios y voilà todo listo.

2016-03-09_23-56-33

Los pasos a seguir son:

  • Seleccionar el repositorio que queremos, haciendo click el botón que lo habilita.
  • Subir a nuestro repositorio el archivo .travis.yml con la configuración.
  • Hacemos un push a nuestro repositorio y automáticamente se ejecuta el primer build.

Travis.yml

Vamos a usar un ejemplo de un proyecto en Ruby.

language: ruby
sudo: false
cache: bundler
rvm:
2.1.0
2.2.1
before_script:
chmod +x build_travis.sh
script: "./build_travis.sh"

view raw
travis.yml
hosted with ❤ by GitHub

Como ven la configuración es sencilla, con las palabras claves nos damos cuenta que significa:

language: Es el lenguaje en el que esta escrita nuestra app. Ejemplo: ruby, go, rust, scala, etc.

sudo: Si vamos a ejecutar la suite como super usuarios. En nuestro caso vamos a hacerlo como usuarios normales.

cache: Los que programamos en Ruby sabemos que hacer un bundle install suele tardar un buen rato, es por eso que con esta opción, podemos tener el cache de la instalación de bundler hasta que nuestro Gemfile cambie, acelerando la ejecución de nuestros tests.

rvm: Esta opción nos permite tener diferentes versiones del lenguaje contra las cuales queremos probar nuestro código. Algo muy bueno de esto, en caso de usar Ruby, es que podemos probar nuestro código contra versiones de jRuby y con diferentes JDKs.

before_script: Podemos ejecutar comandos antes de ejecutar el script de build. En este ejemplo estoy dándole permisos de ejecución al script que va a correr mi build.

script: Es el script (o comandos) para ejecutar el build. En este caso arme un script de bash que contiene solo una linea bundle exec rake spec. Podría incluso escribir esta linea en el este archivo sin necesidad de llamar a un script para hacerlo.

Hay bastante mas posibilidades de configuración y de hacer cosas con Travis, pero en este post pretendo cubrir solo el escenario de correr una suite de test de Rspec.

Configuraciones en la aplicación

Haciendo click en More Options -> Settings accedemos a las configuraciones de Travis.

2016-03-10_00-27-28Podemos ver que tenemos activado el build con cada push a nuestro repositorio. Si nosotros hacemos un push a master o cualquier branch, Travis va a detectarlo y ejecutar un build.

También vemos que esta activado el build pull request. Esta característica es muy útil, ya que podemos estar trabajando en una algo nuevo, enviamos un PR para que nos revisen el código, y podemos asegurarnos que el código que vamos a mergear esta ‘Verde’ y no va a romper el build.

travispr

Vemos también una configuración de limitar jobs concurrentes. Esto nos sirve cuando tenemos tests de integración y estamos accediendo a la misma base de datos o API. No podemos ejecutar tests concurrentemente ya que los datos de prueba no serían consistentes. En este ejemplo no hay necesidad de limitar esto, ya que estoy buildeando una aplicación sencilla de una calculadora.

Por ultimo, si prestamos atención abajo de los botones están las Environment Variables. Estas variables las podemos configurar en el archivo .travis.yml, pero podemos también podemos configurarlas aquí. Podríamos poner en estas variables una conexión a una base de datos o alguna configuración del ambiente. Si es información sensible podemos ocultarla simplemente haciendo que la información no se muestre en el log con el botón al lado de la carga de la variable.

Esta del build en README.md

Un último detalle es que cuando usamos Travis, podemos tener el estado de nuestro build en nuestro repositorio.

Para eso podemos agregar al README.md la línea que nos da travis cuando hacemos click en el estado de nuestro build y seleccionamos Markdown como se puede ver en la siguiente imagen.

markdown

Con lo sencillo que es configurar Travis y si estas haciendo un proyecto open source, ya no hay mas excusas para no tener integración continua.

 

Debian + Jenkins + PHP + GitHub

Preparando una taller para unos alumnos sobre Integración Continua, configure un servidor utilizando Jenkins. A continuación los pasos que fui siguiendo para instalar las herramientas necesarias.

 

Herramientas que vamos a utilizar

Paso a Paso

Instalar Debian

Lo primero que tenemos que hacer es instalar Debian, en el cuadro de “Software Selection” elegimos:

  • Web Server
  • SSH Server
  • Mail Server

Software Selection

Instalar PHP y algo más…

Nota: Para los pasos que siguen, todos los comandos se ejecutan en una terminal como root.

Lo siguiente que vamos a hacer, como estamos creando un servidor de integración continua para PHP, es instalar PHP y Pear.

apt-get install php5 php5-dev php5-xdebug php-pear

Instalar Jenkins

Los siguientes pasos están tomados de la documentación oficial de Jenkins.

wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
apt-get update
apt-get install jenkins

QA Tools

Para instalar las QA tools vamos a usar Pear.

pear upgrade PEAR
pear config-set auto_discover 1
pear install pear.phpqatools.org/phpqatools
pecl install xdebug

Instalar Apache Ant

Como nuestro template para contruir proyectos PHP va a utilizar Ant, vamos a instalarlo.

wget http://www.us.apache.org/dist/ant/binaries/apache-ant-1.9.2-bin.tar.gz
tar xvfvz apache-ant-1.9.2-bin.tar.gz -C /opt
ln -s /opt/apache-ant-1.9.2 /opt/ant

Configurar la variable de entorno para que podamos ejecutar Ant desde cualquier lugar

sh -c 'echo ANT_HOME=/opt/ant >> /etc/environment'
ln -s /opt/ant/bin/ant /usr/bin/ant

Para verificar que Ant se instalo bien, ejecutamos:

ant -version

Instalar Git

Por último, para que Jenkins pueda traer el código a integrar desde GitHub, necesitamos instalar git

apt-get install git-core

Luego tenemos que generar una RSA key para el usuario jenkins (el usuario que ejecuta jenkins). Para eso desde una consola de root, cambiamos el usuario a jenkins y generamos la key.

su - jenkins
ssh-keygen -t rsa -C "your_email@example.com"

Luego copiamos nuestra clave publica.

Para eso podemos hacer:

cat .ssh/id_rsa.pub

Copiamos la salida del comando cat y la pegamos en SSH keys en nuestro usuario de GitHub.

SSH Keys

 

Por último, con el usuario Jenkins, ejecutamos

ssh -T git@github.com

Y aceptamos github.com como parte de nuestros know hosts.

KnowHosts

Últimos detalles

Para poder acceder a Jenkins desde otra maquina, vamos a tener que configurar IP Tables para que nos permita acceder al puerto 8080, desde afuera. Para eso podemos ejecutar, nuevamente como root.

iptables -A INPUT -p tcp --dport 8080 -j ACCEPT

Ahora ya tenemos Jenkins andando en nuestro Debian.

Jenkins Home Page

En proximos posts voy a mostrar como configurar un proyecto PHP en Jenkins.

Team City – Invalid drive specification error

El otro día en el trabajo, tuve que configurar Team City, para que haga un deployment automático de una aplicación, cada vez que alguien del equipo subiera código nuevo al repositorio.

Lo que primeramente hice fue, compartir la carpeta de la maquina donde quería hacer el deployment (en mi caso un servidor de integración). Cuando la compartí, no le puse usuario ni password, para que sea más sencillo.

Después configure una nueva tarea debajo de las de build, para que copie los bits recién compilados a la carpeta en este servidor.

La tarea tenia simplemente el comando

xcopy C:\Temp\App\ \\ServerDeIntegracion\App\ /S /Y

Cuando se ejecutaba esta tarea me daba un error:

Invalid drive specification

Haciendo otras pruebas usando robocopy en lugar de xcopy tuve un error de Access Denied:

errorRobocoy

La solución que encontré fue crear un archivo bat con los siguiente comandos:

net use t: \\ServerDeIntegracion\App\ [Password] /user:dominio\usuario
xcopy C:\Temp\App\ \\ServerDeIntegracion\App\ /S /Y

Lo que hace el primero es hacer disponible el recurso de la red en la sesión de Team City y luego de tenerlo disponible ejecuta la copia de archivos.

Este archivo bat lo llamo desde una tarea de tipo Command Line en Team City.

TareaTeamCity

 

Espero les sirva!

Nos leemos

Integración Continua – Team City + GIT + MVC4

Dentro de los desarrollos de aplicaciones, utilizando metodologías agiles existen muchisimas buenas practicas, que nos ayudan a llegar a una mejor calidad del producto que estemos desarrollando. Una de estas es implementar un servidor de intregración continua.

En este post vamos a explicar, cómo instalar y configurar un build server, utilizando Team City en un Windows 7. Este build server va hacer build de nuestra aplicacion MVC 4 y genere un paquete de instalación.

Para los que no saben que es la integración continua o continuous integration es:

Un modelo informatico propuesto inicialmente por Martin Fowler que consiste en hacer integraciones automáticas de un proyecto lo más a menudo posible para así poder detectar fallos cuanto antes.

Manos a la obra

Pre-requisitios

Una maquina con Windows 7, Visual Studio 2010 y MVC 4.

El instalador de Team City 7.1

Ahora si, con todo esto, manos a la obra.

Instalación de Team City

En nuestra instalacion de Windows 7, ejecutamos el instalador.

Click Next

Team City 1

 

Click I Agree

Team City 2

 

Seleccione la carpeta donde quiere instalar Team City y click Next

Team City 3

 

Seleccione toda las opciones. Click Next
Team City 4

 

Seleccione el puerto donde va a atender la web de Team City. Click Next.

Team City 6

Seleccione directorio donde Team City va a guardar las configuraciones. Click Next.

Team City 5Configure el agente que va a hacer el build (configuracion por defecto). Click Save

Team City 7

Seleccione los usuarios para ejecutar el agente de build, (en ambos casos configuracion por defecto). Click Next

Team City 9

Seleccionar ambos. Click Next

Team City 10

En este punto Team City ya está instalado en nuestra maquina,

Configuración de Team City

Luego de aceptar la licencia, seleccionando accept license agreement un haciendo click en Continue.

Team City 13Completamos el nombre de usuario y contraseña del usuario que va a ser nuestro administrador. Click  Create Account.

Team City 15En este momento podes hacerte un marcador en tu navegador de la URL de Team City, para tenerlo bien a mano.

En la página principal de Team City hacemos click en Create a Project.

Team City 16

Lo primero que hacemos es ponerle un nombre al proyecto. Click Create.

Team City 17

Click Create Build Configuration.

Complete el nombre con el que se va a identificar el build. Por ejemplo si en su poryecto se van a compilar mas de una solución, un buen nombre sería el nombre de cada solución,

Click VCS Settings

Team City 19

Click Create and Attach a new VCS Root.

Team City 20

Seleccione Type VCS -> Git.

  • VCS Root Name: Dirección del repositorio GIT( accesso ssh) + #master
  • Fetch URL: Dirección del repositorio GIT.
  • Default Branch: master

En la sección Autentication Settings

  • Authentication Method: Private Key
  • Private Key Path: Dirección de la key ssh privada que tiene permiso de accesso al repositorio en GitHub.

Click Test Connection.

Team City 22

Si la conexión se pudo establecer, vamos a obtener un cartel como el siguiente

Team City 23Click Save.

Dejar todas las configuraciones por defecto. Click Add Build Step.

Team City 24

  • Runner Type: MSBuild
  • Step Name: Un nombre que identifique el paso de build.
  • Build Path File: Dirección dentro del repositorio al proyecto que vamos a compilar.
  • MSBuild Version: Framework 4.0
  • MSBuild Tool Version: 4.0
  • Run Platform: x64
  • Targets: PublishtoFileSystem (esto lo vamos a configurar más adelante en el archivo del proyecto)

Click Save

Team City 25

Click Build Parameters

Team City 26

Click Add New Parameters, agregar uno con las siguientes características:

  • Name: PublishDestination
  • Type: System
  • Value: Lugar en el disco donde queremos que se genere el paquete de instalación.

Click Save

Team City 28Ahora en General Settings agregar a la sección Artifacts Path la dirección donde se va a generar el paquete. Click Save

Team City 29

Configurando un trigger

Si queremos que al momento de que cualquier miembro del equipo suba código al repositorio, el build server compile nuestra solución y genere un paquete instalable, tenemos que configurar un trigger en Team City, para esto vamos a la sección 5 de las configuraciones del proyecto Build Trigger. Hacer click en Add new trigger.

Team City 32

Seleccionar VCS Trigger, y chequear Trigger a build on each check-in. Click Save.

Team City 33

Ahora cada vez que alguien suba algún cambio al repositorio, el agente de Team CIty va a ejecutar la compilación de nuestra solución.

Nuestra solución MVC 4

Para este ejemplo, hice una aplicación “Hello World” en MVC4, para poder compilar la solución utilizando un repositorio público de GitHub. El que quiera usarlo, solo tiene que bajarlo.

Dentro del proyecto de la solución, tenemos que agregar un nuevo Target. Esto nos va a servir para indicarle a MSBuild como generar y donde dejar el paquete instalable.

Para hacer esto tenemos que, hacer unload del proyecto. Para eso hacemos click con el botón derecho en el proyecto y seleccionamos Unload Project.

Visual Studio 1

Botón derecho sobre el proyecto y click Edit…

Visual Studio 3Buscar la sección Target y debajo de la existente crear una nueva con el siguiente contenido:

<Target Name="PublishToFileSystem" DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
<Error Condition="'$(PublishDestination)'==''" Text="The PublishDestination property must be set to the intended publishing destination." />
<MakeDir Condition="!Exists($(PublishDestination))" Directories="$(PublishDestination)" />
<ItemGroup>
<PublishFiles Include="$(_PackageTempDir)\**\*.*" />
</ItemGroup>
<Copy SourceFiles="@(PublishFiles)" DestinationFiles="@(PublishFiles->'$(PublishDestination)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="True" />
</Target>

view raw
gistfile1.xml
hosted with ❤ by GitHub

 

Visual Studio 4

Guardar el proyecto y subir los cambios a GIT.

Una vez subido los cambios a GIT, el build server ejecutará automáticamente el build de la aplicación. Si vamos a la página principal de Team City veremos que el build esta corriendo.

Cuando éste termina, en la sección Artifacts vamos a encontrar todo lo que se generó en el paquete de salida.

Team City 30

Si hacemos click en Artifacts vamos a ir a una sección donde podemos bajar el archivo .zip con el paquete de instalación.

Team City 31

Ahora ya pueden decir que número de build de su aplicación están instalando en un servidor, llevar tracking de las features que se van agregando y en que build están presentes, integrar toda la aplicación en cada commit y demás.

Espero que les sirva este post y puedan implementar un build server en todos sus proyectos.

Nos leemos!