create_pull_request
Create pull requests in Azure DevOps with reviewers, linked work items, and optional tags to manage code changes and collaboration.
Instructions
Create a new pull request, including reviewers, linked work items, and optional tags
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectId | No | The ID or name of the project (Default: MyProject) | |
| organizationId | No | The ID or name of the organization (Default: mycompany) | |
| repositoryId | Yes | The ID or name of the repository | |
| title | Yes | The title of the pull request | |
| description | No | The description of the pull request (markdown is supported) | |
| sourceRefName | Yes | The source branch name (e.g., refs/heads/feature-branch) | |
| targetRefName | Yes | The target branch name (e.g., refs/heads/main) | |
| reviewers | No | List of reviewer email addresses or IDs | |
| isDraft | No | Whether the pull request should be created as a draft | |
| workItemRefs | No | List of work item IDs to link to the pull request | |
| tags | No | List of tags to apply to the pull request | |
| additionalProperties | No | Additional properties to set on the pull request |
Implementation Reference
- Core handler function that executes the create pull request logic using Azure DevOps Git API, including input validation, tag normalization, PR creation, and label application.export async function createPullRequest( connection: WebApi, projectId: string, repositoryId: string, options: CreatePullRequestOptions, ): Promise<PullRequest> { try { if (!options.title) { throw new Error('Title is required'); } if (!options.sourceRefName) { throw new Error('Source branch is required'); } if (!options.targetRefName) { throw new Error('Target branch is required'); } const gitApi = await connection.getGitApi(); const normalizedTags = normalizeTags(options.tags); // Create the pull request object const pullRequest: PullRequest = { title: options.title, description: options.description, sourceRefName: options.sourceRefName, targetRefName: options.targetRefName, isDraft: options.isDraft || false, workItemRefs: options.workItemRefs?.map((id) => ({ id: id.toString(), })), reviewers: options.reviewers?.map((reviewer) => ({ id: reviewer, isRequired: true, })), }; if (options.additionalProperties) { Object.assign(pullRequest, options.additionalProperties); } if (normalizedTags.length > 0) { pullRequest.labels = normalizedTags.map((tag) => ({ name: tag })); } // Create the pull request const createdPullRequest = await gitApi.createPullRequest( pullRequest, repositoryId, projectId, ); if (!createdPullRequest) { throw new Error('Failed to create pull request'); } if (normalizedTags.length > 0) { const pullRequestId = createdPullRequest.pullRequestId; if (!pullRequestId) { throw new Error('Pull request created without identifier for tagging'); } const existing = new Set( (createdPullRequest.labels ?? []) .map((label) => label.name?.toLowerCase()) .filter((name): name is string => Boolean(name)), ); const tagsToCreate = normalizedTags.filter( (tag) => !existing.has(tag.toLowerCase()), ); if (tagsToCreate.length > 0) { const createdLabels = await Promise.all( tagsToCreate.map((tag) => gitApi.createPullRequestLabel( { name: tag }, repositoryId, pullRequestId, projectId, ), ), ); createdPullRequest.labels = [ ...(createdPullRequest.labels ?? []), ...createdLabels, ]; } } return createdPullRequest; } catch (error) { if (error instanceof AzureDevOpsError) { throw error; } throw new Error( `Failed to create pull request: ${error instanceof Error ? error.message : String(error)}`, ); } }
- src/features/pull-requests/index.ts:65-76 (registration)Request handler registration that routes 'create_pull_request' tool calls, parses arguments with schema, invokes the handler, and formats the response.case 'create_pull_request': { const args = CreatePullRequestSchema.parse(request.params.arguments); const result = await createPullRequest( connection, args.projectId ?? defaultProject, args.repositoryId, args, ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; }
- Zod schema defining the input parameters and validation for the create_pull_request tool.export const CreatePullRequestSchema = z.object({ projectId: z .string() .optional() .describe(`The ID or name of the project (Default: ${defaultProject})`), organizationId: z .string() .optional() .describe(`The ID or name of the organization (Default: ${defaultOrg})`), repositoryId: z.string().describe('The ID or name of the repository'), title: z.string().describe('The title of the pull request'), description: z .string() .optional() .describe('The description of the pull request (markdown is supported)'), sourceRefName: z .string() .describe('The source branch name (e.g., refs/heads/feature-branch)'), targetRefName: z .string() .describe('The target branch name (e.g., refs/heads/main)'), reviewers: z .array(z.string()) .optional() .describe('List of reviewer email addresses or IDs'), isDraft: z .boolean() .optional() .describe('Whether the pull request should be created as a draft'), workItemRefs: z .array(z.number()) .optional() .describe('List of work item IDs to link to the pull request'), tags: z .array(z.string().trim().min(1)) .optional() .describe('List of tags to apply to the pull request'), additionalProperties: z .record(z.string(), z.any()) .optional() .describe('Additional properties to set on the pull request'), });
- src/features/pull-requests/tool-definitions.ts:17-22 (registration)ToolDefinition registration for 'create_pull_request' including name, description, and input schema.{ name: 'create_pull_request', description: 'Create a new pull request, including reviewers, linked work items, and optional tags', inputSchema: zodToJsonSchema(CreatePullRequestSchema), },
- Helper function to normalize and deduplicate tags for the pull request.function normalizeTags(tags?: string[]): string[] { if (!tags) { return []; } const seen = new Set<string>(); const normalized: string[] = []; for (const rawTag of tags) { const trimmed = rawTag.trim(); if (!trimmed) { continue; } const key = trimmed.toLowerCase(); if (seen.has(key)) { continue; } seen.add(key); normalized.push(trimmed); } return normalized; }