Skip to content
Draft
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: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,6 @@ The plugin provides the following built-in tools for interacting with Jenkins:
- `getTestResults`: Retrieve test results of a specific build or the last build.

#### SCM Integration
- `getJobScm`: Retrieve SCM configurations of a Jenkins job.
- `getBuildScm`: Retrieve SCM configurations of a specific build.
- `getBuildChangeSets`: Retrieve change log sets of a specific build.
- `findJobsWithScmUrl`: Find jobs using a specific SCM (git) repository URL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,15 @@
import io.jenkins.plugins.mcp.server.McpServerExtension;
import io.jenkins.plugins.mcp.server.annotation.Tool;
import io.jenkins.plugins.mcp.server.annotation.ToolParam;
import io.jenkins.plugins.mcp.server.extensions.scm.GitScmConfig;
import io.jenkins.plugins.mcp.server.extensions.scm.GitScmUtil;
import io.jenkins.plugins.mcp.server.tool.JenkinsMcpContext;
import jakarta.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import jenkins.model.Jenkins;
import jenkins.model.ParameterizedJobMixIn;
import jenkins.model.queue.QueueItem;
import jenkins.triggers.SCMTriggerItem;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;
Expand Down Expand Up @@ -89,9 +86,35 @@
@Tool(
description = "Get a Jenkins job by its full path",
annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint = false))
public Job getJob(
@ToolParam(description = "Job full name of the Jenkins job (e.g., 'folder/job-name')") String jobFullName) {
return Jenkins.get().getItemByFullName(jobFullName, Job.class);
public JobWithScmConfigs getJob(
@ToolParam(description = "Job full name of the Jenkins job (e.g., 'folder/job-name')") String jobFullName,
@ToolParam(
description =
"To retrieves scm configurations of a Jenkins job (only for type SCMTriggerItem",
required = false)
boolean includeScmConfigurations) {
Job job = Jenkins.get().getItemByFullName(jobFullName, Job.class);
if (job == null) {

Check warning on line 97 in src/main/java/io/jenkins/plugins/mcp/server/extensions/DefaultMcpServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 97 is only partially covered, one branch is missing
return null;

Check warning on line 98 in src/main/java/io/jenkins/plugins/mcp/server/extensions/DefaultMcpServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 98 is not covered by tests
}
if (includeScmConfigurations && job instanceof SCMTriggerItem scmItem) {

Check warning on line 100 in src/main/java/io/jenkins/plugins/mcp/server/extensions/DefaultMcpServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 100 is only partially covered, 2 branches are missing
if (job.hasPermission(Item.EXTENDED_READ)) {

Check warning on line 101 in src/main/java/io/jenkins/plugins/mcp/server/extensions/DefaultMcpServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 101 is only partially covered, one branch is missing
List<GitScmConfig> gitScmConfigs = scmItem.getSCMs().stream()
.filter(scm -> scm.getType().equals("hudson.plugins.git.GitSCM"))
.map(GitScmUtil::extractGitScmInfo)
.filter(Objects::nonNull)
.toList();
return new JobWithScmConfigs(job, gitScmConfigs);
}
}
return new JobWithScmConfigs(job, Collections.emptyList());

Check warning on line 110 in src/main/java/io/jenkins/plugins/mcp/server/extensions/DefaultMcpServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 110 is not covered by tests
}

@Data
@AllArgsConstructor
public static class JobWithScmConfigs {
private Job job;
private List<GitScmConfig> gitScmConfigs;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import jakarta.annotation.Nullable;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -62,29 +61,6 @@ public static boolean isGitPluginInstalled() {
return gitPlugin != null && gitPlugin.isActive();
}

@Tool(
description = "Retrieves scm configurations of a Jenkins job",
annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint = false))
public List getJobScm(
@ToolParam(description = "Full path of the Jenkins job (e.g., 'folder/job-name')") String jobFullName) {
var job = Jenkins.get().getItemByFullName(jobFullName, Job.class);
if (job instanceof SCMTriggerItem scmItem) {
if (job.hasPermission(Item.EXTENDED_READ)) {
return scmItem.getSCMs().stream()
.map(scm -> {
Object result = null;
if (scm.getType().equals("hudson.plugins.git.GitSCM")) {
result = GitScmUtil.extractGitScmInfo(scm);
}
return result;
})
.filter(Objects::nonNull)
.toList();
}
}
return List.of();
}

@Tool(
description = "Retrieves scm configurations of a Jenkins build",
annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint = false))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ void testListTools(JenkinsRule jenkins, JenkinsMcpClientBuilder jenkinsMcpClient
"getJobs",
"getBuild",
"getJob",
"getJobScm",
"getBuildScm",
"findJobsWithScmUrl",
"getBuildChangeSets",
Expand Down Expand Up @@ -106,7 +105,6 @@ void testBuiltinToolHints(JenkinsRule jenkins, JenkinsMcpClientBuilder jenkinsMc
"searchBuildLog",
"getTestResults",
"getFlakyFailures",
"getJobScm",
"getBuildScm",
"getBuildChangeSets",
"findJobsWithScmUrl"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
public class JobScmExtensionTest {

@McpClientTest
void testGetJobScm(JenkinsRule jenkins, GitSampleRepoRule gitRepo, JenkinsMcpClientBuilder jenkinsMcpClientBuilder)
void testGetJobWithScm(
JenkinsRule jenkins, GitSampleRepoRule gitRepo, JenkinsMcpClientBuilder jenkinsMcpClientBuilder)
throws Exception {
// Setup Git repository
gitRepo.init();
Expand All @@ -64,8 +65,8 @@ void testGetJobScm(JenkinsRule jenkins, GitSampleRepoRule gitRepo, JenkinsMcpCli

try (var client = jenkinsMcpClientBuilder.jenkins(jenkins).build()) {
// Call getJobScm tool
McpSchema.CallToolRequest request =
new McpSchema.CallToolRequest("getJobScm", Map.of("jobFullName", project.getFullName()));
McpSchema.CallToolRequest request = new McpSchema.CallToolRequest(
"getJob", Map.of("jobFullName", project.getFullName(), "includeScmConfigurations", Boolean.TRUE));

var response = client.callTool(request);

Expand Down