From 392ca7a4b5d8699b77718b0bdc6e1c98bc432b23 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Oct 2026 08:42:34 +0000 Subject: [PATCH 1/4] Initial plan From 8c92268c1cc45e7154041d857719e4d42de77710 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Oct 2026 08:45:17 +0000 Subject: [PATCH 2/4] fix: skip prerelease Node versions during resolution Co-authored-by: Roemer <393641+Roemer@users.noreply.github.com> --- features/src/node/installer.go | 12 +++++++++++- features/src/node/node_version_test.go | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 features/src/node/node_version_test.go diff --git a/features/src/node/installer.go b/features/src/node/installer.go index a67a7ee..02d7ace 100644 --- a/features/src/node/installer.go +++ b/features/src/node/installer.go @@ -105,7 +105,10 @@ func (c *nodeComponent) GetAllVersions() ([]*gover.Version, error) { } allVersions := []*gover.Version{} for _, entry := range jsonData { - version := gover.MustParseVersionFromRegex(entry.Version, nodeVersionRegex) + version, matches := parseNodeVersion(entry.Version) + if !matches { + continue + } isLtsEntry := false switch entry.Lts.(type) { case bool: @@ -121,6 +124,13 @@ func (c *nodeComponent) GetAllVersions() ([]*gover.Version, error) { return allVersions, nil } +func parseNodeVersion(versionString string) (*gover.Version, bool) { + if !nodeVersionRegex.MatchString(versionString) { + return nil, false + } + return gover.MustParseVersionFromRegex(versionString, nodeVersionRegex), true +} + func (c *nodeComponent) InstallVersion(version *gover.Version) error { // Prepare and download node archPart, err := installer.Tools.System.MapArchitecture(map[string]string{ diff --git a/features/src/node/node_version_test.go b/features/src/node/node_version_test.go new file mode 100644 index 0000000..7ab03ca --- /dev/null +++ b/features/src/node/node_version_test.go @@ -0,0 +1,17 @@ +package main + +import "testing" + +func TestParseNodeVersion(t *testing.T) { + if _, matches := parseNodeVersion("v27.0.0-alpha.0.0.0"); matches { + t.Fatal("expected prerelease version not to match") + } + + version, matches := parseNodeVersion("v27.0.0") + if !matches { + t.Fatal("expected stable version to match") + } + if version.Raw != "27.0.0" { + t.Fatalf("expected raw version 27.0.0, got %s", version.Raw) + } +} From e1cbc71275504fad110f0fc3561ce7c07200f654 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Oct 2026 09:11:00 +0000 Subject: [PATCH 3/4] fix: bump Node feature version for parser fix Co-authored-by: Roemer <393641+Roemer@users.noreply.github.com> --- features/src/node/README.md | 2 +- features/src/node/devcontainer-feature.json | 2 +- features/src/node/installer.go | 11 ++++------- features/src/node/node_version_test.go | 6 +++--- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/features/src/node/README.md b/features/src/node/README.md index 1773e0f..71dcc59 100755 --- a/features/src/node/README.md +++ b/features/src/node/README.md @@ -6,7 +6,7 @@ Installs Node.js. ```json "features": { - "ghcr.io/postfinance/devcontainer-features/node:1.0.0": { + "ghcr.io/postfinance/devcontainer-features/node:1.0.1": { "version": "lts", "npmVersion": "included", "yarnVersion": "none", diff --git a/features/src/node/devcontainer-feature.json b/features/src/node/devcontainer-feature.json index 36b212d..1713e4b 100644 --- a/features/src/node/devcontainer-feature.json +++ b/features/src/node/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "node", - "version": "1.0.0", + "version": "1.0.1", "name": "Node.js", "description": "Installs Node.js.", "options": { diff --git a/features/src/node/installer.go b/features/src/node/installer.go index 02d7ace..0b74f2d 100644 --- a/features/src/node/installer.go +++ b/features/src/node/installer.go @@ -105,8 +105,8 @@ func (c *nodeComponent) GetAllVersions() ([]*gover.Version, error) { } allVersions := []*gover.Version{} for _, entry := range jsonData { - version, matches := parseNodeVersion(entry.Version) - if !matches { + version, err := parseNodeVersion(entry.Version) + if err != nil { continue } isLtsEntry := false @@ -124,11 +124,8 @@ func (c *nodeComponent) GetAllVersions() ([]*gover.Version, error) { return allVersions, nil } -func parseNodeVersion(versionString string) (*gover.Version, bool) { - if !nodeVersionRegex.MatchString(versionString) { - return nil, false - } - return gover.MustParseVersionFromRegex(versionString, nodeVersionRegex), true +func parseNodeVersion(versionString string) (*gover.Version, error) { + return gover.ParseVersionFromRegex(versionString, nodeVersionRegex) } func (c *nodeComponent) InstallVersion(version *gover.Version) error { diff --git a/features/src/node/node_version_test.go b/features/src/node/node_version_test.go index 7ab03ca..c7cef74 100644 --- a/features/src/node/node_version_test.go +++ b/features/src/node/node_version_test.go @@ -3,12 +3,12 @@ package main import "testing" func TestParseNodeVersion(t *testing.T) { - if _, matches := parseNodeVersion("v27.0.0-alpha.0.0.0"); matches { + if _, err := parseNodeVersion("v27.0.0-alpha.0.0.0"); err == nil { t.Fatal("expected prerelease version not to match") } - version, matches := parseNodeVersion("v27.0.0") - if !matches { + version, err := parseNodeVersion("v27.0.0") + if err != nil { t.Fatal("expected stable version to match") } if version.Raw != "27.0.0" { From c22eab48ca31a3424d8162e38afce717cb432fff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Oct 2026 09:14:37 +0000 Subject: [PATCH 4/4] Remove redundant Node version parser wrapper Co-authored-by: Roemer <393641+Roemer@users.noreply.github.com> --- features/src/node/installer.go | 6 +----- features/src/node/node_version_test.go | 10 +++++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/features/src/node/installer.go b/features/src/node/installer.go index 0b74f2d..ce60be7 100644 --- a/features/src/node/installer.go +++ b/features/src/node/installer.go @@ -105,7 +105,7 @@ func (c *nodeComponent) GetAllVersions() ([]*gover.Version, error) { } allVersions := []*gover.Version{} for _, entry := range jsonData { - version, err := parseNodeVersion(entry.Version) + version, err := gover.ParseVersionFromRegex(entry.Version, nodeVersionRegex) if err != nil { continue } @@ -124,10 +124,6 @@ func (c *nodeComponent) GetAllVersions() ([]*gover.Version, error) { return allVersions, nil } -func parseNodeVersion(versionString string) (*gover.Version, error) { - return gover.ParseVersionFromRegex(versionString, nodeVersionRegex) -} - func (c *nodeComponent) InstallVersion(version *gover.Version) error { // Prepare and download node archPart, err := installer.Tools.System.MapArchitecture(map[string]string{ diff --git a/features/src/node/node_version_test.go b/features/src/node/node_version_test.go index c7cef74..b155244 100644 --- a/features/src/node/node_version_test.go +++ b/features/src/node/node_version_test.go @@ -1,13 +1,17 @@ package main -import "testing" +import ( + "testing" + + "github.com/roemer/gover" +) func TestParseNodeVersion(t *testing.T) { - if _, err := parseNodeVersion("v27.0.0-alpha.0.0.0"); err == nil { + if _, err := gover.ParseVersionFromRegex("v27.0.0-alpha.0.0.0", nodeVersionRegex); err == nil { t.Fatal("expected prerelease version not to match") } - version, err := parseNodeVersion("v27.0.0") + version, err := gover.ParseVersionFromRegex("v27.0.0", nodeVersionRegex) if err != nil { t.Fatal("expected stable version to match") }