示例#1
0
def test_loading_illegal_configuration():
    configuration = Configuration(
        os.path.join(MOCK_FOLDER_PATH, 'illegal_conf.ini'))
    with pytest.raises(ValueError) as exception:
        configuration.load_properties()
        assert 'You have either added a section which is not in the column_names key' in exception

    configuration = Configuration(
        os.path.join(MOCK_FOLDER_PATH, 'illegal_query_conf.ini'))
    with pytest.raises(ValueError) as exception:
        configuration.load_properties()
        assert 'You have entered an illegal query' in exception

    configuration = Configuration(
        os.path.join(MOCK_FOLDER_PATH, 'illegal_action_conf.ini'))
    with pytest.raises(ValueError) as exception:
        configuration.load_properties()
        assert 'Provided illegal key' in exception
        assert 'in Actions section' in exception

    configuration = Configuration(
        os.path.join(MOCK_FOLDER_PATH, 'illegal_general_conf.ini'))
    with pytest.raises(ValueError) as exception:
        configuration.load_properties()
        assert 'Provided illegal key' in exception
        assert 'in General section' in exception
示例#2
0
    def run(self):
        item = self.get_project_item_object()
        if item is None:
            return  # In case the event is not for an issue / pull request
        if item.state and item.state.upper() in ('CLOSED', 'MERGED'):
            print(f"The item is {item.state.lower()}, not taking an action.")
            return

        for conf_path in self.conf_paths:
            self.config = Configuration(conf_path, self.verbose, self.quiet,
                                        self.log_path)
            self.config.load_properties()

            if (self.config.project_number in item.get_associated_project()
                    or is_matching_project_item(item.labels,
                                                self.config.must_have_labels,
                                                self.config.cant_have_labels,
                                                self.config.filter_labels)):
                item.set_priority(self.config.priority_list)
                self.manage_item_in_project(item)

            else:
                self.config.logger.debug(
                    f"The issue does not match the filter provided in the configuration "
                    f"file {conf_path}.")
示例#3
0
def test_matching_issue_filter():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()

    assert is_matching_issue(['test', 'bug'], config.must_have_labels,
                             config.cant_have_labels,
                             config.filter_labels) is True
    assert is_matching_issue(['not test', 'bug'], config.must_have_labels,
                             config.cant_have_labels,
                             config.filter_labels) is False
    assert is_matching_issue(['not test', 'test', 'bug'],
                             config.must_have_labels, config.cant_have_labels,
                             config.filter_labels) is False

    config.filter_labels = ['not bug']
    assert is_matching_issue(['bug', 'test'], config.must_have_labels,
                             config.cant_have_labels,
                             config.filter_labels) is False
    assert is_matching_issue(['not bug', 'test'], config.must_have_labels,
                             config.cant_have_labels,
                             config.filter_labels) is True

    config.must_have_labels = ['test||something']
    assert is_matching_issue(['not bug', 'test'], config.must_have_labels,
                             config.cant_have_labels,
                             config.filter_labels) is True
    assert is_matching_issue(['not bug', 'something'], config.must_have_labels,
                             config.cant_have_labels,
                             config.filter_labels) is True
    assert is_matching_issue(['not bug', 'else'], config.must_have_labels,
                             config.cant_have_labels,
                             config.filter_labels) is False
示例#4
0
def test_removing_items():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()
    project = Project(
        name="test project",
        config=config,
        columns={
            "Queue": ProjectColumn(id="id", name="Queue",
                                   cards=[ItemCard(id="sdf",
                                                   item=Issue(id="sdf", title="title", number=1)),
                                          ItemCard(id="sdff",
                                                   item=PullRequest(id="sdff", title="title", number=2))]),
            "Review in progress": ProjectColumn(id="id", name="Review in progress",
                                                cards=[])
        }
    )

    assert len(project.get_all_item_ids()) == 2
    assert len(project.columns.keys()) == 2

    class ClientMock(object):
        def delete_project_card(self, **kwargs):
            return

    project.remove_items(ClientMock, config)
    assert project.get_all_item_ids() == set()
示例#5
0
def test_missing_items():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()
    project = Project(
        name="test project",
        config=config,
        columns={
            "Queue": ProjectColumn(id="id", name="Queue",
                                   cards=[ItemCard(id="sdf",
                                                   item=Issue(id="sdf", title="title", number=1))]),
            "Review in progress": ProjectColumn(id="id", name="Review in progress",
                                                cards=[])
        }
    )

    assert len(project.get_all_item_ids()) == 1
    assert len(project.columns.keys()) == 2

    issue = Issue(
        id="2",
        number=2,
        title="issue title"
    )
    issues = {
        "2": issue
    }
    assert project.find_missing_item_ids(issues) == {"2"}
示例#6
0
def test_sort_column():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()

    class MockClient(object):
        def add_to_column(*args, **kwargs):
            return

        def move_to_specific_place_in_column(*args, **kwargs):
            return

    mock_client = MockClient()
    # Sorting
    config.priority_list = DEFAULT_PRIORITY_LIST
    column_object = ProjectColumn(
        id="id", name="Review in progress",
        cards=[
            ItemCard(id="sdf",
                     item=Issue(id="sdf", title="issue 2", number=2, labels=["Low"])),
            ItemCard(id="sdf3",
                     item=Issue(id="sdf", title="issue 4", number=4, labels=["Medium"])),
            ItemCard(id="sdf2",
                     item=PullRequest(id="sdf2", title="pull request 3", number=3, labels=["High"])),
        ])

    column_object.sort_cards(mock_client, config)
    card_titles_in_column = [card.item.title for card in column_object.cards]

    assert card_titles_in_column == ['pull request 3', "issue 4", 'issue 2']
