[tool] Switch PR description overrides over to labels (#6145)

This commit is contained in:
stuartmorgan
2022-07-27 13:59:04 -04:00
committed by GitHub
parent f2d9f51dd1
commit b83209e3e5
4 changed files with 109 additions and 121 deletions

View File

@ -123,47 +123,49 @@ class VersionCheckCommand extends PackageLoopingCommand {
'(e.g., PR description or commit message).\n\n'
'If supplied, this is used to allow overrides to some version '
'checks.');
argParser.addOption(_prLabelsArg,
help: 'A comma-separated list of labels associated with this PR, '
'if applicable.\n\n'
'If supplied, this may be to allow overrides to some version '
'checks.');
argParser.addFlag(_checkForMissingChanges,
help: 'Validates that changes to packages include CHANGELOG and '
'version changes unless they meet an established exemption.\n\n'
'If used with --$_changeDescriptionFile, this is should only be '
'used in pre-submit CI checks, to prevent the possibility of '
'post-submit breakage if an override justification is not '
'transferred into the commit message.',
'If used with --$_prLabelsArg, this is should only be '
'used in pre-submit CI checks, to prevent post-submit breakage '
'when labels are no longer applicable.',
hide: true);
argParser.addFlag(_ignorePlatformInterfaceBreaks,
help: 'Bypasses the check that platform interfaces do not contain '
'breaking changes.\n\n'
'This is only intended for use in post-submit CI checks, to '
'prevent the possibility of post-submit breakage if a change '
'description justification is not transferred into the commit '
'message. Pre-submit checks should always use '
'--$_changeDescriptionFile instead.',
'prevent post-submit breakage when overriding the check with '
'labels. Pre-submit checks should always use '
'--$_prLabelsArg instead.',
hide: true);
}
static const String _againstPubFlag = 'against-pub';
static const String _changeDescriptionFile = 'change-description-file';
static const String _prLabelsArg = 'pr-labels';
static const String _checkForMissingChanges = 'check-for-missing-changes';
static const String _ignorePlatformInterfaceBreaks =
'ignore-platform-interface-breaks';
/// The string that must be in [_changeDescriptionFile] to allow a breaking
/// The label that must be on a PR to allow a breaking
/// change to a platform interface.
static const String _breakingChangeJustificationMarker =
'## Breaking change justification';
static const String _breakingChangeOverrideLabel =
'override: allow breaking change';
/// The string that must be at the start of a line in [_changeDescriptionFile]
/// to allow skipping a version change for a PR that would normally require
/// one.
static const String _missingVersionChangeJustificationMarker =
'No version change:';
/// The label that must be on a PR to allow skipping a version change for a PR
/// that would normally require one.
static const String _missingVersionChangeOverrideLabel =
'override: no versioning needed';
/// The string that must be at the start of a line in [_changeDescriptionFile]
/// to allow skipping a CHANGELOG change for a PR that would normally require
/// one.
static const String _missingChangelogChangeJustificationMarker =
'No CHANGELOG change:';
/// The label that must be on a PR to allow skipping a CHANGELOG change for a
/// PR that would normally require one.
static const String _missingChangelogChangeOverrideLabel =
'override: no changelog needed';
final PubVersionFinder _pubVersionFinder;
@ -172,6 +174,7 @@ class VersionCheckCommand extends PackageLoopingCommand {
late final List<String> _changedFiles;
late final String _changeDescription = _loadChangeDescription();
late final Set<String> _prLabels = _getPRLabels();
@override
final String name = 'version-check';
@ -498,18 +501,25 @@ ${indentation}The first version listed in CHANGELOG.md is $fromChangeLog.
return true;
}
if (_getChangeDescription().contains(_breakingChangeJustificationMarker)) {
if (_prLabels.contains(_breakingChangeOverrideLabel)) {
logWarning(
'${indentation}Allowing breaking change to ${package.displayName} '
'due to "$_breakingChangeJustificationMarker" in the change '
'description.');
'due to the "$_breakingChangeOverrideLabel" label.');
return true;
}
return false;
}
String _getChangeDescription() => _changeDescription;
/// Returns the labels associated with this PR, if any, or an empty set
/// if that flag is not provided.
Set<String> _getPRLabels() {
final String labels = getStringArg(_prLabelsArg);
if (labels.isEmpty) {
return <String>{};
}
return labels.split(',').map((String label) => label.trim()).toSet();
}
/// Returns the contents of the file pointed to by [_changeDescriptionFile],
/// or an empty string if that flag is not provided.
@ -569,44 +579,38 @@ ${indentation}The first version listed in CHANGELOG.md is $fromChangeLog.
}
if (state.needsVersionChange) {
final String changeDescription = _getChangeDescription();
if (changeDescription.split('\n').any((String line) =>
line.startsWith(_missingVersionChangeJustificationMarker))) {
logWarning('Ignoring lack of version change due to '
'"$_missingVersionChangeJustificationMarker" in the '
'change description.');
} else if (_isAllowedDependabotChange(package, changeDescription)) {
if (_prLabels.contains(_missingVersionChangeOverrideLabel)) {
logWarning('Ignoring lack of version change due to the '
'"$_missingVersionChangeOverrideLabel" label.');
} else if (_isAllowedDependabotChange(package, _changeDescription)) {
logWarning('Ignoring lack of version change for Dependabot change to '
'a known internal dependency.');
} else {
printError(
'No version change found, but the change to this package could '
'not be verified to be exempt from version changes according to '
'repository policy. If this is a false positive, please '
'add a line starting with\n'
'$_missingVersionChangeJustificationMarker\n'
'to your PR description with an explanation of why it is exempt.');
'repository policy. If this is a false positive, please comment in '
'the PR to explain why the PR is exempt, and add (or ask your '
'reviewer to add) the "$_missingVersionChangeOverrideLabel" '
'label.');
return 'Missing version change';
}
}
if (!state.hasChangelogChange) {
final String changeDescription = _getChangeDescription();
if (changeDescription.split('\n').any((String line) =>
line.startsWith(_missingChangelogChangeJustificationMarker))) {
logWarning('Ignoring lack of CHANGELOG update due to '
'"$_missingChangelogChangeJustificationMarker" in the '
'change description.');
} else if (_isAllowedDependabotChange(package, changeDescription)) {
if (_prLabels.contains(_missingChangelogChangeOverrideLabel)) {
logWarning('Ignoring lack of CHANGELOG update due to the '
'"$_missingChangelogChangeOverrideLabel" label.');
} else if (_isAllowedDependabotChange(package, _changeDescription)) {
logWarning('Ignoring lack of CHANGELOG update for Dependabot change to '
'a known internal dependency.');
} else {
printError(
'No CHANGELOG change found. If this PR needs an exemption from '
'the standard policy of listing all changes in the CHANGELOG, '
'please add a line starting with\n'
'$_missingChangelogChangeJustificationMarker\n'
'to your PR description with an explanation of why.');
'comment in the PR to explain why the PR is exempt, and add (or '
'ask your reviewer to add) the '
'"$_missingChangelogChangeOverrideLabel" label.');
return 'Missing CHANGELOG change';
}
}
@ -617,6 +621,11 @@ ${indentation}The first version listed in CHANGELOG.md is $fromChangeLog.
/// Returns true if [changeDescription] matches a Dependabot change for a
/// dependency roll that should bypass the normal version and CHANGELOG change
/// checks (for dependencies that are known not to have client impact).
///
/// Depending on CI, [changeDescription] may either be the PR description, or
/// the description of the last commit (see for example discussion in
/// https://github.com/cirruslabs/cirrus-ci-docs/issues/1029), so this needs
/// to handle both.
bool _isAllowedDependabotChange(
RepositoryPackage package, String changeDescription) {
// Espresso exports some dependencies that are normally just internal test
@ -629,8 +638,7 @@ ${indentation}The first version listed in CHANGELOG.md is $fromChangeLog.
// any other PR, to identify Dependabot PRs.
const String dependabotPRDescriptionMarker =
'Dependabot commands and options';
// The same thing, but for the Dependabot commit message, to work around
// https://github.com/cirruslabs/cirrus-ci-docs/issues/1029.
// The same thing, but for the Dependabot commit message.
const String dependabotCommitMessageMarker =
'Signed-off-by: dependabot[bot]';
// Expression to extract the name of the dependency being updated.