Maven pluginek verziószáma

Technológiák: Maven 2.1.1, Maven 3.0.3

Egy régebbi posztban már említettem, hogy a Maven moduláris felépítésű, és minden pluginben van megvalósítva. Az életciklus különböző fázisaiban (phase) különböző pluginok különböző céljai (goal) futnak le. Minden feladatot tehát valójában egy-egy plugin végez el, ezen pluginokból rengeteg támogatott és egyedi plugin is létezik. A Compiler plugin végzi a fordítást, a JAR, WAR és EAR például a csomagolást, stb. A pluginek két csoportra oszthatók, build pluginek és reporting pluginek.

A következő poszt azt demonstrálja, hogy miért szükséges a pluginek verziószámát is deklarálni a pom.xml-ben. Egy nem általunk készített alkalmazás Maven 3.0.3-ra migrációjánál a következő hibaüzenetet vettem észre egy projektnél:

[WARNING] Warning: selected war files include a WEB-INF/web.xml which
will be ignored
(webxml attribute is missing from war task, or ignoreWebxml attribute
is specified as 'true')

A hibaüzenet a war plugin adja, a hibaüzenet számomra teljesen értelmezhetetlen. Milyen war fájlok (többesszám!) tartalmaznak már web.xml állományt? A dokumentációt megnézve a hibaüzenetben ezen kívül két hiba is van, az első említett paraméter helyes írásmódja webXml, a másik ignoreWebxml paraméter nem is létezik (http://maven.apache.org/plugins/maven-war-plugin/war-mojo.html).

Mivel emlékeztem, hogy a Maven 2.1.1 hasonló hibát nem dobott, ezt újra leellenőriztem, és tényleg nem írt ki hibát. Ebből már sejthető volt, hogy verzióeltérés lesz.

Először egy help:describe paranccsal próbálkoztam Maven 3.0.3-assal, mely egy rövid súgót ad az adott pluginre vonatkozóan. Ez még egy olyan könyvtárban, ahol nincs pom.xml, tehát projekttől függetlenül. Erről a FAQ kicsit félrevezetően ír.

$ mvn help:describe -Dplugin=war
...
Name: Maven WAR Plugin
Description: Builds a Web Application Archive (WAR) file from the project
  output and its dependencies.
Group Id: org.apache.maven.plugins
Artifact Id: maven-war-plugin
Version: 2.1.1
Goal Prefix: war
...

A plugin paraméternél megadott prefix (war) helyett megadhatunk groupId, artifactId párt is (-Dplugin=org.apache.maven.plugins:maven-war-plugin). Amennyiben nem a verziószámra vagyunk kíváncsiak, hanem egy adott verzióhoz tartozó célokra, megadhatunk GAV (groupId, artifactId, version) hármast is, a szokásos jelöléssel, kettőspontokkal elválasztva. De megadhatjuk a GAV-ot három paraméterrel is:

mvn help:describe -DgroupId=org.apache.maven.plugins
  -DartifactId=maven-war-plugin -Dversion=2.1.1 -Ddetail=true -Dgoal=war

Ne feledjük, hogy amennyiben elírjuk a paraméter nevét, a Maven erről nem figyelmeztet, egyszerűen figyelmen kívül hagyja. Részletesebb súgót, mely a paramétereket is tartalmazza a -Ddetail paraméterrel kérhetünk (régebben full paraméter volt). A -Dgoal=war paraméterezéssel tudunk csak egy célról információt kérni.

Az első parancsot kiadva Maven 2.1.1-nél azt tapasztalhatjuk, hogy a verzió 2.2-SNAPSHOT. Egy kis kutakodás után kiderült, hogy a Maven 2 és 3 között inkompatibilitás van, azzal kapcsolatban, hogy hogyan keresi meg a verziószámát a használni kívánt pluginnek. Míg a 2-es a legutolsó verziót tölti le (2.2-SNAPSHOT), addig a 3-asban a stabilitás érdekében azt a döntést hozták, hogy a legutolsó release verziót használja, ami jelenleg a 2.1.1.

Ez a parancs nem adja viszont azt meg, hogy az adott projektben a kérdéses plugin melyik verziója kerül felhasználásra. Az adott projektben nem volt a plugin definiálva. A Maven 3 már futás közben is tájékoztat a verziószámról.

Ahhoz, hogy a Maven 2 futás közben is kiírja, a -X kapcsolóval kell indítani, és a nagyon részletes logból kibogarászni:

[DEBUG] Configuring mojo
  'org.apache.maven.plugins:maven-war-plugin:2.1-alpha-2:war' -->

Látható, hogy míg a 2-es Maven a 2.1-alpha-2 verzióval dolgozik, addig a 3-as a 2.1.1-gyel. De mégis hol van ez definiálva? A választ a következő parancs adja meg:

mvn help:effective-pom

A Maven Help pluginjének effective-pom paranccsa összefésüli a super pom-ot és a projekt pom-ját (, és annak szülőit, valamint figyelembe veszi a profilokat). Mivel a projekt pom-jában nincs a plugin definiálva, azt a super pom-ból veszi, ami a 2-esben a M2_HOME/lib/maven-2.2.1-uber.jar:org/apache/maven/project/pom-4.0.0.xml helyen, míg a 3-asban a M2_HOME/lib/maven-model-builder-3.0.3.jar:org/apache/maven/model/pom-4.0.0.xml helyen van. Tehát a Maven verziójától függ, hogy mik az alapértelmezett plugin verziószámok egy projekten belül.

Tehát míg a Maven 2 által definiált 2.1-alpha-2 nem dobja a hibát, addig a 2.1.1 igen, amiről egy stackoverflow kérdés, és egy JIRA issue is megemlékezik. Ennek megoldása egyszerű, helyezzük el a pom.xml-ben a következőt:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <configuration>
        <packagingExcludes>WEB-INF/web.xml</packagingExcludes>
      </configuration>
    </plugin>
  </plugins>
</build>

Úgy tűnik nem tanultunk az előző hibánkból, és újra elkövettük, hogy a plugin verziószámát nem definiáltuk. Erre a Maven 3 már alapból figyelmeztet:

[WARNING]
[WARNING] Some problems were encountered while building the effective model
  for jtechlog.earconfig:earconfig-web:war:1.0-SNAPSHOT
[WARNING] 'build.plugins.plugin.version' for
  org.apache.maven.plugins:maven-war-plugin is missing. @ line 60, column 9
[WARNING]
[WARNING] It is highly recommended to fix these problems because they
  threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer
  support building such malformed projects.
[WARNING]

A version tag beillesztésével azonnal javíthatjuk a hibát. Ekkor már nem a super pom-ban definiált verzió, hanem a saját pom.xml-ünkben definiált verzió fog érvényesülni. A verzió automatikus meghatározását a Maven Automatic Plugin Version Resolution-nek nevezi, és a warning amiatt jelenik meg, mert a későbbi verziókban a build reprodukálhatóságának megsegítéseként el kívánják távolítani, ezért érdemes mindenképp explicit definiálni a verziókat.

Amennyiben a 2-es Maven verziót használjuk, ugyanerre megfelelő az Enforcer plugin enforce célja. A következőképp konfigurálhatjuk:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-enforcer-plugin</artifactId>
  <version>1.0.1</version>
  <executions>
    <execution>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <requirePluginVersions>
            <banLatest>true</banLatest>
            <banRelease>true</banRelease>
          </requirePluginVersions>
        </rules>
      </configuration>
    </execution>
  </executions>
</plugin>

Futtatáskor a következő hibát kaphatjuk:

[WARNING] Rule 0: org.apache.maven.plugins.enforcer.RequirePluginVersions
  failed with message:
Some plugins are missing valid versions:(LATEST RELEASE SNAPSHOT are
  not allowed )
org.apache.maven.plugins:maven-war-plugin.  The version currently in
  use is 2.1-alpha-2

A Maven 3-nál többet tud, ugyanis a nem definiált plugin-okat is jelzi. Az előbbi példánál maradva, ha nem tettük volna bele a Maven WAR plugin definícióját a pom.xml-be, a Maven 3 nem panaszkodott volna, hogy nem a legfrissebb plugint futtatja. Az Enforcer plugin viszont ezt is észreveszi, bővebb a funkcionalitása.

Az Enforcer plugint a 3-as Mavennel futtatva viszont a következő hibaüzenetet kapjuk. Erről is van JIRA issue.

[INFO] The requirePluginVersions rule is currently not compatible with Maven3.

Projekt öröklődés esetén a plugin beállításai alapesetben nem öröklődnek. Ahhoz, hogy mégis, a beállításokat a szülő projekt pom.xml-jében a pluginManagement részben kell elhelyezni. Így a verziószám és a konfiguráció is öröklődik. Ekkor a gyermek projektben elegendő csak a groupId-t és az artifactId-t elhelyezni. Nagy projekt esetén jelentős copy-paste munkát takaríthatunk meg ezzel.

Néha szükségünk lehet arra is, hogy megnézzük, hogy van-e frissebb verzió egy adott plugin-ból. Ezt a Versions pluginnel kérhetjük le a következő módon:

mvn versions:display-plugin-updates

Régebben a -cpu kapcsoló is jó volt erre, de ez deprecated, így ne használjuk. Másik lehetőség, hogy egyszerűen rákeresünk a Maven repository-ban a http://search.maven.org címen.

A pluginek verziószámát a site generálás is szépen megmutatja a Maven 2-ben, a plugin-management.html oldalon.

Project Plugin Management

A Maven 3-ban ez nem ilyen egyszerű. A mvn site parancsot kiadva alapértelmezetten semmit nem kapunk. Konfigurálni kell a Maven Site plugint, hogy futtassa a Maven Projects Info Reports plugint, és az generálja le pl. a Plugin management riporot. Ez a következőképp néz ki:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-site-plugin</artifactId>
  <version>3.0</version>
  <configuration>
    <reportPlugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-project-info-reports-plugin</artifactId>
        <version>2.4</version>
        <reports>
          <report>plugin-management</report>
        </reports>
      </plugin>
    </reportPlugins>
  </configuration>
</plugin>

Azaz ha biztosak akarunk lenni a build reprodukálhatóságában, mindig definiáljuk a pluginek verziószámát. A Maven 3 tett egy lépést ennek kikényszerítésének az irányában.