Как вызвать сборку, только если изменения происходят в определенном наборе файлов

Как мне сказать Jenkins/Hudson запускать сборку только для изменений конкретного проекта в моем дереве Git?

Ответ 1

Плагин Git имеет опцию (исключенная область), чтобы использовать регулярные выражения, чтобы определить, следует ли пропустить сборку, в зависимости от того, соответствуют ли файлы в фиксации регулярному выражению исключенной области.

К сожалению, стандартный плагин Git не имеет функции "включенный регион" в настоящее время (1.15). Однако кто-то опубликовал патчи на GitHub, которые работают на Jenkins и Hudson и реализуют нужную вам функцию.

Это небольшая работа по созданию, но она работает так, как рекламируется, и была чрезвычайно полезна, поскольку у одного из моих деревьев Git есть несколько независимых проектов.

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

Обновление: плагин Git (1.16) теперь имеет функцию "включенного" региона.

Ответ 2

В основном вам нужно две работы. Один, чтобы проверить, изменились ли файлы, и один, чтобы сделать фактическую сборку:

Работа № 1

Это должно быть вызвано изменениями в вашем Git-репозитории. Затем он проверяет, изменился ли указанный вами путь (здесь "src"), и затем использует CLI Дженкинса для запуска второго задания.

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

Работа № 2

Настройте это задание так, чтобы он принимал параметр GIT_REVISION, например, чтобы убедиться, что вы создаете именно ту ревизию, которую выбрало первое задание.

Parameterized build string parameter Parameterized build Git checkout

Ответ 3

Хотя это не влияет на отдельные задания, вы можете использовать этот script для игнорирования определенных шагов, если последняя фиксация не содержит никаких изменений:

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

Ответ 4

Если вы используете декларативный синтаксис Jenkinsfile для описания конвейера сборки, вы можете использовать условие changeset, чтобы ограничить выполнение этапа только тем случаем, когда изменяются определенные файлы. Теперь это стандартная функция Jenkins и не требует дополнительной настройки/программного обеспечения.

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

Вы можете комбинировать несколько условий, используя ключевые слова anyOf или allOf для поведения ИЛИ или И соответственно:

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

Ответ 5

Если логика выбора файлов не является тривиальной, я бы запускал выполнение script при каждом изменении, а затем записывал script, чтобы проверить, действительно ли требуется сборка, а затем запускает сборку, если она есть.

Ответ 6

Я ответил на этот вопрос в другом посте:

Как получить список измененных файлов со времени последней сборки в 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;

Вы можете добавить проверку непосредственно в верхнюю часть оболочки Job Exec, и она будет exit 0, если не обнаружено никаких изменений... Следовательно, вы всегда можете опрашивать верхний уровень для регистрации, чтобы вызвать сборку.

Ответ 7

Для этого вы можете использовать Generic Webhook Trigger Plugin.

С такой переменной, как changed_files и выражением $.commits[*].['modified','added','removed'][*].

Вы можете иметь фильтр текста, например, $changed_files, и фильтр регулярных выражений, например, "folder/subfolder/[^"]+?", если folder/subfolder - это папка, которая должна запускать сборки.