Cómo activar una compilación solo si se producen cambios en un conjunto particular de archivos

87

¿Cómo le digo a Jenkins / Hudson que active una compilación solo para cambios en un proyecto en particular en mi árbol de Git?

xavier.seignard
fuente

Respuestas:

65

El complemento de Git tiene una opción (región excluida) para usar expresiones regulares para determinar si se debe omitir la construcción en función de si los archivos en la confirmación coinciden con la expresión regular de la región excluida.

Desafortunadamente, el complemento Git estándar no tiene una característica de "región incluida" en este momento (1.15). Sin embargo, alguien publicó parches en GitHub que funcionan en Jenkins y Hudson que implementan la función que desea.

Es un poco trabajo de construir, pero funciona como se anuncia y ha sido extremadamente útil ya que uno de mis árboles Git tiene múltiples proyectos independientes.

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

Actualización: el complemento Git (1.16) ahora tiene la función de región 'incluida'.

Aaron Kushner
fuente
5
1.1.16 es el número de versión correcto para la función incluida. (no hay 1.16)
dan carter
No puedo hacer que funcione, tengo un repositorio con varios módulos (dominio, común, api, desktop_app, ...) Quiero activar una compilación para desktop_app, por ejemplo, puse las "regiones incluidas" production_app / *, Probé varias combinaciones como ./desktop_app incluso ruta absoluta. Y siempre lo tengo Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. ¿Cualquier pista? Más detalles aquí: stackoverflow.com/questions/47439042/…
FranAguiar
38

Básicamente, necesitas dos trabajos. Uno para verificar si los archivos cambiaron y otro para hacer la compilación real:

Trabajo # 1

Esto debería activarse ante cambios en su repositorio de Git. Luego prueba si la ruta que especifica ("src" aquí) tiene cambios y luego usa la CLI de Jenkins para activar un segundo trabajo.

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

Trabajo # 2

Configure este trabajo para que tome un parámetro GIT_REVISION como este, para asegurarse de que está creando exactamente la revisión que eligió construir el primer trabajo.

Parámetro de cadena de construcción parametrizado Comprobación de Git de compilación parametrizada

peritus
fuente
6
¿Y si ocurrieron dos o más confirmaciones desde la última compilación? Creo que es posible que se pierda los cambios en src ya que solo está examinando la confirmación HEAD.
Adam Monsen
@AdamMonsen Correcto. Pero puede adaptar fácilmente el script anterior a cualquier situación / condición contra la que desee probar ... por ejemplo, no diferir contra HEAD sino contra lo que era HEAD la última vez que se ejecutó el script.
peritus
Falta algo en $? || exit 0... test $? -eq 0 || exit 0¿quizás?
antak
32

Si está utilizando una sintaxis declarativa de Jenkinsfile para describir su canalización de construcción, puede usar la condición de conjunto de cambios para limitar la ejecución de la etapa solo al caso en que se modifican archivos específicos. Esta es ahora una característica estándar de Jenkins y no requiere ninguna configuración / software adicional.

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

Puede combinar varias condiciones utilizando anyOfo allOfpalabras clave para el comportamiento OR o AND según corresponda:

when {
    anyOf {
        changeset "nginx/**"
        changeset "fluent-bit/**"
    }
}
steps {
    sh "make build-nginx"
    sh "make start-nginx"
}
Anton Golubev
fuente
1
Tenga en cuenta que no funciona en algunos casos. Consulte issues.jenkins-ci.org/browse/JENKINS-26354 para obtener más detalles.
tamerlaha
7

Si bien esto no afecta a trabajos individuales, puede usar este script para ignorar ciertos pasos si la última confirmación no contiene ningún cambio:

/*
 * 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
}
Adiós StackExchange
fuente
1
@Karl no dude en corregir el código si funciona para usted. Ese fue el único problema que tuve al aplicar este código (en fallas de compilación, no volvería a intentar esta confirmación, si la última confirmación absoluta no cambiaba también la api/carpeta). Si puede solucionar esto, me encantaría un cambio sugerido !
Adiós StackExchange
2

Si la lógica para elegir los archivos no es trivial, activaría la ejecución del script en cada cambio y luego escribiría un script para verificar si realmente se requiere una compilación, y luego activaría una compilación si lo es.

Uri Cohen
fuente
1

Puede utilizar Generic Webhook Trigger Plugin para esto.

Con una variable like changed_filesy expresión $.commits[*].['modified','added','removed'][*].

Puede tener un texto de filtro como $changed_filesy regexp de filtro como "folder/subfolder/[^"]+?"si fuera folder/subfolderla carpeta que debería activar las compilaciones.

Tomas Bjerre
fuente
Estoy tratando de hacer esto pero estoy un poco perdido. ¿Cómo enviar la ruta del archivo modificado a Jenkins? ¿Podrías explicar un poco más por favor? ¿Dónde poner la variable change_files?
Souad
Necesita configurar un webhook en el servicio Git que está utilizando. Si es GitHub, hay un ejemplo aquí: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Tomas Bjerre
De hecho, mientras estoy usando Bitbucket, me di cuenta de que la entrada Changed_files no está disponible en la carga útil del evento push en bibucket (ref: confluence.atlassian.com/bitbucket/… ), así que no estoy seguro de cómo puedo hacer esto. Confiaré en el mensaje de confirmación, creo. gracias
Souad
1

Respondí esta pregunta en otra publicación:

Cómo obtener una lista de archivos modificados desde la última compilación en 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;

Puede agregar el cheque directamente en la parte superior del shell ejecutivo del trabajo, y lo hará exit 0si no se detectan cambios ... Por lo tanto, siempre puede sondear el nivel superior para que los registros activen una compilación.

hhony
fuente
1

Escribí este script para omitir o ejecutar pruebas si hay cambios:

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

Entonces puedes hacer algo como:

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

usuario12513208
fuente