Jak wyzwolić kompilację tylko wtedy, gdy zmiany dotyczą określonego zestawu plików

87

Jak powiedzieć Jenkins / Hudson, aby wyzwalał kompilację tylko w przypadku zmian w określonym projekcie w moim drzewie Git?

xavier.seignard
źródło

Odpowiedzi:

65

Wtyczka Git ma opcję (wykluczony region), aby użyć wyrażeń regularnych w celu określenia, czy pominąć budowanie na podstawie tego, czy pliki w zatwierdzeniu pasują do wyrażenia regularnego wykluczonego regionu.

Niestety, standardowa wtyczka Git nie ma obecnie funkcji „dołączonego regionu” (1.15). Jednak ktoś opublikował poprawki na GitHub, które działają na Jenkins i Hudson, które implementują żądaną funkcję.

Jest to trochę pracy do zbudowania, ale działa zgodnie z reklamą i jest niezwykle przydatne, ponieważ jedno z moich drzew Git ma wiele niezależnych projektów.

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

Aktualizacja: Wtyczka Git (1.16) ma teraz funkcję „uwzględnionego” regionu.

Aaron Kushner
źródło
5
1.1.16 to poprawny numer wersji dołączonej funkcji. (nie ma 1.16)
dan Carter
Nie mogę sprawić, żeby to zadziałało, mam repozytorium z wieloma modułami (domain, common, api, desktop_app, ...) Chcę wyzwolić kompilację dla desktop_app, na przykład umieszczam na "uwzględnionych regionach" production_app / *, Wypróbowałem kilka kombinacji, takich jak ./desktop_app, nawet ścieżka bezwzględna. I zawsze miałem Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. Jakaś wskazówka? Więcej szczegółów tutaj: stackoverflow.com/questions/47439042/…
FranAguiar
38

Zasadniczo potrzebujesz dwóch miejsc pracy. Jeden, aby sprawdzić, czy pliki się zmieniły, i drugi, aby wykonać właściwą kompilację:

Zadanie nr 1

Powinno to być uruchamiane po zmianach w repozytorium Git. Następnie sprawdza, czy określona ścieżka (tutaj „src”) ma zmiany, a następnie używa interfejsu wiersza polecenia Jenkinsa do wyzwolenia drugiego zadania.

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

Zadanie nr 2

Skonfiguruj to zadanie tak, aby przyjmowało parametr GIT_REVISION w ten sposób, aby upewnić się, że tworzysz dokładnie tę wersję, którą zbudowało pierwsze zadanie.

Sparametryzowany parametr ciągu kompilacji Sparametryzowana kompilacja Git checkout

peritus
źródło
6
Co się stanie, jeśli od ostatniej kompilacji wydarzyły się dwa lub więcej zatwierdzeń? Myślę, że możesz przegapić zmiany w src, ponieważ badasz tylko zmianę HEAD.
Adam Monsen
@AdamMonsen Right. Ale możesz łatwo dostosować powyższy skrypt do dowolnej sytuacji / warunku, w odniesieniu do którego chcesz przetestować ... na przykład nie w porównaniu z HEAD, ale z tym, co było HEAD ostatnim razem, gdy skrypt był uruchamiany.
peritus
Coś brakuje w $? || exit 0... test $? -eq 0 || exit 0może?
antak
32

Jeśli używasz deklaratywnej składni Jenkinsfile do opisania potoku budowania, możesz użyć warunku zestawu zmian , aby ograniczyć wykonywanie etapu tylko do przypadku, gdy określone pliki zostaną zmienione. Jest to teraz standardowa funkcja Jenkinsa i nie wymaga żadnej dodatkowej konfiguracji / oprogramowania.

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

Możesz łączyć wiele warunków, używając słów kluczowych anyOflub odpowiednio allOfdla zachowania OR lub AND :

when {
    anyOf {
        changeset "nginx/**"
        changeset "fluent-bit/**"
    }
}
steps {
    sh "make build-nginx"
    sh "make start-nginx"
}
Anton Golubev
źródło
1
Pamiętaj, że w niektórych przypadkach nie działa. Więcej informacji można znaleźć na stronie issue.jenkins-ci.org/browse/JENKINS-26354 .
tamerlaha
7

Chociaż nie ma to wpływu na pojedyncze zadania, możesz użyć tego skryptu, aby zignorować niektóre kroki, jeśli najnowsze zatwierdzenie nie zawierało żadnych zmian:

/*
 * 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
}
Żegnaj StackExchange
źródło
1
@Karl, nie krępuj się naprawić kod, jeśli działa on dla Ciebie. To był jedyny problem, jaki miałem podczas stosowania tego kodu (w przypadku niepowodzeń kompilacji nie spróbowałby ponownie tego zatwierdzenia, gdyby absolutne najnowsze zatwierdzenie nie zmieniło również api/folderu). Jeśli możesz to naprawić, chciałbym zaproponować sugerowaną zmianę !
Goodbye StackExchange
2

Jeśli logika wyboru plików nie jest trywialna, wyzwalałbym wykonanie skryptu przy każdej zmianie, a następnie napisałbym skrypt, aby sprawdzić, czy rzeczywiście jest wymagana kompilacja, a następnie wyzwolić kompilację, jeśli jest.

Uri Cohen
źródło
1

Możesz do tego użyć Generic Webhook Trigger Plugin .

Ze zmienną taką jak changed_filesi wyrażeniem $.commits[*].['modified','added','removed'][*].

Możesz mieć tekst filtru, taki jak $changed_filesi wyrażenie regularne filtru, takie jak "folder/subfolder/[^"]+?"if folder/subfolderto folder, który powinien wyzwalać kompilacje.

Tomas Bjerre
źródło
Próbuję to zrobić, ale jestem trochę zagubiony. jak wysłać ścieżkę zmienionego pliku do jenkins? czy mógłbyś wyjaśnić trochę więcej? Gdzie umieścić zmienną change_files?
Souad
Musisz skonfigurować webhook w usłudze Git, której używasz. Jeśli jest to GitHub, tutaj jest przykład: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Tomas Bjerre
W rzeczywistości, ponieważ używam Bitbucket, zdałem sobie sprawę, że wpis Changed_files nie jest dostępny w ładunku zdarzenia push w bibucket (ref: confluence.atlassian.com/bitbucket/… ), więc nie jestem pewien, jak mam to zrobić. Myślę, że będę polegał na komunikacie dotyczącym zatwierdzenia. dziękuję
Souad
1

Odpowiedziałem na to pytanie w innym poście:

Jak uzyskać listę zmienionych plików od ostatniej kompilacji w 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;

Możesz dodać czek bezpośrednio na górę powłoki exec zadania i zrobi to, exit 0jeśli nie zostaną wykryte żadne zmiany ... Dlatego zawsze możesz sondować najwyższy poziom, aby sprawdzić, czy uruchomi kompilację.

hhony
źródło
1

Napisałem ten skrypt, aby pomijać lub wykonywać testy, jeśli są zmiany:

#!/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 "$@"

Możesz więc zrobić coś takiego:

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

user12513208
źródło