Skip to content

Commit 7a12474

Browse files
authored
create_branch tool (Issue #516) (#530)
create_branch tool ## GitHub issue number Fixes #516 ## **Associated Risks** none ## ✅ **PR Checklist** - [x] **I have read the [contribution guidelines](https://github.com/microsoft/azure-devops-mcp/blob/main/CONTRIBUTING.md)** - [x] **I have read the [code of conduct guidelines](https://github.com/microsoft/azure-devops-mcp/blob/main/CODE_OF_CONDUCT.md)** - [x] Title of the pull request is clear and informative. - [x] 👌 Code hygiene - [x] 🔭 Telemetry added, updated, or N/A - [x] 📄 Documentation added, updated, or N/A - [x] 🛡️ Automated tests added, or N/A ## 🧪 **How did you test it?** Added tests and manually tested all of the arguments.
1 parent 045f318 commit 7a12474

File tree

3 files changed

+402
-0
lines changed

3 files changed

+402
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ Interact with these Azure DevOps services:
9494
- **repo_get_branch_by_name**: Get a branch by its name.
9595
- **repo_get_pull_request_by_id**: Get a pull request by its ID.
9696
- **repo_create_pull_request**: Create a new pull request.
97+
- **repo_create_branch**: Create a new branch in the repository.
9798
- **repo_update_pull_request_status**: Update the status of an existing pull request to active or abandoned.
9899
- **repo_update_pull_request**: Update various fields of an existing pull request (title, description, draft status, target branch).
99100
- **repo_update_pull_request_reviewers**: Add or remove reviewers for an existing pull request.

src/tools/repositories.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const REPO_TOOLS = {
3333
get_branch_by_name: "repo_get_branch_by_name",
3434
get_pull_request_by_id: "repo_get_pull_request_by_id",
3535
create_pull_request: "repo_create_pull_request",
36+
create_branch: "repo_create_branch",
3637
update_pull_request: "repo_update_pull_request",
3738
update_pull_request_reviewers: "repo_update_pull_request_reviewers",
3839
reply_to_comment: "repo_reply_to_comment",
@@ -142,6 +143,99 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
142143
}
143144
);
144145

146+
server.tool(
147+
REPO_TOOLS.create_branch,
148+
"Create a new branch in the repository.",
149+
{
150+
repositoryId: z.string().describe("The ID of the repository where the branch will be created."),
151+
branchName: z.string().describe("The name of the new branch to create, e.g., 'feature-branch'."),
152+
sourceBranchName: z.string().optional().default("main").describe("The name of the source branch to create the new branch from. Defaults to 'main'."),
153+
sourceCommitId: z.string().optional().describe("The commit ID to create the branch from. If not provided, uses the latest commit of the source branch."),
154+
},
155+
async ({ repositoryId, branchName, sourceBranchName, sourceCommitId }) => {
156+
const connection = await connectionProvider();
157+
const gitApi = await connection.getGitApi();
158+
159+
let commitId = sourceCommitId;
160+
161+
// If no commit ID is provided, get the latest commit from the source branch
162+
if (!commitId) {
163+
const sourceRefName = `refs/heads/${sourceBranchName}`;
164+
try {
165+
const sourceBranch = await gitApi.getRefs(repositoryId, undefined, "heads/", false, false, undefined, false, undefined, sourceBranchName);
166+
const branch = sourceBranch.find((b) => b.name === sourceRefName);
167+
if (!branch || !branch.objectId) {
168+
return {
169+
content: [
170+
{
171+
type: "text",
172+
text: `Error: Source branch '${sourceBranchName}' not found in repository ${repositoryId}`,
173+
},
174+
],
175+
isError: true,
176+
};
177+
}
178+
commitId = branch.objectId;
179+
} catch (error) {
180+
return {
181+
content: [
182+
{
183+
type: "text",
184+
text: `Error retrieving source branch '${sourceBranchName}': ${error instanceof Error ? error.message : String(error)}`,
185+
},
186+
],
187+
isError: true,
188+
};
189+
}
190+
}
191+
192+
// Create the new branch using updateRefs
193+
const newRefName = `refs/heads/${branchName}`;
194+
const refUpdate = {
195+
name: newRefName,
196+
newObjectId: commitId,
197+
oldObjectId: "0000000000000000000000000000000000000000", // All zeros indicates creating a new ref
198+
};
199+
200+
try {
201+
const result = await gitApi.updateRefs([refUpdate], repositoryId);
202+
203+
// Check if the branch creation was successful
204+
if (result && result.length > 0 && result[0].success) {
205+
return {
206+
content: [
207+
{
208+
type: "text",
209+
text: `Branch '${branchName}' created successfully from '${sourceBranchName}' (${commitId})`,
210+
},
211+
],
212+
};
213+
} else {
214+
const errorMessage = result && result.length > 0 && result[0].customMessage ? result[0].customMessage : "Unknown error occurred during branch creation";
215+
return {
216+
content: [
217+
{
218+
type: "text",
219+
text: `Error creating branch '${branchName}': ${errorMessage}`,
220+
},
221+
],
222+
isError: true,
223+
};
224+
}
225+
} catch (error) {
226+
return {
227+
content: [
228+
{
229+
type: "text",
230+
text: `Error creating branch '${branchName}': ${error instanceof Error ? error.message : String(error)}`,
231+
},
232+
],
233+
isError: true,
234+
};
235+
}
236+
}
237+
);
238+
145239
server.tool(
146240
REPO_TOOLS.update_pull_request,
147241
"Update a Pull Request by ID with specified fields.",

0 commit comments

Comments
 (0)