# SPDX-License-Identifier: BSD-2-Clause """ This module provides support to describe package changes. """ # Copyright (C) 2023 embedded brains GmbH & Co. KG # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import itertools from typing import Dict, List, Set, Tuple from rtemsspec.items import Item, ItemMapper from rtemsspec.packagebuild import BuildItem from rtemsspec.sphinxcontent import SphinxContent def _issue_prologue(status: str) -> str: return ("When the QDP of this package version was produced, " f"there were the following {status} issues associated:") def _add_issues(content: SphinxContent, issues: Set[Item], header: str, prologue: str, which: str) -> None: with content.section(header): if issues: content.add(prologue) rows: List[Tuple[str, ...]] = [("Database", "Identifier", "Subject")] for item in sorted(issues): database = item.parent("issue-member") url = ItemMapper(item).substitute(database["url"]) identifier = f"`{item['identifier']} <{url}>`_" subject = item["subject"].replace("`", "\\`") rows.append((database["name"], identifier, subject)) content.add_grid_table(rows, [27, 14, 59]) else: content.add(f"""When the QDP of this package version was produced, there were no {which} issues associated.""") class PackageChanges(BuildItem): """ Describes package changes. """ def _get_issues(self, change: Dict[str, str]) -> Tuple[Set[Item], Set[Item]]: issues: Tuple[Set[Item], Set[Item]] = (set(), set()) package_status = self.item.map(change["package-status"]) for link in package_status.links_to_parents("issue"): issues[int(link["status"] == "open")].add(link.item) return issues def _get_change_list(self, section_level: int, with_description: bool) -> List[SphinxContent]: change_list: List[SphinxContent] = [] past_issues: Tuple[Set[Item], Set[Item]] = (set(), set()) previous_issues: Tuple[Set[Item], Set[Item]] = (set(), set()) for change in self["change-list"]: for past, previous in zip(past_issues, previous_issues): past.update(previous) content = SphinxContent(section_level=section_level) if with_description: content.add_blank_line() content.open_section(change["name"]) content.add(change["description"]) current_issues = self._get_issues(change) new_issues = current_issues[1].difference(previous_issues[1]) _add_issues(content, new_issues, "New issues", _issue_prologue("new"), "new") open_issues = current_issues[1].intersection(previous_issues[1]) _add_issues(content, open_issues, "Open issues", _issue_prologue("open"), "open") closed_issues = current_issues[0].difference(past_issues[0]) _add_issues( content, closed_issues, "Closed issues", "The following issues were closed " "for this package version.", "closed") if with_description: content.close_section() change_list.insert(0, content) previous_issues = current_issues return change_list def get_change_list(self, section_level: int) -> str: """ Gets the change list using the section level. """ change_list = self._get_change_list(section_level, True) return "\n".join(itertools.chain.from_iterable(change_list)) def get_open_issues(self, section_level: int) -> str: """ Gets the open issues using the section level. """ content = SphinxContent(section_level=section_level) _, open_issues = self._get_issues(self["change-list"][-1]) _add_issues(content, open_issues, "Open issues", _issue_prologue("open"), "open") return "\n".join(content) def get_current_changes(self) -> str: """ Gets the current changes. """ return self["change-list"][-1]["description"] def get_current_issues(self, section_level: int) -> str: """ Gets the current issues using the section level. """ change_list = self._get_change_list(section_level, False) return "\n".join(change_list[0])