@aashari/mcp-server-atlassian-bitbucket
Version:
Node.js/TypeScript MCP server for Atlassian Bitbucket. Enables AI systems (LLMs) to interact with workspaces, repositories, and pull requests via tools (list, get, comment, search). Connects AI directly to version control workflows through the standard MC
361 lines (360 loc) • 19.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const logger_util_js_1 = require("../utils/logger.util.js");
const error_util_js_1 = require("../utils/error.util.js");
const atlassian_pullrequests_controller_js_1 = __importDefault(require("../controllers/atlassian.pullrequests.controller.js"));
/**
* CLI module for managing Bitbucket pull requests.
* Provides commands for listing, retrieving, and manipulating pull requests.
* All commands require valid Atlassian credentials.
*/
// Create a contextualized logger for this file
const cliLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts');
// Log CLI initialization
cliLogger.debug('Bitbucket pull requests CLI module initialized');
/**
* Register Bitbucket pull requests CLI commands with the Commander program
* @param program - The Commander program instance to register commands with
* @throws Error if command registration fails
*/
function register(program) {
const methodLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'register');
methodLogger.debug('Registering Bitbucket Pull Requests CLI commands...');
registerListPullRequestsCommand(program);
registerGetPullRequestCommand(program);
registerListPullRequestCommentsCommand(program);
registerAddPullRequestCommentCommand(program);
registerAddPullRequestCommand(program);
registerUpdatePullRequestCommand(program);
registerApprovePullRequestCommand(program);
registerRejectPullRequestCommand(program);
methodLogger.debug('CLI commands registered successfully');
}
/**
* Register the command for listing Bitbucket pull requests
* @param program - The Commander program instance
*/
function registerListPullRequestsCommand(program) {
program
.command('ls-prs')
.description('List pull requests in a Bitbucket repository, with filtering and pagination.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. If not provided, the system will use your default workspace (either configured via BITBUCKET_DEFAULT_WORKSPACE or the first workspace in your account). Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull requests. This must be a valid repository in the specified workspace. Example: "project-api"')
.option('-s, --state <state>', 'Filter by pull request state: "OPEN", "MERGED", "DECLINED", or "SUPERSEDED". If omitted, returns pull requests in all states.')
.option('-q, --query <string>', 'Filter pull requests by query string. Searches pull request title and description.')
.option('-l, --limit <number>', 'Maximum number of items to return (1-100). Defaults to 25 if omitted.')
.option('-c, --cursor <string>', 'Pagination cursor for retrieving the next set of results.')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'ls-prs');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller params - keep only type conversions
const filterOptions = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
state: options.state,
query: options.query,
limit: options.limit
? parseInt(options.limit, 10)
: undefined,
cursor: options.cursor,
};
actionLogger.debug('Fetching pull requests with filters:', filterOptions);
const result = await atlassian_pullrequests_controller_js_1.default.list(filterOptions);
actionLogger.debug('Successfully retrieved pull requests');
// Display the content which now includes pagination information
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for retrieving a specific Bitbucket pull request
* @param program - The Commander program instance
*/
function registerGetPullRequestCommand(program) {
program
.command('get-pr')
.description('Get detailed information about a specific Bitbucket pull request.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. If not provided, uses your default workspace. Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull request. Must be a valid repository in the specified workspace. Example: "project-api"')
.requiredOption('-p, --pr-id <id>', 'Numeric ID of the pull request to retrieve. Must be a valid pull request ID in the specified repository. Example: "42"')
.option('--include-full-diff', 'Retrieve the full diff content instead of just the summary. Default: true (rich output by default)', true)
.option('--include-comments', 'Retrieve comments for the pull request. Default: false. Note: Enabling this may increase response time for pull requests with many comments due to additional API calls', false)
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'get-pr');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller params
const params = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
prId: options.prId,
includeFullDiff: options.includeFullDiff,
includeComments: options.includeComments,
};
actionLogger.debug('Fetching pull request:', params);
const result = await atlassian_pullrequests_controller_js_1.default.get(params);
actionLogger.debug('Successfully retrieved pull request');
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for listing comments on a Bitbucket pull request
* @param program - The Commander program instance
*/
function registerListPullRequestCommentsCommand(program) {
program
.command('ls-pr-comments')
.description('List comments on a specific Bitbucket pull request, with pagination.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. If not provided, uses your default workspace. Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull request. Must be a valid repository in the specified workspace. Example: "project-api"')
.requiredOption('-p, --pr-id <id>', 'Numeric ID of the pull request to retrieve comments from. Must be a valid pull request ID in the specified repository. Example: "42"')
.option('-l, --limit <number>', 'Maximum number of items to return (1-100). Defaults to 25 if omitted.')
.option('-c, --cursor <string>', 'Pagination cursor for retrieving the next set of results.')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'ls-pr-comments');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller params - keep only type conversions
const params = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
prId: options.prId,
limit: options.limit
? parseInt(options.limit, 10)
: undefined,
cursor: options.cursor,
};
actionLogger.debug('Fetching pull request comments:', params);
const result = await atlassian_pullrequests_controller_js_1.default.listComments(params);
actionLogger.debug('Successfully retrieved pull request comments');
// Display the content which now includes pagination information
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for adding a comment to a pull request
* @param program - The Commander program instance
*/
function registerAddPullRequestCommentCommand(program) {
program
.command('add-pr-comment')
.description('Add a comment to a Bitbucket pull request.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. If not provided, uses your default workspace. Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull request. Must be a valid repository in the specified workspace. Example: "project-api"')
.requiredOption('-p, --pr-id <id>', 'Numeric ID of the pull request to add a comment to. Must be a valid pull request ID in the specified repository. Example: "42"')
.requiredOption('-m, --content <text>', 'The content of the comment to add to the pull request. Can include markdown formatting.')
.option('-f, --path <file-path>', 'Optional: The file path to add an inline comment to.')
.option('-L, --line <line-number>', 'Optional: The line number to add the inline comment to.', parseInt)
.option('--parent-id <id>', 'Optional: The ID of the parent comment to reply to. If provided, this comment will be a reply to the specified comment.')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'add-pr-comment');
try {
actionLogger.debug('Processing command options:', options);
// Build parameters object
const params = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
prId: options.prId,
content: options.content,
};
// Add inline comment details if both path and line are provided
if (options.path && options.line) {
params.inline = {
path: options.path,
line: options.line,
};
}
else if (options.path || options.line) {
throw new Error('Both -f/--path and -L/--line are required for inline comments');
}
// Add parent ID if provided
if (options.parentId) {
params.parentId = options.parentId;
}
actionLogger.debug('Creating pull request comment:', {
...params,
content: '(content length: ' + options.content.length + ')',
});
const result = await atlassian_pullrequests_controller_js_1.default.addComment(params);
actionLogger.debug('Successfully created pull request comment');
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for adding a new pull request
* @param program - The Commander program instance
*/
function registerAddPullRequestCommand(program) {
program
.command('add-pr')
.description('Add a new pull request in a Bitbucket repository.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. If not provided, uses your default workspace. Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug to create the pull request in. Must be a valid repository in the specified workspace. Example: "project-api"')
.requiredOption('-t, --title <title>', 'Title for the pull request. Example: "Add new feature"')
.requiredOption('-s, --source-branch <branch>', 'Source branch name (the branch containing your changes). Example: "feature/new-login"')
.option('-d, --destination-branch <branch>', 'Destination branch name (the branch you want to merge into, defaults to main). Example: "develop"')
.option('--description <text>', 'Optional description for the pull request.')
.option('--close-source-branch', 'Whether to close the source branch after the pull request is merged. Default: false', false)
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'add-pr');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller params
const params = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
title: options.title,
sourceBranch: options.sourceBranch,
destinationBranch: options.destinationBranch,
description: options.description,
closeSourceBranch: options.closeSourceBranch,
};
actionLogger.debug('Creating pull request:', {
...params,
description: options.description
? '(description provided)'
: '(no description)',
});
const result = await atlassian_pullrequests_controller_js_1.default.add(params);
actionLogger.debug('Successfully created pull request');
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for updating a Bitbucket pull request
* @param program - The Commander program instance
*/
function registerUpdatePullRequestCommand(program) {
program
.command('update-pr')
.description('Update an existing pull request in a Bitbucket repository.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository (optional, uses default workspace if not provided). Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull request. Example: "project-api"')
.requiredOption('-p, --pull-request-id <id>', 'Pull request ID to update. Example: 123', parseInt)
.option('-t, --title <title>', 'Updated title for the pull request. Example: "Updated Feature Implementation"')
.option('--description <text>', 'Updated description for the pull request.')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'update-pr');
try {
actionLogger.debug('Processing command options:', options);
// Validate that at least one field to update is provided
if (!options.title && !options.description) {
throw new Error('At least one field to update (title or description) must be provided');
}
// Map CLI options to controller params
const params = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
pullRequestId: options.pullRequestId,
title: options.title,
description: options.description,
};
actionLogger.debug('Updating pull request:', {
...params,
description: options.description
? '(description provided)'
: '(no description)',
});
const result = await atlassian_pullrequests_controller_js_1.default.update(params);
actionLogger.debug('Successfully updated pull request');
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for approving a Bitbucket pull request
* @param program - The Commander program instance
*/
function registerApprovePullRequestCommand(program) {
program
.command('approve-pr')
.description('Approve a pull request in a Bitbucket repository.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository (optional, uses default workspace if not provided). Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull request. Example: "project-api"')
.requiredOption('-p, --pull-request-id <id>', 'Pull request ID to approve. Example: 123', parseInt)
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'approve-pr');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller params
const params = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
pullRequestId: options.pullRequestId,
};
actionLogger.debug('Approving pull request:', params);
const result = await atlassian_pullrequests_controller_js_1.default.approve(params);
actionLogger.debug('Successfully approved pull request');
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for requesting changes on a Bitbucket pull request
* @param program - The Commander program instance
*/
function registerRejectPullRequestCommand(program) {
program
.command('reject-pr')
.description('Request changes on a pull request in a Bitbucket repository.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository (optional, uses default workspace if not provided). Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull request. Example: "project-api"')
.requiredOption('-p, --pull-request-id <id>', 'Pull request ID to request changes on. Example: 123', parseInt)
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'reject-pr');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller params
const params = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
pullRequestId: options.pullRequestId,
};
actionLogger.debug('Requesting changes on pull request:', params);
const result = await atlassian_pullrequests_controller_js_1.default.reject(params);
actionLogger.debug('Successfully requested changes on pull request');
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
exports.default = { register };