Source code for robota_core.logic

import datetime
from typing import List, Union

from robota_core.commit import Commit


[docs]def is_date_before_other_dates(query_date: datetime.datetime, deadline: datetime.datetime, key_date: datetime.datetime) -> bool: """Determine whether an action was before the deadline and another key date. :param query_date: The date of the action in question, e.g. when was an issue assigned, time estimate set, or due date set. :param deadline: The deadline of the action :param key_date: The query date should be before this significant date, as well as the deadline e.g. branch creation date :return: True if issue query_date was before deadline and key_date else False. """ if query_date is not None and key_date is not None: assert key_date is not query_date if not query_date: return False if query_date < deadline: if not key_date: return True elif query_date < key_date: return True else: return False else: return False
[docs]def get_first_feature_commit(base_commits: List[Commit], feature_commits: List[Commit]) -> Union[Commit, None]: """Get the first commit on a feature branch. Determine first commit by looking for branching points, described by the parent commits. All parameters are lists of commit IDs ordered from newest to oldest :param base_commits: commits from base branch (usually master) :param feature_commits: commits from feature branch :return first_feature_commit: commit ID of first commit on feature """ # No feature branch commits in specified time range if not feature_commits: return None # To be certain that we have the first commit on feature, # there must be a commit common to both lists. if feature_commits[-1] != base_commits[-1]: raise AssertionError('The oldest commit in each list must be common to both branches.') # First check for unmerged feature branch # If last feature commit is not in base commits then the feature branch is unmerged if feature_commits[0] not in base_commits: # Now loop through commits and look at their parents. # The parent that is in base is the branching point for commit in feature_commits: if Commit({"id": commit.parent_ids[0]}, "dict") in base_commits: # If a parent is found in base then the commit is the first on the feature branch. return commit raise AssertionError("Feature branch not connected to master branch.") # Feature commit is in both feature and base, so feature parent must be # parent to a base commit too. Test for merged feature by looking for merge commit: for feature_commit in feature_commits: if find_feature_parent(feature_commit, base_commits): return feature_commit # All feature commits have been tested and neither an unmerged feature # branch, nor a merged feature with merge commit were found. # This is a FAST-FORWARD MERGE, so return the second commit on the feature branch # (the two lists of feature branch commits contains one extra, # earlier commit each so that we can always find a common commit). return feature_commits[-2]
[docs]def find_feature_parent(feature_commit: Commit, base_commits: List[Commit]) -> bool: """Determine whether the provided feature commit has a commit in the base branch with a common parent. :param feature_commit: The feature commit being checked. :param base_commits: A list of the base commits, most recent first. :returns: True if feature_commit has a common parent with a commit in the base branch else False. """ base_commit = base_commits[0] while True: try: feature_parent = feature_commit.parent_ids[0] except IndexError: feature_parent = None if feature_parent in base_commit.parent_ids and base_commit != feature_commit: return True # The first parent is always the branch being merged into - the base branch try: base_commit = find_commit_in_list(base_commit.parent_ids[0], base_commits) except IndexError: base_commit = None if not base_commit: # If we have gone through all of the base commits and not found feature_parent then # this feature commit is not the first in the feature branch return False
[docs]def find_commit_in_list(commit_id: str, commits: List[Commit]) -> Union[None, Commit]: """Find a Commit in a list of Commits by its ID. :param commit_id: The id of the commit to find. :param commits: The list of Commits to search. :return: Commit if found, else None. """ for commit in commits: if commit.id == commit_id: return commit return None
[docs]def fixup_first_feature_commit(feature_branch_commits: List[Commit], initial_guess_of_first_commit: Commit, merge_commits: List[Commit]): """Fix-up function to look for merge commits on master branch before the tip of the feature branch. Any commits up to and including a merge commit in the history of a feature branch cannot be the first commit on the feature branch. :param feature_branch_commits: :return: """ # next_commit means next chronologically, rather than next in the list of commits, # which is ordered newest to oldest. branch_tip = feature_branch_commits[0] next_commit = None for commit in feature_branch_commits: if commit in merge_commits and commit is not branch_tip: if next_commit: return next_commit else: return commit next_commit = commit else: return initial_guess_of_first_commit
[docs]def date_is_before(date1: datetime.datetime, date2: datetime.datetime) -> bool: """If date1 and date2 are provided and date1 is before date2 return True, else return False.""" if date1 and date2 and date1 < date2: return True else: return False
[docs]def logical_and_lists(list1: List[bool], list2: List[bool]) -> List[bool]: """For two lists of booleans of length N, return a list of length N where output[i] is True if list1[i] is True and list2[i] is True, else output[i] is False. """ assert len(list1) == len(list2) return [a and b for a, b in zip(list1, list2)]
[docs]def are_list_items_in_other_list(reference_list: List, query_list: List) -> List[bool]: """Check whether items in query_list exist in correct_list. :param reference_list: The reference list of items :param query_list: The items to check - does this list contain items in reference_list? :return items_present: Whether items in the correct list are in query_list (bool) >>> are_list_items_in_other_list([1, 2, 3], [3, 1, 1]) [True, False, True] """ items_present = [True if item in query_list else False for item in reference_list] return items_present
[docs]def are_lists_equal(list_1: list, list_2: list) -> List[bool]: """Elementwise comparison of lists. Return list of booleans, one for each element in the input lists, True if element N in list 1 is equal to element N in list 2, else False.""" return [i == j for i, j in zip(list_1, list_2)]
[docs]def fraction_of_lists_equal(list_1: list, list_2: list) -> float: """Returns the fraction of list elements are equal when compared elementwise.""" boolean_equals = are_lists_equal(list_1, list_2) return boolean_equals.count(True) / len(boolean_equals)
[docs]def get_value_from_list_of_dicts(list_of_dicts: List[dict], search_key: str, search_value: int, return_key: str): """Given a list of dictionaries, identify the required dictionary which contains the *search_key*: *search_value* pair. Return the value in that dictionary associated with *return_key*.""" assert(search_key != return_key) for d in list_of_dicts: for k in d: if k == search_key and d[k] == search_value: return d[return_key]