Monthly Archives: noviembre 2010

Integración continua. Convertir un problema en una ventaja

Vamos a ver si te suena estas frases:

– Preparando un paquete para instalarlo  “¿quien sabe dónde narices están los scripts de bases de datos?”
– Corrigiendo un bug urgente “¿por qué no me compila ahora este código?”
– Probando una funcionalidad recien implementada “¿de dónde saco lo que acabas de desarrollar?”
– Respondiendo una incidencia de soporte. “En mi máquina funcionaba correctamente”

Estos son los problemas tipicos que pueden ocurrir por una mala o muy laboriosa integración. Cada programador realiza su trabajo correctamente pero a la hora de juntar todas las piezas en un paquete de software que funcione ocurren estos problemas. Esa integración necesita un conocimiento especifico y la persona que la realiza se convierte en una caja negra, es decir, se sabe lo que hace pero no cómo lo hace.
La solución es convertir el conocimiento implicito de integración en un proceso automático realizado por una máquina dedicada. Como para ser ágiles necesitamos feedback lo más temprano posible, esta integración se va a realizar en cada cambio de codigo fuente, cada check-In de cualquier desarrollador.

En video stream networks tenemos un servidor dedicado que realiza las integraciones. En cada proceso de integración se realizan desde cero los siguientes pasos:
– Obtiene todo el codigo fuente del servidor (source safe 2005)
– Realiza una compilación de toda la solución (Visual Studio 2008 y 2010).
– Ejecuta los scripts de bases de datos (que está junto al proyecto en el servidor) creando siempre la base de datos desde cero.
– Ejecuta los tests automaticos, usando la base de datos recien creada
– Crea los ficheros que necesita (ficheros de lenguajes y configuración) a partir de los componentes recien compilados.
– Copia todos los ficheros resultantes en un directorio LastBuild de un servidor

Como me costó encontrar documentación de Cruise Control .NET, el software que usamos para la integración continua, voy a exponer y explicar un ejemplo de proyecto de integración de los que tenemos.

