def activate(self): super(Summit, self).activate() if not self.config: # ie. if the plugin is not configured, it cannot activate. return if ROOMS not in self: self[ROOMS] = {} self.gh = Github(self.config['github-token'], api_preview=True) self.queues = {} # Those are MergeQueues self.rooms_lock = RLock() try: self.gh_status = self.get_plugin('GHStatus') except: self.log.info( "If you want notifications to your chat users on PRs you can install the companion plugin err-ghstatus." ) self.gh_status = None # Reload the state from the storage. with self.mutable(ROOMS) as rooms: for room_name, repo in rooms.items(): for room in self[ROOMS]: self.queues[room] = MergeQueue(self.gh.get_repo(repo.name), initial_queue=repo.queue) self.start_poller(120, method=self.check_pr_states)
def test_datadog_bindings(): repo = FakeGHRepo() mq = MergeQueue(repo) from datadog_stats import Stats mq.stats = Stats(api_key="fdjkfdjkjkfd") assert type(mq.stats) == Stats
def build_merge_queue(self): """Build a queue of node pairs to be merged in a specific priority. The queue elements have a specific format in order to allow 'removing' of specific elements inside the priority queue. Each element is a list of length 4 containing: - the merge priority (any ordered type) - a 'valid' flag - and the two nodes in arbitrary order The valid flag allows one to "remove" elements by setting the flag to False. Then one checks the flag when popping elements and ignores those marked as invalid. One other specific feature is that there are back-links from edges to their corresponding queue items so that when nodes are merged, affected edges can be invalidated and reinserted in the queue. """ queue_items = [] for l1, l2 in self.real_edges_iter(): w = self.merge_priority_function(self, l1, l2) qitem = [w, True, l1, l2] queue_items.append(qitem) self[l1][l2]['qlink'] = qitem self[l1][l2]['weight'] = w return MergeQueue(queue_items, with_progress=self.show_progress)
def test_bless_pr(): mq = MergeQueue(FakeGHRepo()) mq.ask_pr(12) mq.bless_pr(12) assert mq.queue[0].blessed with pytest.raises(MergeQueueException): mq.bless_pr(13)
def test_askpr(): mq = MergeQueue(FakeGHRepo()) mq.ask_pr(13) assert len(mq.queue) == 1 assert mq.queue[0].nb == 13 with pytest.raises(MergeQueueException): mq.ask_pr(13) assert len(mq.queue) == 1
def test_simple_rmpr(): mq = MergeQueue(FakeGHRepo()) mq.ask_pr(12) assert len(mq.queue) == 1 mq.rm_pr(12) assert len(mq.queue) == 0 with pytest.raises(MergeQueueException): mq.rm_pr(14)
def test_sink_pr(): mq = MergeQueue(FakeGHRepo()) mq.ask_pr(12) mq.ask_pr(13) assert mq.queue[0].nb == 12 mq.sink_pr(12) assert mq.queue[0].nb == 13 assert mq.queue[1].nb == 12 with pytest.raises(MergeQueueException): mq.sink_pr(14)
def test_check_merged_externally(): pr_14 = FakeGHPullRequest(14) repo = FakeGHRepo(injected_prs=[pr_14]) mq = MergeQueue(repo) mq.ask_pr(14) transitions = list(mq.check()) assert len(transitions) == 0 # nothing changed so nothing should happen pr_14.merged = True # PR has been merged externally transitions = list(mq.check()) assert len(transitions) == 1 pr, [(transition, params)] = transitions[0] assert transition == PRTransition.MERGED
def test_bump_pr(): mq = MergeQueue(FakeGHRepo()) mq.ask_pr(12) mq.ask_pr(13) assert mq.queue[0].nb == 12 with pytest.raises(MergeQueueException): mq.bump_pr(13) mq.bless_pr(13) mq.bump_pr(13) assert mq.queue[0].nb == 13 assert mq.queue[1].nb == 12 assert mq.pulled_prs[0] == 13 with pytest.raises(MergeQueueException): mq.bump_pr(14)
def merge_config(self, msg, args): """ Configure the merge queue with repo for a room (defaults to the current room). Warning: this is killing the queue. """ try: repo, room = self.optional_room_precheck(msg, args) except Exception as e: return f'Error {e}' gh_repo = self.gh.get_repo(repo) with self.rooms_lock: with self.mutable(ROOMS) as rooms: rooms[room] = Repo(name=repo, owner=msg.frm, queue=[], saints=[msg.frm.aclattr]) self.queues[room] = MergeQueue(gh_repo) return f'Configured {room} with this repo {gh_repo.name}'
def test_check_merged_by_errbot(): pr_14 = FakeGHPullRequest(14, reviews=[FakeGHReview('user1', APPROVED)]) repo = FakeGHRepo(injected_prs=[pr_14]) mq = MergeQueue(repo) mq.ask_pr(14) transitions = list(mq.check()) assert len(transitions) == 0 # nothing changed so nothing should happen pr_14.mergeable_state = CLEAN pr_14.mergeable = True transitions = list(mq.check()) assert len(transitions) == 1 pr, [(transition, params)] = transitions[0] assert transition == PRTransition.NOW_MERGEABLE # PR is not blessed so nothing else should happen mq.bless_pr(14) transitions = list(mq.check()) assert len(transitions) == 1 assert pr_14.asked_to_be_merged pr, [(transition, params)] = transitions[0] assert transition == PRTransition.MERGING
def test_check_review_counting(): pr_14 = FakeGHPullRequest(14) repo = FakeGHRepo(injected_prs=[pr_14]) mq = MergeQueue(repo) mq.ask_pr(14) transitions = list(mq.check()) assert len(transitions) == 0 # nothing changed so nothing should happen pr_14.reviews.append(FakeGHReview('dugenou', APPROVED)) transitions = list(mq.check()) assert len(transitions) == 1 pr, [(transition, params)] = transitions[0] assert transition == PRTransition.GOT_POSITIVE pr_14.reviews.append(FakeGHReview('dugland', CHANGES_REQUESTED)) transitions = list(mq.check()) assert len(transitions) == 1 pr, [(transition, params)] = transitions[0] assert transition == PRTransition.GOT_NEGATIVE
def __init__(self, watershed=array([]), probabilities=array([]), merge_priority_function=None, allow_shared_boundaries=True, gt_vol=None, feature_manager=MomentsFeatureManager(), show_progress=False, lowmem=False, connectivity=1, channel_is_oriented=None, orientation_map=array([]), normalize_probabilities=False): """Create a graph from a watershed volume and image volume. The watershed is assumed to have dams of label 0 in between basins. Then, each basin corresponds to a node in the graph and an edge is placed between two nodes if there are one or more watershed pixels connected to both corresponding basins. """ super(Rag, self).__init__(weighted=False) self.show_progress = show_progress if merge_priority_function is None: self.merge_priority_function = boundary_mean else: self.merge_priority_function = merge_priority_function self.set_watershed(watershed, lowmem, connectivity) self.set_probabilities(probabilities, normalize_probabilities) self.set_orientations(orientation_map, channel_is_oriented) if watershed is None: self.ucm = None else: self.ucm = array(self.watershed == 0, dtype=float) self.ucm[self.ucm == 0] = -inf self.ucm_r = self.ucm.ravel() self.max_merge_score = -inf self.build_graph_from_watershed(allow_shared_boundaries) self.set_feature_manager(feature_manager) self.set_ground_truth(gt_vol) self.merge_queue = MergeQueue()
def test_reviews(): pr_1 = FakeGHPullRequest(1, reviews=[FakeGHReview('user1', APPROVED)], mergeable_state=CLEAN) repo = FakeGHRepo(injected_prs=[pr_1]) mq = MergeQueue(repo, max_pulled_prs=2) mq.ask_pr(1) mq.bless_pr(1) transitions = list(mq.check()) assert len(transitions) == 0 pr_1.add_review(FakeGHReview('user1', COMMENTED)) transitions = list(mq.check()) assert len(transitions) == 0 pr_1.add_review(FakeGHReview('user1', REQUEST_CHANGES)) transitions = list(mq.check()) assert len(transitions) == 1 pr, review_transitions = transitions[0] assert review_transitions[0] == (PRTransition.GOT_POSITIVE, 0) assert review_transitions[1] == (PRTransition.GOT_NEGATIVE, 1)
def test_init(): mq = MergeQueue(FakeGHRepo()) assert mq.get_queue() == []
def test_askpr_closed(): repo = FakeGHRepo(injected_prs=[FakeGHPullRequest(14, state=CLOSED)]) mq = MergeQueue(repo) with pytest.raises(MergeQueueException): mq.ask_pr(14) assert len(mq.queue) == 0
def test_set_stats_plugin(): """Test setting stats plugin""" repo = FakeGHRepo() mq = MergeQueue(repo) assert type(mq.stats) == NoStats
def test_check_queue_depth(): pr_14 = FakeGHPullRequest(14, reviews=[FakeGHReview('user1', APPROVED)], mergeable_state=BEHIND) pr_15 = FakeGHPullRequest(15, reviews=[FakeGHReview('user2', APPROVED)], mergeable_state=BEHIND) pr_16 = FakeGHPullRequest(16, reviews=[FakeGHReview('user2', APPROVED)], mergeable_state=BEHIND) repo = FakeGHRepo(injected_prs=[pr_15, pr_14, pr_16]) mq = MergeQueue(repo, max_pulled_prs=2) mq.ask_pr(14) mq.ask_pr(15) mq.ask_pr(16) transitions = list(mq.check()) assert len(transitions) == 0 # nothing changed so nothing should happen mq.bless_pr(14) mq.bless_pr(15) mq.bless_pr(16) # It should pull the base branch only on 14 and 15 transitions = list(mq.check()) assert len(transitions) == 2 for pr, trs in transitions: assert trs[0][0] == PRTransition.PULLED assert trs[1][0] == PRTransition.PULLED_SUCCESS # Lets say the first one worked pr_14.mergeable_state = CLEAN pr_14.mergeable = True # Second time around it merge the one mergeable. transitions = list(mq.check()) assert len(transitions) == 2 for pr, trs in transitions: if pr.nb == 14: assert trs[0][0] == PRTransition.NOW_MERGEABLE and trs[1][ 0] == PRTransition.MERGING assert pr_14.asked_to_be_merged pr_14.merged = True # PR has been merged pr_15.mergeable_state = BLOCKED # CI still catching up # Third time around as a slot has been freed up, it should pull the last one. transitions = list(mq.check()) assert len(transitions) == 2 for pr, trs in transitions: if pr.nb == 14: assert trs[0][0] == PRTransition.MERGED elif pr.nb == 16: assert trs[0][0] == PRTransition.PULLED and trs[1][ 0] == PRTransition.PULLED_SUCCESS assert len(mq.pulled_prs) == 2 pr_15.mergeable_state = DIRTY transitions = list(mq.check()) assert len(transitions) == 1 assert len(mq.pulled_prs) == 1
def test_getpr(): mq = MergeQueue(FakeGHRepo()) pr, gh_pr = mq.get_pr(12) assert pr.nb == 12 assert gh_pr.number == 12