Come attivare una build solo se vengono apportate modifiche su un particolare set di file


87

Come faccio a dire a Jenkins / Hudson di attivare una build solo per le modifiche su un particolare progetto nel mio albero Git?

Risposte:


65

Il plug-in Git ha un'opzione (regione esclusa) per utilizzare le espressioni regolari per determinare se saltare la creazione in base alla corrispondenza dei file nel commit con la regione esclusa.

Sfortunatamente, il plugin Git di serie non ha una funzione "regione inclusa" al momento (1.15). Tuttavia, qualcuno ha pubblicato patch su GitHub che funzionano su Jenkins e Hudson che implementano la funzionalità desiderata.

È un po 'di lavoro da costruire, ma funziona come pubblicizzato ed è stato estremamente utile poiché uno dei miei alberi Git ha più progetti indipendenti.

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

Aggiornamento: il plug-in Git (1.16) ora ha la funzione di regione "inclusa".


5
1.1.16 è il numero di versione corretto per la funzionalità inclusa. (non c'è 1.16)
dan carter

Non riesco a farlo funzionare, ho un repository con più moduli (domain, common, api, desktop_app, ...) Voglio attivare una build per desktop_app ad esempio, metto le "regioni incluse" production_app / *, Ho provato diverse combinazioni come ./desktop_app anche percorso assoluto. E ho sempre avuto Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. Qualche indizio? Maggiori dettagli qui: stackoverflow.com/questions/47439042/...
FranAguiar

38

Fondamentalmente, hai bisogno di due lavori. Uno per verificare se i file sono cambiati e uno per eseguire la build effettiva:

Lavoro n. 1

Questo dovrebbe essere attivato in caso di modifiche nel tuo repository Git. Quindi verifica se il percorso specificato ("src" qui) presenta modifiche e quindi utilizza la CLI di Jenkins per attivare un secondo lavoro.

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

Lavoro n. 2

Configura questo lavoro per prendere un parametro GIT_REVISION in questo modo, per assicurarti di costruire esattamente la revisione che il primo lavoro ha scelto di costruire.

Parametro della stringa di compilazione parametrizzato Checkout Git di build parametrizzato


7
Cosa succede se due o più commit sono stati eseguiti dall'ultima build? Penso che potresti perdere i cambiamenti in src poiché stai solo esaminando il commit HEAD.
Adam Monsen

@AdamMonsen Right. Ma puoi facilmente adattare lo script precedente a qualsiasi situazione / condizione su cui vuoi testare .. per esempio non differisce da HEAD ma da ciò che era HEAD l'ultima volta che lo script è stato eseguito.
peritus

Manca qualcosa a $? || exit 0... test $? -eq 0 || exit 0forse?
antak

34

Se si utilizza una sintassi dichiarativa di Jenkinsfile per descrivere la pipeline di costruzione, è possibile utilizzare la condizione changeset per limitare l'esecuzione della fase solo nel caso in cui vengano modificati file specifici. Questa è ora una caratteristica standard di Jenkins e non richiede alcuna configurazione / software aggiuntivo.

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

Puoi combinare più condizioni utilizzando anyOfo allOfparole chiave per il comportamento OR o AND di conseguenza:

when {
    anyOf {
        changeset "nginx/**"
        changeset "fluent-bit/**"
    }
}
steps {
    sh "make build-nginx"
    sh "make start-nginx"
}

1
Tieni presente che in alcuni casi non funziona. Fare riferimento a issues.jenkins-ci.org/browse/JENKINS-26354 per maggiori dettagli.
tamerlaha

7

Sebbene ciò non influisca sui singoli lavori, è possibile utilizzare questo script per ignorare determinati passaggi se l'ultimo commit non conteneva modifiche:

/*
 * 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
}

1
@Karl sentiti libero di correggere il codice se funziona per te. Questo è stato l'unico problema che ho riscontrato durante l'applicazione di questo codice (in caso di errori di compilazione, non riproverebbe questo commit, se l'ultimo commit assoluto non cambiasse anche la api/cartella.) Se puoi risolvere questo problema, mi piacerebbe una modifica suggerita !
Arrivederci StackExchange

2

Se la logica per la scelta dei file non è banale, attiverei l'esecuzione di script ad ogni modifica e quindi scriverei uno script per verificare se effettivamente è richiesta una build, quindi attivando una build se lo è.


1

Puoi usare Generic Webhook Trigger Plugin per questo.

Con una variabile like changed_filesand expression $.commits[*].['modified','added','removed'][*].

Puoi avere un filtro di testo come $changed_filese filtro regexp come "folder/subfolder/[^"]+?"se folder/subfolderfosse la cartella che dovrebbe attivare le build.


Sto provando a farlo ma sono un po 'perso. come inviare il percorso del file modificato a jenkins? potresti spiegare un po 'di più per favore? Dove mettere la variabile changes_files?
Souad

Devi configurare un webhook nel servizio Git che stai utilizzando. Se è GitHub, c'è un esempio qui: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Tomas Bjerre

Infatti mentre sto usando Bitbucket, mi sono reso conto che la voce Changed_files non è disponibile nel payload dell'evento push in bibucket (ref: confluence.atlassian.com/bitbucket/… ) quindi non sono sicuro di come posso farlo. Mi affiderò al messaggio di commit, credo. grazie
Souad

1

Ho risposto a questa domanda in un altro post:

Come ottenere l'elenco dei file modificati dall'ultima 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;

Puoi aggiungere il controllo direttamente all'inizio della shell di esecuzione del lavoro e lo farà exit 0se non vengono rilevate modifiche ... Quindi, puoi sempre eseguire il polling del livello più alto per i check-in per attivare una build.


1

Ho scritto questo script per saltare o eseguire test se ci sono modifiche:

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

Quindi puoi fare qualcosa come:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.