So lösen Sie einen Build nur aus, wenn Änderungen an bestimmten Dateien vorgenommen wurden

86

Wie kann ich Jenkins / Hudson anweisen, einen Build nur für Änderungen an einem bestimmten Projekt in meinem Git-Baum auszulösen?

xavier.seignard
quelle

Antworten:

64

Das Git-Plugin verfügt über eine Option (ausgeschlossene Region), mit der Regexe verwendet werden können, um zu bestimmen, ob das Erstellen übersprungen werden soll, basierend darauf, ob die Dateien im Commit mit der Regex der ausgeschlossenen Region übereinstimmen.

Leider verfügt das Standard-Git-Plugin derzeit nicht über die Funktion "Eingeschlossene Region" (1.15). Jemand hat jedoch Patches auf GitHub veröffentlicht, die auf Jenkins und Hudson funktionieren und die gewünschte Funktion implementieren.

Es ist ein wenig Arbeit zu bauen, aber es funktioniert wie angekündigt und war äußerst nützlich, da einer meiner Git-Bäume mehrere unabhängige Projekte hat.

https://github.com/jenkinsci/git-plugin/pull/49

Update: Das Git-Plugin (1.16) verfügt jetzt über die Regionsfunktion "Enthalten".

Aaron Kushner
quelle
5
1.1.16 ist die korrekte Versionsnummer für die enthaltene Funktion. (es gibt keine 1.16)
Dan Carter
Ich kann es nicht zum Laufen bringen, ich habe ein Repositorie mit mehreren Modulen (Domain, Common, API, Desktop_App, ...). Ich möchte einen Build für Desktop_App auslösen. Ich habe zum Beispiel die "eingeschlossenen Regionen" Production_app / * angelegt. Ich habe verschiedene Kombinationen wie ./desktop_app sogar absoluten Pfad ausprobiert. Und ich habe immer Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. Irgendeine Ahnung? Weitere Details hier: stackoverflow.com/questions/47439042/…
FranAguiar
35

Grundsätzlich benötigen Sie zwei Jobs. Eine, um zu überprüfen, ob sich die Dateien geändert haben, und eine, um den eigentlichen Build durchzuführen:

Job # 1

Dies sollte bei Änderungen in Ihrem Git-Repository ausgelöst werden. Anschließend wird geprüft, ob sich der von Ihnen angegebene Pfad (hier "src") geändert hat, und anschließend wird mithilfe der Jenkins-CLI ein zweiter Job ausgelöst.

export JENKINS_CLI="java -jar /var/run/jenkins/war/WEB-INF/jenkins-cli.jar"
export JENKINS_URL=http://localhost:8080/
export GIT_REVISION=`git rev-parse HEAD`
export STATUSFILE=$WORKSPACE/status_$BUILD_ID.txt

# Figure out, whether "src" has changed in the last commit
git diff-tree --name-only HEAD | grep src

# Exit with success if it didn't
$? || exit 0

# Trigger second job
$JENKINS_CLI build job2 -p GIT_REVISION=$GIT_REVISION -s

Job # 2

Konfigurieren Sie diesen Job so, dass er einen Parameter wie GIT_REVISION verwendet, um sicherzustellen, dass Sie genau die Revision erstellen, die der erste Job erstellt hat.

Parametrisierter Build-String-Parameter Parametrisierter Build Git Checkout

Peritus
quelle
6
Was ist, wenn seit dem letzten Build zwei oder mehr Commits stattgefunden haben? Ich denke, Sie könnten Änderungen in src verpassen, da Sie nur das HEAD-Commit untersuchen.
Adam Monsen
@ AdamMonsen Richtig. Sie können das obige Skript jedoch problemlos an jede Situation / Bedingung anpassen, gegen die Sie testen möchten. Beispielsweise unterscheidet es sich nicht von HEAD, sondern von HEAD, als das Skript das letzte Mal ausgeführt wurde.
Peritus
Es fehlt etwas an $? || exit 0... test $? -eq 0 || exit 0vielleicht?
Antak
28

Wenn Sie eine deklarative Syntax von Jenkinsfile verwenden , um Ihre Gebäudepipeline zu beschreiben, können Sie die Änderungssatzbedingung verwenden, um die Bühnenausführung nur auf den Fall zu beschränken, in dem bestimmte Dateien geändert werden. Dies ist jetzt eine Standardfunktion von Jenkins und erfordert keine zusätzliche Konfiguration / Software.

stages {
    stage('Nginx') {
        when { changeset "nginx/*"}
        steps {
            sh "make build-nginx"
            sh "make start-nginx"
        }
    }
}

Sie können mehrere Bedingungen mit anyOfoder allOfSchlüsselwörtern für das ODER- oder UND- Verhalten entsprechend kombinieren :

when {
    anyOf {
        changeset "nginx/**"
        changeset "fluent-bit/**"
    }
}
steps {
    sh "make build-nginx"
    sh "make start-nginx"
}
Anton Golubev
quelle
1
Denken Sie daran, dass es in einigen Fällen nicht funktioniert. Weitere Informationen finden Sie unter issue.jenkins-ci.org/browse/JENKINS-26354 .
Tamerlaha
7

