Cara memicu build hanya jika terjadi perubahan pada kumpulan file tertentu

87

Bagaimana cara memberi tahu Jenkins / Hudson untuk memicu build hanya untuk perubahan pada proyek tertentu di pohon Git saya?

xavier.seignard
sumber

Jawaban:

65

Plugin Git memiliki opsi (wilayah yang dikecualikan) untuk menggunakan regex guna menentukan apakah akan melewati pembuatan berdasarkan apakah file dalam komit cocok dengan regex wilayah yang dikecualikan.

Sayangnya, plugin Git stok saat ini tidak memiliki fitur "wilayah yang disertakan" (1.15). Namun, seseorang memposting tambalan di GitHub yang berfungsi di Jenkins dan Hudson yang menerapkan fitur yang Anda inginkan.

Ini adalah pekerjaan kecil untuk dibangun, tetapi berfungsi seperti yang diiklankan dan sangat berguna karena salah satu pohon Git saya memiliki beberapa proyek independen.

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

Pembaruan: Plugin Git (1.16) sekarang memiliki fitur wilayah 'disertakan'.

Aaron Kushner
sumber
5
1.1.16 adalah nomor versi yang benar untuk fitur yang disertakan. (tidak ada 1,16)
dan carter
Saya tidak bisa membuatnya berfungsi, saya memiliki repositori dengan beberapa modul (domain, common, api, desktop_app, ...) Saya ingin memicu build untuk desktop_app misalnya, saya meletakkan di "wilayah yang disertakan" production_app / *, Saya mencoba beberapa kombinasi seperti ./desktop_app bahkan jalur absolut. Dan aku selalu mendapatkannya Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. Ada petunjuk? Detail lebih lanjut di sini: stackoverflow.com/questions/47439042/…
FranAguiar
38

Pada dasarnya, Anda membutuhkan dua pekerjaan. Satu untuk memeriksa apakah file berubah dan satu untuk melakukan build yang sebenarnya:

Pekerjaan # 1

Ini harus dipicu pada perubahan di repositori Git Anda. Ini kemudian menguji apakah jalur yang Anda tentukan ("src" di sini) memiliki perubahan dan kemudian menggunakan CLI Jenkins untuk memicu pekerjaan kedua.

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

Pekerjaan # 2

Konfigurasi pekerjaan ini untuk mengambil parameter GIT_REVISION seperti itu, untuk memastikan Anda membuat revisi persis seperti yang dipilih oleh pekerjaan pertama untuk dibuat.

Parameter string build yang diparameterisasi Pembayaran Git build parameter

peritus
sumber
7
Bagaimana jika dua atau lebih komit terjadi sejak build terakhir? Saya pikir Anda mungkin melewatkan perubahan dalam src karena Anda hanya memeriksa komit HEAD.
Adam Monsen
@Adamen Benar. Tetapi Anda dapat dengan mudah menyesuaikan skrip di atas ke situasi / kondisi apa pun yang ingin Anda uji .. misalnya tidak berbeda dengan HEAD tetapi terhadap HEAD terakhir kali skrip dijalankan.
peritus
Ada sesuatu yang hilang di $? || exit 0... test $? -eq 0 || exit 0mungkin?
antak
34

Jika Anda menggunakan sintaks deklaratif Jenkinsfile untuk mendeskripsikan pipeline bangunan Anda, Anda bisa menggunakan kondisi changeset untuk membatasi eksekusi tahapan hanya pada kasus ketika file tertentu diubah. Ini sekarang menjadi fitur standar Jenkins dan tidak memerlukan konfigurasi / perangkat lunak tambahan.

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

Anda dapat menggabungkan beberapa ketentuan menggunakan anyOfatau allOfkata kunci untuk ATAU atau DAN perilaku yang sesuai:

when {
    anyOf {
        changeset "nginx/**"
        changeset "fluent-bit/**"
    }
}
steps {
    sh "make build-nginx"
    sh "make start-nginx"
}
Anton Golubev
sumber
1
Ingatlah bahwa ini tidak berfungsi untuk beberapa kasus. Lihat issues.jenkins-ci.org/browse/JENKINS-26354 untuk lebih jelasnya.
tamerlaha
7

Meskipun ini tidak memengaruhi pekerjaan tunggal, Anda dapat menggunakan skrip ini untuk mengabaikan langkah-langkah tertentu jika komit terbaru tidak berisi perubahan apa pun:

/*
 * 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
}
Selamat tinggal StackExchange
sumber
1
@Karl merasa bebas untuk memperbaiki kode jika berhasil untuk Anda. Itulah satu-satunya masalah yang saya hadapi saat menerapkan kode ini (Pada kegagalan build, itu tidak akan mencoba lagi komit ini, jika komit terbaru absolut tidak juga mengubah api/foldernya.) Jika Anda dapat memperbaiki ini, saya akan menyukai perubahan yang disarankan !
Selamat tinggal StackExchange
2

Jika logika untuk memilih file tidak sepele, saya akan memicu eksekusi skrip pada setiap perubahan dan kemudian menulis skrip untuk memeriksa apakah memang diperlukan build, lalu memicu build jika diperlukan.

Uri Cohen
sumber
1

Anda dapat menggunakan Plugin Pemicu Webhook Generik untuk ini.

Dengan variabel suka changed_filesdan ekspresi$.commits[*].['modified','added','removed'][*] .

Anda dapat memiliki teks filter seperti $changed_filesdan filter regexp seperti "folder/subfolder/[^"]+?"jika folder/subfolderfolder yang harus memicu build.

Tomas Bjerre
sumber
Saya mencoba melakukan ini tetapi saya sedikit tersesat. bagaimana cara mengirim jalur file yang diubah ke jenkins? bisakah Anda menjelaskan sedikit lebih banyak? Di mana menempatkan variabel change_files?
Souad
Anda perlu mengkonfigurasi webhook di layanan Git yang Anda gunakan. Jika ini adalah GitHub, ada contohnya di sini: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Tomas Bjerre
Faktanya ketika saya menggunakan Bitbucket, saya menyadari bahwa entri Changed_files tidak tersedia dalam payload event push di bibucket (ref: confluence.atlassian.com/bitbucket/… ) jadi saya tidak yakin bagaimana saya bisa melakukan ini. Saya akan mengandalkan pesan komit yang saya pikir. terima kasih
Souad
1

Saya menjawab pertanyaan ini di posting lain:

Cara mendapatkan daftar file yang diubah sejak pembuatan terakhir di 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;

Anda dapat menambahkan pemeriksaan langsung ke bagian atas shell exec pekerjaan, dan ini akan terjadi exit 0jika tidak ada perubahan yang terdeteksi ... Oleh karena itu, Anda selalu dapat melakukan polling di tingkat teratas untuk check-in guna memicu build.

hhony
sumber
1

Saya menulis skrip ini untuk melewati atau menjalankan tes jika ada perubahan:

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

Jadi Anda bisa melakukan sesuatu seperti:

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

pengguna12513208
sumber