From 59cf27b91f747cf3fbceeb345e0b4a7ce9d5ffba Mon Sep 17 00:00:00 2001 From: Bernard Cafarelli Date: Wed, 17 Jan 2018 15:47:58 +0100 Subject: [PATCH] Add StoryBoard filter and tag tools Based on current Launchpad scripts, these scripts allow to: * sb-tag.py: add a tag to stories * sb-filter-stories-by-priority.py: filter out stories with specific priority * sb-filter-stories-by-tag.py: filter out stories with specific tag Both filter scripts can also optionally filter out stories not marked as bugs Add relevant sections README Change-Id: Ifa73a5747afaf02d606e0da5ba12cc361e77c822 --- README.rst | 51 ++++++++++++++++++++ sb-filter-stories-by-priority.py | 81 ++++++++++++++++++++++++++++++++ sb-filter-stories-by-tag.py | 63 +++++++++++++++++++++++++ sb-tag.py | 61 ++++++++++++++++++++++++ 4 files changed, 256 insertions(+) create mode 100755 sb-filter-stories-by-priority.py create mode 100755 sb-filter-stories-by-tag.py create mode 100755 sb-tag.py diff --git a/README.rst b/README.rst index c94dfa4..792bbe6 100644 --- a/README.rst +++ b/README.rst @@ -874,6 +874,57 @@ Example:: This command will add the 'foo-tag' tag to all bugs fixed since 8.0.0. + +sb-filter-stories-by-priority.py +-------------------------------- + +Reads the list of StoryBoard story numbers on stdin, filters out stories not +marked as bugs or those of priority specified. + +Example:: + + ./bugs-fixed-since.py [...] -sb --start=1.0.0 | \ + ./sb-filter-stories-by-priority.py octavia + +List stories that are fixed in master since 1.0.0. + +Example:: + + ./bugs-fixed-since.py [...] -sb --start=1.0.0 | \ + ./sb-filter-stories-by-priority.py octavia -b --priority low | \ + ./sb-filter-stories-by-priority.py octavia -b --priority medium + +List bugs fixed in master since 1.0.0 that are not low or medium priority (i.e. +only high priority bugs). + + +sb-filter-stories-by-tag.py +--------------------------- + +Reads the list of StoryBoard story numbers on stdin, filters out stories not +marked as bugs or those with a specified tag. + +Example:: + + ./bugs-fixed-since.py [...] -sb --start=1.0.0 | \ + ./sb-filter-stories-by-tag.py octavia --tag in-stable-pike + +List stories fixed in master since 1.0.0 that do not have relevant fixes merged +in stable/pike. + + +sb-tag.py +--------- + +Appends a tag to stories specified on stdin. + +Example:: + + ./bugs-fixed-since.py [...] -sb --start=1.0.0 | \ + ./sb-tag.py foo-tag + +This command will add the 'foo-tag' tag to all stories fixed since 1.0.0. + End of Life =========== diff --git a/sb-filter-stories-by-priority.py b/sb-filter-stories-by-priority.py new file mode 100755 index 0000000..46d7306 --- /dev/null +++ b/sb-filter-stories-by-priority.py @@ -0,0 +1,81 @@ +#!/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. + +""" +This StoryBoard tool is used to filter out stories of specified priority. +""" + +import argparse +import sys + +from storyboardclient.v1 import client + +STORY_PREFIX = "storyboard:" +VALID_PRIORITIES = ('low', 'medium', 'high') + + +def _parse_args(): + parser = argparse.ArgumentParser( + description='Filter out stories of specified priority.') + parser.add_argument( + 'project', help='Project name') + parser.add_argument( + '--bugs-only', '-b', + action='store_true', + default=False, + help='List only stories marked as bugs') + parser.add_argument( + '--priority', + nargs='?', choices=VALID_PRIORITIES, + help='Story priority to filter (default: none)') + return parser.parse_args() + + +def _get_project_id(sb, project_name): + projects = sb.projects.get_all(name=project_name) + for project in projects: + if (project_name == project.name.split("/")[1]): + return project.id + raise ValueError("%s: no matching project" % project_name) + + +def _filter_stories(sb, project_id, bugs_only, priority, story_ids): + for story_id in story_ids: + # Check if story is a bug + story = sb.stories.get(story_id) + if bugs_only and not story.is_bug: + next + # Check priority and project id on tasks + for task in story.tasks.get_all(): + if task.project_id == project_id and task.priority != priority: + yield STORY_PREFIX + story_id + break + + +def main(): + args = _parse_args() + + sb = client.Client("https://storyboard.openstack.org/api/v1") + + project_id = _get_project_id(sb, args.project) + stories = [line.strip()[len(STORY_PREFIX):] + for line in sys.stdin.readlines() + if line.startswith(STORY_PREFIX)] + for story in _filter_stories(sb, project_id, args.bugs_only, + args.priority, stories): + print(story) + + +if __name__ == '__main__': + main() diff --git a/sb-filter-stories-by-tag.py b/sb-filter-stories-by-tag.py new file mode 100755 index 0000000..6e3f978 --- /dev/null +++ b/sb-filter-stories-by-tag.py @@ -0,0 +1,63 @@ +#!/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. + +""" +This StoryBoard tool is used to filter out stories by tag. +""" + +import argparse +import sys + +from storyboardclient.v1 import client + +STORY_PREFIX = "storyboard:" + + +def _parse_args(): + parser = argparse.ArgumentParser( + description='Filter out stories with specified tag.') + parser.add_argument( + '--bugs-only', '-b', + action='store_true', + default=False, + help='List only stories marked as bugs') + parser.add_argument( + 'tag', nargs='?', + help='Tag to filter') + return parser.parse_args() + + +def _filter_stories(sb, bugs_only, tag, story_ids): + for story_id in story_ids: + story = sb.stories.get(story_id) + if bugs_only and not story.is_bug: + next + if tag not in story.tags: + yield STORY_PREFIX + story_id + + +def main(): + args = _parse_args() + + sb = client.Client("https://storyboard.openstack.org/api/v1") + + stories = [line.strip()[len(STORY_PREFIX):] + for line in sys.stdin.readlines() + if line.startswith(STORY_PREFIX)] + for story in _filter_stories(sb, args.bugs_only, args.tag, stories): + print(story) + + +if __name__ == '__main__': + main() diff --git a/sb-tag.py b/sb-tag.py new file mode 100755 index 0000000..3d4e52d --- /dev/null +++ b/sb-tag.py @@ -0,0 +1,61 @@ +#!/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. + +""" +This StoryBoard tool is used to tag stories. +""" + +import argparse +import sys + +from storyboardclient._apiclient.exceptions import BadRequest +from storyboardclient.v1 import client + +STORY_PREFIX = "storyboard:" + + +def _parse_args(): + parser = argparse.ArgumentParser( + description='Tag stories with a tag.') + parser.add_argument( + '--token', required=True, + help='Authentication token, available from ' + + 'https://storyboard.openstack.org/#!/profile/tokens') + parser.add_argument( + 'tag', help='Tag to use') + return parser.parse_args() + + +def _tag_story(sb, story_id, tag): + try: + sb.stories.get(story_id).tags_manager.update(tag) + except BadRequest: + # Story alread had a tag, ignoring + pass + + +def main(): + args = _parse_args() + + sb = client.Client("https://storyboard.openstack.org/api/v1", args.token) + + stories = [line.strip()[len(STORY_PREFIX):] + for line in sys.stdin.readlines() + if line.startswith(STORY_PREFIX)] + for story in stories: + _tag_story(sb, story, args.tag) + + +if __name__ == '__main__': + main()