Dies wirkt sich zwar nicht auf einzelne Jobs aus, Sie können dieses Skript jedoch verwenden, um bestimmte Schritte zu ignorieren, wenn das letzte Commit keine Änderungen enthielt:

/*
 * Check a folder if changed in the latest commit.
 * Returns true if changed, or false if no changes.
 */
def checkFolderForDiffs(path) {
    try {
        // git diff will return 1 for changes (failure) which is caught in catch, or
        // 0 meaning no changes 
        sh "git diff --quiet --exit-code HEAD~1..HEAD ${path}"
        return false
    } catch (err) {
        return true
    }
}

if ( checkFolderForDiffs('api/') ) {
    //API folder changed, run steps here
}
Auf Wiedersehen StackExchange
quelle
1
@Karl Sie können den Code jederzeit korrigieren, wenn er für Sie funktioniert. Dies war das einzige Problem, das ich beim Anwenden dieses Codes hatte (Bei Buildfehlern wurde dieses Commit nicht wiederholt, wenn das absolut letzte Commit nicht auch den api/Ordner geändert hat .) Wenn Sie dies beheben können, würde ich eine vorgeschlagene Änderung lieben !
Auf Wiedersehen StackExchange
2

Wenn die Logik für die Auswahl der Dateien nicht trivial ist, würde ich bei jeder Änderung die Skriptausführung auslösen und dann ein Skript schreiben, um zu überprüfen, ob tatsächlich ein Build erforderlich ist, und dann einen Build auslösen, wenn dies der Fall ist.

Uri Cohen
quelle
1

Sie können hierfür das Generic Webhook Trigger Plugin verwenden .

Mit einer Variablen wie changed_filesund Ausdruck $.commits[*].['modified','added','removed'][*].

Sie können einen Filtertext wie $changed_filesund einen regulären Ausdruck wie "folder/subfolder/[^"]+?"if verwenden, wenn dies folder/subfolderder Ordner ist, der Builds auslösen soll.

Tomas Bjerre
quelle
Ich versuche das zu tun, aber ich bin ein bisschen verloren. Wie sende ich den Pfad der geänderten Datei an Jenkins? Könnten Sie bitte etwas mehr erklären? Wo soll die Variable changed_files abgelegt werden?
Souad
Sie müssen einen Webhook in dem von Ihnen verwendeten Git-Dienst konfigurieren. Wenn es GitHub ist, gibt es hier ein Beispiel: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Tomas Bjerre
Als ich Bitbucket verwende, habe ich festgestellt, dass der Eintrag Changed_files in der Nutzlast des Push-Ereignisses in bibucket nicht verfügbar ist (Ref: Confluence.atlassian.com/bitbucket/… ). Daher bin ich mir nicht sicher, wie ich das tun kann. Ich werde mich auf die Commit-Nachricht verlassen, denke ich. Vielen Dank
Souad
1

Ich habe diese Frage in einem anderen Beitrag beantwortet:

So erhalten Sie eine Liste der geänderten Dateien seit dem letzten Build in Jenkins / Hudson

#!/bin/bash

set -e

job_name="whatever"
JOB_URL="http://myserver:8080/job/${job_name}/"
FILTER_PATH="path/to/folder/to/monitor"

python_func="import json, sys
obj = json.loads(sys.stdin.read())
ch_list = obj['changeSet']['items']
_list = [ j['affectedPaths'] for j in ch_list ]
for outer in _list:
  for inner in outer:
    print inner
"

_affected_files=`curl --silent ${JOB_URL}${BUILD_NUMBER}'/api/json' | python -c "$python_func"`

if [ -z "`echo \"$_affected_files\" | grep \"${FILTER_PATH}\"`" ]; then
  echo "[INFO] no changes detected in ${FILTER_PATH}"
  exit 0
else
  echo "[INFO] changed files detected: "
  for a_file in `echo "$_affected_files" | grep "${FILTER_PATH}"`; do
    echo "    $a_file"
  done;
fi;

Sie können die Prüfung direkt oben in der Exec-Shell des Jobs hinzufügen. exit 0Wenn keine Änderungen festgestellt werden, können Sie jederzeit die oberste Ebene nach Eincheckvorgängen abfragen, um einen Build auszulösen.

hhony
quelle
1

Ich habe dieses Skript geschrieben, um Tests zu überspringen oder auszuführen, wenn es Änderungen gibt:

#!/bin/bash

set -e -o pipefail -u

paths=()
while [ "$1" != "--" ]; do
    paths+=( "$1" ); shift
done
shift

if git diff --quiet --exit-code "${BASE_BRANCH:-origin/master}"..HEAD ${paths[@]}; then
    echo "No changes in ${paths[@]}, skipping $@..." 1>&2
    exit 0
fi
echo "Changes found in ${paths[@]}, running $@..." 1>&2

exec "$@"

Sie können also Folgendes tun:

./scripts/git-run-if-changed.sh cmd vendor go.mod go.sum fixtures/ tools/ -- go test

user12513208
quelle