Skip to content

Instantly share code, notes, and snippets.

@dstanek
Created February 1, 2017 20: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 dstanek/d0273347b360593116654a37cce9531a to your computer and use it in GitHub Desktop.
Save dstanek/d0273347b360593116654a37cce9531a to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# 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.
"""Generate reports from project releasenotes formatted for the RPC
Upstream Release Analysis spreadsheet.
Usage:
# cd to the project directory
cd /opt/stack/project
# make sure you are on master and are all up-to-date
git co master && git pull
# run me, run me!
./rpc-upstream-analysis.py > output.csv
"""
import collections
import configparser
import csv
import itertools
import operator
import os
import subprocess
import sys
import yaml
GET_RELNO_CMD = ("git diff --summary origin/stable/newton...HEAD "
"releasenotes/notes | awk '{print $4}'")
def iter_release_notes():
"""Generator yielding YAML for each release note file."""
release_notes = subprocess.getoutput(GET_RELNO_CMD).split('\n')
for filename in release_notes:
yield filename, yaml.load(open(filename))
def expand_note_items(notes, project_name):
"""Generatory yielding a NoteItem for each item in the YAML.
This:
feature:
- f1
- f2
upgrade:
- u1
Approximately yields:
- NoteItem(filename, 'feature', 'f1')
- NoteItem(filename, 'feature', 'f2')
- NoteItem(filename, 'upgrade', 'u1')
"""
for filename, note in notes:
for type_, items in note.items():
if isinstance(items, str):
items = [items]
for item in items:
yield NoteItem.from_rst(project_name, filename, type_, item)
def get_project_name():
cp = configparser.ConfigParser()
cp.read('setup.cfg')
return cp['metadata']['name']
class NoteItem:
_LINK_TMPL = ('release note <http://git.openstack.org/cgit/openstack' +
'/%s/tree/releasenotes/notes/%s>')
def __init__(self, project_name, filename, _type, description, link=None):
self.type = _type
self._description = description
filename = os.path.basename(filename)
self._links = [self._LINK_TMPL % (project_name, filename)]
if link:
self._links.append(link)
@property
def feature_name(self):
return '' # TODO: can this be automated?
@property
def description(self):
return '[%s] %s' % (self.type, self._description)
@property
def links(self):
return ', '.join(self._links)
@classmethod
def from_rst(cls, project_name, filename, _type, source):
def parse(source):
try:
pos = source.index(']') + 1
except ValueError:
return None, source
link, description = source[:pos], source[pos:]
link = link.strip('[]`_')
return link, description
link, description = parse(source)
return cls(project_name, filename, _type, description, link)
def main(args):
project_name = get_project_name()
sort_key = operator.attrgetter('type')
notes = iter_release_notes()
note_items = sorted(expand_note_items(notes, project_name), key=sort_key)
grouped_items = itertools.groupby(note_items, key=sort_key)
output = csv.writer(sys.stdout)
for type_, items in grouped_items:
for item in items:
output.writerow([
project_name,
item.feature_name,
item.links,
item.description,
])
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment