Summary JSON file
Add support for writing the build summary to a JSON file. This is more machine-friendly than the current approach of writing to standard output at the end of the build. The file is configured via [DEFAULT] summary_json_file. Change-Id: I9868af5d00977750d0673fc48f8863a99f878dc8
This commit is contained in:
parent
bc2d3e4ef4
commit
a5351473e0
|
@ -199,6 +199,10 @@ _CLI_OPTS = [
|
||||||
cfg.StrOpt('format', short='f', default='json',
|
cfg.StrOpt('format', short='f', default='json',
|
||||||
choices=['json', 'none'],
|
choices=['json', 'none'],
|
||||||
help='Format to write the final results in.'),
|
help='Format to write the final results in.'),
|
||||||
|
cfg.StrOpt('summary-json-file',
|
||||||
|
help='Name of a file to write the build summary to when format '
|
||||||
|
'is json. If unset, the summary will be written to '
|
||||||
|
'standard output'),
|
||||||
cfg.StrOpt('tarballs-base', default=TARBALLS_BASE,
|
cfg.StrOpt('tarballs-base', default=TARBALLS_BASE,
|
||||||
help='Base url to OpenStack tarballs'),
|
help='Base url to OpenStack tarballs'),
|
||||||
cfg.IntOpt('threads', short='T', default=8, min=1,
|
cfg.IntOpt('threads', short='T', default=8, min=1,
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import queue
|
import queue
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -195,8 +194,6 @@ def run_build():
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if conf.summary:
|
if conf.summary:
|
||||||
results = kolla.summary()
|
kolla.summary()
|
||||||
if conf.format == 'json':
|
|
||||||
print(json.dumps(results))
|
|
||||||
kolla.cleanup()
|
kolla.cleanup()
|
||||||
return kolla.get_image_statuses()
|
return kolla.get_image_statuses()
|
||||||
|
|
|
@ -564,6 +564,26 @@ class KollaWorker(object):
|
||||||
'name': name,
|
'name': name,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if self.conf.format == 'json':
|
||||||
|
|
||||||
|
def json_summary(f, **kwargs):
|
||||||
|
json.dump(results, f, **kwargs)
|
||||||
|
|
||||||
|
if self.conf.summary_json_file:
|
||||||
|
try:
|
||||||
|
with open(self.conf.summary_json_file, "w") as f:
|
||||||
|
json_summary(f, indent=4)
|
||||||
|
except OSError as e:
|
||||||
|
LOG.error(f'Failed to write JSON build summary to '
|
||||||
|
'{self.conf.summary_json_file}')
|
||||||
|
LOG.error(f'Exception caught: {e}')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# NOTE(mgoddard): Keep single line output for
|
||||||
|
# backwards-compatibility.
|
||||||
|
json_summary(sys.stdout)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def get_image_statuses(self):
|
def get_image_statuses(self):
|
||||||
|
|
|
@ -727,6 +727,53 @@ class KollaWorkerTest(base.TestCase):
|
||||||
self.assertEqual('error', results['failed'][0]['status']) # bad
|
self.assertEqual('error', results['failed'][0]['status']) # bad
|
||||||
self.assertEqual('error', results['failed'][1]['status']) # bad2
|
self.assertEqual('error', results['failed'][1]['status']) # bad2
|
||||||
|
|
||||||
|
@mock.patch('json.dump')
|
||||||
|
def test_summary_json_format(self, dump_mock):
|
||||||
|
self.conf.set_override('format', 'json')
|
||||||
|
kolla = build.KollaWorker(self.conf)
|
||||||
|
kolla.images = self.images
|
||||||
|
kolla.image_statuses_good['good'] = build.Status.BUILT
|
||||||
|
kolla.image_statuses_bad['bad'] = build.Status.ERROR
|
||||||
|
kolla.image_statuses_allowed_to_fail['bad2'] = build.Status.ERROR
|
||||||
|
kolla.image_statuses_unmatched['unmatched'] = build.Status.UNMATCHED
|
||||||
|
results = kolla.summary()
|
||||||
|
dump_mock.assert_called_once_with(results, sys.stdout)
|
||||||
|
|
||||||
|
@mock.patch('json.dump')
|
||||||
|
def test_summary_json_format_file(self, dump_mock):
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
file_path = os.path.join(tmpdir, 'summary.json')
|
||||||
|
try:
|
||||||
|
self.conf.set_override('format', 'json')
|
||||||
|
self.conf.set_override('summary_json_file', file_path)
|
||||||
|
kolla = build.KollaWorker(self.conf)
|
||||||
|
kolla.images = self.images
|
||||||
|
kolla.image_statuses_good['good'] = build.Status.BUILT
|
||||||
|
kolla.image_statuses_bad['bad'] = build.Status.ERROR
|
||||||
|
kolla.image_statuses_allowed_to_fail['bad2'] = build.Status.ERROR
|
||||||
|
kolla.image_statuses_unmatched['unmatched'] = (
|
||||||
|
build.Status.UNMATCHED)
|
||||||
|
results = kolla.summary()
|
||||||
|
dump_mock.assert_called_once_with(results, mock.ANY, indent=4)
|
||||||
|
self.assertEqual(dump_mock.call_args[0][1].name, file_path)
|
||||||
|
finally:
|
||||||
|
os.remove(file_path)
|
||||||
|
os.rmdir(tmpdir)
|
||||||
|
|
||||||
|
@mock.patch('builtins.open')
|
||||||
|
def test_summary_json_format_file_error(self, open_mock):
|
||||||
|
open_mock.side_effect = OSError
|
||||||
|
self.conf.set_override('format', 'json')
|
||||||
|
self.conf.set_override('summary_json_file', 'fake-file')
|
||||||
|
kolla = build.KollaWorker(self.conf)
|
||||||
|
kolla.images = self.images
|
||||||
|
kolla.image_statuses_good['good'] = build.Status.BUILT
|
||||||
|
kolla.image_statuses_bad['bad'] = build.Status.ERROR
|
||||||
|
kolla.image_statuses_allowed_to_fail['bad2'] = build.Status.ERROR
|
||||||
|
kolla.image_statuses_unmatched['unmatched'] = (
|
||||||
|
build.Status.UNMATCHED)
|
||||||
|
self.assertRaises(SystemExit, kolla.summary)
|
||||||
|
|
||||||
@mock.patch('shutil.copytree')
|
@mock.patch('shutil.copytree')
|
||||||
def test_work_dir(self, copytree_mock):
|
def test_work_dir(self, copytree_mock):
|
||||||
self.conf.set_override('work_dir', 'tmp/foo')
|
self.conf.set_override('work_dir', 'tmp/foo')
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds support for writing the build summary to a JSON file specified via the
|
||||||
|
``[DEFAULT] summary_json_file`` option.
|
Loading…
Reference in New Issue