Maven – faza versus komenda wtyczki

Na samym wstępie pragnę wytłumaczyć co rozumiem przez fazę i co rozumiem przez komendę wtyczki.
Faza – tutaj bez niespodzianek, mam na myśli fazę cyklu życia Mavena (ang. phase)
Komenda wtyczki – będzie to to, co w nomenklaturze Mavena nazywa się plugin’s goal (przykładowo effective-pom będzie komendą wtyczki help)

Sformułowanie z tytułu ma za zadanie przybliżyć nas do odpowiedzi na pytanie – co uruchamiamy wpisując powiedzmy:

I krótką odpowiedzią na to pytanie jest – uruchamiamy fazę (komendę uruchamia się podając prefiks wtyczki, później dwukropek i na końcu komenda -> prefiks:komenda).

Uruchamianie komend wtyczek

Aby przygotować grunt pod opis faz cyklu, warto dowiedzieć się, jak uruchamiać komendy wtyczek. Załóżmy, że znaleźliśmy sobie jakąś wtyczkę – niech to będzie maven-failsafe-plugin. Teraz chcemy sprawdzić jakie komendy ona oferuje. Są dwie możliwości:

1. Sprawdzić dokumentację w Internecie. W przypadku wtyczki maven-failsafe-plugin jest to dobrze opisane tutaj
2. Można też sprawdzić opis wtyczki za pomocą linii komend wpisując: mvn help:describe -DgroupId=org.apache.maven.plugins -DartifactId=maven-failsafe-plugin co zwróci:

Name: Maven Failsafe Plugin
Description: Maven Failsafe MOJO in maven-failsafe-plugin.
Group Id: org.apache.maven.plugins
Artifact Id: maven-failsafe-plugin
Version: 3.1.2
Goal Prefix: failsafe

This plugin has 3 goals:

failsafe:help
  Description: Display help information on maven-failsafe-plugin. Call mvn
    failsafe:help -Ddetail=true -Dgoal= to display parameter details.

failsafe:integration-test
  Description: Run integration tests using Surefire.

failsafe:verify
  Description: Verify integration tests ran using Surefire.

For more information, run 'mvn help:describe [...] -Ddetail'

W obydwu źródłach można znaleźć informację o takich komendach jak (help jest wylistowany tylko przez drugą opcję):
integration-test
verify

Zauważ, że poprzedzone są one tak zwanym prefiksem komendy (patrz Goal Prefix). W tym wypadku prefiksem jest failsafe.

Aby uruchomić taką komendę należy ją wprowadzić w pełnej formie – prefiks:komenda :

->mvn failsafe:integration-test
->mvn failsafe:verify
->mvn failsafe:integration-test failsafe:verify

Co się dzieje po uruchomieniu fazy cyklu życia?

Zanim odpowiemy sobie na to pytanie, trzeba wyjaśnić sobie jeszcze kilka rzeczy 🙂

Cykle życia

Maven posiada trzy cykle życia: clean, default oraz site:

Powyższy obrazek nie ukazuje wszystkich faz cyklów. Pełny wykaz faz cyklów znajdziesz tutaj.

Automatyczne uruchamianie poprzednich faz cyklu

Maven domyślnie uruchamia wszystkie poprzedzające fazy cyklu. Patrząc przykładowo na cykl default, można zauważyć, że składa się on z wielu faz (validate, compile, test…). Uruchamiając dowolną z jego faz powodujemy automatyczne uruchomienie wszystkich poprzednich, ale tylko w ramach tego cyklu. Przykładowo uruchamiając:

uruchomione zostaną także fazy: validate, compile, test (i wszystkie inne nie wymienione tutaj fazy poprzedzające). Ale nie zostanie uruchomiona na przykład faza clean cyklu clean. Identycznie jest z fazami innych cyklów – uruchomienie:

nie spowoduje uruchomienia faz cyklu default (validate, compile, test, install…).

Powiązanie faz z komendami wtyczek

Do każdej fazy można przypiąć dowolną ilość komend wtyczek. A robi się to za pomocą konfiguracji wtyczek – sekcja executions:

<build>
    <plugins>
        <plugin>
            <groupId>...</groupId>
            <artifactId>...</artifactId>
            <version>...</version>
            <executions>
                <execution>
                    <id>execution-id-1</id>
                    <phase>compile</phase>
                    <goals>
                        <goal>plugin-goal-1</goal>
                        <goal>plugin-goal-2</goal>
                    </goals>
                </execution>
                <execution>
                    <id>execution-id-2</id>
                    <phase>test</phase>
                    <goals>
                        <goal>plugin-goal-3</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
