java - ¿Cuál es el método Maven para las versiones automáticas de proyectos cuando se realiza una entrega continua?
continuous-integration maven-3 (7)
A partir de Maven 3.2.1, las versiones compatibles de entrega continua se admiten de forma inmediata: https://issues.apache.org/jira/browse/MNG-5576 Puede usar 3 variables predefinidas en la versión:
${changelist}
${revision}
${sha1}
Entonces, básicamente lo que haces es:
- Configure su versión a, por ejemplo,
1.0.0-${revision}
. (Puede usarmvn versions:set
para hacerlo rápida y correctamente en proyectos de varios módulos). - Coloque una propiedad
<revision>SNAPSHOT</revision>
para el desarrollo local. - En su entorno de CI, ejecute
mvn clean install -Drevision=${BUILD_NUMBER}
o algo así o inclusomvn clean verify -Drevision=${BUILD_NUMBER}
.
Puede usar, por ejemplo, https://wiki.jenkins-ci.org/display/JENKINS/Version+Number+Plugin para generar números de compilación interesantes.
Una vez que descubra que la construcción es estable (por ejemplo, pruebas de aceptación de pase), puede enviar la versión a Nexus u otro repositorio. Cualquier compilación inestable solo va a la papelera.
Tengo una aplicación web en la que implementamos en producción cada vez que una función está lista, a veces puede ser un par de veces al día, a veces puede tardar un par de semanas entre lanzamientos.
Actualmente, no incrementamos nuestros números de versión para nuestro proyecto, y todo ha estado funcionando en la versión 0.0.1-SNAPSHOT
durante más de un año. Me pregunto cuál es la forma Maven de hacer entregas continuas para aplicaciones web. Parece excesivo aumentar el número de versión en cada confirmación, y nunca golpear el número de versión como lo estamos haciendo ahora, también parece estar mal.
¿Cuál es la mejor práctica recomendada para este tipo de uso de Maven?
El problema es doble:
- Avance del número de versión del proyecto en el archivo
pom.xml
individual (y puede haber muchos). - Actualizando el número de versión en todos los componentes dependientes para usar los últimos entre sí.
Como punto de partida, puede echar un vistazo a Maven: The Complete Reference. Versiones de proyectos.
Luego hay una buena publicación en la estrategia de control de versiones.
En mi trabajo para aplicaciones web, actualmente utilizamos este patrón de control de versiones:
<jenkins build num>-<git-short-hash>
Ejemplo: 247-262e37b9.
Esto es bueno porque te da una versión que siempre es única y rastreable de vuelta a la versión de jenkins y la revisión de git que la produjo.
En Maven 3.2.1+ finalmente eliminaron las advertencias por usar $ {property} como una versión, por lo que es muy fácil construirlas. Simplemente cambie todos sus poms para usar <version>${revision}</version>
y compilar con -Drevision=whatever
. El único problema con eso es que en tus poms lanzados la versión permanecerá en ${revision}
en el archivo pom real que puede causar todo tipo de problemas extraños. Para resolver esto, escribí un plugin maven simple ( https://github.com/jeffskj/cd-versions-maven-plugin ) que hace la sustitución de variables en el archivo.
Este es mi resumen basado en el video vinculado por la respuesta de Mark O''Connor.
- La solución requiere un DVCS como git y un servidor de CI como Jenkins.
- No utilice compilaciones de instantáneas en la canalización de Entrega continua y no use el complemento de lanzamiento Maven.
- Las versiones de instantáneas como
1.0-SNAPSHOT
se convierten en versiones reales, como1.0.buildNumber
dondebuildNumber
es el número de trabajo de Jenkins.
Pasos del algoritmo:
- Jenkins clona el repositorio git con el código fuente, y dice que el código fuente tiene la versión
1.0-SNAPSHOT
- Jenkins crea una rama de git llamada
1.0.JENKINS-JOB-NUMBER
para que la versión de instantánea se convierta en una versión real1.0.124
- Jenkins invoca el complemento de versiones maven para cambiar el número de versión en los archivos pom.xml de
1.0-SNAPSHOT
a1.0.JENKINS-JOB-NUMBER
- Jenkins invoca la
mvn install
- Si la
mvn install
es exitosa, Jenkins confirmará la rama1.0.JENKINS-JOB-NUMBER
y se creará una versión real que no sea de instantánea con una etiqueta adecuada en git para su posterior reproducción. Si lamvn install
falla, Jenkins simplemente eliminará la rama recién creada y fallará la compilación.
Recomiendo encarecidamente el video vinculado desde la respuesta de Marcos.
Hay algunas grandes discusiones y propuestas sobre cómo lidiar con el número de versión de maven y la entrega continua (CD) (las agregaré después de mi parte de la respuesta).
Así que primero mi opinión sobre las versiones de SNAPSHOT. En maven, una INSTANTÁNEA muestra que esto está actualmente en desarrollo para la versión específica antes del sufijo SNAPSHOT. Debido a esto, las herramientas como Nexus o el complemento maven-release tienen un tratamiento especial para SNAPSHOTS. Para Nexus, se almacenan en un repositorio separado y se le permite actualizar varios artefactos con la misma versión de lanzamiento de SNAPSHOT. Así que una INSTANTÁNEA puede cambiar sin que usted lo sepa (porque nunca incrementa ningún número en su pom). Debido a esto, no recomiendo usar dependencias SNAPSHOT en un proyecto, especialmente en un mundo de CD, ya que la construcción ya no es confiable.
SNAPSHOT como versión de proyecto sería un problema cuando su proyecto es utilizado por otros, debido a las razones anteriores.
Otro problema de SNAPSHOT para mí es que ya no es realmente rastreable ni reproducible. Cuando veo una versión 0.0.1-SNAPSHOT en producción, necesito hacer algunas búsquedas para descubrir cuándo fue compilación a partir de qué revisión fue compilada. Cuando encuentro un lanzamiento de este software en un sistema de archivos, necesito echar un vistazo a los archivos pom.properties o MANIFEST para ver si esto es basura vieja o tal vez la última y mejor versión.
Para evitar el cambio manual del número de versión (especialmente cuando construye varias compilaciones por día), permita que Build Server cambie el número por usted. Entonces para el desarrollo iría con un
<major>.<minor>-SNAPSHOT
versión, pero al construir una nueva versión, Build Server podría reemplazar SNAPSHOT con algo más único y trazable.
Por ejemplo, uno de esto:
<major>.<minor>-b<buildNumber>
<major>.<minor>-r<scmNumber>
Por lo tanto, el número mayor y menor se puede utilizar para cuestiones de marketing o simplemente para mostrar que se alcanza un nuevo hito importante y se puede cambiar manualmente cuando lo desee. Y el buildNumber (número de su servidor de integración continua) o el scmNumber (revisión de SUbversion o GIT) hacen que cada versión sea única y rastreable. Al usar la revisión buildNumber o Subversion, las versiones del proyecto son incluso ordenables (no con números GIT). Con buildNumber o scmNumber también es fácil ver qué cambios hay en esta versión.
Otro ejemplo es la versión de que utiliza
<year>.<month>.<day>.<buildNumber>
Y aquí los enlaces faltantes:
Recomiendo la siguiente presentación que discute las realidades prácticas de hacer una entrega continua con Maven:
El punto clave es que cada versión es una versión potencial, por lo que no debe usar instantáneas.
NO HAGAS ESTO!
<Major>.<minor>-<build>
te morderá en la parte trasera porque Maven trata cualquier cosa después de un guión como LÉXICO. Esto significa que la versión 1 será léxicamente más alta que 10.
Esto es malo, como si estuviera pidiendo la última versión de algo en Maven, entonces el punto anterior gana.
La solución es usar un punto decimal en lugar de un guion que preceda al número de compilación.
¡HACER ESTO!
<Major>.<minor>.<build>
Está bien tener versiones SNAPSHOT localmente, pero como parte de una compilación, es mejor usar
mvn versions:set -DnewVersion=${major}.${minor}.${build.number}
Hay formas de derivar la versión mayor / menor del pom, por ejemplo, usando ayuda: evaluar y canalizar a una variable de entorno antes de invocar versiones: establecer. Esto es sucio, pero realmente me rasqué la cabeza (y otros en mi equipo) para hacerlo más simple, y (en ese momento) Maven no era lo suficientemente maduro como para manejar esto. Creo que Maven 2.3.1 podría tener algo que ayuda de alguna manera a esto, por lo que esta información ya no es relevante.
Está bien que un grupo de desarrolladores publique en la misma versión major.minor, pero siempre es bueno tener en cuenta que los cambios menores no se rompen y que los cambios importantes de la versión tienen algún cambio en la API o una depreciación de la funcionalidad / comportamiento.
Desde una perspectiva de Entrega continua, cada compilación es potencialmente liberable, por lo tanto, cada check-in debe crear una compilación.