From 32a6775fd5cf8fcbaa3be278969f66e2814a3016 Mon Sep 17 00:00:00 2001 From: Sergey Lukjanov Date: Tue, 10 Sep 2013 00:41:20 +0400 Subject: [PATCH] Improve git2lp and is_direct_release behaviour * git2lp and is_direct_release are now functions extracted to the projects.py; * git2lp and is_direct_release mappings are now loaded from projects.yaml; * temporarily old mappings are used if no info found in projects.yaml. Fixes: bug #1202820 Fixes: bug #1202800 Fixes: bug #1082792 Change-Id: I487761d110cf781acea26b997486ea24a7deb25e --- jeepyb/cmd/update_blueprint.py | 22 ++-- jeepyb/cmd/update_bug.py | 120 +++------------------ jeepyb/projects.py | 186 +++++++++++++++++++++++++++++++++ jeepyb/utils.py | 47 +++++++++ 4 files changed, 256 insertions(+), 119 deletions(-) create mode 100644 jeepyb/projects.py create mode 100644 jeepyb/utils.py diff --git a/jeepyb/cmd/update_blueprint.py b/jeepyb/cmd/update_blueprint.py index 738ba13..b0865aa 100644 --- a/jeepyb/cmd/update_blueprint.py +++ b/jeepyb/cmd/update_blueprint.py @@ -28,6 +28,9 @@ from launchpadlib import launchpad from launchpadlib import uris import MySQLdb +from jeepyb import projects as p + + BASE_DIR = '/home/gerrit2/review_site' GERRIT_CACHE_DIR = os.path.expanduser( os.environ.get('GERRIT_CACHE_DIR', @@ -63,22 +66,11 @@ DB_PASS = SECURE_CONFIG.get("database", "password") DB_DB = GERRIT_CONFIG.get("database", "database") -def short_project(full_project_name): - """Return the project part of the git repository name.""" - return full_project_name.split('/')[-1] - - -def git2lp(full_project_name): - """Convert Git repo name to Launchpad project.""" - project_map = { - 'stackforge/puppet-openstack_dev_env': 'puppet-openstack', - 'stackforge/puppet-quantum': 'puppet-neutron', - } - return project_map.get(full_project_name, short_project(full_project_name)) - - def update_spec(launchpad, project, name, subject, link, topic=None): - project = git2lp(project) + if p.is_no_launchpad_blueprints(project): + return + + project = p.git2lp(project) spec = launchpad.projects[project].getSpecification(name=name) if not spec: return diff --git a/jeepyb/cmd/update_bug.py b/jeepyb/cmd/update_bug.py index 3a72546..fdf2b5a 100644 --- a/jeepyb/cmd/update_bug.py +++ b/jeepyb/cmd/update_bug.py @@ -26,6 +26,9 @@ from launchpadlib import launchpad from launchpadlib import uris import jeepyb.gerritdb +from jeepyb import projects as p +from jeepyb import utils as u + BASE_DIR = '/home/gerrit2/review_site' GERRIT_CACHE_DIR = os.path.expanduser( @@ -46,7 +49,8 @@ def fix_or_related_fix(related): def add_change_proposed_message(bugtask, change_url, project, branch, related=False): fix = fix_or_related_fix(related) - subject = '%s proposed to %s (%s)' % (fix, short_project(project), branch) + subject = ('%s proposed to %s (%s)' + % (fix, u.short_project_name(project), branch)) body = '%s proposed to branch: %s\nReview: %s' % (fix, branch, change_url) bugtask.bug.newMessage(subject=subject, content=body) @@ -54,7 +58,7 @@ def add_change_proposed_message(bugtask, change_url, project, branch, def add_change_merged_message(bugtask, change_url, project, commit, submitter, branch, git_log, related=False): subject = '%s merged to %s (%s)' % (fix_or_related_fix(related), - short_project(project), branch) + u.short_project_name(project), branch) git_url = 'http://github.com/%s/commit/%s' % (project, commit) body = '''Reviewed: %s Committed: %s @@ -140,106 +144,6 @@ def tag_in_branchname(bugtask, branch): lp_bug.lp_save() -def short_project(full_project_name): - """Return the project part of the git repository name.""" - return full_project_name.split('/')[-1] - - -def git2lp(full_project_name): - """Convert Git repo name to Launchpad project.""" - project_map = { - 'openstack/api-site': 'openstack-api-site', - 'openstack/identity-api': 'openstack-api-site', - 'openstack/object-api': 'openstack-api-site', - 'openstack/volume-api': 'openstack-api-site', - 'openstack/netconn-api': 'openstack-api-site', - 'openstack/compute-api': 'openstack-api-site', - 'openstack/image-api': 'openstack-api-site', - 'openstack/database-api': 'openstack-api-site', - 'openstack/quantum': 'neutron', - 'openstack/python-quantumclient': 'python-neutronclient', - 'openstack/oslo-incubator': 'oslo', - 'openstack/tripleo-incubator': 'tripleo', - 'openstack-infra/askbot-theme': 'openstack-ci', - 'openstack-infra/config': 'openstack-ci', - 'openstack-infra/devstack-gate': 'openstack-ci', - 'openstack-infra/gear': 'openstack-ci', - 'openstack-infra/gerrit': 'openstack-ci', - 'openstack-infra/gerritbot': 'openstack-ci', - 'openstack-infra/gerritlib': 'openstack-ci', - 'openstack-infra/gitdm': 'openstack-ci', - 'openstack-infra/jeepyb': 'openstack-ci', - 'openstack-infra/jenkins-job-builder': 'openstack-ci', - 'openstack-infra/lodgeit': 'openstack-ci', - 'openstack-infra/meetbot': 'openstack-ci', - 'openstack-infra/nose-html-output': 'openstack-ci', - 'openstack-infra/publications': 'openstack-ci', - 'openstack-infra/puppet-apparmor': 'openstack-ci', - 'openstack-infra/puppet-dashboard': 'openstack-ci', - 'openstack-infra/puppet-vcsrepo': 'openstack-ci', - 'openstack-infra/reviewday': 'openstack-ci', - 'openstack-infra/statusbot': 'openstack-ci', - 'openstack-infra/zmq-event-publisher': 'openstack-ci', - 'stackforge/cookbook-openstack-block-storage': 'openstack-chef', - 'stackforge/cookbook-openstack-common': 'openstack-chef', - 'stackforge/cookbook-openstack-compute': 'openstack-chef', - 'stackforge/cookbook-openstack-dashboard': 'openstack-chef', - 'stackforge/cookbook-openstack-identity': 'openstack-chef', - 'stackforge/cookbook-openstack-image': 'openstack-chef', - 'stackforge/cookbook-openstack-metering': 'openstack-chef', - 'stackforge/cookbook-openstack-network': 'openstack-chef', - 'stackforge/cookbook-openstack-object-storage': 'openstack-chef', - 'stackforge/cookbook-openstack-ops-database': 'openstack-chef', - 'stackforge/cookbook-openstack-ops-messaging': 'openstack-chef', - 'stackforge/cookbook-openstack-orchestration': 'openstack-chef', - 'stackforge/openstack-chef-repo': 'openstack-chef', - 'stackforge/puppet-openstack_dev_env': 'puppet-openstack', - 'stackforge/puppet-quantum': 'puppet-neutron', - 'stackforge/tripleo-heat-templates': 'tripleo', - 'stackforge/tripleo-image-elements': 'tripleo', - } - return project_map.get(full_project_name, short_project(full_project_name)) - - -def is_direct_release(full_project_name): - """Test against a list of projects who directly release changes.""" - return full_project_name in [ - 'openstack/openstack-manuals', - 'openstack/api-site', - 'openstack/tripleo-incubator', - 'openstack/tempest', - 'openstack-dev/devstack', - 'openstack-infra/askbot-theme', - 'openstack-infra/config', - 'openstack-infra/devstack-gate', - 'openstack-infra/gerrit', - 'openstack-infra/gerritbot', - 'openstack-infra/gerritlib', - 'openstack-infra/gitdm', - 'openstack-infra/lodgeit', - 'openstack-infra/meetbot', - 'openstack-infra/nose-html-output', - 'openstack-infra/publications', - 'openstack-infra/reviewday', - 'openstack-infra/statusbot', - 'stackforge/cookbook-openstack-block-storage', - 'stackforge/cookbook-openstack-common', - 'stackforge/cookbook-openstack-compute', - 'stackforge/cookbook-openstack-dashboard', - 'stackforge/cookbook-openstack-identity', - 'stackforge/cookbook-openstack-image', - 'stackforge/cookbook-openstack-metering', - 'stackforge/cookbook-openstack-network', - 'stackforge/cookbook-openstack-object-storage', - 'stackforge/cookbook-openstack-ops-database', - 'stackforge/cookbook-openstack-ops-messaging', - 'stackforge/cookbook-openstack-orchestration', - 'stackforge/openstack-chef-repo', - 'stackforge/tripleo-heat-templates', - 'stackforge/tripleo-image-elements', - ] - - class Task: def __init__(self, lp_task, prefix): '''Prefixes associated with bug references will allow for certain @@ -291,7 +195,7 @@ def process_bugtask(launchpad, task, git_log, args): if args.hook == "change-merged": if args.branch == 'master': - if (is_direct_release(args.project) and + if (p.is_direct_release(args.project) and task.needs_change('set_fix_released')): set_fix_released(bugtask) else: @@ -362,6 +266,13 @@ def find_bugs(launchpad, git_log, args): :returns: an iterable containing Task objects. ''' + project = args.project + + if p.is_no_launchpad_bugs(project): + return [] + + project = p.git2lp(project) + part1 = r'^[\t ]*(?P[-\w]+)?[\s:]*' part2 = r'(?:\b(?:bug|lp)\b[\s#:]*)+' part3 = r'(?P\d+)\s*?$' @@ -377,7 +288,7 @@ def find_bugs(launchpad, git_log, args): try: lp_bug = launchpad.bugs[bug_num] for lp_task in lp_bug.bug_tasks: - if lp_task.bug_target_name == git2lp(args.project): + if lp_task.bug_target_name == project: bugtasks[bug_num] = Task(lp_task, prefix) break except KeyError: @@ -424,5 +335,6 @@ def main(): for task in find_bugs(lpconn, git_log, args): process_bugtask(lpconn, task, git_log, args) + if __name__ == "__main__": main() diff --git a/jeepyb/projects.py b/jeepyb/projects.py new file mode 100644 index 0000000..147c5f9 --- /dev/null +++ b/jeepyb/projects.py @@ -0,0 +1,186 @@ +# Copyright (c) 2013 Mirantis. +# +# 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. + +""" +Expected review.projects.yaml format: + +- project: some/project + launchpad: awesomeproject + description: Best project ever. + options: + - direct-release + - no-launchpad-bugs + - no-launchpad-blueprints +""" + +import jeepyb.utils as u + + +registry = u.ProjectsYamlRegistry('/home/gerrit2/projects.yaml', + 'PROJECTS_YAML') + + +def git2lp(project_full_name): + try: + return registry[project_full_name]['launchpad'] + except KeyError: + return _hardcoded_git2lp(project_full_name) + # return u.short_project_name(project_full_name) + + +def _is_no_launchpad(project_full_name, obj_type): + try: + return ('no-launchpad-' + obj_type + in registry[project_full_name]['options']) + except KeyError: + return False + + +def is_no_launchpad_bugs(project_full_name): + return _is_no_launchpad(project_full_name, 'bugs') + + +def is_no_launchpad_blueprints(project_full_name): + return _is_no_launchpad(project_full_name, 'blueprints') + + +def is_direct_release(project_full_name): + try: + direct = 'direct-release' in registry[project_full_name]['options'] + # return ... + except KeyError: + direct = False + # return False + + return direct or _hardcoded_is_direct_release(project_full_name) + + +# The following functions should be deleted when projects.yaml will be updated + +def _hardcoded_is_direct_release(project_full_name): + """Test against a list of projects who directly release changes. + + This function should be removed when projects.yaml will be updated. + To specify direct_release you just need add option 'direct_relese' to your + project declaration in projects.yaml + + Example: + - project: some/project + options: + - direct-release + description: Best project ever. + """ + return project_full_name in [ + 'openstack/openstack-manuals', + 'openstack/api-site', + 'openstack/tripleo-incubator', + 'openstack/tempest', + 'openstack-dev/devstack', + 'openstack-infra/askbot-theme', + 'openstack-infra/config', + 'openstack-infra/devstack-gate', + 'openstack-infra/gerrit', + 'openstack-infra/gerritbot', + 'openstack-infra/gerritlib', + 'openstack-infra/gitdm', + 'openstack-infra/lodgeit', + 'openstack-infra/meetbot', + 'openstack-infra/nose-html-output', + 'openstack-infra/publications', + 'openstack-infra/reviewday', + 'openstack-infra/statusbot', + 'stackforge/cookbook-openstack-block-storage', + 'stackforge/cookbook-openstack-common', + 'stackforge/cookbook-openstack-compute', + 'stackforge/cookbook-openstack-dashboard', + 'stackforge/cookbook-openstack-identity', + 'stackforge/cookbook-openstack-image', + 'stackforge/cookbook-openstack-metering', + 'stackforge/cookbook-openstack-network', + 'stackforge/cookbook-openstack-object-storage', + 'stackforge/cookbook-openstack-ops-database', + 'stackforge/cookbook-openstack-ops-messaging', + 'stackforge/cookbook-openstack-orchestration', + 'stackforge/openstack-chef-repo', + 'stackforge/tripleo-heat-templates', + 'stackforge/tripleo-image-elements', + ] + + +def _hardcoded_git2lp(project_full_name): + """Convert Git repo name to Launchpad project. + + This function should be removed when projects.yaml will be updated. + To specify launchpad project name you just need add parameter 'lp' to your + project declaration in projects.yaml + + Example: + - project: some/project + launchpad: awesomeproject + description: Best project ever. + """ + + project_map = { + 'openstack/api-site': 'openstack-api-site', + 'openstack/identity-api': 'openstack-api-site', + 'openstack/object-api': 'openstack-api-site', + 'openstack/volume-api': 'openstack-api-site', + 'openstack/netconn-api': 'openstack-api-site', + 'openstack/compute-api': 'openstack-api-site', + 'openstack/image-api': 'openstack-api-site', + 'openstack/database-api': 'openstack-api-site', + 'openstack/quantum': 'neutron', + 'openstack/python-quantumclient': 'python-neutronclient', + 'openstack/oslo-incubator': 'oslo', + 'openstack/tripleo-incubator': 'tripleo', + 'openstack-infra/askbot-theme': 'openstack-ci', + 'openstack-infra/config': 'openstack-ci', + 'openstack-infra/devstack-gate': 'openstack-ci', + 'openstack-infra/gear': 'openstack-ci', + 'openstack-infra/gerrit': 'openstack-ci', + 'openstack-infra/gerritbot': 'openstack-ci', + 'openstack-infra/gerritlib': 'openstack-ci', + 'openstack-infra/gitdm': 'openstack-ci', + 'openstack-infra/jeepyb': 'openstack-ci', + 'openstack-infra/jenkins-job-builder': 'openstack-ci', + 'openstack-infra/lodgeit': 'openstack-ci', + 'openstack-infra/meetbot': 'openstack-ci', + 'openstack-infra/nose-html-output': 'openstack-ci', + 'openstack-infra/publications': 'openstack-ci', + 'openstack-infra/puppet-apparmor': 'openstack-ci', + 'openstack-infra/puppet-dashboard': 'openstack-ci', + 'openstack-infra/puppet-vcsrepo': 'openstack-ci', + 'openstack-infra/reviewday': 'openstack-ci', + 'openstack-infra/statusbot': 'openstack-ci', + 'openstack-infra/zmq-event-publisher': 'openstack-ci', + 'stackforge/cookbook-openstack-block-storage': 'openstack-chef', + 'stackforge/cookbook-openstack-common': 'openstack-chef', + 'stackforge/cookbook-openstack-compute': 'openstack-chef', + 'stackforge/cookbook-openstack-dashboard': 'openstack-chef', + 'stackforge/cookbook-openstack-identity': 'openstack-chef', + 'stackforge/cookbook-openstack-image': 'openstack-chef', + 'stackforge/cookbook-openstack-metering': 'openstack-chef', + 'stackforge/cookbook-openstack-network': 'openstack-chef', + 'stackforge/cookbook-openstack-object-storage': 'openstack-chef', + 'stackforge/cookbook-openstack-ops-database': 'openstack-chef', + 'stackforge/cookbook-openstack-ops-messaging': 'openstack-chef', + 'stackforge/cookbook-openstack-orchestration': 'openstack-chef', + 'stackforge/openstack-chef-repo': 'openstack-chef', + 'stackforge/puppet-openstack_dev_env': 'puppet-openstack', + 'stackforge/puppet-quantum': 'puppet-neutron', + 'stackforge/tripleo-heat-templates': 'tripleo', + 'stackforge/tripleo-image-elements': 'tripleo', + } + return project_map.get(project_full_name, + u.short_project_name(project_full_name)) diff --git a/jeepyb/utils.py b/jeepyb/utils.py new file mode 100644 index 0000000..5ff3830 --- /dev/null +++ b/jeepyb/utils.py @@ -0,0 +1,47 @@ +# Copyright (c) 2013 Mirantis. +# +# 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. + +import os +import yaml + + +def short_project_name(full_project_name): + """Return the project part of the git repository name.""" + return full_project_name.split('/')[-1] + + +class ProjectsYamlRegistry(object): + """review.projects.yaml style config file parser. + + It could be used as dict 'project name' -> 'project properties'. + """ + + def __init__(self, file_path, env_name=None): + self.file_path = file_path + self.env_name = env_name + + self._parse_file() + + def _parse_file(self): + file_path = os.environ.get(self.env_name, self.file_path) + configs_list = [config for config in yaml.load_all(open(file_path))][1] + + configs = {} + for section in configs_list: + configs[section['project']] = section + + self.configs = configs + + def __getitem__(self, item): + return self.configs[item]