in functions/src/plugins/merge.ts [154:262]
private async getChecksStatus(context: Context, pr: CachedPullRequest, config: MergeConfig, labels: Github.PullRequestsGetResponseLabelsItem[] = [], statuses?: GithubGQL.StatusContext[]): Promise<ChecksStatus> {
const checksStatus: ChecksStatus = {
pending: [],
failure: []
};
const labelsNames = getLabelsNames(labels);
// Check if there is any merge conflict
if(config.checks.noConflict) {
// If mergeable is null, we need to get the updated status
if(pr.mergeable === null) {
const {owner, repo} = context.repo();
pr = await this.updateDbPR(context.github, owner, repo, pr.number, context.payload.repository.id);
}
// Check if there is a conflict with the base branch
if(pr.mergeable === false) {
checksStatus.failure.push(`conflicts with base branch "${pr.base.ref}"`);
}
}
// Check if all required labels are present
if(config.checks.requiredLabels) {
const missingLabels: string[] = [];
config.checks.requiredLabels.forEach(reqLabel => {
if(!labelsNames.some(label => !!label.match(new RegExp(reqLabel)))) {
missingLabels.push(reqLabel);
}
});
if(missingLabels.length > 0) {
checksStatus.pending.push(`missing required labels: ${missingLabels.join(', ')}`);
}
}
// Check if all required labels when merge ready are present
if(labelsNames.includes(config.mergeLabel) && config.checks.requiredLabelsWhenMergeReady) {
const missingLabels: string[] = [];
config.checks.requiredLabelsWhenMergeReady.forEach(reqLabel => {
if(!labelsNames.some(label => !!label.match(new RegExp(reqLabel)))) {
missingLabels.push(reqLabel);
}
});
if(missingLabels.length > 0) {
checksStatus.pending.push(`missing required labels: ${missingLabels.join(', ')}`);
}
}
// Check if any forbidden label is present
if(config.checks.forbiddenLabels) {
const fbdLabels: string[] = [];
config.checks.forbiddenLabels.forEach(fbdLabel => {
if(labelsNames.some(label => !!label.match(new RegExp(fbdLabel)))) {
fbdLabels.push(fbdLabel);
}
});
if(fbdLabels.length > 0) {
checksStatus.pending.push(`forbidden labels detected: ${fbdLabels.join(', ')}`);
}
}
// Check if we have any failed/pending external status
statuses = statuses || await this.getStatuses(context, pr.number, config);
statuses.forEach(status => {
switch(status.state) {
case STATUS_STATE.Failure:
case STATUS_STATE.Error:
case GQL_STATUS_STATE.Failure:
case GQL_STATUS_STATE.Error:
checksStatus.failure.push(`status "${status.context}" is failing`);
break;
case STATUS_STATE.Pending:
case GQL_STATUS_STATE.Pending:
checksStatus.pending.push(`status "${status.context}" is pending`);
break;
}
});
// Check if all required statuses are present
if(config.checks.requiredStatuses) {
config.checks.requiredStatuses.forEach(reqCheck => {
if(!statuses.some(status => !!status.context.match(new RegExp(reqCheck)))) {
checksStatus.pending.push(`missing required status "${reqCheck}"`);
}
});
}
// Check if there is any review pending or that requested changes
if(config.checks.requireReviews) {
let nbPendingReviews = pr.pendingReviews;
// Because we're adding cache for this value progressively, ensure that we have the data available
// TODO(ocombe): remove this when all DB PRs have been updated
if(typeof nbPendingReviews !== 'number') {
nbPendingReviews = await this.getPendingReviews(context, pr);
pr.pendingReviews = nbPendingReviews;
const {owner, repo} = context.repo();
await this.updateDbPR(context.github, owner, repo, pr.number, context.payload.repository.id, pr).catch(err => {
throw err;
});
}
if(nbPendingReviews > 0) {
checksStatus.pending.push(`${nbPendingReviews} pending code review${nbPendingReviews > 1 ? 's' : ''}`);
}
}
return checksStatus;
}