2012-01-23 27 views
14

Hãy tưởng tượng công việc Jenkins A mất 1 phút để chạy và công việc B mất 5 phút.Công việc được tham số hóa Jenkins chỉ xếp hàng một bản dựng

Nếu chúng tôi định cấu hình lệnh A để kích hoạt lệnh B, trong khi công việc B đang chạy lệnh A có thể chạy 5 lần trước khi B hoàn tất. Tuy nhiên, Jenkins không thêm 5 bản dựng vào hàng đợi của công việc B, điều này thật tuyệt vời vì công việc A nhanh chóng sẽ tạo ra một bản backlog không ngừng phát triển cho công việc chậm chạp B.

Tuy nhiên, bây giờ chúng tôi muốn có việc làm Trình kích hoạt B làm công việc được tham số hóa, sử dụng parameterized trigger plugin. Các công việc tham số làm xếp hàng tồn đọng, điều đó có nghĩa là công việc A đang tạo ra một đống lớn các công trình xây dựng cho công việc B, mà không thể theo kịp.

Có ý nghĩa khi thêm công cụ tạo tham số mới vào hàng đợi mỗi khi được kích hoạt, vì các tham số có thể khác nhau. Jenkins không nên luôn luôn giả định rằng một phiên bản tham số mới biểu hiện những hàng đợi trước đó không cần thiết.

Tuy nhiên, trong trường hợp của chúng tôi, chúng tôi thực sự muốn điều này. Job A xây dựng và đóng gói ứng dụng của chúng ta, sau đó Job B triển khai nó vào một môi trường giống như sản xuất và chạy một bộ kiểm thử tích hợp nặng hơn. Chúng tôi cũng có một bản dựng C mà triển khai đến một môi trường khác và thậm chí còn thử nghiệm nhiều hơn, vì vậy đây là một mô hình leo thang đối với chúng tôi.

Chúng tôi muốn xếp hàng cho công việc được tham số hóa B của chúng tôi để chỉ giữ bản dựng cuối cùng được thêm vào nó; mỗi công trình mới sẽ thay thế bất kỳ công việc nào hiện có trong hàng đợi.

Có cách nào tốt đẹp để đạt được điều này không?

Trả lời

2

Dưới đây là một cách giải quyết:

  • Tạo một A2B công việc giữa công việc A và B
  • Thêm một bước xây dựng trong A2B công việc mà sẽ xác định xem B đang chạy. Để đạt được điều đó, kiểm tra:
  • Cuối cùng, việc kích hoạt B từ A2B chỉ nếu không có B builds xếp hàng đợi hoặc chạy (mang theo các thông số thông qua)
3

Bạn có thể loại bỏ Plugin kích hoạt tham số và thay vào đó, hãy sử dụng kích hoạt truyền thống. Như bạn đã nói, điều này sẽ ngăn chặn hàng đợi công việc B từ chồng chất lên.

Cách chuyển các tham số từ A sang B? Thực hiện công việc A để đưa ra các tham số trong đầu ra của giao diện điều khiển. Trong công việc B, để có được các tham số xây dựng này, hãy kiểm tra đầu ra của giao diện điều khiển của bản dựng A mới nhất (với một kịch bản Python, có lẽ?).

+0

Bạn có thể lưu tham số vào tệp thuộc tính và sử dụng plugin envInject để đọc thuộc tính. –

+1

Các thông số cũng có thể được truyền trong bộ kích hoạt truyền thống. –

1

Trong trường hợp bạn đang sử dụng Git, điều này hiện được hỗ trợ bởi "Kết hợp băm xếp hàng git" dưới tùy chọn Kích hoạt/Tham số/Vượt qua. Phiên bản plugin Git đầu tiên thực sự hoạt động với tính năng này là 1.1.27 (xem Jenkins-15160)

5

Thêm bước tạo trước "Hệ thống Groovy Script" vào lệnh B để kiểm tra công việc xếp hàng (mới hơn) có cùng tên , và gửi ra nếu được tìm thấy:

def name = build.properties.environment.JOB_NAME 
def queue = jenkins.model.Jenkins.getInstance().getQueue().getItems() 
if (queue.any{ it.task.getName() == name }) { 
    println "Newer " + name + " job(s) in queue, aborting" 
    build.doStop() 
} else { 
    println "No newer " + name + " job(s) in queue, proceeding" 
} 
+0

Cảm ơn! Đây là giải pháp tốt nhất mà tôi đã tìm thấy cho đến nay. Làm việc như một say mê và tôi cũng có thể theo dõi các bản dựng 'đã ngừng'. – Marcelo

+0

Một vấn đề với phương pháp này là bản xây dựng tiếp theo không thể hiển thị các thay đổi của VCS: 'WARN: Dữ liệu sửa đổi cho bản dựng trước đó không khả dụng; không thể xác định nhật ký thay đổi' – mrtnlrsn

+0

@Marcelo Bạn thực hiện điều này ở đâu trong công việc tự do (không có tiền xây dựng trước) – lvthillo

