martes, 3 de julio de 2012

Ensamblados comerciales y builds de TFS

O cómo modificar las builds para TFS 2010.

Cuando estamos desarrollando una aplicación, es frecuente que necesitemos o decidamos utilizar algún componente comercial para simplificar el propio desarrollo o para mejorar la experiencia del usuario.

En este artículo vamos a revisar y solucionar un problema muy común que aparece cuando queremos realizar compilaciones automáticas de estos proyectos mediante Team Foundation Server 2010.

El problema

Pongamos que en mi aplicación estoy utilizando un control de menú muy ‘mono’, que me pinta las barras de herramientas como si de la Ribbon de Office se tratara.

Pongamos también que ese control de menú es comprado y licenciado, en la clásica licencia de componentes para .NET que requiere una licencia para cada desarrollador pero no requiere licencias de ejecución (ojo que este punto es importante, este artículo sólo aplica en estos casos)

Termino mi jornada y hago un check-in del formulario que desencadena una compilación en el servidor de Builds.

¡Sorpresa!

image

La causa

Si observamos la captura anterior, podemos ver que el error al compilar se está generando con el archivo “licenses.licx”

¿Pero qué es este archivo?

En las condiciones que hemos especificado en el punto anterior, en este archivo aparecen los componentes de terceros que estemos utilizando en nuestro proyecto y que además requieran de un control de licenciamiento en la máquina de desarrollo. El contenido concreto, que no voy a reproducir aquí, es una serie de líneas de texto ‘plano’ que indican la ‘firma’ de los componentes que requieren licenciamiento.

El problema que está encontrando el servidor de Builds es que al lanzar la compilación está realizando las operaciones necesarias para comprobar la licencia de todos los controles que aparezcan en este archivo.

Una posible solución

Revisando este problema por Internet, una de las propuestas que he encontrado es quitar ese archivo del control de versiones, con lo que al lanzar la compilación el archivo no existirá y en consecuencia el servidor no intentará validar las licencias. Reconozco que esta opción no la he probado, porque excluir un archivo del proyecto del control de versiones me da la sensación de que me puede acabar generando problemas a posteriori.

La solución

Como la primera alternativa no me convence, es hora de probar otra cosa. He leído por ahí que si el archivo está vacío, hará el mismo efecto que si está fuera del control de fuentes. Esto por si sólo tampoco es que sea una mejora de lo anterior, ya que tendríamos que vaciar el archivo ‘a mano’ antes de cada Build (inaceptable)

Lo que vamos a hacer a cambio, es generar una tarea personalizada para el flujo de compilación que cuando se ejecute limpiará el contenido del archivo automáticamente. De esta forma, las copias de trabajo y el control de fuente no corren riesgo de quedar en un estado inestable, y a su vez el proceso de compilación funcionará correctamente.

Al turrón

Vamos a trabajar con Visual Studio 2010.

Creación del proyecto

  1. Creamos una solución con dos proyectos de “Class Library”. Uno de los proyectos contendrá las tareas personalizadas (CustomBuildActivities) utilizando .Net 4 y el otro contendrá la plantilla de proceso que vamos a modificar para incluir nuestra tarea (CustomBuildProcess).
  2. Localizamos la plantilla de proceso por defecto “DefaultTemplate.xaml” y cambiándole el nombre la incluimos en el proyecto CustomBuildProcess. Una vez incluida, tenemos que modificar su propiedad “Build Action” a “XamlAppDef”.

    image

Creando una actividad personalizada

Para que este sistema funcione, necesitaremos una actividad que nos permita manipular el atributo de sólo lectura de nuestro archivo, ya que si está marcado como de sólo lectura, difícilmente podremos manipular su contenido.

En nuestro proyecto CustomBuildActivities añadimos un nuevo elemento de tipo “Workflow”, “Code Activity”, en este caso voy a utilizar el nombre “SetReadOnlyFlag”. El código de esta clase está disponible en el archivo adjunto y sus características más relevantes son las propiedades que definimos para controlar el Workspace donde el servidor de compilación almacena los archivos y los archivos a manipular.

