diff --git a/bin/jenkins.sh b/bin/jenkins.sh index fb019d12..d9b691e4 100755 --- a/bin/jenkins.sh +++ b/bin/jenkins.sh @@ -1,6 +1,6 @@ #!/bin/bash -docker pull jenkins/jenkins:lts-alpine +docker pull jenkins/jenkins:lts-jdk21 docker compose build --pull diff --git a/doc/Continuous-Integration.md b/doc/Continuous-Integration.md index 8fdaaa01..1518e54a 100644 --- a/doc/Continuous-Integration.md +++ b/doc/Continuous-Integration.md @@ -1,24 +1,18 @@ # Continuous Integration des Coding Style -Gemäß dem Grundsatz **eat your own dogfood** ist dieser Coding Style bereits für die Continuous Integration -in [GitHub Actions](https://github.com/features/actions) und [Jenkins](https://jenkins.io) vorbereitet. +Gemäß dem Grundsatz **eat your own dogfood** ist dieser Coding Style bereits für die Continuous Integration in [GitHub Actions](https://github.com/features/actions), [GitLab CI](https://docs.gitlab.com/ee/ci/) und [Jenkins](https://jenkins.io) vorbereitet. ## Maven Konfiguration -Sowohl für GitHub Actions als auch für Jenkins erfolgt die Automatisierung des Builds über Maven. Im zugehörigen -[POM](../pom.xml) sind alle Versionen der benutzten Maven Plugins und der benötigten Abhängigkeiten über Properties -definiert, d.h. eine Aktualisierung lässt sich im entsprechenden Abschnitt leicht selbst durchführen bzw. wird -über den [Dependabot](https://dependabot.com) Roboter von GitHub automatisch über einen Pull Request aktualisiert. +Sowohl für GitHub Actions als auch für Jenkins erfolgt die Automatisierung des Builds über Maven. Im zugehörigen [POM](../pom.xml) sind alle Versionen der benutzten Maven Plugins und der benötigten Abhängigkeiten über Properties definiert, d.h. eine Aktualisierung lässt sich im entsprechenden Abschnitt leicht selbst durchführen bzw. wird über den [Dependabot](https://dependabot.com) Roboter von GitHub automatisch über einen Pull Request aktualisiert. U.a. sind die folgenden Plugins vorkonfiguriert: -- maven-compiler-plugin: konfiguriert die Java Version auf Java 8 und legt alle Error Prone Regeln fest. Die Java - Version kann beliebig aktualisiert werden. +- maven-compiler-plugin: konfiguriert die Java Version auf Java 11 und legt alle Error Prone Regeln fest. Die Java Version kann beliebig aktualisiert werden. - maven-javadoc-plugin: aktiviert die strikte Prüfung von JavaDoc Kommentaren -- maven-jar-plugin: legt einen Modulnamen fest, falls das Projekt in Java 9 oder höher verwendet wird. Außerdem wird -ein test-jar konfiguriert, sodass alle Tests (und abstrakte Testklassen) auch als Dependencies genutzt werden können. -- maven-pmd-plugin: prüft das Projekt mit PMD, die Regeln liegen in den Dateien [pmd-java-configuration.xml](../etc/pmd-java-configuration.xml), [pmd-tests-configuration.xml](../etc/pmd-tests-configuration.xml) und [pmd-javascript-configuration.xml](../etc/pmd-javascript-configuration.xml). -- maven-checkstyle-plugin: prüft das Projekt mit CheckStyle, die Regeln liegen in den Dateien [checkstyle-java-configuration.xml](../etc/checkstyle-java-configuration.xml) und [checkstyle-tests-configuration.xml](../etc/checkstyle-tests-configuration.xml). -- spotbugs-maven-plugin: prüft das Projekt mit SpotBugs, alle Regeln werden verwendet mit den Ausnahmen definiert in der Datei [spotbugs-exclusion-filter.xml](../etc/spotbugs-exclusion-filter.xml). -- org.revapi: prüft, ob die aktuelle Versionsnummer die [semantische Versionierung](https://semver.org) berücksichtigt (source and binary). D.h. es gilt: +- maven-jar-plugin: legt einen Modulnamen fest. Außerdem wird ein test-jar konfiguriert, sodass alle Tests (und abstrakte Testklassen) auch als Dependencies genutzt werden können. +- maven-pmd-plugin: prüft das Projekt mit [PMD](https://pmd.github.io/), die Regeln liegen in den Dateien [pmd-java-configuration.xml](../etc/pmd-java-configuration.xml), [pmd-tests-configuration.xml](../etc/pmd-tests-configuration.xml) und [pmd-javascript-configuration.xml](../etc/pmd-javascript-configuration.xml). +- maven-checkstyle-plugin: prüft das Projekt mit [CheckStyle](https://checkstyle.sourceforge.io/), die Regeln liegen in den Dateien [checkstyle-java-configuration.xml](../etc/checkstyle-java-configuration.xml) und [checkstyle-tests-configuration.xml](../etc/checkstyle-tests-configuration.xml). +- spotbugs-maven-plugin: prüft das Projekt mit [SpotBugs](https://spotbugs.github.io/), alle Regeln werden verwendet mit den Ausnahmen definiert in der Datei [spotbugs-exclusion-filter.xml](../etc/spotbugs-exclusion-filter.xml). +- revapi-maven-plugin: prüft, ob die aktuelle Versionsnummer die [semantische Versionierung](https://semver.org) berücksichtigt (source and binary). D.h. es gilt: 1. Eine neue **Major** Version wurde definiert, wenn das API nicht mehr abwärtskompatibel ist. 2. Eine neue **Minor** Version wurde definiert, wenn eine neue Funktionalität abwärtskompatibel hinzugefügt wurde. 3. Eine neue **Patch** Version wurde definiert, wenn Fehler abwärtskompatibel behoben wurden. @@ -30,41 +24,23 @@ ein test-jar konfiguriert, sodass alle Tests (und abstrakte Testklassen) auch al [![GitHub Actions](https://github.com/uhafner/codingstyle/workflows/GitHub%20CI/badge.svg)](https://github.com/uhafner/codingstyle/actions) -Die Konfiguration der Continuous Integration in GitHub Actions is sehr [einfach](../.github/workflows/ci.yml). -Da der gesamte Build über Maven automatisiert ist, besteht die Konfiguration eigentlich nur aus einem Maven Aufruf, -der das Projekt baut, alle Tests (Unit und Integrationstests) ausgeführt, die statische Code Analyse durchführt -und schließlich werden nochmals alle Test mit dem Code Coverage Tool JaCoCo analysiert. Bei einem erfolgreichen -Build werden die Code Coverage Ergebnisse in die Platform [CodeCov](https://app.codecov.io/gh/uhafner/codingstyle) hochgeladen. -GitHub Actions bietet die Möglichkeit, Matrix Builds durchzuführen: d.h., der Build wird auf den Plattformen Linux, -Windows und macOS parallel durchgeführt. +Die Konfiguration der Continuous Integration in GitHub Actions is sehr [einfach](../.github/workflows/ci.yml) über eine Pipeline möglich. Da der gesamte Build über Maven automatisiert ist, besteht die Pipeline eigentlich nur aus einem Maven Aufruf, der das Projekt baut, alle Tests (Unit und Integrationstests) ausgeführt, die statische Code Analyse durchführt und schließlich die Coverage misst. GitHub Actions bietet auch die Möglichkeit, Matrix Builds durchzuführen: d.h., der Build wird z.B. auf den Plattformen Linux, Windows und macOS oder mit den Java Versionen 17 und 21 parallel durchgeführt. Ein Beispiel für die Konfiguration eines Matrix Builds ist in der Datei [ci.yml](../.github/workflows/ci.yml) zu finden. + +Wenn gewünscht, können die Ergebnisse der statischen Code Analyse und der Code Coverage Tools auch direkt im Commit oder Pull-Request angezeigt werden. Dazu muss in der Pipeline meine [Quality Monitor Action](https://github.com/uhafner/quality-monitor) aktiviert werden. Eine Beispielkonfiguration ist in der Datei [quality-monitor.yml](../.github/workflows/quality-monitor.yml) zu finden, das Ergebnis in der nachfolgenden Abbildung: + +![Quality Monitor](images/quality-monitor.png) ## Jenkins -Eine Beispielintegration in Jenkins ist auch bereits vorhanden. Diese ist im [Jenkinsfile](../Jenkinsfile) hinterlegt -und startet die Integration in mehreren Schritten (Stages). Zunächst werden auch hier alle Schritte wie in GitHub Actions -aufgerufen. Anschließend erfolgt noch ein Start der Mutation Coverage mit [PIT](http://pitest.org). Insgesamt ist -die CI Konfiguration für Jenkins umfangreicher, da nicht nur der eigentliche Build konfiguriert wird, sondern -auch die Darstellung der Ergebnisse im Jenkins UI über die entsprechenden Jenkins Plugins konfiguriert wird. -Eine solche Visualisierung ist unter GitHub Actions nicht verfügbar. +Eine Beispielintegration mit Jenkins ist auch bereits vorhanden. Diese ist im [Jenkinsfile](../Jenkinsfile) hinterlegt und startet die Integration in mehreren Schritten (Stages). Zunächst werden auch hier alle Schritte wie in GitHub Actions aufgerufen. Anschließend erfolgt noch ein Start der Mutation Coverage mit [PIT](http://pitest.org). Insgesamt ist die CI Konfiguration für Jenkins umfangreicher, da nicht nur der eigentliche Build konfiguriert wird, sondern auch die Darstellung der Ergebnisse im Jenkins UI über die entsprechenden Jenkins Plugins konfiguriert wird. ### Lokale CI in Jenkins (über Docker Compose) -Da es für Jenkins keinen öffentlichen Service wie bei GitHub Actions gibt, um eigene Projekte zu bauen, muss die Jenkins -Integration lokal durchgeführt werden. Zur Vereinfachung des Jenkins Setup ist in diesem Coding Style eine -lauffähige Jenkins Installation enthalten (im Sinne von *Infrastructure as Code*). -Diese kann über `bin/jenkins.sh` gestartet werden. Anschließend wird die -aktuelle Jenkins LTS Version mit allen benötigten Plugins in einem Docker Container gebaut und gestartet (das dauert -beim ersten Aufruf etwas). Dazu wird ebenso ein als Docker Container initialisierter Java Agent (**Achtung**: Java 8) -verbunden, der die Builds ausführt. +Da es für Jenkins keinen öffentlichen Service wie bei GitHub Actions gibt, um eigene Projekte zu bauen, muss die Jenkins Integration lokal auf einem Team-Server durchgeführt werden. Zur Vereinfachung des Jenkins Setup ist in diesem Coding Style eine lauffähige Jenkins Installation enthalten (im Sinne von *Infrastructure as Code*). Diese kann über `bin/jenkins.sh` gestartet werden. Anschließend wird die aktuelle Jenkins LTS Version mit allen benötigten Plugins in einem Docker Container gebaut und gestartet (das dauert beim ersten Aufruf etwas). Dazu wird ebenso ein als Docker Container initialisierter Java Agent verbunden, der die Builds ausführt. + -Nach einem erfolgreichen Start von Jenkins ist dann unter [http://localhost:8080/job/Codingstyle/](http://localhost:8080/job/Codingstyle/) der entsprechende Jenkins Job sichtbar. -Der Zugang auf diesen lokalen Rechner erfolgt zur Vereinfachung -mit Benutzer `admin` und Passwort `admin`, anschließend hat man volle Jenkins Administrationsrechte. -Der Job `Codingstyle` muss danach manuell gestartet werden, -die Ergebnisse der Tests, Code und Mutation Coverage sowie statischen Analyse werden dann automatisch -visualisiert. Das Jenkins Home Verzeichnis ist im Docker Container als externes Volume angelegt: d.h. der Zugriff kann -auf dem Host direkt im Verzeichnis `docker/volumes/jenkins-home` erfolgen. +Nach einem erfolgreichen Start von Jenkins sind dann unter [http://localhost:8081](http://localhost:8080/job/Codingstyle/) mehrere Jenkins Jobs sichtbar. Einer dieser Jobs baut das vorliegende Coding Style Projekt. Der Zugang auf diesen lokalen Rechner erfolgt zur Vereinfachung mit Benutzer `admin` und Passwort `admin`, anschließend hat man volle Jenkins Administrationsrechte. Die jeweiligen Jobs müssen danach manuell gestartet werden, die Ergebnisse der Tests, Code und Mutation Coverage sowie statischen Analyse werden dann automatisch visualisiert. Das Jenkins Home Verzeichnis ist im Docker Container als externes Volume angelegt: d.h. der Zugriff kann auf dem Host direkt im Verzeichnis `docker/volumes/jenkins-home` erfolgen. -Nach einem ersten Build in Jenkins sollte sich dann folgendes Bild ergeben: +Nach einem ersten Build in Jenkins sollte sich dann in etwa folgendes Bild ergeben: ![Jenkins Build Summary](images/build-result.png) diff --git a/doc/images/quality-monitor.png b/doc/images/quality-monitor.png new file mode 100644 index 00000000..5dd3f157 Binary files /dev/null and b/doc/images/quality-monitor.png differ diff --git a/docker-compose.yaml b/docker-compose.yaml index b085be7a..471d4ff3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,20 +1,70 @@ -version: "3" +name: codingstyle + services: - jenkins-controller: + jenkins: + container_name: jenkins build: context: docker/images/jenkins-controller volumes: - - /var/run/docker.sock:/var/run/docker.sock - - ./docker/volumes/jenkins-home:/var/jenkins_home:cached + - ./docker/volumes/jenkins-home:/var/jenkins_home # Mounts the local jenkins_home volume to the /var/jenkins_home path inside the container + - agent-ssh-dir:/ssh-dir # Mounts the shared volume agent-ssh-dir to a path inside the container ports: - 8081:8080 # Jenkins UI - HOST:CONTAINER environment: - TRY_UPGRADE_IF_NO_MARKER=true - - JAVA_OPTS= -Dstapler.jelly.noCache=true -Dhudson.remoting.ClassFilter=com.google.common.collect.ImmutableListMultimap -DexecutableWar.jetty.disableCustomSessionIdCookieName=true -DexecutableWar.jetty.sessionIdCookieName=warnings-ng-devenv + - JAVA_OPTS= -Dstapler.jelly.noCache=true -Dhudson.remoting.ClassFilter=com.google.common.collect.ImmutableListMultimap -DexecutableWar.jetty.disableCustomSessionIdCookieName=true -DexecutableWar.jetty.sessionIdCookieName=codingstyle user: ${CURRENT_UID} restart: unless-stopped - java11-agent: - build: ./docker/images/java11-agent depends_on: - - jenkins-controller + key-generator: + condition: service_completed_successfully # Depends on the successful completion of the sidekick_service + healthcheck: + test: ["CMD-SHELL", "[ -f /ssh-dir/conductor_ok ] || exit 1"] + # Checks if the conductor_ok file exists in the /ssh-dir path + interval: 5s + timeout: 10s + retries: 5 + + key-generator: + container_name: key-generator + build: + context: docker/images/key-generator + stdin_open: true + tty: true + # The entrypoint script generates the SSH keys and outputs them to the /ssh-dir directory. + entrypoint: sh -c "/usr/local/bin/keygen.sh /ssh-dir" # Runs the keygen.sh script and specifies the output directory + volumes: + - agent-ssh-dir:/ssh-dir # Mounts the agent-ssh-dir volume to the /ssh-dir path inside the container + # The healthcheck command checks if the conductor_ok file exists in the /ssh-dir directory. + healthcheck: + test: ["CMD-SHELL", "[ -f /ssh-dir/conductor_ok ] || exit 1"] + # Checks if the conductor_ok file exists in the /ssh-dir path + interval: 5s + timeout: 10s + retries: 5 + + java-agent: + container_name: java-agent + build: docker/images/java-agent + depends_on: + key-generator: + condition: service_completed_successfully # Depends on the successful completion of the sidekick_service + jenkins: + condition: service_started restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "[ -f /ssh-dir/conductor_ok ] || exit 1"] + # Checks if the conductor_ok file exists in the /ssh-dir path + interval: 5s + timeout: 10s + retries: 5 + volumes: + - agent-ssh-dir:/home/jenkins/.ssh:ro # Mounts the agent-ssh-dir volume to the /home/jenkins/.ssh path inside the container as read-only + - ${HOME}/.m2/repository:/home/jenkins/.m2/repository # Mounts the local Maven repository to the /home/jenkins/.m2 path inside the container + +volumes: + agent-ssh-dir: + name: agent-ssh-dir # Creates a named volume called agent-ssh-dir + jenkins_home: + name: jenkins_home # Creates a named volume called jenkins_home + external: true diff --git a/docker/images/java-agent/Dockerfile b/docker/images/java-agent/Dockerfile new file mode 100644 index 00000000..2bb4ad6f --- /dev/null +++ b/docker/images/java-agent/Dockerfile @@ -0,0 +1,27 @@ +FROM jenkins/ssh-agent:latest-jdk21 + +# Install prerequisites for Java and Maven +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates curl \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Install Maven +ARG MAVEN_VERSION=3.9.8 + +SHELL ["/bin/bash", "-eo", "pipefail", "-c"] +RUN curl -sS -L -O --output-dir /tmp/ --create-dirs https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz \ + && printf "%s" "$(sha512sum /tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz)" | sha512sum -c - \ + && curl -sS -L -O --output-dir /tmp/ --create-dirs https://downloads.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz.sha512 \ + && printf "%s /tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz" "$(cat /tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz.sha512)" | sha512sum --check --status - \ + && tar xzf "/tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz" -C /opt/ \ + && rm "/tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \ + && ln -s /opt/apache-maven-${MAVEN_VERSION} /opt/maven \ + && ln -s /opt/maven/bin/mvn /usr/bin/mvn \ + && mkdir -p /etc/profile.d \ + && echo "export JAVA_HOME=$JAVA_HOME \n \ + export M2_HOME=/opt/maven \n \ + export PATH=${M2_HOME}/bin:${PATH}" > /etc/profile.d/maven.sh +ENV M2_HOME="/opt/maven" +ENV PATH="${M2_HOME}/bin/:${PATH}" +RUN echo "PATH=${PATH}" >> /etc/environment && chown -R jenkins:jenkins "${JENKINS_AGENT_HOME}" diff --git a/docker/images/java11-agent/Dockerfile b/docker/images/java11-agent/Dockerfile deleted file mode 100644 index 871fcbbb..00000000 --- a/docker/images/java11-agent/Dockerfile +++ /dev/null @@ -1,65 +0,0 @@ -FROM eclipse-temurin:11-alpine - -RUN apk update \ - && apk add bash git openssh dos2unix curl \ - && mkdir /root/.ssh \ - && chmod 0700 /root/.ssh \ - && ssh-keygen -A \ - && sed -i s/^#PasswordAuthentication\ yes/PasswordAuthentication\ no/ /etc/ssh/sshd_config \ - && sed -i -e "s/MACs /MACs hmac-sha1,/g" /etc/ssh/sshd_config \ - && echo "RSAAuthentication yes" > /etc/ssh/sshd_config \ - && echo "UsePAM yes" > /etc/ssh/sshd_config \ - && echo "PubkeyAuthentication yes" > /etc/ssh/sshd_config -USER root - -ARG MAVEN_VERSION=3.8.6 -ARG USER_HOME_DIR="/root" -ARG SHA=f790857f3b1f90ae8d16281f902c689e4f136ebe584aba45e4b1fa66c80cba826d3e0e52fdd04ed44b4c66f6d3fe3584a057c26dfcac544a60b301e6d0f91c26 -ARG BASE_URL=https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries - -RUN mkdir -p /opt/maven /opt/maven/ref \ - && echo "Downloading maven" \ - && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \ - \ - && echo "Checking download hash" \ - && echo "${SHA} /tmp/apache-maven.tar.gz" | sha512sum -c - \ - \ - && echo "Unzipping maven" \ - && tar -xzf /tmp/apache-maven.tar.gz -C /opt/maven --strip-components=1 \ - \ - && echo "Cleaning and setting links" \ - && rm -f /tmp/apache-maven.tar.gz \ - && ln -s /opt/maven/bin/mvn /usr/bin/mvn - -RUN addgroup -S jenkins && adduser -D agent -G jenkins -RUN echo "agent:Docker!" | chpasswd - -RUN mkdir /home/agent/.ssh -RUN chmod 700 /home/agent/.ssh -RUN chown agent:jenkins /home/agent/.ssh - -COPY --chown=agent:jenkins unsafe.pub /home/agent/.ssh/authorized_keys -RUN chmod 600 /home/agent/.ssh/authorized_keys - -RUN mkdir /var/data -VOLUME /var/data - -COPY docker-entrypoint.sh / -RUN chmod u+x docker-entrypoint.sh -RUN dos2unix /docker-entrypoint.sh - -RUN git config --global user.name "Jenkins Java 11 Agent" -RUN git config --global user.email "java11.agent@jenkins.master" - -EXPOSE 22 - -ENV JAVA_HOME /opt/java/openjdk -ENV MAVEN_HOME /opt/maven - -RUN java --version -RUN mvn --version - -ENTRYPOINT ["/docker-entrypoint.sh"] - -# -D in CMD below prevents sshd from becoming a daemon. -e is to log everything to stderr. -CMD ["/usr/sbin/sshd", "-D", "-e"] diff --git a/docker/images/java11-agent/docker-entrypoint.sh b/docker/images/java11-agent/docker-entrypoint.sh deleted file mode 100644 index c9185eee..00000000 --- a/docker/images/java11-agent/docker-entrypoint.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -if [ ! -f "/etc/ssh/ssh_host_rsa_key" ]; then - # generate fresh rsa key - ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa -fi -if [ ! -f "/etc/ssh/ssh_host_dsa_key" ]; then - # generate fresh dsa key - ssh-keygen -f /etc/ssh/ssh_host_dsa_key -N '' -t dsa -fi - -# prepare run dir -if [ ! -d "/var/run/sshd" ]; then - mkdir -p /var/run/sshd -fi - -TARGET_GID=$(stat -c "%g" /var/data) -addgroup -g $TARGET_GID tempgroup -addgroup agent tempgroup -chmod 770 /var/data -chmod g+s /var/data -chown agent:jenkins /var/data - -echo Added user agent to group GID $TARGET_GID - -# Execute the CMD from the Dockerfile: -exec "$@" diff --git a/docker/images/java11-agent/unsafe b/docker/images/java11-agent/unsafe deleted file mode 100644 index d7d7b319..00000000 --- a/docker/images/java11-agent/unsafe +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEA86cZk1vZh/OwzJDEqga0nnKEh1QpCm1uSDjvuLp2pPDPHMp/ -m9Il9O8ZAZ+IVCUXygO3s1BvBF/a7uVYp7XqjDiTj5Jwrs5lEtl4/1iXXKtwbpAc -bsoiEaFDl7Amc4pUfwzsjaqY4yN4jW+JaLOf/+GqCjwpiyJxZ0N2ONlWoph9dvfH -JBK+LUcbKIqbBAADT12d6ePIBsDn9Yaeem0xSJrwEzcMTFYj6asinMlWgO7VwgZx -JPxhMG+jIq6Mh20tFbwc/XGTqSb/vMkJ8i53RnYm5PoT2xqeYlQCLJtvBRBfuBb5 -WJaQcKvTmLoTgkRCbx/QsQzIWzl4MCj56PRsjQIDAQABAoIBAAGTiy7Q4U9n3DT2 -ms8ey/xacVEO0lUm8Be3hpWDX1Eh3bUp+jlf2q8C/P5tscwZkVXVQFMAqjc1B42U -Hka3fpT5qLq9D82RuEWu8oF0aUZINaoBdK2i0SWcDXvlv9nvgyxvQPiJqgOOLzF7 -D0CGKPrW0urOCNbFmkY4wYMMpOrYXnwb6bc1p7snbzeRigaoGvSgvH7fx2Steg1o -j50C4BKVtXPKQdmckG2SFn0T+U1iCsRG+KNcENX2vX8gyrXImAH093WTjKsmM9et -ddWB+molSnXR/MNrf6BB2mpvXLNyR2/RgBd2jwSQnpDkpms4Br5nek3YYN1dBRL4 -6bofHWECgYEA+7n5OIEbvpMtGxJwOovj0KZMzPkHyQH/DZzo48rS+39goNk/0KLF -c3L3sHbT3Lr4qA/6JOCjlzw7o2AbOrRL4ke1uqcCVQMdDqZdvNezMvTzqEbQGdHD -aFnEcUV2tvEwP11q37ianBRPH5stOnEwQNuv6AJo5LKwi4mTS7qEW9cCgYEA98oJ -h+vMKpXGdJzkSDMzYBrC2tYgqjby6+zGKz8BZ58YecsL+oi2GXBaDTfK+16CKeFM -8+qQN9Kl1ZNOlk64XJXjt77h0FcFuGe+6rUpM1aEizrf9sWPVZO+QQfhnjsiAhtQ -YX783ydy9rMn1FDPMtNNq4GMhGsFCaL4RupOjjsCgYAnk9XbTHFQRVOSLhP3IIdx -BrSMhZrzv5yaR1FWf00svZozr/SYmP7yZ+EJnaUxzzPJOLnbknYmERJPXYzqbe6A -ZUXtUtTLCPJIm1+hkUhbeqfUjU2qwZA3l+WK6aEAomszizyCcEPexlKqZXt29NTh -XakKkVZsnqujRL4j6e9lgQKBgQDvhD8EQJyAyXgkvoc3dy6BBj019WdrwWO9Q4km -wmdkN3gcOnYgvUdwfZa+UiEGLAub2eldmW3AWADu2s5LIlq5PDX7Jir3DTc9UiNM -ksL5mfbS8p0M11i+uupbx/eB0N0FtktTgsGCH4rUBsdIRriSA4h/cOFYGm6rKvnc -6p32gwKBgHZYmXzuBWZlWEmPiXbTaI4egJugur5FrT6BJfiLsN2MHBJi9k1IpKEP -SaT+v0IXJ8jP4gSiu4/gyJQpkn7yiMNhwYWlQt+1zyIkHjUsEG82Z8Mqpjx2EJgG -MxDybQux1uk0hyCmMS757WkbTyi0pTWz7PgTIdfmYqhZVV8KRSUi ------END RSA PRIVATE KEY----- diff --git a/docker/images/java11-agent/unsafe.pub b/docker/images/java11-agent/unsafe.pub deleted file mode 100644 index 0305a8c3..00000000 --- a/docker/images/java11-agent/unsafe.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzpxmTW9mH87DMkMSqBrSecoSHVCkKbW5IOO+4unak8M8cyn+b0iX07xkBn4hUJRfKA7ezUG8EX9ru5VinteqMOJOPknCuzmUS2Xj/WJdcq3BukBxuyiIRoUOXsCZzilR/DOyNqpjjI3iNb4los5//4aoKPCmLInFnQ3Y42VaimH1298ckEr4tRxsoipsEAANPXZ3p48gGwOf1hp56bTFImvATNwxMViPpqyKcyVaA7tXCBnEk/GEwb6MiroyHbS0VvBz9cZOpJv+8yQnyLndGdibk+hPbGp5iVAIsm28FEF+4FvlYlpBwq9OYuhOCREJvH9CxDMhbOXgwKPno9GyN unsafe@nowhere diff --git a/docker/images/jenkins-controller/Dockerfile b/docker/images/jenkins-controller/Dockerfile index 96dcae18..f2bf19ec 100644 --- a/docker/images/jenkins-controller/Dockerfile +++ b/docker/images/jenkins-controller/Dockerfile @@ -1,17 +1,28 @@ -FROM jenkins/jenkins:lts-alpine +# Prepare a Debian-based Docker image with several utilities installed to automatically generate SSH keys +FROM jenkins/jenkins:lts-jdk21 -USER root -RUN addgroup -g 102 docker -RUN adduser jenkins docker -RUN apk add libltdl +# We switch back to the Jenkins user for the remaining operations. USER jenkins -# Install plugins +# We copy the jobs directory from our current directory to the Jenkins home directory in the image. +COPY preconfigured-jobs /usr/share/jenkins/ref/jobs + +# We write the Jenkins version to the UpgradeWizard state file. +# This prevents the Upgrade Wizard from showing up when Jenkins starts. +RUN echo "${JENKINS_VERSION}" > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state + +# We copy a list of plugins to install to the Jenkins ref directory in the image. COPY plugins.txt /usr/share/jenkins/ref/plugins.txt + +# We use the Jenkins plugin CLI to install the plugins listed in the plugins.txt file. RUN jenkins-plugin-cli --verbose -f /usr/share/jenkins/ref/plugins.txt -# Create admin user and don't start the wizard -RUN echo 2.0 > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state +# We copy a pre-configured Jenkins configuration file to the Jenkins ref directory in the image. +# This allows us to pre-configure Jenkins with our desired settings. +COPY jenkins.yaml /usr/share/jenkins/ref/jenkins.yaml + +# Create an admin user and don't start the wizard +RUN echo 2.x > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state ENV JENKINS_OPTS -Djenkins.install.runSetupWizard=false COPY security.groovy /usr/share/jenkins/ref/init.groovy.d/basic-security.groovy diff --git a/docker/images/jenkins-controller/jenkins.yaml b/docker/images/jenkins-controller/jenkins.yaml index 3a48a123..f7673691 100644 --- a/docker/images/jenkins-controller/jenkins.yaml +++ b/docker/images/jenkins-controller/jenkins.yaml @@ -7,6 +7,8 @@ jenkins: standard: excludeClientIPFromCrumb: false disableRememberMe: false + disabledAdministrativeMonitors: + - "hudson.diagnosis.ReverseProxySetupMonitor" markupFormatter: rawHtml: disableSyntaxHighlighting: false @@ -14,48 +16,105 @@ jenkins: myViewsTabBar: "standard" nodes: - permanent: + labelString: "docker linux agent java jdk21 java21" launcher: ssh: - credentialsId: "java-agent-ssh-private-key" - host: "java11-agent" - launchTimeoutSeconds: 210 - maxNumRetries: 10 + credentialsId: "jenkins-ssh-agent-private-key" + host: "java-agent" port: 22 - retryWaitTime: 15 - jvmOptions: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8001" - javaPath: "/opt/java/openjdk/bin/java" sshHostKeyVerificationStrategy: "nonVerifyingKeyVerificationStrategy" - name: "java11-agent" + name: "java-agent" + nodeDescription: "Jenkins Docker Agent with Java 21 and Maven" numExecutors: 1 - remoteFS: "/var/data" - nodeProperties: - - envVars: - env: - - key: "JAVA_HOME" - value: "/opt/java/openjdk" - - key: "MAVEN_HOME" - value: "/opt/maven" + remoteFS: "/home/jenkins/agent" + retentionStrategy: "always" numExecutors: 0 primaryView: - all: - name: "all" + list: + columns: + - "status" + - "weather" + - "jobName" + - "gitBranchSpecifierColumn" + - "lastSuccess" + - "lastFailure" + - "lastDuration" + - coverageTotalsColumn: + columnName: "Line Coverage" + metric: LINE + - coverageTotalsColumn: + columnName: "Branch Coverage" + metric: BRANCH + - "buildButton" + includeRegex: ".*" + name: "List View" projectNamingStrategy: "standard" quietPeriod: 5 - remotingSecurity: - enabled: true scmCheckoutRetryCount: 0 securityRealm: local: allowsSignup: false enableCaptcha: false slaveAgentPort: 50000 - systemMessage: "

