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

87

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

xavier.seignard
источник

Ответы:

65

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

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

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

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

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

Аарон Кушнер
источник
5
1.1.16 - правильный номер версии для включенной функции. (нет 1.16)
Дэн Картер
Я не могу заставить его работать, у меня есть репозиторий с несколькими модулями (domain, common, api, desktop_app, ...). Я хочу запустить сборку для desktop_app, например, я включил "включенные регионы" production_app / *, Я пробовал несколько комбинаций, например ./desktop_app, даже абсолютный путь. И всегда получал Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. Есть подсказка? Подробнее здесь: stackoverflow.com/questions/47439042/…
FranAguiar
38

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

Работа №1

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

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 таким образом, чтобы убедиться, что вы создаете именно ту ревизию, которую выбрало первое задание.

Параметризованный строковый параметр сборки Параметризованная сборка Git checkout

перитус
источник
6
Что, если с момента последней сборки произошло два или более коммитов? Я думаю, вы можете пропустить изменения в src, поскольку вы изучаете только фиксацию HEAD.
Адам Монсен
@AdamMonsen Верно. Но вы можете легко адаптировать приведенный выше сценарий к любой ситуации / условию, которое вы хотите протестировать ... например, не сравнивая с HEAD, а с тем, что было HEAD в последний раз, когда скрипт запускался.
Peritus
Чего-то не хватает $? || exit 0... test $? -eq 0 || exit 0может быть?
antak
32

Если вы используете декларативный синтаксис Jenkinsfile для описания конвейера сборки, вы можете использовать условие набора изменений, чтобы ограничить выполнение стадии только тем случаем, когда были изменены определенные файлы. Теперь это стандартная функция 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"
}
Антон Голубев
источник
1
Имейте в виду, что в некоторых случаях это не работает. См. Issues.jenkins-ci.org/browse/JENKINS-26354 для получения дополнительных сведений.
tamerlaha
7

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

/*
 * 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
}
Прощай, StackExchange
источник
1
@Karl не стесняйтесь исправлять код, если он вам подходит. Это была единственная проблема, с которой я столкнулся при применении этого кода (при сбоях сборки он не будет повторять эту фиксацию, если самая последняя фиксация также не изменила api/папку). Если вы можете это исправить, мне бы понравилось предлагаемое изменение !
Прощай, StackExchange
2

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

Ури Коэн
источник
1

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

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

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

Томас Бьерре
источник
Я пытаюсь это сделать, но я немного потерялся. как отправить путь к измененному файлу jenkins? не могли бы вы объяснить еще немного, пожалуйста? Куда поставить переменную changed_files?
Суад
Вам необходимо настроить веб-перехватчик в используемом вами сервисе Git. Если это GitHub, то здесь есть пример: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Томас Бьерре
Фактически, когда я использую Bitbucket, я понял, что запись Changed_files недоступна в полезной нагрузке события push в bibucket (ref: confluence.atlassian.com/bitbucket/… ), поэтому я не уверен, как я могу это сделать. Думаю, я буду полагаться на сообщение фиксации. спасибо
Суад
1

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

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

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

hhony
источник
1

Я написал этот скрипт, чтобы пропустить или выполнить тесты, если есть изменения:

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

Итак, вы можете сделать что-то вроде:

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

user12513208
источник