Vorgestellt wird ein einfaches Maven Plug-in, das als Open-Source-Projekt mit DevOps realisiert wurde. Es wird auf folgende Aspekte eingegangen: Auswahl des Ablageortes (SCM), Build-Umgebung und Vorgaben des Ziels. Hier ist das Ziel die Veröffentlichung im Maven Central Repository. Dabei sind auch die Punkte Code-Qualität und Sicherheit berücksichtigt.

Um ein Projekt als Open Source zu veröffentlichen und dabei mit DevOps zu bauen und bereitzustellen, ist vieles zu beachten:

  1. Das eigentliche Projekt (die Aufgabe)
  2. Welche Technologie?
  3. Wo veröffentlichen? (SCM)
  4. Welche Tools?
  5. Welche Vorgaben aus der Open-
  6. Source-Umgebung?
  7. (Maven)
  8. Code-Qualität sicherstellen
  9. Sicherheit

Auswahl des Projektes und der Technologie

Damit die Open-Source-Vorgaben sehr konkret und recht üblich sind, habe ich eine Aufgabe ausgewählt, die im Maven Central Repository [4] gehostet werden soll. Naheliegend sind hierbei noch Maven als Build Tool und Java als verwendete Technologie. Ein einfaches Maven Plug-in ist hier die Aufgabe geworden.

Das Projekt

Das Maven Plug-in erstellt aus den Artefakten (Jar-Dateien) mit jlink eine reduzierte Laufzeitumgebung – eine Java- Umgebung nur mit den verwendeten Modulen. Auch die Jars der Anwendung sind dann Teil des Images (lib/modules). Als Bonus lässt sich noch ein Installer für Java erstellen, dieses Feature ist zurzeit nur für Oracle Java 9 und 10 verfügbar. Es wird wieder ab Java 14 für alle JDKs zur Verfügung stehen. Als kleine Zugabe ist es möglich, die Artefakte zu bereinigen.

Das Hosting

Jetzt zu der wichtigen Frage, wo man sein Open-Source-Projekt ablegen oder veröffentlichen kann oder sollte. Klassisch fallen einem die Namen SourceForge, Gnu, Apache und Eclipse ein. SourceForge und Gnu sind nicht der übliche Ort für Java-Projekte, Apache und Eclipse sind nur für größere Java-Projekte zweckmäßig. Für die Aufgabe eignen sich am besten die freien Repositories von GIT. Hier sind GitHub, GitLab und BitBucket aktuell zu sehen. Alle drei Repositories bieten auch das Erstellen einer Pipeline. Ich habe GitHub gewählt, weil hier viele bekannte Open-Source-Projekte mit ihren Repositories zu finden sind.

Die Tools

Man benötigt ein Java JDK mindestens Version 9. Erste Tests nutzten Java 9, aktuell wird Java 11 verwendet. Bei Maven wird die Version 3.6 eingesetzt. Git ist, wie schon beschrieben, GitHub. IDE ist nicht vorgegeben, hier reicht die POM für Intellij, Eclipse und NetBeans. Weitere Tools/ Plug-ins werden später vorgestellt.

Die Maven-Vorgaben

Damit man ein Maven Plug-in erstellen kann, wird Maven als Build Tool benötigt und auch als Umgebung, mit der man testet, da das Plug-in in Maven läuft. Es werden folgende Abhängigkeiten benötigt (siehe Listing 1).

<dependency>
   <groupId>org.apache.maven</groupId>
   <artifactId>maven-plugin-api</artifactId>
   <version>3.6.0</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>org.apache.maven</groupId>
   <artifactId>maven-core</artifactId>
   <version>3.6.0</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>org.apache.maven.plugin-tools</groupId>
   <artifactId>maven-plugin-annotations</artifactId>
   <version>3.6.0</version>
   <scope>provided</scope>
</dependency>

Listing 1: Die Abhängigkeiten eines Maven Plug-ins

In Listing 2 sehen Sie die notwendigen Einstellungen, um ein Maven Plug-in zu erstellen.

<packaging>maven-plugin</packaging>
<name>Plugin to generate jars with module information as Maven Plugin</name>
<description>The maven main core project description</description>
<url>http://github.com/mt-ag/jar-module-maven-plugin</url>
<prerequisites>
   <maven>3.6.0</maven>
</prerequisites>
<inceptionYear>2019</inceptionYear>

Listing 2: Die notwendigen Einstellungen zum Erstellen eines Maven Plug-ins

Das Packaging ist hier nicht jar wie bei einem normalen Java-Projekt. Die Attribute name, description und url sind auch Teil von Standard-Projekten. Bei der URL ist schon das GitHub-Projekt eingetragen. Neu sind die minimale Version von Maven und das Jahr, ab dem das Plug-in eingeführt wurde.

Des Weiteren sind beim Build auch noch Änderungen vorzunehmen (siehe Listing 3).

