Skip to content

Commit 0066652

Browse files
author
Glenn Snyder
committed
fixing issue 79 regarding generating notices report in JSON format
1 parent 84a2569 commit 0066652

File tree

2 files changed

+53
-24
lines changed

2 files changed

+53
-24
lines changed

blackduck/HubRestApi.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,12 +540,12 @@ def create_version_reports(self, version, report_list, format="CSV"):
540540
version_reports_url = self.get_link(version, 'versionReport')
541541
return self.execute_post(version_reports_url, post_data)
542542

543-
valid_notices_formats = ["TEXT", "HTML"]
543+
valid_notices_formats = ["TEXT", "JSON"]
544544
def create_version_notices_report(self, version, format="TEXT"):
545545
assert format in HubInstance.valid_notices_formats, "Format must be one of {}".format(HubInstance.valid_notices_formats)
546546

547547
post_data = {
548-
'categories': HubInstance.valid_categories,
548+
'categories': ["COPYRIGHT_TEXT"],
549549
'versionId': version['_meta']['href'].split("/")[-1],
550550
'reportType': 'VERSION_LICENSE',
551551
'reportFormat': format
@@ -554,9 +554,28 @@ def create_version_notices_report(self, version, format="TEXT"):
554554
return self.execute_post(notices_report_url, post_data)
555555

556556
def download_report(self, report_id):
557+
# TODO: Fix me, looks like the reports should be downloaded from different paths than the one here, and depending on the type and format desired the path can change
557558
url = self.get_urlbase() + "/api/reports/{}".format(report_id)
558559
return self.execute_get(url, {'Content-Type': 'application/zip', 'Accept':'application/zip'})
559560

561+
def download_notification_report(self, report_location_url):
562+
'''Download the notices report using the report URL. Inspect the report object to determine
563+
the format and use the appropriate media header'''
564+
custom_headers = {'Accept': 'application/vnd.blackducksoftware.report-4+json'}
565+
response = self.execute_get(report_location_url, custom_headers=custom_headers)
566+
report_obj = response.json()
567+
568+
if report_obj['reportFormat'] == 'TEXT':
569+
download_url = self.get_link(report_obj, "download") + ".json"
570+
logging.debug("downloading report from {}".format(download_url))
571+
response = self.execute_get(download_url, {'Accept': 'application/zip'})
572+
else:
573+
# JSON
574+
contents_url = self.get_link(report_obj, "content")
575+
logging.debug("retrieving report contents from {}".format(contents_url))
576+
response = self.execute_get(contents_url, {'Accept': 'application/json'})
577+
return response, report_obj['reportFormat']
578+
560579
##
561580
#
562581
# (Global) Vulnerability reports

examples/generate_notices_report_for_project_version.py

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,51 @@
1010

1111
import argparse
1212
import json
13+
import logging
14+
import sys
1315
import time
1416
import zipfile
1517

1618
parser = argparse.ArgumentParser("A program to generate the notices file for a given project-version")
1719
parser.add_argument("project_name")
1820
parser.add_argument("version_name")
19-
parser.add_argument("--zip_file_name", default="notices_report.zip")
20-
parser.add_argument("--reports",
21-
default="version,scans,components,vulnerabilities,source",
22-
help="Comma separated list (no spaces) of the reports to generate - version, scans, components, vulnerabilities, source, and cryptography reports (default: all, except cryptography")
23-
parser.add_argument('--format', default='TEXT', choices=["HTML", "TEXT"], help="Report format - choices are TEXT or HTML")
21+
parser.add_argument('-f', "--file_name_base", default="notices_report", help="Base file name to write the report data into. If the report format is TEXT a .zip file will be created, otherwise a .json file")
22+
parser.add_argument('-r', '--report_format', default='TEXT', choices=["JSON", "TEXT"], help="Report format - choices are TEXT or HTML")
2423

2524
args = parser.parse_args()
2625

2726
hub = HubInstance()
2827

29-
# TODO: Promote this to the API?
28+
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', stream=sys.stderr, level=logging.DEBUG)
29+
3030
class FailedReportDownload(Exception):
3131
pass
3232

33-
def download_report(location, filename, retries=4):
33+
def download_report(location, file_name_base, retries=10):
3434
report_id = location.split("/")[-1]
3535

3636
if retries:
37-
print("Retrieving generated report from {}".format(location))
38-
response = hub.download_report(report_id)
37+
logging.debug("Retrieving generated report from {}".format(location))
38+
# response = hub.download_report(report_id)
39+
response, report_format = hub.download_notification_report(location)
3940
if response.status_code == 200:
40-
with open(filename, "wb") as f:
41-
f.write(response.content)
42-
print("Successfully downloaded zip file to {} for report {}".format(filename, report_id))
41+
if report_format == "TEXT":
42+
filename = file_name_base + ".zip"
43+
with open(filename, "wb") as f:
44+
f.write(response.content)
45+
else:
46+
# JSON format
47+
filename = file_name_base + ".json"
48+
with open(filename, "w") as f:
49+
json.dump(response.json(), f, indent=3)
50+
logging.info("Successfully downloaded json file to {} for report {}".format(
51+
filename, report_id))
4352
else:
44-
print("Failed to retrieve report {}".format(report_id))
45-
print("Probably not ready yet, waiting 5 seconds then retrying...")
53+
logging.warning("Failed to retrieve report {}".format(report_id))
54+
logging.warning("Probably not ready yet, waiting 5 seconds then retrying (remaining retries={}".format(retries))
4655
time.sleep(5)
4756
retries -= 1
48-
download_report(location, filename, retries)
57+
download_report(location, file_name_base, retries)
4958
else:
5059
raise FailedReportDownload("Failed to retrieve report {} after multiple retries".format(report_id))
5160

@@ -54,22 +63,23 @@ def download_report(location, filename, retries=4):
5463
if project:
5564
version = hub.get_version_by_name(project, args.version_name)
5665

57-
response = hub.create_version_notices_report(version, args.format)
66+
response = hub.create_version_notices_report(version, args.report_format)
5867

5968
if response.status_code == 201:
60-
print("Successfully created reports ({}) for project {} and version {}".format(
61-
args.reports, args.project_name, args.version_name))
69+
logging.info("Successfully created notices report in {} format for project {} and version {}".format(
70+
args.report_format, args.project_name, args.version_name))
6271
location = response.headers['Location']
63-
download_report(location, args.zip_file_name)
72+
download_report(location, args.file_name_base)
73+
6474

6575
# Showing how you can interact with the downloaded zip and where to find the
6676
# output content. Uncomment the lines below to see how it works.
6777

68-
# with zipfile.ZipFile(zip_file_name, 'r') as zipf:
78+
# with zipfile.ZipFile(zip_file_name_base, 'r') as zipf:
6979
# with zipf.open("{}/{}/version-license.txt".format(args.project_name, args.version_name), "r") as license_file:
7080
# print(license_file.read())
7181
else:
72-
print("Failed to create reports for project {} version {}, status code returned {}".format(
82+
logging.error("Failed to create reports for project {} version {}, status code returned {}".format(
7383
args.project_name, args.version_name, response.status_code))
7484
else:
75-
print("Did not find project with name {}".format(args.project_name))
85+
logging.warning("Did not find project with name {}".format(args.project_name))

0 commit comments

Comments
 (0)