Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Release with new features and bugfixes:
* https://github.com/devonfw/IDEasy/issues/1904[#1904]: Add Inso CLI to IDEasy commandlets
* https://github.com/devonfw/IDEasy/issues/1952[#1952]: Ability for platform specific dependencies
* https://github.com/devonfw/IDEasy/issues/1950[#1950]: Fix exit autocompletion
* https://github.com/devonfw/IDEasy/issues/1255[#1255]: Enhance snapshot version recognition in IDEasy

The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/44?closed=1[milestone 2026.05.001].

Expand Down
80 changes: 73 additions & 7 deletions cli/src/main/java/com/devonfw/tools/ide/tool/IdeasyCommandlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -71,6 +73,25 @@ public class IdeasyCommandlet extends MvnBasedLocalToolCommandlet {

private final UpgradeMode mode;

/** Pattern for IDEasy SNAPSHOT versions built locally. */
private static final Pattern PATTERN_IDEASY_SNAPSHOT_VERSION = Pattern.compile("^(\\d{4}\\.\\d{2}\\.\\d{3})-(\\d{2})_(\\d{2})_(\\d{2}).*-SNAPSHOT$");

/** Pattern for Maven/Nexus SNAPSHOT versions from downloads . */
private static final Pattern PATTERN_MAVEN_SNAPSHOT_VERSION = Pattern.compile("^(\\d{4}\\.\\d{2}\\.\\d{3})-(\\d{4})(\\d{2})(\\d{2})\\.(\\d{2})\\d{4}.*$");

// Group numbers for PATTERN_IDEASY_SNAPSHOT_VERSION
private static final int GROUP_IDEASY_BASE = 1;
private static final int GROUP_IDEASY_MONTH = 2;
private static final int GROUP_IDEASY_DAY = 3;
private static final int GROUP_IDEASY_HOUR = 4;

// Group numbers for PATTERN_MAVEN_SNAPSHOT_VERSION
private static final int GROUP_MAVEN_BASE = 1;
private static final int GROUP_MAVEN_YEAR = 2;
private static final int GROUP_MAVEN_MONTH = 3;
private static final int GROUP_MAVEN_DAY = 4;
private static final int GROUP_MAVEN_HOUR = 5;

/**
* The constructor.
*
Expand Down Expand Up @@ -178,15 +199,60 @@ public boolean checkIfUpdateIsAvailable() {
return false;
}
VersionIdentifier latestVersion = getLatestVersion();
if (installedVersion.equals(latestVersion)) {
IdeLogLevel.SUCCESS.log(LOG, "Your are using the latest version of IDEasy and no update is available.");
if (IdeVersion.isSnapshot()) {
if (isSameSnapshotVersion(installedVersion.toString(), latestVersion.toString())) {
IdeLogLevel.SUCCESS.log(LOG, "Your are using the latest snapshot version of IDEasy and no update is available.");
return false;
}
} else if (installedVersion.equals(latestVersion)) {
IdeLogLevel.SUCCESS.log(LOG, "Your are using the latest stable version of IDEasy and no update is available.");
return false;
} else {
IdeLogLevel.INTERACTION.log(LOG,
"Your version of IDEasy is {} but version {} is available. Please run the following command to upgrade to the latest version:\n"
+ "ide upgrade", installedVersion, latestVersion);
return true;
}
IdeLogLevel.INTERACTION.log(LOG,
"Your version of IDEasy is {} but version {} is available. Please run the following command to upgrade to the latest version:\n"
+ "ide upgrade", installedVersion, latestVersion);
return true;
}

/**
* Checks if two snapshot versions represent the version
*
* @param installed the installed version string
* @param latest the latest available version string
* @return {@code true} if both versions represent the same version, {@code false} otherwise.
*/
private boolean isSameSnapshotVersion(String installed, String latest) {
if (installed == null || latest == null) {
return false;
}

Matcher installedMatcher = PATTERN_IDEASY_SNAPSHOT_VERSION.matcher(installed);
Matcher latestMatcher = PATTERN_MAVEN_SNAPSHOT_VERSION.matcher(latest);

if (!installedMatcher.matches() || !latestMatcher.matches()) {
return false;
}

// Compare base versions
String baseInstalled = installedMatcher.group(GROUP_IDEASY_BASE);
String baseLatest = latestMatcher.group(GROUP_MAVEN_BASE);
if (!baseInstalled.equals(baseLatest)) {
return false;
}

// Compare year
String yearLatest = latestMatcher.group(GROUP_MAVEN_YEAR);
String baseYear = baseInstalled.split("\\.")[0];
if (!baseYear.equals(yearLatest)) {
return false;
}

// Compare MMDD.HH for both versions
String keyInstalled =
installedMatcher.group(GROUP_IDEASY_MONTH) + installedMatcher.group(GROUP_IDEASY_DAY) + "." + installedMatcher.group(GROUP_IDEASY_HOUR);
String keyLatest = latestMatcher.group(GROUP_MAVEN_MONTH) + latestMatcher.group(GROUP_MAVEN_DAY) + "." + latestMatcher.group(GROUP_MAVEN_HOUR);

return keyInstalled.equals(keyLatest);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.devonfw.tools.ide.os.SystemInfoMock;
import com.devonfw.tools.ide.os.WindowsHelper;
import com.devonfw.tools.ide.os.WindowsPathSyntax;
import com.devonfw.tools.ide.version.VersionIdentifier;

/**
* Test of {@link IdeasyCommandlet}.
Expand Down Expand Up @@ -155,6 +156,66 @@ void testInstallIdeasyTwiceDoesNotDuplicateGitLongpaths() {
assertThat(gitconfigPath).content().doesNotContain("longpaths = false");
}

/**
* Test of {@link IdeasyCommandlet#checkIfUpdateIsAvailable()} with same snapshot versions.
*/
@Test
void testCheckIfUpdateIsAvailableWithSameSnapshotVersions() {

// arrange
IdeTestContext context = newContext("install");
context.getStartContext().setOfflineMode(false);
IdeasyCommandlet ideasy = new IdeasyCommandlet(context) {
@Override
public VersionIdentifier getInstalledVersion() {
return VersionIdentifier.of("2025.04.002-04_17_02-SNAPSHOT");
}

@Override
public VersionIdentifier getLatestVersion() {
return VersionIdentifier.of("2025.04.002-20250417.024201-5");
}
};

// act
boolean updateAvailable = ideasy.checkIfUpdateIsAvailable();

// assert
assertThat(updateAvailable).isFalse();
assertThat(context).logAtSuccess().hasMessage("Your are using the latest snapshot version of IDEasy and no update is available.");
}

/**
* Test of {@link IdeasyCommandlet#checkIfUpdateIsAvailable()} with different snapshot versions.
*/
@Test
void testCheckIfUpdateIsAvailableWithDifferentSnapshotVersions() {

// arrange
IdeTestContext context = newContext("install");
context.getStartContext().setOfflineMode(false);
IdeasyCommandlet ideasy = new IdeasyCommandlet(context) {
@Override
public VersionIdentifier getInstalledVersion() {
return VersionIdentifier.of("2025.04.002-04_17_02-SNAPSHOT");
}

@Override
public VersionIdentifier getLatestVersion() {
return VersionIdentifier.of("2026.05.001-20260519.032313-17");
}
};

// act
boolean updateAvailable = ideasy.checkIfUpdateIsAvailable();

// assert
assertThat(updateAvailable).isTrue();
assertThat(context).logAtInteraction()
.hasMessageContaining("version 2026.05.001-20260519.032313-17 is available. Please run the following command to upgrade to the latest version:\n"
+ "ide upgrade");
}

private void verifyInstallation(Path installationPath) {

assertThat(installationPath).isDirectory();
Expand Down
Loading