<build>
   <plugins>
      <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <version>2.22.0</version>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>3.8.1</version>
         <configuration>
            <source>${java.version}</source>
            <target>${java.version}</target>
         </configuration>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-plugin-plugin</artifactId>
         <version>3.6.0</version>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-site-plugin</artifactId>
         <version>3.7.1</version>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-project-info-reports-plugin</artifactId>
         <version>3.0.0</version>
      </plugin>
   </plugins>
</build>

Listing 3: Die Änderungen beim Build

Das Maven-Surfire-Plug-in und das Maven-Compiler-Plug-in müssen neuere Versionen als Standard verwenden, damit mit Java 9, 10 oder 11 gebaut werden kann. Die beiden anderen Maven Plug-ins werden benötigt, um das neue Plug-in zu bauen und um die Dokumentation zu generieren.

Vorgaben vom Maven Central Repository

Aktuell gelten die Vorgaben von Sonartype [5], hier die wichtigsten:

  1. Metadaten nach Vorgabe
  2. JavaDoc
  3. Java Sources
  4. Checksummen
  5. Signaturen mit GPG/PGP
  6. Repositories von Sonartype

Metadaten nach Vorgabe heißt, der Package-Name in Java beginnt mit der umgekehrten URL der Firma oder Organisation, bei mir ist es com.mt_ag, abgeleitet von www.mt-ag.com. Der ‚_‘ kommt als Ersatz für das nicht erlaubte ‚-‘ für Java-Packages. Der Name der GroupId beginnt auch mit der umgekehrten URL ähnlich wie beim Java-Package (siehe Listing 4).

<groupId>com.mt-ag.tools.maven</groupId>

Listing 4: Die GroupId

Hier ist das ‚-‘ erlaubt, deshalb nicht ‚_‘ in der GroupId.

Der SCM-Eintrag muss auch angegeben werden (siehe Listing 5).

<scm>
   <connection>scm:git:git://github.com/mt-ag/jar-module-maven-lugin.git</connection>
   <developerConnection>scm:git:ssh://github.com:mt-ag/jar-module-maven-plugin.git</developerConnection>
   <url>http://github.com/mt-ag/jar-module-maven-plugin/tree/master</url>
</scm>

Listing 5: Die SCM-URL zum GitHub-Projekt

Des Weiteren sind noch die Lizenz, die Organisation und die Entwickler anzugeben.

Die Lizenz muss eine Open-Source- Lizenz sein.

Das JavaDoc kann noch einfach mit einem Plug-in generiert werden (siehe Listing 6).

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-javadoc-plugin</artifactId>
   <version>3.1.0</version>
   <configuration>
      <quiet>true</quiet>
     <nohelp>true</nohelp>
     <additionalOptions>-html5</additionalOptions>
   </configuration>
      <executions>
         <execution>
         <id>make-assembly</id>
         <phase>package</phase>
         <goals>
             <goal>jar</goal>
         </goals>
     </execution>
   </executions>
</plugin>

Listing 6: JavaDoc generieren

Für Java 9 und 10 ist die zusätzliche Option -html5 zu setzen, bei Java 11 nicht mehr.

Java Source wird mit einem Plug-in als Zip hinzugefügt (siehe Listing 7).

<plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-source-plugin</artifactId>
      <version>3.0.1</version>
      <executions>
         <execution>
            <id>attach-sources</id>
            <phase>verify</phase>
            <goals>
               <goal>jar</goal>
             </goals>
         </execution>
      </executions>
</plugin>

Listing 7: Java Source als Zip-Artefakt

Vorgegeben von Sonartype ist die Verwendung von Checksummen, dies geschieht mit diesem Plug-in (siehe Listing 8).

<plugin>
   <groupId>net.nicoulaj.maven.plugins</groupId>
   <artifactId>checksum-maven-plugin</artifactId>
   <version>1.8</version>
    <executions>
      <execution>
         <id>checksum-artifacts</id>
         <phase>verify</phase>
         <goals>
            <goal>files</goal>
         </goals>
         <configuration>
            <attachChecksums>true</attachChecksums>
            <csvSummary>false</csvSummary>
            <fileSets>
              <fileSet>
                  <directory>target</directory>
                  <include>*.jar</include>
                  <include>*.pom</include>
               </fileSet>
            </fileSets>
         </configuration>
     </execution>
   </executions>
</plugin>

Listing 8: Checksummen für Artefakte

Wichtig hierbei ist, dass nur die Jars und die POM Checksummen bekommen. Es wird keine Zusammenfassung benötigt.

Die Artefakte und POM müssen noch signiert werden, dafür wird das PGP-Plugin verwendet (siehe Listing 9).

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-gpg-plugin</artifactId>
   <version>1.4</version>
   <executions>
      <execution>
         <id>sign-artifacts</id>
         <phase>verify</phase>
         <goals>
             <goal>sign</goal>
         </goals>
         <configuration>
              <skip>false</skip>
         </configuration>
      </execution>
   </executions>
</plugin>

Listing 9: GPG Signing

Hier gibt es noch eine gute Beschreibung für GitHub Actions, siehe [8]. Der Private Key zum Signieren müsste noch in der settings.xml hinterlegt werden. Das ist jedoch zu unsicher, da man die settings. xml noch zum Projekt hinzufügen muss, um sie zu verwenden. Auch wenn man das Passwort mit dem Mitteln von Maven verschlüsseln kann, ist dies nicht zu empfehlen, da dann auch noch die Datei settingssecurity. xml Teil des Projektes würde.

Code-Qualität

Hierfür gibt es keine besonderen Vorgaben. Es empfiehlt sich, Checkstyle und jacoco zu verwenden und passende Tests zu hinterlegen.

Sicherheit

Es muss darauf geachtet werden, dass keine Zugangsdaten miteingecheckt werden.  Besonders nicht in der Konfiguration, wie zum Beispiel settings.xml, oder in der Dokumentation.

Die CI/CD-Konfiguration

Unter GitHub wird die Konfiguration durch die maven.yml-Datei vorgenommen (siehe Listing 10).

name: Java Ubuntu Build
on:
   push:
       branches:
          - master
jobs:
   build:
      runs-on: ubuntu-latest steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 11
           uses: actions/setup-java@v1
           with: java-version: 11
      - name: Cache Maven packages
       uses: actions/cache@v1
       with:
          path: ~/.m2
          key: ${{ runner.os }}-m2-${{ hashFiles(‘**/pom.xml’) }}
          restore-keys: ${{ runner.os }}-m2
      - run: chmod a+x mvnw
      - name: Maven clean
         run: ./mvnw clean --file pom.xml
      - name: Maven compile
         run: ./mvnw compile --file pom.xml
      - name: Maven test
         run: ./mvnw test --file pom.xml
      - name: Maven install
         run: ./mvnw install -Dmaven.test.skip=true --file pom.xml
      - run: mkdir staging && cp target/*.jar staging
      - uses: actions/upload-artifact@v1
            with:
                name: PluginJars
                path: staging

Listing 10: GitHub-Konfiguration

Hier werden für den Cache die Empfehlungen von GitHub berücksichtigt und der Maven Build wird in mehrere Stages unterteilt.

Unter GitLab [9] geschieht die Konfiguration mit der .gitlag-ci.yml-Datei (siehe Listing 11).

image: openjdk:11.0.6-jdk
variables:
   MVN_OPTS: “--batch-mode -Dmaven.repo.local=.m2/repository”
cache:
   paths:
      - .m2/repository/
      - target/
   build:
      stage: build
      script:
         - chmod a+x ./mvnw
         - ./mvnw $MVN_OPTS compile
       artifacts:
         paths:
            - target
test:
   stage: test
   script:
      - chmod a+x ./mvnw
      - ./mvnw $MVN_OPTS test
deploy:
   stage: deploy
   script:
      - chmod a+x ./mvnw
      - ./mvnw $MVN_OPTS -Dmaven.test.skip=true install
   artifacts:
       paths:
         - target/*.jar
    only:
       - master

Listing 11: GitLab-Konfiguration

Beide Konfigurationen stellen am Ende der Pipeline ein Artefakt mit den Jars zur Verfügung. Ein direktes Deployen ins Maven Central Repository wäre zwar möglich, es wäre mir allerdings noch zu unsicher, die Zugangsdaten zu hinterlegen.

Zusammenfassung

Bei Open-Source-Projekten ist viel im Vorfeld zu beachten und es gibt eine Auswahl von guten Webseiten, um ein Projekt zu veröffentlichen. Dabei wird auch eine CI/CD-Pipeline direkt unterstützt. Es ist nicht mehr nötig, die CI/CD-Pipeline über eine andere Webseite anzubinden. Schön bei GitHub ist, dass die generierte Dokumentation gleich mitveröffentlicht werden kann (siehe im Beispielprojekt [1]).

Quellen

[1] https://github.com/mt-ag/jar-module-maven-plugin Das Maven Plug-in des Artikels

[2] https://maven.apache.org/ DasApache-Maven-Projekt

[3] https://maven.apache.org/plugin-developers/index.html Die Plug-ins für Apache Maven

[4] https://maven.apache.org/repository/index.html Das Maven Central Repository

[5] https://central.sonatype.org/pages/requirements.html Die Vorgaben von Sonartype für Maven Repositories

[6] https://github.com/ Das GitHub-Projekt

[7] https://github.com/mt-ag/jar-module-maven-plugin/new/master?filename=.github%2Fworkflows%2Fmaven.yml&workflow_template=maven Hier die Action, um Maven aufzurufen

[8] https://help.github.com/en/actions/language-and-framework-guides/publishing-java-packages-with-maven Hier die Action, um auf Maven Central Repository zu veröffentlichen

[9] https://gitlab.com/ Das GitLab-Projekt

Jetzt teilen auf:

Jetzt kommentieren