scripts/release/util.py (76 lines of code) (raw):

# # 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. # import datetime import urllib import yaml import codecs as _codecs from datetime import datetime from xml.sax.saxutils import escape as escape_html def write_utf8(file, string): with _codecs.open(file, encoding="utf-8", mode="w") as f: f.write(string) return file def get_date_string(): return datetime.today().strftime('%Y-%m-%d') def render_release_notes(project, release): issues = _fetch_issues(project, release) lines = list() bugs = _render_issues(issues, "Bug") new_features = _render_issues(issues, "New Feature") improvements = _render_issues(issues, "Improvement") tests = _render_issues(issues, "Test") tasks = _render_issues(issues, "Task") dependencies = _render_issues(issues, "Dependency upgrade") if bugs is not None: lines.append("\n## Bugs Fixed\n") lines.append(bugs) if new_features is not None: lines.append("\n## New Features\n") lines.append(new_features) if improvements is not None: lines.append("\n## Improvements\n") lines.append(improvements) if tests is not None: lines.append("\n## Tests\n") lines.append(tests) if tasks is not None: lines.append("\n## Tasks\n") lines.append(tasks) if dependencies is not None: lines.append("\n## Dependency Upgrades\n") lines.append(dependencies) return "\n".join(lines) def _fetch_issues(project, release): query = list() query.append("project = '{}'".format(project)) query.append("fixVersion = '{}'".format(release)) query.append("resolution = 'fixed'") query = " and ".join(query) query = "{} order by key asc".format(query) page_size = 100 params = { "jql": query, "fields": "summary,issuetype", "maxResults": page_size, } issues = list() for i in range(100): params["startAt"] = i * page_size url = "https://issues.apache.org/jira/rest/api/2/search?{}".format(urllib.parse.urlencode(params)) filename, headers = urllib.request.urlretrieve(url) with open(filename) as f: data = yaml.load(f, Loader=yaml.Loader) issues.extend(data["issues"]) if len(issues) >= int(data["total"]): break return issues def _render_issues(issues, *types): filtered_issues = [x for x in issues if x["fields"]["issuetype"]["name"] in types] if not filtered_issues: return None lines = list() for issue in filtered_issues: key = escape_html(issue["key"]) url = "https://issues.apache.org/jira/browse/{}".format(key) summary = escape_html(issue["fields"]["summary"]) lines.append("* [{}]({}) - {}".format(key, url, summary)) return "\n".join(lines)