def test_loading_configuration():
    configuration = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'),
                                  quiet=True,
                                  log_path="/tmp/")
    assert 'General' in configuration.config.sections()
    configuration.load_properties()

    assert configuration.closed_issues_column == 'Done'
    assert configuration.project_owner == 'ronykoz'
    assert configuration.repository_name == 'test'
    assert configuration.project_number == 1
    assert configuration.priority_list == [
        'Critical', 'High', 'Medium', 'Low', 'Customer|||zendesk'
    ]
    assert configuration.filter_labels == ['bug']
    assert configuration.filter_milestone == ''
    assert configuration.must_have_labels == ['test']
    assert configuration.cant_have_labels == ['not test']
    assert configuration.column_names == [
        'Queue', 'In progress', 'Review in progress', 'Waiting for Docs'
    ]
    assert configuration.column_rule_desc_order == [
        'Queue', 'Waiting for Docs', 'Review in progress', 'In progress'
    ]

    assert configuration.remove is True
    assert configuration.add is True
    assert configuration.move is True
    assert configuration.sort is False

    assert configuration.column_to_rules['Waiting for Docs'][
        'issue.pull_request.review_requested'] is True
    assert configuration.column_to_rules['Waiting for Docs'][
        'issue.pull_request.assignees'] == ['ronykoz||not rony']
示例#8
0
def test_project_empty_card():
    project = Project(
        name="test project",
        config=Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini')),
        columns={
            "Queue":
            ProjectColumn(id="id",
                          name="Queue",
                          cards=[
                              IssueCard(id="sdf",
                                        issue=Issue(id="sdf",
                                                    title="title",
                                                    number=1))
                          ]),
            "Review in progress":
            ProjectColumn(id="id", name="Review in progress", cards=[])
        })

    assert project.name == "test project"
    assert len(project.get_all_issue_ids()) == 1
    assert len(project.columns.keys()) == 2

    assert project.columns['Queue'].name == 'Queue'

    assert project.columns['Review in progress'].name == 'Review in progress'
示例#9
0
def test_adding_issue():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()
    project = Project(name="test project",
                      config=config,
                      columns={
                          "Queue":
                          ProjectColumn(id="id",
                                        name="Queue",
                                        cards=[
                                            IssueCard(id="sdf",
                                                      issue=Issue(
                                                          id="sdf",
                                                          title="title",
                                                          number=2))
                                        ]),
                          "Review in progress":
                          ProjectColumn(id="id",
                                        name="Review in progress",
                                        cards=[])
                      })

    assert len(project.get_all_issue_ids()) == 1
    assert len(project.columns.keys()) == 2

    issue = Issue(id="1", number=1, title="Rony")
    assert issue.priority_rank == 0
    issues = {"1": issue}

    class ClientMock(object):
        def add_issues_to_project(*args, **kwargs):
            return {'addProjectCard': {'cardEdge': {'node': {'id': "1"}}}}

        def add_to_column(*args, **kwargs):
            return

        def move_to_specific_place_in_column(*args, **kwargs):
            return

    project.add_issues(ClientMock, issues, {"1"}, config)
    assert project.columns['Queue'].cards[0].issue.title == "Rony"

    # testing non existent column
    with pytest.raises(Exception) as err:
        project.add_issue(ClientMock, issue, "non existent", config)
        assert "Did not found a matching column" in err

    issue2 = Issue(id="1",
                   number=1,
                   title="Rony",
                   card_id_to_project={"1": {
                       "project_number": 1
                   }})
    issues2 = {"2": issue2}
    project.add_issues(ClientMock, issues2, {"2"}, config)
    assert project.columns['Queue'].cards[0].issue.title == "Rony"
示例#10
0
def test_no_card_content():
    cards = _extract_card_node_data(
        {"cards": {
            "edges": [{
                "node": {
                    "no": "content"
                }
            }]
        }}, Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini')))
    assert len(cards) == 0
示例#11
0
def test_get_matching_column():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()

    issue_queue = Issue(id="1", title="issue 1", number=1)
    assert Project.get_matching_column(issue_queue, config) == 'Queue'

    issue_in_progress = Issue(id="1", title="issue 1", number=1)
    issue_in_progress.add_assignee("Rony")
    assert Project.get_matching_column(issue_in_progress, config) == ''
    issue_in_progress.add_label("Testing")
    assert Project.get_matching_column(issue_in_progress,
                                       config) == 'In progress'

    issue_review_in_progress = Issue(id="1", title="issue 1", number=1)
    issue_review_in_progress.add_assignee("Rony")

    class MockPullRequest(object):
        review_requested = True
        review_completed = False

    issue_review_in_progress.pull_request = MockPullRequest()

    assert Project.get_matching_column(issue_review_in_progress,
                                       config) == 'Review in progress'

    issue_docs = Issue(id="1", title="issue 1", number=1)
    issue_docs.add_assignee("Rony")

    class MockPullRequest2(object):
        review_requested = True
        review_completed = True
        assignees = "ronykoz"

    issue_docs.pull_request = MockPullRequest2()

    assert Project.get_matching_column(issue_docs,
                                       config) == 'Waiting for Docs'

    class MockPullRequest3(object):
        review_requested = True
        review_completed = True
        assignees = "someone"

    issue_docs.pull_request = MockPullRequest3()

    assert Project.get_matching_column(issue_docs,
                                       config) == 'Review in progress'

    # faulty field from issues
    config.column_to_rules["Waiting for Docs"] = {
        "issue.not_existent": "field"
    }
    assert Project.get_matching_column(issue_docs,
                                       config) == 'Review in progress'
示例#12
0
def manage(**kwargs):
    """Manage a GitHub project board"""
    for conf_path in kwargs['conf'].split(','):
        configuration = Configuration(conf_file_path=conf_path,
                                      verbose=kwargs['verbose'],
                                      quiet=kwargs['quiet'],
                                      log_path=kwargs['log_path'])
        configuration.load_properties()
        configuration.logger.info(f'Starting going over the board {conf_path}')
        manager = ProjectManager(configuration=configuration)
        manager.manage()
示例#13
0
    def __init__(self, conf: str, event: str, quiet: bool = False, log_path: str = '', verbose: int = 2,
                 client=None, api_key=None):
        self.config = None
        self.conf_paths = conf.split(',')
        self.quiet = quiet
        self.log_path = log_path
        self.verbose = verbose

        config = Configuration(self.conf_paths[0])
        config.load_general_properties()
        self.project_owner = config.project_owner
        self.repository_name = config.repository_name

        self.event = json.loads(event)
        self.client = client if client else GraphQLClient(api_key)
示例#14
0
    def run(self):
        issue = self.get_issue_object()

        for conf_path in self.conf_paths:
            self.config = Configuration(conf_path, self.verbose, self.quiet, self.log_path)
            self.config.load_properties()

            if (self.config.project_number in issue.get_associated_project() or
                    is_matching_issue(issue.labels, self.config.must_have_labels, self.config.cant_have_labels,
                                      self.config.filter_labels)):
                issue.set_priority(self.config.priority_list)
                self.manage_issue_in_project(issue)

            else:
                self.config.logger.debug(f"The issue does not match the filter provided in the configuration "
                                         f"file {conf_path}.")
示例#15
0
def test_event_manager_flow(mocker):
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()

    project_object = Project(name="project_name",
                             columns={
                                 "In progress":
                                 ProjectColumn(id="some id",
                                               name='In progress',
                                               cards=[])
                             },
                             config=config)
    mocker.patch.object(EventManager,
                        "get_issue_object",
                        return_value=Issue(id="1",
                                           title="this is a test title",
                                           number=1,
                                           assignees=["ronykoz"],
                                           labels=['test', 'Testing', 'bug']))
    mocker.patch.object(EventManager,
                        "load_project_column",
                        return_value=project_object)

    class MockClient(object):
        def add_issues_to_project(*args, **kwargs):
            return {"addProjectCard": {"cardEdge": {"node": {"id": "1"}}}}

        def add_to_column(self, **kwargs):
            return

        def move_to_specific_place_in_column(self, **kwargs):
            return

    client = MockClient()
    manager = EventManager(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'),
                           client=client,
                           event=json.dumps({"text": "text"}))
    manager.run()
    assert len(project_object.get_all_issue_ids()) == 1
示例#16
0
def test_move_issues():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()
    issue = Issue(id="1",
                  title="title",
                  number=1,
                  assignees=["Rony"],
                  labels=["Testing"],
                  card_id_to_project={"sdf": {
                      "project_number": 1
                  }})
    project = Project(name="test project",
                      config=config,
                      columns={
                          "Queue":
                          ProjectColumn(
                              id="id",
                              name="Queue",
                              cards=[IssueCard(id="sdf", issue=issue)]),
                          "In progress":
                          ProjectColumn(id="id", name="In progress", cards=[])
                      })

    class MockClient(object):
        def add_to_column(*args, **kwargs):
            return

        def move_to_specific_place_in_column(*args, **kwargs):
            return

    project.move_issues(MockClient(), config)
    assert project.is_in_column("Queue", "1") is False
    assert project.is_in_column("In progress", "1") is True

    # Move within the same column
    project.move_issues(MockClient(), config)
    assert project.is_in_column("Queue", "1") is False
    assert project.is_in_column("In progress", "1") is True
示例#17
0
def test_get_prev_column():
    event = {"action": "some action", "issue": {"number": 1}}

    project_layout = {
        "repository": {
            "project": {
                "columns": {
                    "edges": [{
                        "cursor": 1,
                        "node": {
                            "name": "Queue"
                        }
                    }, {
                        "cursor": 2,
                        "node": {
                            "name": "In progress"
                        }
                    }]
                }
            }
        }
    }

    class MockClient(object):
        def get_project_layout(*args, **kwargs):
            return project_layout

    client = MockClient()
    manager = EventManager(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'),
                           client=client,
                           event=json.dumps(event))
    manager.config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    manager.config.load_properties()

    assert manager.get_prev_column_cursor("Queue") == ""
    assert manager.get_prev_column_cursor("In progress") == 1
示例#18
0
def test_get_filters():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()

    filters = ProjectManager.get_filters(config)

    assert len(filters) == 1
    assert ' label:bug' in filters[0]
    assert ' label:test' in filters[0]
    assert '-label:not test' in filters[0]

    config.filter_labels = ['one', 'two']
    config.must_have_labels = ['three', 'four||five']
    config.cant_have_labels = ['six', 'seven']
    filters = ProjectManager.get_filters(config)

    assert len(filters) == 4
    for filter_str in filters:
        assert ('label:one' in filter_str and 'label:two'
                not in filter_str) or ('label:one' not in filter_str
                                       and 'label:two' in filter_str)
        assert ('label:four' in filter_str and 'label:five'
                not in filter_str) or ('label:four' not in filter_str
                                       and 'label:five' in filter_str)
示例#19
0
def test_load_project_column():
    event = {"action": "some action", "issue": {"number": 1}}

    project_layout = {
        "repository": {
            "project": {
                "columns": {
                    "edges": [{
                        "cursor": 1,
                        "node": {
                            "name": "Queue"
                        }
                    }, {
                        "cursor": 2,
                        "node": {
                            "name": "In progress"
                        }
                    }]
                }
            }
        }
    }

    project_column1 = {
        "repository": {
            "project": {
                "columns": {
                    "nodes": [{
                        "name": "Queue",
                        "id": "id",
                        "cards": {
                            "pageInfo": {
                                "endCursor": "A",
                                "hasNextPage": True
                            },
                            "edges": [{
                                "cursor": "A",
                                "node": {
                                    "note": None,
                                    "state": "CONTENT_ONLY",
                                    "id": "id=",
                                    "content": {
                                        "id": "id=",
                                        "number": 1,
                                        "title": "title",
                                        "labels": {
                                            "edges": [{
                                                "node": {
                                                    "name": "one"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "two"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "three"
                                                }
                                            }]
                                        }
                                    }
                                }
                            }]
                        },
                    }]
                }
            }
        }
    }
    project_column1_no_after = deepcopy(project_column1)
    project_column1_no_after['repository']['project']['columns']['nodes'][0][
        'cards']['pageInfo']['hasNextPage'] = False

    project_column2 = {
        "repository": {
            "project": {
                "columns": {
                    "nodes": [{
                        "name": "In progress",
                        "id": "id",
                        "cards": {
                            "pageInfo": {
                                "endCursor": "B",
                                "hasNextPage": True
                            },
                            "edges": [{
                                "cursor": "B",
                                "node": {
                                    "note": None,
                                    "state": "CONTENT_ONLY",
                                    "id": "cardid2=",
                                    "content": {
                                        "id": "id2=",
                                        "number": 2,
                                        "title": "title2",
                                        "labels": {
                                            "edges": [{
                                                "node": {
                                                    "name": "one"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "two"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "three"
                                                }
                                            }]
                                        }
                                    }
                                }
                            }]
                        },
                    }]
                }
            }
        }
    }

    project_column2_no_after = deepcopy(project_column2)
    project_column2_no_after['repository']['project']['columns']['nodes'][0][
        'cards']['pageInfo']['hasNextPage'] = False

    issue_id = "=asdf=sdf="
    title = "issue name"
    labels = ["test", "Low", "bug", "Testing"]
    assignee = "ronykoz"

    issue = {
        "repository": {
            "issue": {
                "projectCards": {
                    "nodes": [{
                        "id": "idadded=",
                        "project": {
                            "number": 1,
                            "columns": {
                                "nodes": [{
                                    "name": "testing"
                                }]
                            }
                        }
                    }, {
                        "id": "id2=",
                        "project": {
                            "number": 2,
                            "columns": {
                                "nodes": [{
                                    "name": "Queue"
                                }]
                            }
                        }
                    }]
                },
                "comments": {
                    "nodes": [{
                        "author": {
                            "login": "******"
                        },
                        "body": "comment 1",
                        "createdAt": "2019-03-19T12:24:27Z"
                    }, {
                        "author": {
                            "login": "******"
                        },
                        "body": "second comment",
                        "createdAt": "2019-03-19T12:27:53Z"
                    }, {
                        "author": {
                            "login": "******"
                        },
                        "body": "third comment",
                        "createdAt": "2019-03-19T12:52:08Z"
                    }]
                },
                "timelineItems": {
                    "__typename":
                    "IssueTimelineItemsConnection",
                    "nodes": [{
                        "__typename": "LabeledEvent",
                        "label": {
                            "name": labels[0]
                        },
                        "createdAt": "2019-03-15T12:40:22Z"
                    }, {
                        "__typename": "LabeledEvent",
                        "label": {
                            "name": labels[1]
                        },
                        "createdAt": "2019-03-17T13:59:27Z"
                    }, {
                        "__typename": "LabeledEvent",
                        "label": {
                            "name": labels[2]
                        },
                        "createdAt": "2019-04-08T10:48:02Z"
                    }]
                },
                "title": title,
                "id": issue_id,
                "number": 1,
                "milestone": {
                    "title": "test"
                },
                "labels": {
                    "edges": [{
                        "node": {
                            "name": labels[0]
                        }
                    }, {
                        "node": {
                            "name": labels[1]
                        }
                    }, {
                        "node": {
                            "name": labels[2]
                        }
                    }, {
                        "node": {
                            "name": labels[3]
                        }
                    }]
                },
                "assignees": {
                    "edges": [{
                        "node": {
                            "login": assignee
                        }
                    }]
                }
            }
        }
    }

    class MockClient(object):
        def add_issues_to_project(self, **kwargs):
            return {
                "addProjectCard": {
                    "cardEdge": {
                        "node": {
                            "id": "idadded="
                        }
                    }
                }
            }

        def add_to_column(self, **kwargs):
            return

        def move_to_specific_place_in_column(self, **kwargs):
            return

        def get_issue(*args, **kwargs):
            return issue

        def delete_project_card(*args, **kwargs):
            return

        def get_project_layout(*args, **kwargs):
            return project_layout

        def get_first_column_issues(*args, **kwargs):
            if 'start_cards_cursor' in kwargs:
                return project_column1_no_after

            return project_column1

        def get_column_issues(*args, **kwargs):
            if 'start_cards_cursor' in kwargs:
                return project_column2_no_after

            return project_column2

    client = MockClient()
    manager = EventManager(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'),
                           client=client,
                           event=json.dumps(event))
    manager.config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    manager.config.load_properties()

    project1 = manager.load_project_column("Queue")
    assert project1.columns["Queue"].name == "Queue"
    assert len(project1.columns["Queue"].cards) == 2
    assert project1.columns["Queue"].cards[0].issue.title == "title"
    assert project1.columns["Queue"].cards[0].id == "id="

    project2 = manager.load_project_column("In progress")
    assert project2.columns["In progress"].name == "In progress"
    assert len(project2.columns["In progress"].cards) == 2
    assert project2.columns["In progress"].cards[0].issue.title == "title2"
    assert project2.columns["In progress"].get_card_id("id2=") == "cardid2="
示例#20
0
def test_project():
    project = Project(**parse_project({
        "name": "test",
        "columns": {
            "nodes": [
                {
                    "name": "Queue",
                    "id": "1234",
                    "cards": {
                          "pageInfo": {
                              "hasNextPage": True,
                              "endCursor": "MQ"
                          },
                        "edges": [
                              {
                                  "cursor": "MQ",
                                  "node": {
                                      "note": None,
                                      "state": "CONTENT_ONLY",
                                      "id": "3434=",
                                      "content": {
                                          "__typename": "Issue",
                                          "id": "1234=",
                                          "number": 1,
                                          "title": "issue 1",
                                          "labels": {
                                              "edges": [
                                                  {
                                                      "node": {
                                                          "name": "High"
                                                      }
                                                  },
                                                  {
                                                      "node": {
                                                          "name": "bug"
                                                      }
                                                  }
                                              ]
                                          },
                                          "assignees": {
                                              "edges": []
                                          }
                                      }
                                  }
                              }
                          ]
                    }
                },
                {
                    "name": "Review in progress",
                    "id": "5656",
                    "cards": {
                          "pageInfo": {
                              "hasNextPage": True,
                              "endCursor": "MQ"
                          },
                        "edges": [
                              {
                                  "cursor": "MQ",
                                  "node": {
                                      "note": None,
                                      "state": "CONTENT_ONLY",
                                      "id": "56565=",
                                      "content": {
                                          "__typename": "Issue",
                                          "id": "5656=",
                                          "number": 15,
                                          "title": "issue 2",
                                          "labels": {
                                              "edges": [
                                                  {
                                                      "node": {
                                                          "name": "Medium"
                                                      }
                                                  },
                                                  {
                                                      "node": {
                                                          "name": "bug"
                                                      }
                                                  }
                                              ]
                                          },
                                          "assignees": {
                                              "edges": [
                                                  {
                                                      "node": {
                                                          "id": "234",
                                                          "login": "******"
                                                      }
                                                  }
                                              ]
                                          }
                                      }
                                  }
                              }
                          ]
                    }
                }
            ]
        }
    }, Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))))

    assert len(project.get_all_item_ids()) == 2
    assert len(project.columns.keys()) == 2

    assert project.columns['Queue'].name == 'Queue'
    assert project.columns['Queue'].cards[0].item_title == 'issue 1'

    assert project.columns['Review in progress'].name == 'Review in progress'
    assert project.columns['Review in progress'].cards[0].item_title == 'issue 2'
示例#21
0
def test_add_card_to_column():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()

    config.priority_list = DEFAULT_PRIORITY_LIST
    column_object = ProjectColumn(id="id", name="Review in progress",
                                  cards=[
                                      ItemCard(id="sdf",
                                               item=Issue(id="sdf", title="issue 2", number=2, labels=["Low"])),
                                      ItemCard(id="sdf2",
                                               item=Issue(id="sdf2", title="issue 3", number=3, labels=["High"]))
                                  ])
    issue_to_inject = Issue(
        id="4",
        title="issue 4",
        number=4,
        labels=['Medium']
    )
    issue_to_inject.set_priority(DEFAULT_PRIORITY_LIST)

    class MockClient(object):
        def add_to_column(*args, **kwargs):
            return

        def move_to_specific_place_in_column(*args, **kwargs):
            return

    mock_client = MockClient()

    # Sorting
    column_object.sort_cards(mock_client, config)
    card_titles_in_column = [card.item.title for card in column_object.cards]
    assert card_titles_in_column == ['issue 3', 'issue 2']

    # Adding in the middle
    column_object.add_card("id", issue_to_inject, mock_client)
    card_titles_in_column = [card.item.title for card in column_object.cards]
    assert card_titles_in_column == ['issue 3', 'issue 4', 'issue 2']

    # Higher priority addition
    issue_to_inject2 = Issue(
        id="5",
        title="issue 5",
        number=5,
        labels=['Critical']
    )
    issue_to_inject2.set_priority(DEFAULT_PRIORITY_LIST)

    column_object.add_card("id", issue_to_inject2, mock_client)
    card_titles_in_column = [card.item.title for card in column_object.cards]
    assert card_titles_in_column == ['issue 5', 'issue 3', 'issue 4', 'issue 2']

    # Lower priority addition
    pr_to_inject3 = PullRequest(
        id="6",
        title="pull request 6",
        number=6
    )

    column_object.add_card("id", pr_to_inject3, mock_client)
    card_titles_in_column = [card.item.title for card in column_object.cards]
    assert card_titles_in_column == ['issue 5', 'issue 3', 'issue 4', 'issue 2', "pull request 6"]

    # Same priority different number
    pr_to_inject4 = PullRequest(
        id="7",
        title="pull request 7",
        number=-1,
    )

    column_object.add_card("id", pr_to_inject4, mock_client)
    card_titles_in_column = [card.item.title for card in column_object.cards]
    assert card_titles_in_column == ['issue 5', 'issue 3', 'issue 4', 'issue 2', "pull request 7", "pull request 6"]
