def merge(self, branch: Branch, branchToMerge: Branch) -> bool: self.verboseCli.execute("git checkout %s" % (branch.getName())) self.verboseCli.execute("git pull %s %s" % (self.name, branch.getName())) self.verboseCli.execute("git merge %s/%s" % (self.name, branchToMerge.getName())) self.push(branch)
def open(self, title: str, body: str, fromBranch: Branch, toBranch: Branch, sourceRemote=None) -> bool: token = self.configPersonal.getToken(self.tokenSpace) url = "%s/repos/%s/%s/pulls" % (self.baseUrl, self.remote.getUsername(), self.remote.getRepositoryName()) head = '' if sourceRemote is not None: # check sourceRemote is github as well if sourceRemote.isGithub() is not True: raise GitcdGithubApiException( "Github is not able to get a pr from a different server") head = '%s:' % (sourceRemote.getUsername()) # check if the token is a string - does not necessarily mean its valid if isinstance(token, str): data = { "title": title, "body": body, "head": '%s%s' % (head, fromBranch.getName()), "base": toBranch.getName() } headers = {'Authorization': 'token %s' % token} response = requests.post( url, headers=headers, data=json.dumps(data), ) if response.status_code == 401: raise GitcdGithubApiException( "Authentication failed, create a new access token.") if response.status_code != 201: try: jsonResponse = response.json() message = jsonResponse['message'] raise GitcdGithubApiException( "Open a pull request failed with message: %s" % (message)) except ValueError: raise GitcdGithubApiException( "Open a pull request on github failed.") defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % (defaultBrowser, response.json()["html_url"])) else: defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute( "%s %s" % (defaultBrowser, "https://github.com/%s/%s/compare/%s...%s" % (self.remote.getUsername(), self.remote.getRepositoryName(), toBranch.getName(), fromBranch.getName()))) return True
def checkDoubleFeaturePrefix(self, branch: Branch) -> Branch: featurePrefix = self.config.getFeature() featurePrefixAsString = self.config.getString(featurePrefix) if not featurePrefix: return branch if branch.getName().startswith('%s%s' % ( featurePrefixAsString, featurePrefixAsString )): fixFeatureBranch = self.interface.askFor( "Your feature branch already starts" + " with your feature prefix," + " should i remove it for you?", ["yes", "no"], "yes" ) if fixFeatureBranch == "yes": branch = self.instantiateBranch( branch.getName().replace('%s%s' % ( featurePrefixAsString, featurePrefixAsString ), '') ) return branch
def run(self, branch: Branch): remote = self.getRemote() masterBranch = self.config.getMaster() featurePrefix = self.config.getFeature() featurePrefixAsString = self.config.getString(featurePrefix) testBranch = self.config.getTest() testBranchAsString = self.config.getString(testBranch) # few checks on the new feature branch if '%s%s' % (featurePrefixAsString, branch.getName()) == masterBranch: # maybe i should use while here # if anyone passes master again, i wouldnt notice branch = self.instantiateBranch(self.interface.askFor( "You passed your master branch name as feature branch,\ please give a different name." )) # not sure if this is smart since test branch is kind of a prefix too if testBranch is not None: featureBranchString = '%s%s' % ( featurePrefixAsString, branch.getName() ) if featureBranchString.startswith(testBranchAsString): # maybe i should use while here # if anyone passes develop again, i wouldnt notice branch = self.instantiateBranch(self.interface.askFor( "You passed your test branch name as feature branch,\ please give a different name." )) branch = self.checkDoubleFeaturePrefix(branch) remote.createFeature(branch)
def run(self, branch: Branch): remote = self.getRemote() masterBranch = self.config.getMaster() featurePrefix = self.config.getFeature() featurePrefixAsString = self.config.getString(featurePrefix) testBranch = self.config.getTest() testBranchAsString = self.config.getString(testBranch) # few checks on the new feature branch if '%s%s' % (featurePrefixAsString, branch.getName()) == masterBranch: # maybe i should use while here # if anyone passes master again, i wouldnt notice branch = self.instantiateBranch( self.interface.askFor( "You passed your master branch name as feature branch,\ please give a different name.")) # not sure if this is smart since test branch is kind of a prefix too if testBranch is not None: featureBranchString = '%s%s' % (featurePrefixAsString, branch.getName()) if featureBranchString.startswith(testBranchAsString): # maybe i should use while here # if anyone passes develop again, i wouldnt notice branch = self.instantiateBranch( self.interface.askFor( "You passed your test branch name as feature branch,\ please give a different name.")) branch = self.checkDoubleFeaturePrefix(branch) remote.createFeature(branch)
def isBehind(self, branch: Branch) -> bool: output = self.cli.execute( "git log %s/%s..%s" % (self.name, branch.getName(), branch.getName())) if not output: return False return True
def status(self, branch: Branch, sourceRemote=None): master = Branch(self.config.getMaster()) auth = self.getAuth() if auth is not None: url = "%s/repositories/%s/%s/pullrequests" % ( self.baseUrl, self.remote.getUsername(), self.remote.getRepositoryName() ) response = requests.get( url, auth=auth ) if response.status_code != 200: raise GitcdGithubApiException( "Could not fetch open pull requests," + " please have a look manually." ) returnValue = {} responseJson = response.json() if 'values' in responseJson and len(responseJson['values']) > 0: for pr in responseJson['values']: if ( 'source' in pr and 'branch' in pr['source'] and 'name' in pr['source']['branch'] and pr['source']['branch']['name'] == branch.getName() ): currentPr = pr reviewers = self.isReviewedBy( currentPr['links']['activity']['href'] ) if len(reviewers) == 0: reviewers = self.getLgtmComments( currentPr['links']['comments']['href'] ) returnValue['state'] = 'REVIEW REQUIRED' if len(reviewers) > 0: returnValue['state'] = 'APPROVED' for reviewer in reviewers: reviewer = reviewers[reviewer] if reviewer['state'] != 'APPROVED': returnValue['state'] = reviewer['state'] returnValue['master'] = master.getName() returnValue['feature'] = branch.getName() returnValue['reviews'] = reviewers returnValue['url'] = currentPr['links']['html']['href'] returnValue['number'] = currentPr['id'] return returnValue
def status(self, branch: Branch): username = self.remote.getUsername() ref = "%s:refs/heads/%s" % (username, branch.getName()) token = self.configPersonal.getToken(self.tokenSpace) master = Branch(self.config.getMaster()) if isinstance(token, str): url = "%s/repos/%s/%s/pulls" % ( self.baseUrl, username, self.remote.getRepositoryName() ) data = { "state": 'open', "head": ref, "base": master.getName() } headers = {'Authorization': 'token %s' % token} response = requests.get( url, headers=headers, params=data ) if response.status_code != 200: raise GitcdGithubApiException( "Could not fetch open pull requests," + " please have a look manually." ) result = response.json() returnValue = {} if len(result) == 1: reviewers = self.isReviewedBy( '%s/%s' % (result[0]['url'], 'reviews') ) returnValue['state'] = 'REVIEW REQUIRED' if len(reviewers) == 0: reviewers = self.getLgtmComments(result[0]['comments_url']) if len(reviewers) > 0: returnValue['state'] = 'APPROVED' for reviewer in reviewers: reviewer = reviewers[reviewer] if reviewer['state'] is not 'APPROVED': returnValue['state'] = reviewer['state'] returnValue['master'] = master.getName() returnValue['feature'] = branch.getName() returnValue['reviews'] = reviewers returnValue['url'] = result[0]['html_url'] returnValue['number'] = result[0]['number'] return returnValue
def status(self, branch: Branch): master = Branch(self.config.getMaster()) auth = self.getAuth() if auth is not None: url = "%s/repositories/%s/%s/pullrequests" % ( self.baseUrl, self.remote.getUsername(), self.remote.getRepositoryName() ) response = requests.get( url, auth=auth ) if response.status_code != 200: raise GitcdGithubApiException( "Could not fetch open pull requests," + " please have a look manually." ) returnValue = {} responseJson = response.json() if 'values' in responseJson and len(responseJson['values']) > 0: for pr in responseJson['values']: if ( 'source' in pr and 'branch' in pr['source'] and 'name' in pr['source']['branch'] and pr['source']['branch']['name'] == branch.getName() ): currentPr = pr reviewers = self.isReviewedBy( currentPr['links']['activity']['href'] ) if len(reviewers) == 0: reviewers = self.getLgtmComments( currentPr['links']['comments']['href'] ) returnValue['state'] = 'REVIEW REQUIRED' if len(reviewers) > 0: returnValue['state'] = 'APPROVED' for reviewer in reviewers: reviewer = reviewers[reviewer] if reviewer['state'] is not 'APPROVED': returnValue['state'] = reviewer['state'] returnValue['master'] = master.getName() returnValue['feature'] = branch.getName() returnValue['reviews'] = reviewers returnValue['url'] = currentPr['links']['html']['href'] returnValue['number'] = currentPr['id'] return returnValue
def merge(self, branch: Branch, branchToMerge: Branch) -> bool: self.verboseCli.execute("git checkout %s" % (branch.getName())) self.verboseCli.execute("git pull %s %s" % ( self.name, branch.getName() )) self.verboseCli.execute("git merge %s/%s" % ( self.name, branchToMerge.getName() )) self.push(branch)
def checkBranch(self, remote: Remote, branch: Branch) -> bool: # check if its a feature branch if not branch.isFeature(): raise GitcdNoFeatureBranchException( "Your current branch is not a valid feature branch." + " Checkout a feature branch or pass one as param." ) # check remote existence if not remote.hasBranch(branch): pushFeatureBranch = self.interface.askFor( "Your feature branch does not exists on remote." + " Do you want me to push it remote?", ["yes", "no"], "yes" ) if pushFeatureBranch == "yes": remote.push(branch) # check behind origin if remote.isBehind(branch): pushFeatureBranch = self.interface.askFor( "Your feature branch is ahead the origin/branch." + " Do you want me to push the changes?", ["yes", "no"], "yes" ) if pushFeatureBranch == "yes": remote.push(branch) return True
def delete(self, branch: Branch) -> bool: output = self.verboseCli.execute("git push %s :%s" % ( self.name, branch.getName()) ) if output is False: return False return True
def checkBranch(self, remote: Remote, branch: Branch) -> bool: # check if its a feature branch if not branch.isFeature(): raise GitcdNoFeatureBranchException( "Your current branch is not a valid feature branch." + " Checkout a feature branch or pass one as param.") # check remote existence if not remote.hasBranch(branch): pushFeatureBranch = self.interface.askFor( "Your feature branch does not exists on remote." + " Do you want me to push it remote?", ["yes", "no"], "yes") if pushFeatureBranch == "yes": remote.push(branch) # check behind origin if remote.isBehind(branch): pushFeatureBranch = self.interface.askFor( "Your feature branch is ahead the origin/branch." + " Do you want me to push the changes?", ["yes", "no"], "yes") if pushFeatureBranch == "yes": remote.push(branch) return True
def getBranches(self) -> List[Branch]: output = self.cli.execute('git branch -a') if not output: return [] lines = output.split("\n") branches = [] for line in lines: line = line.strip() if 'HEAD -> ' in line: continue if not line.startswith('remotes/'): branch = line.replace('* ', '') elif line.startswith('remotes/'): parts = line.split('/') del parts[0] del parts[0] branch = '/'.join(parts) if branch not in branches: branches.append(branch) branchObjects = [] branches.sort() for branch in branches: branchObject = Branch(branch) branchObjects.append(branchObject) return branchObjects
def open(self, title: str, body: str, fromBranch: Branch, toBranch: Branch) -> bool: token = self.configPersonal.getToken(self.tokenSpace) if token is not None: projectId = '%s%s%s' % (self.remote.getUsername(), '%2F', self.remote.getRepositoryName()) url = '%s/projects/%s/merge_requests' % (self.baseUrl, projectId) data = { 'source_branch': fromBranch.getName(), 'target_branch': toBranch.getName(), 'title': title, 'description': body } headers = {'Private-Token': token} response = requests.post(url, headers=headers, json=data) if response.status_code == 401: raise GitcdGithubApiException( "Authentication failed, create a new app password.") if response.status_code == 409: raise GitcdGithubApiException( "This pull-requests already exists.") # anything else but success if response.status_code != 201: raise GitcdGithubApiException( "Open a pull request on gitlab failed.") try: result = response.json() defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % (defaultBrowser, result['web_url'])) except ValueError: raise GitcdGithubApiException( "Open a pull request on gitlab failed.") else: defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute( "%s %s" % (defaultBrowser, "%s/%s/%s/merge_requests/new?%s=%s" % ("https://gitlab.com", self.remote.getUsername(), self.remote.getRepositoryName(), 'merge_request%5Bsource_branch%5D', fromBranch.getName()))) return True
def run(self, branch: str): remote = self.getRemote() sourceRemote = None if self.hasMultipleRemotes() is True: sourceRemote = self.getRemote() if sourceRemote.getUrl() == remote.getUrl(): sourceRemote = None master = Branch(self.config.getMaster()) pr = remote.getGitWebIntegration() self.getTokenOrAskFor(pr.getTokenSpace()) prInfo = pr.status(branch, sourceRemote) if len(prInfo) == 0: self.interface.writeOut("No pull request exists for %s...%s\n" % (branch.getName(), master.getName())) self.interface.writeOut('Run') self.interface.warning("git-cd review %s" % (branch.getName())) self.interface.writeOut('to create a pull request') else: self.interface.writeOut("Branches: %s...%s" % (branch.getName(), master.getName())) if prInfo['state'] == 'APPROVED': state = '%s%s%s' % (self.interface.OK, prInfo['state'], self.interface.ENDC) else: state = '%s%s%s' % (self.interface.ERROR, prInfo['state'], self.interface.ENDC) self.interface.writeOut('State: %s' % (state)) self.interface.writeOut("Number: %s" % (prInfo['number'])) self.interface.writeOut("Reviews:") for user in prInfo['reviews']: review = prInfo['reviews'][user] self.interface.writeOut(' - %s' % (user)) for comment in review['comments']: if comment['state'] == 'APPROVED': state = '%s%s%s' % (self.interface.OK, comment['state'], self.interface.ENDC) else: state = '%s%s%s' % (self.interface.ERROR, comment['state'], self.interface.ENDC) self.interface.writeOut(' %s: %s' % (state, comment['body'])) self.interface.writeOut("URL: %s" % (prInfo['url']))
def getRequestedBranch(self, branch: str) -> [Branch, Tag]: tagPrefix = self.config.getTag() if branch.startswith(tagPrefix): branch = Tag(branch) else: branch = Branch(branch) return branch
def compare(self, branch: Branch, toCompare: [Branch, Tag]) -> bool: if isinstance(toCompare, Tag): toCompareString = toCompare.getName() else: toCompareString = '%s/%s' % (self.name, toCompare.getName()) self.verboseCli.execute("git diff %s %s --color" % (toCompareString, branch.getName())) return True
def createFeature(self, branch: Branch) -> Branch: self.verboseCli.execute("git checkout %s" % (self.config.getMaster())) self.verboseCli.execute("git pull %s %s" % (self.name, self.config.getMaster())) self.verboseCli.execute("git checkout -b %s" % (branch.getName())) self.push(branch) return branch
def compare(self, branch: Branch, toCompare: [Branch, Tag]) -> bool: if isinstance(toCompare, Tag): toCompareString = toCompare.getName() else: toCompareString = '%s/%s' % (self.name, toCompare.getName()) self.verboseCli.execute("git diff %s %s --color" % ( toCompareString, branch.getName() )) return True
def deleteBranches(self, branches: [Branch] = []) -> bool: currentBranch = self.repository.getCurrentBranch() masterBranch = Branch(self.config.getMaster()) for branch in branches: if branch.getName() == currentBranch.getName(): currentBranch = self.repository.checkoutBranch(masterBranch) branch.delete() return True
def checkDoubleFeaturePrefix(self, branch: Branch) -> Branch: featurePrefix = self.config.getFeature() featurePrefixAsString = self.config.getString(featurePrefix) if not featurePrefix: return branch if branch.getName().startswith( '%s%s' % (featurePrefixAsString, featurePrefixAsString)): fixFeatureBranch = self.interface.askFor( "Your feature branch already starts" + " with your feature prefix," + " should i remove it for you?", ["yes", "no"], "yes") if fixFeatureBranch == "yes": branch = self.instantiateBranch(branch.getName().replace( '%s%s' % (featurePrefixAsString, featurePrefixAsString), '')) return branch
def isBehind(self, branch: Branch) -> bool: output = self.cli.execute( "git log %s/%s..%s" % ( self.name, branch.getName(), branch.getName() ) ) if not output: return False return True
def run(self, branch: Branch): remote = self.getRemote() sourceRemote = None if self.hasMultipleRemotes() is True: sourceRemote = self.getRemote() if sourceRemote.getUrl() == remote.getUrl(): sourceRemote = None master = Branch(self.config.getMaster()) self.checkRepository() if sourceRemote is None: self.checkBranch(remote, branch) else: self.checkBranch(sourceRemote, branch) self.interface.warning("Opening pull-request") # check if pr is open already pr = remote.getGitWebIntegration() self.getTokenOrAskFor(pr.getTokenSpace()) prInfo = pr.status(branch, sourceRemote) if prInfo is not None and 'url' in prInfo: openPr = self.interface.askFor( 'Pull request is already open. ' + 'Should i open it in your browser?', ["yes", "no"], "yes") if openPr == "yes": pr.openBrowser(prInfo['url']) return True # ask for title and body title = self.interface.askFor('Pull-Request title?', False, branch.getName()) body = self.interface.askFor("Pull-Request body?") # go on opening pr pr.open(title, body, branch, master, sourceRemote)
def run(self, branch: Branch): remote = self.getRemote() master = Branch(self.config.getMaster()) self.checkRepository() self.checkBranch(remote, branch) self.interface.warning("Opening pull-request") title = self.interface.askFor( 'Pull-Request title?', False, branch.getName()) # use branch name as default title since its mandatory if title == '': title = branch.getName() body = self.interface.askFor("Pull-Request body?") pr = remote.getGitWebIntegration() # ensure a token is set for this remote self.getTokenOrAskFor(pr.getTokenSpace()) pr.open(title, body, branch, master)
def createFeature(self, branch: Branch) -> Branch: self.verboseCli.execute( "git checkout %s" % (self.config.getMaster()) ) self.verboseCli.execute( "git pull %s %s" % (self.name, self.config.getMaster()) ) self.verboseCli.execute( "git checkout -b %s" % (branch.getName()) ) self.push(branch) return branch
def run(self, branch: Branch): remote = self.getRemote() testBranch = self.config.getTest() masterBranch = self.config.getMaster() if branch.getName() == masterBranch: # maybe i should use recursion here # if anyone passes master again, i wouldnt notice branch = Branch('%s%s' % ( branch.getName(), self.interface.askFor( "You passed your master branch name as feature branch,\ please give a different name." ) )) if testBranch: if branch.getName().startswith(testBranch): # maybe i should use recursion here # if anyone passes master again, i wouldnt notice branch = Branch('%s%s' % ( branch.getName(), self.interface.askFor( "You passed your test branch name as feature branch,\ please give a different branch." ) )) self.checkRepository() self.checkBranch(remote, branch) master = Branch(masterBranch) remote.merge(master, branch) deleteFeatureBranch = self.interface.askFor( "Delete your feature branch?", ["yes", "no"], "yes" ) if deleteFeatureBranch == "yes": # delete feature branch remote and locally remote.delete(branch) branch.delete()
def status(self, branch: Branch, sourceRemote=None): username = self.remote.getUsername() if sourceRemote is not None: # check sourceRemote is github as well if sourceRemote.isGithub() is not True: raise GitcdGithubApiException( "Github is not able to see a pr from a different server") ref = '%s:%s' % (sourceRemote.getUsername(), branch.getName()) else: ref = "%s:refs/heads/%s" % (username, branch.getName()) token = self.configPersonal.getToken(self.tokenSpace) master = Branch(self.config.getMaster()) if isinstance(token, str): url = "%s/repos/%s/%s/pulls" % (self.baseUrl, username, self.remote.getRepositoryName()) data = {"state": 'open', "head": ref, "base": master.getName()} headers = {'Authorization': 'token %s' % token} response = requests.get(url, headers=headers, params=data) if response.status_code != 200: raise GitcdGithubApiException( "Could not fetch open pull requests," + " please have a look manually.") result = response.json() returnValue = {} if len(result) == 1: reviewers = self.isReviewedBy('%s/%s' % (result[0]['url'], 'reviews')) returnValue['state'] = 'REVIEW REQUIRED' if len(reviewers) == 0: reviewers = self.getLgtmComments(result[0]['comments_url']) if len(reviewers) > 0: returnValue['state'] = 'APPROVED' for reviewer in reviewers: reviewer = reviewers[reviewer] if reviewer['state'] != 'APPROVED': returnValue['state'] = reviewer['state'] returnValue['master'] = master.getName() returnValue['feature'] = branch.getName() returnValue['reviews'] = reviewers returnValue['url'] = result[0]['html_url'] returnValue['number'] = result[0]['number'] return returnValue
def status(self, branch: Branch): master = Branch(self.config.getMaster()) token = self.configPersonal.getToken(self.tokenSpace) if token is not None: data = { 'state': 'biber', 'source_branch': branch.getName(), 'target_branch': master.getName() } projectId = '%s%s%s' % (self.remote.getUsername(), '%2F', self.remote.getRepositoryName()) baseUrl = "%s/projects/%s/merge_requests" % (self.baseUrl, projectId) url = "%s?state=opened" % (baseUrl) headers = {'Private-Token': token} response = requests.get(url, headers=headers, json=data) if response.status_code != 200: raise GitcdGithubApiException( "Could not fetch open pull requests," + " please have a look manually.") returnValue = {} result = response.json() if len(result) > 0: returnValue['state'] = 'REVIEW REQUIRED' reviewers = self.isReviewedBy("%s/%s/approvals" % (baseUrl, result[0]['iid'])) if len(reviewers) == 0 and result[0]['user_notes_count'] > 0: reviewers = self.getLgtmComments( "%s/%s/notes" % (baseUrl, result[0]['iid'])) if len(reviewers) > 0: returnValue['state'] = 'APPROVED' for reviewer in reviewers: reviewer = reviewers[reviewer] if reviewer['state'] != 'APPROVED': returnValue['state'] = reviewer['state'] returnValue['master'] = master.getName() returnValue['feature'] = branch.getName() returnValue['reviews'] = reviewers returnValue['url'] = result[0]['web_url'] returnValue['number'] = result[0]['iid'] return returnValue
def run(self, branch: Branch): repository = Repository() remote = self.getRemote() developmentBranches = repository.getDevelopmentBranches() if len(developmentBranches) == 1: developmentBranch = developmentBranches[0] else: branchNames = [] for developmentBranch in developmentBranches: branchNames.append(developmentBranch.getName()) branchNames.reverse() default = branchNames[0] choice = branchNames developmentBranch = Branch( self.interface.askFor("Which develop branch you want to use?", choice, default)) remote.merge(developmentBranch, branch) repository.checkoutBranch(branch)
def run(self, branch: Branch): remote = self.getRemote() master = Branch(self.config.getMaster()) if branch.getName() == master.getName(): # maybe i should use recursion here # if anyone passes master again, i wouldnt notice branch = Branch('%s%s' % ( branch.getName(), self.interface.askFor( "You passed your master branch name as feature branch,\ please give a different branch." ) )) remote.merge(branch, master)
def run(self, branch: Branch): remote = self.getRemote() masterBranch = Branch(self.config.getMaster()) releaseHelper = ReleaseHelper() releaseHelper.checkout(remote, masterBranch) version = releaseHelper.getVersion() if version is False: version = self.interface.askFor( "Whats the current version number you want to release?") message = self.interface.askFor( "What message your new release should have?") # escape double quotes for shell command message = message.replace('"', '\\"') version = '%s%s' % (self.config.getString( self.config.getTag()), version) releaseHelper.release(version, message, remote) return True
def run(self, branch: Branch): remote = self.getRemote() testBranch = self.config.getTest() masterBranch = self.config.getMaster() if branch.getName() == masterBranch: # maybe i should use recursion here # if anyone passes master again, i wouldnt notice branch = Branch('%s%s' % ( branch.getName(), self.interface.askFor( "You passed your master branch name as feature branch,\ please give a different name." ) )) if testBranch: if branch.getName().startswith(testBranch): # maybe i should use recursion here # if anyone passes master again, i wouldnt notice branch = Branch('%s%s' % ( branch.getName(), self.interface.askFor( "You passed your test branch name as feature branch,\ please give a different name." ) )) self.checkRepository() self.checkBranch(remote, branch) master = Branch(masterBranch) remote.merge(master, branch) deleteFeatureBranch = self.interface.askFor( "Delete your feature branch?", ["yes", "no"], "yes" ) if deleteFeatureBranch == "yes": # delete feature branch remote and locally remote.delete(branch) branch.delete()
def getCurrentBranch(self) -> Branch: return Branch(self.cli.execute('git rev-parse --abbrev-ref HEAD'))
def run(self, branch: str): remote = self.getRemote() master = Branch(self.config.getMaster()) pr = remote.getGitWebIntegration() self.getTokenOrAskFor(pr.getTokenSpace()) prInfo = pr.status(branch) if len(prInfo) is 0: self.interface.writeOut( "No pull request exists for %s...%s\n" % ( branch.getName(), master.getName() ) ) self.interface.writeOut('Run') self.interface.warning( "git-cd review %s" % ( branch.getName() ) ) self.interface.writeOut('to create a pull request') else: self.interface.writeOut("Branches: %s...%s" % ( branch.getName(), master.getName()) ) if prInfo['state'] == 'APPROVED': state = '%s%s%s' % ( self.interface.OK, prInfo['state'], self.interface.ENDC ) else: state = '%s%s%s' % ( self.interface.ERROR, prInfo['state'], self.interface.ENDC ) self.interface.writeOut('State: %s' % (state)) self.interface.writeOut("Number: %s" % (prInfo['number'])) self.interface.writeOut("Reviews:") for user in prInfo['reviews']: review = prInfo['reviews'][user] self.interface.writeOut(' - %s' % (user)) for comment in review['comments']: if comment['state'] == 'APPROVED': state = '%s%s%s' % ( self.interface.OK, comment['state'], self.interface.ENDC ) else: state = '%s%s%s' % ( self.interface.ERROR, comment['state'], self.interface.ENDC ) self.interface.writeOut(' %s: %s' % ( state, comment['body'] )) self.interface.writeOut("URL: %s" % (prInfo['url']))
def open( self, title: str, body: str, fromBranch: Branch, toBranch: Branch ) -> bool: token = self.configPersonal.getToken(self.tokenSpace) url = "%s/repos/%s/%s/pulls" % ( self.baseUrl, self.remote.getUsername(), self.remote.getRepositoryName() ) # check if the token is a string - does not necessarily mean its valid if isinstance(token, str): data = { "title": title, "body": body, "head": fromBranch.getName(), "base": toBranch.getName() } headers = {'Authorization': 'token %s' % token} response = requests.post( url, headers=headers, data=json.dumps(data), ) if response.status_code == 401: raise GitcdGithubApiException( "Authentication failed, create a new access token." ) if response.status_code != 201: try: jsonResponse = response.json() message = jsonResponse['errors'][0]['message'] raise GitcdGithubApiException( "Open a pull request failed with message: %s" % ( message ) ) except ValueError: raise GitcdGithubApiException( "Open a pull request on github failed." ) defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % ( defaultBrowser, response.json()["html_url"] )) else: defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % ( defaultBrowser, "https://github.com/%s/%s/compare/%s...%s" % ( self.remote.getUsername(), self.remote.getRepositoryName(), toBranch.getName(), fromBranch.getName() ) )) return True
def open( self, title: str, body: str, fromBranch: Branch, toBranch: Branch, sourceRemote=None ) -> bool: auth = self.getAuth() if auth is not None: url = "%s/repositories/%s/%s/pullrequests" % ( self.baseUrl, self.remote.getUsername(), self.remote.getRepositoryName() ) data = { "destination": { "branch": { "name": toBranch.getName() } }, "source": { "branch": { "name": fromBranch.getName() } }, "title": title, "description": body } if sourceRemote is not None: if sourceRemote.isBitbucket() is not True: raise GitcdGithubApiException( "Bitbucket is not able to get a pr" + " from a different server" ) data['source']['repository'] = { 'full_name': "%s/%s" % ( sourceRemote.getUsername(), sourceRemote.getRepositoryName() ) } response = requests.post( url, json=data, auth=auth ) if response.status_code == 401: raise GitcdGithubApiException( "Authentication failed, create a new app password." ) if response.status_code != 201: try: jsonResponse = response.json() message = jsonResponse['error']['message'] raise GitcdGithubApiException( "Open a pull request on bitbucket" + " failed with message: %s" % ( message ) ) except ValueError: raise GitcdGithubApiException( "Open a pull request on bitbucket failed." ) defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % ( defaultBrowser, response.json()["links"]['html']['href'] )) else: defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % ( defaultBrowser, "%s/%s/%s/pull-requests/new?source=%s&event_source=gitcd" % ( "https://bitbucket.org", self.remote.getUsername(), self.remote.getRepositoryName(), fromBranch.getName() ) )) return True
def hasBranch(self, branch: Branch) -> bool: self.readBranches() if branch.getName() in self.branches: return True return False
def instantiateBranch(self, branch: str) -> Branch: featurePrefix = self.config.getFeature() featurePrefixAsString = self.config.getString(featurePrefix) return Branch('%s%s' % (featurePrefixAsString, branch))
def open( self, title: str, body: str, fromBranch: Branch, toBranch: Branch ) -> bool: auth = self.getAuth() if auth is not None: url = "%s/repositories/%s/%s/pullrequests" % ( self.baseUrl, self.remote.getUsername(), self.remote.getRepositoryName() ) data = { "destination": { "branch": { "name": toBranch.getName() } }, "source": { "branch": { "name": fromBranch.getName() } }, "title": title, "description": body } response = requests.post( url, json=data, auth=auth ) if response.status_code == 401: raise GitcdGithubApiException( "Authentication failed, create a new app password." ) if response.status_code != 201: try: jsonResponse = response.json() message = jsonResponse['error']['message'] raise GitcdGithubApiException( "Open a pull request on bitbucket" + " failed with message: %s" % ( message ) ) except ValueError: raise GitcdGithubApiException( "Open a pull request on bitbucket failed." ) defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % ( defaultBrowser, response.json()["links"]['html']['href'] )) else: defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % ( defaultBrowser, "%s/%s/%s/pull-requests/new?source=%s&event_source=gitcd" % ( "https://bitbucket.org", self.remote.getUsername(), self.remote.getRepositoryName(), fromBranch.getName() ) )) return True
def pull(self, branch: Branch) -> bool: self.verboseCli.execute( 'git pull %s %s' % (self.name, branch.getName()) ) return True
def getRequestedBranch(self, branch: str) -> Branch: featureAsString = self.config.getString(self.config.getFeature()) if not branch.startswith(featureAsString): branch = '%s%s' % (featureAsString, branch) return Branch(branch)
def checkoutBranch(self, branch: Branch) -> Branch: self.verboseCli.execute('git checkout %s' % (branch.getName())) return branch
def delete(self, branch: Branch) -> bool: output = self.verboseCli.execute("git push %s :%s" % (self.name, branch.getName())) if output is False: return False return True
def getLatestTag(self) -> [Branch, Tag]: output = self.cli.execute("git describe --abbrev=0") if not output: return Branch(self.config.getMaster()) return Tag(output.strip())
def open( self, title: str, body: str, fromBranch: Branch, toBranch: Branch ) -> bool: token = self.configPersonal.getToken(self.tokenSpace) if token is not None: projectId = '%s%s%s' % ( self.remote.getUsername(), '%2F', self.remote.getRepositoryName() ) url = '%s/projects/%s/merge_requests' % ( self.baseUrl, projectId ) data = { 'source_branch': fromBranch.getName(), 'target_branch': toBranch.getName(), 'title': title, 'description': body } headers = {'Private-Token': token} response = requests.post( url, headers=headers, json=data ) if response.status_code == 401: raise GitcdGithubApiException( "Authentication failed, create a new app password." ) if response.status_code == 409: raise GitcdGithubApiException( "This pull-requests already exists." ) # anything else but success if response.status_code != 201: raise GitcdGithubApiException( "Open a pull request on gitlab failed." ) try: result = response.json() defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % ( defaultBrowser, result['web_url'] )) except ValueError: raise GitcdGithubApiException( "Open a pull request on gitlab failed." ) else: defaultBrowser = self.getDefaultBrowserCommand() self.cli.execute("%s %s" % ( defaultBrowser, "%s/%s/%s/merge_requests/new?%s=%s" % ( "https://gitlab.com", self.remote.getUsername(), self.remote.getRepositoryName(), 'merge_request%5Bsource_branch%5D', fromBranch.getName() ) )) return True
def status(self, branch: Branch): master = Branch(self.config.getMaster()) token = self.configPersonal.getToken(self.tokenSpace) if token is not None: data = { 'state': 'biber', 'source_branch': branch.getName(), 'target_branch': master.getName() } projectId = '%s%s%s' % ( self.remote.getUsername(), '%2F', self.remote.getRepositoryName() ) baseUrl = "%s/projects/%s/merge_requests" % ( self.baseUrl, projectId ) url = "%s?state=opened" % ( baseUrl ) headers = {'Private-Token': token} response = requests.get( url, headers=headers, json=data ) if response.status_code != 200: raise GitcdGithubApiException( "Could not fetch open pull requests," + " please have a look manually." ) returnValue = {} result = response.json() if len(result) > 0: returnValue['state'] = 'REVIEW REQUIRED' reviewers = self.isReviewedBy( "%s/%s/approvals" % ( baseUrl, result[0]['iid'] ) ) if len(reviewers) == 0 and result[0]['user_notes_count'] > 0: reviewers = self.getLgtmComments( "%s/%s/notes" % ( baseUrl, result[0]['iid'] ) ) if len(reviewers) > 0: returnValue['state'] = 'APPROVED' for reviewer in reviewers: reviewer = reviewers[reviewer] if reviewer['state'] is not 'APPROVED': returnValue['state'] = reviewer['state'] returnValue['master'] = master.getName() returnValue['feature'] = branch.getName() returnValue['reviews'] = reviewers returnValue['url'] = result[0]['web_url'] returnValue['number'] = result[0]['iid'] return returnValue
def pull(self, branch: Branch) -> bool: self.verboseCli.execute('git pull %s %s' % (self.name, branch.getName())) return True