Ambientes de desarrollo en Docker + VSCode

Hace unos meses que estuve probando y usando un poco una extensión de Visual Studio Code que se llama Remote Containers. La verdad que me pareció super simple, cómodo y muy potente.

Remote Containers te ayuda a tener un ambiente de desarrollo para muchísimas tecnologías en 5 minutos.

Para este ejemplo voy a usar una aplicación de Ruby on Rails default.

¿Qué necesitamos?

Para seguir este mini tutorial necesitas tener instalado:

Setup

Para empezar abrimos VSCode, en una carpeta nueva y vamos a la parte de Extensions, ahí tenemos que instalar la extensión Remote Containers.

Una vez instalada, vamos a poder usarla:

  • Haciendo click en el icono de abajo a la izquierda.
  • Abriendo la consola de comandos (Command Palette) en el menú View o con el comando CMD + Shift + p (en Mac).

Crear el container

Sabemos que vamos a estar trabajando en un proyecto de Ruby on Rails, entonces abrimos la consola de comandos y buscamos: Remote-Container: Add development container…

Una vez dentro de ese menu, buscamos Ruby on Rails y luego la versión de Ruby que queramos usar, al momento de este post, la última disponible es 2.7, aunque ya salió Ruby 3.0.

Esto nos va a crear una carpeta con 2 archivos:

  • devcontainer.json: Donde esta toda la configuración del ambiente.
  • Dockerfile: Es la imagen de Docker que vamos a usar.

Ambos archivos estan muy bien documentados y tienen secciones que se pueden descomentar para poder hacer que se instalen gemas adicionales, paquetes de Node, etc.

En principio, lo único que vamos a hacer, es descomentar en devcontainer.json la parte de forwardPorts. Así vamos a poder conectarnos desde el browser (en nuestra máquina) a la aplicación que va a estar corriendo en Docker. Entonces configuramos el puerto 3000 que es el default en las apps de Rails.

// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.158.0/containers/ruby-rails
{
"name": "Ruby on Rails",
"build": {
"dockerfile": "Dockerfile",
"args": {
// Update 'VARIANT' to pick a Ruby version: 2, 2.7, 2.6, 2.5
"VARIANT": "2.7",
"NODE_VERSION": "lts/*"
}
},
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"rebornix.Ruby"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [3000],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "ruby –version",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}
view raw devcontainer.json hosted with ❤ by GitHub

Probando el ambiente

Ahora vamos a probar el ambiente, para eso, usando la consola de comandos buscamos Remote-Containers: Reopen in Container

Esto nos va a re-abrir Visual Studio Code y nos va a indicar, donde esta el icono de Remote Containers, si estamos viendo el código dentro de un container.

Ahora si, abrimos la terminal (Ctrl + ` o desde el menu Terminal) desde donde vamos a poder ejecutar comandos dentro del container. Por ejemplo podemos ver que versión de Ruby y de Rails tenemos instalado.

Ahora podemos ejecutar, en esa consola, el comando de Rails para crear una app.

rails new MyApp

O si, como yo, preferís que el proyecto quede al nivel de la carpeta que creaste, anda un nivel para arriba y ejecuta.

rails new [nombre-de-la-carpeta]

Una vez que terminó, entramos a la carpeta del proyecto y ejecutamos rails s para poner a andar el web server.

Entramos en nuestro browser a http://localhost:3000 y voilà, nuestra app de Rails está corriendo dentro del container y podemos usarla desde nuestro browser.

El próximo paso será poder configurar el ambiente para que no use SQLite, sino Postgres o alguna otra base de datos. Pero eso es para otro post.

Espero que lo puedan usar en sus proyectos.

Nos estamos leyendo.

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.

[Fix] SharePoint 2010 – Estilos en el calendario

 

Hace un tiempo, en el trabajo, tuvimos que hacer una presentación de una aplicación a nuestros clientes, no solo a ellos sino a gente que iba a usar la aplicación, a mi jefe y muchos más.

Como siempre el tiempo antes de la Demo se aprovecha para poner a punto todo y revisar que nada esté fallando, y tambien en ese tiempo es donde se encuentra siempre algun bug.

Mientras cargabamos un campo de fecha, al desplegar el calendario nos dimos cuenta que no tenia estilos, se veía como este:

calendar

Lo primero que hicimos fue ver cual era el archivo de estilos del calendario:

.../styles/Themable/datepickerv4.css

Como esto estaba bien, decidimos buscar alguna diferencia entre un calendario que andaba y este que no andaba.

Teniamos acceso a una de nuestrar maquinas donde el calendario andaba bien y pudimos comparar la forma de la url del iFrame.

Lo que descubrimos fue que:

En el iFrame de los calendarios que el estilo estaba bien la URL era:

https://server/subsitio/_layouts/iframe.aspx?...

En el iFrame de los calendarion que el estilo no estaba bien la URL era:

https://server/_layouts/iframe.aspx?...

La diferencia esta en la URL, que el segundo calendario le falta el sub-site, ya que el calendario estaba funcionando en el mismo nivel que el calendario que andaba.

Probamos de modificar como se estaba llamando el iFrame agregandole el sub-sitio a la URL y los estilos comenzaron a andar bien.

Luego buscando en MSDN descubrimos que el DatePicker tiene una propiedad DatePickerFrameURL.

Esta propiedad nos permite especificar la URL del iFrame, por lo que, fuimos a nuestro control de Date Picker y agregamos la siguiente linea:

MyDatePicker.DatePickerFrameUrl = SPContext.Current.Web.ServerRelativeUrl + "/_layouts/iframe.aspx";

Con esta linea lo que hicimos fue decirle al DatePicker, que cada vez que se utilize saque su url del contexto en el que está.

Esta solución arregló nuestro problema en el sistema y tuvimos una feliz Demo.

Nos leemos!

Más información: El blog de Brian Farnhill 

 

Timer Job – Multiples Ejecuciones

Durante el proyecto que estamos llevando a cabo en la empresa para la que trabajo, tuvimos que hacer un Timer Job. La funcionalidad que este tiene es el de mandar un Newsletter a las personas que se suscribieron a ciertos sitios. Basicamente el Timer Job recorre todos los sitios creados en una web application, busca los usuarios subscriptos y manda las noticias. Después de terminar el desarrollo, lleve el timer job para deployarlo en una maquina que utilizamos como integración.

Cuando lo instalo y pruebo andaba, pero me mandaba muchísimos mails de más. Cuando voy a mirar el  history log aparecía como que se ejecutaba múltiples veces.

Me puse a investigar y leyendo un poco descubrí que en la creación del Timer Job, hay un parámetro que se llama SPJobLockType.

Este parametro puede estar entre los siguientes valores:

SPJobLockType.None: El Timer Job se ejecuta en todas las maquinas del farm donde el servicio se instaló. A no se que lo asocie para ejecutarse en un server especifico, en cuyo caso ejecuta solo en ese.

SPJobLockType.ContentDatabase – Se ejecuta una vez por cada content database asociada a la web application.

SPJobLockType.Job – Se ejecuta solo en una maquina del farm.

Como yo necesitaba que se ejecute solo un vez en todo el farm, utilicé SPJobLockType.Job y problema resuelto.

Espero les sirva para el desarrollo de sus Timer Jobs.

Nos leemos…

 

PHP The Right Way

El otro día navegando por internet me tope con el sitio PHP The Right Way, una suerte de copilado que nos sirve de referencia a la hora de encarar un proyecto en PHP.

La presentación del sitio dice:

Hoy en día existe mucha información anticuada acerca de PHP que guía a nuevos programadores por mal camino, propaga las malas prácticas y, en consecuencia, mal código. Esto tiene que parar. PHP: The Right Way es una referencia práctica y fácil de entender, con los mejores métodos, estándares de código, y enlaces a tutoriales autoritativos alrededor de la Web.

El sitio tiene varias secciones, desde “Primero Pasos” donde se tocan temas como el armado del entorno de desarrollo, pasando por reglas de estilo para el código,  mejores practicas para el desarrollo en PHP, manejo de seguridad, unit testing, etc.

Ningún tema esta profundamente desarrollado, pero si nos da un pantallazo general de cada cosa con links interesantes que nos pueden ayudar a aclarar más las dudas que tengamos.

El sitio fue creado por Josh Lockhart un programador con muchisima trayectoria en la comunidad de desarrollo en PHP. Y fue traducido por Eder Weber al español.

Por último este sitio sirvió de inspiración para otro que habla del desarrollo en Javascript, como no podía ser de otra manera se llama JS The Right Way, que aún no tiene traducción al español.

Espero que les sirva, nos leemos.

 

http://www.jstherightway.com/

Knock Out JS

Luego de un tiempo, y de leer este post, en Think Wasabi, decidí volver a escribir algo, aunque más no sea de algunas cositas que fui acumulando en este tiempo, probando, leyendo o aprendiendo.
De mi timeline de Twitter encontré este increíble biblioteca de Javascript. Knockout JS

¿Qué es Knockout JS?

Es una biblioteca Javascript que implementa el patrón MVVM (Model-View-ViewModel). Esta biblioteca puede ayudarte a mantener tus desarrollos más simples y manteníbles.

Características Principales

  • Trackeo de Dependencias Elegantes: Actualiza la interfaz, cuando el modelo de datos se modifica.
  • Bindings Declarativos: Una forma sencilla de conectar la interfaz con el modelo de datos.
  • Templates flexibles y sofisticados: Construye una interfaz compleja fácilmente utilizando templates.
  • Extensibilidad: Con unas pocas líneas de código podés crear nuevo comportamiento.

(Traducción libre de la documentación de KnokOutJS Library)

Lo mejor de esta biblioteca de Javascript, es que no es necesario leer miles de líneas de documentación para poder aprender a utilizarlo, sino que crearon una web exclusiva para aprender a usarlo.

Esta web tiene básicamente 5 tutoriales, que abarcan toda la funcionalidad, desde el “Getting Started“, para aprender lo básico de KO, hasta tópicos avanzados como el guardar datos,  trabajar con templates, listas, etc.