Warnings Next Generation Plugin Showcase

" + systemMessage: "

Java and Maven Showcase

" updateCenter: sites: - id: "default" url: "https://updates.jenkins.io/update-center.json" + views: + - list: + columns: + - "status" + - "weather" + - "jobName" + - "gitBranchSpecifierColumn" + - "lastSuccess" + - "lastFailure" + - "lastDuration" + - coverageTotalsColumn: + columnName: "Line Coverage" + metric: LINE + - coverageTotalsColumn: + columnName: "Branch Coverage" + metric: BRANCH + - "buildButton" + includeRegex: ".*" + name: "List View" + - dashboard: + columns: + - "status" + - "weather" + - "jobName" + - "lastSuccess" + - "lastFailure" + - "lastDuration" + - coverageTotalsColumn: + columnName: "Line Coverage" + metric: LINE + - coverageTotalsColumn: + columnName: "Branch Coverage" + metric: BRANCH + - "buildButton" + includeStdJobList: true + includeRegex: ".*" + leftPortlets: + - issuesChartPortlet: + height: 600 + name: "Static analysis issues chart" + name: "Dashboard View" + rightPortlets: + - issuesTablePortlet: + name: "Static analysis issues per tool and job" + showIcons: true viewsTabBar: "standard" +appearance: + locale: + ignoreAcceptLanguage: true + systemLocale: "USE_BROWSER_LOCALE" + prism: + theme: PRISM + security: apiToken: creationOfLegacyTokenEnabled: false @@ -71,49 +130,18 @@ credentials: domainCredentials: - credentials: - basicSSHUserPrivateKey: - id: "java-agent-ssh-private-key" + description: "Private SSH key for Jenkins agent" + id: "jenkins-ssh-agent-private-key" privateKeySource: directEntry: - privateKey: "-----BEGIN RSA PRIVATE KEY----- \n - MIIEowIBAAKCAQEA86cZk1vZh/OwzJDEqga0nnKEh1QpCm1uSDjvuLp2pPDPHMp/ \n - m9Il9O8ZAZ+IVCUXygO3s1BvBF/a7uVYp7XqjDiTj5Jwrs5lEtl4/1iXXKtwbpAc \n - bsoiEaFDl7Amc4pUfwzsjaqY4yN4jW+JaLOf/+GqCjwpiyJxZ0N2ONlWoph9dvfH \n - JBK+LUcbKIqbBAADT12d6ePIBsDn9Yaeem0xSJrwEzcMTFYj6asinMlWgO7VwgZx \n - JPxhMG+jIq6Mh20tFbwc/XGTqSb/vMkJ8i53RnYm5PoT2xqeYlQCLJtvBRBfuBb5 \n - WJaQcKvTmLoTgkRCbx/QsQzIWzl4MCj56PRsjQIDAQABAoIBAAGTiy7Q4U9n3DT2 \n - ms8ey/xacVEO0lUm8Be3hpWDX1Eh3bUp+jlf2q8C/P5tscwZkVXVQFMAqjc1B42U \n - Hka3fpT5qLq9D82RuEWu8oF0aUZINaoBdK2i0SWcDXvlv9nvgyxvQPiJqgOOLzF7 \n - D0CGKPrW0urOCNbFmkY4wYMMpOrYXnwb6bc1p7snbzeRigaoGvSgvH7fx2Steg1o \n - j50C4BKVtXPKQdmckG2SFn0T+U1iCsRG+KNcENX2vX8gyrXImAH093WTjKsmM9et \n - ddWB+molSnXR/MNrf6BB2mpvXLNyR2/RgBd2jwSQnpDkpms4Br5nek3YYN1dBRL4 \n - 6bofHWECgYEA+7n5OIEbvpMtGxJwOovj0KZMzPkHyQH/DZzo48rS+39goNk/0KLF \n - c3L3sHbT3Lr4qA/6JOCjlzw7o2AbOrRL4ke1uqcCVQMdDqZdvNezMvTzqEbQGdHD \n - aFnEcUV2tvEwP11q37ianBRPH5stOnEwQNuv6AJo5LKwi4mTS7qEW9cCgYEA98oJ \n - h+vMKpXGdJzkSDMzYBrC2tYgqjby6+zGKz8BZ58YecsL+oi2GXBaDTfK+16CKeFM \n - 8+qQN9Kl1ZNOlk64XJXjt77h0FcFuGe+6rUpM1aEizrf9sWPVZO+QQfhnjsiAhtQ \n - YX783ydy9rMn1FDPMtNNq4GMhGsFCaL4RupOjjsCgYAnk9XbTHFQRVOSLhP3IIdx \n - BrSMhZrzv5yaR1FWf00svZozr/SYmP7yZ+EJnaUxzzPJOLnbknYmERJPXYzqbe6A \n - ZUXtUtTLCPJIm1+hkUhbeqfUjU2qwZA3l+WK6aEAomszizyCcEPexlKqZXt29NTh \n - XakKkVZsnqujRL4j6e9lgQKBgQDvhD8EQJyAyXgkvoc3dy6BBj019WdrwWO9Q4km \n - wmdkN3gcOnYgvUdwfZa+UiEGLAub2eldmW3AWADu2s5LIlq5PDX7Jir3DTc9UiNM \n - ksL5mfbS8p0M11i+uupbx/eB0N0FtktTgsGCH4rUBsdIRriSA4h/cOFYGm6rKvnc \n - 6p32gwKBgHZYmXzuBWZlWEmPiXbTaI4egJugur5FrT6BJfiLsN2MHBJi9k1IpKEP \n - SaT+v0IXJ8jP4gSiu4/gyJQpkn7yiMNhwYWlQt+1zyIkHjUsEG82Z8Mqpjx2EJgG \n - MxDybQux1uk0hyCmMS757WkbTyi0pTWz7PgTIdfmYqhZVV8KRSUi \n - -----END RSA PRIVATE KEY----- \n" - scope: GLOBAL - username: "agent" - - gitHubApp: - appID: "74721" - description: "GitHub App" - id: "github-app" - privateKey: ${GITHUB_APP} - scope: GLOBAL + privateKey: ${readFile:/ssh-dir/jenkins_agent_ed} + scope: SYSTEM + username: "jenkins" unclassified: globalDefaultFlowDurabilityLevel: durabilityHint: PERFORMANCE_OPTIMIZED location: - adminAddress: "Adresse nicht konfiguriert " + adminAddress: "Address not configured " url: "http://localhost:8080/" mailer: charset: "UTF-8" @@ -125,21 +153,11 @@ tool: git: installations: - home: "git" - name: "Default" + name: "git-default" maven: installations: - - name: "mvn-default" - properties: - - installSource: - installers: - - maven: - id: "3.6.3" - jdk: - defaultProperties: - - installSource: - installers: - - jdkInstaller: - acceptLicense: false + - home: "/opt/maven" + name: "mvn-default" pipelineMaven: publisherOptions: - jacocoPublisher: @@ -152,66 +170,3 @@ tool: triggerDownstreamUponResultNotBuilt: false triggerDownstreamUponResultSuccess: true triggerDownstreamUponResultUnstable: false - -jobs: - - script: > - pipelineJob('pipeline-codingstyle') { - definition { - cpsScm { - scriptPath 'Jenkinsfile' - scm { - git { - remote { url 'https://github.com/uhafner/codingstyle.git' } - branch '*/main' - extensions {} - } - } - } - } - }; - freeStyleJob('freestyle-codingstyle') { - scm { - git { - remote { url 'https://github.com/uhafner/codingstyle.git' } - branch '*/main' - extensions {} - } - } - steps { - maven { - mavenInstallation('mvn-default') - goals('clean verify') - properties(skipITs: true) - } - } - publishers { - recordIssues { - sourceCodeEncoding('UTF-8') - aggregatingResults(true) - tools { - mavenConsole {} - java {} - javaDoc {} - taskScanner { - highTags('FIXME') - normalTags('TODO') - includePattern('**/*.java') - excludePattern('target/**/*') - } - spotBugs { - pattern('**/target/spotbugsXml.xml') - useRankAsPriority(true) - } - checkStyle { - pattern('**/target/checkstyle-result.xml') - } - pmd { - pattern('**/target/pmd.xml') - } - cpd { - pattern('**/target/cpd.xml') - } - } - } - } - }; diff --git a/docker/images/jenkins-controller/plugins.txt b/docker/images/jenkins-controller/plugins.txt index a89cbd9d..beccaa33 100644 --- a/docker/images/jenkins-controller/plugins.txt +++ b/docker/images/jenkins-controller/plugins.txt @@ -1,5 +1,5 @@ -ace-editor analysis-model-api +ansicolor antisamy-markup-formatter apache-httpcomponents-client-4-api authentication-tokens @@ -7,7 +7,7 @@ autograding bouncycastle-api branch-api cloudbees-folder -code-coverage-api +coverage command-launcher configuration-as-code credentials @@ -18,7 +18,6 @@ docker-commons docker-workflow durable-task email-ext -filesystem_scm file-operations form-element-path git @@ -27,13 +26,12 @@ git-forensics git-server github github-api +github-checks github-branch-source -handlebars jackson2-api javadoc jdk-tool job-dsl -jquery-detached jsch junit locale @@ -42,9 +40,7 @@ mailer matrix-auth matrix-project maven-plugin -metrics-aggregation mock-security-realm -momentjs pam-auth pipeline-build-step pipeline-graph-analysis @@ -57,7 +53,6 @@ pipeline-model-extensions pipeline-rest-api pipeline-stage-step pipeline-stage-tags-metadata -pitmutation plain-credentials resource-disposer scm-api diff --git a/docker/images/jenkins-controller/preconfigured-jobs/freestyle-analysis-model/config.xml b/docker/images/jenkins-controller/preconfigured-jobs/freestyle-analysis-model/config.xml new file mode 100644 index 00000000..0dc75efa --- /dev/null +++ b/docker/images/jenkins-controller/preconfigured-jobs/freestyle-analysis-model/config.xml @@ -0,0 +1,165 @@ + + + + + false + + + 2 + + + https://github.com/jenkinsci/analysis-model.git + + + + + */main + + + false + + + + true + false + false + false + + false + + + clean verify -ntp -Pci + mvn-default + skipITs=true + false + + + true + + + + + + + + 1 + + 2 + + + + JACOCO + + + + + JUNIT + + + + + + + false + Code Coverage + MODIFIED_LINES + false + false + false + false + + + + LAST_BUILD + + + + + + + + + + false + + + + + + + + false + + + + + + + + false + + + + + + FIXME + TODO + + false + false + **/*.java + + + + + + + + + false + true + + + + + + + + false + + + + + + + + false + 50 + 25 + + + UTF-8 + + EVERY_BUILD + false + false + 0 + 0 + + LOW + + + false + false + false + false + true + NEW + false + + AGGREGATION_TOOLS + + + + + \ No newline at end of file diff --git a/docker/images/jenkins-controller/preconfigured-jobs/freestyle-analysis-model/nextBuildNumber b/docker/images/jenkins-controller/preconfigured-jobs/freestyle-analysis-model/nextBuildNumber new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/docker/images/jenkins-controller/preconfigured-jobs/freestyle-analysis-model/nextBuildNumber @@ -0,0 +1 @@ +1 diff --git a/docker/images/jenkins-controller/preconfigured-jobs/history-coverage-model/config.xml b/docker/images/jenkins-controller/preconfigured-jobs/history-coverage-model/config.xml new file mode 100644 index 00000000..f8d6e8fe --- /dev/null +++ b/docker/images/jenkins-controller/preconfigured-jobs/history-coverage-model/config.xml @@ -0,0 +1,168 @@ + + + + + false + + + + true + + + false + diff --git a/docker/images/jenkins-controller/preconfigured-jobs/history-coverage-model/nextBuildNumber b/docker/images/jenkins-controller/preconfigured-jobs/history-coverage-model/nextBuildNumber new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/docker/images/jenkins-controller/preconfigured-jobs/history-coverage-model/nextBuildNumber @@ -0,0 +1 @@ +1 diff --git a/docker/images/jenkins-controller/preconfigured-jobs/pipeline-codingstyle/config.xml b/docker/images/jenkins-controller/preconfigured-jobs/pipeline-codingstyle/config.xml new file mode 100644 index 00000000..2bb17b43 --- /dev/null +++ b/docker/images/jenkins-controller/preconfigured-jobs/pipeline-codingstyle/config.xml @@ -0,0 +1,138 @@ + + + + + false + + + + true + + + false + \ No newline at end of file diff --git a/docker/images/jenkins-controller/preconfigured-jobs/pipeline-codingstyle/nextBuildNumber b/docker/images/jenkins-controller/preconfigured-jobs/pipeline-codingstyle/nextBuildNumber new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/docker/images/jenkins-controller/preconfigured-jobs/pipeline-codingstyle/nextBuildNumber @@ -0,0 +1 @@ +1 diff --git a/docker/images/key-generator/Dockerfile b/docker/images/key-generator/Dockerfile new file mode 100644 index 00000000..995a5eda --- /dev/null +++ b/docker/images/key-generator/Dockerfile @@ -0,0 +1,25 @@ +# Prepare a Debian-based Docker image with several utilities installed to automatically generate SSH keys +FROM debian:bookworm-20240612 + +# Copy all shell scripts from the current directory to /usr/local/bin/ in the image. +COPY *sh /usr/local/bin/ + +# Make all shell scripts in /usr/local/bin/ executable. +RUN chmod +x /usr/local/bin/*.sh + +# The RUN command executes a series of commands in the new layer of the image and commits the results. +# The following commands are executed: + +# 1. Update the package list. +# 2. Install necessary dependencies including several utilities and remove the package list to reduce the image size. +RUN apt update \ + && apt install -y --no-install-recommends ca-certificates curl git gnupg nano openssh-client procps unzip wget \ + && rm -rf /var/lib/apt/lists/* && rm -fr /tmp/* + +# Run the keygen.sh script with /ssh-dir as an argument. +# This script is expected to generate SSH keys and store them in /ssh-dir. +RUN /usr/local/bin/keygen.sh /ssh-dir + +# The CMD command specifies the default command to execute when the container starts. +# In this case, it prints a message and lists the contents of /ssh-dir. +CMD ["sh", "-c", "echo 'Export stage is ready'; ls -l /ssh-dir/"] diff --git a/docker/images/key-generator/keygen.sh b/docker/images/key-generator/keygen.sh new file mode 100644 index 00000000..f65a9922 --- /dev/null +++ b/docker/images/key-generator/keygen.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# This script generates a new SSH key pair and updates a Docker Compose file with the public key. +# Create secrets directory if it doesn't exist +set -x +LOC=$1 +if [[ -z "$LOC" ]]; then + LOC="./" +fi + +echo "Location is $LOC" +ls -artl "$LOC" + +rm "$LOC/conductor_ok" + +mkdir -p "$LOC/secrets" + +# Remove existing keys +rm -fr "$LOC/jenkins_agent_ed" "$LOC/jenkins_agent_ed.pub" + +# Generate new ed25519 SSH key pair +ssh-keygen -t ed25519 -f "$LOC/jenkins_agent_ed" -N "" + +# Set appropriate permissions for private key +chmod 444 "$LOC/jenkins_agent_ed" + +# Extract public key +pubkey=$(cat "$LOC/jenkins_agent_ed.pub") + +echo "The public key is $pubkey" + +# Update the authorized_keys file with the public key +echo "$pubkey" > "$LOC/authorized_keys" && chown 1000:1000 "$LOC/authorized_keys" + +# Generate a random token for JCasc +openssl rand -hex 24 > "$LOC/secrets/jcasc_token" +cat "$LOC/secrets/jcasc_token" + +# This file will be used by other containers to know we went up to the end of the key/token generation +echo "OK" > "$LOC/conductor_ok" + +# Display success message +echo "SSH key pair generated successfully."