diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 8237e2c626..2475adff3a 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -5,7 +5,8 @@ This file documents all notable changes to https://github.com/devonfw/IDEasy[IDE == 2026.07.001 Release with new features and bugfixes: - +* https://github.com/devonfw/IDEasy/issues/1943[#1943]: Create ruby commandlet +* https://github.com/devonfw/IDEasy/issues/1942[#1942]: Create ruby url updater * https://github.com/devonfw/IDEasy/issues/1063[#1063]: Improve IDEasy user specific configuration documentation * https://github.com/devonfw/IDEasy/issues/1909[#1909]: add commandlet for Maven Daemon * https://github.com/devonfw/IDEasy/issues/2068[#2068]: Isolate Claude Code configuration per IDEasy project 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 580534f0f7..08103f9dc9 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 @@ -58,6 +58,7 @@ import com.devonfw.tools.ide.tool.pycharm.Pycharm; import com.devonfw.tools.ide.tool.python.Python; import com.devonfw.tools.ide.tool.quarkus.Quarkus; +import com.devonfw.tools.ide.tool.ruby.Ruby; import com.devonfw.tools.ide.tool.rust.Rust; import com.devonfw.tools.ide.tool.sonar.Sonar; import com.devonfw.tools.ide.tool.spring.Spring; @@ -138,6 +139,7 @@ public CommandletManagerImpl(IdeContext context) { add(new Terraform(context)); add(new Oc(context)); add(new Quarkus(context)); + add(new Ruby(context)); add(new Rust(context)); add(new Kotlinc(context)); add(new KotlincNative(context)); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ruby/Ruby.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ruby/Ruby.java new file mode 100644 index 0000000000..10873b10a0 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ruby/Ruby.java @@ -0,0 +1,30 @@ +package com.devonfw.tools.ide.tool.ruby; + +import java.util.Set; + +import com.devonfw.tools.ide.common.Tag; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; +import com.devonfw.tools.ide.tool.ToolCommandlet; + +/** + * {@link ToolCommandlet} for Ruby. + */ +public class Ruby extends LocalToolCommandlet { + + /** + * The constructor. + * + * @param context the {@link IdeContext}. + */ + public Ruby(IdeContext context) { + + super(context, "ruby", Set.of(Tag.RUBY)); + } + + @Override + public String getToolHelpArguments() { + + return "--help"; + } +} diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index 1e52f11056..ec95d1ec90 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -118,6 +118,8 @@ cmd.quarkus.detail=Quarkus is a Kubernetes-native Java framework for building cl cmd.repository=Set up pre-configured git repositories using 'ide repository setup ' cmd.repository.detail=Without further arguments this will set up all pre-configured git repositories.\nAlso, you can provide an explicit git repo as `` argument and IDEasy will automatically clone, build and set up your project based on the existing property file.\nRepositories are configured in 'settings/repository/.properties' and can therefore be shared with your project team for automatic or optional setup. cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to set up, omit to set up all active repositories. +cmd.ruby=Tool commandlet for Ruby (programming language). +cmd.ruby.detail=Ruby is a dynamic, open-source programming language with a focus on simplicity and productivity. Detailed documentation can be found at https://www.ruby-lang.org/en/documentation/ cmd.rust=Tool commandlet for Rust (programming language). cmd.rust.detail=Rust is a programming-language focused on safety and performance. Detailed documentation can be found at https://www.rust-lang.org/learn cmd.set-edition=Set the edition of the selected tool. diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties index 3c4f9787cf..c2dd76ba53 100644 --- a/cli/src/main/resources/nls/Help_de.properties +++ b/cli/src/main/resources/nls/Help_de.properties @@ -118,6 +118,8 @@ cmd.quarkus.detail=Quarkus ist ein Kubernetes-native Java-Framework zur Entwickl cmd.repository=Richtet das vorkonfigurierte Git Repository ein mittels 'ide repository setup '. cmd.repository.detail=Dies wird alle vorkonfigurierten Repositories einrichten. Rufen Sie einfach 'ide repository setup ' auf, ersetzen Sie durch den Namen Ihrer Projektkonfigurationsdatei, die sich in 'settings/repository/your_project_name' befindet und IDEasy wird Ihr Projekt basierend auf der vorhandenen Eigenschaftsdatei automatisch klonen, bauen und einrichten.\nWenn Sie den Projektnamen weglassen, werden alle im Repository-Verzeichnis gefundenen Projekte vorkonfiguriert. cmd.repository.val.repository=Der Name der Properties-Datei des vorkonfigurierten Git Repositories zum Einrichten. Falls nicht angegeben, werden alle aktiven Projekte eingerichtet. +cmd.ruby=Werkzeug Kommando für Ruby (Programmiersprache). +cmd.ruby.detail=Ruby ist eine dynamische, quelloffene Programmiersprache mit Fokus auf Einfachheit und Produktivität. Detaillierte Dokumentation findet sich unter https://www.ruby-lang.org/de/documentation/ cmd.rust=Werkzeug Kommando für Rust (Programmiersprache). cmd.rust.detail=Rust ist eine Programmiersprache mit Fokus auf Sicherheit und Performance. Detaillierte Dokumentation findet sich unter https://www.rust-lang.org/learn cmd.set-edition=Setzt die Edition des selektierten Werkzeugs. diff --git a/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/ruby/RubyUrlUpdater.java b/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/ruby/RubyUrlUpdater.java new file mode 100644 index 0000000000..c2abe2bb50 --- /dev/null +++ b/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/ruby/RubyUrlUpdater.java @@ -0,0 +1,65 @@ +package com.devonfw.tools.ide.url.tool.ruby; + +import com.devonfw.tools.ide.url.model.folder.UrlVersion; +import com.devonfw.tools.ide.url.updater.GithubUrlReleaseUpdater; +import com.devonfw.tools.ide.version.VersionComparisonResult; +import com.devonfw.tools.ide.version.VersionIdentifier; + +public class RubyUrlUpdater extends GithubUrlReleaseUpdater { + + // Older RubyInstaller releases are ignored because releases before 2.5.3-1 use unsupported legacy tag naming. + private static final VersionIdentifier MIN_RUBY_VID = VersionIdentifier.of("2.5.3-1"); + + @Override + public String getTool() { + return "ruby"; + } + + @Override + protected String getGithubOrganization() { + return "oneclick"; + } + + @Override + protected String getGithubRepository() { + return "rubyinstaller2"; + } + + @Override + protected void addVersion(UrlVersion urlVersion) { + + VersionIdentifier vid = urlVersion.getVersionIdentifier(); + VersionComparisonResult result = vid.compareVersion(MIN_RUBY_VID); + + if (result.isEqual() || result.isGreater()) { + String baseUrl = createGithubReleaseDownloadUrl("RubyInstaller-${version}", "rubyinstaller-${version}-"); + + doAddVersion(urlVersion, baseUrl + "x64.7z", WINDOWS, X64); + } + } + + @Override + public String mapVersion(String version) { + int dateSeparator = version.indexOf(" - "); + if (dateSeparator >= 0) { + version = version.substring(0, dateSeparator); + } + return super.mapVersion(version); + } + + @Override + protected String getVersionPrefixToRemove() { + return "RubyInstaller-"; + } + + + @Override + public String getCpeVendor() { + return "ruby-lang"; + } + + @Override + public String getCpeProduct() { + return "ruby"; + } +} 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 e3370dda23..def029b59f 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 @@ -51,6 +51,7 @@ import com.devonfw.tools.ide.url.tool.pycharm.PycharmUrlUpdater; import com.devonfw.tools.ide.url.tool.python.PythonUrlUpdater; import com.devonfw.tools.ide.url.tool.quarkus.QuarkusUrlUpdater; +import com.devonfw.tools.ide.url.tool.ruby.RubyUrlUpdater; import com.devonfw.tools.ide.url.tool.rust.RustUrlUpdater; import com.devonfw.tools.ide.url.tool.sonar.SonarUrlUpdater; import com.devonfw.tools.ide.url.tool.squirrelsql.SquirrelSqlUrlUpdater; @@ -82,7 +83,7 @@ public class UpdateManager extends AbstractProcessorWithTimeout { new JavaUrlUpdater(), new JenkinsUrlUpdater(), new JmcUrlUpdater(), new KotlincUrlUpdater(), new KotlincNativeUrlUpdater(), new LazyDockerUrlUpdater(), new MvnUrlUpdater(), new MvndUrlUpdater(), 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 PythonUrlUpdater(), new QuarkusUrlUpdater(), new RubyUrlUpdater(), new RustUrlUpdater(), new DockerRancherDesktopUrlUpdater(), new SonarUrlUpdater(), new SquirrelSqlUrlUpdater(), new TerraformUrlUpdater(), new TomcatUrlUpdater(), new UvUrlUpdater(), new VsCodeUrlUpdater(), new VsCodiumUrlUpdater()); diff --git a/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/ruby/RubyUrlUpdaterMock.java b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/ruby/RubyUrlUpdaterMock.java new file mode 100644 index 0000000000..b302e55722 --- /dev/null +++ b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/ruby/RubyUrlUpdaterMock.java @@ -0,0 +1,29 @@ +package com.devonfw.tools.ide.url.tool.ruby; + +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; + +/** + * Mock of {@link RubyUrlUpdater} to allow integration testing with WireMock. + */ +public class RubyUrlUpdaterMock extends RubyUrlUpdater { + + private final String baseUrl; + + private final WireMockRuntimeInfo wmRuntimeInfo; + + RubyUrlUpdaterMock(WireMockRuntimeInfo wireMockRuntimeInfo) { + super(); + this.wmRuntimeInfo = wireMockRuntimeInfo; + this.baseUrl = wireMockRuntimeInfo.getHttpBaseUrl(); + } + + @Override + protected String getDownloadBaseUrl() { + return this.baseUrl; + } + + @Override + protected String doGetVersionUrl() { + return this.baseUrl + "/repos/" + getGithubOrganization() + "/" + getGithubRepository() + "/releases"; + } +} diff --git a/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/ruby/RubyUrlUpdaterTest.java b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/ruby/RubyUrlUpdaterTest.java new file mode 100644 index 0000000000..43e385ab59 --- /dev/null +++ b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/ruby/RubyUrlUpdaterTest.java @@ -0,0 +1,65 @@ +package com.devonfw.tools.ide.url.tool.ruby; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.any; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; + +import java.io.IOException; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import com.devonfw.tools.ide.url.model.folder.UrlRepository; +import com.devonfw.tools.ide.url.updater.AbstractUrlUpdaterTest; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; + + +/** + * Test of {@link RubyUrlUpdater}. + */ +@WireMockTest +class RubyUrlUpdaterTest extends AbstractUrlUpdaterTest { + + /** + * Test of {@link RubyUrlUpdater} for the creation of download URLs and checksums. + * + * @param tempDir path to a temporary directory + * @param wmRuntimeInfo the {@link WireMockRuntimeInfo} + * @throws IOException if the test fails + */ + @Test + void testRubyUrlUpdater(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) throws IOException { + + // arrange + stubFor(get(urlMatching("/repos/oneclick/rubyinstaller2/releases")) + .willReturn(aResponse() + .withStatus(200) + .withBody(readAndResolve( + PATH_INTEGRATION_TEST.resolve("RubyUrlUpdater").resolve("ruby-releases.json"), + wmRuntimeInfo)))); + + stubFor(any(urlMatching("/oneclick/rubyinstaller2/releases/download/.*")) + .willReturn(aResponse() + .withStatus(200) + .withBody(DOWNLOAD_CONTENT))); + + UrlRepository urlRepository = UrlRepository.load(tempDir); + RubyUrlUpdaterMock updater = new RubyUrlUpdaterMock(wmRuntimeInfo); + + // act + updater.update(urlRepository); + + // assert + Path rubyVersionDir = tempDir.resolve("ruby").resolve("ruby").resolve("2.5.3-1"); + assertThat(rubyVersionDir.resolve("status.json")).exists(); + assertUrlVersionFile(rubyVersionDir, "windows_x64"); + + Path oldRubyVersionDir = tempDir.resolve("ruby").resolve("ruby").resolve("2.4.0-7"); + assertThat(oldRubyVersionDir).doesNotExist(); + + } +} diff --git a/url-updater/src/test/resources/integrationtest/RubyUrlUpdater/ruby-releases.json b/url-updater/src/test/resources/integrationtest/RubyUrlUpdater/ruby-releases.json new file mode 100644 index 0000000000..10ff8c9307 --- /dev/null +++ b/url-updater/src/test/resources/integrationtest/RubyUrlUpdater/ruby-releases.json @@ -0,0 +1,32 @@ +[ + { + "url": "https://api.github.com/repos/oneclick/rubyinstaller2/releases/1", + "assets_url": "https://api.github.com/repos/oneclick/rubyinstaller2/releases/1/assets", + "html_url": "https://github.com/oneclick/rubyinstaller2/releases/tag/RubyInstaller-2.5.3-1", + "id": 1, + "tag_name": "RubyInstaller-2.5.3-1", + "target_commitish": "master", + "name": "RubyInstaller-2.5.3-1", + "draft": false, + "prerelease": true, + "assets": [] + }, + { + "url": "https://api.github.com/repos/oneclick/rubyinstaller2/releases/2", + "assets_url": "https://api.github.com/repos/oneclick/rubyinstaller2/releases/2/assets", + "html_url": "https://github.com/oneclick/rubyinstaller2/releases/tag/RubyInstaller-2.4.0-7", + "id": 2, + "tag_name": "RubyInstaller-2.4.0-7", + "target_commitish": "master", + "name": "RubyInstaller-2.4.0-7", + "draft": false, + "prerelease": true, + "assets": [ + { + "name": "rubyinstaller-2.4.0-7-x64.7z", + "browser_download_url": "${testbaseurl}/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.4.0-7/rubyinstaller-2.4.0-7-x64.7z" + } + ] + } +] +``