From 0143c20c08314eafa680a0c4a3b3bb8044bd70fe Mon Sep 17 00:00:00 2001
From: Michael Kriese <michael.kriese@visualon.de>
Date: Fri, 10 May 2019 13:28:35 +0200
Subject: [PATCH] feat(bitbucket-server): use default reviewers (#3647)

---
 lib/config/definitions.js                     |   6 +
 lib/platform/bitbucket-server/index.js        |  64 ++-
 renovate-schema.json                          |   5 +
 .../__snapshots__/index.spec.js.snap          | 480 +++++++++++++++++-
 .../bitbucket-server/_fixtures/responses.js   |   3 +
 test/platform/bitbucket-server/index.spec.js  |  58 ++-
 .../__snapshots__/flatten.spec.js.snap        |   8 +
 website/docs/configuration-options.md         |   4 +
 8 files changed, 611 insertions(+), 17 deletions(-)

diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index 7f7865dfbd..a8537639d4 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -911,6 +911,12 @@ const options = [
     type: 'integer',
     default: 0, // no limit
   },
+  {
+    name: 'bbUseDefaultReviewers',
+    description: 'Use the default reviewers (Bitbucket server only).',
+    type: 'boolean',
+    default: true,
+  },
   // Automatic merging
   {
     name: 'automerge',
diff --git a/lib/platform/bitbucket-server/index.js b/lib/platform/bitbucket-server/index.js
index 1a15af6f82..53e812098e 100644
--- a/lib/platform/bitbucket-server/index.js
+++ b/lib/platform/bitbucket-server/index.js
@@ -97,6 +97,7 @@ async function initRepo({
   gitPrivateKey,
   gitFs,
   localDir,
+  bbUseDefaultReviewers,
 }) {
   logger.debug(
     `initRepo("${JSON.stringify(
@@ -122,6 +123,12 @@ async function initRepo({
   const [projectKey, repositorySlug] = repository.split('/');
   config = { projectKey, repositorySlug, gitPrivateKey };
 
+  /* istanbul ignore else */
+  if (bbUseDefaultReviewers !== false) {
+    logger.debug('Enable bitbucket default reviewer');
+    config.bbUseDefaultReviewers = true;
+  }
+
   // Always gitFs
   const { host, pathname } = url.parse(opts.endpoint);
   const gitUrl = GitStorage.getUrl({
@@ -444,15 +451,40 @@ function addAssignees(iid, assignees) {
   // BB Server doesnt support assignees
 }
 
-async function addReviewers(iid, reviewers) {
-  logger.debug(`Adding reviewers ${reviewers} to #${iid}`);
-  for (const name of reviewers) {
-    await api.post(
+async function addReviewers(prNo, reviewers) {
+  logger.debug(`Adding reviewers ${reviewers} to #${prNo}`);
+
+  try {
+    const pr = await getPr(prNo);
+    if (!pr) {
+      throw Object.assign(new Error('not-found'), { statusCode: 404 });
+    }
+
+    const reviewersSet = new Set([...pr.reviewers, ...reviewers]);
+
+    await api.put(
       `./rest/api/1.0/projects/${config.projectKey}/repos/${
         config.repositorySlug
-      }/pull-requests/${iid}/participants`,
-      { body: { user: { name }, role: 'REVIEWER' } }
+      }/pull-requests/${prNo}`,
+      {
+        body: {
+          title: pr.title,
+          description: pr.description,
+          version: pr.version,
+          reviewers: Array.from(reviewersSet).map(name => ({ user: { name } })),
+        },
+      }
     );
+    await getPr(prNo, true);
+  } catch (err) {
+    if (err.statusCode === 404) {
+      throw new Error('not-found');
+    } else if (err.statusCode === 409) {
+      throw new Error('repository-changed');
+    } else {
+      logger.fatal({ err }, `Failed to add reviewers ${reviewers} to #${prNo}`);
+      throw err;
+    }
   }
 }
 
@@ -651,6 +683,25 @@ async function createPr(
 ) {
   logger.debug(`createPr(${branchName}, title=${title})`);
   const base = useDefaultBranch ? config.defaultBranch : config.baseBranch;
+  let reviewers = [];
+
+  /* istanbul ignore else */
+  if (config.bbUseDefaultReviewers) {
+    logger.debug(`fetching default reviewers`);
+    const { id } = (await api.get(
+      `./rest/api/1.0/projects/${config.projectKey}/repos/${
+        config.repositorySlug
+      }`
+    )).body;
+
+    const defReviewers = (await api.get(
+      `./rest/default-reviewers/1.0/projects/${config.projectKey}/repos/${
+        config.repositorySlug
+      }/reviewers?sourceRefId=refs/heads/${branchName}&targetRefId=refs/heads/${base}&sourceRepoId=${id}&targetRepoId=${id}`
+    )).body;
+
+    reviewers = defReviewers.map(u => ({ user: { name: u.name } }));
+  }
 
   const body = {
     title,
@@ -661,6 +712,7 @@ async function createPr(
     toRef: {
       id: `refs/heads/${base}`,
     },
+    reviewers,
   };
   let prInfoRes;
   try {
diff --git a/renovate-schema.json b/renovate-schema.json
index b869e7581f..d2a96a7b77 100644
--- a/renovate-schema.json
+++ b/renovate-schema.json
@@ -599,6 +599,11 @@
       "type": "integer",
       "default": 0
     },
+    "bbUseDefaultReviewers": {
+      "description": "Use the default reviewers (Bitbucket server only).",
+      "type": "boolean",
+      "default": true
+    },
     "automerge": {
       "description": "Whether to automerge branches/PRs automatically, without human intervention",
       "type": "boolean",
diff --git a/test/platform/bitbucket-server/__snapshots__/index.spec.js.snap b/test/platform/bitbucket-server/__snapshots__/index.spec.js.snap
index 79979eedcf..3b791e3d25 100644
--- a/test/platform/bitbucket-server/__snapshots__/index.spec.js.snap
+++ b/test/platform/bitbucket-server/__snapshots__/index.spec.js.snap
@@ -3,13 +3,217 @@
 exports[`platform/bitbucket-server endpoint with no path addReviewers sends the reviewer name as a reviewer 1`] = `
 Array [
   Array [
-    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/participants",
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": false,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with no path addReviewers sends the reviewer name as a reviewer 2`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
     Object {
       "body": Object {
-        "role": "REVIEWER",
-        "user": Object {
-          "name": "name",
-        },
+        "description": undefined,
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "userName2",
+            },
+          },
+          Object {
+            "user": Object {
+              "name": "name",
+            },
+          },
+        ],
+        "title": "title",
+        "version": 1,
+      },
+    },
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with no path addReviewers sends the reviewer name as a reviewer 3`] = `Array []`;
+
+exports[`platform/bitbucket-server endpoint with no path addReviewers throws 1`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with no path addReviewers throws 2`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "body": Object {
+        "description": undefined,
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "userName2",
+            },
+          },
+          Object {
+            "user": Object {
+              "name": "name",
+            },
+          },
+        ],
+        "title": "title",
+        "version": 1,
+      },
+    },
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with no path addReviewers throws not-found 1`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/4",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with no path addReviewers throws not-found 2`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "body": Object {
+        "description": undefined,
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "userName2",
+            },
+          },
+          Object {
+            "user": Object {
+              "name": "name",
+            },
+          },
+        ],
+        "title": "title",
+        "version": 1,
+      },
+    },
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with no path addReviewers throws repository-changed 1`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with no path addReviewers throws repository-changed 2`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "body": Object {
+        "description": undefined,
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "userName2",
+            },
+          },
+          Object {
+            "user": Object {
+              "name": "name",
+            },
+          },
+        ],
+        "title": "title",
+        "version": 1,
       },
     },
   ],
