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
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.devonfw.tools.ide.url.tool.claude;

import com.devonfw.tools.ide.url.model.folder.UrlVersion;
import com.devonfw.tools.ide.url.updater.GithubUrlTagUpdater;
import com.devonfw.tools.ide.version.VersionIdentifier;

/**
* {@link GithubUrlTagUpdater} for GitHub Claude Code CLI.
* <p>
* Follows the official installation structure from GitHub's claude-code repository: https://github.com/anthropics/claude-code.
* <p>
* Download URL pattern: https://github.com/anthropics/claude-code/releases/download/v${VERSION}/claude-${PLATFORM}-${ARCH}.tar.gz
*/
public class ClaudeUrlUpdater extends GithubUrlTagUpdater {

private static final VersionIdentifier MIN_CLAUDE_VID = VersionIdentifier.of("2.1.117");
private static final VersionIdentifier EXCLUDED_VERSION = VersionIdentifier.of("2.1.120");


@Override
public String getTool() {
return "claude";
}

@Override
protected String getGithubOrganization() {
return "anthropics";
}

@Override
protected String getGithubRepository() {
return "claude-code";
}

@Override
protected void addVersion(UrlVersion urlVersion) {
String baseUrl = createGithubReleaseDownloadUrl("v${version}", "claude-");
Comment thread
AdemZarrouki marked this conversation as resolved.
VersionIdentifier vid = urlVersion.getVersionIdentifier();

if (vid.compareVersion(MIN_CLAUDE_VID).isGreater() && !vid.compareVersion(EXCLUDED_VERSION).isEqual()) {

Comment thread
AdemZarrouki marked this conversation as resolved.
doAddVersion(urlVersion, baseUrl + "linux-x64.tar.gz", LINUX, X64);
doAddVersion(urlVersion, baseUrl + "linux-arm64.tar.gz", LINUX, ARM64);

doAddVersion(urlVersion, baseUrl + "darwin-x64.tar.gz", MAC, X64);
doAddVersion(urlVersion, baseUrl + "darwin-arm64.tar.gz", MAC, ARM64);

doAddVersion(urlVersion, baseUrl + "win32-x64.zip", WINDOWS, X64);
doAddVersion(urlVersion, baseUrl + "win32-arm64.zip", WINDOWS, ARM64);
}
}

@Override
protected String getVersionPrefixToRemove() {
return "v";
}

@Override
public String getCpeVendor() {
return "claude-code";
}

@Override
public String getCpeProduct() {
return "claude-code";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.devonfw.tools.ide.url.tool.androidstudio.AndroidStudioUrlUpdater;
import com.devonfw.tools.ide.url.tool.aws.AwsUrlUpdater;
import com.devonfw.tools.ide.url.tool.az.AzureUrlUpdater;
import com.devonfw.tools.ide.url.tool.claude.ClaudeUrlUpdater;
import com.devonfw.tools.ide.url.tool.copilot.CopilotUrlUpdater;
import com.devonfw.tools.ide.url.tool.corepack.CorepackUrlUpdater;
import com.devonfw.tools.ide.url.tool.docker.DockerDesktopUrlUpdater;
Expand Down Expand Up @@ -68,7 +69,7 @@ public class UpdateManager extends AbstractProcessorWithTimeout {
private final UrlFinalReport urlFinalReport;

private final List<AbstractUrlUpdater> updaters = List.of(
new AndroidStudioUrlUpdater(), new AwsUrlUpdater(), new AzureUrlUpdater(), new CopilotUrlUpdater(), new CorepackUrlUpdater(),
new AndroidStudioUrlUpdater(), new AwsUrlUpdater(), new AzureUrlUpdater(), new ClaudeUrlUpdater(), new CopilotUrlUpdater(), new CorepackUrlUpdater(),
new DockerDesktopUrlUpdater(),
new DotNetUrlUpdater(),
new EclipseCppUrlUpdater(), new EclipseJeeUrlUpdater(), new EclipseJavaUrlUpdater(), new GCloudUrlUpdater(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.devonfw.tools.ide.url.tool.claude;

import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;

/**
* Mock of {@link ClaudeUrlUpdater} to allow integration testing with wiremock.
*/
public class ClaudeUrlUpdaterMock extends ClaudeUrlUpdater {

private final String baseUrl;

private final WireMockRuntimeInfo wmRuntimeInfo;

ClaudeUrlUpdaterMock(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() + "/git/refs/tags";
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.devonfw.tools.ide.url.tool.claude;

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 ClaudeUrlUpdater}.
*/
@WireMockTest
class ClaudeUrlUpdaterTest extends AbstractUrlUpdaterTest {

/**
* Test of {@link ClaudeUrlUpdater} for the creation of download URLs and checksums.
*
* @param tempDir Path to a temporary directory
* @param wmRuntimeInfo the {@link WireMockRuntimeInfo}.
* @throws IOException test fails
*/
@Test
void testClaudeUrlUpdater(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) throws IOException {
// arrange
stubFor(get(urlMatching("/repos/anthropics/claude-code/git/refs/tags")).willReturn(aResponse().withStatus(200)
.withBody(readAndResolve(PATH_INTEGRATION_TEST.resolve("ClaudeUrlUpdater").resolve("claude-tags.json"), wmRuntimeInfo))));

stubFor(any(urlMatching("/anthropics/claude-code/releases/download/.*")).willReturn(aResponse().withStatus(200).withBody(DOWNLOAD_CONTENT)));

UrlRepository urlRepository = UrlRepository.load(tempDir);
ClaudeUrlUpdaterMock updater = new ClaudeUrlUpdaterMock(wmRuntimeInfo);

// act
updater.update(urlRepository);

// assert
Path claudeDir = tempDir.resolve("claude").resolve("claude");
assertUrlVersionOsX64(claudeDir.resolve("2.1.118"));
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[
{
"ref": "refs/tags/v2.1.118"
},
{
"ref": "refs/tags/v2.1.118-rc1"
}
]

Loading