fix: fall back to distribution ID when os-release has no version field (#961)

## Summary

`getLinuxOSNameVersion()` throws `Failed to determine Linux
distribution. Could not read /etc/os-release or /usr/lib/os-release` on
distributions whose os-release is readable but contains **no version
field at all** — no `VERSION_ID`, no `VERSION_CODENAME`, no `BUILD_ID`.
The error message is misleading in that case, and the action fails even
though the distribution is perfectly identifiable.

Void Linux is such a distribution. Its os-release is:

```sh
$ cat /etc/os-release
NAME="Void"
ID="void"
PRETTY_NAME="Void Linux"
HOME_URL="https://voidlinux.org/"
DOCUMENTATION_URL="https://docs.voidlinux.org/"
LOGO="void-logo"
ANSI_COLOR="0;38;2;71;128;97"

DISTRIB_ID="void"
```

Unlike Arch (fixed by #912 via `BUILD_ID`) and debian:unstable (fixed
via `VERSION_CODENAME`, #773), Void ships only `ID`, so both existing
fallbacks miss it. This breaks any workflow using `container:
ghcr.io/void-linux/void-glibc-full` with caching enabled — e.g.
SageMath's CI started failing after bumping to v8:
https://github.com/sagemath/sage/actions/runs/29456228986/job/87489892141
(worked around downstream in https://github.com/sagemath/sage/pull/42547
by injecting a fake `BUILD_ID` into the container's os-release).

This PR adds a last-resort fallback: if `ID` is present but no version
field is, return the plain `ID` (`void`), following the same reasoning
as #912 — a stable cache key for a rolling release is better than
crashing. Distributions with a version field are unaffected, and files
without even an `ID` still raise the existing error.
This commit is contained in:
Chenxin Zhong
2026-07-19 16:04:14 +08:00
committed by GitHub
parent ecd24dd710
commit f12b1f0a84
2 changed files with 19 additions and 0 deletions

7
dist/setup/index.cjs generated vendored
View File

@@ -90506,6 +90506,7 @@ function getOSNameVersion() {
} }
function getLinuxOSNameVersion() { function getLinuxOSNameVersion() {
const files = ["/etc/os-release", "/usr/lib/os-release"]; const files = ["/etc/os-release", "/usr/lib/os-release"];
let idWithoutVersion;
for (const file of files) { for (const file of files) {
try { try {
const content = import_node_fs2.default.readFileSync(file, "utf8"); const content = import_node_fs2.default.readFileSync(file, "utf8");
@@ -90522,9 +90523,15 @@ function getLinuxOSNameVersion() {
if (id && buildId) { if (id && buildId) {
return `${id}-${buildId}`; return `${id}-${buildId}`;
} }
if (id && idWithoutVersion === void 0) {
idWithoutVersion = id;
}
} catch { } catch {
} }
} }
if (idWithoutVersion) {
return idWithoutVersion;
}
throw new Error( throw new Error(
"Failed to determine Linux distribution. Could not read /etc/os-release or /usr/lib/os-release" "Failed to determine Linux distribution. Could not read /etc/os-release or /usr/lib/os-release"
); );

View File

@@ -102,6 +102,7 @@ export function getOSNameVersion(): string {
function getLinuxOSNameVersion(): string { function getLinuxOSNameVersion(): string {
const files = ["/etc/os-release", "/usr/lib/os-release"]; const files = ["/etc/os-release", "/usr/lib/os-release"];
let idWithoutVersion: string | undefined;
for (const file of files) { for (const file of files) {
try { try {
@@ -122,11 +123,22 @@ function getLinuxOSNameVersion(): string {
if (id && buildId) { if (id && buildId) {
return `${id}-${buildId}`; return `${id}-${buildId}`;
} }
// Remember the ID but keep looking: the next file might still
// provide a version field
if (id && idWithoutVersion === undefined) {
idWithoutVersion = id;
}
} catch { } catch {
// Try next file // Try next file
} }
} }
// Fallback for rolling releases (e.g. void) that have no version
// field at all
if (idWithoutVersion) {
return idWithoutVersion;
}
throw new Error( throw new Error(
"Failed to determine Linux distribution. " + "Failed to determine Linux distribution. " +
"Could not read /etc/os-release or /usr/lib/os-release", "Could not read /etc/os-release or /usr/lib/os-release",