Skip to content

Commit 2f8bb3a

Browse files
author
Trong Nhan Mai
committed
feat: always prioritize jdk version obtained from JAR from maven central
1 parent 5d6a99c commit 2f8bb3a

File tree

2 files changed

+120
-37
lines changed

2 files changed

+120
-37
lines changed

src/macaron/build_spec_generator/reproducible_central/reproducible_central.py

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -121,24 +121,27 @@ def _get_build_command_sequence(cmds_sequence: list[list[str]]) -> str:
121121

122122

123123
def _get_default_build_command_sequence(
124-
macaron_build_tool_name: _MacaronBuildToolName,
124+
rc_build_tool_name: _ReproducibleCentralBuildToolName,
125125
patches: Mapping[
126126
PatchCommandBuildTool,
127127
Mapping[str, PatchValueType | None],
128128
],
129129
) -> list[list[str]] | None:
130130
"""Return a default build command sequence for the corresponding build tool name discovered by Macaron."""
131131
default_build_command = None
132-
if macaron_build_tool_name == _MacaronBuildToolName.MAVEN:
133-
default_build_command = "mvn clean package"
134132

135-
if macaron_build_tool_name == _MacaronBuildToolName.GRADLE:
136-
default_build_command = "./gradlew clean assemble publishToMavenLocal"
133+
match rc_build_tool_name:
134+
case _ReproducibleCentralBuildToolName.MAVEN:
135+
default_build_command = "mvn clean package"
136+
case _ReproducibleCentralBuildToolName.GRADLE:
137+
default_build_command = "./gradlew clean assemble publishToMavenLocal"
138+
case _:
139+
pass
137140

138141
if not default_build_command:
139142
logger.critical(
140-
"The default build command %s is not supported for getting default build command.",
141-
macaron_build_tool_name,
143+
"There is no default build command available for RC build tool %s.",
144+
rc_build_tool_name,
142145
)
143146
return None
144147

@@ -166,12 +169,27 @@ def _get_macaron_build_tool_name(build_tool_facts: Sequence[BuildToolFacts]) ->
166169
except ValueError:
167170
continue
168171

169-
# TODO: What happen if we report multiple build tool in the database.
172+
# TODO: What happen if we report multiple build tools in the database.
170173
return macaron_build_tool_name
171174

172175
return None
173176

174177

