mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
b41b924b2d
Summary: This PR connects breaking change detection with a danger bot. The action takes snapshot from main branch and from the PR as inputs to`diff-api-snapshot` (saved in runner temp directory). ## Changelog: [Internal] For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests Pull Request resolved: https://github.com/facebook/react-native/pull/52045 Reviewed By: huntie Differential Revision: D76735630 Pulled By: coado fbshipit-source-id: 9208117340c1e0bf10d58b67892727717d22e62f
125 lines
4.3 KiB
JavaScript
125 lines
4.3 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
* @noflow
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const {danger, fail, warn} = require('danger');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const body = danger.github.pr.body?.toLowerCase() ?? '';
|
|
|
|
function body_contains(...text) {
|
|
for (const matcher of text) {
|
|
if (body.includes(matcher)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const isFromPhabricator = body_contains('differential revision:');
|
|
|
|
// Provides advice if a summary section is missing, or body is too short
|
|
const includesSummary = body_contains('## summary', 'summary:');
|
|
|
|
const snapshot_output = JSON.parse(
|
|
fs.readFileSync(
|
|
path.join(
|
|
process.env.RUNNER_TEMP,
|
|
'diff-js-api-breaking-changes/output.json',
|
|
),
|
|
'utf8',
|
|
),
|
|
);
|
|
if (snapshot_output && snapshot_output.result !== 'NON_BREAKING') {
|
|
const title = ':exclamation: JavaScript API change detected';
|
|
const idea =
|
|
'This PR commits an update to ReactNativeApi.d.ts, indicating a change to React Native's public JavaScript API. ' +
|
|
'Please include a clear changelog message. ' +
|
|
'This change will be subject to extra review.\n\n' +
|
|
`This change was flagged as: <code>${snapshot_output.result}</code>`;
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
const hasNoUsefulBody =
|
|
!danger.github.pr.body || danger.github.pr.body.length < 50;
|
|
const hasTooShortAHumanSummary =
|
|
!includesSummary && body.split('\n').length <= 2 && !isFromPhabricator;
|
|
if (hasNoUsefulBody) {
|
|
fail(':grey_question: This pull request needs a description.');
|
|
} else if (hasTooShortAHumanSummary) {
|
|
// PRs from Phabricator always includes the Summary by default.
|
|
const title = ':clipboard: Missing Summary';
|
|
const idea =
|
|
'Can you add a Summary? ' +
|
|
'To do so, add a "## Summary" section to your PR description. ' +
|
|
'This is a good place to explain the motivation for making this change.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
// Provides advice if a test plan is missing.
|
|
const includesTestPlan = body_contains(
|
|
'## test plan',
|
|
'test plan:',
|
|
'tests:',
|
|
'test:',
|
|
);
|
|
if (!includesTestPlan && !isFromPhabricator) {
|
|
// PRs from Phabricator never exports the Test Plan so let's disable this check.
|
|
const title = ':clipboard: Missing Test Plan';
|
|
const idea =
|
|
'Can you add a Test Plan? ' +
|
|
'To do so, add a "## Test Plan" section to your PR description. ' +
|
|
'A Test Plan lets us know how these changes were tested.';
|
|
warn(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
// Check if there is a changelog and validate it
|
|
if (!isFromPhabricator) {
|
|
const status = require('@rnx-kit/rn-changelog-generator').default.validate(
|
|
danger.github.pr.body,
|
|
);
|
|
const changelogInstructions =
|
|
'See <a target="_blank" href="https://reactnative.dev/contributing/changelogs-in-pull-requests">Changelog format</a>';
|
|
if (status === 'missing') {
|
|
// Provides advice if a changelog is missing
|
|
const title = ':clipboard: Missing Changelog';
|
|
const idea =
|
|
'Please add a Changelog to your PR description. ' + changelogInstructions;
|
|
fail(`${title} - <i>${idea}</i>`);
|
|
} else if (status === 'invalid') {
|
|
const title = ':clipboard: Verify Changelog Format';
|
|
const idea = changelogInstructions;
|
|
fail(`${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 `main` or `-stable`.
|
|
const isMergeRefMain = danger.github.pr.base.ref === 'main';
|
|
const isMergeRefStable = danger.github.pr.base.ref.endsWith('-stable');
|
|
if (!isMergeRefMain && !isMergeRefStable) {
|
|
const title = ':exclamation: Base Branch';
|
|
const idea =
|
|
'The base branch for this PR is something other than `main` or a `-stable` branch. [Are you sure you want to target something other than the `main` branch?](https://reactnative.dev/docs/contributing#pull-requests)';
|
|
fail(`${title} - <i>${idea}</i>`);
|
|
}
|
|
|
|
// If the PR is opened against stable should add `Pick Request` label
|
|
if (isMergeRefStable) {
|
|
danger.github.api.issues.addLabels({
|
|
owner: danger.github.pr.base.repo.owner.login,
|
|
repo: danger.github.pr.base.repo.name,
|
|
issue_number: danger.github.pr.number,
|
|
labels: ['Pick Request'],
|
|
});
|
|
}
|