La automatización de procesos es una de las tareas esenciales en integración continua, ya que permite estandarizar los procesos (que siempre sean iguales) y ahorrar muchísimo tiempo en el desarrollo de los proyectos.

Lo primero que vamos a automatizar es la creación de repositorios. Para ello vamos a utilizar un script en Bash para poder ejecutarlo en consola a través de ssh. Es posible crear algo parecido con otros lenguajes de programación y además, con una interfaz web que facilite la gestión; pero de momento vamos con lo más básico.

CONVENCIONES

Como recordarás del último post (Integración continua: Metodologías y convenciones), debemos especificar unas convenciones o reglas que nos permitan diseñar cómo se van a crear los repositorios. En este caso esas reglas son las siguientes:

  • Se utilizará Git y Subversion.
  • Para Subversion se automatizará la creación de las ramas «trunk«, «branches» y «tags«.
  • Los repositorios se guardarán en «/var/repos«.
  • Dentro de cada repositorio se crearán los siguientes directorios: src, metrics, changes, test, db, phing y sh. En el directorio src guardaremos los datos del proyecto. En metrics guardaremos las métricas en subdirectorios, uno para cada una de las métricas (phpcs, pdepend, phpcpd, phpmd). El directorio changes dispondrá de un subdirectorio llamado modules que nos permitirá guardar en un archivo los cambios realizados sobre módulos o plugins que se distribuyan con el cms. En los directorio test habrá dos subdirectorios: units y functionals, para separar los test unitarios de los funcionales. En db habrá tres subdirectorios: basic, modules-dev y modules, que nos permitirá guardar una copia del proyecto al inicio sin módulos ni plugins (basic); con los módulos en desarrollo (modules-dev) y en producción (modules). Por último los directorios phing y sh nos permitirán guardar los xml de algunas tareas automatizadas específicas para el proyecto (phing, lo veremos más adelante) y los scripts en bash, también específicos para el proyecto en el que estemos trabajando, en sh.
  • Cada proyecto se nombrará con su dominio (interadictos.es). El nombre de los repositorios en Git terminarán en «.git».
  • Se creará un archivo «.conf» en Apache para poder acceder a los repositorios de Subversion desde el navegador.

Con esto ya podemos empezar a desarrollar nuestro script.

 

PERO ANTES

Como ves, el último elemento de la lista es la creación de un archivo «.conf» para poder ver el repositorio a través del navegador. Esta es una opción que te puedes saltar si no tienes necesidad de esta característica. Pero con el fin de hacer esta guía lo más detallada posible lo comentaré.

Para realizar estos cambios debes ser «root» o disponer del comando «sudo».

Nos vamos al directorio de Apache:

cd /etc/apache2

Y creamos el directorio

mkdir repos

Comprueba que los permisos del directorio son correctos.

 

CREAR UN SUBDOMINIO AL REPOSITORIO

Ahora entra en el directorio «sites-available»:

cd sites-available

Crearemos un subdominio para el dominio «ic.net», que te recuerdo era el dominio de nuestro servidor de integración continua.

Utiliza tu editor favorito y crea un archivo llamado «001-repos.ic.net.conf». El número al principio es simplemente una forma de ordenar los archivos. Puedes obviarlo si lo deseas.

Ahora introduce el siguiente código en el archivo y guárdalo:

  1. <VirtualHost *:80>
  2. ServerName repos.ic.net
  3.  
  4. DocumentRoot /var/www/repos.ic.net
  5. <Directory />
  6. Options FollowSymLinks
  7. AllowOverride None
  8. </Directory>
  9. <Directory /var/repos>
  10. Options Indexes FollowSymLinks MultiViews
  11. AllowOverride None
  12. Order allow,deny
  13. allow from all
  14. </Directory>
  15.  
  16. ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
  17. <Directory "/usr/lib/cgi-bin">
  18. AllowOverride None
  19. Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
  20. Order allow,deny
  21. Allow from all
  22. </Directory>
  23.  
  24. ErrorLog ${APACHE_LOG_DIR}/repos.ic.net.error.log
  25.  
  26. # Possible values include: debug, info, notice, warn, error, crit,
  27. # alert, emerg.
  28. LogLevel warn
  29.  
  30. CustomLog ${APACHE_LOG_DIR}/repos.ic.net.access.log combined
  31.  
  32. Alias /doc/ "/usr/share/doc/"
  33. <Directory "/usr/share/doc/">
  34. Options Indexes MultiViews FollowSymLinks
  35. AllowOverride None
  36. Order deny,allow
  37. Deny from all
  38. Allow from 127.0.0.0/255.0.0.0 ::1/128
  39. </Directory>
  40.  
  41. Include /etc/apache2/repos
  42.  
  43. </VirtualHost>

