diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 8dfbe6ad1e..4e54f3ed6f 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -20,6 +20,7 @@ Release with new features and bugfixes: * https://github.com/devonfw/IDEasy/issues/1853[#1853]: Add ARM releases for VSCode on Mac * https://github.com/devonfw/IDEasy/issues/797[#797]: Use system unzip on macOS to preserve symlinks in ZIP extraction * https://github.com/devonfw/IDEasy/issues/1723[#1723]: Add commandlet for GitHub Copilot CLI +* https://github.com/devonfw/IDEasy/issues/1685[#1685]: Add Nest CLI to IDEasy commandlets 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]. diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java index 58e49310e6..69b23e64b8 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java @@ -42,6 +42,7 @@ import com.devonfw.tools.ide.tool.kubectl.KubeCtl; import com.devonfw.tools.ide.tool.lazydocker.LazyDocker; import com.devonfw.tools.ide.tool.mvn.Mvn; +import com.devonfw.tools.ide.tool.nest.Nest; import com.devonfw.tools.ide.tool.ng.Ng; import com.devonfw.tools.ide.tool.node.Node; import com.devonfw.tools.ide.tool.npm.Npm; @@ -154,6 +155,7 @@ public CommandletManagerImpl(IdeContext context) { add(new Go(context)); add(new Gui(context)); add(new SquirrelSql(context)); + add(new Nest(context)); } /** diff --git a/cli/src/main/java/com/devonfw/tools/ide/common/Tag.java b/cli/src/main/java/com/devonfw/tools/ide/common/Tag.java index 6ae92c6e0b..559259eae4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/common/Tag.java +++ b/cli/src/main/java/com/devonfw/tools/ide/common/Tag.java @@ -329,6 +329,9 @@ public final class Tag { /** {@link #Tag} for encryption. */ public static final Tag ENCRYPTION = create("encryption", CRYPTO); + /** {@link Tag} for Nest. */ + public static final Tag NEST = create("nest", FRAMEWORK, false, new String[] { "nestjs", "nestcli" }, TYPE_SCRIPT); + private final String id; private final Tag parent; diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java index 10769d760e..126e538d7a 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java @@ -185,10 +185,18 @@ protected final void performToolInstallation(ToolInstallRequest request, Path in PackageManagerRequest packageManagerRequest = new PackageManagerRequest(PackageManagerRequest.TYPE_INSTALL, getPackageName()) .setProcessContext(request.getProcessContext()).setVersion(request.getRequested().getResolvedVersion()); - runPackageManager(packageManagerRequest, true).failOnError(); + runPackageManager(packageManagerRequest, isSkipInstallation()).failOnError(); this.installedVersion.invalidate(); } + /** + * @return {@code false} if the underlying {@link #getPackageManagerClass() package manager} should also be installed, {@code false} to skip that additional installation (e.g. to prevent infinite loop in case of cyclic + * dependencies between package manager based tools such as node and npm). + */ + protected boolean isSkipInstallation() { + return false; + } + /** * @return {@code true} if the tool can be uninstalled, {@code false} if not. */ diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/nest/Nest.java b/cli/src/main/java/com/devonfw/tools/ide/tool/nest/Nest.java new file mode 100644 index 0000000000..30ad153999 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/nest/Nest.java @@ -0,0 +1,30 @@ +package com.devonfw.tools.ide.tool.nest; + +import java.util.Set; + +import com.devonfw.tools.ide.common.Tag; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.ToolCommandlet; +import com.devonfw.tools.ide.tool.npm.NpmBasedCommandlet; + +/** + * {@link ToolCommandlet} for Nest CLI. + */ +public class Nest extends NpmBasedCommandlet { + + /** + * The constructor. + * + * @param context the {@link IdeContext}. + */ + public Nest(IdeContext context) { + + super(context, "nest", Set.of(Tag.NEST, Tag.BUILD)); + } + + @Override + public String getPackageName() { + + return "@nestjs/cli"; + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/npm/Npm.java b/cli/src/main/java/com/devonfw/tools/ide/tool/npm/Npm.java index 7dae4eb1c4..48079f01c2 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/npm/Npm.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/npm/Npm.java @@ -46,6 +46,11 @@ public String getToolHelpArguments() { return "help"; } + @Override + protected boolean isSkipInstallation() { + return true; + } + /** * @return the {@link Path} to the npm user configuration file, creates the folder and configuration file if it was not existing. */ diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index 1b8505d864..9f5dd711bd 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -81,6 +81,8 @@ cmd.list-versions=List the available versions of the selected tool. cmd.list-versions.detail=To list all available versions of e.g. 'intellij' simply type: 'ide list-versions intellij'. cmd.mvn=Tool commandlet for Maven (Build-Tool). cmd.mvn.detail=Apache Maven is a build automation and dependency management tool for Java projects. Detailed documentation can be found at https://maven.apache.org/guides/index.html +cmd.nest=Tool commandlet for Nest CLI. +cmd.nest.detail=The Nest CLI is a command-line interface tool that helps you to initialize, develop, and maintain your Nest applications. Detailed documentation can be found at https://docs.nestjs.com/cli/overview cmd.ng=Tool commandlet for Angular CLI. cmd.ng.detail=Angular is a web framework that empowers developers to build fast, reliable applications. Detailed documentation can be found at https://angular.dev/overview/. cmd.node=Tool commandlet for Node.js (JavaScript runtime). diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties index dfcc22c285..a90b64bc66 100644 --- a/cli/src/main/resources/nls/Help_de.properties +++ b/cli/src/main/resources/nls/Help_de.properties @@ -81,6 +81,8 @@ cmd.list-versions=Listet die verfügbaren Versionen des selektierten Werkzeugs a cmd.list-versions.detail=Um alle verfügbaren Versionen von z.B. 'intellij' aufzulisten, geben Sie einfach 'ide list-versions intellij' in die Konsole ein. cmd.mvn=Werkzeug Kommando für Maven (Build-Werkzeug). cmd.mvn.detail=Apache Maven ist ein Build-Automatisierungs- und Abhängigkeitsverwaltungstool für Java-Projekte. Detaillierte Dokumentation ist zu finden unter https://maven.apache.org/guides/index.html +cmd.nest=Werkzeug Kommando für Nest CLI. +cmd.nest.detail=Die Nest CLI ist ein Command‑Line‑Interface‑Tool zur Initialisierung, Entwicklung und Wartung von Nest‑Anwendungen. Detaillierte Dokumentation ist zu finden unter https://docs.nestjs.com/cli/overview cmd.ng=Werkzeug Kommando für Angular CLI. cmd.ng.detail=Angular ist ein web framework dass Entwicklern die Möglichkeit bietet, schnelle und zuverlässige Anwendungen zu entwickeln. Detaillierte Dokumentation ist zu finden unter https://angular.dev/overview/. cmd.node=Werkzeug Kommando für Node.js (JavaScript Laufzeitumgebung). diff --git a/cli/src/test/integration-tests/install-nest.sh b/cli/src/test/integration-tests/install-nest.sh new file mode 100644 index 0000000000..ad5f9654ab --- /dev/null +++ b/cli/src/test/integration-tests/install-nest.sh @@ -0,0 +1,13 @@ +echo "Running install nest integration test" +ide -d install nest + +nest_location="" + +if doIsWindows +then + nest_location="" +else + nest_location="bin/" +fi + +assertThat "${IDE_ROOT}/${TEST_PROJECT_NAME}/software/node/${nest_location}nest" exists diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/nest/NestTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/nest/NestTest.java new file mode 100644 index 0000000000..87f51b171f --- /dev/null +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/nest/NestTest.java @@ -0,0 +1,91 @@ +package com.devonfw.tools.ide.tool.nest; + +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; + +/** + * Test of {@link Nest}. + */ +@WireMockTest +class NestTest extends AbstractIdeContextTest { + + private static final String PROJECT_NEST = "nest"; + + /** + * Tests if the {@link Nest} install works correctly. + * + * @param wireMockRuntimeInfo wireMock server on a random port + */ + @Test + void testNestInstall(WireMockRuntimeInfo wireMockRuntimeInfo) { + + // arrange + IdeTestContext context = newContext(PROJECT_NEST, wireMockRuntimeInfo); + Nest commandlet = new Nest(context); + + // act + commandlet.install(); + + // assert + checkInstallation(context); + + } + + /** + * Tests if the {@link Nest} install works correctly. + * + * @param wireMockRuntimeInfo wireMock server on a random port + */ + @Test + void testNestUninstall(WireMockRuntimeInfo wireMockRuntimeInfo) { + + // arrange + IdeTestContext context = newContext(PROJECT_NEST, wireMockRuntimeInfo); + Nest commandlet = new Nest(context); + + // act I + commandlet.install(); + + // assert I + checkInstallation(context); + + // act II + commandlet.uninstall(); + + // assert II + assertThat(context).logAtInfo().hasMessageContaining("npm uninstall -g @nestjs/cli"); + + assertThat(context).logAtSuccess().hasMessage("Successfully uninstalled nest"); + } + + /** + * Tests if {@link Nest} run works correctly. + * + * @param wireMockRuntimeInfo wireMock server on a random port + */ + @Test + void testNestRun(WireMockRuntimeInfo wireMockRuntimeInfo) { + + // arrange + IdeTestContext context = newContext(PROJECT_NEST, wireMockRuntimeInfo); + Nest commandlet = new Nest(context); + commandlet.arguments.setValue("--version"); + + // act + commandlet.run(); + + // assert + assertThat(context).logAtInfo().hasMessageContaining("nest --version"); + } + + private void checkInstallation(IdeTestContext context) { + + assertThat(context).logAtInfo().hasMessageContaining("npm install -gf @nestjs/cli@11.0.21"); + + assertThat(context).logAtSuccess().hasMessageContaining("Successfully installed nest in version 11.0.21"); + } +} diff --git a/cli/src/test/resources/ide-projects/nest/_ide/urls/node/node/v18.19.1/urls b/cli/src/test/resources/ide-projects/nest/_ide/urls/node/node/v18.19.1/urls new file mode 100644 index 0000000000..a07d5a1205 --- /dev/null +++ b/cli/src/test/resources/ide-projects/nest/_ide/urls/node/node/v18.19.1/urls @@ -0,0 +1 @@ +${testbaseurl}/download/node/node/v18.19.1/node-v18.19.1.tgz diff --git a/cli/src/test/resources/ide-projects/nest/_ide/urls/npm/npm/dependencies.json b/cli/src/test/resources/ide-projects/nest/_ide/urls/npm/npm/dependencies.json new file mode 100644 index 0000000000..b84a1b86c9 --- /dev/null +++ b/cli/src/test/resources/ide-projects/nest/_ide/urls/npm/npm/dependencies.json @@ -0,0 +1,8 @@ +{ + "[9.0, 10.0)": [ + { + "tool": "node", + "versionRange": "[18.0.0,)" + } + ] +} diff --git a/cli/src/test/resources/ide-projects/nest/project/home/.ide/ide.properties b/cli/src/test/resources/ide-projects/nest/project/home/.ide/ide.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/src/test/resources/ide-projects/nest/project/settings/ide.properties b/cli/src/test/resources/ide-projects/nest/project/settings/ide.properties new file mode 100644 index 0000000000..77fba82c0e --- /dev/null +++ b/cli/src/test/resources/ide-projects/nest/project/settings/ide.properties @@ -0,0 +1,3 @@ +NODE_VERSION=v18.19.1 +NPM_VERSION=9.9.2 +NEST_VERSION=11.0.21 diff --git a/cli/src/test/resources/ide-projects/nest/project/workspaces/main/.gitkeep b/cli/src/test/resources/ide-projects/nest/project/workspaces/main/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/src/test/resources/ide-projects/nest/repository/node/node/default/nest b/cli/src/test/resources/ide-projects/nest/repository/node/node/default/nest new file mode 100755 index 0000000000..6a41fc7994 --- /dev/null +++ b/cli/src/test/resources/ide-projects/nest/repository/node/node/default/nest @@ -0,0 +1,2 @@ +#!/bin/bash +echo "nest $*" diff --git a/cli/src/test/resources/ide-projects/nest/repository/node/node/default/npm b/cli/src/test/resources/ide-projects/nest/repository/node/node/default/npm new file mode 100755 index 0000000000..ee633ea32e --- /dev/null +++ b/cli/src/test/resources/ide-projects/nest/repository/node/node/default/npm @@ -0,0 +1,6 @@ +#!/bin/bash +if [ "$1" == "--version" ]; then + echo "9.9.2" + exit +fi +echo "npm $*" diff --git a/cli/src/test/resources/ide-projects/nest/repository/node/node/default/npx b/cli/src/test/resources/ide-projects/nest/repository/node/node/default/npx new file mode 100755 index 0000000000..0723c2041b --- /dev/null +++ b/cli/src/test/resources/ide-projects/nest/repository/node/node/default/npx @@ -0,0 +1,2 @@ +#!/bin/bash +echo "npx $*" diff --git a/cli/src/test/resources/ide-projects/nest/repository/npmjs/@nest/cli.json b/cli/src/test/resources/ide-projects/nest/repository/npmjs/@nest/cli.json new file mode 100644 index 0000000000..fd621c4c96 --- /dev/null +++ b/cli/src/test/resources/ide-projects/nest/repository/npmjs/@nest/cli.json @@ -0,0 +1,10 @@ +{ + "versions": { + "11.0.21": { + "version": "11.0.21", + "dist": { + "tarball": "${testbaseurl}/@nestjs/-/cli-11.0.21.tgz" + } + } + } +} diff --git a/documentation/LICENSE.adoc b/documentation/LICENSE.adoc index a84f3c7ccc..c1c5c60664 100644 --- a/documentation/LICENSE.adoc +++ b/documentation/LICENSE.adoc @@ -103,6 +103,7 @@ The column `inclusion` indicates the way the component is included: |https://docs.astral.sh/uv/[uv] |Optional|https://docs.astral.sh/uv/reference/policies/license/[Apache 2.0] |https://github.com/openjdk/jfx[OpenJFX] |Optional|https://github.com/openjdk/jfx/blob/master/LICENSE[GPLv2] (with the “Classpath” Exception) |https://squirrel-sql.sourceforge.io/[SQuirreL SQL Client]|Optional|https://github.com/squirrel-sql-client/squirrel-sql-stable-releases/blob/main/LICENSE[LGPL 2.1] +|https://docs.nestjs.com/cli/overview[NestJS CLI] |Optional|https://github.com/nestjs/nest-cli/blob/master/LICENSE[MIT License] |=== == Apache Software License - Version 2.0 diff --git a/url-updater/src/main/java/com/devonfw/tools/ide/url/updater/UpdateManager.java b/url-updater/src/main/java/com/devonfw/tools/ide/url/updater/UpdateManager.java index 5dc08f8e7a..fcadcb2121 100644 --- a/url-updater/src/main/java/com/devonfw/tools/ide/url/updater/UpdateManager.java +++ b/url-updater/src/main/java/com/devonfw/tools/ide/url/updater/UpdateManager.java @@ -4,8 +4,6 @@ import java.time.Instant; import java.util.List; -import com.devonfw.tools.ide.url.tool.java.JavaAzulUrlUpdater; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,6 +30,7 @@ import com.devonfw.tools.ide.url.tool.helm.HelmUrlUpdater; import com.devonfw.tools.ide.url.tool.intellij.IntellijUrlUpdater; import com.devonfw.tools.ide.url.tool.jasypt.JasyptUrlUpdater; +import com.devonfw.tools.ide.url.tool.java.JavaAzulUrlUpdater; import com.devonfw.tools.ide.url.tool.java.JavaUrlUpdater; import com.devonfw.tools.ide.url.tool.jenkins.JenkinsUrlUpdater; import com.devonfw.tools.ide.url.tool.jmc.JmcUrlUpdater; @@ -69,7 +68,8 @@ public class UpdateManager extends AbstractProcessorWithTimeout { private final UrlFinalReport urlFinalReport; private final List updaters = List.of( - new AndroidStudioUrlUpdater(), new AwsUrlUpdater(), new AzureUrlUpdater(), new CopilotUrlUpdater(), new CorepackUrlUpdater(), new DockerDesktopUrlUpdater(), + new AndroidStudioUrlUpdater(), new AwsUrlUpdater(), new AzureUrlUpdater(), new CopilotUrlUpdater(), new CorepackUrlUpdater(), + new DockerDesktopUrlUpdater(), new DotNetUrlUpdater(), new EclipseCppUrlUpdater(), new EclipseJeeUrlUpdater(), new EclipseJavaUrlUpdater(), new GCloudUrlUpdater(), new GcViewerUrlUpdater(), new GhUrlUpdater(), new GoUrlUpdater(), new GraalVmCommunityUpdater(), new GraalVmOracleUrlUpdater(), @@ -77,7 +77,8 @@ public class UpdateManager extends AbstractProcessorWithTimeout { new JavaUrlUpdater(), new JavaAzulUrlUpdater(), new JenkinsUrlUpdater(), new JmcUrlUpdater(), new KotlincUrlUpdater(), new KotlincNativeUrlUpdater(), new LazyDockerUrlUpdater(), new MvnUrlUpdater(), new NgUrlUpdater(), new NodeUrlUpdater(), new NpmUrlUpdater(), new OcUrlUpdater(), new PgAdminUrlUpdater(), new PipUrlUpdater(), new PycharmUrlUpdater(), - new PythonUrlUpdater(), new QuarkusUrlUpdater(), new RustUrlUpdater(), new DockerRancherDesktopUrlUpdater(), new SonarUrlUpdater(), new SquirrelSqlUrlUpdater(), + new PythonUrlUpdater(), new QuarkusUrlUpdater(), new RustUrlUpdater(), new DockerRancherDesktopUrlUpdater(), new SonarUrlUpdater(), + new SquirrelSqlUrlUpdater(), new TerraformUrlUpdater(), new TomcatUrlUpdater(), new UvUrlUpdater(), new VsCodeUrlUpdater()); /**