<!-- Empieza el bloque de un proyecto -->
<project name="vsnarchive4" webURL="http://localhost/ccnet">

	<triggers>
		<!-- Comprueba cada minuto el código fuente por si hay cambios -->
		<intervalTrigger /> 

		<!-- A las 11 de la noche siempre hace un build de todos los proyectos -->
		<scheduleTrigger time="23:15" buildCondition="ForceBuild" name="Scheduled" />
	</triggers>

	<!-- Bloque de control de código fuente. Usamos SourceSafe 2005 como control de código fuente -->
	<sourcecontrol type="vss" autoGetSource="true">
		<!--  Proyecto de SorceSafe -->
		<project>$/DesktopApplications/MultiPlatform/MultiPlatform</project>

		<!-- Usuario de sourcesafe. Hemos creado uno especial con permisos de lectura -->
		<username>builds</username>
		<password></password>

		<!-- Esto es importante para que lea los cambios. El lenguaje en el que se tiene el sourcesafe -->
		<culture>en-US</culture>

		<!-- Directorio donde esta la configuracion de sourcesafe. Normalmente en otro servidor -->
		<ssdir>\\servidor2\VSS\</ssdir>

		<!-- Directorio donde se descarga el codigo fuente y que va a usarse para compilar -->
		<workingDirectory>E:\vsn.net\vsnarchive4</workingDirectory>
	</sourcecontrol>

	<-- Lista de cosas a realizar paa hacer la integracion. Se ejecutan por orden -->
	<tasks>
		<!-- Compilacion con Visual Studio 2008 -->
		<devenv>
			<configuration>Release</configuration>
			<executable>D:\Desarrollo\Microsoft Visual Studio 9.0\Common7\IDE\devenv.com 		</executable>
			<version>VS2008</version>
			<solutionfile>E:\vsn.net\vsnarchive4\Multiplatform.sln</solutionfile>
		</devenv>

		<!-- Pasos previos del testeo unitario -->
		<!-- Creamos desde 0 la BD de vsnarchive4 -->

		<exec>
			<executable>sqlcmd</executable>
			<baseDirectory>c:\windows</baseDirectory>
			<buildArgs>-iE:\vsn.net\vsnarchive4\Database\vsnarchive4DB_Creation.sql</buildArgs>
			<buildTimeoutSeconds>60</buildTimeoutSeconds>
			<successExitCodes>0</successExitCodes>

		</exec>

		<exec>
			<executable>sqlcmd</executable>
			<baseDirectory>c:\windows</baseDirectory>
			<buildArgs>-iE:\vsn.net\vsnarchive4\Database\vsnarchive4DB_Update.sql</buildArgs>
			<buildTimeoutSeconds>60</buildTimeoutSeconds>
			<successExitCodes>0</successExitCodes>
		</exec>

		<!-- Insertamos los datos necsarios en la BD para hacer los tests
		<exec>
			<executable>sqlcmd</executable>
			<baseDirectory>c:\windows</baseDirectory>
			<buildArgs>-iE:\vsn.net\vsnarchive4\MultiPlatform\Tests\ScriptsDB\Before.sql</buildArgs>
			<buildTimeoutSeconds>60</buildTimeoutSeconds>
			<successExitCodes>0</successExitCodes>

		</exec>	-->

		<!-- Fin de pasos previos del testeo unitario -->

		<!-- Tests unitarios con NUnit -->
		<nunit path="D:\Desarrollo\NUnit\2.4.8\bin\nunit-console.exe">
			<assemblies>
				<assembly>E:\vsn.net\vsnarchive4\UIWPF\bin\Release\vsnarchive4.exe</assembly>
			</assemblies>
		</nunit>

		<!-- Pasos posteriores del testeo unitario -->

		<exec>
			<executable>sqlcmd</executable>
			<baseDirectory>c:\windows</baseDirectory>
			<buildArgs>-iE:\vsn.net\vsnarchive4\MultiPlatform\Tests\ScriptsDB\After.sql</buildArgs>
			<buildTimeoutSeconds>60</buildTimeoutSeconds>
			<successExitCodes>0</successExitCodes>

		</exec>
		<!-- Fin de pasos posteriores del testeo unitario -->

		<!-- Creamos los ficheros de configuración a partir de los assemblies -->
		<exec>
			<executable>vsnarchive4.exe</executable>
			<baseDirectory>E:\vsn.net\vsnarchive4\UIWPF\bin\Release\</baseDirectory>
			<buildArgs>/CreateConfig</buildArgs>
			<buildTimeoutSeconds>10</buildTimeoutSeconds>
			<successExitCodes>0,1,3,5</successExitCodes>
		</exec>

		<!-- Creamos los ficheros de lenguaje a partir de los assemblies -->
		<exec>
			<executable>vsnarchive4.exe</executable>
			<baseDirectory>E:\vsn.net\vsnarchive4\UIWPF\bin\Release\</baseDirectory>
			<buildArgs>/CreateLang</buildArgs>
			<buildTimeoutSeconds>10</buildTimeoutSeconds>
			<successExitCodes>0,1,3,5</successExitCodes>
		</exec>

		<!-- Copiamos los scripts de BD a la carpeta origen del deploy -->
		<exec>
			<executable>cmd</executable>
			<baseDirectory>c:\windows</baseDirectory>
			<buildArgs>/C xcopy E:\vsn.net\vsnarchive4\Database\*.* E:\vsn.net\vsnarchive4\UIWPF\bin\Release\Database  /e /y /I</buildArgs>
			<buildTimeoutSeconds>10</buildTimeoutSeconds>
			<successExitCodes>0,1,3,5</successExitCodes>
		</exec>

		<!-- Fin de las tareas de integracion. Falta el deploy en sí mismo -->
	</tasks>

	<!-- Fin de la integración. Qué hacemos con lo que hemos generado -->
	<publishers>
		<!-- Los logs de resultado al subdirectorio log -->
		<xmllogger logDir="log" />

		<!-- Envio de emails de los resultados. A mi como buildmaster un email siempre con el resultado -->
		<!-- y al programador responsable cuando algo se ha roto y cuando se ha arreglado -->
		<email mailport="25" mailhost="mail.myworkplace.es" includeDetails="True" mailhostUsername="builds@myworkplace.es" mailhostPassword="pass">
			<from>builds@myworkplace.es</from>
			<users>
				<user name="Jorge" group="buildmaster" address="jorge@myworkplace.es"/>
				<user name="Antonio" group="developers" address="antonio@myworkplace.es"/>
			</users>
			<groups>
				<group name="developers">
					<notifications>
						<NotificationType>Failed</NotificationType>
						<NotificationType>Fixed</NotificationType>
					</notifications>
				</group>
				<group name="buildmaster" >
					<notifications>
						<NotificationType>Always</NotificationType>
					</notifications>
				</group>
			</groups>
		</email>

		<!-- Deploy del directorio especificado. Borra el directorio antes de copiar -->
		<buildpublisher>
			<cleanPublishDirPriorToCopy>true</cleanPublishDirPriorToCopy>
			<sourceDir>E:\vsn.net\vsnarchive4\UIWPF\bin\Release\</sourceDir>
			<publishDir>\\servidor\Distribuciones\vsnarchive4\Win32\LastBuild</publishDir>
			<useLabelSubDirectory>false</useLabelSubDirectory>
			<alwaysPublish>false</alwaysPublish>
		</buildpublisher>
	</publishers>

</project>

Sólo falta instalar el programita cliente que se conecta al servidor y asociar una musica cuando alguien ha roto el build. En mi caso si se rompe el build suena la Marcha Imperial de Dark Vader. 😉

Anuncios