Lo más destacable del archivo es el segundo directorio al que le hemos dado permisos:

	<Directory /var/repos>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride None
		Order allow,deny
		allow from all
	</Directory>

Y la última línea antes de cerrar la etiqueta «VirtualHost»:

Include /etc/apache2/repos

Esta línea le dice a Apache que incluya también los archivos de configuración que haya en ese directorio. No incluyas esta línea si no quieres que tus repositorios se puedan acceder desde el navegador.

 

DESARROLLO DEL SCRIPT

Abrimos Gedit o el Bloc de notas si estás en Windows, o cualquier otro editor de textos o IDE de desarrollo que permita crear scripts en Bash y escribimos lo siguiente:

  1. #!/bin/bash
  2.  
  3. #Variables necesarias
  4. DIR_BASE_REPOS='/var/repos'
  5.  
  6. #Limpiamos la pantalla
  7. clear
  8.  
  9. #Iniciamos el script
  10. echo 'Bienvenido al creador automatizado de repositorios.'
  11. echo 'A continuación se le realizarán algunas preguntas para realizar el proceso.'
  12. echo ' '
  13. echo '¿Está de acuerdo? (y/n):'
  14. read ACEPTADO
  15.  
  16. #Comprobamos que el usuario está de acuerdo
  17. if [ "$ACEPTADO" == 'n' ] || [ "$ACEPTADO" != 'y' ]
  18. then
  19. #Si no está de acuerdo se le echa
  20. echo 'Hasta luego xD'
  21. exit 0
  22. else
  23.  
  24. fi
  25. exit

Bien, en primer lugar indicamos que el archivo que vamos a crear es un script en Bash con la línea:

#!/bin/bash

A continuación creamos la variable que guardará el directorio donde guardaremos los repositorios:

DIR_BASE_REPOS='/var/repos/'

Después limpiamos la pantalla con el comando «clear».

Iniciamos el script y le preguntamos al usuario si acepta que se le realicen unas preguntas para realizar el proceso.

Si contenta con la letra «n» o con algo distinto a «y» entonces se le envía un mensaje de despedida y se finaliza el script:

#Iniciamos el script
echo 'Bienvenido al creador automatizado de repositorios.'
echo 'A continuación se le realizarán algunas preguntas para realizar el proceso.'
echo ' '
echo '¿Está de acuerdo? (y/n):'
read ACEPTADO

#Comprobamos que el usuario está de acuerdo
if [ "$ACEPTADO" == 'n' ] || [ "$ACEPTADO" != 'y' ] 
then
 #Si no está de acuerdo se le echa
 echo 'Hasta luego xD'
 exit 0

En el caso de que haya aceptado, añadiremos todos bloques de código siguientes dentro del «else» del condicional.

Le preguntamos el nombre del proyecto:

  1. #Se pide el nombre del repositorio o proyecto
  2. echo 'Nombre del nuevo repositorio o proyecto:'
  3. read NOMBRE_REPOSITORIO
  4.  
  5. #Se comprueba que la variable no esté vacía
  6. if [ -z $NOMBRE_REPOSITORIO ]
  7. then
  8. echo 'No se ha escrito el nombre del repositorio. Adios.'
  9. exit 0
  10. fi

Si no se ha escrito el nombre del repositorio, el script finaliza. En caso contrario, en la variable «NOMBRE_REPOSITORIO» tendremos el nombre que el usuario le ha dado al proyecto.

