Release: support generating LTS release notes from Gitea #104402
|
@ -1,41 +1,18 @@
|
||||||
This folder contains several scripts to smoothen the Blender LTS releases.
|
This folder contains a script to generate release notes and download URLs
|
||||||
|
for Blender LTS releases.
|
||||||
|
|
||||||
create_download_urls.py
|
Ensure required Python modules are installed before running:
|
||||||
=======================
|
|
||||||
|
|
||||||
This python script is used to generate the download urls which we can
|
pip3 install -r ./requirements.txt
|
||||||
copy-paste directly into the CMS of www.blender.org.
|
|
||||||
|
|
||||||
Usage: create_download_urls.py --version 2.83.7
|
Then run for example:
|
||||||
|
|
||||||
Arguments:
|
./create_release_notes.py --version 3.3.2 --format=html
|
||||||
--version VERSION Version string in the form of {major}.{minor}.{build}
|
|
||||||
(eg 2.83.7)
|
|
||||||
|
|
||||||
The resulting html will be printed to the console.
|
Available arguments:
|
||||||
|
|
||||||
create_release_notes.py
|
--version VERSION Version string in the form of {major}.{minor}.{build}
|
||||||
=======================
|
(e.g. 3.3.2)
|
||||||
|
--issue ISSUE Gitea issue that is contains the release notes
|
||||||
This python script is used to generate the release notes which we can
|
information (e.g. #77348)
|
||||||
copy-paste directly into the CMS of www.blender.org and stores.
|
--format FORMAT Format the result in `text`, `steam`, `wiki` or `html`
|
||||||
|
|
||||||
Usage: ./create_release_notes.py --task=T77348 --version=2.83.7
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
--version VERSION Version string in the form of {major}.{minor}.{build}
|
|
||||||
(e.g. 2.83.7)
|
|
||||||
--task TASK Phabricator ticket that is contains the release notes
|
|
||||||
information (e.g. T77348)
|
|
||||||
--format FORMAT Format the result in `text`, `steam`, `wiki` or `html`
|
|
||||||
|
|
||||||
Requirements
|
|
||||||
============
|
|
||||||
|
|
||||||
* Python 3.8 or later
|
|
||||||
* Python phabricator client version 0.7.0
|
|
||||||
https://pypi.org/project/phabricator/
|
|
||||||
|
|
||||||
For convenience the python modules can be installed using pip
|
|
||||||
|
|
||||||
pip3 install -r ./requirements.txt
|
|
||||||
|
|
|
@ -1,169 +1,46 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import phabricator
|
|
||||||
|
|
||||||
|
import lts_issue
|
||||||
|
import lts_download
|
||||||
|
|
||||||
DESCRIPTION = ("This python script is used to generate the release notes "
|
DESCRIPTION = ("This python script is used to generate the release notes and "
|
||||||
"which we can copy-paste directly into the CMS of "
|
"download URLs which we can copy-paste directly into the CMS of "
|
||||||
"www.blender.org and stores.")
|
"www.blender.org and stores.")
|
||||||
USAGE = "./create_release_notes.py --task=T77348 --version=2.83.7"
|
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
parser = argparse.ArgumentParser(description=DESCRIPTION)
|
||||||
|
parser.add_argument(
|
||||||
|
"--version",
|
||||||
|
required=True,
|
||||||
|
help="Version string in the form of {major}.{minor}.{patch} (e.g. 3.3.2)")
|
||||||
|
parser.add_argument(
|
||||||
|
"--issue",
|
||||||
|
help="Task that is contains the release notes information (e.g. #77348)")
|
||||||
|
parser.add_argument(
|
||||||
|
"--format",
|
||||||
|
help="Format the result in `text`, `steam`, `wiki` or `html`",
|
||||||
|
default="text")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
class ReleaseLogLine:
|
# Determine issue number
|
||||||
"""
|
version = args.version
|
||||||
Class containing the information of a single line of the release log
|
issue = args.issue
|
||||||
|
if not issue:
|
||||||
|
if version.startswith("2.83."):
|
||||||
|
issue = "#77348"
|
||||||
|
elif version.startswith("2.93."):
|
||||||
|
issue = "#88449"
|
||||||
|
elif version.startswith("3.3."):
|
||||||
|
issue = "#100749"
|
||||||
|
else:
|
||||||
|
raise ValueError("Specify --issue or update script to include issue number for this version")
|
||||||
|
|
||||||
Instance attributes:
|
# Print
|
||||||
|
if args.format == "html":
|
||||||
|
lts_download.print_urls(version=version)
|
||||||
|
print("")
|
||||||
|
|
||||||
* line: (str) the original line used to create this log line
|
lts_issue.print_notes(version=version, format=args.format, issue=issue)
|
||||||
* task_id: (int or None) the extracted task id associated with this log
|
|
||||||
line. Can be None if the log line isn't associated with a task.
|
|
||||||
* commit_id: (str or None) the extracted commit id associated with this log
|
|
||||||
line. Only filled when no `task_id` could be found.
|
|
||||||
* ref: (str) `task_id` or `commit_id` of this line, including `T` for tasks
|
|
||||||
or `D` for diffs.
|
|
||||||
* title: (str) title of this log line. When constructed this attribute is
|
|
||||||
an empty string. The called needs to retrieve the title from the
|
|
||||||
backend.
|
|
||||||
* url: (str) url of the ticket task or commit.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, line: str):
|
|
||||||
self.line = line
|
|
||||||
items = line.split("|")
|
|
||||||
self.task_id = None
|
|
||||||
self.commit_id = None
|
|
||||||
try:
|
|
||||||
task_id = int(items[1].strip()[1:])
|
|
||||||
self.task_id = task_id
|
|
||||||
self.ref = f"T{self.task_id}"
|
|
||||||
except ValueError:
|
|
||||||
# no task
|
|
||||||
commit_string = items[3].strip()
|
|
||||||
commits = commit_string.split(",")
|
|
||||||
commit_id = commits[0]
|
|
||||||
commit_id = commit_id.replace("{", "").replace("}", "")
|
|
||||||
if not commit_id.startswith("rB"):
|
|
||||||
commit_id = f"rB{commit_id}"
|
|
||||||
self.commit_id = commit_id
|
|
||||||
|
|
||||||
self.ref = f"{self.commit_id}"
|
|
||||||
|
|
||||||
self.title = ""
|
|
||||||
self.url = f"https://developer.blender.org/{self.ref}"
|
|
||||||
|
|
||||||
def __format_as_html(self) -> str:
|
|
||||||
return f" <li>{self.title} [<a href=\"{self.url}\">{self.ref}</a>]</li>"
|
|
||||||
|
|
||||||
def __format_as_text(self) -> str:
|
|
||||||
return f"* {self.title} [{self.ref}]"
|
|
||||||
|
|
||||||
def __format_as_steam(self) -> str:
|
|
||||||
return f"* {self.title} ([url={self.url}]{self.ref}[/url])"
|
|
||||||
|
|
||||||
def __format_as_wiki(self) -> str:
|
|
||||||
if self.task_id:
|
|
||||||
return f"* {self.title} [{{{{BugReport|{self.task_id}}}}}]"
|
|
||||||
else:
|
|
||||||
return f"* {self.title} [{{{{GitCommit|{self.commit_id[2:]}}}}}]"
|
|
||||||
|
|
||||||
def format(self, format: str) -> str:
|
|
||||||
"""
|
|
||||||
Format this line
|
|
||||||
|
|
||||||
:attr format: the desired format. Possible values are 'text', 'steam' or 'html'
|
|
||||||
:type string:
|
|
||||||
"""
|
|
||||||
if format == 'html':
|
|
||||||
return self.__format_as_html()
|
|
||||||
elif format == 'steam':
|
|
||||||
return self.__format_as_steam()
|
|
||||||
elif format == 'wiki':
|
|
||||||
return self.__format_as_wiki()
|
|
||||||
else:
|
|
||||||
return self.__format_as_text()
|
|
||||||
|
|
||||||
|
|
||||||
def format_title(title: str) -> str:
|
|
||||||
title = title.strip()
|
|
||||||
if not title.endswith("."):
|
|
||||||
title = title + "."
|
|
||||||
return title
|
|
||||||
|
|
||||||
|
|
||||||
def extract_release_notes(version: str, task_id: int):
|
|
||||||
"""
|
|
||||||
Extract all release notes logs
|
|
||||||
|
|
||||||
# Process
|
|
||||||
|
|
||||||
1. Retrieval of description of the given `task_id`.
|
|
||||||
2. Find rows for the given `version` and convert to `ReleaseLogLine`.
|
|
||||||
3. based on the associated task or commit retrieves the title of the log
|
|
||||||
line.
|
|
||||||
"""
|
|
||||||
phab = phabricator.Phabricator()
|
|
||||||
phab.update_interfaces()
|
|
||||||
task = phab.maniphest.info(task_id=task_id)
|
|
||||||
description = task["description"]
|
|
||||||
lines = description.split("\n")
|
|
||||||
start_index = lines.index(f"## Blender {version} ##")
|
|
||||||
lines = lines[start_index + 1:]
|
|
||||||
for line in lines:
|
|
||||||
if not line.strip():
|
|
||||||
continue
|
|
||||||
if line.startswith("| **Report**"):
|
|
||||||
continue
|
|
||||||
if line.startswith("## Blender"):
|
|
||||||
break
|
|
||||||
|
|
||||||
log_line = ReleaseLogLine(line)
|
|
||||||
if log_line.task_id:
|
|
||||||
issue_task = phab.maniphest.info(task_id=log_line.task_id)
|
|
||||||
log_line.title = format_title(issue_task.title)
|
|
||||||
yield log_line
|
|
||||||
elif log_line.commit_id:
|
|
||||||
commits = phab.diffusion.commit.search(constraints={"identifiers": [log_line.commit_id]})
|
|
||||||
commit = commits.data[0]
|
|
||||||
commit_message = commit['fields']['message']
|
|
||||||
commit_title = commit_message.split("\n")[0]
|
|
||||||
log_line.title = format_title(commit_title)
|
|
||||||
yield log_line
|
|
||||||
|
|
||||||
|
|
||||||
def print_release_notes(version: str, format: str, task_id: int):
|
|
||||||
"""
|
|
||||||
Generate and print the release notes to the console.
|
|
||||||
"""
|
|
||||||
if format == 'html':
|
|
||||||
print("<ul>")
|
|
||||||
if format == 'steam':
|
|
||||||
print("[ul]")
|
|
||||||
for log_item in extract_release_notes(version=version, task_id=task_id):
|
|
||||||
print(log_item.format(format=format))
|
|
||||||
if format == 'html':
|
|
||||||
print("</ul>")
|
|
||||||
if format == 'steam':
|
|
||||||
print("[/ul]")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(description=DESCRIPTION, usage=USAGE)
|
|
||||||
parser.add_argument(
|
|
||||||
"--version",
|
|
||||||
required=True,
|
|
||||||
help="Version string in the form of {major}.{minor}.{build} (e.g. 2.83.7)")
|
|
||||||
parser.add_argument(
|
|
||||||
"--task",
|
|
||||||
required=True,
|
|
||||||
help="Phabricator ticket that is contains the release notes information (e.g. T77348)")
|
|
||||||
parser.add_argument(
|
|
||||||
"--format",
|
|
||||||
help="Format the result in `text`, `steam`, `wiki` or `html`",
|
|
||||||
default="text")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
print_release_notes(version=args.version, format=args.format, task_id=int(args.task[1:]))
|
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import argparse
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION = ("This python script is used to generate the download urls "
|
|
||||||
"which we can copy-paste directly into the CMS of "
|
|
||||||
"www.blender.org")
|
|
||||||
USAGE = "create_download_urls --version=2.83.7"
|
|
||||||
# Used date format: "September 30, 2020"
|
# Used date format: "September 30, 2020"
|
||||||
DATE_FORMAT = "%B %d, %Y"
|
DATE_FORMAT = "%B %d, %Y"
|
||||||
|
|
||||||
|
@ -62,19 +57,8 @@ def generate_html(version: Version) -> str:
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
def print_download_urls(version: Version):
|
def print_urls(version: str):
|
||||||
"""
|
"""
|
||||||
Generate the download urls and print them to the console.
|
Generate the download urls and print them to the console.
|
||||||
"""
|
"""
|
||||||
print(generate_html(version))
|
print(generate_html(Version(version)))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(description=DESCRIPTION, usage=USAGE)
|
|
||||||
parser.add_argument("--version",
|
|
||||||
required=True,
|
|
||||||
help=("Version string in the form of {major}.{minor}."
|
|
||||||
"{build} (eg 2.83.7)"))
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
print_download_urls(version=Version(args.version))
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
class ReleaseLogLine:
|
||||||
|
"""
|
||||||
|
Class containing the information of a single line of the release log
|
||||||
|
|
||||||
|
Instance attributes:
|
||||||
|
|
||||||
|
* line: (str) the original line used to create this log line
|
||||||
|
* issue_id: (int or None) the extracted issue id associated with this log
|
||||||
|
line. Can be None if the log line isn't associated with a issue.
|
||||||
|
* commit_id: (str or None) the extracted commit id associated with this log
|
||||||
|
line. Only filled when no `issue_id` could be found.
|
||||||
|
* ref: (str) `issue_id` or `commit_id` of this line, including `T` for issues
|
||||||
|
or `D` for diffs.
|
||||||
|
* title: (str) title of this log line. When constructed this attribute is
|
||||||
|
an empty string. The called needs to retrieve the title from the
|
||||||
|
backend.
|
||||||
|
* url: (str) url of the ticket issue or commit.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, line: str):
|
||||||
|
self.line = line
|
||||||
|
items = line.split("|")
|
||||||
|
self.issue_id = None
|
||||||
|
self.issue_repo = None
|
||||||
|
self.commit_id = None
|
||||||
|
self.commit_repo = None
|
||||||
|
base_url = "https://projects.blender.org"
|
||||||
|
try:
|
||||||
|
issue_tokens = items[1].strip().split("#")
|
||||||
|
if len(issue_tokens[0]) > 0:
|
||||||
|
self.issue_repo = issue_tokens[0]
|
||||||
|
self.issue_id = issue_tokens[1]
|
||||||
|
else:
|
||||||
|
self.issue_repo = "blender/blender"
|
||||||
|
self.issue_id = issue_tokens[1]
|
||||||
|
|
||||||
|
self.ref = f"#{self.issue_id}"
|
||||||
|
self.url = f"{base_url}/{self.issue_repo}/issues/{self.issue_id}"
|
||||||
|
except IndexError:
|
||||||
|
# no issue
|
||||||
|
commit_string = items[3].strip()
|
||||||
|
commit_string = commit_string.split(",")[0]
|
||||||
|
commit_string = commit_string.split("]")[0]
|
||||||
|
commit_string = commit_string.replace("[", "")
|
||||||
|
|
||||||
|
commit_tokens = commit_string.split("@")
|
||||||
|
if len(commit_tokens) > 1:
|
||||||
|
self.commit_repo = commit_tokens[0]
|
||||||
|
self.commit_id = commit_tokens[1]
|
||||||
|
else:
|
||||||
|
self.commit_repo = "blender/blender"
|
||||||
|
self.commit_id = commit_tokens[0]
|
||||||
|
|
||||||
|
self.ref = f"{self.commit_id}"
|
||||||
|
self.url = f"{base_url}/{self.commit_repo}/commit/{self.commit_id}"
|
||||||
|
|
||||||
|
self.title = ""
|
||||||
|
|
||||||
|
def __format_as_html(self) -> str:
|
||||||
|
return f" <li>{self.title} [<a href=\"{self.url}\">{self.ref}</a>]</li>"
|
||||||
|
|
||||||
|
def __format_as_text(self) -> str:
|
||||||
|
return f"* {self.title} [{self.ref}]"
|
||||||
|
|
||||||
|
def __format_as_steam(self) -> str:
|
||||||
|
return f"* {self.title} ([url={self.url}]{self.ref}[/url])"
|
||||||
|
|
||||||
|
def __format_as_wiki(self) -> str:
|
||||||
|
if self.issue_id:
|
||||||
|
return f"* {self.title} [{{{{BugReport|{self.issue_id}}}}}]"
|
||||||
|
else:
|
||||||
|
return f"* {self.title} [{{{{GitCommit|{self.commit_id[2:]}}}}}]"
|
||||||
|
|
||||||
|
def format(self, format: str) -> str:
|
||||||
|
"""
|
||||||
|
Format this line
|
||||||
|
|
||||||
|
:attr format: the desired format. Possible values are 'text', 'steam' or 'html'
|
||||||
|
:type string:
|
||||||
|
"""
|
||||||
|
if format == 'html':
|
||||||
|
return self.__format_as_html()
|
||||||
|
elif format == 'steam':
|
||||||
|
return self.__format_as_steam()
|
||||||
|
elif format == 'wiki':
|
||||||
|
return self.__format_as_wiki()
|
||||||
|
else:
|
||||||
|
return self.__format_as_text()
|
||||||
|
|
||||||
|
|
||||||
|
def format_title(title: str) -> str:
|
||||||
|
title = title.strip()
|
||||||
|
if not title.endswith("."):
|
||||||
|
title = title + "."
|
||||||
|
return title
|
||||||
|
|
||||||
|
|
||||||
|
def extract_release_notes(version: str, issue: str):
|
||||||
|
"""
|
||||||
|
Extract all release notes logs
|
||||||
|
|
||||||
|
# Process
|
||||||
|
|
||||||
|
1. Retrieval of description of the given `issue_id`.
|
||||||
|
2. Find rows for the given `version` and convert to `ReleaseLogLine`.
|
||||||
|
3. based on the associated issue or commit retrieves the title of the log
|
||||||
|
line.
|
||||||
|
"""
|
||||||
|
base_url = "https://projects.blender.org/api/v1/repos"
|
||||||
|
issues_url = base_url + "/blender/blender/issues/"
|
||||||
|
headers = {'accept': 'application/json'}
|
||||||
|
|
||||||
|
response = requests.get(issues_url + issue[1:], headers=headers)
|
||||||
|
description = response.json()["body"]
|
||||||
|
|
||||||
|
lines = description.split("\n")
|
||||||
|
start_index = lines.index(f"## Blender {version}")
|
||||||
|
lines = lines[start_index + 1:]
|
||||||
|
for line in lines:
|
||||||
|
if not line.strip():
|
||||||
|
continue
|
||||||
|
if line.startswith("| **Report**"):
|
||||||
|
continue
|
||||||
|
if line.startswith("## Blender"):
|
||||||
|
break
|
||||||
|
if line.find("| -- |") != -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
log_line = ReleaseLogLine(line)
|
||||||
|
if log_line.issue_id:
|
||||||
|
issue_url = f"{base_url}/{log_line.issue_repo}/issues/{log_line.issue_id}"
|
||||||
|
response = requests.get(issue_url, headers=headers)
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise ValueError("Issue not found: " + str(log_line.issue_id))
|
||||||
|
|
||||||
|
log_line.title = format_title(response.json()["title"])
|
||||||
|
yield log_line
|
||||||
|
elif log_line.commit_id:
|
||||||
|
commit_url = f"{base_url}/{log_line.commit_repo}/git/commits/{log_line.commit_id}"
|
||||||
|
response = requests.get(commit_url, headers=headers)
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise ValueError("Commit not found: " + log_line.commit_id)
|
||||||
|
|
||||||
|
commit_message = response.json()['commit']['message']
|
||||||
|
commit_title = commit_message.split("\n")[0]
|
||||||
|
log_line.title = format_title(commit_title)
|
||||||
|
yield log_line
|
||||||
|
|
||||||
|
|
||||||
|
def print_notes(version: str, format: str, issue: str):
|
||||||
|
"""
|
||||||
|
Generate and print the release notes to the console.
|
||||||
|
"""
|
||||||
|
if format == 'html':
|
||||||
|
print("<ul>")
|
||||||
|
if format == 'steam':
|
||||||
|
print("[ul]")
|
||||||
|
for log_item in extract_release_notes(version=version, issue=issue):
|
||||||
|
print(log_item.format(format=format))
|
||||||
|
if format == 'html':
|
||||||
|
print("</ul>")
|
||||||
|
if format == 'steam':
|
||||||
|
print("[/ul]")
|
|
@ -1 +1 @@
|
||||||
phabricator==0.7.0
|
requests
|
||||||
|
|
Loading…
Reference in New Issue