Index: hooks/scripts/extract_pr_numbers.py =================================================================== --- /dev/null +++ hooks/scripts/extract_pr_numbers.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +## +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2019 Eric van Gyzen +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +# Given a Subversion commit log on stdin, extract the PR numbers +# and print them on a single line to stdout. +# +# The recommended form is: +# +# PR: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=123456 +# +# Bare PR numbers are also accepted, multiple per line, with optional commas. +# A commit log can have multiple "PR:" lines. +# Specifically, any whitespace-delimited field that is entirely numeric +# (with an optional trailing comma) is considered a PR number. +# Other text is ignored. See tests/test_extract_pr_numbers.py for examples. + +from __future__ import print_function +import sys + +BZ_URL = 'https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=' +prs = set() + +for line in sys.stdin: + if line[:3].upper() != 'PR:': + continue + fields = line[3:].split() + for field in fields: + if field.startswith(BZ_URL): + field = field[len(BZ_URL):] + field = field.rstrip(',') + try: + pr = int(field) + except ValueError as e: + continue + if pr <= 0: + continue + prs.add(pr) + +if prs: + print(' '.join(map(str, sorted(prs)))) Index: hooks/scripts/notify_bz.sh =================================================================== --- hooks/scripts/notify_bz.sh +++ hooks/scripts/notify_bz.sh @@ -14,7 +14,7 @@ exit 1 fi -PRS="$(svnlook info "$REPO" -r "$REV" | grep -e '^[[:space:]]*[pP][rR]:[[:space:]]*'|grep -Eo '([a-zA-Z]+\/)*[^[]([0-9]+)[^],]'|sed -Ee 's,[[:space:]],,g' -e 's,[a-zA-Z]+\/,,g')" +PRS="$(svnlook info "$REPO" -r "$REV" | extract_pr_numbers.py)" if [ -z "$PRS" ]; then exit 0 Index: hooks/scripts/tests/test_extract_pr_numbers.py =================================================================== --- /dev/null +++ hooks/scripts/tests/test_extract_pr_numbers.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python + +## +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2019 Eric van Gyzen +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +from __future__ import print_function +import subprocess + +CASE_DATA = """ +123456|PR: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=123456 +123456|PR: 123456 +123456|pr: 123456 +123456|Pr: 123456 +123456|pR: 123456 +123456|PR: 123456 (foo bar) +123456|PR: 123456 sort-of, but not really +123456|PR: 123456 [exp-run] +123456|PR: 123456 [1] +123456|PR:123456 [1] +123456|PR: 123456 +123456 234567|PR: 123456 234567 ... +123456 234567|PR: 123456, 234567, ... +123456 234567|PR: 123456 [1], 234567 [2], ... +123456 234567|PR: 123456 and maybe 234567 but I doubt it... +123456 234567|PR:123456 234567 ... +123456 234567|PR: 123456 234567 ... +123456 234567|Pr: 123456 234567 ... +123456 234567|pR: 123456 234567 ... +|PR 76812 is not a PR line because it has no ":" +""" + +MULTI_LINE_CASE_DATA = [ + '123456 234567|PR:\t123456\nPR:\t234567', + '123456 234567|' + \ + 'PR:\thttps://bugs.freebsd.org/bugzilla/show_bug.cgi?id=123456\n' + \ + 'PR:\thttps://bugs.freebsd.org/bugzilla/show_bug.cgi?id=234567\n', +] + +for line in CASE_DATA.split('\n') + MULTI_LINE_CASE_DATA: + if not line: continue + (expected, case) = line.split('|', 1) + if expected != '': + expected += '\n' + proc = subprocess.Popen( + ['../extract_pr_numbers.py'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + (stdout, stderr) = proc.communicate(case) + if proc.returncode != 0 or stderr != '' or stdout != expected: + print('FAIL:') + print('input: ' + case) + print('output: ' + stdout) + print('stderr: ' + stderr) + print('status: ' + str(proc.returncode)) + else: + print('PASS')