diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000000000..0967ef424bce67 --- /dev/null +++ b/.babelrc @@ -0,0 +1 @@ +{} diff --git a/circle.yml b/circle.yml index d5f2dead8c9ad9..5eedefe2c93373 100644 --- a/circle.yml +++ b/circle.yml @@ -49,6 +49,8 @@ test: - source scripts/circle-ci-android-setup.sh && waitForAVD override: + # Run Danger against PRs. + - if [[ $CI_PULL_REQUEST ]]; then DANGER_GITHUB_API_TOKEN="5fc403da51e5e05666e1e3ae6380190178a1cdb3" npm run danger; fi # eslint bot. This GitHub token grants public_repo access scope. - cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; npm run flow --silent -- check --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" CI_USER=$CIRCLE_PROJECT_USERNAME CI_REPO=$CIRCLE_PROJECT_REPONAME PULL_REQUEST_NUMBER=$CIRCLE_PR_NUMBER node bots/code-analysis-bot.js - npm run lint diff --git a/dangerfile.js b/dangerfile.js new file mode 100644 index 00000000000000..55fb0ff8f7c70e --- /dev/null +++ b/dangerfile.js @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2016-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. + */ + +// Removed require +const fs = require('fs'); +const includes = require('lodash.includes'); + +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) + markdown(`:page_facing_up: Thanks for your contribution to the docs!`); +} + +const isBlogFile = path => includes(path, 'blog/'); + +// Flags new blog posts. +const addsBlogPost = danger.git.created_files.filter(isBlogFile).length > 0; +if (addsBlogPost) { + const message = ':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(`${message} - ${idea}`); + markdown(`:memo: This PR requires attention from the @facebook/react-native team.`); +} + +// Flags edits to blog posts +const editsBlogPost = danger.git.modified_files.filter(isBlogFile).length > 0; +if (editsBlogPost) { + const message = ':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(`${message} - ${idea}`); + markdown(`This PR requires attention from the @facebook/react-native team.`); +} + +// Fails if the description is too short. +if (danger.github.pr.body.length < 10) { + fail(':grey_question: This pull request needs a description.') +} + +// Warns if the PR title contains [WIP] +const isWIP = includes(danger.github.pr.title, '[WIP]') +if (isWIP) { + const message = ':construction_worker: Work In Progress'; + const idea = 'Do not merge yet.'; + warn(`${message} - ${idea}`); +} + +// Warns if there are changes to package.json, and tags the team. +const packageChanged = includes(danger.git.modified_files, 'package.json'); +if (packageChanged) { + const message = ':lock: Changes were made to package.json'; + const idea = 'This will require a manual import. Once approved, a Facebook employee should import the PR, then run `yarn add` for any new packages.'; + warn(`${message} - ${idea}`); + markdown(`This PR requires attention from the @facebook/react-native team.`); +} + +// 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 message = ':clipboard: Test Plan'; + const idea = 'This PR appears to be missing a Test Plan.'; + warn(`${message} - ${idea}`); +} +// Doc edits rarely require a test plan. We'll trust the reviewer to push back if one is needed. +if (!includesTestPlan && !editsDocs) { + const message = ':clipboard: Test Plan'; + const idea = 'This PR appears to be missing a Test Plan.'; + warn(`${message} - ${idea}`); +} + +// Tags the React Native team is the PR is submitted by a core contributor +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(`This PR has been submitted by a core contributor. Notifying @facebook/react-native.`); +} diff --git a/package.json b/package.json index 8637b078297611..e3581d08c33d44 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,8 @@ "test-android-all": "npm run test-android-build && npm run test-android-run-unit && npm run test-android-run-instrumentation && npm run test-android-run-e2e", "test-android-instrumentation": "npm run test-android-build && npm run test-android-run-instrumentation", "test-android-unit": "npm run test-android-build && npm run test-android-run-unit", - "test-android-e2e": "npm run test-android-build && npm run test-android-run-e2e" + "test-android-e2e": "npm run test-android-build && npm run test-android-run-e2e", + "danger": "node ./node_modules/.bin/danger" }, "bin": { "react-native": "local-cli/wrong-react-native.js" @@ -220,6 +221,7 @@ }, "devDependencies": { "babel-eslint": "^7.2.3", + "danger": "^0.21.2", "eslint": "^3.19.0", "eslint-config-fb-strict": "^20.0.3", "eslint-config-fbjs": "^1.1.1",