async function checkBreakChange(file){ var diff = await danger.git.diffForFile(file); if (diff && diff.removed && diff.removed.match(/^-\s*?public\s+[\s\S]+$/gm)) { if (isNotDanger) { warn("Potential BREAK CHANGE. Modify public in " + file); } else { warn( "Potential BREAK CHANGE. Modify public in " + file + " without metion it in commit message. You'd better add '@notdanger' in your commit log. " ); } } }
affectedServices.forEach(service => { if (testedServices.indexOf(service) === -1) { warn( [ `This PR modified service code for <kbd>${service}</kbd> but not its test code. <br>`, "That's okay so long as it's refactoring existing code.", ].join('') ) } })
danger.git.diffForFile(file).then(diff => { if (/\+.*assert[(.]/.test(diff.diff)) { warn( [ `Found 'assert' statement added in \`${file}\`. <br>`, 'Please ensure tests are written using Chai ', '[expect syntax](http://chaijs.com/guide/styles/#expect)', ].join('') ) } })
danger.git.diffForFile(file).then(({ diff }) => { if (/serverSecrets/.test(diff) && !secretsDocs.modified) { warn( [ `:books: Remember to ensure any changes to \`serverSecrets\` `, `in \`${file}\` are reflected in the [server secrets documentation]`, '(https://github.com/badges/shields/blob/master/doc/server-secrets.md)', ].join('') ) } if (/\+.*assert[(.]/.test(diff)) { warn( [ `Found 'assert' statement added in \`${file}\`. <br>`, 'Please ensure tests are written using Chai ', '[expect syntax](http://chaijs.com/guide/styles/#expect)', ].join('') ) } })
async function main() { const taskName = String(process.env.task) switch (taskName) { case 'ANDROID': await runAndroid() break case 'IOS': await runiOS() break case 'JS-general': await runJSのGeneral() await yarn() break case 'JS-data': await runJSのData() break case 'JS-flow': await runJSのFlow() break case 'JS-jest': await runJSのJest() break case 'JS-lint': await runJSのLint() break case 'JS-prettier': await runJSのPrettier() break case 'JS-yarn-dedupe': await runJSのYarnDedupe() break case 'JS-bundle-android': case 'JS-bundle-ios': break default: warn(`Unknown task name "${taskName}"; Danger cannot report anything.`) } }
* External dependencies */ import { danger, warn } from 'danger'; // Skip danger check if "no ci" or "no danger" in latest commit const lastCommit = danger.git.commits.slice( -1 )[ 0 ].message; if ( lastCommit.includes( 'no ci' ) || lastCommit.includes( 'skip ci' ) || lastCommit.includes( 'no danger' ) || lastCommit.includes( 'skip danger' ) ) { process.exit( 0 ); // eslint-disable-line no-process-exit } // No PR is too small to include a description of why you made a change if ( danger.github.pr.body.length < 10 ) { warn( 'Please include a description of your PR changes.' ); } // Use labels please! const ghLabels = danger.github.issue.labels; if ( ! ghLabels.find( l => l.name.toLowerCase().includes( '[status]' ) ) ) { warn( 'The PR is missing at least one [Status] label. Suggestions: `[Status] In Progress`, `[Status] Needs Review`' ); } // Test instructions if ( ! danger.github.pr.body.includes( 'Testing instructions' ) ) { warn( '"Testing instructions" are missing for this PR. Please add some' ); }
const {danger, fail, markdown, message, warn} = require('danger'); // Fails if the description is too short. if (!danger.github.pr.body || danger.github.pr.body.length < 10) { fail(':grey_question: This pull request needs a description.'); } // 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 includesTestPlan = danger.github.pr.body && danger.github.pr.body.toLowerCase().includes('test plan'); if (!includesTestPlan) { const title = ':clipboard: Test Plan'; const idea = 'This PR appears to be missing a Test Plan.'; warn(`${title} - <i>${idea}</i>`); } // Regex looks for given categories, types, a file/framework/component, and a message - broken into 4 capture groups const releaseNotesRegex = /\[\s?(ANDROID|CLI|DOCS|GENERAL|INTERNAL|IOS|TVOS|WINDOWS)\s?\]\s*?\[\s?(BREAKING|BUGFIX|ENHANCEMENT|FEATURE|MINOR)\s?\]\s*?\[(.*)\]\s*?\-\s*?(.*)/gi; const includesReleaseNotes =
const packageLock = fileMatch('package-lock.json') const capitals = fileMatch('**/*[A-Z]*.js') const underscores = fileMatch('**/*_*.js') const targetBranch = danger.github.pr.base.ref message( [ ':sparkles: Thanks for your contribution to Shields, ', `@${danger.github.pr.user.login}!`, ].join('') ) if (targetBranch !== 'master') { const message = `This PR targets \`${targetBranch}\`` const idea = 'It is likely that the target branch should be `master`' warn(`${message} - <i>${idea}</i>`) } if (documentation.createdOrModified) { message( [ 'Thanks for contributing to our documentation. ', 'We :heart: our [documentarians](http://www.writethedocs.org/)!', ].join('') ) } if (packageJson.modified && !packageLock.modified) { const message = 'This PR modified `package.json`, but not `package-lock.json`' const idea = 'Perhaps you need to run `npm install`?' warn(`${message} - <i>${idea}</i>`)
const secretsDocs = fileMatch('doc/server-secrets.md') const capitals = fileMatch('**/*[A-Z]*.js') const underscores = fileMatch('**/*_*.js') const targetBranch = danger.github.pr.base.ref message( [ ':sparkles: Thanks for your contribution to Shields, ', `@${danger.github.pr.user.login}!`, ].join('') ) if (targetBranch !== 'master') { const message = `This PR targets \`${targetBranch}\`` const idea = 'It is likely that the target branch should be `master`' warn(`${message} - <i>${idea}</i>`) } if (documentation.createdOrModified) { message( [ 'Thanks for contributing to our documentation. ', 'We :heart: our [documentarians](http://www.writethedocs.org/)!', ].join('') ) } if (packageJson.modified && !packageLock.modified) { const message = 'This PR modified `package.json`, but not `package-lock.json`' const idea = 'Perhaps you need to run `npm install`?' warn(`${message} - <i>${idea}</i>`)
import { danger, fail, warn } from "danger" // Check if the CHANGELOG.md file has been edited // Fail the build and post a comment reminding submitters to do so if it wasn't changed if (!danger.git.modified_files.includes("CHANGELOG.md")) { warn("Please include an updated `CHANGELOG.md` file.<br>This way we can keep track of all the contributions.") } // Check if the PR request is send to the master branch. // This should only be done by MichMich. if (danger.github.pr.base.ref === "master" && danger.github.pr.user.login !== "MichMich") { // Check if the PR body or title includes the text: #accepted. // If not, the PR will fail. if ((danger.github.pr.body + danger.github.pr.title).includes("#accepted")) { fail("Please send all your pull requests to the `develop` branch.<br>Pull requests on the `master` branch will not be accepted.") } }
(async function() { // Use git locally to grab the commit which represents the place // where the branches differ const upstreamRepo = danger.github.pr.base.repo.full_name; if (upstreamRepo !== 'facebook/react') { // Exit unless we're running in the main repo return; } const upstreamRef = danger.github.pr.base.ref; await git(`remote add upstream https://github.com/facebook/react.git`); await git('fetch upstream'); const baseCommit = await git(`merge-base HEAD upstream/${upstreamRef}`); let previousBuildResults = null; try { let baseCIBuildId = null; const statusesResponse = await fetch( `https://api.github.com/repos/facebook/react/commits/${baseCommit}/statuses` ); const statuses = await statusesResponse.json(); for (let i = 0; i < statuses.length; i++) { const status = statuses[i]; if (status.context === 'ci/circleci') { if (status.state === 'success') { baseCIBuildId = /\/facebook\/react\/([0-9]+)/.exec( status.target_url )[1]; break; } if (status.state === 'failure') { warn(`Base commit is broken: ${baseCommit}`); return; } } } if (baseCIBuildId === null) { warn(`Could not find build artifacts for base commit: ${baseCommit}`); return; } const baseArtifactsInfoResponse = await fetch( `https://circleci.com/api/v1.1/project/github/facebook/react/${baseCIBuildId}/artifacts` ); const baseArtifactsInfo = await baseArtifactsInfoResponse.json(); for (let i = 0; i < baseArtifactsInfo.length; i++) { const info = baseArtifactsInfo[i]; if (info.path === 'home/circleci/project/build/bundle-sizes.json') { const resultsResponse = await fetch(info.url); previousBuildResults = await resultsResponse.json(); break; } } } catch (error) { warn(`Failed to fetch build artifacts for base commit: ${baseCommit}`); return; } if (previousBuildResults === null) { warn(`Could not find build artifacts for base commit: ${baseCommit}`); return; } // Take the JSON of the build response and // make an array comparing the results for printing const results = generateResultsArray( currentBuildResults, previousBuildResults ); const packagesToShow = results .filter( r => Math.abs(r.prevFileSizeAbsoluteChange) >= 300 || // bytes Math.abs(r.prevGzipSizeAbsoluteChange) >= 100 // bytes ) .map(r => r.packageName); if (packagesToShow.length) { let allTables = []; // Highlight React and React DOM changes inline // e.g. react: `react.production.min.js`: -3%, `react.development.js`: +4% if (packagesToShow.includes('react')) { const reactProd = results.find( r => r.bundleType === 'UMD_PROD' && r.packageName === 'react' ); if ( reactProd.prevFileSizeChange !== 0 || reactProd.prevGzipSizeChange !== 0 ) { const changeSize = addPercent(reactProd.prevFileSizeChange, true); const changeGzip = addPercent(reactProd.prevGzipSizeChange, true); markdown(`React: size: ${changeSize}, gzip: ${changeGzip}`); } } if (packagesToShow.includes('react-dom')) { const reactDOMProd = results.find( r => r.bundleType === 'UMD_PROD' && r.packageName === 'react-dom' ); if ( reactDOMProd.prevFileSizeChange !== 0 || reactDOMProd.prevGzipSizeChange !== 0 ) { const changeSize = addPercent(reactDOMProd.prevFileSizeChange, true); const changeGzip = addPercent(reactDOMProd.prevGzipSizeChange, true); markdown(`ReactDOM: size: ${changeSize}, gzip: ${changeGzip}`); } } // Show a hidden summary table for all diffs // eslint-disable-next-line no-var,no-for-of-loops/no-for-of-loops for (var name of new Set(packagesToShow)) { const thisBundleResults = results.filter(r => r.packageName === name); const changedFiles = thisBundleResults.filter( r => r.prevFileSizeChange !== 0 || r.prevGzipSizeChange !== 0 ); const mdHeaders = [ 'File', 'Filesize Diff', 'Gzip Diff', 'Prev Size', 'Current Size', 'Prev Gzip', 'Current Gzip', 'ENV', ]; const mdRows = changedFiles.map(r => { const isProd = r.bundleType.includes('PROD'); return setBoldness( [ r.filename, addPercent(r.prevFileSizeChange, isProd), addPercent(r.prevGzipSizeChange, isProd), r.prevSize, r.prevFileSize, r.prevGzip, r.prevGzipSize, r.bundleType, ], isProd ); }); allTables.push(`\n## ${name}`); allTables.push(generateMDTable(mdHeaders, mdRows)); } const summary = ` <details> <summary>Details of bundled changes.</summary> <p>Comparing: ${baseCommit}...${danger.github.pr.head.sha}</p> ${allTables.join('\n')} </details> `; markdown(summary); } })();
* Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import { schedule, danger, fail, warn, message, markdown } from "danger"; import fs from "fs"; import path from 'path'; import GitHubApi from 'github'; import parseDiff from 'parse-diff'; // Make sure there are changelog entries const hasChangelog = danger.git.modified_files.includes("changelog.md") if (!hasChangelog) { warn("No Changelog changes!") } const jsFiles = danger.git.created_files.filter(path => path.endsWith("js")); function absolute (relPath) { return path.resolve(__dirname, relPath) } const flowIgnorePaths = [ 'node_modules', 'test', 'build', 'examples', 'doc', 'android', 'ios',