|
Packit |
5ce601 |
############################################################################
|
|
Packit |
5ce601 |
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
Packit |
5ce601 |
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
Packit Service |
704ed8 |
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# See the COPYRIGHT file distributed with this work for additional
|
|
Packit |
5ce601 |
# information regarding copyright ownership.
|
|
Packit |
5ce601 |
############################################################################
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
import re
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
# Helper functions and variables
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
def added_lines(target_branch, paths):
|
|
Packit |
5ce601 |
import subprocess
|
|
Packit |
5ce601 |
subprocess.check_output(['/usr/bin/git', 'fetch', '--depth', '1', 'origin',
|
|
Packit |
5ce601 |
target_branch])
|
|
Packit |
5ce601 |
diff = subprocess.check_output(['/usr/bin/git', 'diff', 'FETCH_HEAD..',
|
|
Packit |
5ce601 |
'--'] + paths)
|
|
Packit |
5ce601 |
added_lines = []
|
|
Packit |
5ce601 |
for line in diff.splitlines():
|
|
Packit |
5ce601 |
if line.startswith(b'+') and not line.startswith(b'+++'):
|
|
Packit |
5ce601 |
added_lines.append(line)
|
|
Packit |
5ce601 |
return added_lines
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
issue_or_mr_id_regex = re.compile(br'\[(GL [#!]|RT #)[0-9]+\]')
|
|
Packit |
5ce601 |
release_notes_regex = re.compile(r'doc/(arm|notes)/notes-.*\.(rst|xml)')
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
modified_files = danger.git.modified_files
|
|
Packit |
5ce601 |
mr_labels = danger.gitlab.mr.labels
|
|
Packit |
5ce601 |
target_branch = danger.gitlab.mr.target_branch
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
# COMMIT MESSAGES
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# - FAIL if any of the following is true for any commit on the MR branch:
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The subject line starts with "fixup!" or "Apply suggestion".
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * There is no empty line between the subject line and the log message.
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# - WARN if any of the following is true for any commit on the MR branch:
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The length of the subject line exceeds 72 characters.
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * There is no log message present (i.e. commit only has a subject) and the
|
|
Packit |
5ce601 |
# subject line does not contain any of the following strings: "fixup! ",
|
|
Packit |
5ce601 |
# " CHANGES ", " release note".
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * Any line of the log message is longer than 72 characters. This rule is
|
|
Packit |
5ce601 |
# not evaluated for lines starting with four spaces, which allows long
|
|
Packit |
5ce601 |
# lines to be included in the commit log message by prefixing them with
|
|
Packit |
5ce601 |
# four spaces (useful for pasting compiler warnings, static analyzer
|
|
Packit |
5ce601 |
# messages, log lines, etc.)
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
for commit in danger.git.commits:
|
|
Packit |
5ce601 |
message_lines = commit.message.splitlines()
|
|
Packit |
5ce601 |
subject = message_lines[0]
|
|
Packit |
5ce601 |
if subject.startswith('fixup!') or subject.startswith('Apply suggestion'):
|
|
Packit |
5ce601 |
fail('Fixup commits are still present in this merge request. '
|
|
Packit |
5ce601 |
'Please squash them before merging.')
|
|
Packit |
5ce601 |
if len(subject) > 72:
|
|
Packit |
5ce601 |
warn(
|
|
Packit |
5ce601 |
f'Subject line for commit {commit.sha} is too long: '
|
|
Packit |
5ce601 |
f'```{subject}``` ({len(subject)} > 72 characters).'
|
|
Packit |
5ce601 |
)
|
|
Packit |
5ce601 |
if len(message_lines) > 1 and message_lines[1]:
|
|
Packit |
5ce601 |
fail(f'No empty line after subject for commit {commit.sha}.')
|
|
Packit |
5ce601 |
if (len(message_lines) < 3 and
|
|
Packit |
5ce601 |
'fixup! ' not in subject and
|
|
Packit |
5ce601 |
' CHANGES ' not in subject and
|
|
Packit |
5ce601 |
' release note' not in subject):
|
|
Packit |
5ce601 |
warn(f'Please write a log message for commit {commit.sha}.')
|
|
Packit |
5ce601 |
for line in message_lines[2:]:
|
|
Packit |
5ce601 |
if len(line) > 72 and not line.startswith(' '):
|
|
Packit |
5ce601 |
warn(
|
|
Packit |
5ce601 |
f'Line too long in log message for commit {commit.sha}: '
|
|
Packit |
5ce601 |
f'```{line}``` ({len(line)} > 72 characters).'
|
|
Packit |
5ce601 |
)
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
# MILESTONE
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# FAIL if the merge request is not assigned to any milestone.
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
if not danger.gitlab.mr.milestone:
|
|
Packit |
5ce601 |
fail('Please assign this merge request to a milestone.')
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
# VERSION LABELS
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# FAIL if any of the following is true for the merge request:
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The "Backport" label is set and the number of version labels set is
|
|
Packit |
5ce601 |
# different than 1. (For backports, the version label is used for indicating
|
|
Packit |
5ce601 |
# its target branch. This is a rather ugly attempt to address a UI
|
|
Packit |
5ce601 |
# deficiency - the target branch for each MR is not visible on milestone
|
|
Packit |
5ce601 |
# dashboards.)
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * Neither the "Backport" label nor any version label is set. (If the merge
|
|
Packit |
5ce601 |
# request is not a backport, version labels are used for indicating
|
|
Packit |
5ce601 |
# backporting preferences.)
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
backport_label_set = 'Backport' in mr_labels
|
|
Packit |
5ce601 |
version_labels = [l for l in mr_labels if l.startswith('v9.')]
|
|
Packit |
5ce601 |
if backport_label_set and len(version_labels) != 1:
|
|
Packit |
5ce601 |
fail('The *Backport* label is set for this merge request. '
|
|
Packit |
5ce601 |
'Please also set exactly one version label (*v9.x*).')
|
|
Packit |
5ce601 |
if not backport_label_set and not version_labels:
|
|
Packit |
5ce601 |
fail('If this merge request is a backport, set the *Backport* label and '
|
|
Packit |
5ce601 |
'a single version label (*v9.x*) indicating the target branch. '
|
|
Packit |
5ce601 |
'If not, set version labels for all targeted backport branches.')
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
# OTHER LABELS
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# WARN if any of the following is true for the merge request:
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The "Review" label is not set. (It may be intentional, but rarely is.)
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The "Review" label is set, but the "LGTM" label is not set. (This aims to
|
|
Packit |
5ce601 |
# remind developers about the need to set the latter on merge requests which
|
|
Packit |
5ce601 |
# passed review.)
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
if 'Review' not in mr_labels:
|
|
Packit |
5ce601 |
warn('This merge request does not have the *Review* label set. '
|
|
Packit |
5ce601 |
'Please set it if you would like the merge request to be reviewed.')
|
|
Packit |
5ce601 |
elif 'LGTM (Merge OK)' not in mr_labels:
|
|
Packit |
5ce601 |
warn('This merge request is currently in review. '
|
|
Packit |
5ce601 |
'It should not be merged until it is marked with the *LGTM* label.')
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
# 'CHANGES' FILE
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# FAIL if any of the following is true:
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The merge request does not update the CHANGES file, but it does not have
|
|
Packit |
5ce601 |
# the "No CHANGES" label set. (This attempts to ensure that the author of
|
|
Packit |
5ce601 |
# the MR did not forget about adding a CHANGES entry.)
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The merge request updates the CHANGES file, but it has the "No CHANGES"
|
|
Packit |
5ce601 |
# label set. (This attempts to ensure the the "No CHANGES" label is used in
|
|
Packit |
5ce601 |
# a sane way.)
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The merge request adds a new CHANGES entry that does not contain any
|
|
Packit |
5ce601 |
# GitLab/RT issue/MR identifiers.
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
changes_modified = 'CHANGES' in modified_files
|
|
Packit |
5ce601 |
no_changes_label_set = 'No CHANGES' in mr_labels
|
|
Packit |
5ce601 |
if not changes_modified and not no_changes_label_set:
|
|
Packit |
5ce601 |
fail('This merge request does not modify `CHANGES`. '
|
|
Packit |
5ce601 |
'Add a `CHANGES` entry or set the *No CHANGES* label.')
|
|
Packit |
5ce601 |
if changes_modified and no_changes_label_set:
|
|
Packit |
5ce601 |
fail('This merge request modifies `CHANGES`. '
|
|
Packit |
5ce601 |
'Revert `CHANGES` modifications or unset the *No Changes* label.')
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
changes_added_lines = added_lines(target_branch, ['CHANGES'])
|
|
Packit |
5ce601 |
identifiers_found = filter(issue_or_mr_id_regex.search, changes_added_lines)
|
|
Packit |
5ce601 |
if changes_added_lines and not any(identifiers_found):
|
|
Packit |
5ce601 |
fail('No valid issue/MR identifiers found in added `CHANGES` entries.')
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
# RELEASE NOTES
|
|
Packit |
5ce601 |
###############################################################################
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# - FAIL if any of the following is true:
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The merge request does not update release notes and has the "Release
|
|
Packit |
5ce601 |
# Notes" label set. (This attempts to point out missing release notes.)
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# * The merge request updates release notes but does not have the "Release
|
|
Packit |
5ce601 |
# Notes" label set. (This ensures that merge requests updating release
|
|
Packit |
5ce601 |
# notes can be easily found using the "Release Notes" label.)
|
|
Packit |
5ce601 |
#
|
|
Packit |
5ce601 |
# - WARN if this merge request updates release notes, but no GitLab/RT issue/MR
|
|
Packit |
5ce601 |
# identifiers are found in the lines added to the release notes by this MR.
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
release_notes_regex = re.compile(r'doc/(arm|notes)/notes-.*\.(rst|xml)')
|
|
Packit |
5ce601 |
release_notes_changed = list(filter(release_notes_regex.match, modified_files))
|
|
Packit |
5ce601 |
release_notes_label_set = 'Release Notes' in mr_labels
|
|
Packit |
5ce601 |
if not release_notes_changed and release_notes_label_set:
|
|
Packit |
5ce601 |
fail('This merge request has the *Release Notes* label set. '
|
|
Packit |
5ce601 |
'Add a release note or unset the *Release Notes* label.')
|
|
Packit |
5ce601 |
if release_notes_changed and not release_notes_label_set:
|
|
Packit |
5ce601 |
fail('This merge request modifies release notes. '
|
|
Packit |
5ce601 |
'Revert release note modifications or set the *Release Notes* label.')
|
|
Packit |
5ce601 |
|
|
Packit |
5ce601 |
if release_notes_changed:
|
|
Packit |
5ce601 |
notes_added_lines = added_lines(target_branch, release_notes_changed)
|
|
Packit |
5ce601 |
identifiers_found = filter(issue_or_mr_id_regex.search, notes_added_lines)
|
|
Packit |
5ce601 |
if notes_added_lines and not any(identifiers_found):
|
|
Packit |
5ce601 |
warn('No valid issue/MR identifiers found in added release notes.')
|