178+
def _get_rc_build_tool_name(
179+
build_tool_facts: Sequence[BuildToolFacts],
180+
) -> _ReproducibleCentralBuildToolName | None:
181+
"""Return the build tool name to be put into the RC buildspec."""
182+
macaron_build_tool_name = _get_macaron_build_tool_name(build_tool_facts)
183+
if not macaron_build_tool_name:
184+
return None
185+
186+
match macaron_build_tool_name:
187+
case _MacaronBuildToolName.MAVEN:
188+
return _ReproducibleCentralBuildToolName.MAVEN
189+
case _MacaronBuildToolName.GRADLE:
190+
return _ReproducibleCentralBuildToolName.GRADLE
191+
192+
175193
def _gen_reproducible_central_build_spec(
176194
build_info: RcInternalBuildInfo,
177195
patches: Mapping[
@@ -201,6 +219,7 @@ def _gen_reproducible_central_build_spec(
201219
pformat(patches),
202220
)
203221

222+
# Getting groupid, artifactid and version from PURL.
204223
group = purl.namespace
205224
artifact = purl.name
206225
version = purl.version
@@ -210,29 +229,20 @@ def _gen_reproducible_central_build_spec(
210229

211230
extra_comments.append(f"Input PURL - {purl}")
212231

213-
macaron_build_tool_name = _get_macaron_build_tool_name(build_info.build_tool_facts)
214-
if not macaron_build_tool_name:
232+
# Getting the RC build tool name from the build tool check facts.
233+
rc_build_tool_name = _get_rc_build_tool_name(build_info.build_tool_facts)
234+
if not rc_build_tool_name:
215235
logger.error(
216-
"The PackageURL %s doesn't have any build tool that we support for generating RC buildspec. It has %s.",
217-
purl.to_string(),
236+
"The Component doesn't have any build tool that we support for generating RC buildspec. It has %s.",
218237
[(fact.build_tool_name, fact.language) for fact in build_info.build_tool_facts],
219238
)
220239
return None
221240

222-
rc_build_tool_name = None
223-
if macaron_build_tool_name == _MacaronBuildToolName.MAVEN:
224-
rc_build_tool_name = _ReproducibleCentralBuildToolName.MAVEN
225-
elif macaron_build_tool_name == _MacaronBuildToolName.GRADLE:
226-
rc_build_tool_name = _ReproducibleCentralBuildToolName.GRADLE
227-
if not rc_build_tool_name:
228-
logger.critical("%s is not supported to generate RC's buildspec.", macaron_build_tool_name.value)
229-
return None
230-
231241
# Set the default build command and jdk version.
232242
# The default build command depends on the build tool, while the default jdk version
233243
# is 8.
234244
final_build_command_seq = _get_default_build_command_sequence(
235-
macaron_build_tool_name=macaron_build_tool_name,
245+
rc_build_tool_name=rc_build_tool_name,
236246
patches=patches,
237247
)
238248
if not final_build_command_seq:
@@ -246,6 +256,22 @@ def _gen_reproducible_central_build_spec(
246256
f"Initial default JDK version {final_jdk_version} and default build command {final_build_command_seq}."
247257
)
248258

259+
# We always attempt to get the JDK version from maven central JAR for this GAV artifact.
260+
jdk_from_jar = find_jdk_version_from_central_maven_repo(
261+
group_id=purl.name,
262+
artifact_id=group,
263+
version=version,
264+
)
265+
if jdk_from_jar:
266+
extra_comments.append(f"Use JDK version from jar {jdk_from_jar}.")
267+
final_jdk_version = jdk_from_jar
268+
else:
269+
extra_comments.append(f"No JDK version found from jar {jdk_from_jar}.")
270+
271+
# If there is a build command available from the database, patch and use it in the final
272+
# buildspec.
273+
# If we couldn't find a JDK version from Maven Central JAR, we use the language_version
274+
# of the build command with the highest confidence score (if available).
249275
if build_info.generic_build_command_facts:
250276
# The elements are ordered in decreasing confidence score. We pick the highest one.
251277
build_fact = build_info.generic_build_command_facts[0]
@@ -265,23 +291,14 @@ def _gen_reproducible_central_build_spec(
265291

266292
final_build_command_seq = patched_build_commands
267293

268-
lookup_jdk_vers = build_fact.language_versions
269-
if lookup_jdk_vers:
270-
lookup_jdk_ver = lookup_jdk_vers.pop()
271-
extra_comments.append(f"Jdk version from lookup build command {lookup_jdk_ver}.")
294+
if not jdk_from_jar and build_fact.language_versions:
295+
# We pop the last element without any concrete reason, and we haven't had any issue
296+
# with it so far.
297+
lookup_jdk_ver = build_fact.language_versions.pop()
298+
extra_comments.append(f"Use Jdk version from lookup build command {lookup_jdk_ver}.")
272299
final_jdk_version = lookup_jdk_ver
273300
else:
274-
extra_comments.append("No JDK version found from lookup result.")
275-
jdk_from_jar = find_jdk_version_from_central_maven_repo(
276-
group_id=purl.name,
277-
artifact_id=group,
278-
version=version,
279-
)
280-
if jdk_from_jar:
281-
extra_comments.append(f"Found JDK version from jar {jdk_from_jar}.")
282-
final_jdk_version = jdk_from_jar
283-
else:
284-
extra_comments.append(f"No JDK version found from jar {jdk_from_jar}.")
301+
extra_comments.append("No JDK version used from lookup result.")
285302

286303
major_jdk_version = normalize_jdk_version(final_jdk_version)
287304
if not major_jdk_version:

tests/build_spec_generator/reproducible_central/test_reproducible_central.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
from macaron.build_spec_generator.reproducible_central.reproducible_central import (
99
_get_build_command_sequence,
1010
_get_extra_comments,
11+
_get_rc_build_tool_name,
12+
_ReproducibleCentralBuildToolName,
1113
)
14+
from macaron.slsa_analyzer.checks.build_tool_check import BuildToolFacts
1215

1316

1417
@pytest.mark.parametrize(
@@ -62,3 +65,66 @@ def test_get_build_command_sequence(
6265
) -> None:
6366
"""Test the _get_build_command_sequence function."""
6467
assert _get_build_command_sequence(cmds_sequence) == expected
68+
69+
70+
@pytest.mark.parametrize(
71+
("build_tool_facts", "expected"),
72+
[
73+
pytest.param(
74+
[
75+
BuildToolFacts(
76+
language="python",
77+
build_tool_name="pip",
78+
)
79+
],
80+
None,
81+
id="python_is_not_supported_for_rc",
82+
),
83+
pytest.param(
84+
[
85+
BuildToolFacts(
86+
language="java",
87+
build_tool_name="gradle",
88+
)
89+
],
90+
_ReproducibleCentralBuildToolName.GRADLE,
91+
id="build_tool_gradle",
92+
),
93+
pytest.param(
94+
[
95+
BuildToolFacts(
96+
language="java",
97+
build_tool_name="maven",
98+
)
99+
],
100+
_ReproducibleCentralBuildToolName.MAVEN,
101+
id="build_tool_maven",
102+
),
103+
pytest.param(
104+
[
105+
BuildToolFacts(
106+
language="not_java",
107+
build_tool_name="maven",
108+
)
109+
],
110+
None,
111+
id="java_is_the_only_supported_language",
112+
),
113+
pytest.param(
114+
[
115+
BuildToolFacts(
116+
language="java",
117+
build_tool_name="some_java_build_tool",
118+
)
119+
],
120+
None,
121+
id="test_unsupported_java_build_tool",
122+
),
123+
],
124+
)
125+
def test_get_rc_build_tool_name(
126+
build_tool_facts: list[BuildToolFacts],
127+
expected: _ReproducibleCentralBuildToolName | None,
128+
) -> None:
129+
"""Test the _get_rc_build_tool_name function."""
130+
assert _get_rc_build_tool_name(build_tool_facts) == expected

0 commit comments

Comments
 (0)