Commit 0a888107 authored by Adrian DC's avatar Adrian DC
Browse files

feat(cli): implement '--{get,set}-project-issues-boards' features

Issue: #4
---

Signed-off-by: default avatarAdrian DC <radian.dc@gmail.com>
parent fbd6678c
Loading
Loading
Loading
Loading
Loading
+10 −2
Changes for README.md: 10 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -78,8 +78,9 @@ usage: gitlab-projects-settings [-h] [--version] [--no-color] [--update-check] [
                                [--protect-branches] [--protect-tags [LEVEL]] [--set-merge-method [METHOD]]
                                [--set-merge-squash [SQUASH]] [--set-merge-pipelines [CHECK]]
                                [--set-merge-skipped [CHECK]] [--set-merge-resolved [CHECK]]
                                [--erase-jobs-artifacts | --erase-jobs-contents]
                                [--get-group-labels | --set-group-labels JSON]
                                [--add-jobs-token-allowlist PATH] [--remove-jobs-token-allowlist PATH]
                                [--erase-jobs-artifacts | --erase-jobs-contents] [--get-project-issues-boards]
                                [--set-project-issues-boards JSON] [--get-group-labels | --set-group-labels JSON]
                                [--get-project-labels | --set-project-labels JSON] [--]
                                [url_path]

@@ -137,9 +138,16 @@ merge requests settings arguments:
  --set-merge-resolved [CHECK]      # Set project merge requests check for resolved threads (true, false, default: True)

ci/cd settings arguments:
  --add-jobs-token-allowlist PATH   # Add a group or project to CI/CD job token allowlist
  --remove-jobs-token-allowlist PATH
                                    # Remove a group or project from CI/CD job token allowlist
  --erase-jobs-artifacts            # Erase all CI/CD jobs artifacts
  --erase-jobs-contents             # Erase all CI/CD jobs artifacts and traces

issues arguments:
  --get-project-issues-boards       # Get the GitLab project issues boards in JSON format
  --set-project-issues-boards JSON  # Set the GitLab project issues boards from JSON format

labels arguments:
  --get-group-labels                # Get the GitLab group labels in JSON format
  --set-group-labels JSON           # Set the GitLab group labels from JSON format
+56 −9
Changes for src/cli/entrypoint.py: 56 added lines, 9 removed lines.
Original line number Diff line number Diff line
@@ -396,10 +396,10 @@ class Entrypoint:
            for label_json in labels_json:
                label_set = gitlab.group_set_label(
                    criteria,
                    label_json['name'],
                    label_json['description'],
                    label_json['text_color'],
                    label_json['color'],
                    name=label_json['name'],
                    description=label_json['description'],
                    text_color=label_json['text_color'],
                    color=label_json['color'],
                )
                labels_names += [label_set.name]
            print(f'{Colors.CYAN}{", ".join(labels_names)}'
@@ -721,6 +721,53 @@ class Entrypoint:
                  f'{Colors.RESET}')
            Platform.flush()

        # Get project issues boards
        if options.get_project_issues_boards:
            issues_boards_objects = gitlab.project_get_issues_boards(criteria)
            if issues_boards_objects:
                print(f'{Colors.BOLD}   - Get issues boards to JSON: '
                      f'{Colors.RESET}', end='')
                issues_boards_list: List[Dict[str, Union[bool, str, List[Dict[str, str]],
                                                         None]]] = []
                for board in issues_boards_objects:
                    board_lists: List[Dict[str, str]] = []
                    for board_list in board.lists.list(get_all=True):
                        board_lists += [{
                            'label': board_list.label['name'],
                            'position': board_list.position,
                        }]
                    issues_boards_list += [{
                        'name': board.name,
                        'hide_backlog_list': board.hide_backlog_list,
                        'hide_closed_list': board.hide_closed_list,
                        'lists': board_lists,
                    }]
                print(json.dumps(issues_boards_list))
                Platform.flush()

        # Set project issues boards
        elif options.set_project_issues_boards:
            print(f'{Colors.BOLD}   - Set issues boards from JSON: '
                  f'{Colors.RESET}', end='')
            if not project.archived:
                issues_boards_names: List[str] = []
                issues_boards_json = json.loads(options.set_project_issues_boards)
                for board_json in issues_boards_json:
                    board_set = gitlab.project_set_issues_board(
                        criteria, name=board_json['name'],
                        hide_backlog_list=board_json['hide_backlog_list'],
                        hide_closed_list=board_json['hide_closed_list'], lists=[{
                            'label': board_list['label'],
                            'position': board_list['position'],
                        } for board_list in board_json['lists']])
                    issues_boards_names += [board_set.name]
                print(f'{Colors.CYAN}{", ".join(issues_boards_names)}'
                      f'{Colors.RESET}')
            else:
                print(f'{Colors.RED}Archived project are read-only'
                      f'{Colors.RESET}')
            Platform.flush()

        # Get project labels
        if options.get_project_labels:
            labels_objects = gitlab.project_get_labels(criteria)
@@ -749,11 +796,11 @@ class Entrypoint:
                for label_json in labels_json:
                    label_set = gitlab.project_set_label(
                        criteria,
                        label_json['name'],
                        label_json['description'],
                        label_json['text_color'],
                        label_json['color'],
                        label_json['priority'],
                        name=label_json['name'],
                        description=label_json['description'],
                        text_color=label_json['text_color'],
                        color=label_json['color'],
                        priority=label_json['priority'],
                    )
                    labels_names += [label_set.name]
                print(f'{Colors.CYAN}{", ".join(labels_names)}'
+15 −0
Changes for src/cli/main.py: 15 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -382,6 +382,21 @@ def main() -> None:
        help='Erase all CI/CD jobs artifacts and traces',
    )

    # Arguments issues definitions
    group = parser.add_argument_group('issues arguments')
    group.add_argument(
        '--get-project-issues-boards',
        dest='get_project_issues_boards',
        action='store_true',
        help='Get the GitLab project issues boards in JSON format',
    )
    group.add_argument(
        '--set-project-issues-boards',
        dest='set_project_issues_boards',
        metavar='JSON',
        help='Set the GitLab project issues boards from JSON format',
    )

    # Arguments labels definitions
    group = parser.add_argument_group('labels arguments')
    subgroup = group.add_mutually_exclusive_group()
+78 −1
Changes for src/features/gitlab.py: 78 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@

# Standard libraries
from time import sleep
from typing import cast, List, Union
from typing import cast, Dict, List, Union

# Modules libraries
from gitlab import Gitlab
@@ -18,6 +18,8 @@ from gitlab.v4.objects import (
    GroupLabel,
    Namespace,
    Project,
    ProjectBoard,
    ProjectBoardList,
    ProjectLabel,
    User,
)
@@ -500,6 +502,16 @@ class GitLabFeature:
        # Result
        return result

    # Project get issues boards
    def project_get_issues_boards(
        self,
        criteria: str,
    ) -> Union[RESTObjectList, List[RESTObject]]:

        # Get project issues boards
        project = self.project(criteria)
        return project.boards.list(get_all=True)

    # Project get labels
    def project_get_labels(
        self,
@@ -655,6 +667,71 @@ class GitLabFeature:
            # Save project
            project.save()

    # Project set issues_board, pylint: disable=too-many-arguments,too-many-positional-arguments
    def project_set_issues_board(
        self,
        criteria: str,
        name: str,
        hide_backlog_list: bool,
        hide_closed_list: bool,
        lists: List[Dict[str, str]],
    ) -> ProjectBoard:

        # Create project issues board
        project = self.project(criteria)
        issues_board: ProjectBoard
        try:
            issues_board = next(board for board in project.boards.list(get_all=True)
                                if board.name == name and isinstance(board, ProjectBoard))
        except GitlabGetError:
            project.boards.create({
                'name': name,
            })
            issues_board = next(board for board in project.boards.list(get_all=True)
                                if board.name == name and isinstance(board, ProjectBoard))

        # Update project issues board
        issues_board.hide_backlog_list = hide_backlog_list
        issues_board.hide_closed_list = hide_closed_list
        issues_board.save()

        # Iterate through issue board lists
        for list_json in lists:

            # Create project issues board list
            board_list: ProjectBoardList
            try:
                board_list = next(board_list
                                  for board_list in issues_board.lists.list(get_all=True)
                                  if board_list.label['name'] == list_json['label']
                                  and isinstance(board_list, ProjectBoardList))
            except (GitlabGetError, IndexError):
                label = project.labels.get(list_json['label'],
                                           include_ancestor_groups=True)
                issues_board.lists.create({
                    'label_id': label.id,
                })
                board_list = next(board_list
                                  for board_list in issues_board.lists.list(get_all=True)
                                  if board_list.label['name'] == list_json['label']
                                  and isinstance(board_list, ProjectBoardList))

            # Update project issues board list
            if board_list.position != list_json['position']:
                board_list.position = list_json['position']
                board_list.save()

        # Prune project issues board lists
        for board_list in [
                board_list for board_list in issues_board.lists.list(get_all=True)
                if isinstance(board_list, ProjectBoardList)
                and board_list.label['name'] not in [item['label'] for item in lists]
        ]:
            board_list.delete()

        # Result
        return issues_board

    # Project set label, pylint: disable=too-many-arguments,too-many-positional-arguments
    def project_set_label(
        self,