Skip to content

[BE-1996] Support .nvmrc version files for tool setup#1233

Open
marcell-vida wants to merge 2 commits intomasterfrom
be-1996-nvmrc-support
Open

[BE-1996] Support .nvmrc version files for tool setup#1233
marcell-vida wants to merge 2 commits intomasterfrom
be-1996-nvmrc-support

Conversation

@marcell-vida
Copy link
Copy Markdown
Contributor

@marcell-vida marcell-vida commented Mar 24, 2026

Checklist

  • I've read and followed the Contribution Guidelines
  • README.md is updated with the changes (if needed)
  • I've run go mod tidy both in root and in integrationtests/ if any dependencies have changed.

Version

Requires a MAJOR/MINOR/PATCH version update

Context

Changes

Investigation details

Decisions

@bitrise
Copy link
Copy Markdown
Contributor

bitrise bot commented Mar 24, 2026

Summary

Added support for .nvmrc version files in tool setup. Implemented parsing logic for Node.js version files, added Flutter -stable suffix fallback mechanism for mise provider, and added conditional Python precompiled flavor environment variable support for Python 3.14+.

Walkthrough

File Summary
toolprovider/versionfile/parser.go Added .nvmrc file parsing support with parseNVMRC function to extract Node.js versions from NVM config files
cli/tools.go Added .nvmrc documentation to tools setup command with example usage
toolprovider/mise/workarounds/flutter_stable_fallback.go New file implementing Flutter -stable suffix fallback for mise provider
toolprovider/mise/install.go, execenv/execenv.go Added RunMiseWithTimeoutAndEnvs method and Python 3.14+ precompiled flavor workaround
toolprovider/run.go, go.mod, mise.go Integrated Flutter fallback logic, fixed indirect dependency, cosmetic formatting

Copy link
Copy Markdown
Contributor

@bitrise bitrise bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an AI-generated review. Please review it carefully.

Actionable comments posted: 1

Copy link
Copy Markdown
Contributor

@bitrise bitrise bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an AI-generated review. Please review it carefully.

Actionable comments posted: 2

return nil, fmt.Errorf("%s: invalid version (empty after removing 'v' prefix)", path)
}
return []ToolVersion{
{ToolName: "node", Version: version},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐛 Bug

The ToolName is hardcoded as "node", but the alias map in toolprovider/alias/alias.go shows that "node" is an alias for "nodejs". Other parsers like parseSingleToolVersion use inferToolID which calls GetCanonicalToolID to convert aliases to canonical tool IDs. This creates an inconsistency: .node-version files return "nodejs" (canonical), while .nvmrc files return "node" (alias). While the alias conversion happens later in run.go, the parser should be consistent with other parsers and return the canonical tool ID "nodejs".

🔄 Suggestion:

Suggested change
{ToolName: "node", Version: version},
{ToolName: "nodejs", Version: version},

Copy link
Copy Markdown
Contributor

@bitrise bitrise bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an AI-generated review. Please review it carefully.

Actionable comments posted: 1

return false
}

if strings.HasPrefix(miseVersion, "v2026") {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐛 Bug

Incomplete version check: the condition only excludes versions starting with "v2026" but doesn't account for future versions like "v2027", "v2028", etc. Additionally, it doesn't verify the patch version for v2026 (the fix was in v2026.3.10, so v2026.0.0 through v2026.3.9 would still need the workaround).

🤖 Prompt for AI Agents:
In toolprovider/mise/install.go at line 104, Improve the version check to properly handle all mise versions >= v2026.3.10 and future versions. Consider using semantic version comparison or a more robust string comparison.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plan is to remove this temporary change in 2 weeks and previously there were only 2025 Mise versions pinned. Since now we pin the latest (from 2026) it doesn't matter which exact date it is, since all 2026 editions will be correct after this.

require.NoError(t, err)

t.Run(tt.name, func(t *testing.T) {
t.Parallel()

This comment was marked as outdated.

tool: "node",
version: "22.22.1",
name: "Install non-core tool with forced nixpkgs backend",
tool: "fake-unsupported-tool",

This comment was marked as outdated.

assert.Contains(t, output, "3.29.0")
},
},
// fvm_config.json tests

This comment was marked as outdated.

InstallDir() string
RunMise(args ...string) (string, error)
RunMiseWithTimeout(timeout time.Duration, args ...string) (string, error)
RunMiseWithTimeoutAndEnvs(timeout time.Duration, extraEnvs map[string]string, args ...string) (string, error)

This comment was marked as outdated.


// ShouldTryStableFallback checks if we should retry a Flutter installation without the -stable suffix.
// Returns the fallback version to try, or empty string if no fallback should be attempted.
func ShouldTryStableFallback(

This comment was marked as outdated.

@marcell-vida marcell-vida changed the title [BE-1996] Support .nvmrc version files for tool setup [BE-1996] Support .nvmrc version files for tool setup, fix Python and Flutter installs Mar 26, 2026
var toolErr provider.ToolInstallError
if errors.As(err, &toolErr) {
// Try Flutter -stable suffix workaround for mise provider
if miseProvider, ok := toolProvider.(*mise.MiseToolProvider); ok {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this whole thing into the mise package? This is breaking the abstraction.

if errors.As(err, &toolErr) {
// Try Flutter -stable suffix workaround for mise provider
if miseProvider, ok := toolProvider.(*mise.MiseToolProvider); ok {
fallbackVersion, fallbackErr := workarounds.ShouldTryStableFallback(miseProvider.ExecEnv, toolErr, silent)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the name of this method no longer reflects what is actually does (returns with a version number or an err). My broader concern is what I wrote above about parsing the error string, but if we decide to keep parsing the error string, we could at least rename this method to something more accurate.

@marcell-vida marcell-vida force-pushed the be-1996-nvmrc-support branch from 5edfcc6 to fa1e27f Compare March 27, 2026 14:32
@marcell-vida marcell-vida changed the title [BE-1996] Support .nvmrc version files for tool setup, fix Python and Flutter installs [BE-1996] Support .nvmrc version files for tool setup Mar 27, 2026
files := []struct {
directory string
filename string
}{{"", ".tool-versions"}, {"", ".ruby-version"}, {"", ".node-version"}, {"", ".fvmrc"}, {".fvm", "fvm_config.json"}}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to .nvmrc to this list

return nil, fmt.Errorf("read %s: %w", path, err)
}

content = bytes.TrimSpace(content)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why not use strings.TrimSpace()?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants