163 lines
7.4 KiB
JavaScript
163 lines
7.4 KiB
JavaScript
/**
|
|
* Copyright (c) 2013-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const includes = require('lodash.includes');
|
|
const minimatch = require('minimatch');
|
|
|
|
import { danger, fail, markdown, message, warn } from 'danger';
|
|
|
|
const isDocsFile = path => includes(path, 'docs/');
|
|
const editsDocs = danger.git.modified_files.filter(isDocsFile).length > 0;
|
|
const addsDocs = danger.git.created_files.filter(isDocsFile).length > 0;
|
|
if (addsDocs || editsDocs) {
|
|
// Note, this does not yet cover edits to the autogenerated docs
|
|
// (e.g. comments within JS source files)
|
|
const title = ':page_facing_up: Docs';
|
|
const idea = 'Thanks for your contribution to the docs!';
|
|
message(`${title} - <i>${idea}</i>`);
|
|
|
|
// Add the Documentation label via bot, as @facebook-open-source-bot does not have write privileges on the repo.
|
|
markdown('@facebook-github-bot label Documentation');
|
|
}
|
|
|
|
const isBlogFile = path => includes(path, 'blog/');
|
|
|
|
// Flags new blog posts. Note that mentions will not be parsed as the access token we're using does
|
|
// not belong to the Facebook org (on purpose)
|
|
const addsBlogPost = danger.git.created_files.filter(isBlogFile).length > 0;
|
|
if (addsBlogPost) {
|
|
const title = ':memo: Blog post';
|
|
const idea = 'This PR appears to add a new blog post, ' +
|
|
'and may require further review from the React Native team.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
// Flags edits to blog posts
|
|
const editsBlogPost = danger.git.modified_files.filter(isBlogFile).length > 0;
|
|
if (editsBlogPost) {
|
|
const title = ':memo: Blog post';
|
|
const idea = 'This PR appears to edit an existing blog post, ' +
|
|
'and may require further review from the React Native team.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
// Fails if the description is too short.
|
|
if (danger.github.pr.body.length < 10) {
|
|
fail(':grey_question: This pull request needs a description.');
|
|
markdown('@facebook-github-bot label Needs more information');
|
|
}
|
|
|
|
// Warns if the PR title contains [WIP]
|
|
const isWIP = includes(danger.github.pr.title, '[WIP]');
|
|
if (isWIP) {
|
|
const title = ':construction_worker: Work In Progress';
|
|
const idea = 'This PR appears to be a work in progress, and may not be ready to be merged yet.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
// Warns if there are changes to package.json, and tags the team.
|
|
const packageChanged = includes(danger.git.modified_files, 'package.json');
|
|
if (packageChanged) {
|
|
const title = ':lock: package.json';
|
|
const idea = 'Changes were made to package.json. ' +
|
|
'This will require a manual import by a Facebook employee.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
// Warns if a test plan is missing.
|
|
const gettingStartedChanged = includes(danger.git.modified_files, 'docs/GettingStarted.md');
|
|
const includesTestPlan = danger.github.pr.body.toLowerCase().includes('test plan');
|
|
|
|
// Warns if a test plan is missing, when editing the Getting Started guide. This page needs to be
|
|
// tested in all its permutations.
|
|
if (!includesTestPlan && gettingStartedChanged) {
|
|
const title = ':clipboard: Test Plan';
|
|
const idea = 'This PR appears to be missing a Test Plan.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
markdown('@facebook-github-bot label Needs more information');
|
|
}
|
|
// Doc edits rarely require a test plan. We'll trust the reviewer to push back if one is needed.
|
|
if (!includesTestPlan && !editsDocs) {
|
|
const title = ':clipboard: Test Plan';
|
|
const idea = 'This PR appears to be missing a Test Plan.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
markdown('@facebook-github-bot label Needs more information');
|
|
}
|
|
|
|
// Tags PRs that have been submitted by a core contributor.
|
|
// TODO: Switch to using an actual MAINTAINERS file.
|
|
const taskforce = fs.readFileSync('../bots/IssueCommands.txt', 'utf8').split('\n')[0].split(':')[1];
|
|
const isSubmittedByTaskforce = includes(taskforce, danger.github.pr.user.login);
|
|
if (isSubmittedByTaskforce) {
|
|
markdown('@facebook-github-bot label Core Team');
|
|
}
|
|
|
|
// Tags big PRs
|
|
var bigPRThreshold = 600;
|
|
if (danger.github.pr.additions + danger.github.pr.deletions > bigPRThreshold) {
|
|
const title = ':exclamation: Big PR';
|
|
const idea = `This PR is extremely unlikely to get reviewed because it touches ${danger.github.pr.additions + danger.github.pr.deletions} lines.`;
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
|
|
markdown('@facebook-github-bot large-pr');
|
|
}
|
|
if (danger.git.modified_files + danger.git.added_files + danger.git.deleted_files > bigPRThreshold) {
|
|
const title = ':exclamation: Big PR';
|
|
const idea = `This PR is extremely unlikely to get reviewed because it touches ${danger.git.modified_files + danger.git.added_files + danger.git.deleted_files} files.`;
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
|
|
markdown('@facebook-github-bot large-pr');
|
|
}
|
|
|
|
// Warns if the bots whitelist file is updated.
|
|
const issueCommandsFileModified = includes(danger.git.modified_files, 'bots/IssueCommands.txt');
|
|
if (issueCommandsFileModified) {
|
|
const title = ':exclamation: Bots';
|
|
const idea = 'This PR appears to modify the list of people that may issue ' +
|
|
'commands to the GitHub bot.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
// Warns if the PR is opened against stable, as commits need to be cherry picked and tagged by a release maintainer.
|
|
// Fails if the PR is opened against anything other than `master` or `-stable`.
|
|
const isMergeRefMaster = danger.github.pr.base.ref === 'master';
|
|
const isMergeRefStable = danger.github.pr.base.ref.indexOf(`-stable`) !== -1;
|
|
if (!isMergeRefMaster && isMergeRefStable) {
|
|
const title = ':grey_question: Base Branch';
|
|
const idea = 'The base branch for this PR is something other than `master`. Are you sure you want to merge these changes into a stable release? If you are interested in backporting updates to an older release, the suggested approach is to land those changes on `master` first and then cherry-pick the commits into the branch for that release. The [Releases Guide](https://github.com/facebook/react-native/blob/master/Releases.md) has more information.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
} else if (!isMergeRefMaster && !isMergeRefStable) {
|
|
const title = ':exclamation: Base Branch';
|
|
const idea = 'The base branch for this PR is something other than `master`. [Are you sure you want to target something other than the `master` branch?](http://facebook.github.io/react-native/docs/contributing.html#pull-requests)';
|
|
fail(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
// People can add themselves to CODEOWNERS in order to be automatically added as reviewers when a file matching a glob pattern is modified. The following will have the bot add a mention in that case.
|
|
const codeowners = fs.readFileSync('../.github/CODEOWNERS', 'utf8').split('\n');
|
|
let mentions = [];
|
|
codeowners.forEach((codeowner) => {
|
|
const pattern = codeowner.split(' ')[0];
|
|
const owners = codeowner.substring(pattern.length).trim().split(' ');
|
|
|
|
const modifiedFileHasOwner = path => minimatch(path, pattern);
|
|
const modifiesOwnedCode = danger.git.modified_files.filter(modifiedFileHasOwner).length > 0;
|
|
|
|
if (modifiesOwnedCode) {
|
|
mentions = mentions.concat(owners);
|
|
}
|
|
});
|
|
const isOwnedCodeModified = mentions.length > 0;
|
|
if (isOwnedCodeModified) {
|
|
const uniqueMentions = new Set(mentions);
|
|
markdown('Attention: ' + [...uniqueMentions].join(', '));
|
|
}
|