From e6ef82bfa8cf26dfe3820961715a3ece900ca143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Rohde=20D=C3=B8ssing?= Date: Mon, 31 Jul 2017 21:48:22 +0200 Subject: [PATCH] STORM-2665: Adapt Kafka's release note generation script for Storm --- dev-tools/jira-github-join.py | 2 +- dev-tools/{jira => jira_github}/__init__.py | 0 dev-tools/release_notes.py | 118 ++++++++++++++++++++ dev-tools/report/report.py | 2 +- 4 files changed, 120 insertions(+), 2 deletions(-) rename dev-tools/{jira => jira_github}/__init__.py (100%) mode change 100755 => 100644 create mode 100644 dev-tools/release_notes.py diff --git a/dev-tools/jira-github-join.py b/dev-tools/jira-github-join.py index fe0daf3d810..1931f19ee6f 100755 --- a/dev-tools/jira-github-join.py +++ b/dev-tools/jira-github-join.py @@ -15,7 +15,7 @@ from optparse import OptionParser from datetime import datetime from github import GitHub -from jira import JiraRepo +from jira_github import JiraRepo from report.report_builder import CompleteReportBuilder diff --git a/dev-tools/jira/__init__.py b/dev-tools/jira_github/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from dev-tools/jira/__init__.py rename to dev-tools/jira_github/__init__.py diff --git a/dev-tools/release_notes.py b/dev-tools/release_notes.py new file mode 100644 index 00000000000..c1e053a2d9b --- /dev/null +++ b/dev-tools/release_notes.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +"""Usage: release_notes.py > RELEASE_NOTES.html + +Depends on https://pypi.python.org/pypi/jira/, please use pip to install this module. + +Generates release notes for a Storm release by generating an HTML doc containing some introductory information about the + release with links to the Storm docs followed by a list of issues resolved in the release. The script will fail if it finds + any unresolved issues still marked with the target release. You should run this script after either resolving all issues or + moving outstanding issues to a later release. + +""" + +from jira import JIRA +import itertools, sys + +if len(sys.argv) < 2: + print >>sys.stderr, "Usage: release_notes.py " + sys.exit(1) + +version = sys.argv[1] + +JIRA_BASE_URL = 'https://issues.apache.org/jira' +MAX_RESULTS = 100 # This is constrained for cloud instances so we need to fix this value + +def get_issues(jira, query, **kwargs): + """ + Get all issues matching the JQL query from the JIRA instance. This handles expanding paginated results for you. Any additional keyword arguments are forwarded to the JIRA.search_issues call. + """ + results = [] + startAt = 0 + new_results = None + while new_results == None or len(new_results) == MAX_RESULTS: + new_results = jira.search_issues(query, startAt=startAt, maxResults=MAX_RESULTS, **kwargs) + results += new_results + startAt += len(new_results) + return results + +def issue_link(issue): + return "%s/browse/%s" % (JIRA_BASE_URL, issue.key) + + +if __name__ == "__main__": + apache = JIRA(JIRA_BASE_URL) + issues = get_issues(apache, 'project=STORM and fixVersion=%s' % version) + if not issues: + print >>sys.stderr, "Didn't find any issues for the target fix version" + sys.exit(1) + + # Some resolutions, including a lack of resolution, indicate that the bug hasn't actually been addressed and we shouldn't even be able to create a release until they are fixed + UNRESOLVED_RESOLUTIONS = [None, + "Unresolved", + "Duplicate", + "Invalid", + "Not A Problem", + "Not A Bug", + "Won't Fix", + "Incomplete", + "Cannot Reproduce", + "Later", + "Works for Me", + "Workaround", + "Information Provided" + ] + unresolved_issues = [issue for issue in issues if issue.fields.resolution in UNRESOLVED_RESOLUTIONS or issue.fields.resolution.name in UNRESOLVED_RESOLUTIONS] + if unresolved_issues: + print >>sys.stderr, "The release is not completed since unresolved issues or improperly resolved issues were found still tagged with this release as the fix version:" + for issue in unresolved_issues: + print >>sys.stderr, "Unresolved issue: %15s %20s %s" % (issue.key, issue.fields.resolution, issue_link(issue)) + print >>sys.stderr + print >>sys.stderr, "Note that for some resolutions, you should simply remove the fix version as they have not been truly fixed in this release." + sys.exit(1) + + # Get list of (issue type, [issues]) sorted by the issue ID type, with each subset of issues sorted by their key so they + # are in increasing order of bug #. To get a nice ordering of the issue types we customize the key used to sort by issue + # type a bit to ensure features and improvements end up first. + def issue_type_key(issue): + if issue.fields.issuetype.name == 'New Feature': + return -2 + if issue.fields.issuetype.name == 'Improvement': + return -1 + return issue.fields.issuetype.id + by_group = [(k,sorted(g, key=lambda issue: issue.id)) for k,g in itertools.groupby(sorted(issues, key=issue_type_key), lambda issue: issue.fields.issuetype.name)] + + print "" + print "" + print "" + print "" + print "Storm %(version)s Release Notes" % { 'version': version } + print "" + print "" + print "

Release Notes for Storm %s

" % version + print """

JIRA issues addressed in the %(version)s release of Storm. Documentation for this + release is available at the Apache Storm + project site.

""" % { 'version': version } + for itype, issues in by_group: + print "

%s

" % itype + print "
    " + for issue in issues: + print '
  • [%(key)s] - %(summary)s
  • ' % {'key': issue.key, 'link': issue_link(issue), 'summary': issue.fields.summary} + print "
" + print "" + print "" diff --git a/dev-tools/report/report.py b/dev-tools/report/report.py index 477a4989bfe..d2df077e1ca 100644 --- a/dev-tools/report/report.py +++ b/dev-tools/report/report.py @@ -14,7 +14,7 @@ from datetime import datetime from github import mstr -from jira import Jira +from jira_github import Jira from formatter import Formatter, encode