Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use David's scope team's reviewable config #464

Open
davidabrahams opened this issue May 12, 2018 · 0 comments
Open

Use David's scope team's reviewable config #464

davidabrahams opened this issue May 12, 2018 · 0 comments

Comments

@davidabrahams
Copy link
Collaborator

It was based on the tagprobot config, with some added features/bug fixes:

// These variables are provided by the reviewable environment.
// For debugging, we import these functions and created a sample json PR using the info
// in: https://github.com/Reviewable/Reviewable/wiki/FAQ
// import _ from 'lodash';
// import review from './sample_pr.json';

const numReviewersRequired = 2;

const files = {};
const assignees = _(review.pullRequest.assignees).map('username')
  .without(review.pullRequest.author.username).value();
const fidelity = ['joeylmaalouf', 'Ziyilan', 'davidabrahams', 'jovanduy', 'jsutker', 'SeanCCarter'];

_.each(review.files, file => {
  const reviewInfo = {};
  // get the revision matching the lastRevision field
  let lastrevision = _.find(file.revisions, r => r.key === review.summary.lastRevision);
  // if there is no revision matching the lastRevision field, use the last non-obsolete revision
  if (!lastrevision) lastrevision = _.last(_.reject(file.revisions, r => r.obsolete))
  // reviewers are all people who submitted reviews on the last file revision , other than
  // the PR author, who are also assignees
  const reviewers = _(lastrevision.reviewers)
    .map('username')
    .filter(u => _.includes(assignees, u))
    .value();

  // iterate over revisions for each file
  _.each(file.revisions, revision => {
    // calculate number of reviewers this revision by dropping pr author and taking length of
    // reviewers
    const reviewersThisRevision = _(revision.reviewers)
      .map('username')
      .filter(u => _.includes(assignees, u))
      .value();
    // mark this revision as unreviewed the number of reviews is not high enough
    revision.reviewed = reviewersThisRevision.length >= numReviewersRequired;
  });

  const neededReviewers = [];
  if (reviewers.length < numReviewersRequired) {
    // place all non-author fidelity members who haven't reviewed the file and add them
    // to neededReviewers
    _.each(_(assignees)
      .reject(a => _.includes(reviewers, a))
      .value(), r => neededReviewers.push(r));
  }
  reviewInfo.neededReviewers = neededReviewers;
  reviewInfo.numReviewsLeft = Math.max(0, numReviewersRequired - reviewers.length);
  files[file.path] = reviewInfo;
});

// map from fidelity member to the number of discussions they must resolve
const discussions = {};
_.each(fidelity, c => { discussions[c] = 0; });
_.each(_(review.discussions)
  .map('participants')
  .flatten()
  .filter({ resolved: false })
  .value(),
  d => { discussions[d.username] += 1; });

const unresolvedDiscussions = _.pick(discussions, o => o > 0);
let completed = _(files)
  // no files have reviews remaining
  .values()
  .map('numReviewsLeft')
  .map(c => c === 0)
  .every()
  &&
  // no discussions are unresolved
  !_(discussions)
  .values()
  .some();

const shortReasons = [];
for (let i = 1; i <= numReviewersRequired; i++) {
  const numFiles = _(files).keys().filter(f => files[f].numReviewsLeft === i).value().length;
  if (numFiles) {
    // N file(s) need(s) M review(s)
    shortReasons.push(numFiles.toString() + ' file' + (numFiles > 1 ? 's' : '') + ' need' +
      (numFiles === 1 ? 's ' : ' ') + i.toString() + ' review' + (i > 1 ? 's' : ''));
  }
}
if (!_.isEmpty(unresolvedDiscussions)) {
  const pendingChauncies = _.keys(unresolvedDiscussions);
  shortReasons.push(pendingChauncies.join(', ') + ' must resolve discussions');
}

const longReasons = [];

_.each(fidelity, c => {
  const filesToReview = _(files)
    .keys()
    // files where this fidelity needs to review it
    .filter(f => _.includes(files[f].neededReviewers, c))
    // and there are reviews required
    .filter(f => files[f].numReviewsLeft)
    .value();
  if (filesToReview.length) {
    longReasons.push(c + ' must review ' + filesToReview.length + ' file' + (filesToReview.length > 1 ? 's' : ''));
  }
});

_.each(_.keys(discussions),
  c => {
    if (discussions[c])
      longReasons.push(c + ' must resolve ' + discussions[c] + ' discussion' + (discussions[c] > 1 ? 's' : ''));
  }
);

if (review.pullRequest.target.branch !== 'master') {
  completed = false;
  shortReasons.push('target branch is not master');
  longReasons.push('target branch is not master');
}


const reviewableStatus = {
  completed,
  description: longReasons.join(', '),
  shortDescription: shortReasons.join(', '),
  files: review.files,
};

// console.log(reviewableStatus);

return reviewableStatus;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants