示例#1
0
def test_removing_issues():
    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=1))
                                        ]),
                          "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="1")
    issues = {1: issue}

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

    project.remove_issues(ClientMock, issues, config)
    assert project.get_all_issue_ids() == set()
示例#2
0
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']
示例#3
0
def test_missing_issues():
    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=1))
                                        ]),
                          "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="2", number=2, title="issue title")
    issues = {"2": issue}
    assert project.find_missing_issue_ids(issues) == {"2"}
示例#4
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"
示例#5
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()
        manager = ProjectManager(configuration=configuration)
        manager.manage()
示例#6
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'
def test_matching_issue_filter():
    config = Configuration(os.path.join(MOCK_FOLDER_PATH, 'conf.ini'))
    config.load_properties()

    assert EventManager.is_matching_issue(['test'], config.must_have_labels,
                                          config.cant_have_labels) is True
    assert EventManager.is_matching_issue(['not test'],
                                          config.must_have_labels,
                                          config.cant_have_labels) is False
    assert EventManager.is_matching_issue(['not test', 'test'],
                                          config.must_have_labels,
                                          config.cant_have_labels) is False
示例#8
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
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']))
    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
示例#10
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=[
                                      IssueCard(id="sdf",
                                                issue=Issue(id="sdf",
                                                            title="issue 2",
                                                            number=2,
                                                            labels=["Low"])),
                                      IssueCard(id="sdf3",
                                                issue=Issue(id="sdf",
                                                            title="issue 4",
                                                            number=4,
                                                            labels=["Medium"
                                                                    ])),
                                      IssueCard(id="sdf2",
                                                issue=Issue(id="sdf2",
                                                            title="issue 3",
                                                            number=3,
                                                            labels=["High"]))
                                  ])

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

    assert card_titles_in_column == ['issue 3', "issue 4", 'issue 2']
示例#11
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(), {"1": issue}, 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(), {"1": issue}, config)
    assert project.is_in_column("Queue", "1") is False
    assert project.is_in_column("In progress", "1") is True
示例#12
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=[
                                      IssueCard(id="sdf",
                                                issue=Issue(id="sdf",
                                                            title="issue 2",
                                                            number=2,
                                                            labels=["Low"])),
                                      IssueCard(id="sdf2",
                                                issue=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.issue.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.issue.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.issue.title for card in column_object.cards]
    assert card_titles_in_column == [
        'issue 5', 'issue 3', 'issue 4', 'issue 2'
    ]

    # Lower priority addition
    issue_to_inject3 = Issue(id="6", title="issue 6", number=6)

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

    # Same priority different number
    issue_to_inject4 = Issue(
        id="7",
        title="issue 7",
        number=-1,
    )

    column_object.add_card("id", issue_to_inject4, mock_client)
    card_titles_in_column = [card.issue.title for card in column_object.cards]
    assert card_titles_in_column == [
        'issue 5', 'issue 3', 'issue 4', 'issue 2', "issue 7", "issue 6"
    ]
示例#13
0
class EventManager(object):
    DEFAULT_PRIORITY_LIST = ['Critical', 'High', 'Medium', 'Low']

    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)

    @staticmethod
    def is_matching_issue(issue_labels, must_have_labels, cant_have_labels):
        for label in must_have_labels:
            if label not in issue_labels:
                return False

        for label in cant_have_labels:
            if label in issue_labels:
                return False

        return True

    @staticmethod
    def get_issue_number(event):
        return event['issue']['number']

    def get_prev_column_cursor(self, column_name):
        layout = self.client.get_project_layout(
            owner=self.config.project_owner,
            repository_name=self.config.repository_name,
            project_number=self.config.project_number)

        prev_cursor = ''
        column_edges = layout['repository']['project']['columns']['edges']
        for index, column in enumerate(column_edges):
            if column_name == column['node']['name']:
                if index != 0:
                    prev_cursor = column_edges[index - 1]['cursor']

        return prev_cursor

    def load_project_column(self, column_name):
        prev_cursor = self.get_prev_column_cursor(column_name)
        if prev_cursor:
            response = get_column_issues_with_prev_column(
                self.client, self.config, prev_cursor)

        else:
            response = get_first_column_issues(self.client, self.config)

        return Project(
            **parse_project(response.get("repository", {}).get('project', {}),
                            config=self.config))

    def manage_issue_in_project(self, issue):
        if (self.config.remove and self.config.project_number
                in issue.get_associated_project()
                and not self.is_matching_issue(issue.labels,
                                               self.config.must_have_labels,
                                               self.config.cant_have_labels)):

            card_id = [
                _id for _id, value in issue.card_id_project.items()
                if value['project_number'] == self.config.project_number
            ][0]
            Project.remove_issue(self.client, issue.title, card_id,
                                 self.config)
            return

        matching_column_name = Project.get_matching_column(issue, self.config)
        project = self.load_project_column(matching_column_name)

        if self.config.add and self.config.project_number not in issue.get_associated_project(
        ):
            project.add_issue(self.client, issue, matching_column_name,
                              self.config)
            return

        if (self.config.add and not all(project.get_current_location(
                issue.id))  # The issue is in the triage
                or self.config.move):
            column_name_before, _ = project.get_current_location(issue.id)
            if column_name_before != matching_column_name:
                project.move_issue(self.client, issue, matching_column_name,
                                   self.config)
                return

        if self.config.sort:
            column_name_before, _ = project.get_current_location(issue.id)
            if column_name_before == matching_column_name:
                project.columns[matching_column_name].sort_cards(
                    self.client, self.config)

            return

    def get_issue_object(self):
        issue_number = self.get_issue_number(self.event)
        issue_response = self.client.get_issue(
            self.project_owner, self.repository_name,
            issue_number)  # need to address the remove here
        issue = Issue(**parse_issue(issue_response['repository']['issue']))
        return issue

    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 self.is_matching_issue(issue.labels,
                                              self.config.must_have_labels,
                                              self.config.cant_have_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}.")
示例#14
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 = {
        "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_issues(self, **kwargs):
            return column1

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

        def get_github_issues(self, **kwargs):
            if not kwargs['after']:
                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