@atlassian-dc-mcp/bitbucket 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +53 -1
- package/build/__tests__/bitbucket-service.test.js +25 -1
- package/build/__tests__/bitbucket-service.test.js.map +1 -1
- package/build/__tests__/bitbucket-token-optimization.test.js +11 -0
- package/build/__tests__/bitbucket-token-optimization.test.js.map +1 -1
- package/build/__tests__/merge-gateway.test.d.ts +2 -0
- package/build/__tests__/merge-gateway.test.d.ts.map +1 -0
- package/build/__tests__/merge-gateway.test.js +98 -0
- package/build/__tests__/merge-gateway.test.js.map +1 -0
- package/build/__tests__/pr-comment-mapper.test.js +91 -11
- package/build/__tests__/pr-comment-mapper.test.js.map +1 -1
- package/build/__tests__/pr-merge.test.d.ts +2 -0
- package/build/__tests__/pr-merge.test.d.ts.map +1 -0
- package/build/__tests__/pr-merge.test.js +166 -0
- package/build/__tests__/pr-merge.test.js.map +1 -0
- package/build/bitbucket-response-mapper.d.ts +10 -0
- package/build/bitbucket-response-mapper.d.ts.map +1 -1
- package/build/bitbucket-response-mapper.js +16 -0
- package/build/bitbucket-response-mapper.js.map +1 -1
- package/build/bitbucket-service.d.ts +53 -9
- package/build/bitbucket-service.d.ts.map +1 -1
- package/build/bitbucket-service.js +70 -15
- package/build/bitbucket-service.js.map +1 -1
- package/build/index.js +30 -4
- package/build/index.js.map +1 -1
- package/build/merge-gateway.d.ts +34 -0
- package/build/merge-gateway.d.ts.map +1 -0
- package/build/merge-gateway.js +86 -0
- package/build/merge-gateway.js.map +1 -0
- package/build/pr-comment-mapper.d.ts +3 -0
- package/build/pr-comment-mapper.d.ts.map +1 -1
- package/build/pr-comment-mapper.js +8 -3
- package/build/pr-comment-mapper.js.map +1 -1
- package/build/pr-merge.d.ts +23 -0
- package/build/pr-merge.d.ts.map +1 -0
- package/build/pr-merge.js +59 -0
- package/build/pr-merge.js.map +1 -0
- package/package.json +3 -3
- package/src/__tests__/bitbucket-service.test.ts +78 -1
- package/src/__tests__/bitbucket-token-optimization.test.ts +11 -0
- package/src/__tests__/merge-gateway.test.ts +119 -0
- package/src/__tests__/pr-comment-mapper.test.ts +95 -11
- package/src/__tests__/pr-merge.test.ts +206 -0
- package/src/bitbucket-response-mapper.ts +27 -0
- package/src/bitbucket-service.ts +75 -14
- package/src/index.ts +45 -6
- package/src/merge-gateway.ts +132 -0
- package/src/pr-comment-mapper.ts +11 -3
- package/src/pr-merge.ts +94 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const DISABLED = { enabled: false, repos: [], targetRefs: [] };
|
|
2
|
+
const REPO_ENTRY_RE = /^[^\s/]+\/[^\s/]+$/;
|
|
3
|
+
function readBool(env, name) {
|
|
4
|
+
const value = env[name]?.trim().toLowerCase();
|
|
5
|
+
return value === 'true' || value === '1' || value === 'yes';
|
|
6
|
+
}
|
|
7
|
+
function parseList(raw) {
|
|
8
|
+
return (raw ?? '').split(/[,;\s]+/).map(entry => entry.trim()).filter(Boolean);
|
|
9
|
+
}
|
|
10
|
+
function dedupe(values) {
|
|
11
|
+
return [...new Set(values)];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Accepts `PROJECT/repository-slug` or `PROJECT/*`. The project key is upper-cased and
|
|
15
|
+
* the slug lower-cased to match the casing the REST API uses, so comparisons are exact.
|
|
16
|
+
*/
|
|
17
|
+
function normalizeRepoEntry(entry, warn) {
|
|
18
|
+
if (!REPO_ENTRY_RE.test(entry)) {
|
|
19
|
+
warn(`Ignoring merge repository entry that is not "PROJECT/repository-slug" or "PROJECT/*": "${entry}"`);
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const [projectKey, slug] = entry.split('/');
|
|
23
|
+
if (projectKey === '*') {
|
|
24
|
+
warn(`Ignoring merge repository entry that would allow every project: "${entry}"`);
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
return `${projectKey.toUpperCase()}/${slug.toLowerCase()}`;
|
|
28
|
+
}
|
|
29
|
+
/** Bare branch names are expanded so operators can write `develop` instead of `refs/heads/develop`. */
|
|
30
|
+
function normalizeRefEntry(entry) {
|
|
31
|
+
return entry.startsWith('refs/') ? entry : `refs/heads/${entry}`;
|
|
32
|
+
}
|
|
33
|
+
function matchesPattern(value, pattern) {
|
|
34
|
+
return pattern.endsWith('*') ? value.startsWith(pattern.slice(0, -1)) : value === pattern;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Reads the merge gateway configuration from the environment. Merging only activates
|
|
38
|
+
* when the flag is set and at least one repository entry is valid; otherwise a warning
|
|
39
|
+
* is logged and the gateway stays disabled.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveMergeGateway(options) {
|
|
42
|
+
const env = options?.env ?? process.env;
|
|
43
|
+
const warn = options?.warn ?? ((message) => console.error(`[merge-gateway] ${message}`));
|
|
44
|
+
if (!readBool(env, 'BITBUCKET_MERGE_ENABLED')) {
|
|
45
|
+
return DISABLED;
|
|
46
|
+
}
|
|
47
|
+
const repos = dedupe(parseList(env.BITBUCKET_MERGE_ALLOWED_REPOS)
|
|
48
|
+
.map(entry => normalizeRepoEntry(entry, warn))
|
|
49
|
+
.filter((entry) => Boolean(entry)));
|
|
50
|
+
if (repos.length === 0) {
|
|
51
|
+
warn('Merging was enabled but no valid repository is configured (set BITBUCKET_MERGE_ALLOWED_REPOS ' +
|
|
52
|
+
'to a list of "PROJECT/repository-slug" or "PROJECT/*" entries); the merge tool will stay disabled.');
|
|
53
|
+
return DISABLED;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
enabled: true,
|
|
57
|
+
repos,
|
|
58
|
+
targetRefs: dedupe(parseList(env.BITBUCKET_MERGE_ALLOWED_TARGET_REFS).map(normalizeRefEntry)),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Throws unless the gateway allows merging in this repository. No network call. */
|
|
62
|
+
export function assertRepoMergeAllowed(gateway, projectKey, repositorySlug) {
|
|
63
|
+
if (!gateway.enabled) {
|
|
64
|
+
throw new Error('Merging pull requests is disabled on this server. Enable it with BITBUCKET_MERGE_ENABLED ' +
|
|
65
|
+
'and list the allowed repositories in BITBUCKET_MERGE_ALLOWED_REPOS.');
|
|
66
|
+
}
|
|
67
|
+
const target = `${projectKey.toUpperCase()}/${repositorySlug.toLowerCase()}`;
|
|
68
|
+
if (!gateway.repos.some(pattern => matchesPattern(target, pattern))) {
|
|
69
|
+
throw new Error(`Merging is not allowed in ${target} on this server. Allowed: ${gateway.repos.join(', ')}.`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Throws unless the gateway allows merging into this target ref. A gateway with no ref restriction allows all. */
|
|
73
|
+
export function assertTargetRefMergeAllowed(gateway, targetRefId) {
|
|
74
|
+
if (gateway.targetRefs.length === 0) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!targetRefId) {
|
|
78
|
+
throw new Error('Could not determine the target branch of the pull request, and this server restricts which ' +
|
|
79
|
+
'branches may be merged into (BITBUCKET_MERGE_ALLOWED_TARGET_REFS); refusing to merge.');
|
|
80
|
+
}
|
|
81
|
+
if (!gateway.targetRefs.some(pattern => matchesPattern(targetRefId, pattern))) {
|
|
82
|
+
throw new Error(`Merging into ${targetRefId} is not allowed on this server. ` +
|
|
83
|
+
`Allowed target refs: ${gateway.targetRefs.join(', ')}.`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=merge-gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-gateway.js","sourceRoot":"","sources":["../src/merge-gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,6 +26,7 @@ interface SimplifiedComment {
|
|
|
26
26
|
comments: SimplifiedComment[];
|
|
27
27
|
threadResolved: boolean;
|
|
28
28
|
state: string;
|
|
29
|
+
severity: string;
|
|
29
30
|
}
|
|
30
31
|
interface SimplifiedActivity {
|
|
31
32
|
id: number;
|
|
@@ -43,6 +44,8 @@ export interface SimplifiedPRResponse {
|
|
|
43
44
|
prAuthor?: SimplifiedUser;
|
|
44
45
|
commentCount: number;
|
|
45
46
|
unresolvedCount: number;
|
|
47
|
+
blockerCount: number;
|
|
48
|
+
unresolvedBlockerCount: number;
|
|
46
49
|
};
|
|
47
50
|
}
|
|
48
51
|
export interface PullRequestCommentOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-comment-mapper.d.ts","sourceRoot":"","sources":["../src/pr-comment-mapper.ts"],"names":[],"mappings":"AAsHA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAGD,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,iBAAiB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"pr-comment-mapper.d.ts","sourceRoot":"","sources":["../src/pr-comment-mapper.ts"],"names":[],"mappings":"AAsHA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAGD,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,iBAAiB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,kBAAkB;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,OAAO,EAAE;QACP,eAAe,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,EAAE,cAAc,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,YAAY,EAAE,MAAM,CAAC;QACrB,sBAAsB,EAAE,MAAM,CAAC;KAChC,CAAC;CACH;AAED,MAAM,WAAW,yBAAyB;IACxC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA4HD,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,sBAAsB,EAChC,OAAO,GAAE,yBAA8B,GACtC,sBAAsB,CAyBxB;AAeD,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,sBAAsB,EAChC,OAAO,GAAE,yBAA8B,GACtC,oBAAoB,GAAG,sBAAsB,CAsC/C;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,sBAAsB,EAAE,OAAO,GAAE,yBAA8B,GAAG,MAAM,EAAE,CAmBrH"}
|
|
@@ -80,7 +80,8 @@ function simplifyComment(comment, ancestorIds = new Set()) {
|
|
|
80
80
|
.filter(childComment => !nextAncestorIds.has(childComment.id))
|
|
81
81
|
.map(childComment => simplifyComment(childComment, nextAncestorIds)),
|
|
82
82
|
threadResolved: comment.threadResolved,
|
|
83
|
-
state: comment.state
|
|
83
|
+
state: comment.state,
|
|
84
|
+
severity: comment.severity
|
|
84
85
|
};
|
|
85
86
|
}
|
|
86
87
|
function filterComment(comment, includeResolved, ancestorIds = new Set()) {
|
|
@@ -149,9 +150,11 @@ export function simplifyBitbucketPRComments(response, options = {}) {
|
|
|
149
150
|
}
|
|
150
151
|
// Find PR author (usually the one who OPENED the PR)
|
|
151
152
|
const prAuthor = activities.find(a => a.action === 'OPENED')?.user;
|
|
152
|
-
// Count comments and
|
|
153
|
+
// Count comments, unresolved threads and blocker tasks
|
|
153
154
|
const comments = activities.filter(a => a.action === 'COMMENTED' && a.comment);
|
|
154
155
|
const unresolvedCount = comments.filter(a => a.comment && !a.comment.threadResolved).length;
|
|
156
|
+
const blockers = comments.filter(a => a.comment && a.comment.severity === 'BLOCKER');
|
|
157
|
+
const unresolvedBlockerCount = blockers.filter(a => a.comment && a.comment.state !== 'RESOLVED').length;
|
|
155
158
|
return {
|
|
156
159
|
isLastPage: filteredResponse.isLastPage ?? true,
|
|
157
160
|
activities,
|
|
@@ -159,7 +162,9 @@ export function simplifyBitbucketPRComments(response, options = {}) {
|
|
|
159
162
|
totalActivities: activities.length,
|
|
160
163
|
...(prAuthor && { prAuthor }),
|
|
161
164
|
commentCount: comments.length,
|
|
162
|
-
unresolvedCount
|
|
165
|
+
unresolvedCount,
|
|
166
|
+
blockerCount: blockers.length,
|
|
167
|
+
unresolvedBlockerCount
|
|
163
168
|
}
|
|
164
169
|
};
|
|
165
170
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-comment-mapper.js","sourceRoot":"","sources":["../src/pr-comment-mapper.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pr-comment-mapper.js","sourceRoot":"","sources":["../src/pr-comment-mapper.ts"],"names":[],"mappings":"AAmLA,oDAAoD;AACpD,SAAS,eAAe,CAAC,GAAY;IACnC,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACZ,OAAQ,GAAW,CAAC,IAAI,KAAK,QAAQ;QACrC,OAAQ,GAAW,CAAC,YAAY,KAAK,QAAQ;QAC7C,OAAQ,GAAW,CAAC,MAAM,KAAK,SAAS;QACxC,OAAQ,GAAW,CAAC,WAAW,KAAK,QAAQ;QAC5C,OAAQ,GAAW,CAAC,EAAE,KAAK,QAAQ;QACnC,OAAQ,GAAW,CAAC,IAAI,KAAK,QAAQ;QACrC,OAAQ,GAAW,CAAC,IAAI,KAAK,QAAQ;QACrC,OAAQ,GAAW,CAAC,KAAK,KAAK,QAAQ,CACvC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,GAAY;IACnC,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACZ,OAAQ,GAAW,CAAC,QAAQ,KAAK,QAAQ;QACzC,OAAQ,GAAW,CAAC,MAAM,KAAK,QAAQ;QACvC,OAAQ,GAAW,CAAC,IAAI,KAAK,QAAQ;QACrC,OAAQ,GAAW,CAAC,QAAQ,KAAK,QAAQ;QACzC,OAAQ,GAAW,CAAC,QAAQ,KAAK,QAAQ;QACzC,OAAQ,GAAW,CAAC,IAAI,KAAK,QAAQ;QACrC,OAAQ,GAAW,CAAC,QAAQ,KAAK,QAAQ;QACzC,OAAQ,GAAW,CAAC,QAAQ,KAAK,SAAS,CAC3C,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,GAAY;IAC7B,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACZ,OAAQ,GAAW,CAAC,EAAE,KAAK,QAAQ;QACnC,OAAQ,GAAW,CAAC,OAAO,KAAK,QAAQ;QACxC,OAAQ,GAAW,CAAC,IAAI,KAAK,QAAQ;QACrC,eAAe,CAAE,GAAW,CAAC,MAAM,CAAC;QACpC,OAAQ,GAAW,CAAC,WAAW,KAAK,QAAQ;QAC5C,OAAQ,GAAW,CAAC,WAAW,KAAK,QAAQ;QAC5C,KAAK,CAAC,OAAO,CAAE,GAAW,CAAC,QAAQ,CAAC;QACpC,OAAQ,GAAW,CAAC,cAAc,KAAK,SAAS;QAChD,OAAQ,GAAW,CAAC,QAAQ,KAAK,QAAQ;QACzC,OAAQ,GAAW,CAAC,KAAK,KAAK,QAAQ;QACtC,OAAQ,GAAW,CAAC,UAAU,KAAK,QAAQ;QAC3C,OAAQ,GAAW,CAAC,mBAAmB,KAAK,QAAQ,CACrD,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,GAAY;IAChC,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACZ,OAAQ,GAAW,CAAC,EAAE,KAAK,QAAQ;QACnC,OAAQ,GAAW,CAAC,WAAW,KAAK,QAAQ;QAC5C,eAAe,CAAE,GAAW,CAAC,IAAI,CAAC;QAClC,OAAQ,GAAW,CAAC,MAAM,KAAK,QAAQ,CACxC,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,IAAmB;IACvC,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,MAAqB;IAC3C,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,CAAC,MAAM,CAAC,eAAe;YACxB,CAAC,CAAC;gBACE,SAAS,EAAE,MAAM,CAAC,eAAe,CAAC,SAAS;gBAC3C,aAAa,EAAE,MAAM,CAAC,eAAe,CAAC,aAAa;aACpD;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,OAAgB,EAAE,cAA2B,IAAI,GAAG,EAAE;IAC7E,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7C,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAEhC,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC;QACpC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACjE,QAAQ,EAAE,OAAO,CAAC,QAAQ;aACvB,MAAM,CAAC,SAAS,CAAC;aACjB,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;aAC7D,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,eAAe,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;QACtE,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,OAAgB,EAAE,eAAwB,EAAE,cAA2B,IAAI,GAAG,EAAE;IACrG,IAAI,CAAC,eAAe,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7C,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAEhC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ;SAC9B,MAAM,CAAC,SAAS,CAAC;SACjB,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;SAC7D,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC;SAClF,MAAM,CAAC,CAAC,YAAY,EAA2B,EAAE,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC;IAE5E,OAAO;QACL,GAAG,OAAO;QACV,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,QAAgC,EAChC,UAAqC,EAAE;IAEvC,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,KAAK,CAAC;IAEzD,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO;QACL,GAAG,QAAQ;QACX,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;YACjD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpH,OAAO,CAAC,QAAQ,CAAC,CAAC;YACpB,CAAC;YAED,MAAM,eAAe,GAAG,aAAa,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;YACzE,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,OAAO,CAAC;oBACN,GAAG,QAAQ;oBACX,OAAO,EAAE,eAAe;iBACzB,CAAC,CAAC;QACL,CAAC,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAoB;IAC5C,OAAO;QACL,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC;QACjC,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,GAAG,CAAC,QAAQ,CAAC,aAAa,IAAI,EAAE,aAAa,EAAE,QAAQ,CAAC,aAAa,EAAE,CAAC;QACxE,GAAG,CAAC,QAAQ,CAAC,OAAO,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;YACrD,OAAO,EAAE,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC;SAC3C,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,QAAgC,EAChC,UAAqC,EAAE;IAEvC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtE,MAAM,UAAU,GAAyB,EAAE,CAAC;IAE5C,mDAAmD;IACnD,KAAK,MAAM,QAAQ,IAAI,gBAAgB,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACrD,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,4EAA4E;IAC9E,CAAC;IAED,kEAAkE;IAClE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1E,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,qDAAqD;IACrD,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,EAAE,IAAI,CAAC;IAEnE,uDAAuD;IACvD,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;IAC/E,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC;IAC5F,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IACrF,MAAM,sBAAsB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;IAExG,OAAO;QACL,UAAU,EAAE,gBAAgB,CAAC,UAAU,IAAI,IAAI;QAC/C,UAAU;QACV,OAAO,EAAE;YACP,eAAe,EAAE,UAAU,CAAC,MAAM;YAClC,GAAG,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,CAAC;YAC7B,YAAY,EAAE,QAAQ,CAAC,MAAM;YAC7B,eAAe;YACf,YAAY,EAAE,QAAQ,CAAC,MAAM;YAC7B,sBAAsB;SACvB;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgC,EAAE,UAAqC,EAAE;IACzG,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtE,MAAM,gBAAgB,GAAa,EAAE,CAAC;IAEtC,KAAK,MAAM,QAAQ,IAAI,gBAAgB,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACrD,gDAAgD;QAChD,IAAI,YAAY,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,WAAW,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YAClF,8CAA8C;YAC9C,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;gBACjC,gBAAgB,CAAC,IAAI,CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,OAAO,OAAO,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,KAAK,OAAO,CAAC,IAAI,EAAE,CAClH,CAAC;YACJ,CAAC;QACH,CAAC;QACD,4EAA4E;IAC9E,CAAC;IAED,OAAO,gBAAgB,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BitbucketMutationOutputMode } from './bitbucket-response-mapper.js';
|
|
2
|
+
import { type MergeGateway } from './merge-gateway.js';
|
|
3
|
+
export interface MergePullRequestParams {
|
|
4
|
+
projectKey: string;
|
|
5
|
+
repositorySlug: string;
|
|
6
|
+
pullRequestId: string;
|
|
7
|
+
/** Current PR version, required for optimistic locking. */
|
|
8
|
+
version: number;
|
|
9
|
+
gateway: MergeGateway;
|
|
10
|
+
strategyId?: string;
|
|
11
|
+
message?: string;
|
|
12
|
+
output?: BitbucketMutationOutputMode;
|
|
13
|
+
}
|
|
14
|
+
/** Read-only mergeability check: reports conflicts and merge-check vetoes. */
|
|
15
|
+
export declare function fetchMergeability(projectKey: string, repositorySlug: string, pullRequestId: string): Promise<import("@atlassian-dc-mcp/common").ApiErrorResponse<import("./bitbucket-client/index.js").RestPullRequestMergeability>>;
|
|
16
|
+
/**
|
|
17
|
+
* Merge a pull request under the operator's merge policy. Order matters: the repository
|
|
18
|
+
* (and target branch, when restricted) is checked before any request, and the mergeability
|
|
19
|
+
* check runs before the POST so a conflicted or vetoed pull request is refused without
|
|
20
|
+
* issuing the write.
|
|
21
|
+
*/
|
|
22
|
+
export declare function mergePullRequest(params: MergePullRequestParams): Promise<import("@atlassian-dc-mcp/common").ApiErrorResponse<import("./bitbucket-client/index.js").RestPullRequest>>;
|
|
23
|
+
//# sourceMappingURL=pr-merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-merge.d.ts","sourceRoot":"","sources":["../src/pr-merge.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,2BAA2B,EAG5B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAuD,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE5G,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,2BAA2B,CAAC;CACtC;AAED,8EAA8E;AAC9E,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,mIAWxG;AAkCD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,uHAoBpE"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { handleApiOperation } from '@atlassian-dc-mcp/common';
|
|
2
|
+
import { PullRequestsService } from './bitbucket-client/index.js';
|
|
3
|
+
import { shapeMergeability, shapePullRequestAck, } from './bitbucket-response-mapper.js';
|
|
4
|
+
import { assertRepoMergeAllowed, assertTargetRefMergeAllowed } from './merge-gateway.js';
|
|
5
|
+
/** Read-only mergeability check: reports conflicts and merge-check vetoes. */
|
|
6
|
+
export async function fetchMergeability(projectKey, repositorySlug, pullRequestId) {
|
|
7
|
+
const result = await handleApiOperation(() => PullRequestsService.canMerge(projectKey, pullRequestId, repositorySlug), 'Error checking pull request mergeability');
|
|
8
|
+
if (result.success && result.data) {
|
|
9
|
+
return { ...result, data: shapeMergeability(result.data) };
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
function describeVetoes(vetoes) {
|
|
14
|
+
return vetoes
|
|
15
|
+
.map(veto => [veto.summary, veto.detail].filter(Boolean).join(' — '))
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.join('; ');
|
|
18
|
+
}
|
|
19
|
+
async function assertMergeable(projectKey, repositorySlug, pullRequestId) {
|
|
20
|
+
const mergeability = shapeMergeability(await PullRequestsService.canMerge(projectKey, pullRequestId, repositorySlug));
|
|
21
|
+
if (mergeability.canMerge) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const cause = mergeability.conflicted ? 'it has conflicts' : 'a merge check vetoed the merge';
|
|
25
|
+
const reasons = describeVetoes(mergeability.vetoes);
|
|
26
|
+
throw new Error(`Pull request cannot be merged: ${cause}${reasons ? `. ${reasons}` : ''}`);
|
|
27
|
+
}
|
|
28
|
+
/** Only fetches the pull request when the operator restricts target branches. */
|
|
29
|
+
async function assertTargetRefAllowed(params) {
|
|
30
|
+
if (params.gateway.targetRefs.length === 0) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const pullRequest = await PullRequestsService.get3(params.projectKey, params.pullRequestId, params.repositorySlug);
|
|
34
|
+
assertTargetRefMergeAllowed(params.gateway, pullRequest?.toRef?.id);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Merge a pull request under the operator's merge policy. Order matters: the repository
|
|
38
|
+
* (and target branch, when restricted) is checked before any request, and the mergeability
|
|
39
|
+
* check runs before the POST so a conflicted or vetoed pull request is refused without
|
|
40
|
+
* issuing the write.
|
|
41
|
+
*/
|
|
42
|
+
export async function mergePullRequest(params) {
|
|
43
|
+
const { projectKey, repositorySlug, pullRequestId, version, gateway } = params;
|
|
44
|
+
const result = await handleApiOperation(async () => {
|
|
45
|
+
assertRepoMergeAllowed(gateway, projectKey, repositorySlug);
|
|
46
|
+
await assertTargetRefAllowed(params);
|
|
47
|
+
await assertMergeable(projectKey, repositorySlug, pullRequestId);
|
|
48
|
+
return PullRequestsService.merge(projectKey, pullRequestId, repositorySlug, String(version), {
|
|
49
|
+
version,
|
|
50
|
+
...(params.strategyId ? { strategyId: params.strategyId } : {}),
|
|
51
|
+
...(params.message ? { message: params.message } : {}),
|
|
52
|
+
});
|
|
53
|
+
}, 'Error merging pull request');
|
|
54
|
+
if (result.success && result.data && params.output !== 'full') {
|
|
55
|
+
return { ...result, data: shapePullRequestAck(result.data) };
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=pr-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-merge.js","sourceRoot":"","sources":["../src/pr-merge.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlassian-dc-mcp/bitbucket",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"main": "build/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "./bin/run.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"test": "jest"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@atlassian-dc-mcp/common": "^0.
|
|
34
|
+
"@atlassian-dc-mcp/common": "^0.30.0",
|
|
35
35
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
36
36
|
"dotenv": "^16.4.7",
|
|
37
37
|
"zod": "^3.24.2"
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "92a4fc60548de5ee374489deef4d09271536014f"
|
|
52
52
|
}
|
|
@@ -2166,7 +2166,7 @@ describe('BitbucketService', () => {
|
|
|
2166
2166
|
const mockComment = { id: 502, version: 4, text: 'New body', state: 'RESOLVED', severity: 'BLOCKER' };
|
|
2167
2167
|
(PullRequestsService.updateComment2 as jest.Mock).mockResolvedValue(mockComment);
|
|
2168
2168
|
|
|
2169
|
-
await bitbucketService.updatePullRequestComment(
|
|
2169
|
+
const result = await bitbucketService.updatePullRequestComment(
|
|
2170
2170
|
mockProjectKey,
|
|
2171
2171
|
mockRepositorySlug,
|
|
2172
2172
|
mockPullRequestId,
|
|
@@ -2184,6 +2184,83 @@ describe('BitbucketService', () => {
|
|
|
2184
2184
|
mockRepositorySlug,
|
|
2185
2185
|
{ version: 3, text: 'New body', state: 'RESOLVED', severity: 'BLOCKER' }
|
|
2186
2186
|
);
|
|
2187
|
+
expect(result.data).toMatchObject({ state: 'RESOLVED', severity: 'BLOCKER' });
|
|
2188
|
+
});
|
|
2189
|
+
|
|
2190
|
+
it('should resolve a comment thread by sending threadResolved true', async () => {
|
|
2191
|
+
const mockComment = { id: 504, version: 3, state: 'OPEN', threadResolved: true };
|
|
2192
|
+
(PullRequestsService.updateComment2 as jest.Mock).mockResolvedValue(mockComment);
|
|
2193
|
+
|
|
2194
|
+
const result = await bitbucketService.updatePullRequestComment(
|
|
2195
|
+
mockProjectKey,
|
|
2196
|
+
mockRepositorySlug,
|
|
2197
|
+
mockPullRequestId,
|
|
2198
|
+
'504',
|
|
2199
|
+
2,
|
|
2200
|
+
undefined, // text
|
|
2201
|
+
undefined, // state
|
|
2202
|
+
undefined, // severity
|
|
2203
|
+
true // threadResolved
|
|
2204
|
+
);
|
|
2205
|
+
|
|
2206
|
+
expect(PullRequestsService.updateComment2).toHaveBeenCalledWith(
|
|
2207
|
+
mockProjectKey,
|
|
2208
|
+
'504',
|
|
2209
|
+
mockPullRequestId,
|
|
2210
|
+
mockRepositorySlug,
|
|
2211
|
+
{ version: 2, threadResolved: true }
|
|
2212
|
+
);
|
|
2213
|
+
expect(result.data).toMatchObject({ state: 'OPEN', threadResolved: true });
|
|
2214
|
+
});
|
|
2215
|
+
|
|
2216
|
+
it('should reopen a comment thread by sending threadResolved false', async () => {
|
|
2217
|
+
const mockComment = { id: 505, version: 4, threadResolved: false };
|
|
2218
|
+
(PullRequestsService.updateComment2 as jest.Mock).mockResolvedValue(mockComment);
|
|
2219
|
+
|
|
2220
|
+
await bitbucketService.updatePullRequestComment(
|
|
2221
|
+
mockProjectKey,
|
|
2222
|
+
mockRepositorySlug,
|
|
2223
|
+
mockPullRequestId,
|
|
2224
|
+
'505',
|
|
2225
|
+
3,
|
|
2226
|
+
undefined,
|
|
2227
|
+
undefined,
|
|
2228
|
+
undefined,
|
|
2229
|
+
false
|
|
2230
|
+
);
|
|
2231
|
+
|
|
2232
|
+
expect(PullRequestsService.updateComment2).toHaveBeenCalledWith(
|
|
2233
|
+
mockProjectKey,
|
|
2234
|
+
'505',
|
|
2235
|
+
mockPullRequestId,
|
|
2236
|
+
mockRepositorySlug,
|
|
2237
|
+
{ version: 3, threadResolved: false }
|
|
2238
|
+
);
|
|
2239
|
+
});
|
|
2240
|
+
|
|
2241
|
+
it('should set task state and thread resolution independently in one update', async () => {
|
|
2242
|
+
const mockComment = { id: 506, version: 5, state: 'OPEN', threadResolved: true };
|
|
2243
|
+
(PullRequestsService.updateComment2 as jest.Mock).mockResolvedValue(mockComment);
|
|
2244
|
+
|
|
2245
|
+
await bitbucketService.updatePullRequestComment(
|
|
2246
|
+
mockProjectKey,
|
|
2247
|
+
mockRepositorySlug,
|
|
2248
|
+
mockPullRequestId,
|
|
2249
|
+
'506',
|
|
2250
|
+
4,
|
|
2251
|
+
undefined,
|
|
2252
|
+
'OPEN',
|
|
2253
|
+
undefined,
|
|
2254
|
+
true
|
|
2255
|
+
);
|
|
2256
|
+
|
|
2257
|
+
expect(PullRequestsService.updateComment2).toHaveBeenCalledWith(
|
|
2258
|
+
mockProjectKey,
|
|
2259
|
+
'506',
|
|
2260
|
+
mockPullRequestId,
|
|
2261
|
+
mockRepositorySlug,
|
|
2262
|
+
{ version: 4, state: 'OPEN', threadResolved: true }
|
|
2263
|
+
);
|
|
2187
2264
|
});
|
|
2188
2265
|
|
|
2189
2266
|
it('should propagate API errors', async () => {
|
|
@@ -143,6 +143,7 @@ describe('BitbucketService token optimization paths', () => {
|
|
|
143
143
|
comments: [],
|
|
144
144
|
threadResolved: false,
|
|
145
145
|
state: 'OPEN',
|
|
146
|
+
severity: 'NORMAL',
|
|
146
147
|
},
|
|
147
148
|
},
|
|
148
149
|
],
|
|
@@ -151,6 +152,8 @@ describe('BitbucketService token optimization paths', () => {
|
|
|
151
152
|
prAuthor: { name: 'author', displayName: 'Author' },
|
|
152
153
|
commentCount: 1,
|
|
153
154
|
unresolvedCount: 1,
|
|
155
|
+
blockerCount: 0,
|
|
156
|
+
unresolvedBlockerCount: 0,
|
|
154
157
|
},
|
|
155
158
|
});
|
|
156
159
|
expect(PullRequestsService.getActivities).toHaveBeenCalledWith('TEST', '123', 'repo', undefined, undefined, undefined, 25);
|
|
@@ -202,6 +205,8 @@ describe('BitbucketService token optimization paths', () => {
|
|
|
202
205
|
prAuthor: { name: 'author', displayName: 'Author' },
|
|
203
206
|
commentCount: 0,
|
|
204
207
|
unresolvedCount: 0,
|
|
208
|
+
blockerCount: 0,
|
|
209
|
+
unresolvedBlockerCount: 0,
|
|
205
210
|
},
|
|
206
211
|
});
|
|
207
212
|
expect(includeResolvedResult.success).toBe(true);
|
|
@@ -238,10 +243,12 @@ describe('BitbucketService token optimization paths', () => {
|
|
|
238
243
|
comments: [],
|
|
239
244
|
threadResolved: true,
|
|
240
245
|
state: 'OPEN',
|
|
246
|
+
severity: 'NORMAL',
|
|
241
247
|
},
|
|
242
248
|
],
|
|
243
249
|
threadResolved: true,
|
|
244
250
|
state: 'OPEN',
|
|
251
|
+
severity: 'NORMAL',
|
|
245
252
|
},
|
|
246
253
|
},
|
|
247
254
|
],
|
|
@@ -250,6 +257,8 @@ describe('BitbucketService token optimization paths', () => {
|
|
|
250
257
|
prAuthor: { name: 'author', displayName: 'Author' },
|
|
251
258
|
commentCount: 1,
|
|
252
259
|
unresolvedCount: 0,
|
|
260
|
+
blockerCount: 0,
|
|
261
|
+
unresolvedBlockerCount: 0,
|
|
253
262
|
},
|
|
254
263
|
});
|
|
255
264
|
});
|
|
@@ -267,6 +276,8 @@ describe('BitbucketService token optimization paths', () => {
|
|
|
267
276
|
prAuthor: { name: 'author', displayName: 'Author' },
|
|
268
277
|
commentCount: 1,
|
|
269
278
|
unresolvedCount: 1,
|
|
279
|
+
blockerCount: 0,
|
|
280
|
+
unresolvedBlockerCount: 0,
|
|
270
281
|
},
|
|
271
282
|
items: ['Reviewer on src/app.ts:10: Looks good'],
|
|
272
283
|
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertRepoMergeAllowed,
|
|
3
|
+
assertTargetRefMergeAllowed,
|
|
4
|
+
resolveMergeGateway,
|
|
5
|
+
} from '../merge-gateway.js';
|
|
6
|
+
|
|
7
|
+
const silentWarn = () => undefined;
|
|
8
|
+
|
|
9
|
+
describe('resolveMergeGateway', () => {
|
|
10
|
+
it('is disabled by default', () => {
|
|
11
|
+
const gateway = resolveMergeGateway({ env: {}, warn: silentWarn });
|
|
12
|
+
expect(gateway.enabled).toBe(false);
|
|
13
|
+
expect(gateway.repos).toEqual([]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('stays disabled when enabled without any repository', () => {
|
|
17
|
+
const gateway = resolveMergeGateway({ env: { BITBUCKET_MERGE_ENABLED: 'true' }, warn: silentWarn });
|
|
18
|
+
expect(gateway.enabled).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('stays disabled when every configured repository entry is malformed', () => {
|
|
22
|
+
const gateway = resolveMergeGateway({
|
|
23
|
+
env: { BITBUCKET_MERGE_ENABLED: 'true', BITBUCKET_MERGE_ALLOWED_REPOS: 'demo, PROJ/a/b, */*' },
|
|
24
|
+
warn: silentWarn,
|
|
25
|
+
});
|
|
26
|
+
expect(gateway.enabled).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('normalizes repository entries and de-duplicates them', () => {
|
|
30
|
+
const gateway = resolveMergeGateway({
|
|
31
|
+
env: {
|
|
32
|
+
BITBUCKET_MERGE_ENABLED: 'yes',
|
|
33
|
+
BITBUCKET_MERGE_ALLOWED_REPOS: 'proj/Demo, PROJ/demo; OTHER/*',
|
|
34
|
+
},
|
|
35
|
+
warn: silentWarn,
|
|
36
|
+
});
|
|
37
|
+
expect(gateway.enabled).toBe(true);
|
|
38
|
+
expect(gateway.repos).toEqual(['PROJ/demo', 'OTHER/*']);
|
|
39
|
+
expect(gateway.targetRefs).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('expands bare branch names into fully-qualified target refs', () => {
|
|
43
|
+
const gateway = resolveMergeGateway({
|
|
44
|
+
env: {
|
|
45
|
+
BITBUCKET_MERGE_ENABLED: '1',
|
|
46
|
+
BITBUCKET_MERGE_ALLOWED_REPOS: 'PROJ/demo',
|
|
47
|
+
BITBUCKET_MERGE_ALLOWED_TARGET_REFS: 'develop, refs/heads/release/*',
|
|
48
|
+
},
|
|
49
|
+
warn: silentWarn,
|
|
50
|
+
});
|
|
51
|
+
expect(gateway.targetRefs).toEqual(['refs/heads/develop', 'refs/heads/release/*']);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('warns about ignored entries and about being enabled with no valid repository', () => {
|
|
55
|
+
const warnings: string[] = [];
|
|
56
|
+
resolveMergeGateway({
|
|
57
|
+
env: { BITBUCKET_MERGE_ENABLED: 'true', BITBUCKET_MERGE_ALLOWED_REPOS: 'demo' },
|
|
58
|
+
warn: message => warnings.push(message),
|
|
59
|
+
});
|
|
60
|
+
expect(warnings).toHaveLength(2);
|
|
61
|
+
expect(warnings[0]).toContain('"demo"');
|
|
62
|
+
expect(warnings[1]).toContain('stay disabled');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('assertRepoMergeAllowed', () => {
|
|
67
|
+
const gateway = resolveMergeGateway({
|
|
68
|
+
env: { BITBUCKET_MERGE_ENABLED: 'true', BITBUCKET_MERGE_ALLOWED_REPOS: 'PROJ/demo, OTHER/*' },
|
|
69
|
+
warn: silentWarn,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('refuses everything when merging is disabled', () => {
|
|
73
|
+
expect(() => assertRepoMergeAllowed({ enabled: false, repos: [], targetRefs: [] }, 'PROJ', 'demo'))
|
|
74
|
+
.toThrow(/disabled on this server/);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('allows an exact repository regardless of the casing used by the caller', () => {
|
|
78
|
+
expect(() => assertRepoMergeAllowed(gateway, 'proj', 'DEMO')).not.toThrow();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('allows any repository in a wildcard project', () => {
|
|
82
|
+
expect(() => assertRepoMergeAllowed(gateway, 'OTHER', 'anything')).not.toThrow();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('refuses a repository outside the allowed list', () => {
|
|
86
|
+
expect(() => assertRepoMergeAllowed(gateway, 'PROJ', 'other-repo')).toThrow(/not allowed in PROJ\/other-repo/);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('does not treat a wildcard project as a prefix of another project', () => {
|
|
90
|
+
expect(() => assertRepoMergeAllowed(gateway, 'OTHERS', 'demo')).toThrow(/not allowed/);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('assertTargetRefMergeAllowed', () => {
|
|
95
|
+
const unrestricted = { enabled: true, repos: ['PROJ/demo'], targetRefs: [] };
|
|
96
|
+
const restricted = {
|
|
97
|
+
enabled: true,
|
|
98
|
+
repos: ['PROJ/demo'],
|
|
99
|
+
targetRefs: ['refs/heads/develop', 'refs/heads/release/*'],
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
it('allows any ref when no target-ref restriction is configured', () => {
|
|
103
|
+
expect(() => assertTargetRefMergeAllowed(unrestricted, 'refs/heads/master')).not.toThrow();
|
|
104
|
+
expect(() => assertTargetRefMergeAllowed(unrestricted, undefined)).not.toThrow();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('allows an exact and a wildcard target ref', () => {
|
|
108
|
+
expect(() => assertTargetRefMergeAllowed(restricted, 'refs/heads/develop')).not.toThrow();
|
|
109
|
+
expect(() => assertTargetRefMergeAllowed(restricted, 'refs/heads/release/1.2')).not.toThrow();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('refuses a target ref outside the allowed list', () => {
|
|
113
|
+
expect(() => assertTargetRefMergeAllowed(restricted, 'refs/heads/master')).toThrow(/refs\/heads\/master is not allowed/);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('refuses when the target ref is unknown but restrictions apply', () => {
|
|
117
|
+
expect(() => assertTargetRefMergeAllowed(restricted, undefined)).toThrow(/Could not determine the target branch/);
|
|
118
|
+
});
|
|
119
|
+
});
|