in tools/@aws-cdk/prlint/lint.ts [195:328]
public async validatePullRequestTarget(): Promise<LinterActions> {
let ret: LinterActions = {};
const number = this.props.number;
const sha = (await this.pr()).head.sha;
console.log(`⌛ Fetching PR number ${number}`);
const pr = await this.pr();
console.log(`PR base ref is: ${pr.base.ref}`)
console.log(`⌛ Fetching files for PR number ${number}`);
const files = await this.client.paginate(this.client.pulls.listFiles, this.prParams);
console.log('⌛ Validating...');
const validationCollector = new ValidationCollector(pr, files);
validationCollector.validateRuleSet({
exemption: shouldExemptReadme,
exemptionMessage: `Not validating README changes since the PR is labeled with '${Exemption.README}'`,
testRuleSet: [{ test: featureContainsReadme }],
});
validationCollector.validateRuleSet({
exemption: shouldExemptTest,
exemptionMessage: `Not validating test changes since the PR is labeled with '${Exemption.TEST}'`,
testRuleSet: [{ test: featureContainsTest }, { test: fixContainsTest }],
});
validationCollector.validateRuleSet({
exemption: shouldExemptIntegTest,
exemptionMessage: `Not validating integration test changes since the PR is labeled with '${Exemption.INTEG_TEST}'`,
testRuleSet: [{ test: featureContainsIntegTest }, { test: fixContainsIntegTest }],
});
validationCollector.validateRuleSet({
exemption: shouldExemptBreakingChange,
exemptionMessage: `Not validating breaking changes since the PR is labeled with '${Exemption.BREAKING_CHANGE}'`,
testRuleSet: [{ test: assertStability }],
});
validationCollector.validateRuleSet({
exemption: shouldExemptCliIntegTested,
testRuleSet: [{ test: noCliChanges }],
});
validationCollector.validateRuleSet({
exemption: shouldExemptAnalyticsMetadataChange,
testRuleSet: [
{ test: noMetadataChanges },
{ test: noAnalyticsClassesChanges },
{ test: noAnalyticsEnumsChanges },
{ test: noAnalyticsEnumAutomationChanges },
{ test: noAnalyticsEnumLikeAutomationChanges },
],
});
validationCollector.validateRuleSet({
testRuleSet: [
{ test: validateBreakingChangeFormat },
{ test: validateTitlePrefix },
{ test: validateTitleScope },
{ test: validateTitleLowercase },
{ test: validateBranch },
],
});
validationCollector.validateRuleSet({
exemption: shouldExemptSizeCheck,
testRuleSet: [
{ test: prIsSmall },
],
})
if (pr.base.ref === 'main') {
// Only check CodeCov for PRs targeting 'main'
const runs = await this.checkRuns(sha);
const codeCovRuns = CODECOV_CHECKS.map(c => runs[c] as CheckRun | undefined);
validationCollector.validateRuleSet({
exemption: () => hasLabel(pr, Exemption.CODECOV),
testRuleSet: [{
test: () => {
const summary = summarizeRunConclusions(codeCovRuns.map(r => r?.conclusion));
console.log('CodeCov Summary:', summary);
switch (summary) {
case 'failure': return TestResult.failure('CodeCov is indicating a drop in code coverage');
// If we don't know the result of the CodeCov results yet, we pretend that there isn't a problem.
//
// It would be safer to ask for changes until we're confident that CodeCov has passed, but if we do
// that the following sequence of events happens:
//
// 1. PR is ready to be merged (approved, everything passes)
// 2. Mergify enqueues it and merges from main
// 3. CodeCov needs to run again
// 4. PR linter requests changes because CodeCov result is uncertain
// 5. Mergify dequeues the PR because PR linter requests changes
//
// This looks very confusing and noisy, and also will never fix itself, so the PR ends up unmerged.
//
// The better solution would probably be not to do a "Request Changes" review, but leave a comment
// and create a GitHub "status" on the PR to say 'success/pending/failure', and make it required.
// (https://github.com/aws/aws-cdk/issues/33136)
//
// For now, not doing anything with a 'waiting' status is a smaller delta, and the race condition posed by it is
// unlikely to happen given that there are much slower jobs that the merge is blocked on anyway.
case 'waiting': return TestResult.success();
case 'success': return TestResult.success();
}
},
}],
});
}
// We always delete all comments; in the future we will just communicate via reviews.
ret.deleteComments = await this.findExistingPRLinterComments();
ret = mergeLinterActions(ret, await this.validationToActions(validationCollector));
// also assess whether the PR needs review or not
try {
const state = await this.codeBuildJobSucceeded(sha);
console.log(`PR code build job ${state ? "SUCCESSFUL" : "not yet successful"}`);
if (state) {
console.log('Assessing if the PR needs a review now');
ret = mergeLinterActions(ret, await this.assessNeedsReview());
}
} catch (e) {
console.log(`assessing review failed for sha ${sha}: `, e);
}
return ret;
}