#67: Konsistente Versionierung via Maven CI-friendly revision

- ${revision}-Property im Parent-POM eingeführt; alle Kind-POM-<parent>-Blöcke
  verwenden ${revision} statt hartkodierter Version
- flatten-maven-plugin 1.6.0 in <build><plugins> des Parent-POM aktiviert
  (resolveCiFriendliesOnly), sodass installierte POMs keine unaufgelösten
  ${revision}-Referenzen enthalten
- MANIFEST.MF des Shade-JARs enthält Implementation-Version und Implementation-Title
- app.version im Packaging-Modul auf ${revision} umgestellt (war 2.5.0)
- ApplicationVersionProvider: neue Utility-Klasse im Bootstrap-Modul liest
  Implementation-Version aus MANIFEST.MF, Fallback "dev" bei ungepacktem Betrieb
- ApplicationVersionProviderTest: prüft Fallback-Verhalten im Testlauf
- .gitignore: .flattened-pom.xml-Dateien ausgeschlossen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-30 10:36:55 +02:00
parent 01e97848a7
commit c6379c04f6
12 changed files with 138 additions and 14 deletions
@@ -0,0 +1,45 @@
package de.gecheckt.pdf.umbenenner.bootstrap;
/**
* Liest die Anwendungsversion aus dem MANIFEST.MF des ausführbaren Fat-JARs.
* <p>
* Im gepackten Betrieb wird der Eintrag {@code Implementation-Version} aus dem
* JAR-Manifest gelesen, der beim Build durch das Shade-Plugin befüllt wird.
* Im IDE-Betrieb und in Testumgebungen ohne gepacktes JAR steht kein Manifest
* zur Verfügung; in diesem Fall wird der Fallback {@code "dev"} zurückgegeben.
* <p>
* Diese Klasse ist eine reine Hilfsklasse ohne Zustand; alle Methoden sind statisch.
* Die Verdrahtung mit der GUI-Statuszeile erfolgt in einer späteren Ausbaustufe.
*/
public final class ApplicationVersionProvider {
/** Fallback-Version, wenn kein Manifest-Eintrag verfügbar ist. */
private static final String FALLBACK_VERSION = "dev";
/** Utility-Klasse kein öffentlicher Konstruktor. */
private ApplicationVersionProvider() {
// nicht instanziierbar
}
/**
* Gibt die Anwendungsversion zurück.
* <p>
* Die Version wird aus dem {@code Implementation-Version}-Eintrag des Pakets
* {@code de.gecheckt.pdf.umbenenner.bootstrap} gelesen. Dieser Eintrag wird
* beim Build durch das Shade-Plugin mit dem Wert der Property {@code ${revision}}
* befüllt.
* <p>
* Ist der Eintrag nicht vorhanden (IDE-Start, Tests, ungepackter Betrieb),
* wird der Wert {@code "dev"} zurückgegeben.
*
* @return die aufgelöste Versionsnummer, niemals {@code null}
*/
public static String resolveVersion() {
String version = ApplicationVersionProvider.class.getPackage().getImplementationVersion();
if (version == null) {
// Fallback für IDE-Start und ungepackten Betrieb
return FALLBACK_VERSION;
}
return version;
}
}
@@ -0,0 +1,36 @@
package de.gecheckt.pdf.umbenenner.bootstrap;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit-Tests für {@link ApplicationVersionProvider}.
* <p>
* Im Testlauf ist kein gepacktes JAR mit Manifest vorhanden; der Test prüft deshalb
* ausschließlich das Fallback-Verhalten und stellt sicher, dass die Methode niemals
* {@code null} zurückgibt.
*/
class ApplicationVersionProviderTest {
/**
* Im Testlauf (kein Fat-JAR, kein Manifest-Eintrag) muss der Fallback-Wert
* {@code "dev"} zurückgegeben werden.
*/
@Test
void resolveVersion_ohneGepacktesJar_gibtDevZurueck() {
// Wenn kein MANIFEST.MF mit Implementation-Version vorhanden ist (IDE / Test),
// wird der Fallback-Wert geliefert.
String version = ApplicationVersionProvider.resolveVersion();
assertThat(version).isEqualTo("dev");
}
/**
* Das Ergebnis von {@link ApplicationVersionProvider#resolveVersion()} darf
* niemals {@code null} sein weder im IDE-Betrieb noch im gepackten Betrieb.
*/
@Test
void resolveVersion_gibtNiemalsNull() {
assertThat(ApplicationVersionProvider.resolveVersion()).isNotNull();
}
}