File indexing completed on 2024-12-01 08:16:20
0001 """ 0002 Module containing issues command 0003 """ 0004 0005 # SPDX-FileCopyrightText: 2020 Benjamin Port <benjamin.port@kde.org> 0006 # 0007 # SPDX-License-Identifier: GPL-2.0-or-later 0008 0009 import argparse 0010 import os 0011 import sys 0012 from typing import List, Dict 0013 0014 from gitlab.v4.objects import ProjectIssue 0015 from gitlab.exceptions import GitlabGetError 0016 0017 from lab.repositoryconnection import RepositoryConnection 0018 from lab.utils import TextFormatting, Utils, LogType 0019 from lab.table import Table 0020 0021 0022 def parser( 0023 subparsers: argparse._SubParsersAction, # pylint: disable=protected-access 0024 ) -> argparse.ArgumentParser: 0025 """ 0026 Subparser for issues command 0027 :param subparsers: subparsers object from global parser 0028 :return: issues subparser 0029 """ 0030 0031 issues_parser: argparse.ArgumentParser = subparsers.add_parser("issues", help="Gitlab issues") 0032 0033 issues_parser.add_argument( 0034 "--opened", 0035 help="Show opened issues", 0036 action="store_true", 0037 ) 0038 issues_parser.add_argument( 0039 "--closed", 0040 help="Show closed issues", 0041 action="store_true", 0042 ) 0043 group = issues_parser.add_mutually_exclusive_group() 0044 group.add_argument( 0045 "--assigned", 0046 help="Show only issues assigned to me", 0047 action="store_true", 0048 ) 0049 group.add_argument( 0050 "--project", 0051 help="Show all project issues and not only the one you authored", 0052 action="store_true", 0053 ) 0054 issues_parser.add_argument( 0055 "issue_id", help="Show issue by id if provided", metavar="issue_id", type=int, nargs="?" 0056 ) 0057 issues_parser.add_argument("--web", help="open on web browser", action="store_true") 0058 return issues_parser 0059 0060 0061 def run(args: argparse.Namespace) -> None: 0062 """ 0063 run merge request list command 0064 :param args: parsed arguments 0065 """ 0066 if args.issue_id is not None: 0067 issue: IssuesShow = IssuesShow(args.issue_id) 0068 if args.web: 0069 issue.open_web() 0070 else: 0071 print(issue) 0072 else: 0073 lister: IssuesList = IssuesList(args.opened, args.closed, args.assigned, args.project) 0074 if args.web: 0075 lister.open_web() 0076 else: 0077 lister.print_formatted_list() 0078 0079 0080 class IssuesList(RepositoryConnection): 0081 """ 0082 Lists all merge requests of the current repository 0083 """ 0084 0085 opened: bool = True 0086 closed: bool = True 0087 assigned: bool = False 0088 project: bool = False 0089 0090 def __init__(self, opened: bool, closed: bool, assigned: bool, for_project: bool) -> None: 0091 RepositoryConnection.__init__(self) 0092 self.opened = opened 0093 self.closed = closed 0094 self.assigned = assigned 0095 self.for_project = for_project 0096 0097 def print_formatted_list(self) -> None: 0098 """ 0099 prints the list of issues to the terminal formatted as a table 0100 """ 0101 table = Table() 0102 args: Dict[str, str] = {} 0103 0104 # compute filters 0105 state: str = "all" 0106 if self.opened and not self.closed: 0107 state = "opened" 0108 elif self.closed and not self.opened: 0109 state = "closed" 0110 args["state"] = state 0111 0112 issues: List[ProjectIssue] = [] 0113 if not self.for_project and self.assigned: 0114 # List issues all over the instance assigned to me 0115 args["scope"] = "assigned_to_me" 0116 issues = self._connection.issues.list(**args) 0117 elif not self.for_project and not self.assigned: 0118 # Request both created and assigned issues on the whole instance 0119 args["scope"] = "created_by_me" 0120 issues = self._connection.issues.list(**args) 0121 args["scope"] = "assigned_to_me" 0122 issues += self._connection.issues.list(**args) 0123 elif self.for_project and not self.assigned: 0124 # Request all issues on the current project 0125 args["scope"] = "all" 0126 issues = self._remote_project.issues.list(**args) 0127 0128 for issue in issues: 0129 formatting = TextFormatting.GREEN if issue.state == "opened" else TextFormatting.RED 0130 row: List[str] = [ 0131 TextFormatting.BOLD + issue.references["full"] + TextFormatting.END, 0132 issue.title, 0133 formatting + issue.state + TextFormatting.END, 0134 ] 0135 0136 table.add_row(row) 0137 0138 table.print() 0139 0140 def open_web(self) -> None: 0141 """ 0142 Open issue with xdg-open 0143 """ 0144 if self._remote_project.issues_enabled: 0145 Utils.xdg_open(f"{self._remote_project.web_url}/-/issues") 0146 else: 0147 Utils.log(LogType.ERROR, "Issue are disabled for this project") 0148 0149 0150 class IssuesShow(RepositoryConnection): 0151 """ 0152 Show issue 0153 """ 0154 0155 def __init__(self, issue_id: int): 0156 RepositoryConnection.__init__(self) 0157 try: 0158 self.issue: ProjectIssue = self._remote_project.issues.get(issue_id, lazy=False) 0159 except GitlabGetError: 0160 Utils.log(LogType.WARNING, f"No issue with ID {issue_id}") 0161 sys.exit(1) 0162 0163 def open_web(self) -> None: 0164 """ 0165 Open issue with xdg-open 0166 """ 0167 Utils.xdg_open(self.issue.web_url) 0168 0169 def __str__(self) -> str: 0170 formatting = TextFormatting.GREEN if self.issue.state == "opened" else TextFormatting.RED 0171 textbuffer: str = "" 0172 textbuffer += ( 0173 TextFormatting.BOLD 0174 + self.issue.title 0175 + TextFormatting.END 0176 + f" (#{self.issue.iid}) " 0177 + formatting 0178 + self.issue.state 0179 + TextFormatting.END 0180 + os.linesep 0181 ) 0182 textbuffer += self.issue.description 0183 return textbuffer