Skip to content

Commit

Permalink
infra: bumpver: Add JIRA validation of issues
Browse files Browse the repository at this point in the history
Validate JIRA issues on commits with Red Hat JIRA and not to bugzilla
anymore. From RHEL-8.10 and RHEL-9.4 Bugzilla is not used by Red Hat any
JIRA is the successor. Let's adapt this script to that.

It's simplified version of RHBZ solution.

What is different:
* JIRA don't have ACKs but instead states
* JIRA don't support Related / Resolves - still in the code because it
could help us but JIRA is just taking the issue and ignores the rest.
* Don't support BZ in summary (we are not using that anymore)
* Print confirmation that the given commit is correct
  • Loading branch information
jkonecny12 committed Dec 1, 2023
1 parent 03e9e50 commit 9f643f1
Showing 1 changed file with 125 additions and 6 deletions.
131 changes: 125 additions & 6 deletions scripts/makebumpver
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ import argparse
import datetime
import logging

from jira import JIRA, JIRAError
from functools import cache

log = logging.getLogger("bumpver")
log.setLevel(logging.INFO)


VERSION_NUMBER_INCREMENT = 1
DEFAULT_ADDED_VERSION_NUMBER = 1
DEFAULT_MINOR_VERSION_NUMBER = 1

TOKEN_PATH = "~/.config/anaconda/jira"

def run_program(*args):
"""Run a program with universal newlines on"""
Expand Down Expand Up @@ -65,6 +68,72 @@ class ParseCommaSeparatedList(argparse.Action):
setattr(namespace, self.dest, value_list)


class JIRAValidator:
def __init__(self):
self.jira = None

self._connect()

def _connect(self):
"""Connect to our JIRA instance by provided token file."""
token = self._read_token(TOKEN_PATH)
self.jira = JIRA("https://issues.redhat.com/", token_auth=token)

@staticmethod
def _read_token(token_path):
token_path = os.path.expanduser(token_path)
try:
with open(token_path, "r", encoding="utf-8") as f:
return f.read().strip()
except FileNotFoundError:
print(f"Token can't be found! Please generate your JIRA token in {TOKEN_PATH}", file=sys.stderr)
print("Please generate the token here: https://issues.redhat.com/secure/ViewProfile.jspa?selectedTab=com.atlassian.pats.pats-plugin:jira-user-personal-access-tokens")
sys.exit(1)

return None

@cache
def _query_RHEL_issue(self, bug):
try:
issue = self.jira.issue(bug)
except JIRAError as ex:
raise ValueError(f"Error during JIRA query for bug {bug}: {ex.text}") from ex

return issue

def check_if_RHEL_issue(self, bug):
if not bug.startswith("RHEL-"):
return False, "is not the 'RHEL' JIRA project - Skipping"

self._query_RHEL_issue(bug)

return True, ""

def validate_RHEL_issue_status(self, bug):
issue = self._query_RHEL_issue(bug)

valid_statuses = ("Planning", "In Progress")
status = issue.fields.status.name
if status not in valid_statuses:
return False, f"incorrect status '{status}'! Valid values: {valid_statuses}"

return True, ""

def validate_RHEL_issue_fixversion(self, bug):
issue = self._query_RHEL_issue(bug)

# TODO: Switch this to template solution "distro_release"
valid_fix_version = "rhel-9"
fix_version = issue.fields.fixVersions
for version in fix_version:
# Let's simplify and check only major version (ignore minor RHEL releases)
if version.name.startswith(valid_fix_version):
return True, ""

msg = f"incorrect fixVersion '{fix_version}! It has to start with {valid_fix_version}"
return False, msg


class MakeBumpVer:
def __init__(self):
cwd = os.getcwd()
Expand Down Expand Up @@ -156,6 +225,8 @@ class MakeBumpVer:
self.bz = None
self._bz_cache = {}

self._jira = JIRAValidator()

self.gituser = self._git_config('user.name')
self.gitemail = self._git_config('user.email')

Expand Down Expand Up @@ -333,8 +404,8 @@ class MakeBumpVer:
continue

if self.rhel:
bad, rhbz = self._check_rhel_bugs(commit, summary, body, author)
rpm_log.append((summary.strip(), list(rhbz)))
bad, bugs = self._check_rhel_issues(commit, summary, body, author)
rpm_log.append(("%s (%s)" % (summary.strip(), author), list(bugs)))
else:
rpm_log.append(("%s (%s)" % (summary.strip(), author), None))

Expand All @@ -346,6 +417,54 @@ class MakeBumpVer:

return rpm_log

def _check_rhel_issues(self, commit, summary, body, author):
issues = set()
bad = False

summary = summary + f" ({author})"

for bodyline in body:
m = re.match(r"^(Resolves|Related):\ +jira#\w+-\d+.*$", bodyline)
if not m:
continue

actionre = re.search("(Resolves|Related)", bodyline)
bugre = re.search(r"\w+-\d+", bodyline)

if actionre and bugre:
action = actionre.group()
bug = bugre.group()

# store the bug to output list if checking is disabled and continue
if self.skip_all:
issues.add(f"{action}: jira#{bug}")
print(f"*** Bug {bug} Related commit {commit} is skipped\n")
continue

if not self._jira.check_if_RHEL_issue(bug):
print_failure("is not the 'RHEL' JIRA project", bug, commit, summary)
bad = True
continue

valid_status, msg = self._jira.validate_RHEL_issue_status(bug)
if not valid_status:
print_failure(msg, bug, commit, summary)
bad = True

valid_fixversion, msg = self._jira.validate_RHEL_issue_fixversion(bug)
if not valid_fixversion:
print_failure(msg, bug, commit, summary)
bad = True

print(f"*** Bug {bug} Related commit {commit} is allowed\n")
issues.add(f"{action}: jira#{bug}")

if len(issues) == 0 and not self.skip_all:
print("*** No bugs referenced in commit %s\n" % commit)
bad = True

return bad, issues

def _check_rhel_bugs(self, commit, summary, body, author):
rhbz = set()
bad = False
Expand Down Expand Up @@ -487,7 +606,7 @@ class MakeBumpVer:
f.write("* %s %s <%s> - %s-%s\n" % (stamp, self.gituser, self.gitemail,
newVersion, self.new_release))

for msg, rhbz in rpmlog:
for msg, bugs in rpmlog:
msg = re.sub('(?<!%)%%(?!%)|(?<!%%)%(?!%%)', '%%', msg)
sublines = textwrap.wrap(msg, 77)
f.write("- %s\n" % sublines[0])
Expand All @@ -496,8 +615,8 @@ class MakeBumpVer:
for subline in sublines[1:]:
f.write(" %s\n" % subline)

if rhbz:
for entry in rhbz:
if bugs:
for entry in bugs:
f.write(" %s\n" % entry)

f.write("\n")
Expand Down

0 comments on commit 9f643f1

Please sign in to comment.