From 7f6879bdbaf36d7614c4b52be44e0abd70082659 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-bugs-by-priority.py: only keep stories marked as bugs, and optionally filter out these with specific priority * sb-filter-stories-by-tag.py: filter out stories with specific tag Add relevant sections README Change-Id: Ifa73a5747afaf02d606e0da5ba12cc361e77c822 --- README.rst | 51 ++++++++++++++++++++++ sb-filter-bugs-by-priority.py | 81 +++++++++++++++++++++++++++++++++++ sb-filter-stories-by-tag.py | 57 ++++++++++++++++++++++++ sb-tag.py | 57 ++++++++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100755 sb-filter-bugs-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..fe32458 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-bugs-by-priority.py +----------------------------- + +Reads the list of StoryBoard story numbers on stdin, filters out stories not +marked as bugs and optionally those of priority specified. + +Example:: + + ./bugs-fixed-since.py [...] -sb --start=1.0.0 | \ + ./sb-filter-bugs-by-priority.py octavia + +List bugs that are fixed in master since 1.0.0. + +Example:: + + ./bugs-fixed-since.py [...] -sb --start=1.0.0 | \ + ./sb-filter-bugs-by-priority.py octavia --priority low | \ + ./sb-filter-bugs-by-priority.py octavia --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 and filters out those with +a tag specified. + +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-bugs-by-priority.py b/sb-filter-bugs-by-priority.py new file mode 100755 index 0000000..ab08a5d --- /dev/null +++ b/sb-filter-bugs-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 bugs of specified priority. +""" + +import argparse +import requests +import sys + +SB_URL = "https://storyboard.openstack.org/api/v1/" +STORY_PREFIX = "storyboard:" +VALID_PRIORITIES = ('low', 'medium', 'high') + + +def _parse_args(): + parser = argparse.ArgumentParser( + description='Filter out bugs of specified priority.') + parser.add_argument( + 'project', help='Project name') + parser.add_argument( + '--priority', + nargs='?', choices=VALID_PRIORITIES, + help='Bug priority to filter (default: none)') + return parser.parse_args() + + +def _get_project_id(project_name): + r = requests.get(SB_URL + "projects", + {"name": project_name}) + for project in r.json(): + if (project_name == project["name"].split("/")[1]): + return project["id"] + print("%s: no matching project" % project_name) + sys.exit(1) + + +def _filter_stories(project_id, priority, story_ids): + result = [] + for story_id in story_ids: + # Check if story is a bug + r = requests.get(SB_URL + "stories/%s" + % story_id) + if not r.json()["is_bug"]: + next + # Check priority and project id on tasks + r = requests.get(SB_URL + "stories/%s/tasks" + % story_id) + for task in r.json(): + if (task["project_id"] == project_id and + task["priority"] != priority): + result.append(STORY_PREFIX + story_id) + break + return result + + +def main(): + args = _parse_args() + + project_id = _get_project_id(args.project) + stories = [line.strip()[len(STORY_PREFIX):] + for line in sys.stdin.readlines() + if line.startswith(STORY_PREFIX)] + for story in _filter_stories(project_id, 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..2c8d603 --- /dev/null +++ b/sb-filter-stories-by-tag.py @@ -0,0 +1,57 @@ +#!/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 requests +import sys + +SB_URL = "https://storyboard.openstack.org/api/v1/" +STORY_PREFIX = "storyboard:" + + +def _parse_args(): + parser = argparse.ArgumentParser( + description='Filter out stories with specified tag.') + parser.add_argument( + 'tag', nargs='?', + help='Tag to filter') + return parser.parse_args() + + +def _filter_stories(tag, story_ids): + result = [] + for story_id in story_ids: + r = requests.get(SB_URL + "stories/%s" + % story_id) + if tag not in r.json()["tags"]: + result.append(STORY_PREFIX + story_id) + return result + + +def main(): + args = _parse_args() + + stories = [line.strip()[len(STORY_PREFIX):] + for line in sys.stdin.readlines() + if line.startswith(STORY_PREFIX)] + for story in _filter_stories(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..41de783 --- /dev/null +++ b/sb-tag.py @@ -0,0 +1,57 @@ +#!/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 requests +import sys + +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(token, story_id, tag): + data = {"tags": tag} + headers = {"Authorization": "Bearer " + token} + r = requests.put("https://storyboard.openstack.org/api/v1/tags/%s" % + story_id, data=data, headers=headers) + if r.status_code == requests.codes.unauthorized: + print("Authorization failure, incorrect token?") + + +def main(): + args = _parse_args() + stories = [line.strip()[len(STORY_PREFIX):] + for line in sys.stdin.readlines() + if line.startswith(STORY_PREFIX)] + for story in stories: + _tag_story(args.token, story, args.tag) + + +if __name__ == '__main__': + main()