From c0612a2ef6d67a24a74acca0d9ecf6391b0f1bef Mon Sep 17 00:00:00 2001 From: rossella Date: Fri, 25 Mar 2016 17:46:11 +0100 Subject: [PATCH] Add a link for Neutron Gerrit dashboard In Neutron we created a tool to generate a Gerrit dashboard that shows the most important reviews (bug fixes for high/critical bugs and patches that implement approved blueprints) [1]. This patch adds a section to store the links of the project dashboards in reviewday, copies the mentioned script in this repo and use it to generate an updated link to the Gerrit dashboard. [1] https://github.com/openstack/neutron/blob/master/tools/milestone-review-dash.py Depends-on: I42ea25bdf69a1d75db24785db0e86396206fd48d Change-Id: Id2e8590193fbf21a52a767323a77df9be4048b5a --- bin/neutron | 161 ++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + reviewday/report.html | 10 +++ reviewday/util.py | 19 +++++ 4 files changed, 191 insertions(+) create mode 100755 bin/neutron diff --git a/bin/neutron b/bin/neutron new file mode 100755 index 0000000..bc26729 --- /dev/null +++ b/bin/neutron @@ -0,0 +1,161 @@ +#!/usr/bin/env python + +# 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 argparse +import sys + +from launchpadlib.launchpad import Launchpad + + +def is_milestone_valid(project, name): + milestone_names = [] + for s in project.active_milestones: + milestone_names.append(s.name) + if name == s.name: + return True + print("No active milestone found") + print("List of active milestones %s" % milestone_names) + return False + + +def get_current_milestone(project): + series = project.get_timeline()['entries'] + current_milestone = "" + for s in series: + if s['is_development_focus']: + for landmark in s['landmarks']: + #landmark with a date set are past milestones + if not landmark['date']: + if (landmark['name'] < current_milestone or + not current_milestone): + current_milestone = landmark['name'] + return current_milestone + + +def _search_task(project, **kwargs): + bugs = project.searchTasks(**kwargs) + if not bugs: + return + gerrit_query = "(" + for b in bugs: + gerrit_query += ("message:%d OR " % b.bug.id) + gerrit_query = gerrit_query[:-4] + gerrit_query += ")\n\n" + return gerrit_query + + +def get_approved_rfe_query(project): + return _search_task(project, **{'tags': ['rfe-approved']}) + + +def get_critical_bugs_query(project): + return _search_task(project, + **{'status': ["In Progress"], 'importance': ["Critical"]}) + + +def get_high_bugs_query(project): + return _search_task(project, + **{'status': ["In Progress"], 'importance': ["High"]}) + + +def get_specs_query(project, milestone): + query = "(" + for s in project.valid_specifications: + if s.milestone is not None: + if s.milestone.name == milestone: + query += ("topic:bp/%s OR " % s.name) + if query == "(": + # no blueprint was found + return + query = query[:-4] + query += ")\n" + return query + + +def write_section(f, section_name, query): + print(section_name) + if query: + f.write("[section \"") + f.write(section_name) + f.write("\"]\n") + f.write("query = ") + f.write(query) + print(query) + else: + print("No result found\n") + + +def write_queries_for_project(f, project, milestone): + query = get_approved_rfe_query(project) + section_name = "Approved RFE %s" % project.name + write_section(f, section_name, query) + + query = get_critical_bugs_query(project) + section_name = "Critical Bugs %s" % project.name + write_section(f, section_name, query) + + query = get_high_bugs_query(project) + section_name = "High Bugs %s" % project.name + write_section(f, section_name, query) + + query = get_specs_query(project, milestone) + section_name = "Blueprints %s" % project.name + write_section(f, section_name, query) + + +parser = argparse.ArgumentParser( + description='Create dashboard for critical/high bugs, approved rfe and' + ' blueprints. A .dash file will be created in the current' + ' folder that you can serve as input for gerrit-dash-creator.' + ' The output of the script can be used to query Gerrit' + ' directly.') +parser.add_argument('-m', '--milestone', type=str, + help='The release milestone') +parser.add_argument('-o', '--output', type=str, help='Output file') + +cachedir = "~/.launchpadlib/cache/" +launchpad = Launchpad.login_anonymously('just testing', 'production', cachedir, + version="devel") +neutron = launchpad.projects['neutron'] +neutron_client = launchpad.projects['python-neutronclient'] + +args = parser.parse_args() +if args.milestone: + milestone = args.milestone + if not is_milestone_valid(neutron, milestone): + sys.exit() +else: + milestone = get_current_milestone(neutron) +if args.output: + file_name = args.output +else: + file_name = milestone + '.dash' + + +with open(file_name, 'w') as f: + title = "[dashboard]\ntitle = Neutron %s Review Inbox\n" % milestone + f.write(title) + f.write("description = Review Inbox\n") + f.write("foreach = (project:openstack/neutron OR " + "project:openstack/python-neutronclient OR " + "project:openstack/neutron-specs OR " + "project:openstack/neutron-fwaas OR " + "project:openstack/neutron-lbaas OR " + "project:openstack/neutron-vpnaas) status:open NOT owner:self " + "NOT label:Workflow<=-1 " + "NOT label:Code-Review>=-2,self branch:master\n") + f.write("\n") + + print("Querying Launchpad, this might take a while...") + write_queries_for_project(f, neutron, milestone) + write_queries_for_project(f, neutron_client, milestone) diff --git a/requirements.txt b/requirements.txt index 68861c4..8ef49da 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ launchpadlib PyYAML Cheetah simplejson +-e git+https://git.openstack.org/openstack/gerrit-dash-creator#egg=gerrit_dash_creator diff --git a/reviewday/report.html b/reviewday/report.html index d5753fb..256d755 100644 --- a/reviewday/report.html +++ b/reviewday/report.html @@ -24,6 +24,16 @@ +
+

+ Gerrit Dashboard links +

+

+ + Neutron + +

+

ReviewDay diff --git a/reviewday/util.py b/reviewday/util.py index 1d63e37..e4309dd 100644 --- a/reviewday/util.py +++ b/reviewday/util.py @@ -1,8 +1,10 @@ import json import os import html_helper +import subprocess from Cheetah.Template import Template from distutils.dir_util import copy_tree +import gerrit_dash_creator def prep_out_dir(out_dir): @@ -52,12 +54,29 @@ def _create_data_html(out_dir, name_space={}): return data_table_text +def create_projects_dashboard(out_dir): + gerrit_dash_bin = os.path.join(os.path.dirname( + gerrit_dash_creator.__file__), '../gerrit-dash-creator') + template_dir = os.path.join(os.path.dirname( + gerrit_dash_creator.__file__), '../templates') + dashboard_file = '%s/milestone.dash' % out_dir + os.system('bin/neutron -o %s' % dashboard_file) + p = subprocess.Popen([gerrit_dash_bin, + dashboard_file, + '--template-directory', '%s' % template_dir], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + neutron_dash, err = p.communicate() + return {'neutron_dash': neutron_dash} + + def create_report(out_dir, name_space={}): # create html partial with just the unstyled data data_table_text = _create_data_html(out_dir, name_space) # create the full report report_name_space = {'data': data_table_text, 'helper': html_helper} + report_name_space.update(create_projects_dashboard(out_dir)) filename = os.path.join(os.path.dirname(__file__), 'report.html') report_text = open(filename).read() t = Template(report_text, searchList=[report_name_space])