Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions e2e/backend/test_dev_version_filter
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash

# Test that PEP 440 .dev versions are filtered out during fuzzy version matching
# Regression test for https://github.com/jdx/mise/discussions/8784
#
# The bug: VERSION_REGEX only catches "-dev" (hyphen) but not ".dev" (dot),
# so PEP 440 dev versions like "2026.3.3.162408.dev0" slip through the
# pre-release filter and incorrectly satisfy a request for "2026.3.3".

# Create a custom plugin that returns versions including .dev suffixes
PLUGIN_DIR="$MISE_DATA_DIR/plugins/devtest"
mkdir -p "$PLUGIN_DIR/bin"

cat <<'LISTALL' >"$PLUGIN_DIR/bin/list-all"
#!/usr/bin/env bash
echo "2026.3.2 2026.3.3.dev0 2026.3.3 2026.3.3.162408.dev0 2026.3.4.dev1"
LISTALL
chmod +x "$PLUGIN_DIR/bin/list-all"

cat <<'INSTALL' >"$PLUGIN_DIR/bin/install"
#!/usr/bin/env bash
mkdir -p "$ASDF_INSTALL_PATH/bin"
cat <<EOF >"$ASDF_INSTALL_PATH/bin/devtest"
#!/usr/bin/env bash
echo "devtest $ASDF_INSTALL_VERSION"
EOF
chmod +x "$ASDF_INSTALL_PATH/bin/devtest"
INSTALL
chmod +x "$PLUGIN_DIR/bin/install"

# Test 1: latest for "2026.3.3" should return exactly "2026.3.3", not a dev version
assert "mise latest devtest@2026.3.3" "2026.3.3"

# Test 2: latest for "2026.3" should return "2026.3.3" (highest stable), not a dev version
assert "mise latest devtest@2026.3" "2026.3.3"

# Test 3: If user explicitly requests a dev version by exact match, it should work
mise install devtest@2026.3.3.dev0
assert_contains "mise x devtest@2026.3.3.dev0 -- devtest" "2026.3.3.dev0"

# Test 4: Install stable version, then verify it resolves correctly even with
# the dev version already installed (core bug from the discussion)
mise install devtest@2026.3.3
assert_contains "mise x devtest@2026.3.3 -- devtest" "devtest 2026.3.3"
assert_not_contains "mise x devtest@2026.3.3 -- devtest" "dev0"

# Test 5: latest for a version that only has dev releases should return nothing
assert_empty "mise latest devtest@2026.3.4"
29 changes: 28 additions & 1 deletion src/plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ pub fn warn_if_env_plugin_shadows_registry(name: &str, plugin_path: &Path) {

pub static VERSION_REGEX: Lazy<regex::Regex> = Lazy::new(|| {
Regex::new(
r"(?i)(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|-test|([abc])[0-9]+|snapshot|SNAPSHOT|master)"
r"(?i)(^Available versions:|-src|[-\\.]dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|-test|([abc])[0-9]+|snapshot|SNAPSHOT|master)"
)
.unwrap()
});
Expand Down Expand Up @@ -426,4 +426,31 @@ mod tests {
_ => panic!("Expected a git plugin"),
}
}

#[test]
fn test_version_regex_filters_prerelease() {
// Standard pre-release patterns
assert!(VERSION_REGEX.is_match("1.0.0-alpha"));
assert!(VERSION_REGEX.is_match("1.0.0-beta"));
assert!(VERSION_REGEX.is_match("1.0.0-rc1"));
assert!(VERSION_REGEX.is_match("1.0.0.rc1"));
assert!(VERSION_REGEX.is_match("1.0.0-dev"));
assert!(VERSION_REGEX.is_match("1.0.0-pre1"));
assert!(VERSION_REGEX.is_match("1.0.0.pre1"));

// PEP 440 dot-separated dev versions (GitHub discussion #8784)
assert!(
VERSION_REGEX.is_match("2026.3.3.dev0"),
"PEP 440 .dev suffix should be filtered"
);
assert!(
VERSION_REGEX.is_match("2026.3.3.162408.dev0"),
"PEP 440 .dev suffix with build number should be filtered"
);

// Stable versions should NOT match
assert!(!VERSION_REGEX.is_match("1.0.0"));
assert!(!VERSION_REGEX.is_match("2026.3.3"));
assert!(!VERSION_REGEX.is_match("22.6.0"));
}
}
Loading