Necesitamos también una actividad que nos permita modificar el contenido del archivo. Para esta actividad voy a utilizar el nombre “UpdateLicensesContent”. El código de esta clase está disponible también en el archivo adjunto y sus características más relevantes son las propiedades de definimos para localizar el archivo a manipular. Básicamente lo que hace esta actividad es localizar el archivo y, si no está vacío, vaciarlo.

Actualizando el flujo de trabajo de compilación

Hasta ahora hemos preparado unas actividades que nos permitirán manipular el archivo de licencias, pero ahora llega el momento de utilizarlas.

Para ello abrimos el proceso de Build en el proyecto “CustomBuildProcess”. En la caja de herramientas veremos las actividades que hemos programado anteriormente:

image

Lo que vamos a hacer va a ser ubicar nuestras tareas en el punto adecuado del flujo, para ello en el flujo localizamos la siguiente sección:

image

Justo después de “Get Workspace” añadimos una actividad de tipo “Sequence”, le cambiamos el nombre de manera adecuada y añadimos dentro la actividad personalizada que hemos creado “SetReadOnlyFlag”.

image

Los indicadores de error significan que nos falta informar las propiedades de la actividad, para ello vamos al panel de propiedades:

image

Lo que vamos a hacer es permitir a los usuarios especificar los valores de la propiedad “FileMask” en la ventana de definición de la Build, para darle más flexibilidad al sistema y además los valores de la propiedad “Workspace” estarán basados en la propia Build actual.

Para permitir a los usuarios interactuar con la propiedad “FileMask”, añadimos un nuevo “Argument” al Flujo que estamos personalizando, utilizando para ello el botón “Arguments” que aparece en la parte inferior del diseñador del Flujo. Una vez que se abre el panel de argumentos, vamos al final del mismo y hacemos clic en “Create Argument”, creando nuestro argumento (en este caso “LicensesMask”) e indicando el valor deseado:

image

Antes de utilizar este argumento en nuestra actividad, tenemos que habilitar su ‘presencia’ en la ventana de definición de la Build. Para esto en el panel de argumentos localizamos “Metadata” y añadimos un parámetro a la colección:

image

Una vez añadido el parámetro, actualizamos la propiedad “FileMask” en la actividad “SetReadOnlyFlag” para utilizar el argumento que acabamos de crear, así como el resto de propiedades:

image

Una vez configurada la actividad, añadimos a continuación la segunda actividad personalizada “UpdateLicensesContent” y otra instancia de la actividad “SetReadOnlyFlag” y establecemos sus correspondientes propiedades:

Actividad “UpdateLicensesContent”

image

Segunda actividad “SetReadOnlyFlag”

image

y ya está todo preparado para utilizar el nuevo proceso de Build.

Utilizar el nuevo proceso de Build

Para poder utilizar el proceso de Build, tenemos que asegurarnos de que tanto el propio proceso como las actividades personalizadas están disponibles para el sistema. Para ello lo más común es añadir la plantilla de proceso a la carpeta “BuildProcessTemplates” y las actividades en una subcarpeta, por ejemplo “CustomActivities”. Esta carpeta está accesible desde el Team Explorer:

image

Lo siguiente que tenemos que hacer es indicar al controlador de compilaciones dónde tiene que ir a buscar las actividades personalizadas, para ello en el elemento “Builds”, hacemos clic con el botón derecho del ratón y elegimos “Manage Build Controllers”

image

En la ventana que se abre especificamos la ruta a las actividades personalizadas:

image

Ahora ya podemos generar una nueva compilación que utilice nuestra plantilla de proceso.

Lo único que tenemos que tener en cuenta al generar la nueva definición de build es que en la pestaña “Process” tendremos que elegir nuestra plantilla personalizada en lugar de la que propone Visual Studio por defecto:

image

El resultado

Una configurado el nuevo proceso de compilación, el resultado del mismo ya, por fin, es el esperado:

image

El código asociado a este artículo estará disponible próximamente como adjunto y en Codeplex, en cuanto lo tenga publicado actualizaré esta entrada. Si alguien quiere más información no tiene más que dejar un comentario.

No hay comentarios: