Cách kích hoạt bản dựng chỉ khi các thay đổi xảy ra trên một nhóm tệp cụ thể


87

Làm cách nào để nói Jenkins / Hudson chỉ kích hoạt một bản dựng cho những thay đổi trên một dự án cụ thể trong cây Git của tôi?

Câu trả lời:


65

Plugin Git có một tùy chọn (vùng bị loại trừ) để sử dụng các regex để xác định xem có bỏ qua việc xây dựng hay không dựa trên việc các tệp trong cam kết có khớp với regex của vùng bị loại trừ hay không.

Thật không may, plugin Git cổ phiếu không có tính năng "khu vực được bao gồm" tại thời điểm này (1.15). Tuy nhiên, ai đó đã đăng các bản vá trên GitHub hoạt động trên Jenkins và Hudson triển khai tính năng bạn muốn.

Nó là một công việc nhỏ để xây dựng, nhưng nó hoạt động như quảng cáo và cực kỳ hữu ích vì một trong những cây Git của tôi có nhiều dự án độc lập.

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

Cập nhật: Plugin Git (1.16) hiện có tính năng khu vực 'bao gồm'.


5
1.1.16 là số phiên bản chính xác cho tính năng được bao gồm. (không có 1.16)
dan carter

Tôi không thể làm cho nó hoạt động, tôi có một kho lưu trữ với nhiều mô-đun (miền, chung, api, desktop_app, ...). Tôi muốn kích hoạt một bản dựng cho desktop_app, ví dụ, tôi đặt trên production_app / * "vùng được bao gồm", Tôi đã thử một số kết hợp như ./desktop_app thậm chí là đường dẫn tuyệt đối. Và tôi luôn luôn có Ignored commit c6e2b1dca0d1885: No paths matched included region whitelist. Có manh mối nào không? Thêm chi tiết tại đây: stackoverflow.com/questions/47439042/…
FranAguiar,

38

Về cơ bản, bạn cần hai công việc. Một để kiểm tra xem các tệp đã thay đổi hay chưa và một để thực hiện việc xây dựng thực tế:

Công việc số 1

Điều này sẽ được kích hoạt khi có những thay đổi trong kho lưu trữ Git của bạn. Sau đó, nó kiểm tra xem đường dẫn bạn chỉ định ("src" ở đây) có thay đổi hay không và sau đó sử dụng CLI của Jenkins để kích hoạt công việc thứ hai.

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

Công việc số 2

Định cấu hình công việc này để nhận tham số GIT_REVISION như vậy, để đảm bảo rằng bạn đang tạo chính xác bản sửa đổi mà công việc đầu tiên đã chọn để tạo.

Tham số chuỗi xây dựng được tham số hóa Kiểm tra Git xây dựng được tham số hóa


6
Điều gì sẽ xảy ra nếu hai hoặc nhiều cam kết xảy ra kể từ lần xây dựng cuối cùng? Tôi nghĩ rằng bạn có thể bỏ lỡ các thay đổi trong src vì bạn chỉ kiểm tra cam kết HEAD.
Adam Monsen

@AdamMonsen Đúng. Nhưng bạn có thể dễ dàng điều chỉnh tập lệnh trên cho bất kỳ tình huống / điều kiện nào bạn muốn kiểm tra. Ví dụ: không khác với HEAD nhưng so với HEAD lần trước khi tập lệnh chạy.
peritus

Có điều gì đó bị thiếu ở $? || exit 0... test $? -eq 0 || exit 0có thể?
antak

31

Nếu bạn đang sử dụng một cú pháp khai báo của Jenkinsfile để mô tả đường ống tòa nhà của bạn, bạn có thể sử dụng changeset điều kiện để thực hiện giai đoạn giới hạn chỉ với trường hợp khi các tập tin cụ thể được thay đổi. Đây hiện là một tính năng tiêu chuẩn của Jenkins và không yêu cầu bất kỳ cấu hình / phần mềm bổ sung nào.

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

Bạn có thể kết hợp nhiều điều kiện bằng cách sử dụng anyOfhoặc allOftừ khóa cho hành vi HOẶC hoặc VÀ cho phù hợp:

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

1
Hãy nhớ rằng nó không hoạt động đối với một số trường hợp. Tham khảo issue.jenkins-ci.org/browse/JENKINS-26354 để biết thêm chi tiết.
tamerlaha

7

Mặc dù điều này không ảnh hưởng đến các công việc đơn lẻ, nhưng bạn có thể sử dụng tập lệnh này để bỏ qua các bước nhất định nếu bản cam kết mới nhất không có bất kỳ thay đổi nào:

/*
 * 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 vui lòng sửa mã nếu nó phù hợp với bạn. Đó là một vấn đề tôi gặp phải khi áp dụng mã này (Khi xây dựng thất bại, nó sẽ không thử lại cam kết này, nếu cam kết mới nhất tuyệt đối cũng không thay đổi api/thư mục.) Nếu bạn có thể khắc phục điều này, tôi rất thích một thay đổi được đề xuất !
Goodbye StackExchange vào

2

Nếu logic để chọn tệp không phải là nhỏ, tôi sẽ kích hoạt thực thi tập lệnh trên mỗi thay đổi và sau đó viết một tập lệnh để kiểm tra xem có thực sự cần một bản dựng hay không, sau đó kích hoạt một bản dựng nếu đúng như vậy.


1

Bạn có thể sử dụng Generic Webhook Trigger Plugin cho việc này.

Với một biến like changed_filesvà biểu thức $.commits[*].['modified','added','removed'][*].

Bạn có thể có một văn bản bộ lọc như $changed_filesvà bộ lọc regexp như "folder/subfolder/[^"]+?"nếu folder/subfolderlà thư mục sẽ kích hoạt các bản dựng.


Tôi đang cố gắng làm điều này nhưng tôi hơi mất hứng. làm thế nào để gửi đường dẫn của tệp đã thay đổi đến jenkins? bạn có thể giải thích thêm một chút được không? Đặt biến change_files ở đâu?
Souad

Bạn cần định cấu hình một webhook trong dịch vụ Git mà bạn đang sử dụng. Nếu đó là GitHub, có một ví dụ ở đây: github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/…
Tomas Bjerre

Trên thực tế, khi tôi đang sử dụng Bitbucket, tôi nhận ra rằng mục nhập Changed_files không có sẵn trong tải trọng của sự kiện đẩy trong bibucket (ref: confluence.atlassian.com/bitbucket/… ) nên tôi không chắc mình có thể thực hiện việc này như thế nào. Tôi sẽ dựa vào thông điệp cam kết mà tôi nghĩ. cảm ơn bạn
Souad

1

Tôi đã trả lời câu hỏi này trong một bài đăng khác:

Cách lấy danh sách các tệp đã thay đổi kể từ lần xây dựng cuối cùng trong 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;

Bạn có thể thêm séc trực tiếp vào đầu trình bao thực thi của công việc và nó sẽ làm exit 0như vậy nếu không có thay đổi nào được phát hiện ... Do đó, bạn luôn có thể thăm dò ý kiến ​​cấp cao nhất về đăng ký để kích hoạt bản dựng.


1

Tôi đã viết tập lệnh này để bỏ qua hoặc thực hiện kiểm tra nếu có thay đổi:

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

Vì vậy, bạn có thể làm điều gì đó như:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.