Ahora le preguntamos qué repositorio desea usar para el proyecto:

  1. #Preguntamos el tipo de cvs a usar
  2. echo '¿Qué repositorio usará, git o subversion? (git/svn):'
  3. read TIPO_REPOSITORIO
  4.  
  5. #Se comprueba que se ha elegido un cvs
  6. if [ "$TIPO_REPOSITORIO" != 'git' ] && [ "$TIPO_REPOSITORIO" != 'svn' ]
  7. then
  8. #Si no se ha elegido ninguno, por defecto será git
  9. echo "No se ha elegido repositorio."
  10. echo "Por defecto se usará git"
  11. $TIPO_REPOSITORIO='git'
  12. fi

Como necesitamos un repositorio para nuestro proyecto, si el usuario no ha elegido ninguno le ponemos por defecto Git.

Creamos varias variables con la url del repositorio:

  1. #Dependiendo del tipo de repositorio elegido creamos las variables correspondientes
  2. #a la url y la ruta en el sistema de archivos
  3. if [ "$TIPO_REPOSITORIO" == 'git' ]
  4. then
  5. URI_REPO="${DIR_BASE_REPOS}${NOMBRE_REPOSITORIO}.git/"
  6. URL_REPO="${NOMBRE_REPOSITORIO}.git"
  7. elif [ "$TIPO_REPOSITORIO" == 'svn' ]
  8. then
  9. URI_REPO="${DIR_BASE_REPOS}$NOMBRE_REPOSITORIO"
  10. URL_REPO="$NOMBRE_REPOSITORIO"
  11. fi

En «URL_REPO» se guarda el nombre del repositorio que, como puedes observar, si es Git se añade al final del nombre el texto «.git», tal como hemos acordado en nuestras convenciones.

A continuación creamos el directorio del repositorio:

  1. echo 'Creo el directorio del repositorio.'
  2.  
  3. REPO_DIR=$(mkdir $URI_REPO)
  4.  
  5. if [ $REPO_DIR ]
  6. then
  7. echo 'No se ha podido crear el directorio del repositorio'
  8. exit 0
  9. else
  10. echo 'Creado'
  11. fi

Si por alguna razón (quizá por los permisos) no se ha podido crear el repositorio, mostramos un mensaje y finalizamos el script.

Ahora creamos el repositorio propiamente dicho:

  1. #Se crea el repositorio utilizando la uri o ruta del sistema de archivos
  2. #donde se encuentra el repositorio.
  3. if [ $TIPO_REPOSITORIO == 'git' ]
  4. then
  5. REPO_GIT=$(git init --bare $URI_REPO)
  6.  
  7. if [ "$REPO_GIT" == "Initialized empty Git repository in ${URI_REPO}" ]
  8. then
  9. echo 'Creado'
  10. else
  11. echo 'Algo falló.'
  12. echo $REPO_GIT
  13. exit 0
  14. fi
  15. elif [ $TIPO_REPOSITORIO == 'svn' ]
  16. then
  17. REPO_SVN=$( svnadmin create "$URI_REPO" )
  18.  
  19. if [ -z $REPO_SVN ]
  20. then
  21. echo 'Creado'
  22. else
  23. echo 'Algo falló.'
  24. echo $REPO_SVN
  25. exit 0
  26. fi
  27. fi

Como tenemos dos tipos de repositorios (Git y Subversion) tenemos que comprobar cual de ellos a elegido el usuario. Seguidamente se ejecuta el comando correspondiente para crear el repositorio, y se comprueba si ha funciona o se ha producido algún error, con lo que habría que finalizar el script.

Tenemos que crear un directorio temporal para crear los directorios que hemos acordado en las convenciones (src y metrics):

  1. echo "Creo un directorio temporal para crear los directorios src y metrics"
  2.  
  3. TEMP_DIR=$(mkdir /tmp/directory)
  4.  
  5. if [ $TEMP_DIR ]
  6. then
  7. echo 'Algo falló'
  8. echo $TEMP_DIR
  9. exit 0
  10. else
  11. if [ $TIPO_REPOSITORIO == 'git' ]
  12. then
  13. TEMP_DIR='/tmp/directory'
  14. TEMP_DIR_TRUNK='/tmp/directory'
  15. elif [ $TIPO_REPOSITORIO == 'svn' ]
  16. then
  17. echo "Creo los directorios trunk, branches y tags para el repositorio de subversion."
  18. $(mkdir -pv /tmp/directory/trunk /tmp/directory/branch /tmp/directory/tag)
  19. TEMP_DIR='/tmp/directory'
  20. TEMP_DIR_TRUNK='/tmp/directory/trunk'
  21. fi
  22. fi

