Jenkins ist ein sehr vielseitiger Buildserver. Mit Groovy-Scripts kann man neben der Erweiterung durch Plugins noch viel mehr herausholen. Dieser Beitrag zeigt wie das geht.

Seit einigen Jahren setze ich nun auf Jenkins und bin seit jeher sehr glücklich mit diesem System. Durch die zahlreich verfügbaren Plugins kann man Builds unheimlich schnell konfigurieren. Mit steigenden Anforderungen, die über allgemeine Ansätze hinaus gehen, muss man jedoch selbst Hand anlegen. Eine gute Möglichkeit dazu bieten Groovy-Scripts.

Was ist Groovy?

Dazu sagt die Groovy-Webiste:

Apache Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities, for the Java platform aimed at improving developer productivity thanks to a concise, familiar and easy to learn syntax. It integrates smoothly with any Java program, and immediately delivers to your application powerful features, including scripting capabilities, Domain-Specific Language authoring, runtime and compile-time meta-programming and functional programming.

Jenkins und Groovy

Jenkins bietet über die Skript-Konsole (siehe Jenkins-Verwaltung) die Möglichkeit Groovy-Scripts auszuführen. Dazu muss allerdings Groovy installiert sein, auch in der Global Tool Configuration ist der Pfad zu konfigurieren.

Mit dem Groovy-Plugin können Groovy-Scripts auch innerhalb eines Builds ausgeführt werden. Hierzu stehen zwei Varianten zur Verfügung:

  • Groovy Scripts
  • System Groovy Scripts

Während normale Groovy Scripts in einer eigenen JVM auf dem Slave ausgeführt werden, der den Build ausführt, laufen die System Groovy Scripts innerhalb der Jenkins JVM. So haben sie Zugriff auf die Jenkins API und Informationen des Builds können ausgelesen werden. In vielen Fällen ist eine Manipulation derselben ebenfalls möglich.

Als ganz einfaches Beispiel kann der Name des Builds angepasst werden. Im Standard wird #Buildnummer verwendet. In vielen Fällen möchte man aber eine andere Notation um zusätzliche Informationen darin zu kodieren. Diese könnte als Beispiel so aussehen: 1.0.0.1-DEV-20161212-1800 und entspricht dem ersten DEV-Build inkl. Datumsinformation. Und so sieht das Script dazu aus:

import java.text.SimpleDateFormat;

def sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
def version = "1.0.0.";
def type = "DEV";
def build_date = sdf.format(build.getTime());

def build_id = build.properties.environment.BUILD_NUMBER.toString();

def version_number_formatted = version + build_id + "-" + type + "-" + build_date;

build.displayName = version_number_formatted;

Nun möchte man so generierte Informationen in Build-Variablen setzen, um sie eventuell in anderen Plugins abrufen zu können. Hierzu habe ich den Artikel Programmatically set Jenkins build variables gefunden. Im Gegensatz zu vielen anderen Lösungen, die man über die Suchmaschine seiner Wahl findet, funktioniert diese auch. Erreicht wird dies durch nachfolgenden Code:

import hudson.EnvVars
import hudson.model.*

def build_number = Job.getVariable("BUILD_NUMBER")
def branch_name  = Job.getVariable("GIT_BRANCH")

def build_branch = "${build_number}-${branch_name}"

Job.setVariable("BUILD_BRANCH", build_branch)

class Job {

    static def getVariable(String key) {
        def config = new HashMap()
        def thr = Thread.currentThread()
        def build = thr?.executable
        def envVarsMap = build.parent.builds[0].properties.get("envVars")
        config.putAll(envVarsMap)
        return config.get(key)
    }

    static def setVariable(String key, String value) {
        def build = Thread.currentThread().executable
        def action = new VariableInjectionAction(key, value)
        build.addAction(action)
        build.getEnvironment()
    }
}

class VariableInjectionAction implements EnvironmentContributingAction {

    private String key
    private String value

    public VariableInjectionAction(String key, String value) {
        this.key = key
        this.value = value
    }

    public void buildEnvVars(AbstractBuild build, EnvVars envVars) {

        if (envVars != null && key != null && value != null) {
            envVars.put(key, value);
        }
    }

    public String getDisplayName() {
        return "VariableInjectionAction";
    }

    public String getIconFileName() {
        return null;
    }

    public String getUrlName() {
        return null;
    }
}

Groovy als Post-Build Action ausführen

Standardmäßig können in der Post-Build Action keine Shell- und Script-Tasks ausgeführt werden. Wer das benötigt, installiert sich das Hudson Post build task-Plugin. Dieses ermöglicht die Ausführung von Groovy Commands und Scripts (auch System Scripts). Zuvor gesetzte Variablen können natürlich an dieser Stelle verwendet werden.

Zudem hat man die Möglichkeit, die Scripts nur dann ausführen zu lassen, wenn der Build durchgelaufen ist.

Fazit

Wer das Buildsystem ausreizen möchte, hat mehrere Möglichkeiten. Parametrisierte Shell-Scripts/Commands sind eine mögliche Variante. Weit angenehmer empfinde ich jedoch Groovy-Scripts, da durch die System Scripts auf die Jenkins-API zugegriffen werden kann. Grundlegende Java-Kenntnisse werden allerdings empfohlen.

Über den Autor

Norbert Eder

Ich bin ein leidenschaftlicher Softwareentwickler und Fotograf. Mein Wissen und meine Gedanken teile ich nicht nur hier im Blog, sondern auch in Fachartikeln und Büchern.