@@ -39,6 +243,12 @@ Array [
   Array [
     "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
   ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/default-reviewers/1.0/projects/SOME/repos/repo/reviewers?sourceRefId=refs/heads/branch&targetRefId=refs/heads/master&sourceRepoId=13076&targetRepoId=13076",
+  ],
 ]
 `;
 
@@ -52,6 +262,13 @@ Array [
         "fromRef": Object {
           "id": "refs/heads/branch",
         },
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "jcitizen",
+            },
+          },
+        ],
         "title": "title",
         "toRef": Object {
           "id": "refs/heads/master",
@@ -70,6 +287,12 @@ Array [
   Array [
     "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
   ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/default-reviewers/1.0/projects/SOME/repos/repo/reviewers?sourceRefId=refs/heads/branch&targetRefId=refs/heads/master&sourceRepoId=13076&targetRepoId=13076",
+  ],
 ]
 `;
 
@@ -83,6 +306,13 @@ Array [
         "fromRef": Object {
           "id": "refs/heads/branch",
         },
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "jcitizen",
+            },
+          },
+        ],
         "title": "title",
         "toRef": Object {
           "id": "refs/heads/master",
@@ -1139,13 +1369,217 @@ Array [
 exports[`platform/bitbucket-server endpoint with path addReviewers sends the reviewer name as a reviewer 1`] = `
 Array [
   Array [
-    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/participants",
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": false,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with path addReviewers sends the reviewer name as a reviewer 2`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
     Object {
       "body": Object {
-        "role": "REVIEWER",
-        "user": Object {
-          "name": "name",
-        },
+        "description": undefined,
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "userName2",
+            },
+          },
+          Object {
+            "user": Object {
+              "name": "name",
+            },
+          },
+        ],
+        "title": "title",
+        "version": 1,
+      },
+    },
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with path addReviewers sends the reviewer name as a reviewer 3`] = `Array []`;
+
+exports[`platform/bitbucket-server endpoint with path addReviewers throws 1`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with path addReviewers throws 2`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "body": Object {
+        "description": undefined,
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "userName2",
+            },
+          },
+          Object {
+            "user": Object {
+              "name": "name",
+            },
+          },
+        ],
+        "title": "title",
+        "version": 1,
+      },
+    },
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with path addReviewers throws not-found 1`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/4",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with path addReviewers throws not-found 2`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "body": Object {
+        "description": undefined,
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "userName2",
+            },
+          },
+          Object {
+            "user": Object {
+              "name": "name",
+            },
+          },
+        ],
+        "title": "title",
+        "version": 1,
+      },
+    },
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with path addReviewers throws repository-changed 1`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "useCache": true,
+    },
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/merge",
+  ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5/commits?withCounts=true",
+  ],
+]
+`;
+
+exports[`platform/bitbucket-server endpoint with path addReviewers throws repository-changed 2`] = `
+Array [
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo/pull-requests/5",
+    Object {
+      "body": Object {
+        "description": undefined,
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "userName2",
+            },
+          },
+          Object {
+            "user": Object {
+              "name": "name",
+            },
+          },
+        ],
+        "title": "title",
+        "version": 1,
       },
     },
   ],
@@ -1175,6 +1609,12 @@ Array [
   Array [
     "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
   ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/default-reviewers/1.0/projects/SOME/repos/repo/reviewers?sourceRefId=refs/heads/branch&targetRefId=refs/heads/master&sourceRepoId=13076&targetRepoId=13076",
+  ],
 ]
 `;
 
