Como acionar uma compilação apenas se as mudanças acontecerem em um determinado conjunto de arquivos

87

Como faço para dizer ao Jenkins / Hudson para acionar uma construção apenas para mudanças em um projeto específico em minha árvore Git?

xavier.seignard
fonte

Respostas:

65

O plugin Git tem uma opção (região excluída) para usar regexes para determinar se deve pular a construção com base em se os arquivos no commit correspondem ao regex da região excluída.

Infelizmente, o plugin Git padrão não tem um recurso de "região incluída" no momento (1.15). No entanto, alguém postou patches no GitHub que funcionam no Jenkins e no Hudson e implementam o recurso que você deseja.

É um pouco trabalhoso de construir, mas funciona como anunciado e tem sido extremamente útil, pois uma das minhas árvores Git tem vários projetos independentes.

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

Atualização: O plugin Git (1.16) agora tem o recurso de região 'incluído'.

Aaron Kushner
fonte
5
1.1.16 é o número da versão correto para o recurso incluído. (não há 1.16)
dan carter
Não consigo fazer funcionar, tenho um repositório com vários módulos (domínio, comum, api, desktop_app, ...) Quero acionar uma compilação para desktop_app por exemplo, coloco em "regiões incluídas" production_app / *, Tentei várias combinações como ./desktop_app até mesmo caminho absoluto. E eu sempre consegui Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. Qualquer pista? Mais detalhes aqui: stackoverflow.com/questions/47439042/…
FranAguiar
38

Basicamente, você precisa de dois empregos. Um para verificar se os arquivos foram alterados e outro para fazer a compilação real:

Trabalho # 1

Isso deve ser acionado em mudanças em seu repositório Git. Em seguida, testa se o caminho que você especifica ("src" aqui) tem alterações e usa a CLI do Jenkins para acionar um segundo trabalho.

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

Trabalho # 2

Configure este trabalho para receber um parâmetro GIT_REVISION como este, para ter certeza de que está construindo exatamente a revisão que o primeiro trabalho escolheu construir.

Parâmetro de string de construção parametrizado Verificação de Git da compilação parametrizada

perito
fonte
6
E se dois ou mais commits aconteceram desde a última compilação? Acho que você pode perder as mudanças no src, já que está apenas examinando o commit HEAD.
Adam Monsen,
@AdamMonsen Certo. Mas você pode facilmente adaptar o script acima para qualquer situação / condição que você deseja testar ... por exemplo, não comparando com HEAD, mas com o que era HEAD da última vez que o script foi executado.
peritus
Há algo faltando em $? || exit 0... test $? -eq 0 || exit 0talvez?
antak
32

Se você estiver usando uma sintaxe declarativa de Jenkinsfile para descrever o pipeline de construção, poderá usar a condição do changeset para limitar a execução do estágio apenas para o caso em que arquivos específicos são alterados. Este agora é um recurso padrão do Jenkins e não requer nenhuma configuração / software adicional.

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

Você pode combinar várias condições usando anyOfou allOfpalavras - chave para comportamento OR ou AND de acordo:

when {
    anyOf {
        changeset "nginx/**"
        changeset "fluent-bit/**"
    }
}
steps {
    sh "make build-nginx"
    sh "make start-nginx"
}
Anton Golubev
fonte
1
Lembre-se de que não funciona em alguns casos. Consulte issues.jenkins-ci.org/browse/JENKINS-26354 para obter mais detalhes.
tamerlaha
7

Embora isso não afete jobs individuais, você pode usar este script para ignorar certas etapas se o commit mais recente não contiver nenhuma alteração:

/*
 * 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
}
Adeus StackExchange
fonte
1
@Karl sinta-se à vontade para corrigir o código se funcionar para você. Esse foi o único problema que tive ao aplicar este código (em falhas de compilação, ele não tentaria novamente este commit, se o commit mais recente absoluto também não alterasse a api/pasta.) Se você pudesse corrigir isso, eu adoraria uma alteração sugerida !
Adeus StackExchange
2

Se a lógica para escolher os arquivos não for trivial, eu acionaria a execução do script em cada mudança e, em seguida, escreveria um script para verificar se de fato uma construção é necessária e, em seguida, acionaria uma construção se for.

Uri Cohen
fonte
1

Você pode usar o plug-in do acionador do Webhook genérico para isso.

Com uma variável like changed_filese expression $.commits[*].['modified','added','removed'][*].

Você pode ter um texto de filtro $changed_filese um regexp de filtro como "folder/subfolder/[^"]+?"se folder/subfolderfor a pasta que deve acionar as compilações.

Tomas Bjerre
fonte
Estou tentando fazer isso, mas estou um pouco perdido. como enviar o caminho do arquivo alterado para jenkins? você poderia explicar um pouco mais por favor? Onde colocar a variável changed_files?
Souad
Você precisa configurar um webhook no serviço Git que está usando. Se for o GitHub, há um exemplo aqui: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Tomas Bjerre
Na verdade, como estou usando o Bitbucket, percebi que a entrada Changed_files não está disponível na carga do evento push no bibucket (ref: confluence.atlassian.com/bitbucket/… ), então não tenho certeza de como posso fazer isso. Vou confiar na mensagem de commit, eu acho. obrigado
Souad
1

Eu respondi a essa pergunta em outro post:

Como obter uma lista de arquivos alterados desde a última compilação no 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;

Você pode adicionar a verificação diretamente ao topo do shell exec da tarefa, e isso acontecerá exit 0se nenhuma alteração for detectada ... Portanto, você sempre pode pesquisar o nível superior para verificações para acionar uma compilação.

hhony
fonte
1

Escrevi este script para pular ou executar testes se houver alterações:

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

Então você pode fazer algo como:

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

user12513208
fonte