Skip to content

Commit

Permalink
fix: bitbucket inactive reviewers (#11834)
Browse files Browse the repository at this point in the history
  • Loading branch information
setchy committed Oct 7, 2021
1 parent d80bc01 commit 0c977e4
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 11 deletions.
154 changes: 154 additions & 0 deletions lib/platform/bitbucket/__snapshots__/index.spec.ts.snap
Expand Up @@ -1611,6 +1611,160 @@ Array [
]
`;

exports[`platform/bitbucket/index updatePr() removes inactive reviewers when updating pr 1`] = `
Array [
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo",
},
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5",
},
Object {
"body": Object {
"description": "body",
"reviewers": Array [
Object {
"account_id": "456",
"display_name": "Jane Smith",
"uuid": "{90b6646d-1724-4a64-9fd9-539515fe94e9}",
},
Object {
"account_id": "123",
"display_name": "Bob Smith",
"uuid": "{d2238482-2e9f-48b3-8630-de22ccb9e42f}",
},
],
"title": "title",
},
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"content-length": "245",
"content-type": "application/json",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "PUT",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5",
},
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/users/456",
},
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/users/123",
},
Object {
"body": Object {
"description": "body",
"reviewers": Array [
Object {
"account_id": "456",
"display_name": "Jane Smith",
"uuid": "{90b6646d-1724-4a64-9fd9-539515fe94e9}",
},
],
"title": "title",
},
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"content-length": "149",
"content-type": "application/json",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "PUT",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5",
},
]
`;

exports[`platform/bitbucket/index updatePr() rethrows exception when PR update error not due to inactive reviewers 1`] = `"Response code 400 (Bad Request)"`;

exports[`platform/bitbucket/index updatePr() rethrows exception when PR update error not due to inactive reviewers 2`] = `
Array [
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo",
},
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5",
},
Object {
"body": Object {
"description": "body",
"reviewers": Array [
Object {
"display_name": "Jane Smith",
"uuid": "{90b6646d-1724-4a64-9fd9-539515fe94e9}",
},
],
"title": "title",
},
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"content-length": "130",
"content-type": "application/json",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "PUT",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5",
},
]
`;

exports[`platform/bitbucket/index updatePr() throws an error on failure to get current list of reviewers 1`] = `"Response code 500 (Internal Server Error)"`;

exports[`platform/bitbucket/index updatePr() throws an error on failure to get current list of reviewers 2`] = `
Expand Down
63 changes: 63 additions & 0 deletions lib/platform/bitbucket/index.spec.ts
Expand Up @@ -765,6 +765,69 @@ describe('platform/bitbucket/index', () => {
await bitbucket.updatePr({ number: 5, prTitle: 'title', prBody: 'body' });
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('removes inactive reviewers when updating pr', async () => {
const inactiveReviewer = {
display_name: 'Bob Smith',
uuid: '{d2238482-2e9f-48b3-8630-de22ccb9e42f}',
account_id: '123',
};
const activeReviewer = {
display_name: 'Jane Smith',
uuid: '{90b6646d-1724-4a64-9fd9-539515fe94e9}',
account_id: '456',
};
const scope = await initRepoMock();
scope
.get('/2.0/repositories/some/repo/pullrequests/5')
.reply(200, { reviewers: [activeReviewer, inactiveReviewer] })
.put('/2.0/repositories/some/repo/pullrequests/5')
.reply(400, {
type: 'error',
error: {
fields: {
reviewers: ['Malformed reviewers list'],
},
message: 'reviewers: Malformed reviewers list',
},
})
.get('/2.0/users/123')
.reply(200, {
account_status: 'inactive',
})
.get('/2.0/users/456')
.reply(200, {
account_status: 'active',
})
.put('/2.0/repositories/some/repo/pullrequests/5')
.reply(200);
await bitbucket.updatePr({ number: 5, prTitle: 'title', prBody: 'body' });
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('rethrows exception when PR update error not due to inactive reviewers', async () => {
const reviewer = {
display_name: 'Jane Smith',
uuid: '{90b6646d-1724-4a64-9fd9-539515fe94e9}',
};

const scope = await initRepoMock();
scope
.get('/2.0/repositories/some/repo/pullrequests/5')
.reply(200, { reviewers: [reviewer] })
.put('/2.0/repositories/some/repo/pullrequests/5')
.reply(400, {
type: 'error',
error: {
fields: {
reviewers: ['Some other unhandled error'],
},
message: 'Some other unhandled error',
},
});
await expect(() =>
bitbucket.updatePr({ number: 5, prTitle: 'title', prBody: 'body' })
).rejects.toThrowErrorMatchingSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('throws an error on failure to get current list of reviewers', async () => {
const scope = await initRepoMock();
scope
Expand Down
67 changes: 57 additions & 10 deletions lib/platform/bitbucket/index.ts
Expand Up @@ -30,7 +30,13 @@ import { smartTruncate } from '../utils/pr-body';
import { readOnlyIssueBody } from '../utils/read-only-issue-body';
import * as comments from './comments';
import * as utils from './utils';
import { PrResponse, RepoInfoBody, mergeBodyTransformer } from './utils';
import {
PrResponse,
PrReviewer,
RepoInfoBody,
UserResponse,
mergeBodyTransformer,
} from './utils';

const bitbucketHttp = new BitbucketHttp();

Expand Down Expand Up @@ -712,16 +718,57 @@ export async function updatePr({
)
).body;

await bitbucketHttp.putJson(
`/2.0/repositories/${config.repository}/pullrequests/${prNo}`,
{
body: {
title,
description: sanitize(description),
reviewers: pr.reviewers,
},
try {
await bitbucketHttp.putJson(
`/2.0/repositories/${config.repository}/pullrequests/${prNo}`,
{
body: {
title,
description: sanitize(description),
reviewers: pr.reviewers,
},
}
);
} catch (err) {
if (
err.statusCode === 400 &&
err.body?.error?.message.includes('reviewers: Malformed reviewers list')
) {
logger.warn(
{ err },
'PR contains inactive reviewer accounts. Will try setting only active reviewers'
);

// Bitbucket returns a 400 if any of the PR reviewer accounts are now inactive (ie: disabled/suspended)
const activeReviewers: PrReviewer[] = [];

// Validate that each previous PR reviewer account is still active
for (const reviewer of pr.reviewers) {
const reviewerUser = (
await bitbucketHttp.getJson<UserResponse>(
`/2.0/users/${reviewer.account_id}`
)
).body;

if (reviewerUser.account_status === 'active') {
activeReviewers.push(reviewer);
}
}

await bitbucketHttp.putJson(
`/2.0/repositories/${config.repository}/pullrequests/${prNo}`,
{
body: {
title,
description: sanitize(description),
reviewers: activeReviewers,
},
}
);
} else {
throw err;
}
);
}

if (state === PrState.Closed && pr) {
await bitbucketHttp.postJson(
Expand Down
15 changes: 14 additions & 1 deletion lib/platform/bitbucket/utils.ts
Expand Up @@ -190,7 +190,7 @@ export interface PrResponse {
name: string;
};
};
reviewers: Array<any>;
reviewers: Array<PrReviewer>;
created_on: string;
}

Expand All @@ -208,3 +208,16 @@ export function prInfo(pr: PrResponse): Pr {
createdAt: pr.created_on,
};
}

export interface UserResponse {
display_name: string;
account_id: string;
nickname: string;
account_status: string;
}

export interface PrReviewer {
display_name: string;
account_id: string;
nickname: string;
}

0 comments on commit 0c977e4

Please sign in to comment.