# SPDX-License-Identifier: GPL-2.0-or-later #!/usr/bin/env python3 import argparse import phabricator DESCRIPTION = ("This python script is used to generate the release notes " "which we can copy-paste directly into the CMS of " "www.blender.org and stores.") USAGE = "./create_release_notes.py --task=T77348 --version=2.83.7" 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 * 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"
  • {self.title} [{self.ref}]
  • " 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("") 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:]))