diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index a8dcae4f64..3043d37fac 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -19,6 +19,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/1849[#1849]: Add VSCodium support 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/tool/vscode/Vscode.java b/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java index 9cfc99407c..c1debf3916 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java @@ -14,6 +14,7 @@ import com.devonfw.tools.ide.io.IdeProgressBar; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.process.ProcessContext; +import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.process.ProcessMode; import com.devonfw.tools.ide.process.ProcessResult; import com.devonfw.tools.ide.step.Step; @@ -28,6 +29,12 @@ public class Vscode extends IdeToolCommandlet { private static final Logger LOG = LoggerFactory.getLogger(Vscode.class); + /** The {@link #getConfiguredEdition() edition} for VSCodium. */ + private static final String EDITION_VSCODIUM = "vscodium"; + + /** Plugin IDs collected during {@link #installPlugins} that the VSCodium build refused to install. */ + private final List vscodiumUnavailablePlugins = new ArrayList<>(); + /** * The constructor. * @@ -41,11 +48,20 @@ public Vscode(IdeContext context) { @Override protected String getBinaryName() { + if (EDITION_VSCODIUM.equals(getConfiguredEdition())) { + return "codium"; + } return "code"; } @Override protected void installPlugins(Collection plugins, ProcessContext pc) { + boolean isVscodium = EDITION_VSCODIUM.equals(getConfiguredEdition()); + if (isVscodium) { + this.vscodiumUnavailablePlugins.clear(); + pc.errorHandling(ProcessErrorHandling.NONE); + } + IdeLogLevel suppressLevel = isVscodium ? IdeLogLevel.WARNING : IdeLogLevel.STEP; this.context.runWithoutLogging(() -> { IdeProgressBar pb = this.context.newProgressBarForPlugins(plugins.size()); pc.setOutputListener((msg, err) -> { @@ -55,7 +71,14 @@ protected void installPlugins(Collection plugins, ProcessC }); super.installPlugins(plugins, pc); pb.close(); - }); + }, suppressLevel); + if (isVscodium && !this.vscodiumUnavailablePlugins.isEmpty()) { + LOG.warn("{} plugin(s) could not be installed on VSCodium due to not being available on open-vsx or other errors:\n - {}\n" + + "For full plugin support, set VSCODE_EDITION=vscode to use Microsoft's distribution.\n" + + "For more detailed information on why plugins failed to install, check the IDEasy logfile at $IDE_ROOT/_ide/logs/.", + this.vscodiumUnavailablePlugins.size(), + String.join("\n - ", this.vscodiumUnavailablePlugins)); + } } @Override @@ -70,10 +93,13 @@ public boolean installPlugin(ToolPluginDescriptor plugin, Step step, ProcessCont IdeLogLevel.SUCCESS.log(LOG, "Successfully installed plugin: {}", plugin.name()); step.success(); return true; - } else { - LOG.warn("An error occurred while installing plugin: {}", plugin.name()); + } + if (EDITION_VSCODIUM.equals(getConfiguredEdition())) { + this.vscodiumUnavailablePlugins.add(plugin.id()); return false; } + LOG.warn("An error occurred while installing plugin: {}", plugin.name()); + return false; } @Override diff --git a/cli/src/test/resources/ide-projects/vscodium/_ide/urls/vscode/vscodium/1.116.02821/urls b/cli/src/test/resources/ide-projects/vscodium/_ide/urls/vscode/vscodium/1.116.02821/urls new file mode 100644 index 0000000000..ce0f1b90af --- /dev/null +++ b/cli/src/test/resources/ide-projects/vscodium/_ide/urls/vscode/vscodium/1.116.02821/urls @@ -0,0 +1 @@ +${testbaseurl}/download/vscode/vscodium/1.116.02821/VSCodium-1.116.02821.tgz diff --git a/cli/src/test/resources/ide-projects/vscodium/project/settings/ide.properties b/cli/src/test/resources/ide-projects/vscodium/project/settings/ide.properties new file mode 100644 index 0000000000..6b53acf2ae --- /dev/null +++ b/cli/src/test/resources/ide-projects/vscodium/project/settings/ide.properties @@ -0,0 +1,2 @@ +VSCODE_EDITION=vscodium +VSCODE_VERSION=1.116.02821 diff --git a/cli/src/test/resources/ide-projects/vscodium/repository/vscode/vscodium/default/bin/codium b/cli/src/test/resources/ide-projects/vscodium/repository/vscode/vscodium/default/bin/codium new file mode 100755 index 0000000000..73d55c2221 --- /dev/null +++ b/cli/src/test/resources/ide-projects/vscodium/repository/vscode/vscodium/default/bin/codium @@ -0,0 +1,2 @@ +#!/bin/bash +echo "Test for linux and Mac" \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/vscodium/repository/vscode/vscodium/default/bin/codium.cmd b/cli/src/test/resources/ide-projects/vscodium/repository/vscode/vscodium/default/bin/codium.cmd new file mode 100644 index 0000000000..5fc84a8640 --- /dev/null +++ b/cli/src/test/resources/ide-projects/vscodium/repository/vscode/vscodium/default/bin/codium.cmd @@ -0,0 +1 @@ +@echo test for windows \ No newline at end of file diff --git a/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/vscode/VsCodiumUrlUpdater.java b/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/vscode/VsCodiumUrlUpdater.java new file mode 100644 index 0000000000..423c0254a8 --- /dev/null +++ b/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/vscode/VsCodiumUrlUpdater.java @@ -0,0 +1,77 @@ +package com.devonfw.tools.ide.url.tool.vscode; + +import com.devonfw.tools.ide.url.model.folder.UrlVersion; +import com.devonfw.tools.ide.url.updater.GithubUrlTagUpdater; + +/** + * {@link GithubUrlTagUpdater} for the "vscodium" edition of vscode (VSCodium). + */ +public class VsCodiumUrlUpdater extends GithubUrlTagUpdater { + + private static final String DOWNLOAD_BASE_URL = "https://github.com/VSCodium/vscodium/releases/download"; + + @Override + public String getTool() { + + return "vscode"; + } + + @Override + protected String getEdition() { + + return "vscodium"; + } + + @Override + protected String getGithubOrganization() { + + return "VSCodium"; + } + + @Override + protected String getGithubRepository() { + + return "vscodium"; + } + + @Override + protected String getDownloadBaseUrl() { + + return DOWNLOAD_BASE_URL; + } + + @Override + protected void addVersion(UrlVersion urlVersion) { + + String baseUrl = getDownloadBaseUrl() + "/${version}/VSCodium-"; + doAddVersion(urlVersion, baseUrl + "linux-x64-${version}.tar.gz", LINUX, X64); + doAddVersion(urlVersion, baseUrl + "linux-arm64-${version}.tar.gz", LINUX, ARM64); + doAddVersion(urlVersion, baseUrl + "darwin-x64-${version}.zip", MAC, X64); + doAddVersion(urlVersion, baseUrl + "darwin-arm64-${version}.zip", MAC, ARM64); + doAddVersion(urlVersion, baseUrl + "win32-x64-${version}.zip", WINDOWS, X64); + doAddVersion(urlVersion, baseUrl + "win32-arm64-${version}.zip", WINDOWS, ARM64); + } + + @Override + public String mapVersion(String version) { + + // VSCodium tag schemes seen in history: 3-segment "1.55.0", 4-segment "1.84.2.23319", and current 3-segment with + // build-encoded patch like "1.116.02821". Accept any 3- or 4-segment numeric tag. + if (version.matches("\\d+\\.\\d+\\.\\d+(\\.\\d+)?")) { + return super.mapVersion(version); + } else { + return null; + } + } + + @Override + public String getCpeVendor() { + return "vscodium"; + } + + @Override + public String getCpeProduct() { + return "vscodium"; + } + +} 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..66f418dc83 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 @@ -55,6 +55,7 @@ import com.devonfw.tools.ide.url.tool.tomcat.TomcatUrlUpdater; import com.devonfw.tools.ide.url.tool.uv.UvUrlUpdater; import com.devonfw.tools.ide.url.tool.vscode.VsCodeUrlUpdater; +import com.devonfw.tools.ide.url.tool.vscode.VsCodiumUrlUpdater; /** * The {@code UpdateManager} class manages the update process for various tools by using a list of {@link AbstractUrlUpdater}s to update the @@ -78,7 +79,7 @@ public class UpdateManager extends AbstractProcessorWithTimeout { 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 TerraformUrlUpdater(), new TomcatUrlUpdater(), new UvUrlUpdater(), new VsCodeUrlUpdater()); + new TerraformUrlUpdater(), new TomcatUrlUpdater(), new UvUrlUpdater(), new VsCodeUrlUpdater(), new VsCodiumUrlUpdater()); /** * The constructor. diff --git a/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/vscode/VsCodiumUrlUpdaterMock.java b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/vscode/VsCodiumUrlUpdaterMock.java new file mode 100644 index 0000000000..cd2f947362 --- /dev/null +++ b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/vscode/VsCodiumUrlUpdaterMock.java @@ -0,0 +1,27 @@ +package com.devonfw.tools.ide.url.tool.vscode; + +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; + +/** + * Mock of {@link VsCodiumUrlUpdater} to allow integration testing with wiremock. + */ +public class VsCodiumUrlUpdaterMock extends VsCodiumUrlUpdater { + + private final String baseUrl; + + VsCodiumUrlUpdaterMock(WireMockRuntimeInfo wireMockRuntimeInfo) { + super(); + this.baseUrl = wireMockRuntimeInfo.getHttpBaseUrl(); + } + + @Override + protected String getDownloadBaseUrl() { + return this.baseUrl; + } + + @Override + protected String doGetVersionUrl() { + + return this.baseUrl + "/repos/" + getGithubOrganization() + "/" + getGithubRepository() + "/git/refs/tags"; + } +} diff --git a/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/vscode/VsCodiumUrlUpdaterTest.java b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/vscode/VsCodiumUrlUpdaterTest.java new file mode 100644 index 0000000000..ffe3344442 --- /dev/null +++ b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/vscode/VsCodiumUrlUpdaterTest.java @@ -0,0 +1,50 @@ +package com.devonfw.tools.ide.url.tool.vscode; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.head; +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.Files; +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 VsCodiumUrlUpdater}. + */ +@WireMockTest +class VsCodiumUrlUpdaterTest extends AbstractUrlUpdaterTest { + + /** + * verifies that update creates expected files for VSCodium versions. + */ + @Test + void testVsCodiumUrlUpdaterCreatesDownloadUrlsAndChecksums(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) throws IOException { + // given + stubFor(get(urlMatching("/repos/VSCodium/vscodium/git/refs/tags")).willReturn(aResponse().withStatus(200) + .withBody(Files.readAllBytes(PATH_INTEGRATION_TEST.resolve("VsCodiumUrlUpdater").resolve("vscodium-tags.json"))))); + stubFor(head(urlMatching("/.*/VSCodium-(linux|darwin|win32)-(x64|arm64)-.*\\.(tar\\.gz|zip)")).willReturn(aResponse().withStatus(200))); + stubFor(get(urlMatching("/.*/VSCodium-(linux|darwin|win32)-(x64|arm64)-.*\\.(tar\\.gz|zip)")).willReturn(aResponse().withStatus(200).withBody(DOWNLOAD_CONTENT))); + + UrlRepository urlRepository = UrlRepository.load(tempDir); + VsCodiumUrlUpdaterMock updater = new VsCodiumUrlUpdaterMock(wmRuntimeInfo); + // when + updater.update(urlRepository); + + Path vscodium1 = tempDir.resolve("vscode").resolve("vscodium").resolve("1.92.1.24228"); + Path vscodium2 = tempDir.resolve("vscode").resolve("vscodium").resolve("1.116.02821"); + + // then + assertUrlVersionOsArch(vscodium1); + assertUrlVersionOsArch(vscodium2); + } +} diff --git a/url-updater/src/test/resources/integrationtest/VsCodiumUrlUpdater/vscodium-tags.json b/url-updater/src/test/resources/integrationtest/VsCodiumUrlUpdater/vscodium-tags.json new file mode 100644 index 0000000000..c1818375ba --- /dev/null +++ b/url-updater/src/test/resources/integrationtest/VsCodiumUrlUpdater/vscodium-tags.json @@ -0,0 +1,8 @@ +[ + { + "ref": "refs/tags/1.92.1.24228" + }, + { + "ref": "refs/tags/1.116.02821" + } +]