feat: Add support for nested comment replies in Bitbucket Server (v0.6.1)
- Enhanced FormattedComment interface with replies field for nested threads - Updated comment fetching to recursively process nested structure - Fixed comment counting to include all nested replies - Updated documentation to explain reply handling differences - Maintained backward compatibility with existing tools
This commit is contained in:
parent
c6d5b0a6f5
commit
793355bdaa
6 changed files with 420 additions and 7 deletions
40
CHANGELOG.md
40
CHANGELOG.md
|
@ -5,6 +5,46 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.6.1] - 2025-01-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Support for nested comment replies in Bitbucket Server
|
||||||
|
- Added `replies` field to `FormattedComment` interface to support nested comment threads
|
||||||
|
- Comments now include nested replies that are still relevant (not orphaned or resolved)
|
||||||
|
- Total and active comment counts now include nested replies
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Updated comment fetching logic to handle Bitbucket Server's nested comment structure
|
||||||
|
- Server uses `comments` array inside each comment object for replies
|
||||||
|
- Cloud continues to use `parent` field for reply relationships
|
||||||
|
- Improved comment filtering to exclude orphaned inline comments when code has changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed missing comment replies in PR details - replies are now properly included in the response
|
||||||
|
|
||||||
|
## [0.6.0] - 2025-01-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **Enhanced `get_pull_request` with active comments and file changes**:
|
||||||
|
- Fetches and displays active (unresolved) comments that need attention
|
||||||
|
- Shows up to 20 most recent active comments with:
|
||||||
|
- Comment text, author, and creation date
|
||||||
|
- Inline comment details (file path and line number)
|
||||||
|
- Comment state (OPEN/RESOLVED for Server)
|
||||||
|
- Provides comment counts:
|
||||||
|
- `active_comment_count`: Total unresolved comments
|
||||||
|
- `total_comment_count`: Total comments including resolved
|
||||||
|
- Includes file change statistics:
|
||||||
|
- List of all modified files with lines added/removed
|
||||||
|
- File status (added, modified, removed, renamed)
|
||||||
|
- Summary statistics (total files, lines added/removed)
|
||||||
|
- Added new TypeScript interfaces for comments and file changes
|
||||||
|
- Added `FormattedComment` and `FormattedFileChange` types for consistent response format
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Modified `handleGetPullRequest` to make parallel API calls for better performance
|
||||||
|
- Enhanced error handling to gracefully continue if comment/file fetching fails
|
||||||
|
|
||||||
## [0.5.0] - 2025-01-21
|
## [0.5.0] - 2025-01-21
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
43
README.md
43
README.md
|
@ -188,6 +188,25 @@ Returns detailed information about the pull request including:
|
||||||
- `merged_by`: Who performed the merge
|
- `merged_by`: Who performed the merge
|
||||||
- `merged_at`: When the merge occurred
|
- `merged_at`: When the merge occurred
|
||||||
- `merge_commit_message`: The merge commit message
|
- `merge_commit_message`: The merge commit message
|
||||||
|
- **Active comments with nested replies** (unresolved comments that need attention):
|
||||||
|
- `active_comments`: Array of active comments (up to 20 most recent top-level comments)
|
||||||
|
- Comment text and author
|
||||||
|
- Creation date
|
||||||
|
- Whether it's an inline comment (with file path and line number)
|
||||||
|
- **Nested replies** (for Bitbucket Server):
|
||||||
|
- `replies`: Array of reply comments with same structure
|
||||||
|
- Replies can be nested multiple levels deep
|
||||||
|
- **Parent reference** (for Bitbucket Cloud):
|
||||||
|
- `parent_id`: ID of the parent comment for replies
|
||||||
|
- `active_comment_count`: Total count of unresolved comments (including nested replies)
|
||||||
|
- `total_comment_count`: Total count of all comments (including resolved and replies)
|
||||||
|
- **File changes**:
|
||||||
|
- `file_changes`: Array of all files modified in the PR
|
||||||
|
- File path
|
||||||
|
- Status (added, modified, removed, or renamed)
|
||||||
|
- Old path (for renamed files)
|
||||||
|
- `file_changes_summary`: Summary statistics
|
||||||
|
- Total files changed
|
||||||
- And more...
|
- And more...
|
||||||
|
|
||||||
### List Pull Requests
|
### List Pull Requests
|
||||||
|
@ -252,7 +271,7 @@ Returns a paginated list of pull requests with:
|
||||||
|
|
||||||
### Add Comment
|
### Add Comment
|
||||||
|
|
||||||
Add general comments or inline comments on specific lines of code:
|
Add general comments, reply to existing comments, or add inline comments on specific lines of code:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// General comment
|
// General comment
|
||||||
|
@ -262,8 +281,19 @@ Add general comments or inline comments on specific lines of code:
|
||||||
"workspace": "PROJ",
|
"workspace": "PROJ",
|
||||||
"repository": "my-repo",
|
"repository": "my-repo",
|
||||||
"pull_request_id": 123,
|
"pull_request_id": 123,
|
||||||
"comment_text": "Great work! Just one small suggestion...",
|
"comment_text": "Great work! Just one small suggestion..."
|
||||||
"parent_comment_id": 456 // Optional - for replies
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reply to an existing comment
|
||||||
|
{
|
||||||
|
"tool": "add_comment",
|
||||||
|
"arguments": {
|
||||||
|
"workspace": "PROJ",
|
||||||
|
"repository": "my-repo",
|
||||||
|
"pull_request_id": 123,
|
||||||
|
"comment_text": "Thanks for the feedback! I've updated the code.",
|
||||||
|
"parent_comment_id": 456 // ID of the comment you're replying to
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,6 +312,13 @@ Add general comments or inline comments on specific lines of code:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Note on comment replies:**
|
||||||
|
- Use `parent_comment_id` to reply to any comment (general or inline)
|
||||||
|
- In `get_pull_request` responses:
|
||||||
|
- Bitbucket Server shows replies nested in a `replies` array
|
||||||
|
- Bitbucket Cloud shows a `parent_id` field for reply comments
|
||||||
|
- You can reply to replies, creating nested conversations
|
||||||
|
|
||||||
**Note on inline comments:**
|
**Note on inline comments:**
|
||||||
- `file_path`: The path to the file as shown in the diff
|
- `file_path`: The path to the file as shown in the diff
|
||||||
- `line_number`: The line number as shown in the diff
|
- `line_number`: The line number as shown in the diff
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@nexus2520/bitbucket-mcp-server",
|
"name": "@nexus2520/bitbucket-mcp-server",
|
||||||
"version": "0.5.0",
|
"version": "0.6.1",
|
||||||
"description": "MCP server for Bitbucket API integration - supports both Cloud and Server",
|
"description": "MCP server for Bitbucket API integration - supports both Cloud and Server",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./build/index.js",
|
"main": "./build/index.js",
|
||||||
|
|
|
@ -5,7 +5,11 @@ import {
|
||||||
BitbucketServerPullRequest,
|
BitbucketServerPullRequest,
|
||||||
BitbucketCloudPullRequest,
|
BitbucketCloudPullRequest,
|
||||||
BitbucketServerActivity,
|
BitbucketServerActivity,
|
||||||
MergeInfo
|
MergeInfo,
|
||||||
|
BitbucketCloudComment,
|
||||||
|
BitbucketCloudFileChange,
|
||||||
|
FormattedComment,
|
||||||
|
FormattedFileChange
|
||||||
} from '../types/bitbucket.js';
|
} from '../types/bitbucket.js';
|
||||||
import {
|
import {
|
||||||
isGetPullRequestArgs,
|
isGetPullRequestArgs,
|
||||||
|
@ -78,16 +82,49 @@ export class PullRequestHandlers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch comments and file changes in parallel
|
||||||
|
let comments: FormattedComment[] = [];
|
||||||
|
let activeCommentCount = 0;
|
||||||
|
let totalCommentCount = 0;
|
||||||
|
let fileChanges: FormattedFileChange[] = [];
|
||||||
|
let fileChangesSummary: any = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [commentsResult, fileChangesResult] = await Promise.all([
|
||||||
|
this.fetchPullRequestComments(workspace, repository, pull_request_id),
|
||||||
|
this.fetchPullRequestFileChanges(workspace, repository, pull_request_id)
|
||||||
|
]);
|
||||||
|
|
||||||
|
comments = commentsResult.comments;
|
||||||
|
activeCommentCount = commentsResult.activeCount;
|
||||||
|
totalCommentCount = commentsResult.totalCount;
|
||||||
|
fileChanges = fileChangesResult.fileChanges;
|
||||||
|
fileChangesSummary = fileChangesResult.summary;
|
||||||
|
} catch (error) {
|
||||||
|
// Log error but continue with PR data
|
||||||
|
console.error('Failed to fetch additional PR data:', error);
|
||||||
|
}
|
||||||
|
|
||||||
// Format the response based on server type
|
// Format the response based on server type
|
||||||
const formattedResponse = this.apiClient.getIsServer()
|
const formattedResponse = this.apiClient.getIsServer()
|
||||||
? formatServerResponse(pr as BitbucketServerPullRequest, mergeInfo, this.baseUrl)
|
? formatServerResponse(pr as BitbucketServerPullRequest, mergeInfo, this.baseUrl)
|
||||||
: formatCloudResponse(pr as BitbucketCloudPullRequest);
|
: formatCloudResponse(pr as BitbucketCloudPullRequest);
|
||||||
|
|
||||||
|
// Add comments and file changes to the response
|
||||||
|
const enhancedResponse = {
|
||||||
|
...formattedResponse,
|
||||||
|
active_comments: comments,
|
||||||
|
active_comment_count: activeCommentCount,
|
||||||
|
total_comment_count: totalCommentCount,
|
||||||
|
file_changes: fileChanges,
|
||||||
|
file_changes_summary: fileChangesSummary
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: JSON.stringify(formattedResponse, null, 2),
|
text: JSON.stringify(enhancedResponse, null, 2),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -483,4 +520,213 @@ export class PullRequestHandlers {
|
||||||
return this.apiClient.handleApiError(error, `merging pull request ${pull_request_id} in ${workspace}/${repository}`);
|
return this.apiClient.handleApiError(error, `merging pull request ${pull_request_id} in ${workspace}/${repository}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async fetchPullRequestComments(
|
||||||
|
workspace: string,
|
||||||
|
repository: string,
|
||||||
|
pullRequestId: number
|
||||||
|
): Promise<{ comments: FormattedComment[]; activeCount: number; totalCount: number }> {
|
||||||
|
try {
|
||||||
|
let comments: FormattedComment[] = [];
|
||||||
|
let activeCount = 0;
|
||||||
|
let totalCount = 0;
|
||||||
|
|
||||||
|
if (this.apiClient.getIsServer()) {
|
||||||
|
// Helper function to process nested comments recursively
|
||||||
|
const processNestedComments = (comment: any, anchor: any): FormattedComment => {
|
||||||
|
const formattedComment: FormattedComment = {
|
||||||
|
id: comment.id,
|
||||||
|
author: comment.author.displayName,
|
||||||
|
text: comment.text,
|
||||||
|
created_on: new Date(comment.createdDate).toISOString(),
|
||||||
|
is_inline: !!anchor,
|
||||||
|
file_path: anchor?.path,
|
||||||
|
line_number: anchor?.line,
|
||||||
|
state: comment.state
|
||||||
|
};
|
||||||
|
|
||||||
|
// Process nested replies
|
||||||
|
if (comment.comments && comment.comments.length > 0) {
|
||||||
|
formattedComment.replies = comment.comments
|
||||||
|
.filter((reply: any) => {
|
||||||
|
// Apply same filters to replies
|
||||||
|
if (reply.state === 'RESOLVED') return false;
|
||||||
|
if (anchor && anchor.orphaned === true) return false;
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.map((reply: any) => processNestedComments(reply, anchor));
|
||||||
|
}
|
||||||
|
|
||||||
|
return formattedComment;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to count all comments including nested ones
|
||||||
|
const countAllComments = (comment: any): number => {
|
||||||
|
let count = 1;
|
||||||
|
if (comment.comments && comment.comments.length > 0) {
|
||||||
|
count += comment.comments.reduce((sum: number, reply: any) => sum + countAllComments(reply), 0);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to count active comments including nested ones
|
||||||
|
const countActiveComments = (comment: any, anchor: any): number => {
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
// Check if this comment is active
|
||||||
|
if (comment.state !== 'RESOLVED' && (!anchor || anchor.orphaned !== true)) {
|
||||||
|
count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count active nested comments
|
||||||
|
if (comment.comments && comment.comments.length > 0) {
|
||||||
|
count += comment.comments.reduce((sum: number, reply: any) => sum + countActiveComments(reply, anchor), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bitbucket Server API - fetch from activities
|
||||||
|
const apiPath = `/rest/api/1.0/projects/${workspace}/repos/${repository}/pull-requests/${pullRequestId}/activities`;
|
||||||
|
const response = await this.apiClient.makeRequest<any>('get', apiPath, undefined, {
|
||||||
|
params: { limit: 1000 }
|
||||||
|
});
|
||||||
|
|
||||||
|
const activities = response.values || [];
|
||||||
|
|
||||||
|
// Filter for comment activities
|
||||||
|
const commentActivities = activities.filter((a: any) =>
|
||||||
|
a.action === 'COMMENTED' && a.comment
|
||||||
|
);
|
||||||
|
|
||||||
|
// Count all comments including nested ones
|
||||||
|
totalCount = commentActivities.reduce((sum: number, activity: any) => {
|
||||||
|
return sum + countAllComments(activity.comment);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
// Count active comments including nested ones
|
||||||
|
activeCount = commentActivities.reduce((sum: number, activity: any) => {
|
||||||
|
return sum + countActiveComments(activity.comment, activity.commentAnchor);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
// Process top-level comments and their nested replies
|
||||||
|
const processedComments = commentActivities
|
||||||
|
.filter((a: any) => {
|
||||||
|
const c = a.comment;
|
||||||
|
const anchor = a.commentAnchor;
|
||||||
|
|
||||||
|
// Skip resolved comments
|
||||||
|
if (c.state === 'RESOLVED') return false;
|
||||||
|
|
||||||
|
// Skip orphaned inline comments
|
||||||
|
if (anchor && anchor.orphaned === true) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.map((a: any) => processNestedComments(a.comment, a.commentAnchor));
|
||||||
|
|
||||||
|
// Limit to 20 top-level comments
|
||||||
|
comments = processedComments.slice(0, 20);
|
||||||
|
} else {
|
||||||
|
// Bitbucket Cloud API
|
||||||
|
const apiPath = `/repositories/${workspace}/${repository}/pullrequests/${pullRequestId}/comments`;
|
||||||
|
const response = await this.apiClient.makeRequest<any>('get', apiPath, undefined, {
|
||||||
|
params: { pagelen: 100 }
|
||||||
|
});
|
||||||
|
|
||||||
|
const allComments = response.values || [];
|
||||||
|
totalCount = allComments.length;
|
||||||
|
|
||||||
|
// Filter for active comments (not deleted or resolved) and limit to 20
|
||||||
|
const activeComments = allComments
|
||||||
|
.filter((c: BitbucketCloudComment) => !c.deleted && !c.resolved)
|
||||||
|
.slice(0, 20);
|
||||||
|
|
||||||
|
activeCount = allComments.filter((c: BitbucketCloudComment) => !c.deleted && !c.resolved).length;
|
||||||
|
|
||||||
|
comments = activeComments.map((c: BitbucketCloudComment) => ({
|
||||||
|
id: c.id,
|
||||||
|
author: c.user.display_name,
|
||||||
|
text: c.content.raw,
|
||||||
|
created_on: c.created_on,
|
||||||
|
is_inline: !!c.inline,
|
||||||
|
file_path: c.inline?.path,
|
||||||
|
line_number: c.inline?.to
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { comments, activeCount, totalCount };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch comments:', error);
|
||||||
|
return { comments: [], activeCount: 0, totalCount: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchPullRequestFileChanges(
|
||||||
|
workspace: string,
|
||||||
|
repository: string,
|
||||||
|
pullRequestId: number
|
||||||
|
): Promise<{ fileChanges: FormattedFileChange[]; summary: any }> {
|
||||||
|
try {
|
||||||
|
let fileChanges: FormattedFileChange[] = [];
|
||||||
|
let totalLinesAdded = 0;
|
||||||
|
let totalLinesRemoved = 0;
|
||||||
|
|
||||||
|
if (this.apiClient.getIsServer()) {
|
||||||
|
// Bitbucket Server API - use changes endpoint
|
||||||
|
const apiPath = `/rest/api/1.0/projects/${workspace}/repos/${repository}/pull-requests/${pullRequestId}/changes`;
|
||||||
|
const response = await this.apiClient.makeRequest<any>('get', apiPath, undefined, {
|
||||||
|
params: { limit: 1000 }
|
||||||
|
});
|
||||||
|
|
||||||
|
const changes = response.values || [];
|
||||||
|
|
||||||
|
fileChanges = changes.map((change: any) => {
|
||||||
|
let status: 'added' | 'modified' | 'removed' | 'renamed' = 'modified';
|
||||||
|
if (change.type === 'ADD') status = 'added';
|
||||||
|
else if (change.type === 'DELETE') status = 'removed';
|
||||||
|
else if (change.type === 'MOVE' || change.type === 'RENAME') status = 'renamed';
|
||||||
|
|
||||||
|
return {
|
||||||
|
path: change.path.toString,
|
||||||
|
status,
|
||||||
|
old_path: change.srcPath?.toString
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Bitbucket Cloud API - use diffstat endpoint (has line statistics)
|
||||||
|
const apiPath = `/repositories/${workspace}/${repository}/pullrequests/${pullRequestId}/diffstat`;
|
||||||
|
const response = await this.apiClient.makeRequest<any>('get', apiPath, undefined, {
|
||||||
|
params: { pagelen: 100 }
|
||||||
|
});
|
||||||
|
|
||||||
|
const diffstats = response.values || [];
|
||||||
|
|
||||||
|
fileChanges = diffstats.map((stat: BitbucketCloudFileChange) => {
|
||||||
|
totalLinesAdded += stat.lines_added;
|
||||||
|
totalLinesRemoved += stat.lines_removed;
|
||||||
|
|
||||||
|
return {
|
||||||
|
path: stat.path,
|
||||||
|
status: stat.type,
|
||||||
|
old_path: stat.old?.path
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const summary = {
|
||||||
|
total_files: fileChanges.length
|
||||||
|
};
|
||||||
|
|
||||||
|
return { fileChanges, summary };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch file changes:', error);
|
||||||
|
return {
|
||||||
|
fileChanges: [],
|
||||||
|
summary: {
|
||||||
|
total_files: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ class BitbucketMCPServer {
|
||||||
this.server = new Server(
|
this.server = new Server(
|
||||||
{
|
{
|
||||||
name: 'bitbucket-mcp-server',
|
name: 'bitbucket-mcp-server',
|
||||||
version: '0.5.0',
|
version: '0.6.1',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
capabilities: {
|
capabilities: {
|
||||||
|
|
|
@ -262,3 +262,93 @@ export interface MergeInfo {
|
||||||
mergedAt?: string;
|
mergedAt?: string;
|
||||||
mergeCommitMessage?: string;
|
mergeCommitMessage?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Comment types
|
||||||
|
export interface BitbucketServerComment {
|
||||||
|
id: number;
|
||||||
|
version: number;
|
||||||
|
text: string;
|
||||||
|
author: {
|
||||||
|
name: string;
|
||||||
|
emailAddress: string;
|
||||||
|
displayName: string;
|
||||||
|
};
|
||||||
|
createdDate: number;
|
||||||
|
updatedDate: number;
|
||||||
|
state?: 'OPEN' | 'RESOLVED';
|
||||||
|
anchor?: {
|
||||||
|
line: number;
|
||||||
|
lineType: string;
|
||||||
|
fileType: string;
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BitbucketCloudComment {
|
||||||
|
id: number;
|
||||||
|
content: {
|
||||||
|
raw: string;
|
||||||
|
markup: string;
|
||||||
|
html: string;
|
||||||
|
};
|
||||||
|
user: {
|
||||||
|
display_name: string;
|
||||||
|
account_id: string;
|
||||||
|
};
|
||||||
|
created_on: string;
|
||||||
|
updated_on: string;
|
||||||
|
deleted?: boolean;
|
||||||
|
resolved?: boolean;
|
||||||
|
inline?: {
|
||||||
|
to: number;
|
||||||
|
from?: number;
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// File change types
|
||||||
|
export interface BitbucketServerFileChange {
|
||||||
|
path: {
|
||||||
|
toString: string;
|
||||||
|
};
|
||||||
|
executable: boolean;
|
||||||
|
percentUnchanged: number;
|
||||||
|
type: string;
|
||||||
|
nodeType: string;
|
||||||
|
srcPath?: {
|
||||||
|
toString: string;
|
||||||
|
};
|
||||||
|
linesAdded?: number;
|
||||||
|
linesRemoved?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BitbucketCloudFileChange {
|
||||||
|
path: string;
|
||||||
|
type: 'added' | 'modified' | 'removed' | 'renamed';
|
||||||
|
lines_added: number;
|
||||||
|
lines_removed: number;
|
||||||
|
old?: {
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formatted comment type for response
|
||||||
|
export interface FormattedComment {
|
||||||
|
id: number;
|
||||||
|
author: string;
|
||||||
|
text: string;
|
||||||
|
created_on: string;
|
||||||
|
is_inline: boolean;
|
||||||
|
file_path?: string;
|
||||||
|
line_number?: number;
|
||||||
|
state?: 'OPEN' | 'RESOLVED';
|
||||||
|
parent_id?: number; // For Bitbucket Cloud style replies
|
||||||
|
replies?: FormattedComment[]; // For Bitbucket Server nested replies
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formatted file change type for response
|
||||||
|
export interface FormattedFileChange {
|
||||||
|
path: string;
|
||||||
|
status: 'added' | 'modified' | 'removed' | 'renamed';
|
||||||
|
old_path?: string;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue