Yalnızca belirli dosya kümelerinde değişiklik olursa bir derleme nasıl tetiklenir


87

Jenkins / Hudson'a yalnızca Git ağacımdaki belirli bir projedeki değişiklikler için bir derlemeyi tetiklemesini nasıl söylerim?

Yanıtlar:


65

Git eklentisinin, kaydetmedeki dosyaların hariç tutulan bölge normal ifadesiyle eşleşip eşleşmediğine bağlı olarak derlemeyi atlayıp atlamayacağını belirlemek için normal ifadeleri kullanma seçeneği (hariç tutulan bölge) vardır.

Ne yazık ki, stok Git eklentisinin şu anda "dahil edilen bölge" özelliği yok (1.15). Ancak, birisi GitHub'da Jenkins ve Hudson üzerinde çalışan ve istediğiniz özelliği uygulayan yamalar yayınladı.

Yapılması gereken küçük bir iş, ancak reklamı yapıldığı gibi çalışıyor ve Git ağaçlarımdan birinin birden fazla bağımsız projesi olduğu için son derece yararlı oldu.

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

Güncelleme: Git eklentisi (1.16) artık 'dahil edilen' bölge özelliğine sahiptir.


5
1.1.16, dahil edilen özellik için doğru sürüm numarasıdır. (1.16 yok)
dan carter

Çalışmasını sağlayamıyorum, birden fazla modül içeren bir depom var (etki alanı, ortak, api, desktop_app, ...) Örneğin desktop_app için bir derlemeyi tetiklemek istiyorum, "dahil edilen bölgeler" production_app / * koyuyorum, ./Desktop_app gibi birkaç kombinasyon denedim, hatta mutlak yol. Ve her zaman anladım Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. Bir ipucu? Daha fazla ayrıntı burada: stackoverflow.com/questions/47439042/…
FranAguiar

38

Temel olarak, iki işe ihtiyacınız var. Biri dosyaların değişip değişmediğini kontrol etmek için ve biri asıl derlemeyi yapmak için:

İş 1

Bu, Git deponuzdaki değişikliklerde tetiklenmelidir. Daha sonra belirttiğiniz yolda ("src" burada) değişiklik olup olmadığını test eder ve ardından ikinci bir işi tetiklemek için Jenkins'in CLI'sini kullanır .

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

İlk işin oluşturmayı seçtiği revizyonu tam olarak oluşturduğunuzdan emin olmak için bu işi GIT_REVISION parametresini alacak şekilde yapılandırın.

Parametreli derleme dizesi parametresi Parametreli derleme Git kontrolü


7
Ya son derlemeden bu yana iki veya daha fazla kaydetme gerçekleşirse? Yalnızca HEAD kaydetmeyi incelediğiniz için src'deki değişiklikleri gözden kaçırabileceğinizi düşünüyorum.
Adam Monsen

@AdamMonsen Sağ. Ancak yukarıdaki betiği, test etmek istediğiniz durum / koşula kolayca uyarlayabilirsiniz. Örneğin, HEAD ile değil, komut dosyası en son çalıştırıldığında HEAD olanla farklılık gösterebilir.
peritus

Eksik bir şey var $? || exit 0... test $? -eq 0 || exit 0belki?
antak

34

Bina ardışık düzeninizi tanımlamak için açıklayıcı bir Jenkinsfile sözdizimi kullanıyorsanız , şunu kullanabilirsiniz: değişiklik kümesi belirli dosyalar değiştiğinde sadece davaya sınır sahne yürütmeye koşulu. Bu artık Jenkins'in standart bir özelliğidirve herhangi bir ek yapılandırma / yazılım gerektirmez.

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

VEYA veya VE davranışı için anyOfveya allOfanahtar kelimelerini kullanarak birden çok koşulu buna göre birleştirebilirsiniz:

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

1
Bazı durumlarda işe yaramadığını unutmayın. Daha fazla ayrıntı için issue.jenkins-ci.org/browse/JENKINS-26354 adresine bakın .
tamerlaha

7

Bu, tek işleri etkilemese de, en son kaydetme herhangi bir değişiklik içermiyorsa, bu komut dosyasını belirli adımları yok saymak için kullanabilirsiniz:

/*
 * 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, sizin için çalışıyorsa kodu düzeltmekten çekinmeyin. Bu kodu uygularken yaşadığım tek sorun buydu (Derleme hatalarında, mutlak en son işlem api/klasörü de değiştirmediyse, bu işlemi yeniden denemezdi .) Bunu düzeltebilirseniz, önerilen bir değişikliği çok isterim. !
Hoşçakal StackExchange

2

Dosyaları seçme mantığı önemsiz değilse, her değişiklikte komut dosyası yürütmeyi tetiklerim ve ardından gerçekten bir yapı gerekip gerekmediğini kontrol etmek için bir komut dosyası yazar ve ardından bir yapıyı tetiklerim.


1

Sen kullanabilirsiniz Jenerik Webhook Tetik Plugin .

Değişken gibi changed_filesve ifade ile$.commits[*].['modified','added','removed'][*] .

Bir gibi filtre metin olabilir $changed_filesgibi ve filtre Regexp'i "folder/subfolder/[^"]+?"eğer folder/subfolderkurar tetiklemesi gereken klasördür.


Bunu yapmaya çalışıyorum ama biraz kayboldum. değiştirilen dosyanın yolu jenkins'e nasıl gönderilir? biraz daha açıklar mısın lütfen? Change_files değişkeni nereye koyulur?
Souad

Kullandığınız Git hizmetinde bir web kancası yapılandırmanız gerekir. GitHub ise burada bir örnek var: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Tomas Bjerre

Aslında Bitbucket kullandığım için, Changed_files girişinin bibucket'taki push olayının yükünde bulunmadığını fark ettim (ref: confluence.atlassian.com/bitbucket/… ), bu yüzden bunu nasıl yapabilirim bilmiyorum. Sanırım taahhüt mesajına güveneceğim. teşekkür ederim
Souad

1

Bu soruyu başka bir gönderide cevapladım:

Jenkins / Hudson'daki son derlemeden bu yana değişen dosyaların listesi nasıl alınır

#!/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;

Denetimi doğrudan işin yürütme kabuğunun üstüne ekleyebilirsiniz ve exit 0herhangi bir değişiklik tespit edilmezse, bu nedenle, bir yapıyı tetiklemek için teslimatlar için her zaman en üst seviyeyi sorgulayabilirsiniz.


1

Değişiklikler varsa testleri atlamak veya yürütmek için bu komut dosyasını yazdım:

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

Böylece şöyle bir şey yapabilirsiniz:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.