Integración continua: Automatizando la creación de proyectos WordPress, Drupal, Symfony, etc. (II)
En el post anterior hemos actualizado el script que crea los repositorios, para poder añadirle unas cuantas acciones para automatizar la creación del proyecto (creación de directorios, directorios ignorados, etc.). Ahora vamos a desarrollar la segunda parte, que consistirá en la automatización de la instalación del cms o framework elegido.
Automatizando la instalación de WordPress
En primer lugar vamos a copiar el archivo wp-config-sample.php de la raíz de WordPress a /var/www/dev/utils/wp-config-sample.php. Lo tendremos que modificar para poder trabajar más cómodamente con él.
Sustituye las líneas:
- <?php
-
- /** The name of the database for WordPress */
-
- /** MySQL database username */
-
- /** MySQL database password */
-
- /** MySQL hostname */
por:
- <?php
-
- /** The name of the database for WordPress */
-
- /** MySQL database username */
-
- /** MySQL database password */
-
- /** MySQL hostname */
Sustituimos las siguientes líneas:
- <?php
Por:
@UNIQUE_PHRASES@
Sustituye o añade las siguientes líneas:
/** * WordPress Localized Language, defaults to English. * * Change this to localize WordPress. A corresponding MO file for the chosen * language must be installed to wp-content/languages. For example, install * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German * language support. */ define('WPLANG', '@I18N@');
Si en tu wp-config-sample.php tienes esta línea:
define('WP_DEBUG', false);
Sustitúyela por:
define('WP_DEBUG', @DEBUG@);
Sino tendrás que añadirla igualmente.
Guarda el archivo
Ahora creamos un nuevo script en bash llamado content-wordpress.sh en /var/www/dev/utils, con el siguiente contenido:
- #!/bin/bash
-
- #Variables
- TIPO_REPOSITORIO=$1
- URL_REPO=$2
- URI_REPO=$3
- TEMP_DIR=$4
- DIR_SOURCES=$5
- NOMBRE_REPOSITORIO=$6
- SED_TEMP_DIR=$(echo $TEMP_DIR | sed -e 's/\//\\\//g')
- DIR_BASE_PROJECTS="var/www/"
Aquí guardamos en variables los parámetros que le hemos pasado al script. Si recuerdas del post anterior, al finalizar la creación del repositorio llamamos al archivo content-wordpress.sh con algunos parámetros:
/var/www/dev/utils/./content-wordpress.sh $TIPO_REPOSITORIO $URL_REPO $URI_REPO $TEMP_DIR_TRUNK $DIR_WORDPRESS $NOMBRE_REPOSITORIO
Debajo de las variables añadimos el siguiente código:
- echo "Bienvenido/a, en primer lugar vamos a añadir el archivo wp-config a tu WordPress."
- echo "Voy a añadir las unique phrases para proteger la app de posibles ataques."
-
- SALT=$(wget https://api.wordpress.org/secret-key/1.1/salt/ -q -O -)
- $(cp "/var/www/dev/utils/wp-config-sample.php" "${TEMP_DIR}/src/wp-config.php")
- $(printf '%s\n' "g/@UNIQUE_PHRASES@/d" a "$SALT" . w | ed -s "${TEMP_DIR}/src/wp-config.php")
Añadimos un texto de bienvenida y procedemos a ejecutar el primer paso: crear las unique phrases. Las obtenemos a través de wget; a continuación copiamos el archivo wp-confi-sample.php al directorio src del proyecto. Por último sustituimos el texto «@UNIQUE_PHRASES@» por los datos obtenidos de wget, que previamente hemos guardado en la variable $SALT.
Ahora añadimos el código correspondiente para obtener las credenciales para que WordPress conecte con la base de datos:
- echo "Ahora necesito conocer algunos datos para configurar la base de datos"
-
- while [ -z $DB_NAME ]
- do
- echo "Nombre de la base de datos: "
- read DB_NAME
- done
-
- while [ -z $DB_USER ]
- do
- echo "Nombre del usuario de la base de datos: "
- read DB_USER
- done
-
- while [ -z $DB_PASSWORD ]
- do
- echo "Password del usuario de la base de datos: "
- read DB_PASSWORD
- done
-
- while [ -z $DB_HOST ]
- do
- echo "Host de la base de datos (por defecto localhost): "
- read DB_HOST
-
- if [ -z $DB_HOST ]
- then
- DB_HOST="localhost"
- fi
- done
Le preguntamos al usuario por el idioma en el que estará WordPress, y si quiere activar el modo de depuración:
- while [ -z $I18N ]
- do
- echo "Idioma de la app (recuerda que debe tener el siguiente formato en_EN, es_ES, etc., (por defecto es_ES): "
- read I18N
-
- if [ -z $I18N ]
- then
- I18N="es_ES"
- fi
- done
-
- while [ -z $DEBUG ]
- do
- echo "¿Activar modo depuración? (y/n)(por defecto y): "
- read DEBUG
-
- if [ -z $DEBUG ]
- then
- DEBUG="y"
- fi
- done
Ahora se modifica el archivo wp-config.php del proyecto para añadir los valores que ha indicado el usuario:
- echo "Modificando el archivo wp-config.php, un momento por favor..."
- $(printf '%s\n' "g/@DB_NAME@/d" a "define('DB_NAME', '$DB_NAME');" . w | ed -s "${TEMP_DIR}/src/wp-config.php")
- $(printf '%s\n' "g/@DB_USER@/d" a "define('DB_USER', '$DB_USER');" . w | ed -s "${TEMP_DIR}/src/wp-config.php")
- $(printf '%s\n' "g/@DB_PASSWORD@/d" a "define('DB_PASSWORD', '$DB_PASSWORD');" . w | ed -s "${TEMP_DIR}/src/wp-config.php")
- $(printf '%s\n' "g/@DB_HOST@/d" a "define('DB_HOST', '$DB_HOST');" . w | ed -s "${TEMP_DIR}/src/wp-config.php")
- $(printf '%s\n' "g/@I18N@/d" a "define('WPLANG', '$I18N');" . w | ed -s "${TEMP_DIR}/src/wp-config.php")
-
- if [ $DEBUG == "y" ]
- then
- $(printf '%s\n' "g/@DEBUG@/d" a "define('WP_DEBUG', true);" . w | ed -s "${TEMP_DIR}/src/wp-config.php")
- elif [ $DEBUG == "n" ]
- then
- $(printf '%s\n' "g/@DEBUG@/d" a "define('WP_DEBUG', false);" . w | ed -s "${TEMP_DIR}/src/wp-config.php")
- fi
Debajo de lo anterior añadimos el siguiente código:
- echo "Copio todos los archivos del proyecto al directorio ${NOMBRE_REPOSITORIO} en /var/www/ para poder recuperar la base de datos base."
- mkdir "/var/www/${NOMBRE_REPOSITORIO}"
-
- cp -r "${TEMP_DIR}/src/*" "/var/www/${NOMBRE_REPOSITORIO}"
Ahora creamos la base de datos:
- echo "Creo la base de datos"
- $(mysqladmin -u ic --password=12312312 create ${DB_NAME})
-
- echo "Creo el usuario de MySQL"
- $(mysql -u ic --password=12312312 --execute="GRANT ALL on ${DB_NAME}.* to ${DB_USER}@localhost identified by '${DB_PASSWORD}'")
Al realizar la instalación de WordPress desde el navegador, nos piden algunos datos que debemos indicar, por tanto se los pedimos al usuario:
- echo "Antes de iniciar el proceso de instalación para obtener una copia de la BD es necesario que me indiques algunos datos"
-
- while [ -z $TITLE ]
- do
- echo "¿Título del blog?: "
- read TITLE
-
- if [ -z $TITLE ]
- then
- echo "Es necesario indicar un título"
- fi
- done
-
- while [ -z $ADMIN_NAME ]
- do
- echo "¿Nombre del administrador? (por defecto: admin): "
- read ADMIN_NAME
-
- if [ -z $ADMIN_NAME ]
- then
- ADMIN_NAME="admin"
- fi
- done
-
- while [ -z $ADMIN_PASS ]
- do
- echo "¿Contraseña para el administrador? (por defecto: 12312312): "
- read ADMIN_PASS
-
- if [ -z $ADMIN_PASS ]
- then
- ADMIN_PASS="12312312"
- fi
- done
-
- while [ -z $ADMIN_EMAIL ]
- do
- echo "¿Email para el administrador? (por defecto: tuemail@mail.com): "
- read ADMIN_EMAIL
-
- if [ -z $ADMIN_EMAIL ]
- then
- ADMIN_EMAIL="tuemail@mail.com"
- fi
- done
-
- while [ -z $SEARCH_ENGINES ]
- do
- echo "¿Permite que los motores de búsquedas indexen este sitio.? y/n (por defecto: y): "
- read SEARCH_ENGINES
-
- if [ -z $SEARCH_ENGINES ]
- then
- SEARCH_ENGINES="y"
- fi
- done
Puedes sustituir «tuemail@mail.com» por la dirección de email que uses en tus desarrollos.
Ahora añadimos una línea para ejecutar la instalación de WordPress en Selenium:
- echo "Ejecuto el script de Selenium para instalar WordPress y así poder hacer una copia de la BD"
-
- $(php /var/www/dev/selenium/wordpress/instalar_wordpress.php -- ${NOMBRE_REPOSITORIO} "${TITLE}" ${ADMIN_NAME} ${ADMIN_PASS} ${ADMIN_EMAIL} ${SEARCH_ENGINES})
El contenido del script lo explicaré con detenimiento en el próximo post.
Una vez finalizado el script de Selenium es necesario guardar una copia de la BD, por seguridad:
- echo "Realizo la copia de la estructura de la BD"
- $(mysqldump -uic -p12312312 --no-data --add-drop-database --databases ${DB_NAME} > "${TEMP_DIR}/db/basic/basic_structure.sql")
-
- echo "Realizo la copia de los datos de la BD"
- $(mysqldump -uic -p12312312 --complete-insert --no-create-info ${DB_NAME} > "${TEMP_DIR}/db/basic/basic_data.sql")
Le preguntamos al usuario por los plugins y/o temas a instalar en el proyecto:
- echo "Ahora necesito saber los temas y plugins a instalar"
-
- while [ -z $IFEATURE ]
- do
- echo "¿Desea utilizar iFeature como Tema? (y/n) (default=n)"
- read IFEATURE
-
- if [ -z $IFEATURE ]
- then
- IFEATURE="n"
- fi
- done
-
- while [ -z $ERRORLOGMONITOR ]
- do
- echo "¿Desea utilizar el plugin de desarrollo error-log-monitor? (y/n) (default=y)"
- read ERRORLOGMONITOR
-
- if [ -z $ERRORLOGMONITOR ]
- then
- ERRORLOGMONITOR="y"
- fi
- done
En mi caso tengo bastantes más plugins en el script, pero para que te hagas una idea de la estructura que debe tener el código solo te muestro dos, el resto es siempre igual: Se crea el while, se muestra la pregunta y se comprueba que el usuario haya escrito algo o no. Para otros temas o plugins tendrías que replicar el mismo código tantas veces como temas y plugins quieras añadir al script. Recuerda que en cada bloque debe existir una variable única para cada tema o plugin.
Copiamos los temas y plugins a sus respectivos directorios dentro del proyecto:
- echo "Con esta información voy a copiar los temas y plugins elegidos al directorio temporal."
-
- if [ $IFEATURE == "y" ]
- then
- $(mkdir "${TEMP_DIR}/wp-content/themes/ifeature")
- $(cp -r "${DIR_SOURCES}themes/ifeature/"* "${TEMP_DIR}/src/wp-content/themes/ifeature")
- THEME="iFeature"
- fi
Para el tema que vayas a instalar es necesario añadir la variable THEME con el nombre del tema. Esto permitirá instalar el tema a través de Selenium.
El código de arriba será igual para todos los temas y plugins (exceptuando la línea «THEME» que solo se utiliza en los temas), tendrás que cambiar las rutas para que apunten a sus respectivos directorios.
Y debajo de este código, añadimos el siguiente:
- echo "Copio de nuevo el contenido del directorio temporal a /var/www/ para obtener una copia de la BD"
- cp -r "${TEMP_DIR}/src/*" "/var/www/${NOMBRE_REPOSITORIO}"
-
- echo "Activo los plugins utilizando un script de Selenium"
- $(php /var/www/dev/selenium/wordpress/instalar_plugins_wordpress.php -- ${NOMBRE_REPOSITORIO} ${ADMIN_NAME} ${ADMIN_PASS})
-
- echo "Activo el tema que se ha elegido"
- $(php /var/www/dev/selenium/wordpress/instalar_tema_wordpress.php -- ${NOMBRE_REPOSITORIO} ${ADMIN_NAME} ${ADMIN_PASS} ${THEME})
-
- echo "Hago un backup de la base de datos con los plugins y el tema ya instalados"
- $(mysqldump -uic -p12312312 --no-data --add-drop-database --databases ${DB_NAME} > "${TEMP_DIR}/db/modules/modules_structure.sql")
-
- echo "Realizo la copia de los datos de la BD"
- $(mysqldump -uic -p12312312 --complete-insert --no-create-info ${DB_NAME} > "${TEMP_DIR}/db/modules/modules_data.sql")
Al instalar los plugins y temas, volvemos a realizar la copia de la base de datos.
Para los plugin de desarrollo como error-log-monitor, lo que hice es separarlos del resto de plugins, con lo que ahora toca copiarlos e instalarlos:
- echo "Instalo los plugins de desarrollo elegidos"
-
- if [ $ERRORLOGMONITOR == "y" ]
- then
- $(mkdir "${TEMP_DIR}/wp-content/plugins/error-log-monitor")
- $(cp -r "${DIR_SOURCES}plugins/error-log-monitor/"* "${TEMP_DIR}/src/wp-content/plugins/error-log-monitor")
- fi
Esto me permite crear dos copias de la base de datos: una con los plugins de desarrollo y otra sin ellos. Esto es muy útil a la hora de poder cambiar entre bases de datos y entornos.
Hacemos copia de la BD con los nuevos plugins:
- echo "Copio de nuevo el contenido del directorio temporal a /var/www/ para obtener una copia de la BD"
- cp -r "${TEMP_DIR}/src/*" "/var/www/${NOMBRE_REPOSITORIO}"
-
- echo "Activo los plugins utilizando un script de Selenium"
- $(php /var/www/dev/selenium/wordpress/instalar_plugins_dev_wordpress.php -- ${NOMBRE_REPOSITORIO} ${ADMIN_NAME} ${ADMIN_PASS})
-
- echo "Hago un backup de la base de datos con los plugins de desarrollo ya instalados"
- $(mysqldump -uic -p12312312 --no-data --add-drop-database --databases ${DB_NAME} > "${TEMP_DIR}/db/modules-dev/modules-dev_structure.sql")
-
- echo "Realizo la copia de los datos de la BD"
- $(mysqldump -uic -p12312312 --complete-insert --no-create-info ${DB_NAME} > "${TEMP_DIR}/db/modules-dev/modules-dev_data.sql")
El script de Selenium lo veremos más adelante.
El código es practicamente igual, con la excepción de que ahora se crea un archivo sql con los plugins de desarrollo ya instalados.
Ahora copiamos algunos scripts para la instalación de la base de datos en los diferentes entornos:
- echo "Añado el archivo de instalación de la base de datos en el directorio sh"
- cp "${DIR_BASE_PROJECTS}dev/sh/instalar_db.sh" "${TEMP_DIR_TRUNK}/sh/instalar_db.sh"
- cp "${DIR_BASE_PROJECTS}dev/sh/instalar_db.sh" "${TEMP_DIR_TRUNK}/sh/instalar_db_dev.sh"
- sed -i -e "s/@USER@/ic/g" "${TEMP_DIR_TRUNK}/sh/instalar_db_dev.sh"
- sed -i -e "s/@PASS@/12312312/g" "${TEMP_DIR_TRUNK}/sh/instalar_db_dev.sh"
- sed -i -e "s/@BD@/${DB_NAME}/g" "${TEMP_DIR_TRUNK}/sh/instalar_db_dev.sh"
- sed -i -e "s/@STRUCTURE_FILE@/${SED_TEMP_DIR}\/db\/modules-dev\/modules-dev_structure.sql/g" "${TEMP_DIR_TRUNK}/sh/instalar_db_dev.sh"
- sed -i -e "s/@DATA_FILE@/${SED_TEMP_DIR}\/db\/modules-dev\/modules-dev_data.sql/g" "${TEMP_DIR_TRUNK}/sh/instalar_db_dev.sh"
-
- sed -i -e "s/@USER@/ic/g" "${TEMP_DIR_TRUNK}/sh/instalar_db.sh"
- sed -i -e "s/@PASS@/12312312/g" "${TEMP_DIR_TRUNK}/sh/instalar_db.sh"
- sed -i -e "s/@BD@/${DB_NAME}/g" "${TEMP_DIR_TRUNK}/sh/instalar_db.sh"
- sed -i -e "s/@STRUCTURE_FILE@/${SED_TEMP_DIR}\/db\/modules\/modules_structure.sql/g" "${TEMP_DIR_TRUNK}/sh/instalar_db.sh"
- sed -i -e "s/@DATA_FILE@/${SED_TEMP_DIR}\/db\/modules\/modules_data.sql/g" "${TEMP_DIR_TRUNK}/sh/instalar_db.sh"
De esta manera podemos tener siempre una copia de la base de datos con diferentes plugins instalados, lo que nos da muchas facilidades a la hora de cambiar de entorno de desarrollo a preproducción, testeo y/o producción.
Por último, y para acabar nuestro script hacemos commit y eliminamos los datos temporales:
- echo "Ahora procederé a realizar un commit del nuevo contenido"
-
- cd $TEMP_DIR
-
- if [ "$TIPO_REPOSITORIO" == 'git' ]
- then
- $(git add *)
- $(git commit -m "Añadido los temas y plugins correspondientes")
- $(git push origin master)
- elif [ "$TIPO_REPOSITORIO" == 'svn' ]
- then
- $(svn commit -m "Añadidos los temas y plugins correspondientes" http://svn.ic.net/$NOMBRE_REPOSITORIO)
- fi
-
- #Eliminamos el directorio temporal
- echo "Eliminamos el directorio temporal, la base de datos y su usuario y cerramos la máquina virtual"
- $(mysql -u ic --password=12312312 --execute="REVOKE ALL ON *.* FROM '${DB_USER}'@'localhost';")
- $(mysqladmin -uic -p12312312 drop ${DB_NAME})
- $(VBoxManage controlvm Ubuntu poweroff)
- $(rm -fr $TEMP_DIR)
- $(rm -fr "/var/www/${NOMBRE_REPOSITORIO}"