def finish_feature(self, feature_name, delete_on_remote=False): repo_name = self.utils.current_repo_name() if not feature_name: feature_name = self.utils.current_feature_name() self.utils.assert_is_not_dirty() self.utils.assert_feature_exists(feature_name) Error.abort_if(feature_name == "master", "You cannot finish your master feature") Error.abort_if( self.tfs.has_active_pull_request(repo_name, feature_name), "You have an active pull request on that branch.\nPlease complete it or abandon it to continue" ) Confirmation.show_if(self.utils.has_unpushed_commits(feature_name), "You have unpushed commits on this branch") if feature_name == self.utils.current_feature_name(): self.move_to_feature("master") try: self.git.branch("-D", feature_name) if delete_on_remote: self.git.push("origin", "--delete", feature_name) if self.utils.current_feature_name() == "master": Utils.print_encoded(click.style("Updating master", bold=True)) self.update_feature(silent=True) Utils.print_encoded("Finished feature " + click.style(feature_name, bold=True)) except git.exc.GitCommandError as command_error: Utils.print_encoded(command_error.stderr.decode("UTF-8")) Error.abort("Couldn't finish feature")
def review_feature(self, title, hotfix): repo_name = self.utils.current_repo_name() current_feature = self.utils.current_feature_name() if current_feature == "master": if not title: title = self.utils.obtain_pull_request_title_from_last_commit() current_feature = Utils.create_feature_name_from_title(title) self.create_feature(current_feature) self.share_feature(silent=True) if not self.tfs.has_active_pull_request(repo_name, current_feature): if not title: title = self.utils.obtain_pull_request_title_from_last_commit() if hotfix: title = '[HOTFIX] ' + title response = self.tfs.create_pull_request(repo_name, current_feature, title) Error.abort_if( response.status_code != 201, "Request error - HTTP_CODE: " + str(response.status_code) + "\n\n" + response.json()["message"] if "message" in response.json() else "") Utils.print_encoded( click.style("Pull request successfully created", bold=True)) else: Utils.print_encoded( click.style("Pull request successfully updated", bold=True)) if hotfix: self.tfs.approve_pull_request(repo_name, current_feature) Utils.print_encoded( click.style("[HOTFIX] ", bold=True, fg="red") + click.style( "Pull request successfully merged into master", bold=True)) time.sleep(0.5) self.finish_feature(current_feature, delete_on_remote=True)
def __get_active_policies(self, repository_name): Error.abort_if(repository_name not in self.settings['repo_id'], "Couldn't find this repository on your TFS") auth = self.__get_auth() fullUrl = self.settings['url'] + '/' + self.settings['project'] + '/_apis/policy/configurations?api-version=2.0' policies = requests.get(fullUrl, auth=auth).json()['value'] policies_from_repository = filter(lambda policy: policy["settings"]["scope"][0]["repositoryId"] == self.settings['repo_id'][repository_name], policies) return list(policies_from_repository)
def share_feature(self, silent=False): current_feature = self.utils.current_feature_name() Error.abort_if(current_feature == "master", "You cannot push changes on master") try: output = self.git.push("--set-upstream", "origin", current_feature) if not silent: Utils.print_encoded( click.style("Feature shared successfully", bold=True)) except git.exc.GitCommandError as command_error: Utils.print_encoded(command_error.stderr.decode("UTF-8")) Error.abort("Couldn't share feature")
def approve_pull_request(self, repository_name, feature_name): Error.abort_if(repository_name not in self.settings['repo_id'], "Couldn't find this repository on your TFS") policies = self.__get_active_policies(repository_name) self.__deactivate_policies(policies) try: self.__wait_for_merge_analysis(repository_name, feature_name) pull_request = self.__get_pull_requests(repository_name, feature_name, only_active=True)[0] Error.abort_if(pull_request['mergeStatus'] != 'succeeded', "Hotfix couldn't be pushed because conflicts were found") self.__delete_reviewers(pull_request) auth = self.__get_auth() fullUrl = self.settings['url'] + "/_apis/git/repositories/" + self.settings['repo_id'][repository_name] + "/pullrequests/" + str(pull_request['pullRequestId']) + "?api-version=2.0" response = requests.patch(fullUrl, json={"status": "completed", "lastMergeSourceCommit": pull_request['lastMergeSourceCommit']}, auth=auth) self.__wait_for_merge_analysis(repository_name, feature_name) finally: self.__activate_policies(policies)
def has_active_pull_request(self, repository_name, feature_name): Error.abort_if(repository_name not in self.settings['repo_id'], "Couldn't find this repository on your TFS") return len(self.__get_pull_requests(repository_name, feature_name, only_active=True)) > 0
def create_pull_request(self, repository_name, feature_name, title): auth = self.__get_auth() Error.abort_if(repository_name not in self.settings['repo_id'], "Couldn't find this repository on your TFS") fullUrl = self.settings['url'] + "/_apis/git/repositories/" + self.settings['repo_id'][repository_name] + "/pullrequests?api-version=2.0" return requests.post(fullUrl, json={"sourceRefName": "refs/heads/" + feature_name, "targetRefName": "refs/heads/master", "title": title}, auth=auth)
def assert_feature_exists(self, feature): Error.abort_if(not self.feature_exists(feature), "Couldn't find feature with feature name " + feature)
def assert_feature_does_not_exists(self, feature): Error.abort_if(self.feature_exists(feature), "feature name " + feature + " already assigned to another feature")
def assert_is_not_dirty(self): Error.abort_if(self.repo.is_dirty(), "You have uncommited changes, please commit or stash them before continuing")