示例#22
0
def test_loading():
    project_layout = {
        "repository": {
            "project": {
                "columns": {
                    "edges": [{
                        "cursor": 1,
                        "node": {
                            "name": "Queue"
                        }
                    }, {
                        "cursor": 2,
                        "node": {
                            "name": "Review in progress"
                        }
                    }]
                }
            }
        }
    }

    column1 = {
        "repository": {
            "project": {
                "name": "test",
                "columns": {
                    "nodes": [{
                        "name": "Queue",
                        "id": "1234",
                        "cards": {
                            "pageInfo": {
                                "hasNextPage": False,
                                "endCursor": "MQ"
                            },
                            "edges": [{
                                "cursor": "MQ",
                                "node": {
                                    "note": None,
                                    "state": "CONTENT_ONLY",
                                    "id": "3434=",
                                    "content": {
                                        "id": "1234=",
                                        "number": 1,
                                        "title": "issue 1",
                                        "labels": {
                                            "edges": [{
                                                "node": {
                                                    "name": "High"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "bug"
                                                }
                                            }]
                                        },
                                        "assignees": {
                                            "edges": []
                                        }
                                    }
                                }
                            }]
                        }
                    }]
                }
            }
        }
    }
    column2 = {
        "repository": {
            "project": {
                "name": "test",
                "columns": {
                    "nodes": [{
                        "name": "In progress",
                        "id": "5656",
                        "cards": {
                            "pageInfo": {
                                "hasNextPage": False,
                                "endCursor": "MQ"
                            },
                            "edges": [{
                                "cursor": "MQ",
                                "node": {
                                    "note": None,
                                    "state": "CONTENT_ONLY",
                                    "id": "56565=",
                                    "content": {
                                        "id": "56567=",
                                        "number": 15,
                                        "title": "issue 2",
                                        "labels": {
                                            "edges": [{
                                                "node": {
                                                    "name": "Medium"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "bug"
                                                }
                                            }]
                                        },
                                        "assignees": {
                                            "edges": [{
                                                "node": {
                                                    "id": "234",
                                                    "login": "******"
                                                }
                                            }]
                                        }
                                    }
                                }
                            }, {
                                "cursor": "MB",
                                "node": {
                                    "note": None,
                                    "state": "CONTENT_ONLY",
                                    "id": "123=",
                                    "content": {
                                        "id": "1234=",
                                        "number": 3,
                                        "title": "issue 3",
                                        "labels": {
                                            "edges": [{
                                                "node": {
                                                    "name": "High"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "bug"
                                                }
                                            }]
                                        },
                                        "assignees": {
                                            "edges": [{
                                                "node": {
                                                    "id": "234",
                                                    "login": "******"
                                                }
                                            }]
                                        }
                                    }
                                }
                            }]
                        }
                    }]
                }
            }
        }
    }

    issue_id = "=asdf=sdf="
    title = "issue name"
    labels = ["HighEffort", "Critical", "bug", "test", "Testing"]
    issue = {
        "projectCards": {
            "nodes": [{
                "id": "id=",
                "project": {
                    "number": 1,
                    "columns": {
                        "nodes": [{
                            "name": "testing"
                        }]
                    }
                }
            }, {
                "id": "id2=",
                "project": {
                    "number": 2,
                    "columns": {
                        "nodes": [{
                            "name": "Queue"
                        }]
                    }
                }
            }]
        },
        "comments": {
            "nodes": [{
                "author": {
                    "login": "******"
                },
                "body": "comment 1",
                "createdAt": "2019-03-19T12:24:27Z"
            }, {
                "author": {
                    "login": "******"
                },
                "body": "second comment",
                "createdAt": "2019-03-19T12:27:53Z"
            }, {
                "author": {
                    "login": "******"
                },
                "body": "third comment",
                "createdAt": "2019-03-19T12:52:08Z"
            }]
        },
        "timelineItems": {
            "__typename":
            "IssueTimelineItemsConnection",
            "nodes": [{
                "__typename": "LabeledEvent",
                "label": {
                    "name": labels[0]
                },
                "createdAt": "2019-03-15T12:40:22Z"
            }, {
                "__typename": "LabeledEvent",
                "label": {
                    "name": labels[1]
                },
                "createdAt": "2019-03-17T13:59:27Z"
            }, {
                "__typename": "LabeledEvent",
                "label": {
                    "name": labels[2]
                },
                "createdAt": "2019-04-08T10:48:02Z"
            }]
        },
        "title": title,
        "id": issue_id,
        "number": 1,
        "milestone": {
            "title": "test"
        },
        "labels": {
            "edges": [{
                "node": {
                    "name": labels[0]
                }
            }, {
                "node": {
                    "name": labels[1]
                }
            }, {
                "node": {
                    "name": labels[2]
                }
            }, {
                "node": {
                    "name": labels[3]
                }
            }, {
                "node": {
                    "name": labels[4]
                }
            }]
        },
        "assignees": {
            "edges": [{
                "node": {
                    "login": "******"
                }
            }]
        }
    }

    issues = {
        "search": {
            "pageInfo": {
                "hasNextPage": True,
                "endCursor": "cursor"
            },
            "edges": [{
                "node": issue
            }]
        }
    }
    issues_with_no_after = {
        "search": {
            "pageInfo": {
                "hasNextPage": False,
                "endCursor": "cursor"
            },
            "edges": [{
                "node": issue
            }]
        }
    }

    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()
    config.sort = True

    class MockClient(object):
        def delete_project_card(*args, **kwargs):
            return

        def add_issues_to_project(self, **kwargs):
            return {"addProjectCard": {"cardEdge": {"node": {"id": "id="}}}}

        def get_project_layout(self, **kwargs):
            return project_layout

        def get_first_column_issues(self, **kwargs):
            return column1

        def get_column_issues(self, **kwargs):
            return column2

        def search_issues_by_query(self, **kwargs):
            if 'start_cursor' not in kwargs:
                return issues

            return issues_with_no_after

        def add_to_column(self, **kwargs):
            return

        def move_to_specific_place_in_column(self, **kwargs):
            return

    client = MockClient()
    manager = ProjectManager(configuration=config, client=client)

    assert len(manager.matching_issues) == 1
    assert manager.project.name == 'test'
    assert manager.project.get_current_location("56567=") == ("In progress",
                                                              "56565=")
    assert manager.project.get_current_location("Random text") == (None, None)
    assert manager.project.is_in_column("In progress", "56567=") is True
    assert manager.project.is_in_column("In progress", "Random text") is False

    manager.project.sort_issues_in_columns(client, config)
    issues = [
        card.issue.title
        for card in manager.project.columns['In progress'].cards
    ]
    assert issues == ['issue 3', 'issue 2']

    manager.project.columns['In progress'].remove_card("56565=")
    assert manager.project.is_in_column("In progress", "56567=") is False

    manager.manage()
    assert manager.project.is_in_column("In progress", issue_id) is True
    assert manager.project.columns["In progress"].cards[0].issue.id == issue_id
