Статьи

Использование удаленного API Jenkins / Hudson для проверки статуса заданий

Во время работы над докладом « Написание плагина Hudson / Jenkins» (для EclipseCon NA 2014) я хотел публиковать в блоге сообщения об идеях, упомянутых в докладе; в этом посте я объясню, как вы можете взаимодействовать с сервером CI без использования веб-интерфейса.

Удаленный API Jenkins / Hudson может быть очень удобным для быстрого получения статуса работы (и даже для создания или запуска вакансий! Но я не буду освещать этот аспект в этой записи в блоге); давайте посмотрим на некоторые примеры.

Посмотрите на CLI для автоматизации задач конфигурации Jenkins.

Он доступен по адресу http: // hudson-or-jenkins / cli: загрузите hudson-cli.jar или jenkins-cli.jar и начните с этой первой команды:

1
$ java -jar jenkins-cli.jar -s http://jenkins.terracotta.eur.ad.sag:8080/ help

Недавно мне пришлось заменить 50 заданий матричным заданием: после того, как я создал задание матрицы, мы решили деактивировать предыдущие 50 заданий (прежде чем удалить их навсегда).

Используя CLI, я мог быстро войти:

1
$ java -jar jenkins-cli.jar -s http://jenkins.xx:8080/ login --username anthony --password password

затем получить список вакансий:

1
$ java -jar jenkins-cli.jar -s http://jenkins.xx:8080/ list-jobs

Я сохранил список из 50 заданий, которые я хотел деактивировать, в текстовом файле, и перебрал этот список:

1
$ while read p; do java -jar jenkins-cli.jar -s http://jenkins.xx:8080/ disable-job $p; done < list_of_jobs.txt

Более эффективно, чем через пользовательский интерфейс, не так ли?

Каждый URL может быть представлен как XML или JSON

Как объясняется в документации Jenkins и документации Hudson , вам просто нужно добавить / api / xml или / api / json или / api / python к любому URL-адресу Jenkins, чтобы увидеть соответствующее представление

Вы можете настроить ответы, добавив несколько аргументов в URL:

глубина

Глубина по умолчанию равна 0, чтобы получить более подробную информацию о ваших работах, сборках и т. Д., Установите глубину 1: http://ci.jruby.org/api/xml?depth=1

Этот аргумент может быть вредным для вашего CI-сервера, если он больше 1 (он намного превышает 1 …), поскольку ответы, как правило, становятся действительно большими.

дерево

Аргумент дерева позволяет выбрать часть ответа http://ci.jruby.org/api/xml?depth=1&tree=jobs[displayName,lastBuild[result]]

xpath и exclude (только XML)

Эти аргументы, вероятно, самые мощные, к сожалению, они доступны только для ответов XML:

Если я хочу отображать только неуспешные задания, я могу просто использовать этот URL-адрес: http://ci.jruby.org/api/xml?depth=1&tree=jobs[displayName,lastBuild[result]]&exclude=hudson/ работа [lastBuild [результат = ‘УСПЕХ’]]

И если я хочу видеть только задания с именем, начинающимся с «jruby», я могу применить функции Xpath к URL: http://ci.jruby.org/api/xml?xpath=hudson/job [начинается с (( имя, ‘JRuby’)] & обертка = mywrap

URL-адреса нескольких открытых экземпляров Jenkins и Hudson

Довольно легко найти некоторые общедоступные экземпляры Jenkins и Hudson, чтобы потренироваться в вашей последней фильтрации URL (Google для «Hudson Dashboard» или «Jenkins Dashboard»), но сложнее найти актуальные и значимые (несколько рабочих мест) экземпляры:

Дженкинс:

Хадсон:

Тем не менее, попробуйте сначала ваш местный экземпляр!

Сценарии удаленного API Jenkins и Hudson

Основной интерес удаленного API Jenkins / Hudson заключается в взаимодействии с ним из вашего собственного программного обеспечения: здесь я соберу несколько примеров на нескольких языках сценариев.

Groovy Script для анализа результатов сборки Jenkins Hudson

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
class BuildParser {
  static void main(String[] args) {
    if (args.length != 1) {
      println("Please run the script with a Jenkins or Hudson url as the only argument\n Example : groovy BuildParser.groovy http://ci.jruby.org");
      return;
    }
    def url = args[0];
    def xmlInputFilteringSuccess = new XmlParser().parse(url + "/api/xml?depth=1&tree=jobs[displayName,lastBuild[result]]&exclude=hudson/job[lastBuild[result=%27SUCCESS%27]]");
    def xmlInputNoFilter = new XmlParser().parse(url + "/api/xml?depth=1&tree=jobs");
  
    def jobs = xmlInputFilteringSuccess.job;
    println(jobs.size() + " jobs out of " + xmlInputNoFilter.job.size() + " are currently failing")
    jobs.each(
        {
          println(
              it.displayName.text() +
              " result is " + it.lastBuild.result.text())
        }
    )
  }
}

Скрипт Python для анализа результатов сборки Jenkins Hudson

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
import ast
import urllib
import sys
 
if len(sys.argv) != 2:
  print "Please run the script with a Jenkins or Hudson url as the only argument\n Example : python BuildParser.py http://ci.jruby.org"
  sys.exit(1)
 
url = str(sys.argv[1])
print url
 
xml_input_no_filter = ast.literal_eval(urllib.urlopen(url + "/api/python?depth=1&tree=jobs[displayName,lastBuild[result]]").read())
 
all_jobs = xml_input_no_filter['jobs']
non_successful_jobs = [row for row in all_jobs if 'SUCCESS' != row['lastBuild']['result']]
 
print(str(len(non_successful_jobs)) + " jobs out of " + str(len(all_jobs)) + " are currently failing")
 
for (i, item) in enumerate(non_successful_jobs):
  print "Job name : " + item['displayName'] + "Result : " + item['lastBuild']['result']

Код JavaScript для анализа результатов сборки Jenkins Hudson

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!-- Strongly inspired by https://gist.github.com/alexschwartz/912787 -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  <title>Build Parser</title>
  
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" type="text/javascript"></script>
  
  <script type="text/javascript">
    $(document).ready(function(){
      var baseUrl;
      $('button').click(function(){
        baseUrl = $("#baseUrl").val();
        $("#jobUrl").html(baseUrl)
  
        var success = function(json) {
          var allJobs = json["jobs"];
          var nonSuccessfulJobs = allJobs.filter(function( job ) {
            return job["lastBuild"] != null && job["lastBuild"]["result"] != "SUCCESS";
          });
  
          $("#downstream").html(nonSuccessfulJobs.length + " out of " + allJobs.length + " are currently failing");
          $.each(nonSuccessfulJobs, function( index, value ) {
            $("#downstream").append("<br />Job name : " + value["displayName"] + " : "+ value["lastBuild"]["result"] );
          });
        };
  
        $.ajax({
          url: baseUrl + "/api/json",
          data: "depth=1&tree=jobs[displayName,lastBuild[result]]&jsonp=callBack",
          jsonpCallback: "callBack",
          dataType: 'jsonp',
  
          success: success
        });
      });
    });
  </script>
</head>
<body marginwidth="50" marginheight="50" topmargin="50" leftmargin="50">
<h3>Input Data</h3>
  
Hudson/Jenkins Base URL:
<input type="text" id="baseUrl" value="https://hudson.eclipse.org/hudson/" size="80" /><br/>
  
<button>update</button><br />
  
<h2>Output</h2>
  
<h3>Failing Jobs</h3>
<div id="downstream">
</div>
  
</body></html>