</build>

Sekcja executions może zawierać dowolną ilość elementów execution. Z tym, że każda sekcja execution musi posiadać unikalny identyfikator (id).

W każdej sekcji execution określamy zarówno fazę (phase) jak i komendy wtyczki (goals):

<execution>
    <id>execution-id-1</id>
    <phase>compile</phase>
    <goals>
        <goal>plugin-goal-1</goal>
        <goal>plugin-goal-2</goal>
    </goals>
</execution>

Fazę wybieramy z zakresu dostępnych faz. A komendy muszą przynależeć do konfigurowanej wtyczki – patrz Uruchamianie komend wtyczek – podawanymi bez prefiksu.

Jak można łatwo zauważyć, możliwe jest uruchomienie więcej niż jednej komendy w danej fazie.

Taka konfiguracja zapewnia, że komendy wtyczki uruchomią się w wybranych fazach.

Domyślne fazy komend

Czasami można spotkać konfigurację wtyczki bez podania fazy, przykładowo:

<plugin>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>3.1.2</version>
    <executions>
        <execution>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Jest to jak najbardziej poprawna konfiguracja. A sztuczka polega na tym, że komendy wtyczek mogą być domyślnie powiązane z jakąś fazą. I tak też jest w sytuacji komend integration-test oraz verify wtyczki maven-failsafe-plugin. Można to sprawdzić poprzez wyświetlenie szczegółowych (-Ddetail=true) informacji na temat danej wtyczki:

mvn help:describe -DgroupId=org.apache.maven.plugins   -DartifactId=maven-failsafe-plugin  -Ddetail=true

i otrzymujemy:

Name: Maven Failsafe Plugin
Description: Maven Failsafe MOJO in maven-failsafe-plugin.
[...]
This plugin has 3 goals:
failsafe:help
  Description: Display help information on maven-failsafe-plugin. Call mvn
    failsafe:help -Ddetail=true -Dgoal= to display parameter details.
  Implementation: org.apache.maven.plugins.maven_failsafe_plugin.HelpMojo
  Language: java
[...]
failsafe:integration-test
  Description: Run integration tests using Surefire.
  Implementation: org.apache.maven.plugin.failsafe.IntegrationTestMojo
  Language: java
  Bound to phase: integration-test
[...]
failsafe:verify
  Description: Verify integration tests ran using Surefire.
  Implementation: org.apache.maven.plugin.failsafe.VerifyMojo
  Language: java
  Bound to phase: verify

Jak widać, komenda integration-test jest domyślnie powiązana z fazą integration-test. A komenda verify, jest powiązana domyślnie z fazą verify. Widać także, że komenda help nie jest powiązana domyślnie z żadną fazą. Warto wspomnieć, że wciąż można jawnie wskazać fazę w konfiguracji lub też ją nadpisać dla każdej z komend, przykładowo:

<plugin>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>3.1.2</version>
    <executions>
        <execution>
            <phase>test</phase>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
        <execution>
            <phase>install</phase>
            <goals>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Taka konfiguracja nie do końca ma sens, ale jest to możliwe 🙂

A co jeśli nie powiążę żadnych komend z fazami?

Można by pomyśleć, że jeśli sami nie podepniemy komend do faz cyklów, to uruchomienie konkretnej fazy nie spowoduje żadnego działania. Nic bardziej mylnego. Maven posiada wbudowane powiązania komend wtyczek z fazami. Tutaj kilka przykładowych powiązań:

clean -> clean:clean
compile -> compiler:compile
test -> surefire:test

Pełną listę powiązań można znaleźć tutaj.

Odpowiedź

Zatem odpowiedzią na pytanie „Co się dzieje po uruchomieniu fazy cyklu życia?” będzie: Uruchamiane są wszystkie poprzedzające fazy danego cyklu wraz z wybraną fazą. A co za tym idzie uruchamiane są komendy wtyczek podpięte (domyślnie, bądź jawnie) pod każdą z uruchomionych faz.

Miksowanie faz i komend

Okazuje się, że możliwe jest uruchamianie faz i komend w ramach jednej instrukcji, na przykład:

mvn clean dependency:copy-dependencies package

Podane fazy/komendy uruchomią się z zadaną kolejnością – najpierw zostanie uruchomiona faza clean (z ją poprzedzającymi fazami w ramach cyklu cleanpre-clean), następnie komenda copy-dependencies wtyczki dependency, a na końcu faza package (z ją poprzedzającymi fazami w ramach cyklu defaultvalidate, compile, test…).

Warto zajrzeć

1. https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html