153 lines
5.5 KiB
Python
153 lines
5.5 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# Copyright 2015 Markus Zoeller <mzoeller@de.ibm.com>
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
|
|
# +-----+ 1 1..* +----------+
|
|
# | bug +----------------> bug_task |
|
|
# +--+--+ +-----+----+
|
|
# | |
|
|
# | |
|
|
# | +---------+ |
|
|
# +-------> project <-------+
|
|
# 1..* +---------+ 1
|
|
#
|
|
# One bug has at least 1 bug_task.
|
|
# One bug_task belongs to exactly one bug.
|
|
# One bug can affect multiple projects
|
|
# One bug_task is specific to one project
|
|
|
|
|
|
import argparse
|
|
import logging
|
|
import os
|
|
|
|
import launchpadlib.launchpad
|
|
|
|
# Parameters
|
|
parser = argparse.ArgumentParser(description="Cleanup Launchpad (LP) Bugs")
|
|
parser.add_argument('projectname', help='The project to act on')
|
|
parser.add_argument("--test", action='store_const', const='staging',
|
|
default='production', help='Use LP staging server to test')
|
|
parser.add_argument("--newbugs", action="store_true",
|
|
help="Cleanup inconsistencies in new bugs")
|
|
parser.add_argument('exceptions', type=int, nargs='*', help='Bugs to ignore')
|
|
parser.add_argument('--dryrun', action='store_true',
|
|
help='Do not actually do anything')
|
|
parser.add_argument("-v", "--verbose", action="store_true",
|
|
help="increase output verbosity")
|
|
args = parser.parse_args()
|
|
|
|
|
|
class LaunchpadCleanup(object):
|
|
"""Triggers specific cleanups in Launchpad."""
|
|
|
|
def __init__(self, project_name, server="staging", dryrun=True,
|
|
ignoreable_bug_ids=[]):
|
|
self.project_name = project_name
|
|
self.client = self._create_launchpad_client(server)
|
|
self.dryrun = dryrun
|
|
self.ignoreable_bug_ids = ignoreable_bug_ids
|
|
logger.info("Created launchpad client for server '%s'", server)
|
|
if self.dryrun:
|
|
logger.info("That's a dry run, nothing will happen")
|
|
|
|
def _create_launchpad_client(self, server):
|
|
cachedir = os.path.expanduser("~/.launchpadlib/cache/")
|
|
if not os.path.exists(cachedir):
|
|
os.makedirs(cachedir, 0o0700)
|
|
return launchpadlib.launchpad.Launchpad.login_with('openstack-cleanup', server, cachedir)
|
|
|
|
def cleanup_new_bugs_with_assignee(self):
|
|
"""A new bug with an assignee is in progress."""
|
|
logger.info("Cleanup new bugs with an assignee")
|
|
|
|
message = ("@%s:\n\nSince you are set as assignee, I switch the "
|
|
"status to 'In Progress'.")
|
|
subject = "Cleanup"
|
|
|
|
project = self.client.projects[self.project_name]
|
|
bug_tasks = project.searchTasks(status=['New'],
|
|
omit_duplicates=True)
|
|
switched_bugs = []
|
|
|
|
for t in bug_tasks:
|
|
bug_id = t.bug.id
|
|
if bug_id in self.ignoreable_bug_ids:
|
|
logger.debug("Ignore bug '%s'. ", bug_id)
|
|
continue
|
|
logger.debug("Checking bug '%s'", bug_id)
|
|
assignee = t.assignee
|
|
if assignee is None:
|
|
continue
|
|
t.status = 'In Progress'
|
|
switched_bugs.append(bug_id)
|
|
content = message % assignee.display_name
|
|
if self.dryrun:
|
|
logger.debug("DRYRUN: I would switch bug '%s'", bug_id)
|
|
continue
|
|
logger.debug("Switching status of bug '%s'", bug_id)
|
|
t.lp_save()
|
|
t.bug.newMessage(content=content, subject=subject)
|
|
|
|
logger.info("Switched bugs: '%s'", switched_bugs)
|
|
|
|
def cleanup_incomplete_bugs_without_response(self):
|
|
"""There should be a response of the reporter to incomplete bugs
|
|
|
|
change status to invalid and make a comment
|
|
"""
|
|
raise NotImplementedError("not yet done")
|
|
|
|
def cleanup_in_progress_bugs_without_patches(self):
|
|
"""Not yet implemented
|
|
|
|
If a bug is in progress but does not provide a patch set
|
|
it is not in progress
|
|
|
|
* Remove assignee
|
|
* move back to last state (probably confirmed)
|
|
"""
|
|
raise NotImplementedError("not yet done")
|
|
|
|
|
|
def create_logger():
|
|
logger = logging.getLogger("os.bug.cleanup")
|
|
logger.setLevel(logging.DEBUG)
|
|
formatter = logging.Formatter('%(asctime)s - %(name)s - '
|
|
'%(levelname)s - %(message)s')
|
|
file_handler = logging.FileHandler("os.bug.cleanup.log")
|
|
file_handler.setFormatter(formatter)
|
|
logger.addHandler(file_handler)
|
|
stream_handler = logging.StreamHandler()
|
|
stream_handler.setFormatter(formatter)
|
|
stream_level = logging.DEBUG if args.verbose else logging.INFO
|
|
stream_handler.setLevel(stream_level)
|
|
logger.addHandler(stream_handler)
|
|
return logger
|
|
|
|
if __name__ == '__main__':
|
|
logger = create_logger()
|
|
logger.info("Started for project '%s'", args.projectname)
|
|
|
|
cleanup = LaunchpadCleanup(args.projectname, args.test, args.dryrun)
|
|
logger.info("Found project '%s'", args.projectname)
|
|
|
|
if args.newbugs:
|
|
cleanup.cleanup_new_bugs_with_assignee()
|
|
|
|
logger.info("Finished for project '%s'", args.projectname)
|