Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This file documents all notable changes to https://github.com/devonfw/IDEasy[IDE

Release with new features and bugfixes:

* https://github.com/devonfw/IDEasy/issues/1987[#1987]: Fixed issue that the GUI would not launch in SNAPSHOT versions. Added -l flag to allow extended logging for the GUI.

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

Expand Down
30 changes: 24 additions & 6 deletions cli/src/main/java/com/devonfw/tools/ide/tool/gui/Gui.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import com.devonfw.tools.ide.commandlet.Commandlet;
import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.process.ProcessContext;
import com.devonfw.tools.ide.process.ProcessContextImpl;
import com.devonfw.tools.ide.process.ProcessMode;
import com.devonfw.tools.ide.property.FlagProperty;
import com.devonfw.tools.ide.tool.ToolEditionAndVersion;
import com.devonfw.tools.ide.tool.ToolInstallRequest;
import com.devonfw.tools.ide.tool.ToolInstallation;
Expand All @@ -27,13 +27,16 @@ public class Gui extends Commandlet {

private static final Logger LOG = LoggerFactory.getLogger(Gui.class);

final FlagProperty enableExtendedLogging;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Other commandlet property fields are declared public final (see e.g. AbstractUpdateCommandlet, CreateCommandlet). For consistency:

Suggested change
final FlagProperty enableExtendedLogging;
/** {@link FlagProperty} to enable logging of the GUI process to the terminal. */
public final FlagProperty enableExtendedLogging;


/**
* @param context the {@link IdeContext}.
*/
public Gui(IdeContext context) {

super(context);
addKeyword(getName());
enableExtendedLogging = add(new FlagProperty("--enableLogging", false, "-l"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For logging we already have properties like --debug or --trace, etc.
Further, don't use --pascalCase for CLI options but --train-case instead following POSIX and GNU standards.

After reading the code, I figured out that the property is actually changing the process mode and enforces that we do not run in background.
I would therefore completely rename the property and option to something like --foreground if you want to keep it explicit. If you think this is more related to the logging, then I would not add a new property at all but just trigger the feature when loglevel is DEBUG or below (--debug or --trace).

Suggested change
enableExtendedLogging = add(new FlagProperty("--enableLogging", false, "-l"));
this.enableExtendedLogging = add(new FlagProperty("--enable-logging", false, "-l"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

BTW: For such special flags avoid adding short options like -l this will easily conflict with other global flags that we might want to introduce later.

}

@Override
Expand All @@ -45,7 +48,7 @@ public String getName() {
@Override
protected void doRun() {

ProcessContext processContext = new ProcessContextImpl(this.context);
ProcessContext processContext = context.newProcess();

Java java = this.context.getCommandletManager().getCommandlet(Java.class);
Mvn mvn = this.context.getCommandletManager().getCommandlet(Mvn.class);
Expand All @@ -58,9 +61,16 @@ protected void doRun() {
new ToolEditionAndVersion(VersionIdentifier.of("25.*"))
);

mvn.installTool(mavenToolInstallRequest);
ToolInstallation mvnToolInstallation = mvn.installTool(mavenToolInstallRequest);
ToolInstallation javaInstallation = java.installTool(javaToolInstallRequest);

/* Register the freshly installed mvn on the IDEasy managed PATH so that the IDEasy controlled maven is used to launch
the GUI instead of any maven that happens to be on the system PATH. We install via installTool (software repository
only) and therefore have to register the bin directory ourselves (install() would normally do this). I tried to achieve this alternatively via .withPathEntry(), however, this did not work as expected.
This was tested on a Mac; potentially, withPathVariable() works correctly on Windows.
*/
Comment on lines +67 to +71

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Per the Code-Documentation conventions, implementation comments should factually explain the why. This drops the first-person/speculative wording and wraps the long line to match the rest of the file:

Suggested change
/* Register the freshly installed mvn on the IDEasy managed PATH so that the IDEasy controlled maven is used to launch
the GUI instead of any maven that happens to be on the system PATH. We install via installTool (software repository
only) and therefore have to register the bin directory ourselves (install() would normally do this). I tried to achieve this alternatively via .withPathEntry(), however, this did not work as expected.
This was tested on a Mac; potentially, withPathVariable() works correctly on Windows.
*/
/*
* Register the freshly installed mvn on the IDEasy-managed PATH so the IDEasy-controlled maven (from the software
* repository) launches the GUI instead of any maven on the system PATH. installTool only installs into the software
* repository, so we register the bin directory here (install() would normally do this).
*/

context.getPath().setPath(mvn.getName(), mvnToolInstallation.binDir());

LOG.debug("Starting GUI via commandlet");

Path pomPath = context.getIdeInstallationPath().resolve("gui/pom.xml");
Expand All @@ -69,9 +79,10 @@ protected void doRun() {
}

List<String> args = List.of(
"-f",
"-U", //required for latest snapshot versions
"-f", //use specified POM file
pomPath.toString(),
"exec:exec",
"org.codehaus.mojo:exec-maven-plugin:3.1.0:exec",
"-Dexec.executable=java",
"-Dexec.classpathScope=compile",
"-Dexec.args=-classpath %classpath com.devonfw.ide.gui.AppLauncher"
Expand All @@ -81,6 +92,13 @@ protected void doRun() {
* We manually update the PATH entry with our java version, as by default IDEasy includes the SymLink under /projectname/software/java/bin in the PATH
* In case of projects using older Java Versions, this is important as the java version of the project could potentially older.
*/
mvn.runTool(processContext.withPathEntry(javaInstallation.binDir()), ProcessMode.BACKGROUND_SILENT, args);
ProcessMode processMode = this.enableExtendedLogging.isTrue() ? ProcessMode.DEFAULT : ProcessMode.BACKGROUND_SILENT;
try {
mvn.runTool(processContext.withPathEntry(javaInstallation.binDir()), processMode, args);
} catch (Exception e) {
LOG.error(
"Failed to launch the GUI. If maven states issues with dependency resolution, check whether the maven M2 repo is enabled in your project.",
e);
}
Comment on lines +96 to +102

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As written, any failure is logged and then swallowed, so ide gui exits successfully even when the GUI never launched. Wrapping-and-rethrowing keeps your hint but surfaces the failure to the caller (and narrows the catch to RuntimeException):

Suggested change
try {
mvn.runTool(processContext.withPathEntry(javaInstallation.binDir()), processMode, args);
} catch (Exception e) {
LOG.error(
"Failed to launch the GUI. If maven states issues with dependency resolution, check whether the maven M2 repo is enabled in your project.",
e);
}
try {
mvn.runTool(processContext.withPathEntry(javaInstallation.binDir()), processMode, args);
} catch (RuntimeException e) {
throw new CliException(
"Failed to launch the GUI. If maven reports issues with dependency resolution, check whether the maven M2 repo is enabled in your project.", e);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Instead of adding an extra option flag or a log-level based hack - can't we always run maven in foreground but tell it to run exec in background so we get logs and errors if maven cannot launch the GUI, but the GUI will still not block the active terminal when started?
Would IMHO be the real and clean solution:
https://www.mojohaus.org/exec-maven-plugin/exec-mojo.html#async

BTW: All this feature about foreground vs. background is not related to the bugfix that snapshots cannot open GUI. It is easier to create two separate issues and according PRs. Maybe then we could already merge the snapshot bugfix and include it into the current release while now the PR is stuck.

}
}
16 changes: 15 additions & 1 deletion cli/src/main/package/gui/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<repositories>
<repository>
<id>ossrh</id>
<name>OSSRH Snapshots</name>
<url>https://central.sonatype.com/repository/maven-snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>

<groupId>com.devonfw.tools.IDEasy</groupId>
<artifactId>ide-gui-launcher</artifactId>
<version>$[project.version]</version>
Expand All @@ -17,5 +32,4 @@
<version>$[project.version]</version>
</dependency>
</dependencies>

</project>
1 change: 1 addition & 0 deletions cli/src/main/resources/nls/Help.properties
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ cmd.gradle=Tool commandlet for Gradle (Build-Tool).
cmd.gradle.detail=Gradle is a build automation tool for Java, Kotlin, and other JVM-based languages. Detailed documentation can be found at https://docs.gradle.org/
cmd.gui=Tool commandlet for running the IDEasy GUI
cmd.gui.detail=This command will run the GUI version of IDEasy, opening up a more comprehensible project dashboard and allowing for easier management of your local IDEasy instance.
cmd.gui.opt.--enableLogging=Run the GUI with enabled logging to the terminal.
cmd.helm=Tool commandlet for Helm (Kubernetes Package Manager).
cmd.helm.detail=Helm is a package manager for Kubernetes that simplifies deploying and managing applications. Detailed documentation can be found at https://helm.sh/docs/
cmd.help=Prints this help.
Expand Down
1 change: 1 addition & 0 deletions cli/src/main/resources/nls/Help_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ cmd.gradle=Werkzeug Kommando für Gradle (Build-Tool).
cmd.gradle.detail=Gradle ist ein Build-Automatisierungstool für Java, Kotlin und andere JVM-basierte Sprachen. Detaillierte Dokumentation ist zu finden unter https://docs.gradle.org/
cmd.gui=Werkzeug Kommando, um die GUI von IDEasy zu öffnen.
cmd.gui.detail=Dieser Befehl startet die GUI-Version von IDEasy, öffnet ein übersichtlicheres Projekt-Dashboard und erleichtert die Verwaltung Ihrer lokalen IDEasy-Instanz.
cmd.gui.opt.--enableLogging=Führe die GUI mit aktiviertem Debug-Logging auf das Terminal aus.
cmd.helm=Werkzeug Kommando für Helm (Kubernetes Package Manager).
cmd.helm.detail=Helm ist ein Paketmanager für Kubernetes, der das Bereitstellen und Verwalten von Anwendungen vereinfacht. Detaillierte Dokumentation ist zu finden unter https://helm.sh/docs/
cmd.help=Zeigt diese Hilfe an.
Expand Down
45 changes: 45 additions & 0 deletions cli/src/test/java/com/devonfw/tools/ide/tool/gui/GuiTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.devonfw.tools.ide.tool.gui;

import org.junit.jupiter.api.Test;

import com.devonfw.tools.ide.context.AbstractIdeContextTest;
import com.devonfw.tools.ide.context.IdeTestContext;
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;

/**
* Tests for {@link Gui}.
*/
@WireMockTest
class GuiTest extends AbstractIdeContextTest {

private static final String PROJECT_GUI = "gui";

@Test
void testEnableLoggingUsesDefaultProcessMode(WireMockRuntimeInfo wmRuntimeInfo) {
// arrange
IdeTestContext context = newContext(PROJECT_GUI, wmRuntimeInfo);
Gui gui = new Gui(context);
gui.enableExtendedLogging.setValue(true);

// act
gui.run();

// assert: with ProcessMode.DEFAULT, process output is captured as INFO log
assertThat(context).logAtInfo().hasMessage("Scanning for projects...");
}

@Test
void testDisabledLoggingUsesBackgroundSilentMode(WireMockRuntimeInfo wmRuntimeInfo) {
// arrange
IdeTestContext context = newContext(PROJECT_GUI, wmRuntimeInfo);
Gui gui = new Gui(context);
// enableExtendedLogging is false by default → ProcessMode.BACKGROUND_SILENT

// act
gui.run();

// assert: with ProcessMode.BACKGROUND_SILENT, process output is suppressed
assertThat(context).logAtInfo().hasNoMessage("Scanning for projects...");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<PlaceholderFile/>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
${testbaseurl}/download/java/java/25.0.2/java-25.0.2.tgz
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
${testbaseurl}/download/mvn/mvn/3.9.0/mvn-3.9.0.tgz
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MAVEN_VERSION=3.9.0
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
echo java $*
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
echo "Scanning for projects..."
Loading