def run(): parser = argparse.ArgumentParser(prog = get_script_name_from_python_file(__file__)) parser.add_argument("-d", "--description") parser.add_argument("-n", "--nobranch", action="store_true") parser.add_argument("title") args = parser.parse_args() if len(args.title) < 5: print "The title should be 5 characters or longer" parser.print_usage() sys.exit(2) owner, repo = Helper.owner_and_repo() api = GithubAPIGateway(owner, repo, token=os.environ['GITHUB_TOKEN']) username = api.call('user')[0]['login'] data = { 'title': args.title, 'assignee': username } if args.description is not None: data.update(body=args.description) issue = api.call('create_issue', owner=owner, repo=repo, data=data)[0] print issue['html_url'] branch_name = Helper.branch_name(issue) if args.nobranch == False: Helper.create_branch(branch_name) else: print branch_name
def create_pr(args): handler = create_handler(args) title = handler.get_title() body = handler.get_body() params = urllib.urlencode({'title':title,'body':body.encode("UTF-8")}) owner, repo = Helper.owner_and_repo() branch = Helper.push_private() url = "https://github.com/{owner}/{repo}/compare/{branch}?expand=1&{params}".format( owner = owner, repo = repo, branch = branch, params = params ) if args.debug == True: print('-- URL --') print(url) print('') print('-- TITLE --') print(title) print('') print('-- BODY --') print(body) else: webbrowser.open(url)
def run(): owner, repo = Helper.owner_and_repo() github_gateway = GithubAPIGateway(owner, repo) wrike_gateway = Wrike(data_filepath=Helper.get_data_filepath('wrike')) printer = StatusPrinter(70) merge(printer, github_gateway) close_wrike_task(printer, github_gateway, wrike_gateway) remove_remote_branch(printer, owner, repo)
def master_differences_check(printer): ################################################################################################### # MAKE SURE MASTER LOCAL AND REMOTE ARE THE SAME ################################################################################################### printer.print_process('Checking for differences with local master') if Helper.local_sha('master') != Helper.origin_sha('master'): printer.print_warning("Remote master is different than local master. Suggestion: (git checkout master && git pull origin master)") else: printer.print_check()
def run(): branch = Helper.current_branch() match = re.search('^(\d+)\-', branch) issue = None if match is not None: owner, repo = Helper.owner_and_repo() webbrowser.open('https://github.com/{0}/{1}/issues/{2}'.format(owner, repo, match.group(1))) else: print 'No issue number on branch'
def master_conflicts_check(printer): ################################################################################################### # CHECK FOR CONFLICTS WITH LOCAL MASTER ################################################################################################### printer.print_process('Checking for conflicts with origin master') if not Helper.has_origin_conflicts(): printer.print_check() else: msg = 'There are conflicts that must be resolved' msg += '. Suggestion: (git checkout master && git pull origin master && git checkout {0} && git rebase master)' printer.print_error(msg.format(Helper.current_branch()))
def run(): parser = argparse.ArgumentParser(prog = get_script_name_from_python_file(__file__)) parser.add_argument("item_counter") args = parser.parse_args() owner, repo = Helper.owner_and_repo() api = PyRollbarAPI(repo) item = api.get_item_from_counter(args.item_counter) branch_name = Helper.branch_name_from_item(item['id'], item['title']) result = Helper2().create_branch(branch_name) if result[0] != 0: print(result[1]) sys.exit(result[0])
def sync_repos(self, sync_all=False): if sync_all: for deployment_name, repolist in Helper.sorted_dict(self).items(): for repo_name, repo in Helper.sorted_dict(repolist).items(): for branch_name, branch_settings in Helper.sorted_dict(repo.get('branches')).items(): pass # TODO else: pending_updates = [] for deployment_name, repolist in Helper.sorted_dict(self).items(): for repo_name, repo in Helper.sorted_dict(repolist).items(): if repo.get('updates').get('updated_refs'): pending_updates.append(repo.get('updates')) if pending_updates: for pending_update in pending_updates: cache_name = pending_update.get('cache').name for updated_ref in pending_update.get('updated_refs'): repo_name = updated_ref.get('repo') repo_url = updated_ref.get('url') repo_ref = updated_ref.get('ref') for deployment_name, repolist in Helper.sorted_dict(self).items(): for repo_name, repo in Helper.sorted_dict(repolist).items(): for branch_name, branch_settings in Helper.sorted_dict(repo.get('branches')).items(): if repo_url == branch_settings.get('url') and \ repo_ref == branch_settings.get('ref') and \ cache_name == branch_settings.get('cache', repo.get('defaults').get('cache')): repo.sync(branch_name, repo_ref, branch_settings.get('root', ''))
def branch_differences_check(printer, github_gateway): ################################################################################################### # MAKE SURE LOCAL AND REMOTE BRANCH ARE THE SAME ################################################################################################### printer.print_process('Checking for differences with local branch') commits = github_gateway.get_pr_commits(Helper.current_branch()) if len(commits) <= 0: printer.print_error("No commits on the pr. Suggestion: push any changes") else: pr_sha = commits[-1]['sha'] local_sha = Helper.local_sha() if pr_sha != local_sha: branch = Helper.current_branch() printer.print_warning("The commit on the pr is different than local. Suggestion: (git push -f origin {0}) or (git pull origin {0})".format(branch)) else: printer.print_check()
def __init__(self, token=os.environ['CIRCLE_TOKEN']): APIGateway.__init__(self) self._username, self._project = Helper.owner_and_repo() self._host_url = 'https://circleci.com/api/v1' self._api = { 'recent_branch_builds': { 'path': '/project/{username}/{project}/tree/{branch}', 'method': 'GET', 'valid_status': [200] }, 'cancel_build': { 'path': '/project/{username}/{project}/{build_num}/cancel', 'method': 'POST' }, 'new_build': { 'path': '/project/{username}/{project}/tree/{branch}', 'method': 'POST' } } self._common_headers = { 'Accept': 'application/json' } self._common_params = { 'circle-token': token }
def unbrought_changes_check(printer): ################################################################################################### # CHECK FOR UNBROUGHT CHANGES FROM MASTER ################################################################################################### printer.print_process('Checking for unbrought in changes in master') if not Helper.branch_contains('master'): printer.print_warning("There are unbrought changes in master. Suggestion: (git rebase master)") else: printer.print_check()
def remove_remote_branch(printer, owner, repo): ################################################################################################### # REMOVE REMOTE BRANCH ################################################################################################### printer.print_process('Removing remote branch') if Helper.delete_origin_branch(): printer.print_check() else: printer.print_warning('Could not remove it. Visit https://github.com/{0}/{1}/branches to remove manually'.format(owner, repo))
def create_handler(args): if args.wrike_task is not None: id_number = args.wrike_task id_type = 'task' elif args.github_issue is not None: id_number = args.github_issue id_type = 'issue' elif args.rollbar_item is not None: id_number = args.rollbar_item id_type = 'item' else: id_type = Helper.branch_id_type() id_number = Helper.branch_id() if id_number is not None and int(id_number) == 0: id_type = None thismodule = sys.modules[__name__] return getattr(thismodule, str(id_type).title() + 'Handler')(args, id_number)
def create_task(args): # INITIALIZE DRIVERS AND HELPERS wrike_gateway = Wrike(wait_for_redirect=True, data_filepath=Helper.get_data_filepath("wrike")) github_helper = GithubAPIHelper() # GET FOLDER ID id_folder = args.id_folder should_check_folder_id_validity = True if id_folder is None: res = WrikeAPIHelper(wrike=wrike_gateway).get_folders_list(args.title_folder) if res["id"] is None: print 'Folder "{0}" could not be found'.format(res["prepend"]) sys.exit(-1) else: id_folder = res["id"] should_check_folder_id_validity = False if should_check_folder_id_validity: f = wrike_gateway.get_folder(id_folder) if f is None: print "Wrong folder id" sys.exit(-1) # CREATE TASK create_task_params = {"description": args.description} if args.self_assign: contact = wrike_gateway.get_current_contact() create_task_params.update({"responsibles": "['{0}']".format(contact["id"])}) task = wrike_gateway.create_task(id_folder, args.title, create_task_params) print task["permalink"] # CREATE ISSUE if args.github_issue: issue = github_helper.issue_from_task_object(task, args.self_assign) print issue["html_url"] wrike_gateway.create_task_comment(task["id"], issue["html_url"]) branch_name = Helper.branch_name(issue) if not args.nobranch: Helper.create_branch(branch_name) else: print branch_name wrike_gateway.redirect(task["permalink"])
def __init__(self, args, issue_number): super(IssueHandler, self).__init__(args) self.issue_number = issue_number owner, repo = Helper.owner_and_repo() api = GithubAPIGateway(owner, repo, token=os.environ['GITHUB_TOKEN']) result = api.call('list_issue', owner=owner, repo=repo, number=issue_number) if result[1] != 200: raise ObjectNotFoundException('issue', issue_number) else: self.obj = result[0]
def run(): parser = argparse.ArgumentParser(prog = get_script_name_from_python_file(__file__)) parser.add_argument("taskid") args = parser.parse_args() taskid = args.taskid match = re.match(r'^https:\/\/www\.wrike\.com\/open\.htm\?id=(\d+)$', taskid) if match is not None: taskid = match.group(1) wrike_gateway = Wrike(data_filepath=Helper.get_data_filepath('wrike')) task = wrike_gateway.get_task(taskid) if task is not None: branch_name = Helper.branch_name_from_task(taskid, task['title']) result = Helper2().create_branch(branch_name) if result[0] != 0: print(result[1]) sys.exit(result[0]) else: print "Task not found"
def run(): circle_gateway = CircleCiAPIGateway() github_gateway = GithubAPIGateway(*Helper.owner_and_repo()) printer = StatusPrinter() branch_differences_check(printer, github_gateway) master_differences_check(printer) unbrought_changes_check(printer) master_conflicts_check(printer) circleci_check(printer, circle_gateway) lgs_check(printer, github_gateway)
def run(): current_branch = Repo(os.getcwd()).active_branch api = CircleCiAPIGateway(token=os.environ['CIRCLE_TOKEN']) builds_canceled = 0 owner, repo = Helper.owner_and_repo() for build in api.call('recent_branch_builds', username=owner, project=repo, branch=current_branch)[0]: if build['status'] in ['running', 'not_running', 'queued', 'scheduled']: api.call('cancel_build', username=owner, project=repo, build_num=build['build_num']) builds_canceled += 1 print '{0} builds canceled'.format(builds_canceled)
def run(): current_branch = Repo(os.getcwd()).active_branch api = CircleCiAPIGateway(token=os.environ['CIRCLE_TOKEN']) owner, repo = Helper.owner_and_repo() result = api.call('new_build', username=owner, project=repo, branch=current_branch)[0] if result.get('build_url') is not None: print result['build_url'] else: if result.get('message') is not None: print result['message'] else: print result
def issue_from_wrike(args): # GET TASKS tasks = [] wrike_gateway = Wrike(data_filepath=Helper.get_data_filepath('wrike'), wait_for_redirect=True) github_gateway = GithubAPIGateway(*Helper.owner_and_repo()) for taskid in args.taskids: task = wrike_gateway.get_task(taskid) if task is None: print "'{0}' is not a valid taskid or it cannot be found".format(taskid) sys.exit(-1) tasks.append(task) # BODY OF ISSUE body = '' for task in tasks: body += '### {0}\n___\n\n{1}\n'.format(task['permalink'].encode('utf-8'), task['description'].encode('utf-8')) # TITLE OF ISSUE title = tasks[0]['title'] if len(tasks) > 1: title += ' (+{0} Wrike tasks)'.format(len(tasks) - 1) # CREATE ISSUE issue = github_gateway.create_issue(title, True, {'body': body}) print issue['html_url'] branch_name = Helper.branch_name(issue) if args.nobranch == False: Helper.create_branch(branch_name) else: print branch_name # WRITE LINK TO ISSUE ON EVERY TASK AND SET ASIGNEE wrike_gateway.redirect(issue['html_url']) contact = wrike_gateway.get_current_contact() for task in tasks: wrike_gateway.create_task_comment(task['id'], issue['html_url']) if contact['id'] not in task['responsibleIds']: wrike_gateway.change_task(task['id'], { 'addResponsibles': "['{0}']".format(contact['id']) })
def circleci_check(printer, circle_gateway): ################################################################################################### # CHECK FOR CIRCLECI TESTS ################################################################################################### printer.print_process('Checking CircleCi tests status') passed = False for build in circle_gateway.get_builds(): if build['vcs_revision'] == Helper.local_sha() and build['outcome'] == 'success': passed = True break if passed: printer.print_check() else: printer.print_error("Tests have not yet passed")
def remove_label_from_issue(args): results, status = GithubAPIGateway(*Helper.owner_and_repo()).remove_label_from_issue(args.issue_number, args.label, args.all_labels) if status in [200, 204]: print "Issue {0} labels:".format(args.issue_number) if results: for label in results: color = rgb2short(label['color'])[1] label_color = fg('black') + bg('#' + color) reset_color = attr('reset') print "[-l {0}\"{1}\"{2}]".format(label_color, label['name'], reset_color) else: print "No labels found." else: print results['message']
def _append(self, folder, msg, flags=(), msg_time=None): # TODO """ FORKED FORM IMAPCLIENT """ if msg_time: if not msg_time.tzinfo: # pragma: no cover msg_time = msg_time.replace(tzinfo=FixedOffset.for_system()) # pragma: no cover time_val = '"{0}"'.format(msg_time.strftime("%d-%b-%Y %H:%M:%S %z")) time_val = imapclient.imapclient.to_unicode(time_val) else: time_val = None return self.conn._command_and_check('append', self.conn._normalise_folder(folder), imapclient.imapclient.seq_to_parenstr(flags), time_val, Helper.str_to_bytes(msg), unpack=True)
def list_labels(args): results, status = GithubAPIGateway(*Helper.owner_and_repo()).get_labels(issue_number=args.issue_number) if status == 200: if args.issue_number: print "Issue {0} labels:".format(args.issue_number) if results: for label in results: color = rgb2short(label['color'])[1] label_color = fg('black') + bg('#' + color) reset_color = attr('reset') print "[-l {0}\"{1}\"{2}]".format(label_color, label['name'], reset_color) else: print "No labels found." else: print results['message']
def merge(printer, github_gateway): ################################################################################################### # 'CLICK' MERGE BUTTON ################################################################################################### printer.print_process('Triggering "Merge pull request" button actions') result = github_gateway.merge_pr(Helper.current_branch()) if result is not None: if result.get('merged') is not None and result['merged'] == True: printer.print_check() else: if result.get('message') is not None: printer.print_error(result['message']) else: printer.print_error('Could not perform merge') sys.exit(-1) else: printer.print_error('Could not find open PR') sys.exit(-1)
def update(self, repo): """ Update the cache, e.g. the Git repository in the file system """ self.repo = repo branches = self.repo.get('branches') changed_refs = [] for branch_name, branch_settings in Helper.sorted_dict(branches).items(): repo_path = '{}/{}'.format(self.path, branch_settings.get('repo')) repo['remotes'] = {'origin': {'url': branch_settings.get('url')}} self.repo.git.set_path(repo_path) self.repo.git.init() self.repo.git.add_remotes(repo['remotes']) update_info = self.repo.git.update_ref(branch_settings.get('ref'), 'origin', branch_settings.get('repo')) if update_info.get('updated'): changed_refs.append(update_info) return changed_refs
def get_body(self): ret = '' if self.args.body is None: ret = self._get_body() else: ret = self.args.body if len(ret) > 0: ret += '\n' if self.args.changes == True: changed_files = Helper2().changed_files_printable() ret += '\n'.join(['<changes>', changed_files, '</changes>']) if self.args.authors == True: original_authors = Helper.displayable_recommended_reviewers() if len(original_authors) > 0: if ret is not None and len(ret) > 0: ret += '\n' ret += 'Original Authors:\n' + original_authors return ret
def close_wrike_task(printer, github_gateway, wrike_gateway): ################################################################################################### # CLOSE WRIKE TASK ################################################################################################### printer.print_process('Finding issue') issue = github_gateway.get_issue(Helper.issue_number_from_branch()) if issue.get('number') is None: printer.print_warning('No issue found') else: printer.print_check() printer.print_process('Finding wrike tasks') matches = re.findall('### (https://www\.wrike\.com/(?:open\.htm\?)id=([\d\w]+))', issue.get('body') or '') if len(matches) <= 0: printer.print_warning('No wrike tasks found') else: printer.print_check() for task_tuple in matches: printer.print_process('Completing task {0}'.format(task_tuple[0])) task = wrike_gateway.complete_task(task_tuple[1]) if task is not None and task.get('status') is not None and task['status'] == 'Completed': printer.print_check() else: printer.print_warning('Task could not be changed to completed')
def get_lg_data(self): current_user = self._github_gateway.get_user()['login'] all_comments = self._github_gateway.get_pr_and_review_comments(Helper.current_branch()) comment_ids_addressed = self.get_ids_addressed(current_user, all_comments) all_comments.pop(current_user, None) ret = {} ret['lgs_count'] = 0 ret['has_unaddressed_comments'] = False ret['has_nonregular_lgs'] = False ret['comments'] = {} for comments_user, comments in all_comments.iteritems(): unaddressed_comments = [] lgd = False lgcomment = None for comment in reversed(comments): match = re.search(r'\bLG\b', comment['body'], flags=re.IGNORECASE) if match is not None: lgcomment = comment['body'] if len(unaddressed_comments) <= 0: ret['lgs_count'] += 1 if comment['body'].upper().strip() != 'LG': ret['has_nonregular_lgs'] = True break else: if str(comment['id']) not in comment_ids_addressed: unaddressed_comments.append(comment) if len(unaddressed_comments) > 0: ret['has_unaddressed_comments'] = True ret['comments'][comments_user] = { 'unaddressed_comments': unaddressed_comments, 'lgcomment': lgcomment } return ret
def main(): version = '0.0.1' program_name = 'gathergit' parser = argparse.ArgumentParser(prog=program_name, description='A description') # general args parser.add_argument('-V', action='version', version='%(prog)s {version}'.format(version=version)) parser.add_argument('--confdir', action='store', dest='confdir', help='directory to search for configuration files (default: config/)', default='config/') parser.add_argument('--all', action='store_true', dest='sync_all', help='Initialize, update and synchronize ALL repositories', default=False) parser_results = parser.parse_args() confdir = parser_results.confdir sync_all = parser_results.sync_all # config parsing cfg_parser = ConfigParser(confdir) config = cfg_parser.dump() # logging logconfig = config.get('settings', {}).get('logging', {}) logger = Helper().create_logger(program_name, logconfig) # let's start working now logger.debug('Starting new instance of %s', program_name) logger.debug('Raw configuration: %s', config) # collecting deployment configuration deployments = {} repolists = {} repoindex = Repoindex() for deployment_name, deployment_settings in config.get('deployments', {}).items(): repos = deployment_settings.get('repos') if repos is None: continue deployments[deployment_name] = {'target': deployment_settings.get('target'), 'defaults': deployment_settings.get('defaults', {})} if deployment_name not in repolists.keys(): repolists[deployment_name] = {} repolists[deployment_name].update(repos) # updating caches for deployment_name, repolist in Helper.sorted_dict(repolists).items(): for repoid, repo_settings in Helper.sorted_dict(repolist).items(): repo_name = repo_settings.get('name', repoid) repo_defaults = repo_settings.get('defaults', {}) branches = repo_settings.get('branches') if branches is None: logger.info('Skipping repo %s of deployment definition %s, is doesn\'t have any branches defined', repo_name, deployment_name) continue # adding repo to repoindex repo = Repo() repo['name'] = repo_name repo['defaults'] = repo_defaults repo['target'] = deployments[deployment_name].get('target') repo.add_branches(branches, deployments[deployment_name]) repoindex.add_repo(deployment_name, repoid, repo) cache_name = repoindex[deployment_name][repoid].get('defaults').get('cache') cache_settings = config.get('settings').get('caches').get(cache_name) cache = Cache(name=cache_name, settings=cache_settings) cache.init() updated_refs = cache.update(repoindex[deployment_name][repoid]) if updated_refs: repoindex[deployment_name][repoid]['updates'] = {'updated_refs': updated_refs, 'cache': cache} elif sync_all: repoindex[deployment_name][repoid]['updates'] = {'cache': cache} repoindex.sync_repos(sync_all) # Everything is done, closing now logger.debug('Shutting down..')