Skip to content

Commit 91120ae

Browse files
committed
Clean up code and improve formatting #1763
Signed-off-by: Chin Yeung Li <tli@nexb.com>
1 parent 2631c80 commit 91120ae

3 files changed

Lines changed: 49 additions & 112 deletions

File tree

scanpipe/pipelines/scan_maven_package.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class ScanMavenPackage(ScanSinglePackage, DeployToDevelop):
3737
This pipeline takes a Maven PURL as input, fetches the binary and
3838
source archives (if they exist), and then performs scans for package
3939
metadata, declared dependencies, licenses, license clarity scores, and
40-
copyrights. It also performs a D2D scan if both the source and binary
41-
archives are available.
40+
copyrights. It also performs a deployment to development relation scan
41+
if both the source and binary archives are available.
4242
4343
The output is a summary of the scan results in JSON format.
4444
"""
@@ -76,7 +76,10 @@ def fetch_inputs(self):
7676
self.to_files = [to_file]
7777

7878
def d2d_check(self):
79-
"""Set D2D enable if both from and to files are present."""
79+
"""
80+
Enable the deployment to development relation scan if both from
81+
and to files are present.
82+
"""
8083
self.d2d_enabled = False
8184
if self.from_files and self.to_files:
8285
self.d2d_enabled = True
@@ -98,7 +101,7 @@ def extract_input(self):
98101
self.extract_inputs_to_codebase_directory()
99102

100103
def maven_d2d_steps(self):
101-
"""Run D2D steps for Maven projects."""
104+
"""Run deployment to development relation scan steps for Maven projects."""
102105
if self.d2d_enabled:
103106
self.collect_and_create_codebase_resources()
104107
self.fingerprint_codebase_directories()
@@ -116,11 +119,6 @@ def maven_d2d_steps(self):
116119
self.d2d_process()
117120

118121
def d2d_ecosystem_config(self):
119-
# The following langages will be included:
120-
# - Java
121-
# - Kotlin
122-
# - Scala
123-
# - JavaScript
124122
options = ["Java", "Kotlin", "Scala", "JavaScript"]
125123
d2d_config.load_ecosystem_config(pipeline=self, options=options)
126124

@@ -178,5 +176,8 @@ def fetch_and_scan_remote_pom(self):
178176
)
179177

180178
def update_package_license_from_resource_if_missing(self):
181-
"""Update PACKAGE license from the license detected in RESOURCES if missing."""
179+
"""
180+
Fill in missing package licenses using licenses detected in
181+
their resources.
182+
"""
182183
update_package_license_from_resource_if_missing(self.project)

scanpipe/pipes/maven.py

Lines changed: 28 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from urllib.parse import urlparse
2626

2727
import requests
28+
from license_expression import Licensing
2829
from packageurl import PackageURL
2930
from packageurl.contrib import purl2url
3031

@@ -46,19 +47,11 @@ def check_input_and_return_purl(project):
4647
if input_purl.type != "maven":
4748
error_msg = "Only maven purl is supported."
4849
raise ValueError(error_msg)
49-
# Version is required
5050
if not input_purl.version:
5151
error_msg = "Version is required."
5252
raise ValueError(error_msg)
5353

54-
purl = PackageURL(
55-
type=input_purl.type,
56-
namespace=input_purl.namespace,
57-
name=input_purl.name,
58-
version=input_purl.version,
59-
)
60-
61-
return purl
54+
return input_purl
6255

6356

6457
def fetch_inputs(purl):
@@ -88,11 +81,10 @@ def fetch_and_scan_remote_pom(input_purl, scan_output_location):
8881
"""Fetch the .pom file from from maven.org if not present in codebase."""
8982
with open(scan_output_location) as file:
9083
data = json.load(file)
91-
# Return and do nothing if data has pom.xml
92-
for file in data["files"]:
93-
if "pom.xml" in file["path"]:
94-
return []
95-
packages = data.get("packages", [])
84+
# Return and do nothing if data has pom.xml
85+
for file in data["files"]:
86+
if "pom.xml" in file["path"]:
87+
return []
9688

9789
pom_url = get_pom_url(input_purl)
9890
if not pom_url:
@@ -103,14 +95,18 @@ def fetch_and_scan_remote_pom(input_purl, scan_output_location):
10395
scanning_errors = scan_pom_file(pom_file)
10496

10597
scanned_pom_packages, scanned_dependencies = update_datafile_paths(pom_file)
98+
updated_data = update_scan_data(data, scanned_pom_packages, scanned_dependencies)
10699

107-
updated_packages = packages + scanned_pom_packages
108-
# Replace/Update the package and dependencies section
109-
data["packages"] = updated_packages
110-
data["dependencies"] = scanned_dependencies
111100
with open(scan_output_location, "w") as file:
112-
json.dump(data, file, indent=2)
113-
return scanning_errors
101+
json.dump(updated_data, file, indent=2)
102+
return [scanning_errors]
103+
104+
105+
def update_scan_data(data, scanned_packages, scanned_dependencies):
106+
"""Update packages and dependencies data"""
107+
data["packages"] = data.get("packages", []) + scanned_packages
108+
data["dependencies"] = scanned_dependencies
109+
return data
114110

115111

116112
def get_pom_url(input_purl):
@@ -135,25 +131,9 @@ def get_pom_url(input_purl):
135131

136132
def download_pom_file(pom_url):
137133
"""Fetch the pom file from the input pom_url"""
138-
# PO: Could we use fetchcode to fetch instead? Yes, we could, but
139-
# the issue is do we want to. Following is the code if we switch to
140-
# fetchcode which seems making things complicated, OR we can move
141-
# the "fetch_http" to fetchcode and use it.
142-
"""
143-
import os
144-
import fetchcode
145-
downloaded_pom = fetchcode.fetch(pom_url)
146-
location = str(downloaded_pom.location)
147-
path = location + ".pom"
148-
# The fetch function from fetchcode save the file as /tmp/name
149-
# without an extension. We need to add the ".pom" extension so that
150-
# the package scan can work properly for this file.
151-
os.rename(location, path)
152-
"""
153134
try:
154135
downloaded_pom = fetch.fetch_http(pom_url)
155136
except requests.RequestException:
156-
# Return an empty dictionary
157137
return {}
158138
path = str(downloaded_pom.path)
159139
pom_file_dict = {}
@@ -165,21 +145,18 @@ def download_pom_file(pom_url):
165145

166146
def scan_pom_file(pom_file_dict):
167147
"""Fetch and scan the pom file from the input pom_urls"""
168-
scan_errors = []
169148
pom_file_path = pom_file_dict.get("pom_file_path", "")
170149
scanned_pom_output_path = pom_file_dict.get("output_path", "")
171150

172151
# Run a package scan on the fetched pom.xml
173-
scanning_errors = scancode.run_scan(
152+
# Return scanning errors, if present
153+
return scancode.run_scan(
174154
location=pom_file_path,
175155
output_file=scanned_pom_output_path,
176156
run_scan_args={
177157
"package": True,
178158
},
179159
)
180-
if scanning_errors:
181-
scan_errors.append(scanning_errors)
182-
return scan_errors
183160

184161

185162
def update_datafile_paths(pom_file_dict):
@@ -197,11 +174,9 @@ def update_datafile_paths(pom_file_dict):
197174
scanned_dependencies = scanned_pom_data.get("dependencies", [])
198175

199176
for scanned_package in scanned_packages:
200-
# Replace the 'datafile_path' with the pom_url
201177
scanned_package["datafile_paths"] = [pom_url]
202178
scanned_pom_packages.append(scanned_package)
203179
for scanned_dep in scanned_dependencies:
204-
# Replace the 'datafile_path' with empty string
205180
# See https://github.com/aboutcode-org/scancode.io/issues/1763#issuecomment-3525165830
206181
scanned_dep["datafile_path"] = ""
207182
scanned_pom_deps.append(scanned_dep)
@@ -210,20 +185,20 @@ def update_datafile_paths(pom_file_dict):
210185

211186
def update_package_license_from_resource_if_missing(project):
212187
"""Populate missing licenses to packages based on resource data."""
213-
from license_expression import Licensing
214-
215188
for package in project.discoveredpackages.all():
216189
if not package.get_declared_license_expression():
217190
package_uid = package.package_uid
218-
detected_lics = []
191+
detected_licenses = []
219192
for resource in project.codebaseresources.has_license_expression():
220193
for for_package in resource.for_packages:
221194
if for_package == package_uid:
222-
detected_lic_exp = resource.detected_license_expression
223-
if detected_lic_exp not in detected_lics:
224-
detected_lics.append(detected_lic_exp)
225-
if detected_lics:
226-
lic_exp = " AND ".join(detected_lics)
227-
declared_lic_exp = str(Licensing().dedup(lic_exp))
228-
package.declared_license_expression = declared_lic_exp
195+
detected_license_expression = (
196+
resource.detected_license_expression
197+
)
198+
if detected_license_expression not in detected_licenses:
199+
detected_licenses.append(detected_license_expression)
200+
if detected_licenses:
201+
license_expression = " AND ".join(detected_licenses)
202+
declared_license_expression = str(Licensing().dedup(license_expression))
203+
package.declared_license_expression = declared_license_expression
229204
package.save()

scanpipe/tests/pipes/test_maven.py

Lines changed: 10 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -241,66 +241,27 @@ def test_scanpipe_maven_fetch_and_scan_remote_pom_no_pom_file(
241241
)
242242
self.assertEqual(result, ["Failed to download the POM file."])
243243

244-
@mock.patch("builtins.open", new_callable=mock.mock_open)
245-
@mock.patch("json.load")
246-
@mock.patch("json.dump")
247-
@mock.patch("scanpipe.pipes.maven.get_pom_url")
248-
@mock.patch("scanpipe.pipes.maven.download_pom_file")
249-
@mock.patch("scanpipe.pipes.maven.scan_pom_file")
250-
@mock.patch("scanpipe.pipes.maven.update_datafile_paths")
251-
def test_scanpipe_maven_fetch_and_scan_remote_pom_success(
252-
self,
253-
mock_update_datafile_paths,
254-
mock_scan_pom_file,
255-
mock_download_pom_file,
256-
mock_get_pom_url,
257-
mock_json_dump,
258-
mock_json_load,
259-
mock_open,
260-
):
261-
mock_json_load.return_value = {
262-
"files": [],
263-
"packages": [{"name": "sample-package"}],
264-
}
265-
mock_get_pom_url.return_value = "https://example.com/test.pom"
266-
mock_download_pom_file.return_value = {
267-
"pom_file_path": "/project/path.pom",
268-
"output_path": "/project/out.json",
269-
}
270-
mock_scan_pom_file.return_value = []
244+
def test_update_scan_data(self):
245+
original_data = {"packages": [{"name": "package1"}], "dependencies": []}
246+
new_package = [{"name": "package2"}]
247+
new_dependency = [{"name": "dep1"}]
271248

272-
mock_update_datafile_paths.return_value = (
273-
[{"name": "new-package"}],
274-
[{"name": "new-dependency"}],
275-
)
249+
result = maven.update_scan_data(original_data, new_package, new_dependency)
276250

277-
result = maven.fetch_and_scan_remote_pom(
278-
"pkg:maven/org/test@1.0", "/path/to/output.json"
251+
self.assertEqual(
252+
result["packages"], [{"name": "package1"}, {"name": "package2"}]
279253
)
280-
self.assertEqual(result, [])
281-
282-
expected_saved_data = {
283-
"files": [],
284-
"packages": [{"name": "sample-package"}, {"name": "new-package"}],
285-
"dependencies": [{"name": "new-dependency"}],
286-
}
287-
288-
self.assertTrue(mock_json_dump.called)
289-
290-
args, _kwargs = mock_json_dump.call_args
291-
# Get the data as in the first argument: json.dump(data, file, indent=2)
292-
data = args[0]
293-
self.assertEqual(data, expected_saved_data)
254+
self.assertEqual(result["dependencies"], [{"name": "dep1"}])
294255

295256
@mock.patch("scanpipe.pipes.maven.scancode.run_scan")
296257
def test_scanpipe_maven_scan_pom_file(self, mock_run_scan):
297258
pom_file_dict = {
298259
"pom_file_path": "/main/mock.pom",
299260
"output_path": "/main/mock.pom-output.json",
300261
}
301-
mock_run_scan.return_value = None
262+
mock_run_scan.return_value = {}
302263
result = maven.scan_pom_file(pom_file_dict)
303-
self.assertEqual(result, [])
264+
self.assertEqual(result, {})
304265

305266
mock_run_scan.assert_called_once_with(
306267
location="/main/mock.pom",

0 commit comments

Comments
 (0)