示例#23
0
def test_move_items():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()
    issue = Issue(id="1",
                  title="title",
                  number=1,
                  assignees=["Rony"],
                  labels=["Testing"],
                  card_id_to_project={
                      "sdf": {
                          "project_number": 1
                      }
                  }
                  )
    pull_request = PullRequest(id="10",
                               title="title",
                               number=10,
                               assignees=["Daud"],
                               labels=["Testing"],
                               card_id_to_project={
                                   "dsf": {
                                       "project_number": 1
                                   }
                               })
    project = Project(
        name="test project",
        config=config,
        columns={
            "Queue": ProjectColumn(id="id", name="Queue",
                                   cards=[ItemCard(id="sdf",
                                                   item=issue),
                                          ItemCard(id="dsf",
                                                   item=pull_request)
                                          ]),
            "In progress": ProjectColumn(id="id", name="In progress", cards=[])
        }
    )

    class MockClient(object):
        def add_to_column(*args, **kwargs):
            return

        def move_to_specific_place_in_column(*args, **kwargs):
            return

    project.move_items(MockClient(), config, {'1': issue})
    assert project.is_in_column("Queue", "1") is False
    assert project.is_in_column("In progress", "1") is True

    project.move_items(MockClient(), config, {'10': pull_request})
    assert project.is_in_column("Queue", "10") is False
    assert project.is_in_column("In progress", "10") is True

    # Move within the same column
    project.move_items(MockClient(), config, {'1': issue})
    assert project.is_in_column("Queue", "1") is False
    assert project.is_in_column("In progress", "1") is True

    issue.state = 'closed'
    project.move_item(MockClient(), issue, 'In progress', config)
    assert project.is_in_column("In progress", "1") is True