Observa que dependiendo del tipo de repositorio, la variable TEMP_DIR_TRUNK tendrá un subdirectorio «trunk», si es Subversion, o no si es Git.

Ahora los directorios de la covención:

 

  1. # Creamos los directorios para las métricas y la aplicación
  2. echo "Creo las carpetas para las métricas y la aplicación."
  3. mkdir ${TEMP_DIR_TRUNK}/src
  4. mkdir ${TEMP_DIR_TRUNK}/metrics
  5. mkdir ${TEMP_DIR_TRUNK}/metrics/phpcs
  6. mkdir ${TEMP_DIR_TRUNK}/metrics/pdepend
  7. mkdir ${TEMP_DIR_TRUNK}/metrics/phpcpd
  8. mkdir ${TEMP_DIR_TRUNK}/metrics/phpmd
  9. mkdir ${TEMP_DIR_TRUNK}/changes
  10. mkdir ${TEMP_DIR_TRUNK}/changes/modules
  11. mkdir ${TEMP_DIR_TRUNK}/test
  12. mkdir ${TEMP_DIR_TRUNK}/test/functionals
  13. mkdir ${TEMP_DIR_TRUNK}/test/units
  14. mkdir ${TEMP_DIR_TRUNK}/db
  15. mkdir ${TEMP_DIR_TRUNK}/db/basic
  16. mkdir ${TEMP_DIR_TRUNK}/db/modules-dev
  17. mkdir ${TEMP_DIR_TRUNK}/db/modules
  18. mkdir ${TEMP_DIR_TRUNK}/phing
  19. mkdir ${TEMP_DIR_TRUNK}/sh

 

Si quieres que sea posible acceder a los repositorios de Subversion desde el navegador, deberás añadir las siguientes líneas:

  1. #Se modifica Apache para permitir ver el repositorio desde el navegador
  2. if [ $TIPO_REPOSITORIO == 'svn' ]
  3. then
  4. echo 'Creo la ruta en Apache para el repositorio'
  5. FILE_CONF="/etc/apache2/repos/${URL_REPO}.conf"
  6. echo "<Location /${URL_REPO}>" >> $FILE_CONF
  7. echo " DAV svn" >> $FILE_CONF
  8. echo " SVNPath /var/repos/${URL_REPO}" >> $FILE_CONF
  9. echo "</Location>" >> $FILE_CONF
  10.  
  11. echo 'Recarga Apache'
  12. $( /etc/init.d/apache2 reload )
  13. fi

Este código crea un archivo «.conf» con los datos necesarios para poder navegar por el repositorio desde el navegador.