@@ -1188,6 +1628,13 @@ Array [
         "fromRef": Object {
           "id": "refs/heads/branch",
         },
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "jcitizen",
+            },
+          },
+        ],
         "title": "title",
         "toRef": Object {
           "id": "refs/heads/master",
@@ -1206,6 +1653,12 @@ Array [
   Array [
     "./rest/api/1.0/projects/SOME/repos/repo/branches/default",
   ],
+  Array [
+    "./rest/api/1.0/projects/SOME/repos/repo",
+  ],
+  Array [
+    "./rest/default-reviewers/1.0/projects/SOME/repos/repo/reviewers?sourceRefId=refs/heads/branch&targetRefId=refs/heads/master&sourceRepoId=13076&targetRepoId=13076",
+  ],
 ]
 `;
 
@@ -1219,6 +1672,13 @@ Array [
         "fromRef": Object {
           "id": "refs/heads/branch",
         },
+        "reviewers": Array [
+          Object {
+            "user": Object {
+              "name": "jcitizen",
+            },
+          },
+        ],
         "title": "title",
         "toRef": Object {
           "id": "refs/heads/master",
diff --git a/test/platform/bitbucket-server/_fixtures/responses.js b/test/platform/bitbucket-server/_fixtures/responses.js
index 22400d45c3..3886c36f6f 100644
--- a/test/platform/bitbucket-server/_fixtures/responses.js
+++ b/test/platform/bitbucket-server/_fixtures/responses.js
@@ -569,6 +569,9 @@ function generateServerResponses(endpoint) {
     [`${endpoint}/rest/build-status/1.0/commits/0d9c7726c3d628b7e28af234595cfd20febdbf8e`]: {
       POST: {},
     },
+    [`${endpoint}/rest/default-reviewers/1.0/projects/SOME/repos/repo/reviewers?sourceRefId=refs/heads/branch&targetRefId=refs/heads/master&sourceRepoId=13076&targetRepoId=13076`]: {
+      GET: [{ name: 'jcitizen' }],
+    },
   };
 }
 
diff --git a/test/platform/bitbucket-server/index.spec.js b/test/platform/bitbucket-server/index.spec.js
index 10880bfffa..952039f46e 100644
--- a/test/platform/bitbucket-server/index.spec.js
+++ b/test/platform/bitbucket-server/index.spec.js
@@ -211,11 +211,67 @@ describe('platform/bitbucket-server', () => {
         });
 
         it('sends the reviewer name as a reviewer', async () => {
-          expect.assertions(1);
+          expect.assertions(3);
           await initRepo();
           await bitbucket.addReviewers(5, ['name']);
+          expect(api.get.mock.calls).toMatchSnapshot();
+          expect(api.put.mock.calls).toMatchSnapshot();
           expect(api.post.mock.calls).toMatchSnapshot();
         });
+
+        it('throws not-found', async () => {
+          expect.assertions(5);
+          await initRepo();
+
+          await expect(bitbucket.addReviewers(null, ['name'])).rejects.toThrow(
+            'not-found'
+          );
+
+          await expect(bitbucket.addReviewers(4, ['name'])).rejects.toThrow(
+            'not-found'
+          );
+          api.put.mockReturnValueOnce(
+            Promise.reject({
+              statusCode: 404,
+            })
+          );
+          await expect(bitbucket.addReviewers(5, ['name'])).rejects.toThrow(
+            'not-found'
+          );
+
+          expect(api.get.mock.calls).toMatchSnapshot();
+          expect(api.put.mock.calls).toMatchSnapshot();
+        });
+
+        it('throws repository-changed', async () => {
+          expect.assertions(3);
+          await initRepo();
+          api.put.mockReturnValueOnce(
+            Promise.reject({
+              statusCode: 409,
+            })
+          );
+          await expect(bitbucket.addReviewers(5, ['name'])).rejects.toThrow(
+            'repository-changed'
+          );
+          expect(api.get.mock.calls).toMatchSnapshot();
+          expect(api.put.mock.calls).toMatchSnapshot();
+        });
+
+        it('throws', async () => {
+          expect.assertions(3);
+          await initRepo();
+          api.put.mockReturnValueOnce(
+            Promise.reject({
+              statusCode: 405,
+            })
+          );
+          await expect(bitbucket.addReviewers(5, ['name'])).rejects.toEqual({
+            statusCode: 405,
+          });
+          expect(api.get.mock.calls).toMatchSnapshot();
+          expect(api.put.mock.calls).toMatchSnapshot();
+        });
       });
 
       describe('deleteLAbel()', () => {
diff --git a/test/workers/repository/updates/__snapshots__/flatten.spec.js.snap b/test/workers/repository/updates/__snapshots__/flatten.spec.js.snap
index f0875d7611..fbbd2eef18 100644
--- a/test/workers/repository/updates/__snapshots__/flatten.spec.js.snap
+++ b/test/workers/repository/updates/__snapshots__/flatten.spec.js.snap
@@ -9,6 +9,7 @@ Array [
     "automergeType": "pr",
     "azureWorkItemId": 0,
     "baseDir": null,
+    "bbUseDefaultReviewers": true,
     "binarySource": "bundled",
     "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
     "branchPrefix": "renovate/",
@@ -117,6 +118,7 @@ Array [
     "automergeType": "pr",
     "azureWorkItemId": 0,
     "baseDir": null,
+    "bbUseDefaultReviewers": true,
     "binarySource": "bundled",
     "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
     "branchPrefix": "renovate/",
@@ -225,6 +227,7 @@ Array [
     "automergeType": "pr",
     "azureWorkItemId": 0,
     "baseDir": null,
+    "bbUseDefaultReviewers": true,
     "binarySource": "bundled",
     "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
     "branchPrefix": "renovate/",
@@ -333,6 +336,7 @@ Array [
     "automergeType": "pr",
     "azureWorkItemId": 0,
     "baseDir": null,
+    "bbUseDefaultReviewers": true,
     "binarySource": "bundled",
     "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
     "branchPrefix": "renovate/",
@@ -441,6 +445,7 @@ Array [
     "automergeType": "pr",
     "azureWorkItemId": 0,
     "baseDir": null,
+    "bbUseDefaultReviewers": true,
     "binarySource": "bundled",
     "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
     "branchPrefix": "renovate/",
@@ -549,6 +554,7 @@ Array [
     "automergeType": "pr",
     "azureWorkItemId": 0,
     "baseDir": null,
+    "bbUseDefaultReviewers": true,
     "binarySource": "bundled",
     "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
     "branchPrefix": "renovate/",
@@ -657,6 +663,7 @@ Array [
     "automergeType": "pr",
     "azureWorkItemId": 0,
     "baseDir": null,
+    "bbUseDefaultReviewers": true,
     "binarySource": "bundled",
     "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
     "branchPrefix": "renovate/",
@@ -765,6 +772,7 @@ Array [
     "automergeType": "pr",
     "azureWorkItemId": 0,
     "baseDir": null,
+    "bbUseDefaultReviewers": true,
     "binarySource": "bundled",
     "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
     "branchPrefix": "renovate/",
diff --git a/website/docs/configuration-options.md b/website/docs/configuration-options.md
index 0a14583253..eb609c1ce3 100644
--- a/website/docs/configuration-options.md
+++ b/website/docs/configuration-options.md
@@ -91,6 +91,10 @@ It's possible to add this setting into the `renovate.json` file as part of the "
 
 ## bazel
 
+## bbUseDefaultReviewers
+
+Apply the default reviewers rules to PR's (Bitbucket server only).
+
 ## branchName
 
 It's recommended to use our default templates, but you may override branch name if you really wish. It's recommended to still keep `depName` and `newMajor` in the branch name to make sure all other Renovate features can still work.
-- 
GitLab