diff --git a/etc/status.html b/etc/status.html deleted file mode 100644 index b78ff0dc68..0000000000 --- a/etc/status.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - Zuul Status - - - - - - - - - -

Zuul Status

- -
-

-

- -
-
- - - diff --git a/etc/status.js b/etc/status.js deleted file mode 100644 index c9532e4f06..0000000000 --- a/etc/status.js +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2012 OpenStack Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -window.zuul_enable_status_updates = true; - -function format_pipeline(data) { - var html = '

'+ - data['name']+'

'; - if (data['description'] != null) { - html += '

'+data['description']+'

'; - } - - $.each(data['change_queues'], function(change_queue_i, change_queue) { - $.each(change_queue['heads'], function(head_i, head) { - if (data['change_queues'].length > 1 && head_i == 0) { - html += '
Change queue: '; - - var name = change_queue['name']; - html += ''; - if (name.length > 32) { - name = name.substr(0,32) + '...'; - } - html += name + '
' - } - $.each(head, function(change_i, change) { - if (change_i > 0) { - html += '
' - } - html += format_change(change); - }); - }); - }); - - html += '
'; - return html; -} - -function format_change(change) { - var html = '
'; - - html += ''+change['project']+''; - var id = change['id']; - var url = change['url']; - if (id.length == 40) { - id = id.substr(0,7); - } - html += ''; - if (url != null) { - html += ''; - } - html += id; - if (url != null) { - html += ''; - } - html += '
'; - - $.each(change['jobs'], function(i, job) { - result = job['result']; - var result_class = "result"; - if (result == null) { - if (job['url'] != null) { - result = 'in progress'; - } else { - result = 'queued'; - } - } else if (result == 'SUCCESS') { - result_class += " result_success"; - } else if (result == 'FAILURE') { - result_class += " result_failure"; - } else if (result == 'LOST') { - result_class += " result_unstable"; - } else if (result == 'UNSTABLE') { - result_class += " result_unstable"; - } - html += ''; - if (job['url'] != null) { - html += ''; - } - html += job['name']; - if (job['url'] != null) { - html += ''; - } - html += ': '+result+''; - if (job['voting'] == false) { - html += ' (non-voting)'; - } - html += ''; - }); - - html += '
'; - return html; -} - -function update_timeout() { - if (!window.zuul_enable_status_updates) { - setTimeout(update_timeout, 5000); - return; - } - - update(); - - setTimeout(update_timeout, 5000); -} - -function update() { - var html = ''; - - $.getJSON('/status.json', function(data) { - if ('message' in data) { - $("#message-container").attr('class', 'topMessage'); - $("#message").html(data['message']); - } else { - $("#message-container").removeClass('topMessage'); - $("#message").html(''); - } - - html += '
'; - - $.each(data['pipelines'], function(i, pipeline) { - html = html + format_pipeline(pipeline); - }); - - html += '
'; - $("#pipeline-container").html(html); - }); -} - -$(function() { - update_timeout(); - - $(document).on({ - 'show.visibility': function() { - window.zuul_enable_status_updates = true; - update(); - }, - 'hide.visibility': function() { - window.zuul_enable_status_updates = false; - } - }); - -}); diff --git a/etc/status/.gitignore b/etc/status/.gitignore new file mode 100644 index 0000000000..a4b95708a1 --- /dev/null +++ b/etc/status/.gitignore @@ -0,0 +1,3 @@ +public_html/jquery.min.js +public_html/jquery-visibility.min.js +public_html/bootstrap diff --git a/etc/status/README.rst b/etc/status/README.rst new file mode 100644 index 0000000000..5b4a6bb104 --- /dev/null +++ b/etc/status/README.rst @@ -0,0 +1,27 @@ +Zuul Status +==== + +Zuul Status is a web portal for a Zuul server. + +Set up +------------ + +The markup generated by the javascript is fairly generic so it should be easy +to drop into an existing portal. All it needs is +``
``. + +Having said that, the markup is optimised for Twitter Bootstrap, though it in +no way depends on Boostrap and any element using a bootstrap class has a +``zuul-`` prefixed class alongside it. + +The script depends on jQuery (tested with version 1.8 and 1.9). + +The script optimises updates by stopping when the page is not visible. +This is done by listerning to ``show`` and ``hide`` events emitted by the +Page Visibility plugin for jQuery. If you don't want to load this plugin you +can undo undo this optimisation by removing the 9 lines using this on the +bottom of ``app.js`` + +To automatically fetch the latest versions of jQuery, the Page Visibility +plugin and Twitter Boostrap, run the ``fetch-dependencies.sh`` script. +The default ``index.html`` references these. diff --git a/etc/status/fetch-dependencies.sh b/etc/status/fetch-dependencies.sh new file mode 100755 index 0000000000..f224557809 --- /dev/null +++ b/etc/status/fetch-dependencies.sh @@ -0,0 +1,9 @@ +#!/bin/bash +BASE_DIR=$(cd $(dirname $0); pwd) +echo "Destination: $BASE_DIR/public_html" +echo "Fetching jquery.min.js..." +curl --silent http://code.jquery.com/jquery.min.js > $BASE_DIR/public_html/jquery.min.js +echo "Fetching jquery-visibility.min.js..." +curl --silent https://raw.github.com/mathiasbynens/jquery-visibility/master/jquery-visibility.min.js > $BASE_DIR/public_html/jquery-visibility.min.js +echo "Fetching bootstrap..." +curl --silent http://twitter.github.io/bootstrap/assets/bootstrap.zip > bootstrap.zip && unzip -q -o bootstrap.zip -d $BASE_DIR/public_html/ && rm bootstrap.zip diff --git a/etc/status/public_html/app.js b/etc/status/public_html/app.js new file mode 100644 index 0000000000..f7de2cce2d --- /dev/null +++ b/etc/status/public_html/app.js @@ -0,0 +1,241 @@ +// Client script for Zuul status page +// +// Copyright 2012 OpenStack Foundation +// Copyright 2013 Timo Tijhof +// Copyright 2013 Wikimedia Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +(function ($) { + var $container, $msg, $msgWrap, $indicator, $queueInfo, $queueEventsNum, $queueResultsNum, $pipelines, + prevHtml, xhr, zuul, $jq, + demo = location.search.match(/[?&]demo=([^?&]*)/), + source = demo ? + './status-' + (demo[1] || 'basic') + '.json-sample' : + '/zuul/status.json'; + + zuul = { + enabled: true, + + schedule: function () { + if (!zuul.enabled) { + setTimeout(zuul.schedule, 5000); + return; + } + zuul.update().complete(function () { + setTimeout(zuul.schedule, 5000); + }); + }, + + /** @return {jQuery.Promise} */ + update: function () { + // Cancel the previous update if it hasn't completed yet. + if (xhr) { + xhr.abort(); + } + + zuul.emit('update-start'); + + xhr = $.ajax({ + url: source, + dataType: 'json', + cache: false + }) + .done(function (data) { + var html = ''; + data = data || {}; + + if ('message' in data) { + $msg.html(data.message); + $msgWrap.removeClass('zuul-msg-wrap-off'); + } else { + $msg.empty(); + $msgWrap.addClass('zuul-msg-wrap-off'); + } + + $.each(data.pipelines, function (i, pipeline) { + html += zuul.format.pipeline(pipeline); + }); + + // Only re-parse the DOM if we have to + if (html !== prevHtml) { + prevHtml = html; + $pipelines.html(html); + } + + $queueEventsNum.text( + data.trigger_event_queue ? data.trigger_event_queue.length : '0' + ); + $queueResultsNum.text( + data.result_event_queue ? data.result_event_queue.length : '0' + ); + }) + .fail(function (err, jqXHR, errMsg) { + $msg.text(source + ': ' + errMsg).show(); + $msgWrap.removeClass('zuul-msg-wrap-off'); + }) + .complete(function () { + xhr = undefined; + zuul.emit('update-end'); + }); + + return xhr; + }, + + format: { + change: function (change) { + var html = '
'; + return html; + }, + + pipeline: function (pipeline) { + var html = '

' + + pipeline.name + '

'; + if (typeof pipeline.description === 'string') { + html += '

' + pipeline.description + '

'; + } + + $.each(pipeline.change_queues, function (queueNum, changeQueue) { + $.each(changeQueue.heads, function (headNum, changes) { + if (pipeline.change_queues.length > 1 && headNum === 0) { + var name = changeQueue.name; + html += '

Queue: '; + if (name.length > 32) { + name = name.substr(0, 32) + '...'; + } + html += name + '

'; + } + $.each(changes, function (changeNum, change) { + // If there are multiple changes in the same head it means they're connected + if (changeNum > 0) { + html += '
'; + } + html += zuul.format.change(change); + }); + }); + }); + + html += '
'; + return html; + } + }, + + emit: function () { + $jq.trigger.apply($jq, arguments); + return this; + }, + on: function () { + $jq.on.apply($jq, arguments); + return this; + }, + one: function () { + $jq.one.apply($jq, arguments); + return this; + } + }; + + $jq = $(zuul); + + $jq.on('update-start', function () { + $container.addClass('zuul-container-loading'); + $indicator.addClass('zuul-spinner-on'); + }); + + $jq.on('update-end', function () { + $container.removeClass('zuul-container-loading'); + setTimeout(function () { + $indicator.removeClass('zuul-spinner-on'); + }, 550); + }); + + $jq.one('update-end', function () { + // Do this asynchronous so that if the first update adds a message, it will not animate + // while we fade in the content. Instead it simply appears with the rest of the content. + setTimeout(function () { + $container.addClass('zuul-container-ready'); // Fades in the content + }); + }); + + $(function ($) { + $msg = $('
'); + $msgWrap = $msg.wrap('
').parent(); + $indicator = $('updating '); + $queueInfo = $('

Queue lengths: 0 events, 0 results.

'); + $queueEventsNum = $queueInfo.find('span').eq(0); + $queueResultsNum = $queueEventsNum.next(); + $pipelines = $('
'); + + $container = $('#zuul-container').append($msgWrap, $indicator, $queueInfo, $pipelines); + + zuul.schedule(); + + $(document).on({ + 'show.visibility': function () { + zuul.enabled = true; + zuul.update(); + }, + 'hide.visibility': function () { + zuul.enabled = false; + } + }); + }); +}(jQuery)); diff --git a/etc/status/public_html/index.html b/etc/status/public_html/index.html new file mode 100644 index 0000000000..f5efce0d24 --- /dev/null +++ b/etc/status/public_html/index.html @@ -0,0 +1,141 @@ + + + + + Zuul Status + + + + + +
+

Zuul Status

+

Real-time status monitor of Zuul, the pipeline manager between Gerrit and Jenkins.

+ +
+
+ + + + + diff --git a/etc/status/public_html/status-basic.json-sample b/etc/status/public_html/status-basic.json-sample new file mode 100644 index 0000000000..4e12cd6497 --- /dev/null +++ b/etc/status/public_html/status-basic.json-sample @@ -0,0 +1,176 @@ +{ + "message": "Example error message", + "pipelines": [ + { + "name": "test", + "description": "Lint and unit tests", + "change_queues": [ + { + "name": "some-jobs@worker301.ci-example.org", + "heads": [ + [ + { + "id": "10101,1", + "url": "#!/review.example.org/r/10101", + "project": "openstack/infra/zuul", + "jobs": [ + { + "name": "zuul-merge", + "url": "#!/jenkins.example.org/job/zuul-merge/201", + "result": "SUCCESS", + "voting": true + }, + { + "name": "zuul-lint", + "url": "#!/jenkins.example.org/job/zuul-lint/201", + "result": "SUCCESS", + "voting": true + }, + { + "name": "zuul-test", + "url": "#!/jenkins.example.org/job/zuul-test/201", + "result": "SUCCESS", + "voting": true + } + ] + } + ], + [ + { + "id": "10103,1", + "url": "#!/review.example.org/r/10103", + "project": "google/gerrit", + "jobs": [ + { + "name": "gerrit-merge", + "url": "#!/jenkins.example.org/job/gerrit-merge/203", + "result": "SUCCESS", + "voting": false + } + ] + } + ] + ] + }, + { + "name": "other-jobs@worker301.ci-example.org", + "heads": [ + [ + { + "id": "10102,1", + "url": "#!/review.example.org/r/10102", + "project": "google/gerrit", + "jobs": [ + { + "name": "gerrit-merge", + "url": "#!/jenkins.example.org/job/gerrit-merge/202", + "result": "UNSTABLE", + "voting": false + } + ] + } + ], + [ + { + "id": "10104,1", + "url": "#!/review.example.org/r/10104", + "project": "openstack/infra/zuul", + "jobs": [ + { + "name": "zuul-merge", + "url": "#!/jenkins.example.org/job/zuul-merge/204", + "result": "SUCCESS", + "voting": true + }, + { + "name": "zuul-lint", + "url": "#!/jenkins.example.org/job/zuul-lint/204", + "result": "FAILURE", + "voting": true + }, + { + "name": "zuul-test", + "url": "#!/jenkins.example.org/job/zuul-test/204", + "result": null, + "voting": true + } + ] + } + ] + ] + } + ] + }, + { + "name": "gate-and-submit", + "change_queues": [] + }, + { + "name": "postmerge", + "change_queues": [ + { + "name": "some-jobs@worker301.ci-example.org", + "heads": [ + [ + { + "id": "7f1d65cb0f663c907698f915da01c008c7ef4748", + "url": "#!/review.example.org/r/10100", + "project": "openstack/infra/zuul", + "jobs": [ + { + "name": "zuul-lint", + "url": "#!/jenkins.example.org/job/zuul-lint/200", + "result": "SUCCESS", + "voting": true + }, + { + "name": "zuul-test", + "url": "#!/jenkins.example.org/job/zuul-test/200", + "result": "FAILURE", + "voting": true + }, + { + "name": "zuul-regression-python2", + "url": "#!/jenkins.example.org/job/zuul-regression-python2/200", + "result": "SUCCESS", + "voting": true + }, + { + "name": "zuul-regression-python3", + "url": "#!/jenkins.example.org/job/zuul-regression-python3/200", + "result": "FAILURE", + "voting": true + }, + { + "name": "zuul-performance-python2", + "url": null, + "result": null, + "voting": true + }, + { + "name": "zuul-performance-python3", + "url": null, + "result": null, + "voting": true + }, + { + "name": "zuul-docs-publish", + "url": null, + "result": null, + "voting": true + } + ] + } + ] + ] + } + ] + } + ], + "trigger_event_queue": { + "length": 0 + }, + "result_event_queue": { + "length": 0 + } +} diff --git a/etc/status/public_html/status-openstack.json-sample b/etc/status/public_html/status-openstack.json-sample new file mode 100644 index 0000000000..5d16bdd269 --- /dev/null +++ b/etc/status/public_html/status-openstack.json-sample @@ -0,0 +1,310 @@ +{ + "pipelines": [ + { + "name": "check", + "description": "Newly uploaded patchsets enter this pipeline to receive an initial +/-1 Verified vote from Jenkins.", + "change_queues": [ + { + "heads": [], + "name": "stackforge/tripleo-image-elements" + } + ] + }, + { + "description": "Changes that have been approved by core developers are enqueued in order in this pipeline, and .", + "change_queues": [ + { + "heads": [], + "name": "openstack-detackforge/reddwarf-integration" + }, + { + "heads": [], + "name": "stackforge/moniker" + }, + { + "heads": [ + [ + { + "url": "https://review.openstack.org/26292", + "project": "openstack/quantum", + "jobs": [ + { + "url": "https://jenkins.openstack.org/job/gate-quantum-docs/5501/consoleFull", + "voting": true, + "result": "SUCCESS", + "name": "gate-quantum-docs" + }, + { + "url": "https://jenkins.openstack.org/job/gate-quantum-pep8/6254/consoleFull", + "voting": true, + "result": "SUCCESS", + "name": "gate-quantum-pep8" + }, + { + "url": "https://jenkins.openstack.org/job/gate-quantum-python26/5876/", + "voting": true, + "result": null, + "name": "gate-quantum-python26" + }, + { + "url": "https://jenkins.openstack.org/job/gate-quantum-python27/5887/", + "voting": true, + "result": null, + "name": "gate-quantum-python27" + }, + { + "url": "https://jenkins.openstack.org/job/gate-tempest-devstack-vm-quantum/17548/", + "voting": true, + "result": null, + "name": "gate-tempest-devstack-vm-quantum" + } + ], + "id": "26292,1" + } + ] + ], + "name": "openstack-dev/devstack, openstack-infra/devstack-gate, openstack/cinder, openstack/glance, openstack/horizon, openstack/keystone, openstack/nova, openstack/python-cinderclient, openstack/python-glanceclient, openstack/python-keystoneclient, openstack/python-novaclient, openstack/python-quantumclient, openstack/quantum, openstack/swift, openstack/tempest, z/tempest" + }, + { + "heads": [], + "name": "openstack/ceilometer" + }, + { + "heads": [], + "name": "stackforge/puppet-openstack" + }, + { + "heads": [], + "name": "stackforge/puppet-cinder" + }, + { + "heads": [], + "name": "stackforge/marconi" + }, + { + "heads": [], + "name": "openstack-infra/config" + }, + { + "heads": [], + "name": "stackforge/tripleo-image-elements" + }, + { + "heads": [], + "name": "stackforge/kwapi" + }, + { + "heads": [], + "name": "stackforge/python-reddwarfclient" + }, + { + "heads": [], + "name": "stackforge/python-savannaclient" + }, + { + "heads": [], + "name": "stackforge/python-monikerclient" + }, + { + "heads": [], + "name": "stackforge/packstack" + }, + { + "heads": [], + "name": "openstack/oslo.config" + }, + { + "heads": [], + "name": "openstack-infra/jenkins-job-builder" + }, + { + "heads": [], + "name": "stackforge/puppet-horizon" + }, + { + "heads": [], + "name": "openstack/heat-cfntools" + }, + { + "heads": [], + "name": "openstack/oslo-incubator" + }, + { + "heads": [], + "name": "stackforge/os-config-applier" + }, + { + "heads": [], + "name": "openstack/requirements" + }, + { + "heads": [], + "name": "stackforge/puppet-glance" + }, + { + "heads": [], + "name": "openstack-infra/gearman-plugin" + }, + { + "heads": [], + "name": "stackforge/puppet-keystone" + }, + { + "heads": [], + "name": "stackforge/puppet-nova" + }, + { + "heads": [], + "name": "stackforge/climate" + }, + { + "heads": [], + "name": "openstack/python-swiftclient" + }, + { + "heads": [], + "name": "openstack/python-ceilometerclient" + }, + { + "heads": [], + "name": "openstack-infra/git-review" + }, + { + "heads": [], + "name": "stackforge/bufunfa" + }, + { + "heads": [], + "name": "stackforge/puppet-swift" + }, + { + "heads": [], + "name": "openstack-infra/statusbot" + }, + { + "heads": [], + "name": "openstack/openstack-planet" + }, + { + "heads": [], + "name": "openstack/python-openstackclient" + }, + { + "heads": [], + "name": "stackforge/diskimage-builder" + }, + { + "heads": [], + "name": "openstack-infra/gerritlib" + }, + { + "heads": [], + "name": "openstack-infra/zuul" + }, + { + "heads": [], + "name": "stackforge/reddwarf" + }, + { + "heads": [], + "name": "openstack-dev/hacking" + }, + { + "heads": [], + "name": "openstack/python-heatclient" + }, + { + "heads": [], + "name": "stackforge/python-libraclient" + }, + { + "heads": [], + "name": "openstack-infra/reviewday" + }, + { + "heads": [], + "name": "openstack-infra/jeepyb" + }, + { + "heads": [], + "name": "openstack/heat" + }, + { + "heads": [], + "name": "stackforge/libra" + }, + { + "heads": [], + "name": "openstack-infra/gerrit" + }, + { + "heads": [], + "name": "stackforge/healthnmon" + }, + { + "heads": [], + "name": "openstack-infra/gerritbot" + }, + { + "heads": [], + "name": "openstack-dev/pbr" + }, + { + "heads": [], + "name": "stackforge/savanna" + }, + { + "heads": [], + "name": "openstack/openstack-manuals" + } + ], + "name": "gate" + }, + { + "description": "This pipeline runs jobs that operate after each change is merged.", + "change_queues": [ + { + "heads": [], + "name": "openstack-dev/hacking, openstack-dev/openstack-qa, openstack-dev/pbr, openstack-infra/config, openstack-infra/gearman-plugin, openstack-infra/gerrit, openstack-infra/gerritbot, openstack-infra/git-review, openstack-infra/jenkins-job-builder, openstack-infra/nose-html-output, openstack-infra/reviewday, openstack-infra/statusbot, openstack-infra/zuul, openstack/api-site, openstack/ceilometer, openstack/cinder, openstack/compute-api, openstack/glance, openstack/heat, openstack/heat-cfntools, openstack/horizon, openstack/identity-api, openstack/image-api, openstack/keystone, openstack/netconn-api, openstack/nova, openstack/object-api, openstack/openstack-manuals, openstack/oslo-incubator, openstack/oslo.config, openstack/python-ceilometerclient, openstack/python-cinderclient, openstack/python-glanceclient, openstack/python-heatclient, openstack/python-keystoneclient, openstack/python-novaclient, openstack/python-openstackclient, openstack/python-quantumclient, openstack/python-swiftclient, openstack/quantum, openstack/requirements, openstack/swift, openstack/volume-api, stackforge/bufunfa, stackforge/diskimage-builder, stackforge/moniker, stackforge/os-config-applier, stackforge/python-monikerclient, stackforge/python-savannaclient, stackforge/reddwarf, stackforge/savanna, stackforge/tripleo-image-elements" + } + ], + "name": "post" + }, + { + "description": "This pipeline runs jobs on projects in response to pre-release tags.", + "change_queues": [ + { + "heads": [], + "name": "openstack-dev/hacking, openstack-dev/pbr, openstack-infra/gerritbot, openstack-infra/gerritlib, openstack-infra/git-review, openstack-infra/jeepyb, openstack-infra/jenkins-job-builder, openstack-infra/nose-html-output, openstack-infra/reviewday, openstack-infra/statusbot, openstack-infra/zuul, openstack/ceilometer, openstack/cinder, openstack/glance, openstack/heat, openstack/heat-cfntools, openstack/horizon, openstack/keystone, openstack/nova, openstack/oslo.config, openstack/python-ceilometerclient, openstack/python-cinderclient, openstack/python-glanceclient, openstack/python-heatclient, openstack/python-keystoneclient, openstack/python-novaclient, openstack/python-openstackclient, openstack/python-quantumclient, openstack/python-swiftclient, openstack/quantum, openstack/swift, stackforge/moniker, stackforge/python-monikerclient, stackforge/python-reddwarfclient, stackforge/python-savannaclient, stackforge/savanna" + } + ], + "name": "pre-release" + }, + { + "description": "When a commit is tagged as a release, this pipeline runs jobs that publish archives and documentation.", + "change_queues": [ + { + "heads": [], + "name": "openstack-dev/hacking, openstack-dev/openstack-qa, openstack-dev/pbr, openstack-infra/gerritbot, openstack-infra/gerritlib, openstack-infra/git-review, openstack-infra/jeepyb, openstack-infra/jenkins-job-builder, openstack-infra/nose-html-output, openstack-infra/reviewday, openstack-infra/statusbot, openstack-infra/zuul, openstack/ceilometer, openstack/cinder, openstack/glance, openstack/heat, openstack/heat-cfntools, openstack/horizon, openstack/keystone, openstack/nova, openstack/oslo-incubator, openstack/oslo.config, openstack/python-ceilometerclient, openstack/python-cinderclient, openstack/python-glanceclient, openstack/python-heatclient, openstack/python-keystoneclient, openstack/python-novaclient, openstack/python-openstackclient, openstack/python-quantumclient, openstack/python-swiftclient, openstack/quantum, openstack/swift, stackforge/moniker, stackforge/python-monikerclient, stackforge/python-reddwarfclient, stackforge/python-savannaclient, stackforge/savanna" + } + ], + "name": "release" + }, + { + "description": "This pipeline is used for silently testing new jobs.", + "change_queues": [ + { + "heads": [], + "name": "" + } + ], + "name": "silent" + } + ], + "trigger_event_queue": { + "length": 0 + }, + "result_event_queue": { + "length": 0 + } +}