Як ініціювати збірку, лише якщо зміни відбуваються в певному наборі файлів


87

Як я можу сказати Дженкінсу / Хадсону запускати збірку лише для змін у певному проекті в моєму дереві Git?

Відповіді:


65

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

На жаль, плагін Git на даний момент не має функції "включений регіон" (1.15). Однак хтось розмістив на GitHub патчі, які працюють на Дженкінса та Хадсона, що реалізують потрібну вам функцію.

Будувати невелику роботу, але вона працює за рекламою і була надзвичайно корисною, оскільки одне з моїх дерев Git має кілька незалежних проектів.

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

Оновлення: Плагін Git (1.16) тепер має функцію "включений" регіон.


5
1.1.16 - правильний номер версії включеної функції. (немає 1.16)
dan carter

Я не можу змусити це працювати, у мене є сховище з декількома модулями (домен, загальний, api, desktop_app, ...) Я хочу запустити збірку для desktop_app, наприклад, я ставлю "включені регіони" Я спробував кілька комбінацій, таких як ./desktop_app, навіть абсолютний шлях. І я завжди отримував Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. Будь-яка підказка? Детальніше тут: stackoverflow.com/questions/47439042 / ...
FranAguiar

38

В основному, потрібно дві роботи. Один, щоб перевірити, чи змінилися файли, і один, щоб виконати фактичну збірку:

Робота No1

Це слід викликати при змінах у вашому сховищі 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

Робота No2

Налаштуйте це завдання, щоб прийняти параметр GIT_REVISION таким чином, щоб переконатися, що ви будуєте саме ту версію, яку вибрало перше завдання.

Параметризований параметр рядка збірки Параметризована перевірка збірки Git


6
Що робити, якщо після останньої збірки сталося два або більше комітів? Я думаю, ви можете пропустити зміни в src, оскільки ви лише перевіряєте коміт HEAD.
Адам Монсен,

@AdamMonsen Правильно. Але ви можете легко адаптувати вищезазначений сценарій до будь-якої ситуації / умови, для якої ви хочете протестувати .. наприклад, не відрізняючись від HEAD, а від того, що було HEAD останнього запуску сценарію.
перитус

Щось не вистачає на $? || exit 0... test $? -eq 0 || exit 0можливо?
антак

31

Якщо ви використовуєте декларативний синтаксис 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
}

1
@Karl сміливо виправляйте код, якщо він вам підходить. Це була одна проблема, з якою я стикався при застосуванні цього коду (при помилках збірки він не буде повторювати цей коміт, якщо абсолютний останній коміт також не змінить api/папку.) Якщо ви можете це виправити, я хотів би запропонувати зміну !
До побачення StackExchange

2

Якщо логіка вибору файлів не є тривіальною, я запускав би виконання скриптів при кожній зміні, а потім писав скрипт, щоб перевірити, чи справді потрібна збірка, а потім запускав збірку, якщо вона є.


1

Для цього ви можете використовувати загальний плагін Webhook Trigger .

Зі змінною like changed_filesта виразом $.commits[*].['modified','added','removed'][*].

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


Я намагаюся це зробити, але я трохи загубився. як надіслати шлях до зміненого файлу jenkins? Ви могли б пояснити ще трохи, будь ласка? Куди покласти змінну змінені файли?
Суад

Вам потрібно налаштувати веб-хук у службі Git, якою ви користуєтесь. Якщо це GitHub, тут є приклад: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Томаш

Насправді, використовуючи Bitbucket, я зрозумів, що запис Changed_files недоступний у корисному навантаженні push-події в bibucket (посилання: 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;

Ви можете додати перевірку безпосередньо у верхню частину командної оболонки завдання, і вона буде, exit 0якщо не буде виявлено змін ... Отже, ви завжди можете опитати верхній рівень для реєстрації, щоб викликати збірку.


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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.