示例#24
0
def test_loading_repo_project():
    project_layout = {
        "repository": {
            "project": {
                "columns": {
                    "edges": [{
                        "cursor": 1,
                        "node": {
                            "name": "Queue"
                        }
                    }, {
                        "cursor": 2,
                        "node": {
                            "name": "Review in progress"
                        }
                    }]
                }
            }
        }
    }

    column1 = {
        "repository": {
            "project": {
                "name": "test",
                "columns": {
                    "nodes": [{
                        "name": "Queue",
                        "id": "1234",
                        "cards": {
                            "pageInfo": {
                                "hasNextPage": False,
                                "endCursor": "MQ"
                            },
                            "edges": [{
                                "cursor": "MQ",
                                "node": {
                                    "note": None,
                                    "state": "CONTENT_ONLY",
                                    "id": "3434=",
                                    "content": {
                                        "__typename": "Issue",
                                        "id": "1234=",
                                        "number": 1,
                                        "title": "issue 1",
                                        "labels": {
                                            "edges": [{
                                                "node": {
                                                    "name": "High"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "bug"
                                                }
                                            }]
                                        },
                                        "assignees": {
                                            "edges": []
                                        }
                                    }
                                }
                            }]
                        }
                    }]
                }
            }
        }
    }
    column2 = {
        "repository": {
            "project": {
                "name": "test",
                "columns": {
                    "nodes": [{
                        "name": "In progress",
                        "id": "5656",
                        "cards": {
                            "pageInfo": {
                                "hasNextPage": False,
                                "endCursor": "MQ"
                            },
                            "edges": [{
                                "cursor": "MQ",
                                "node": {
                                    "note": None,
                                    "state": "CONTENT_ONLY",
                                    "id": "56565=",
                                    "content": {
                                        "__typename": "Issue",
                                        "id": "56567=",
                                        "number": 15,
                                        "title": "issue 2",
                                        "labels": {
                                            "edges": [{
                                                "node": {
                                                    "name": "Medium"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "bug"
                                                }
                                            }]
                                        },
                                        "assignees": {
                                            "edges": [{
                                                "node": {
                                                    "id": "234",
                                                    "login": "******"
                                                }
                                            }]
                                        }
                                    }
                                }
                            }, {
                                "cursor": "MB",
                                "node": {
                                    "note": None,
                                    "state": "CONTENT_ONLY",
                                    "id": "123=",
                                    "content": {
                                        "__typename": "Issue",
                                        "id": "1234=",
                                        "number": 3,
                                        "title": "issue 3",
                                        "labels": {
                                            "edges": [{
                                                "node": {
                                                    "name": "High"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "bug"
                                                }
                                            }]
                                        },
                                        "assignees": {
                                            "edges": [{
                                                "node": {
                                                    "id": "234",
                                                    "login": "******"
                                                }
                                            }]
                                        }
                                    }
                                }
                            }, {
                                "cursor": "HZ",
                                "node": {
                                    "note": None,
                                    "state": "CONTENT_ONLY",
                                    "id": "76565=",
                                    "content": {
                                        "__typename": "PullRequest",
                                        "title": "pull_request 1",
                                        "id": "76566=",
                                        "state": "OPEN",
                                        "number": 20,
                                        "mergedAt": None,
                                        "merged": False,
                                        "reviewDecision": None,
                                        "reviews": {
                                            "totalCount": 0
                                        },
                                        "reviewRequests": {
                                            "totalCount": 0
                                        },
                                        "labels": {
                                            "edges": [{
                                                "node": {
                                                    "name": "Medium"
                                                }
                                            }, {
                                                "node": {
                                                    "name": "bug"
                                                }
                                            }]
                                        },
                                        "assignees": {
                                            "edges": [{
                                                "node": {
                                                    "id": "334",
                                                    "login": "******"
                                                }
                                            }]
                                        }
                                    }
                                }
                            }]
                        }
                    }]
                }
            }
        }
    }

    pr_id = "=zxcx=sads="
    pr_title = "pr name"
    labels = ["HighEffort", "Critical", "bug", "test", "Testing"]
    assignee = "daud"

    pull_request = {
        "projectCards": {
            "nodes": [{
                "id": "id=",
                "column": {
                    "name": "testing"
                },
                "project": {
                    "number": 1
                }
            }, {
                "id": "id2=",
                "column": {
                    "name": "Queue"
                },
                "project": {
                    "number": 2
                }
            }]
        },
        "title": pr_title,
        "id": pr_id,
        "number": 1,
        "state": "MERGED",
        "mergedAt": "2021-01-25T15:27:08Z",
        "merged": True,
        "reviewDecision": None,
        "reviews": {
            "totalCount": 0
        },
        "reviewRequests": {
            "totalCount": 1
        },
        "labels": {
            "edges": [{
                "node": {
                    "name": labels[0]
                }
            }, {
                "node": {
                    "name": labels[1]
                }
            }, {
                "node": {
                    "name": labels[2]
                }
            }, {
                "node": {
                    "name": labels[3]
                }
            }]
        },
        "assignees": {
            "edges": [{
                "node": {
                    "login": assignee
                }
            }]
        }
    }

    issue_id = "=asdf=sdf="
    issue_title = "issue name"
    issue = {
        "projectCards": {
            "nodes": [{
                "id": "id=",
                "column": {
                    "name": "Queue"
                },
                "project": {
                    "number": 1
                }
            }, {
                "id": "id2=",
                "column": {
                    "name": "In progress"
                },
                "project": {
                    "number": 2
                }
            }]
        },
        "comments": {
            "nodes": [{
                "author": {
                    "login": "******"
                },
                "body": "comment 1",
                "createdAt": "2019-03-19T12:24:27Z"
            }, {
                "author": {
                    "login": "******"
                },
                "body": "second comment",
                "createdAt": "2019-03-19T12:27:53Z"
            }, {
                "author": {
                    "login": "******"
                },
                "body": "third comment",
                "createdAt": "2019-03-19T12:52:08Z"
            }]
        },
        "timelineItems": {
            "__typename":
            "IssueTimelineItemsConnection",
            "nodes": [{
                "__typename": "LabeledEvent",
                "label": {
                    "name": labels[0]
                },
                "createdAt": "2019-03-15T12:40:22Z"
            }, {
                "__typename": "LabeledEvent",
                "label": {
                    "name": labels[1]
                },
                "createdAt": "2019-03-17T13:59:27Z"
            }, {
                "__typename": "LabeledEvent",
                "label": {
                    "name": labels[2]
                },
                "createdAt": "2019-04-08T10:48:02Z"
            }]
        },
        "title": issue_title,
        "id": issue_id,
        "number": 1,
        "milestone": {
            "title": "test"
        },
        "labels": {
            "edges": [{
                "node": {
                    "name": labels[0]
                }
            }, {
                "node": {
                    "name": labels[1]
                }
            }, {
                "node": {
                    "name": labels[2]
                }
            }, {
                "node": {
                    "name": labels[3]
                }
            }, {
                "node": {
                    "name": labels[4]
                }
            }]
        },
        "assignees": {
            "edges": [{
                "node": {
                    "login": "******"
                }
            }]
        }
    }

    items = {
        "repository": {
            "issues": {
                "pageInfo": {
                    "hasNextPage": True,
                    "endCursor": "cursor"
                },
                "edges": [{
                    "node": issue
                }]
            }
        }
    }
    issues_with_no_after = {
        "repository": {
            "issues": {
                "pageInfo": {
                    "hasNextPage": False,
                    "endCursor": "cursor"
                },
                "edges": [{
                    "node": issue
                }]
            }
        }
    }

    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()
    config.sort = True

    class MockClient(object):
        def delete_project_card(*args, **kwargs):
            return

        def add_issues_to_project(self, **kwargs):
            return {"addProjectCard": {"cardEdge": {"node": {"id": "id="}}}}

        def get_project_layout(self, **kwargs):
            return project_layout

        def get_first_column_items(self, **kwargs):
            return column1

        def get_column_items(self, **kwargs):
            return column2

        def get_github_issues(self, **kwargs):
            if not kwargs['after']:
                return items

            return issues_with_no_after

        def add_to_column(self, **kwargs):
            return

        def move_to_specific_place_in_column(self, **kwargs):
            return

        def get_github_pull_requests(self, **kwargs):
            return {
                "repository": {
                    "pullRequests": {
                        "pageInfo": {
                            "endCursor": "cursor",
                            "hasNextPage": False
                        },
                        "edges": [{
                            "node": pull_request,
                        }]
                    }
                }
            }

    client = MockClient()
    manager = ProjectManager(configuration=config, client=client)

    assert len(manager.matching_issues) == 1
    assert len(manager.matching_pull_requests) == 1
    assert manager.project.name == 'test'
    assert manager.project.get_current_location("56567=") == ("In progress",
                                                              "56565=")
    assert manager.project.get_current_location("Random text") == (None, None)
    assert manager.project.is_in_column("In progress", "56567=") is True
    assert manager.project.is_in_column("In progress", "Random text") is False

    # assert there're 3 items 'In Progress' column
    manager.project.sort_items_in_columns(client, config)
    items = [
        card.item.title
        for card in manager.project.columns['In progress'].cards
    ]
    assert items == ['issue 3', 'issue 2', "pull_request 1"]

    # remove a single issue from the column
    manager.project.columns['In progress'].remove_card("56565=")
    items = [
        card.item.title
        for card in manager.project.columns['In progress'].cards
    ]
    assert len(items) == 2
    assert manager.project.is_in_column("In progress", "1234=") is True
    assert manager.project.is_in_column("In progress", "76566=") is True
    assert manager.project.is_in_column("In progress", "56565=") is False

    # remove a single pull request from the column
    manager.project.columns['In progress'].remove_card("76565=")
    items = [
        card.item.title
        for card in manager.project.columns['In progress'].cards
    ]
    assert len(items) == 1
    assert manager.project.is_in_column("In progress", "1234=") is True
    assert manager.project.is_in_column("In progress", "76566=") is False

    manager.manage()
    assert manager.project.is_in_column("In progress", "56565=") is False