Skip to content

Commit f46cfa1

Browse files
committed
Fix list-runtimes to dynamically discover Java versions including Java 25
- Remove hardcoded Java version lists that were missing Java 25 - Add dynamic parsing of Java versions from API's runtimes array - Add _get_java_versions_from_minor_versions() for Linux Java SE containers - Add _get_java_versions_from_windows_container() for Windows containers - Add _get_java_runtimes_from_container_settings() for Linux container runtimes - Add deduplication to prevent duplicate runtime entries (e.g., JBOSSEAP) - Future-proof: new Java versions will automatically appear without code changes
1 parent 42719ba commit f46cfa1

File tree

1 file changed

+97
-10
lines changed
  • src/azure-cli/azure/cli/command_modules/appservice

1 file changed

+97
-10
lines changed

src/azure-cli/azure/cli/command_modules/appservice/custom.py

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6152,12 +6152,13 @@ def _get_raw_stacks_from_api(self):
61526152
return list(self._client.provider.get_web_app_stacks(stack_os_type=None))
61536153

61546154
def _parse_raw_stacks(self, stacks):
6155+
seen_runtimes = set() # Track seen runtime display names to avoid duplicates
61556156
for lang in stacks:
61566157
for major_version in lang.major_versions:
61576158
if self._linux:
61586159
if lang.display_text.lower() == "java":
61596160
continue
6160-
self._parse_major_version_linux(major_version, self._stacks)
6161+
self._parse_major_version_linux(major_version, self._stacks, seen_runtimes)
61616162
if self._windows:
61626163
self._parse_major_version_windows(major_version, self._stacks, self.windows_config_mappings)
61636164

@@ -6302,17 +6303,100 @@ def _filter(minor_version):
63026303
return cls._is_valid_runtime_setting(cls._get_runtime_setting(minor_version, linux, java))
63036304
return [m for m in major_version.minor_versions if _filter(m)]
63046305

6306+
@staticmethod
6307+
def _get_java_versions_from_minor_versions(minor_versions):
6308+
"""Dynamically extract unique Java versions from minor version values.
6309+
Used for Linux Java SE containers where minor.value is like "25.0.0", "21.0.0".
6310+
Returns versions sorted in descending order (newest first)."""
6311+
java_versions = set()
6312+
for minor in minor_versions:
6313+
# minor.value is like "25.0.0", "21.0.0", "17.0.0", "11.0.0", "8.0.0" or "1.8.0"
6314+
value = minor.value
6315+
if value:
6316+
# Handle both "1.8" format and newer "25", "21" formats
6317+
if value.startswith("1.8"):
6318+
java_versions.add("1.8")
6319+
else:
6320+
# Extract major version number (e.g., "25" from "25.0.0")
6321+
major_ver = value.split('.')[0]
6322+
if major_ver.isdigit():
6323+
java_versions.add(major_ver)
6324+
# Sort descending (newest versions first), treating "1.8" specially
6325+
return sorted(java_versions, key=lambda x: -1 if x == "1.8" else -int(x))
6326+
6327+
@staticmethod
6328+
def _get_java_versions_from_windows_container(container_settings):
6329+
"""Dynamically extract Java versions from Windows container settings.
6330+
Looks at the 'runtimes' array in additional_properties.
6331+
Returns versions sorted in descending order (newest first)."""
6332+
java_versions = set()
6333+
additional_props = getattr(container_settings, 'additional_properties', {}) or {}
6334+
runtimes_array = additional_props.get('runtimes', [])
6335+
6336+
for runtime_info in runtimes_array:
6337+
version = runtime_info.get('runtimeVersion')
6338+
if version:
6339+
# Normalize version: convert "1.8" to "1.8", keep others as-is
6340+
java_versions.add(version)
6341+
6342+
# Sort descending (newest versions first), treating "1.8" specially
6343+
return sorted(java_versions, key=lambda x: -1 if x == "1.8" else -int(x))
6344+
6345+
@staticmethod
6346+
def _get_java_runtimes_from_container_settings(container_settings):
6347+
"""Dynamically extract Java runtimes from container settings.
6348+
Prefers the 'runtimes' array from the API when available (most future-proof),
6349+
falls back to individual java*Runtime properties in additional_properties,
6350+
and finally SDK-defined properties (java8_runtime, java11_runtime).
6351+
Returns list of tuples: (runtime_name, version, is_auto_update)"""
6352+
runtimes = []
6353+
is_auto_update = getattr(container_settings, 'is_auto_update', False)
6354+
additional_props = getattr(container_settings, 'additional_properties', {}) or {}
6355+
6356+
# Prefer the 'runtimes' array if available (cleanest, most future-proof)
6357+
runtimes_array = additional_props.get('runtimes', [])
6358+
if runtimes_array:
6359+
for runtime_info in runtimes_array:
6360+
runtime_name = runtime_info.get('runtime')
6361+
version = runtime_info.get('runtimeVersion')
6362+
if runtime_name and version:
6363+
runtimes.append((runtime_name, version, is_auto_update))
6364+
else:
6365+
# Fallback: Get runtimes from additional_properties (java*Runtime keys)
6366+
for key, value in additional_props.items():
6367+
# Match pattern like "java25Runtime", "java21Runtime", etc.
6368+
if key.startswith('java') and key.endswith('Runtime') and value:
6369+
# Extract version number from key (e.g., "25" from "java25Runtime")
6370+
version = key[4:-7] # Remove "java" prefix and "Runtime" suffix
6371+
if version.isdigit():
6372+
runtimes.append((value, version, is_auto_update))
6373+
6374+
# Also get runtimes from SDK-defined properties (java8_runtime, java11_runtime)
6375+
if getattr(container_settings, 'java11_runtime', None):
6376+
# Avoid duplicates if already found in additional_properties
6377+
if not any(v == "11" for _, v, _ in runtimes):
6378+
runtimes.append((container_settings.java11_runtime, "11", is_auto_update))
6379+
if getattr(container_settings, 'java8_runtime', None):
6380+
if not any(v == "8" for _, v, _ in runtimes):
6381+
runtimes.append((container_settings.java8_runtime, "8", is_auto_update))
6382+
6383+
# Sort by version descending (newest first)
6384+
runtimes.sort(key=lambda x: -1 if x[1] == "8" else -int(x[1]))
6385+
return runtimes
6386+
63056387
def _parse_major_version_windows(self, major_version, parsed_results, config_mappings):
63066388
java_container_minor_versions = self._get_valid_minor_versions(major_version, linux=False, java=True)
63076389
if java_container_minor_versions:
6308-
javas = ["21", "17", "11", "1.8"]
6390+
# Limit to 3 containers for display
63096391
if len(java_container_minor_versions) > 0:
63106392
leng = len(java_container_minor_versions) if len(java_container_minor_versions) < 3 else 3
63116393
java_container_minor_versions = java_container_minor_versions[:leng]
63126394
for container in java_container_minor_versions:
63136395
container_settings = container.stack_settings.windows_container_settings
63146396
java_container = container_settings.java_container
63156397
container_version = container_settings.java_container_version
6398+
# Get Java versions from the container's runtimes array
6399+
javas = self._get_java_versions_from_windows_container(container_settings)
63166400
for java in javas:
63176401
runtime = self.get_windows_java_runtime(
63186402
java,
@@ -6380,11 +6464,13 @@ def get_windows_java_runtime(self, java_version=None,
63806464
linux=False,
63816465
is_auto_update=is_auto_update)
63826466

6383-
def _parse_major_version_linux(self, major_version, parsed_results):
6467+
def _parse_major_version_linux(self, major_version, parsed_results, seen_runtimes):
63846468
minor_java_container_versions = self._get_valid_minor_versions(major_version, linux=True, java=True)
63856469
if "SE" in major_version.display_text:
6386-
se_containers = [minor_java_container_versions[0]]
6387-
for java in ["21", "17", "11", "1.8"]:
6470+
# Dynamically get Java versions from the available minor versions
6471+
java_versions = self._get_java_versions_from_minor_versions(minor_java_container_versions)
6472+
se_containers = [minor_java_container_versions[0]] if minor_java_container_versions else []
6473+
for java in java_versions:
63886474
se_java_containers = [c for c in minor_java_container_versions if c.value.startswith(java)]
63896475
se_containers = se_containers + se_java_containers[:len(se_java_containers) if len(se_java_containers) < 2 else 2] # pylint: disable=line-too-long
63906476
minor_java_container_versions = se_containers
@@ -6394,14 +6480,15 @@ def _parse_major_version_linux(self, major_version, parsed_results):
63946480
"SE" not in major_version.display_text else len(minor_java_container_versions)
63956481
for minor in minor_java_container_versions[:leng]:
63966482
linux_container_settings = minor.stack_settings.linux_container_settings
6397-
runtimes = [
6398-
(linux_container_settings.additional_properties.get("java21Runtime"), "21", linux_container_settings.is_auto_update), # pylint: disable=line-too-long
6399-
(linux_container_settings.additional_properties.get("java17Runtime"), "17", linux_container_settings.is_auto_update), # pylint: disable=line-too-long
6400-
(linux_container_settings.java11_runtime, "11", linux_container_settings.is_auto_update),
6401-
(linux_container_settings.java8_runtime, "8", linux_container_settings.is_auto_update)]
6483+
# Dynamically get all Java runtimes from container settings
6484+
runtimes = self._get_java_runtimes_from_container_settings(linux_container_settings)
64026485
# Remove the JBoss'_byol' entries from the output
64036486
runtimes = [(r, v, au) for (r, v, au) in runtimes if r is not None and not r.endswith("_byol")] # pylint: disable=line-too-long
64046487
for runtime_name, version, auto_update in [(r, v, au) for (r, v, au) in runtimes if r is not None]:
6488+
# Skip duplicates
6489+
if runtime_name in seen_runtimes:
6490+
continue
6491+
seen_runtimes.add(runtime_name)
64056492
runtime = self.Runtime(display_name=runtime_name,
64066493
configs={"linux_fx_version": runtime_name},
64076494
github_actions_properties={"github_actions_version": version},

0 commit comments

Comments
 (0)