Skip to content

Commit 70a1387

Browse files
SONARPY-925 Fix bug when comparing semantic versions
1 parent 52dbad7 commit 70a1387

File tree

2 files changed

+60
-12
lines changed

2 files changed

+60
-12
lines changed

python-frontend/src/main/java/org/sonar/plugins/python/api/PythonVersionUtils.java

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,47 @@
3838
public class PythonVersionUtils {
3939

4040
public enum Version {
41-
V_27(2.7, "27"), V_35(3.5, "35"), V_36(3.6, "36"), V_37(3.7, "37"), V_38(3.8, "38"), V_39(3.9, "39"), V_310(3.10, "310");
41+
V_27(2, 7, "27"),
42+
V_35(3, 5, "35"),
43+
V_36(3, 6, "36"),
44+
V_37(3, 7, "37"),
45+
V_38(3, 8, "38"),
46+
V_39(3, 9, "39"),
47+
V_310(3, 10, "310");
4248

43-
private final double value;
49+
private final int major;
50+
private final int minor;
4451
private final String serializedValue;
4552

46-
Version(double value, String serializedValue) {
47-
this.value = value;
53+
Version(int major, int minor, String serializedValue) {
54+
this.major = major;
55+
this.minor = minor;
4856
this.serializedValue = serializedValue;
4957
}
5058

51-
public double value() {
52-
return value;
59+
public int major() {
60+
return major;
61+
}
62+
63+
public int minor() {
64+
return minor;
5365
}
5466

5567
public String serializedValue() {
5668
return serializedValue;
5769
}
70+
71+
public int compare(int major, int minor) {
72+
if (major() == major) {
73+
return Integer.compare(minor(), minor);
74+
}
75+
return Integer.compare(major(), major);
76+
}
77+
78+
@Override
79+
public String toString() {
80+
return major + "." + minor;
81+
}
5882
}
5983

6084
/**
@@ -112,12 +136,22 @@ public static Set<Version> allVersions() {
112136
}
113137

114138
private static boolean guessPythonVersion(Set<Version> pythonVersions, String versionValue) {
139+
String[] version = versionValue.split("\\.");
115140
try {
116-
double parsedVersion = Double.parseDouble(versionValue);
117-
if (parsedVersion < MIN_SUPPORTED_VERSION.value()) {
141+
int major = Integer.parseInt(version[0]);
142+
int minor = version.length > 1 ? Integer.parseInt(version[1]) : 0;
143+
Version guessedVersion = STRING_VERSION_MAP.get(major + "." + minor);
144+
if (guessedVersion != null) {
145+
pythonVersions.add(guessedVersion);
146+
logWarningGuessVersion(versionValue, guessedVersion);
147+
return true;
148+
}
149+
if (MIN_SUPPORTED_VERSION.compare(major, minor) > 0) {
118150
pythonVersions.add(MIN_SUPPORTED_VERSION);
119-
} else if (parsedVersion > MAX_SUPPORTED_VERSION.value()) {
151+
logWarningGuessVersion(versionValue, MIN_SUPPORTED_VERSION);
152+
} else if (MAX_SUPPORTED_VERSION.compare(major, minor) < 0) {
120153
pythonVersions.add(MAX_SUPPORTED_VERSION);
154+
logWarningGuessVersion(versionValue, MAX_SUPPORTED_VERSION);
121155
} else {
122156
logErrorMessage(versionValue);
123157
return false;
@@ -133,4 +167,9 @@ private static void logErrorMessage(String propertyValue) {
133167
String prefix = "Error while parsing value of parameter '%s' (%s). Versions must be specified as MAJOR_VERSION.MIN.VERSION (e.g. \"3.7, 3.8\")";
134168
LOG.warn(String.format(Locale.ROOT, prefix, PYTHON_VERSION_KEY, propertyValue));
135169
}
170+
171+
private static void logWarningGuessVersion(String propertyValue, Version guessedVersion) {
172+
String prefix = "No explicit support for version %s. Python version has been set to %s.";
173+
LOG.warn(String.format(Locale.ROOT, prefix, propertyValue, guessedVersion));
174+
}
136175
}

python-frontend/src/test/java/org/sonar/plugins/python/api/PythonVersionUtilsTest.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,24 @@ public void supportedVersions() {
5151

5252
@Test
5353
public void version_out_of_range() {
54-
assertThat(PythonVersionUtils.fromString("4")).containsExactlyInAnyOrder(V_39);
54+
assertThat(PythonVersionUtils.fromString("4")).containsExactlyInAnyOrder(V_310);
55+
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 4. Python version has been set to 3.10.");
5556
assertThat(PythonVersionUtils.fromString("1")).containsExactlyInAnyOrder(V_27);
57+
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 1. Python version has been set to 2.7.");
58+
assertThat(PythonVersionUtils.fromString("3.11")).containsExactlyInAnyOrder(V_310);
59+
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 3.11. Python version has been set to 3.10.");
60+
}
61+
62+
@Test
63+
public void bugfix_versions() {
64+
assertThat(PythonVersionUtils.fromString("3.8.1")).containsExactlyInAnyOrder(V_38);
65+
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 3.8.1. Python version has been set to 3.8.");
66+
assertThat(PythonVersionUtils.fromString("3.11.1")).containsExactlyInAnyOrder(V_310);
5667
}
5768

5869
@Test
5970
public void error_while_parsing_version() {
6071
assertThat(PythonVersionUtils.fromString("foo")).containsExactlyInAnyOrder(V_27, V_35, V_36, V_37, V_38, V_39, V_310);
61-
assertThat(PythonVersionUtils.fromString("3.8.1")).containsExactlyInAnyOrder(V_27, V_35, V_36, V_37, V_38, V_39, V_310);
62-
assertThat(PythonVersionUtils.fromString("3.81")).containsExactlyInAnyOrder(V_27, V_35, V_36, V_37, V_38, V_39, V_310);
6372
assertThat(logTester.logs(LoggerLevel.WARN)).contains("Error while parsing value of parameter 'sonar.python.version' (foo). Versions must be specified as MAJOR_VERSION.MIN.VERSION (e.g. \"3.7, 3.8\")");
6473
}
6574
}

0 commit comments

Comments
 (0)