diff --git a/build/config.json b/build/config.json index 20f24d5455..19912f2266 100644 --- a/build/config.json +++ b/build/config.json @@ -183,7 +183,7 @@ "downloadUrl": "https://github.com/cli/cli" }, "yarn": { - "versionCommand": "yarn --version", + "versionCommand": "yarn --version 2>/dev/null | grep -oE '[0-9]+\\.[0-9]+\\.[0-9]+'", "downloadUrl": "https://yarnpkg.com/" }, "Maven": { diff --git a/build/src/utils/config.js b/build/src/utils/config.js index 3bea536bc1..96b5b2b8ac 100644 --- a/build/src/utils/config.js +++ b/build/src/utils/config.js @@ -214,6 +214,7 @@ function getTagsForVersion(definitionId, version, registry, registryPath, varian } } + const seen = new Set(); return tags.reduce((list, tag) => { // One of the tags that needs to be supported is one where there is no version, but there // are other attributes. For example, python:3 in addition to python:0.35.0-3. So, a version @@ -224,7 +225,11 @@ function getTagsForVersion(definitionId, version, registry, registryPath, varian .replace(/\$\{?VARIANT\}?/, variant || 'NOVARIANT') .replace('-NOVARIANT', ''); if (baseTag.charAt(baseTag.length - 1) !== ':') { - list.push(`${registry}/${registryPath}/${baseTag}`); + const fullTag = `${registry}/${registryPath}/${baseTag}`; + if (!seen.has(fullTag)) { + seen.add(fullTag); + list.push(fullTag); + } } return list; }, []); @@ -305,13 +310,23 @@ function getTagList(definitionId, release, versionPartHandling, registry, regist // If this variant should also be used for the the latest tag, add it. The "latest" value could be // true, false, or a specific variant. "true" assumes the first variant is the latest. const definitionLatestProperty = config.definitionBuildSettings[definitionId].latest; - return tagList.concat((updateLatest + const allTags = tagList.concat((updateLatest && definitionLatestProperty && (!allVariants - || variant === definitionLatestProperty + || variant === definitionLatestProperty || (definitionLatestProperty === true && variant === firstVariant))) ? getLatestTag(definitionId, registry, registryPath) : []); + + // Deduplicate tags while preserving order + const seen = new Set(); + return allTags.filter((tag) => { + if (seen.has(tag)) { + return false; + } + seen.add(tag); + return true; + }); } const getDefinitionObject = (id, variant) => { diff --git a/build/src/utils/image-content-extractor.js b/build/src/utils/image-content-extractor.js index 237d871e12..4f47e2fef0 100644 --- a/build/src/utils/image-content-extractor.js +++ b/build/src/utils/image-content-extractor.js @@ -271,12 +271,34 @@ async function getPipPackageInfo(imageTagOrContainerName, packageList, usePipx, console.log('(*) Gathering information about pip packages...'); const versionLookup = usePipx ? await getPipxVersionLookup(imageTagOrContainerName) : await getPipVersionLookup(imageTagOrContainerName, imageId); - return packageList.map((package) => { - return { - name: package, - version: versionLookup[package] - }; - }); + // Build a fallback lookup keyed by PEP 503 normalized names so packages that + // differ only by casing/normalization (e.g. "pyOpenssl" vs "pyOpenSSL") still resolve. + const normalizedVersionLookup = Object.keys(versionLookup).reduce((prev, name) => { + prev[normalizePipPackageName(name)] = versionLookup[name]; + return prev; + }, {}); + + return packageList.reduce((list, package) => { + const version = versionLookup[package] || normalizedVersionLookup[normalizePipPackageName(package)]; + // Skip packages that aren't actually installed in the inspected environment. + // Emitting an entry without a version produces blank markdown rows and + // conflicting/duplicate cgmanifest.json (SBOM) registrations. + if (version) { + list.push({ + name: package, + version: version + }); + } else { + console.log(`(!) Warning: Could not determine version for pip package "${package}" - skipping.`); + } + return list; + }, []); +} + +// Normalize a Python package name per PEP 503 (lowercase, runs of "-_." collapsed to "-") +// so lookups are tolerant of casing/separator differences between manifests and pip output. +function normalizePipPackageName(name) { + return name.replace(/[-_.]+/g, '-').toLowerCase(); } function getUserName(imageId) { diff --git a/src/dotnet/manifest.json b/src/dotnet/manifest.json index d021c42e73..de6bf64c15 100644 --- a/src/dotnet/manifest.json +++ b/src/dotnet/manifest.json @@ -1,5 +1,5 @@ { - "version": "2.1.2", + "version": "2.1.3", "variants": [ "11.0-preview-resolute", "10.0-noble", @@ -80,7 +80,7 @@ "languages": { ".NET": { "cgIgnore": true, - "versionCommand": "dotnet --version | grep -oE '[0-9]+\\.[0-9]+\\.[0-9]+' | tr -d '\\n' && echo \\\" (\\$(dotnet --info | grep -ozP 'Host.*:\\s*Version:\\s*\\K[0-9]\\.[0-9]\\.[0-9]' | tr '\\0' '\\n'))\\\"", + "versionCommand": "dotnet --version | grep -oE '[0-9]+\\.[0-9]+\\.[0-9]+' | tr -d '\\n' && echo \\\" (\\$(dotnet --info | grep -ozP 'Host.*:\\s*Version:\\s*\\K[0-9]+\\.[0-9]+\\.[0-9]+' | tr '\\0' '\\n'))\\\"", "path": "/usr", "downloadUrl": "https://dotnet.microsoft.com/" } diff --git a/src/java-8/manifest.json b/src/java-8/manifest.json index 961511ba14..fa090a3177 100644 --- a/src/java-8/manifest.json +++ b/src/java-8/manifest.json @@ -1,5 +1,5 @@ { - "version": "3.0.10", + "version": "3.1.0", "variants": [ "trixie", "bookworm" @@ -56,7 +56,7 @@ "languages": { "Java": { "cgIgnore": true, - "versionCommand": "/usr/local/sdkman/candidates/java/current/bin/java -version 2>&1 | grep -ozP '^openjdk\\sversion\\s\\\"\\K[^\\\"]+' | tr '\\0' '\\n' && /usr/local/openjdk-*/bin/java --version | grep -ozP 'openjdk\\s+\\K[0-9]+\\.[0-9]+\\.[0-9]+' | tr '\\0' '\\n'", + "versionCommand": "/usr/local/sdkman/candidates/java/current/bin/java -version 2>&1 | grep -ozP '^openjdk\\sversion\\s\\\"\\K[^\\\"]+' | tr '\\0' '\\n'", "path": "/usr/local/sdkman/candidates/java/current
/usr/local" } } diff --git a/src/universal/manifest.json b/src/universal/manifest.json index 84cdc91435..3cf7ec4b41 100644 --- a/src/universal/manifest.json +++ b/src/universal/manifest.json @@ -1,5 +1,5 @@ { - "version": "6.0.6", + "version": "6.0.7", "build": { "latest": true, "rootDistro": "debian", @@ -119,8 +119,7 @@ "plotly", "jupyterlab_git", "certifi", - "setuptools", - "wheel" + "setuptools" ], "other": { "git": {},