0

Giải pháp của Ron làm việc cho tôi.Nếu bạn không thích phải bó hủy xây dựng trong xây dựng lịch sử bạn có thể thêm các hệ thống kịch bản hấp dẫn sau đây để công việc A trước khi bạn kích hoạt công việc B:

import hudson.model.* 
def q = jenkins.model.Jenkins.getInstance().getQueue() 
def items = q.getItems() 
for (i=0;i<items.length;i++){ 
    if(items[i].task.getName() == "JobB"){ 
    items[i].doCancelQueue() 
    } 
} 
0

Dưới đây là một lựa chọn linh hoạt hơn nếu bạn chỉ quan tâm đến một vài thông số phù hợp. Điều này đặc biệt hữu ích khi công việc được kích hoạt bên ngoài (tức là từ GitHub hoặc Stash) và một số thông số không cần một bản dựng riêng biệt.

Nếu thông số đã chọn khớp với cả giá trị và sự tồn tại trong cả bản dựng hiện tại và bản dựng hàng đợi, bản dựng hiện tại sẽ bị hủy và mô tả sẽ hiển thị rằng bản dựng trong tương lai chứa cùng các thông số đã chọn (cùng với những gì chúng).

Nó có thể được sửa đổi để hủy bỏ tất cả các công việc xếp hàng khác ngoại trừ công việc cuối cùng nếu bạn không muốn có lịch sử xây dựng hiển thị các công việc bị hủy bỏ.

checkedParams = [ 
    "PARAM1", 
    "PARAM2", 
    "PARAM3", 
    "PARAM4", 
] 

def buildParams = null 
def name = build.project.name 
def queuedItems = jenkins.model.Jenkins.getInstance().getQueue().getItems() 

yieldToQueuedItem = false 
for(hudson.model.Queue.Item item : queuedItems.findAll { it.task.getName() == name }) { 
    if(buildParams == null) {  
     buildParams = [:] 
     paramAction = build.getAction(hudson.model.ParametersAction.class) 
     if(paramAction) { 
      buildParams = paramAction.getParameters().collectEntries { 
       [(it.getName()) : it.getValue()] 
      } 
     } 
    } 
    itemParams = [:] 
    paramAction = item.getAction(hudson.model.ParametersAction.class) 
    if(paramAction) { 
     itemParams = paramAction.getParameters().collectEntries { 
      [(it.getName()) : it.getValue()] 
     } 
    } 

    equalParams = true 
    for(String compareParam : checkedParams) { 
     itemHasKey = itemParams.containsKey(compareParam) 
     buildHasKey = buildParams.containsKey(compareParam) 
     if(itemHasKey != buildHasKey || (itemHasKey && itemParams[compareParam] != buildParams[compareParam])) { 
      equalParams = false 
      break; 
     } 
    } 
    if(equalParams) { 
     yieldToQueuedItem = true 
     break 
    } 
} 

if (yieldToQueuedItem) { 
    out.println "Newer " + name + " job(s) in queue with matching checked parameters, aborting" 
    build.description = "Yielded to future build with:" 
    checkedParams.each { 
     build.description += "<br>" + it + " = " + build.buildVariables[it] 
    } 

    build.doStop() 
    return 
} else { 
    out.println "No newer " + name + " job(s) in queue with matching checked parameters, proceeding" 
} 
0

Sau đây là dựa trên giải pháp của Ron, nhưng với một số sửa lỗi để làm việc trên Jenkins của tôi 2 bao gồm loại bỏ java.io.NotSerializableException ngoại lệ và xử lý các định dạng của getName() là một số thời điểm khác nhau từ đó của JOB_NAME

// Exception to distinguish abort due to newer jobs in queue 
class NewerJobsException extends hudson.AbortException { 
    public NewerJobsException(String message) { super(message); } 
} 

// Find jenkins job name from url name (which is the most consistently named 
// field in the task object) 
// Known forms: 
// job/NAME/ 
// job/NAME/98/ 
@NonCPS 
def name_from_url(url) 
{ 
    url = url.substring(url.indexOf("/") + 1); 
    url = url.substring(0, url.indexOf("/")); 
    return url 
} 

// Depending on installed plugins multiple jobs may be queued. If that is the 
// case skip this one. 
// http://stackoverflow.com/questions/26845003/how-to-execute-only-the-most-recent-queued-job-in-jenkins 
// http://stackoverflow.com/questions/8974170/jenkins-parameterized-job-that-only-queues-one-build 
@NonCPS 
def check_queue() 
{ 
    def name = env.JOB_NAME 
    def queue = jenkins.model.Jenkins.getInstance().getQueue().getItems() 
    if (queue.any{ name_from_url(it.task.getUrl()) == name }) { 
     print "Newer ${name} job(s) in queue, aborting" 
     throw new NewerJobsException("Newer ${name} job(s) in queue, aborting") 
    } else { 
     print "No newer ${name} job(s) in queue, proceeding" 
    } 
} 
Các vấn đề liên quan