This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/storm.git
The following commit(s) were added to refs/heads/master by this push:
new 4549e4f6e Update Release Note Generation and Docs (#7936)
4549e4f6e is described below
commit 4549e4f6ed7eb23054531358ff1929581a22408e
Author: Richard Zowalla <[email protected]>
AuthorDate: Sun Jan 26 09:53:29 2025 +0100
Update Release Note Generation and Docs (#7936)
* Update Release Note Generation to work with GitHub Issues
* Update Release Note Generation to work with GitHub Issues
---
README.markdown | 4 +-
RELEASING.md | 34 +++--
dev-tools/jira-github-join.py | 50 -------
dev-tools/jira_github/__init__.py | 296 --------------------------------------
dev-tools/release_notes.py | 162 ++++++++++++---------
doap_Storm.rdf | 2 +-
pom.xml | 4 +-
7 files changed, 121 insertions(+), 431 deletions(-)
diff --git a/README.markdown b/README.markdown
index 24afdad82..d455e0ef0 100644
--- a/README.markdown
+++ b/README.markdown
@@ -31,14 +31,14 @@ You can subscribe to this list by sending an email to
[[email protected]
You can also [browse the archives of the storm-dev mailing
list](https://mail-archives.apache.org/mod_mbox/storm-dev/).
-Storm developers who would want to track the JIRA issues should subscribe to
[[email protected]](mailto:[email protected]).
+Storm developers who would want to track issues should subscribe to
[[email protected]](mailto:[email protected]).
You can subscribe to this list by sending an email to
[[email protected]](mailto:[email protected]).
Likewise, you can cancel a subscription by sending an email to
[[email protected]](mailto:[email protected]).
You can view the archives of the mailing list
[here](https://mail-archives.apache.org/mod_mbox/storm-issues/).
### Issue tracker
-In case you want to raise a bug/feature or propose an idea, please use [Apache
Jira](https://issues.apache.org/jira/projects/STORM).
+In case you want to raise a bug/feature or propose an idea, please use [GitHub
Issues](https://github.com/apache/storm/issues).
If you do not have an account, you need to create one.
### Which list should I send/subscribe to?
diff --git a/RELEASING.md b/RELEASING.md
index 1c07c3015..dd55d85fc 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -51,7 +51,7 @@ Apache Storm follows the basic idea of [Semantic
Versioning](https://semver.org/
If you are setting up a new MINOR version release, create a new branch based
on `master` branch, e.g. `2.6.x-branch`. Then on master branch, set the version
to a higher MINOR version (with SNAPSHOT), e.g. `mvn versions:set
-DnewVersion=2.3.0-SNAPSHOT -P dist,rat,externals,examples`.
-In this way, you create a new release line and then you can create PATCH
version releases from it, e.g. `2.6.0`.
+In this way, you create a new release line and then you can create PATCH
version releases from it, e.g. `2.8.1`.
## Setting up a vote
@@ -60,26 +60,26 @@ In this way, you create a new release line and then you can
create PATCH version
2. Run `mvn release:prepare -P dist,rat,externals,examples` followed `mvn
release:perform -P dist,rat,externals,examples`.
This will create all the artifacts that will eventually be available in maven
central. This step may seem simple,
but a lot can go wrong (mainly flaky tests). Note that this will create and
push two commits with the commit message
-starting with "[maven-release-plugin]" and it will also create and publish a
git tag, e.g. `v2.6.0`. Note: the full build can take up to 30 minutes to
complete.
+starting with "[maven-release-plugin]" and it will also create and publish a
git tag, e.g. `v2.8.1`. Note: the full build can take up to 30 minutes to
complete.
3. Once you get a successful maven release, a “staging repository” will be
created at http://repository.apache.org
in the “open” state, meaning it is still writable. You will need to close it,
making it read-only. You can find more
information on this step
[here](https://infra.apache.org/publishing-maven-artifacts.html).
-4. Checkout to the git tag that was published by Step 1 above, e.g. `git
checkout tags/v2.6.0 -b v2.6.0`.
+4. Checkout to the git tag that was published by Step 1 above, e.g. `git
checkout tags/v2.8.1 -b v2.8.1`.
Then build it with `mvn clean install -DskipTests`. Run `mvn package` for
`storm-dist/binary` and `storm-dist/source`
to create the actual distributions.
5. Generate checksums for the *.tar.gz and *.zip distribution files, e.g.
```bash
pushd storm-dist/source/target
-sha512sum apache-storm-2.6.0-src.zip > apache-storm-2.6.0-src.zip.sha512
-sha512sum apache-storm-2.6.0-src.tar.gz > apache-storm-2.6.0-src.tar.gz.sha512
+sha512sum apache-storm-2.8.1-src.zip > apache-storm-2.8.1-src.zip.sha512
+sha512sum apache-storm-2.8.1-src.tar.gz > apache-storm-2.8.1-src.tar.gz.sha512
popd
pushd storm-dist/binary/final-package/target
-sha512sum apache-storm-2.6.0.zip > apache-storm-2.6.0.zip.sha512
-sha512sum apache-storm-2.6.0.tar.gz > apache-storm-2.6.0.tar.gz.sha512
+sha512sum apache-storm-2.8.1.zip > apache-storm-2.8.1.zip.sha512
+sha512sum apache-storm-2.8.1.tar.gz > apache-storm-2.8.1.tar.gz.sha512
popd
```
@@ -87,11 +87,23 @@ popd
7. Run `dev-tools/release_notes.py` for the release version, piping the output
to a RELEASE_NOTES.html file. Move that file to the svn release directory, sign
it, and generate checksums, e.g.
```bash
-python3 dev-tools/release_notes.py 2.6.0 > RELEASE_NOTES.html
+export GITHUB_TOKEN=MY_PERSONAL_ACCESS_TOKEN_FOR_GI
+python3 dev-tools/release_notes.py <id-of-the-github-milestone> >
RELEASE_NOTES.html
gpg --armor --output RELEASE_NOTES.html.asc --detach-sig RELEASE_NOTES.html
sha512sum RELEASE_NOTES.html > RELEASE_NOTES.html.sha512
```
+To create a personal access token:
+
+- Go to your GitHub account settings.
+- Navigate to **Developer Settings** > **Personal Access Tokens** > **Tokens
(classic)**.
+- Generate a token with the `public_repo` scope.
+
+To obtain the ID of a GitHub milestone:
+- Visit the [milestone overview](https://github.com/apache/storm/milestones).
+- Click on the milestone you want to create release notes for.
+- Look at the URL in your browser. It will look like this:
`https://github.com/apache/storm/milestone/40`, where the last number is the
milestone ID.
+
8. Move the release files from steps 4,5 and 7 to the svn directory from Step
6. Add and commit the files.
This makes them available in the Apache staging repo.
@@ -187,7 +199,9 @@ the site as described in the storm-site README to publish
the site.
8. Delete any outdated releases from the storm-site releases directory, and
republish the site.
-9. Tweet, promote, celebrate. ;) Annoucement email can be sent to
[email protected] using the following template:
+10. Create a release on [GitHub](https://github.com/apache/storm/releases).
Generate the release notes with the GitHub tooling.
+
+11. Post, promote, celebrate. ;) Annoucement email can be sent to
[email protected] using the following template:
```agsl
Subject: [ANNOUNCE] Apache Storm [VERSION] Released
@@ -225,7 +239,7 @@ Regards,
The Apache Storm Team
[1]
https://downloads.apache.org/storm/apache-storm-[VERSION]/RELEASE_NOTES.html
-[2] https://issues.apache.org/jira/browse/STORM
+[2] https://github.com/apache/storm/issues
```
## Cleaning up if the vote fails
diff --git a/dev-tools/jira-github-join.py b/dev-tools/jira-github-join.py
deleted file mode 100755
index a6e1580b6..000000000
--- a/dev-tools/jira-github-join.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-# 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.
-
-from optparse import OptionParser
-from datetime import datetime
-from github import GitHub
-from jira_github import JiraRepo
-from report.report_builder import CompleteReportBuilder
-
-"""
-If you get certificate error when running on Mac,
-(https://stackoverflow.com/questions/50236117/scraping-ssl-certificate-verify-failed-error-for-http-en-wikipedia-org)
-Go to Macintosh HD
- > Applications
- > Python3.9 folder (or whatever version of Python you're using)
- > double click on "Install Certificates.command" file.
-
-"""
-
-
-def main():
- parser = OptionParser(usage="usage: %prog [options]")
- parser.add_option("-g", "--github-user", dest="gituser",
- type="string", help="github User, if not supplied no
auth is used", metavar="USER")
-
- (options, args) = parser.parse_args()
-
- jira_repo = JiraRepo("https://issues.apache.org/jira/rest/api/2")
- github_repo = GitHub(options)
-
- print("=" * 100)
- print("Report generated on: %s (GMT)" %
(datetime.strftime(datetime.utcnow(), "%Y-%m-%d %H:%M:%S")))
- print("-" * 100)
- report_builder = CompleteReportBuilder(jira_repo, github_repo)
- report_builder.report.print_all()
-
-
-if __name__ == "__main__":
- main()
diff --git a/dev-tools/jira_github/__init__.py
b/dev-tools/jira_github/__init__.py
deleted file mode 100644
index 46412e6dd..000000000
--- a/dev-tools/jira_github/__init__.py
+++ /dev/null
@@ -1,296 +0,0 @@
-# -*- coding: utf-8 -*-
-# 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.
-
-import re
-import urllib
-import urllib.request
-import urllib.parse
-from datetime import datetime
-
-try:
- import json
-except ImportError:
- import simplejson as json
-
-
-def jiratime(obj):
- if obj is None:
- return None
- return datetime.strptime(obj[0:19], "%Y-%m-%dT%H:%M:%S")
-
-
-# Regex pattern definitions
-github_user = re.compile(r"Git[Hh]ub user ([\w-]+)")
-github_pull = re.compile(r"https://github.com/[^/\s]+/[^/\s]+/pull/[0-9]+")
-has_vote = re.compile(r"\s+([-+][01])\s*")
-is_diff = re.compile("--- End diff --")
-
-
-def search_group(reg, txt, group):
- m = reg.search(txt)
- if m is None:
- return None
- return m.group(group)
-
-
-class JiraComment:
- """A comment on a JIRA"""
-
- def __init__(self, data):
- self.data = data
- self.author = self.data['author']['name']
- self.github_author = None
- self.githubPull = None
- self.githubComment = (self.author == "githubbot")
- body = self.get_body()
- if is_diff.search(body) is not None:
- self.vote = None
- else:
- self.vote = search_group(has_vote, body, 1)
-
- if self.githubComment:
- self.github_author = search_group(github_user, body, 1)
- self.githubPull = search_group(github_pull, body, 0)
-
- def get_author(self):
- if self.github_author is not None:
- return self.github_author
- return self.author
-
- def get_body(self):
- return self.data['body']
-
- def get_pull(self):
- return self.githubPull
-
- def has_github_pull(self):
- return self.githubPull is not None
-
- def raw(self):
- return self.data
-
- def has_vote(self):
- return self.vote is not None
-
- def get_vote(self):
- return self.vote
-
- def get_created(self):
- return jiratime(self.data['created'])
-
-
-class Jira:
- """A single JIRA"""
-
- def __init__(self, data, parent):
- self.key = data['key']
- self.fields = data['fields']
- self.parent = parent
- self.notes = None
- self.comments = None
-
- def get_id(self):
- """
- Get Jira ID as a string from the string stored in self.key
- :return: Jira id, example "STORM-1234"
- """
- return self.key
-
- def get_id_num(self):
- """
- Get Jira ID number as an integer from the string stored in self.key
- :return: Numeric Jira Id as a number. Example "STORM-1234" and
"ZKP-1234" will both return 1234
- """
- return int(self.key.split('-')[-1])
-
- def get_description(self):
- return self.fields['description']
-
- def getReleaseNote(self):
- if self.notes is None:
- field = self.parent.fieldIdMap['Release Note']
- if field in self.fields:
- self.notes = self.fields[field]
- else:
- self.notes = self.get_description()
- return self.notes
-
- def get_status(self):
- ret = ""
- status = self.fields['status']
- if status is not None:
- ret = status['name']
- return ret
-
- def get_priority(self):
- ret = ""
- pri = self.fields['priority']
- if pri is not None:
- ret = pri['name']
- return ret
-
- def get_assignee_email(self):
- ret = ""
- mid = self.fields['assignee']
- if mid is not None:
- ret = mid['emailAddress']
- return ret
-
- def get_assignee(self):
- ret = ""
- mid = self.fields['assignee']
- if mid is not None:
- ret = mid['displayName']
- return ret
-
- def get_components(self):
- return " , ".join([comp['name'] for comp in self.fields['components']])
-
- def get_summary(self):
- return self.fields['summary']
-
- def get_trimmed_summary(self):
- limit = 40
- summary = self.fields['summary']
- return summary if len(summary) < limit else summary[0:limit] + "..."
-
- def get_type(self):
- ret = ""
- mid = self.fields['issuetype']
- if mid is not None:
- ret = mid['name']
- return ret
-
- def get_reporter(self):
- ret = ""
- mid = self.fields['reporter']
- if mid is not None:
- ret = mid['displayName']
- return ret
-
- def get_project(self):
- ret = ""
- mid = self.fields['project']
- if mid is not None:
- ret = mid['key']
- return ret
-
- def get_created(self):
- return jiratime(self.fields['created'])
-
- def get_updated(self):
- return jiratime(self.fields['updated'])
-
- def get_comments(self):
- if self.comments is None:
- jiraId = self.get_id()
- comments = []
- at = 0
- end = 1
- count = 100
- while at < end:
- params = urllib.parse.urlencode({'startAt': at, 'maxResults':
count})
- resp = urllib.request.urlopen(self.parent.baseUrl + "/issue/"
+ jiraId + "/comment?" + params)
- resp_str = resp.read().decode()
- data = json.loads(resp_str)
- if 'errorMessages' in data:
- raise Exception(data['errorMessages'])
- at = data['startAt'] + data['maxResults']
- end = data['total']
- for item in data['comments']:
- j = JiraComment(item)
- comments.append(j)
- self.comments = comments
- return self.comments
-
- def has_voted_comment(self):
- for comment in self.get_comments():
- if comment.has_vote():
- return True
- return False
-
- def get_trimmed_comments(self, limit=40):
- comments = self.get_comments()
- return comments if len(comments) < limit else comments[0:limit] +
["..."]
-
- def raw(self):
- return self.fields
-
- def storm_jira_cmp(self, x, y):
- xn = x.get_id().split("-")[1]
- yn = y.get_id().split("-")[1]
- return int(xn) - int(yn)
-
-
-class JiraRepo:
- """A Repository for JIRAs"""
-
- def __init__(self, baseUrl):
- self.baseUrl = baseUrl
- resp = urllib.request.urlopen(baseUrl + "/field")
- resp_str = resp.read().decode()
- data = json.loads(resp_str)
-
- self.fieldIdMap = {}
- for part in data:
- self.fieldIdMap[part['name']] = part['id']
-
- def get(self, id):
- resp = urllib.request.urlopen(self.baseUrl + "/issue/" + id)
- resp_str = resp.read().decode()
- data = json.loads(resp_str)
- if 'errorMessages' in data:
- raise Exception(data['errorMessages'])
- j = Jira(data, self)
- return j
-
- def query(self, query):
- jiras = {}
- at = 0
- end = 1
- count = 100
- while at < end:
- params = urllib.parse.urlencode({'jql': query, 'startAt': at,
'maxResults': count})
- # print params
- resp = urllib.request.urlopen(self.baseUrl + "/search?%s" % params)
- resp_str = resp.read().decode()
- data = json.loads(resp_str)
- if 'errorMessages' in data:
- raise Exception(data['errorMessages'])
- at = data['startAt'] + data['maxResults']
- end = data['total']
- for item in data['issues']:
- j = Jira(item, self)
- jiras[j.get_id()] = j
- return jiras
-
- def unresolved_jiras(self, project):
- """
- :param project: The JIRA project to search for unresolved issues
- :return: All JIRA issues that have the field resolution = Unresolved
- """
- return self.query(f"project = {project} AND resolution = Unresolved")
-
- def open_jiras(self, project):
- """
- :param project: The JIRA project to search for open issues
- :return: All JIRA issues that have the field status = Open
- """
- return self.query(f"project = {project} AND status = Open")
-
- def in_progress_jiras(self, project):
- """
- :param project: The JIRA project to search for In Progress issues
- :return: All JIRA issues that have the field status = 'In Progress'
- """
- return self.query(f"project = {project} AND status = 'In Progress'")
diff --git a/dev-tools/release_notes.py b/dev-tools/release_notes.py
index 1c8663d2b..a0d79a9c0 100755
--- a/dev-tools/release_notes.py
+++ b/dev-tools/release_notes.py
@@ -15,9 +15,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Usage: release_notes.py <version> > RELEASE_NOTES.html
+"""Usage: release_notes.py <milestone_id_from_github> > RELEASE_NOTES.html
-Depends on https://pypi.python.org/pypi/jira/, please use pip to install this
module.
+Depends on "requests", 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
@@ -26,105 +26,127 @@ Generates release notes for a Storm release by generating
an HTML doc containing
"""
-from jira import JIRA
-import itertools, sys
+import requests
+import sys
+import os
if len(sys.argv) < 2:
- print("Usage: release_notes.py <version>", file=sys.stderr)
+ print("Usage: release_notes.py <milestone_id>", file=sys.stderr)
sys.exit(1)
-version = sys.argv[1]
+# GitHub configuration
+GITHUB_API_BASE_URL = "https://api.github.com"
+GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
-JIRA_BASE_URL = 'https://issues.apache.org/jira'
-MAX_RESULTS = 100 # This is constrained for cloud instances so we need to fix
this value
+if not GITHUB_TOKEN:
+ print("Error: GITHUB_TOKEN environment variable not set.", file=sys.stderr)
+ sys.exit(1)
+
+# Input arguments
+owner = "apache"
+repo = "storm"
+milestone = sys.argv[1] # Milestone ID
+
+print(f"Fetching issues for milestone with id= '{milestone}'...")
+headers = {
+ "Authorization": f"Bearer {GITHUB_TOKEN}",
+ "Accept": "application/vnd.github.v3+json"
+}
-def get_issues(jira, query, **kwargs):
+def get_milestone_title(owner, repo, milestone_number):
"""
- 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.
+ Fetch the title of a specific milestone by its number.
"""
- results = []
- startAt = 0
- new_results = None
- while new_results is 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
+ url =
f"{GITHUB_API_BASE_URL}/repos/{owner}/{repo}/milestones/{milestone_number}"
+ response = requests.get(url, headers=headers)
+ if response.status_code != 200:
+ print(f"Failed to fetch milestone: {response.status_code}
{response.reason}", file=sys.stderr)
+ sys.exit(1)
-def issue_link(issue):
- return "%s/browse/%s" % (JIRA_BASE_URL, issue.key)
+ milestone = response.json()
+ return milestone["title"]
+
+def get_issues(owner, repo, milestone):
+ """
+ Fetch all issues for a given milestone from a GitHub repository.
+ """
+ issues_url = f"{GITHUB_API_BASE_URL}/repos/{owner}/{repo}/issues"
+ params = {
+ "milestone": milestone,
+ "state": "all", # Include both open and closed issues
+ "per_page": 100
+ }
+
+ issues = []
+ while issues_url:
+ response = requests.get(issues_url, headers=headers, params=params)
+ if response.status_code != 200:
+ print(f"Failed to fetch issues: {response.status_code}
{response.reason}", file=sys.stderr)
+ sys.exit(1)
+
+ data = response.json()
+ issues.extend(data)
+ # Get next page URL from 'Link' header if available
+ issues_url = response.links.get("next", {}).get("url")
+
+ return issues
+def issue_link(issue):
+ return issue["html_url"]
if __name__ == "__main__":
- apache = JIRA(JIRA_BASE_URL)
- issues = get_issues(apache, 'project=STORM and fixVersion=%s' % version)
+ issues = get_issues(owner, repo, milestone)
+
if not issues:
- print("Didn't find any issues for the target fix version",
file=sys.stderr)
+ print("No issues found for the specified milestone.", file=sys.stderr)
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]
+ unresolved_issues = [issue for issue in issues if issue["state"] !=
"closed"]
if unresolved_issues:
- print("The release is not completed since unresolved issues or
improperly resolved issues were found still "
- "tagged with this release as the fix version:", file=sys.stderr)
+ print("The release is not completed since unresolved issues were
found:", file=sys.stderr)
for issue in unresolved_issues:
- print("Unresolved issue: %15s %20s %s" % (issue.key,
issue.fields.resolution, issue_link(issue)),
- file=sys.stderr)
- print('', file=sys.stderr)
- print("Note that for some resolutions, you should simply remove the
fix version as they have not been truly "
- "fixed in this release.", file=sys.stderr)
+ print(f"Unresolved issue: {issue['number']:5d}
{issue['state']:10s} {issue_link(issue)}", file=sys.stderr)
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 int(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)]
+ # Group issues by labels
+ issues_by_label = {}
+ unlabeled_issues = []
+ for issue in issues:
+ if issue["labels"]: # If the issue has labels
+ for label in issue["labels"]:
+ label_name = label["name"]
+ issues_by_label.setdefault(label_name, []).append(issue)
+ else:
+ unlabeled_issues.append(issue) # Add to the unlabeled list if no
labels exist
+
+ # Add unlabeled issues under a special "No Label" category
+ if unlabeled_issues:
+ issues_by_label["Uncategorized"] = unlabeled_issues
+
issues_str = "\n".join([
- f"\n\t<h2>{itype}</h2>" +
+ f"\n\t<h2>{label}</h2>" +
f"\n\t<ul>" +
- '\n\t\t'.join([f'<li>[<a href="{issue_link(issue)}">{issue.key}</a>] -
{issue.fields.summary}</li>' for issue in issues]) +
+ "\n\t\t".join([
+ f'<li>[<a href="{issue_link(issue)}">#{issue["number"]}</a>] -
{issue["title"]}</li>'
+ for issue in issues
+ ]) +
"\n\t</ul>"
- for itype, issues in by_group])
+ for label, issues in issues_by_label.items()
+ ])
+
+ version = get_milestone_title(owner, repo, milestone)
print(f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
-<title>Storm {version} Release Notes</title>
+<title>Release Notes for Apache Storm {version}</title>
</head>
<body>
-<h1>Release Notes for Storm {version}</h1>
-<p>JIRA issues addressed in the {version} release of Storm. Documentation for
this
- release is available at the <a href="https://storm.apache.org/">Apache
Storm project site</a>.</p>
+<h1>Release Notes for Apache Storm {version}</h1>
+<p>Issues addressed in {version}.</p>
{issues_str}
</body>
</html>""")
diff --git a/doap_Storm.rdf b/doap_Storm.rdf
index 733d2fbe4..7960a149d 100644
--- a/doap_Storm.rdf
+++ b/doap_Storm.rdf
@@ -29,7 +29,7 @@
<asfext:pmc rdf:resource="http://storm.apache.org" />
<shortdesc>Apache Storm is a distributed real-time computation
system.</shortdesc>
<description>Apache Storm is a distributed real-time computation system.
Similar to how Hadoop provides a set of general primitives for doing batch
processing, Storm provides a set of general primitives for doing real-time
computation.</description>
- <bug-database rdf:resource="https://issues.apache.org/jira/browse/STORM" />
+ <bug-database rdf:resource="https://github.com/apache/storm/issues" />
<mailing-list rdf:resource="http://storm.apache.org/community.html" />
<download-page rdf:resource="http://storm.apache.org/downloads.html" />
<programming-language>Java</programming-language>
diff --git a/pom.xml b/pom.xml
index 5ff568273..50aac66e0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,8 +63,8 @@
</scm>
<issueManagement>
- <system>jira</system>
- <url>https://issues.apache.org/jira/browse/STORM</url>
+ <system>github</system>
+ <url>https://github.com/apache/storm/issues</url>
</issueManagement>
<properties>