Example #1
0
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. "
      );
    }
  }
}
Example #2
0
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('')
    )
  }
})
Example #3
0
 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('')
     )
   }
 })
Example #4
0
    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('')
        )
      }
    })
Example #5
0
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.`)
	}
}
Example #6
0
 * 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' );
}
Example #7
0
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 =
Example #8
0
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>`)
Example #9
0
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>`)
Example #10
0
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.")
	}
}
Example #11
0
(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);
  }
})();
Example #12
0
 * 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',