Para finalizar realizamos el primer commit del repositorio:

  1. echo 'Entro al directorio temporal y hago un commit'
  2. cd $TEMP_DIR
  3.  
  4. #Se hace un primer commit con el código base
  5. if [ "$TIPO_REPOSITORIO" == 'git' ]
  6. then
  7. git init
  8. $(git update-server-info)
  9. git remote add origin "ssh://nombre_usuario@repos.ic.net/${DIR_BASE_REPOS}${URL_REPO}"
  10. $(git add *)
  11. git commit -m "Commit inicial"
  12. $(git push origin master)
  13. elif [ "$TIPO_REPOSITORIO" == 'svn' ]
  14. then
  15. $(svn checkout http://repos.ic.net/$NOMBRE_REPOSITORIO $URI_REPO)
  16. $(svn commit -m "Commit inicial" http://repos.ic.net/$NOMBRE_REPOSITORIO)
  17.  
  18. fi

En el caso de que el repositorio sea Git tendrás que sustituir «nombre_usuario» por el nombre de un usuario que tenga permisos para acceder al directorio /var/repos.

Y aquí el script final:

  1. #!/bin/bash
  2.  
  3. #Variables necesarias
  4. DIR_BASE_REPOS='/var/repos'
  5.  
  6. #Limpiamos la pantalla
  7. clear
  8.  
  9. #Iniciamos el script
  10. echo 'Bienvenido al creador automatizado de repositorios.'
  11. echo 'A continuación se le realizarán algunas preguntas para realizar el proceso.'
  12. echo ' '
  13. echo '¿Está de acuerdo? (y/n):'
  14. read ACEPTADO
  15.  
  16. #Comprobamos que el usuario está de acuerdo
  17. if [ "$ACEPTADO" == 'n' ] || [ "$ACEPTADO" != 'y' ]
  18. then
  19. #Si no está de acuerdo se le echa
  20. echo 'Hasta luego xD'
  21. exit 0
  22. else
  23. #Se pide el nombre del repositorio o proyecto
  24. echo 'Nombre del nuevo repositorio o proyecto:'
  25. read NOMBRE_REPOSITORIO
  26.  
  27. #Se comprueba que la variable no esté vacía
  28. if [ -z $NOMBRE_REPOSITORIO ]
  29. then
  30. echo 'No se ha escrito el nombre del repositorio. Adios.'
  31. exit 0
  32. fi
  33.  
  34. #Preguntamos el tipo de cvs a usar
  35. echo '¿Qué repositorio usará, git o subversion? (git/svn):'
  36. read TIPO_REPOSITORIO
  37.  
  38. #Se comprueba que se ha elegido un cvs
  39. if [ "$TIPO_REPOSITORIO" != 'git' ] && [ "$TIPO_REPOSITORIO" != 'svn' ]
  40. then
  41. #Si no se ha elegido ninguno, por defecto será git
  42. echo "No se ha elegido repositorio."
  43. echo "Por defecto se usará git"
  44. $TIPO_REPOSITORIO='git'
  45. fi
  46.  
  47. #Dependiendo del tipo de repositorio elegido creamos las variables correspondientes
  48. #a la url y la ruta en el sistema de archivos
  49. if [ "$TIPO_REPOSITORIO" == 'git' ]
  50. then
  51. URI_REPO="${DIR_BASE_REPOS}${NOMBRE_REPOSITORIO}.git/"
  52. URL_REPO="${NOMBRE_REPOSITORIO}.git"
  53. elif [ "$TIPO_REPOSITORIO" == 'svn' ]
  54. then
  55. URI_REPO="${DIR_BASE_REPOS}$NOMBRE_REPOSITORIO"
  56. URL_REPO="$NOMBRE_REPOSITORIO"
  57. fi
  58.  
  59. echo 'Creo el directorio del repositorio.'
  60.  
  61. REPO_DIR=$(mkdir $URI_REPO)
  62.  
  63. if [ $REPO_DIR ]
  64. then
  65. echo 'No se ha podido crear el directorio del repositorio'
  66. exit 0
  67. else
  68. echo 'Creado'
  69. fi
  70.  
  71. #Se crea el repositorio utilizando la uri o ruta del sistema de archivos
  72. #donde se encuentra el repositorio.
  73. if [ $TIPO_REPOSITORIO == 'git' ]
  74. then
  75. REPO_GIT=$(git init --bare $URI_REPO)
  76.  
  77. if [ "$REPO_GIT" == "Initialized empty Git repository in ${URI_REPO}" ]
  78. then
  79. echo 'Creado'
  80. else
  81. echo 'Algo falló.'
  82. echo $REPO_GIT
  83. exit 0
  84. fi
  85. elif [ $TIPO_REPOSITORIO == 'svn' ]
  86. then
  87. REPO_SVN=$( svnadmin create "$URI_REPO" )
  88.  
  89. if [ -z $REPO_SVN ]
  90. then
  91. echo 'Creado'
  92. else
  93. echo 'Algo falló.'
  94. echo $REPO_SVN
  95. exit 0
  96. fi
  97. fi
  98.  
  99. echo "Creo un directorio temporal para crear los directorios src y metrics"
  100.  
  101. TEMP_DIR=$(mkdir /tmp/directory)
  102.  
  103. if [ $TEMP_DIR ]
  104. then
  105. echo 'Algo falló'
  106. echo $TEMP_DIR
  107. exit 0
  108. else
  109. if [ $TIPO_REPOSITORIO == 'git' ]
  110. then
  111. TEMP_DIR='/tmp/directory'
  112. TEMP_DIR_TRUNK='/tmp/directory'
  113. elif [ $TIPO_REPOSITORIO == 'svn' ]
  114. then
  115. echo "Creo los directorios trunk, branches y tags para el repositorio de subversion."
  116. $(mkdir -pv /tmp/directory/trunk /tmp/directory/branch /tmp/directory/tag)
  117. TEMP_DIR='/tmp/directory'
  118. TEMP_DIR_TRUNK='/tmp/directory/trunk'
  119. fi
  120. fi
  121.  
  122. # Creamos los directorios para las métricas y la aplicación
  123. echo "Creo las carpetas para las métricas y la aplicación."
  124. mkdir ${TEMP_DIR_TRUNK}/src
  125. mkdir ${TEMP_DIR_TRUNK}/metrics
  126. mkdir ${TEMP_DIR_TRUNK}/metrics/phpcs
  127. mkdir ${TEMP_DIR_TRUNK}/metrics/pdepend
  128. mkdir ${TEMP_DIR_TRUNK}/metrics/phpcpd
  129. mkdir ${TEMP_DIR_TRUNK}/metrics/phpmd
  130. mkdir ${TEMP_DIR_TRUNK}/changes
  131. mkdir ${TEMP_DIR_TRUNK}/changes/modules
  132. mkdir ${TEMP_DIR_TRUNK}/test
  133. mkdir ${TEMP_DIR_TRUNK}/test/functionals
  134. mkdir ${TEMP_DIR_TRUNK}/test/units
  135. mkdir ${TEMP_DIR_TRUNK}/db
  136. mkdir ${TEMP_DIR_TRUNK}/db/basic
  137. mkdir ${TEMP_DIR_TRUNK}/db/modules-dev
  138. mkdir ${TEMP_DIR_TRUNK}/db/modules
  139. mkdir ${TEMP_DIR_TRUNK}/phing
  140. mkdir ${TEMP_DIR_TRUNK}/sh
  141.  
  142. #Se modifica Apache para permitir ver el repositorio desde el navegador
  143. if [ $TIPO_REPOSITORIO == 'svn' ]
  144. then
  145. echo 'Creo la ruta en Apache para el repositorio'
  146. FILE_CONF="/etc/apache2/repos/${URL_REPO}.conf"
  147. echo "<Location /${URL_REPO}>" >> $FILE_CONF
  148. echo " DAV svn" >> $FILE_CONF
  149. echo " SVNPath /var/repos/${URL_REPO}" >> $FILE_CONF
  150. echo "</Location>" >> $FILE_CONF
  151.  
  152. echo 'Recarga Apache'
  153. $( /etc/init.d/apache2 reload )
  154. fi
  155.  
  156. echo 'Entro al directorio temporal y hago un commit'
  157. cd $TEMP_DIR
  158.  
  159. #Se hace un primer commit con el código base
  160. if [ "$TIPO_REPOSITORIO" == 'git' ]
  161. then
  162. git init
  163. $(git update-server-info)
  164. git remote add origin "ssh://nombre_usuario@repos.ic.net/${DIR_BASE_REPOS}${URL_REPO}"
  165. $(git add *)
  166. git commit -m "Commit inicial"
  167. $(git push origin master)
  168. elif [ "$TIPO_REPOSITORIO" == 'svn' ]
  169. then
  170. $(svn checkout http://repos.ic.net/$NOMBRE_REPOSITORIO $URI_REPO)
  171. $(svn commit -m "Commit inicial" http://repos.ic.net/$NOMBRE_REPOSITORIO)
  172.  
  173. fi
  174. fi
  175. exit

Este es el script inicial para crear repositorios en Git y Subversion en nuestro servidor de integración continua. Más adelante iremos añadiendo nuevas tareas como los hooks de los repositorios, los archivos ignore, el código base de los frameworks o cms, unirlos con Jenkins, etc, etc, etc.