Skip to content

Instantly share code, notes, and snippets.

@jberry-suse
Created January 20, 2017 23:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jberry-suse/ebef106a308ec22d082519d42dc3277e to your computer and use it in GitHub Desktop.
Save jberry-suse/ebef106a308ec22d082519d42dc3277e to your computer and use it in GitHub Desktop.
diff --git a/issue-diff.py b/issue-diff.py
index dd5e819..51cfe45 100755
--- a/issue-diff.py
+++ b/issue-diff.py
@@ -3,7 +3,7 @@
from __future__ import print_function
import argparse
-#import bugzilla
+import bugzilla
import dateutil.parser
from datetime import timedelta, datetime
from dateutil.tz import tzlocal
@@ -24,22 +24,47 @@ from osclib.cache import Cache
# either summary or one in which ISSUE_SUMMARY is then placed must be unicode.
# For example, translation-update-upstream contains bsc#877707 which has a
# unicode character in its summary.
-BUG_SUMMARY = 'Missing issue references from {project}/{package} to {factory}/{package}'
+BUG_SUMMARY = 'Missing issue references from {project}/{package} in {factory}/{package}'
BUG_TEMPLATE = u'{message_start}\n\n{issues}'
MESSAGE_START = 'The following issues were referenced in the changelog for {project}/{package}, but where not found in {factory}/{package} after {newest} days. Review the issues and submit changes to {factory} as necessary.'
-ISSUE_SUMMARY = u'[{label}]({url}) owned by @{owner}: {summary}'
-ISSUE_SUMMARY_PLAIN = '[{label}]({url})'
-
-
-def create_bug(api, summary, description):
- createinfo = api.build_createbug(
- product='??', # TODO
- version='??',
- component='??',
+ISSUE_SUMMARY = u'[{label}]({url}) owned by {owner}: {summary}'
+ISSUE_SUMMARY_PLAIN = u'[{label}]({url})'
+
+
+def bug_create(bugzilla_api, meta, cc, summary, description):
+ createinfo = bugzilla_api.build_createbug(
+ product=meta[0],
+ component=meta[1],
+ version=meta[2],
+ severity='normal',
+ op_sys='Linux',
+ platform='PC',
+ cc=cc,
summary=summary,
description=description)
+ newbug = bugzilla_api.createbug(createinfo)
+
+ return newbug.id
+
+def bug_meta_get(bugzilla_api, bug_id):
+ bug = bugzilla_api.getbug(bug_id)
+ return (bug.product, bug.component, bug.version)
- return createinfo.id
+def bug_meta(bugzilla_api, defaults, trackers, issues):
+ # Extract meta from the first bug from bnc tracker or fallback to defaults.
+ prefix = trackers['bnc'][:3]
+ for issue in issues:
+ if issue.startswith(prefix):
+ return bug_meta_get(bugzilla_api, issue[4:])
+
+ return defaults
+
+def bugzilla_init(apiurl):
+ bugzilla_api = bugzilla.Bugzilla(apiurl)
+ if not bugzilla_api.logged_in:
+ print('Bugzilla credentials required to create bugs.')
+ bugzilla_api.interactive_login()
+ return bugzilla_api
def prompt_continue(change_count):
allowed = ['y', 'n', '']
@@ -64,7 +89,7 @@ def prompt_continue(change_count):
def prompt_interactive(changes, project, factory, package, newest):
with tempfile.NamedTemporaryFile(suffix='.yml') as temp:
- temp.write(yaml.dump(changes, default_flow_style=False, default_style="'") + '\n')
+ temp.write(yaml.safe_dump(changes, default_flow_style=False, default_style="'") + '\n')
temp.write('# {}/{}\n'.format(project, package))
temp.write('# comment or remove lines to whitelist issues')
temp.flush()
@@ -116,7 +141,7 @@ def issues_get(apiurl, project, package, trackers, db):
if summary is not None:
summary = summary.text
- owner = issue.find('owner/login')
+ owner = issue.find('owner/email')
if owner is not None:
owner = owner.text
@@ -217,12 +242,15 @@ def main(args):
print('Comparing {} against {}'.format(args.project, args.factory))
+ bugzilla_api = bugzilla_init(args.bugzilla_apiurl)
+ bugzilla_defaults = (args.bugzilla_product, args.bugzilla_component, args.bugzilla_version)
+
trackers = issue_trackers(apiurl)
packages_project = package_list(apiurl, args.project)
packages_factory = package_list(apiurl_default, args.factory)
packages = set(packages_project).intersection(set(packages_factory))
new = 0
- for package in packages:
+ for package in sorted(packages):
issues_project = issues_get(apiurl, args.project, package, trackers, db)
issues_factory = issues_get(apiurl_default, args.factory, package, trackers, db)
@@ -252,10 +280,14 @@ def main(args):
# Determine if any real changes (vs typos) and create text issue list.
issues = []
+ cc = []
if len(changes_after) > 0:
for issue, summary in changes.items():
if issue in changes_after:
issues.append('- ' + summary)
+ owner = issues_project[issue]['owner']
+ if owner is not None:
+ cc.append(owner)
# Prompt user about how to continue.
response = prompt_continue(len(issues))
@@ -272,9 +304,11 @@ def main(args):
project=args.project, factory=args.factory, package=package, newest=args.newest),
issues='\n'.join(issues))
- # TODO Lookup bugzilla component.
- bug_id = '17'
- #bug_id = bug_create(bugzilla_api, summary, message)
+ # Determine bugzilla meta information to use when creating bug.
+ meta = bug_meta(bugzilla_api, bugzilla_defaults, trackers, changes.keys())
+ if args.bugzilla_cc:
+ cc.append(args.bugzilla_cc)
+ bug_id = bug_create(bugzilla_api, meta, cc, summary, message)
# Mark changes in db.
notified, whitelisted = 0, 0
@@ -283,7 +317,7 @@ def main(args):
db[package] = {}
if issue in changes_after:
- db[package][issue] = bug_id
+ db[package][issue] = str(bug_id)
notified += 1
else:
db[package][issue] = 'whitelist'
@@ -291,7 +325,7 @@ def main(args):
# Write out changes after each package to avoid loss.
with open(db_file, 'w') as outfile:
- yaml.dump(db, outfile, default_flow_style=False, default_style="'")
+ yaml.safe_dump(db, outfile, default_flow_style=False, default_style="'")
if notified > 0:
print('{}: {} notified in bug #{}, {} whitelisted'.format(package, notified, bug_id, whitelisted))
@@ -315,7 +349,11 @@ if __name__ == '__main__':
'of previously handled issues to avoid repeats and kept in sync via a git repository.'
parser = argparse.ArgumentParser(description=description)
parser.add_argument('-A', '--apiurl', default='https://api.suse.de', metavar='URL', help='OBS instance API URL')
- parser.add_argument('--bugzilla-apiurl', default='apibugzilla.suse.com', metavar='URL', help='bugzilla API URL')
+ parser.add_argument('--bugzilla-apiurl', required=True, metavar='URL', help='bugzilla API URL')
+ parser.add_argument('--bugzilla-product', default='SUSE Linux Enterprise Desktop 12 SP2', metavar='PRODUCT', help='default bugzilla product')
+ parser.add_argument('--bugzilla-component', default='Other', metavar='COMPONENT', help='default bugzilla component')
+ parser.add_argument('--bugzilla-version', default='GM', metavar='VERSION', help='default bugzilla version')
+ parser.add_argument('--bugzilla-cc', metavar='EMAIL', help='bugzilla address added to cc on all bugs created')
parser.add_argument('-d', '--debug', action='store_true', help='print info useful for debugging')
parser.add_argument('-f', '--factory', default='openSUSE:Factory', metavar='PROJECT', help='factory project to use as baseline for comparison')
parser.add_argument('-p', '--project', default='SUSE:SLE-12-SP2:GA', metavar='PROJECT', help='project to check for issues that have are not found in factory')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment