def rename(old, new=None): if not new: old, new = Git.branch(), old if new in Git.branches(): if not ARGS.force: raise Exception('The branch %s already exists.' % new) Delete.delete(new) Fresh.fresh(new, old) Delete.delete(old)
def get_format_string(name, user, context): def get_url(): full_path = os.getcwd() if name: path, f = os.path.split(name) full_path = os.path.join(full_path, path) if not os.path.exists(full_path): raise ValueError("Path %s doesn't exist." % full_path) if f: for p in os.listdir(full_path): if startswith(p, f): full_path = os.path.join(full_path, p) break else: raise ValueError("Can't find file matching " + name) context['path'] = os.path.relpath(full_path, GitRoot.ROOT) return _URL if not name: return get_url() if name.isdigit(): context['number'] = int(name) return PULL if 'commits'.startswith(name): return _COMMIT if 'diffs'.startswith(name): return _DIFF if 'pull'.startswith(name): return _PULL if 'pending'.startswith(name): if user == Settings.PROJECT_USER: return Pulls.pull_urls()[0] if user == Settings.USER: branch_name = '%s:%s' % (user, Git.branch()) for number, pull in Git.pulls().items(): if pull.branch == branch_name: context['number'] = number return PULL else: return _NEW_PULL raise ValueError("Can't pull for user %s." % user) if 'root'.startswith(name): name = GitRoot.root() return get_url()
def explode(): root = GitRoot.root() for line in Git.git("status", "--porcelain").splitlines(): mode, filename = line.split() try: if mode == "??": Git.git("add", filename, cwd=root) Git.git("commit", filename, "-m", "[fold] %s" % filename, cwd=root) except Exception as e: print("ERROR: couldn't commit filename %s." % filename) print("ERROR:", e)
def _pull_request(pull, working_branch): if pull.user == Settings.USER: nickname = 'origin' else: try: nickname = Remote.inverse()[pull.user] except KeyError: Remote.add_remote(pull.user, pull.user) nickname = pull.user keywords = { 'nickname': nickname, 'pull_branch': pull.branch, 'working_branch': working_branch, 'print': print if ARGS.verbose else None, } Call.runlines( """git fetch {nickname} {pull_branch} git checkout {nickname}/{pull_branch} git rebase --preserve-merges {working_branch}""", **keywords) # Store the commit ID at this point so we can merge back to it. keywords['commit_id'] = Git.commit_id() Call.runlines( """git checkout {working_branch} git merge --ff-only {commit_id}""", **keywords) _check_vcxproj()
def get_context(user=None): return { 'branch': Git.branch(), 'user': user or Settings.USER, 'project_user': Settings.PROJECT_USER, 'project': Settings.PROJECT, }
def slack(days=2): days = int(days) inverse = Remote.inverse() slack_names = Project.settings('slack') def slack(user): return '@' + slack_names[user] label_names = dict((v, k) for (k, v) in Project.settings('labels').items()) def labels_to_names(labels): return ' '.join( slack(label_names[i]) for i in labels if i in label_names) previous = get_previous_business_day(days) def match(issue): if issue['updated_at'] >= previous: # print('too new:', issue['number'], issue['updated_at'], previous) return False for label in issue['labels']: if label['name'] in ('Passed', 'Hold'): # print('passed:', issue['number']) return False # print('slack:', issue['number']) return True if False: import json json.dump(Git.issues(), open('/tmp/git-issues.json', 'w'), sort_keys=True, indent=4, separators=(',', ': ')) slackers = [i for i in Git.issues() if match(i)] if not slackers: return; print('\nPull requests that are over %d business day%s stale:' % ( days, '' if days == 1 else 's')) labels = Git.labels() for issue in sorted(slackers, key=operator.itemgetter('updated_at')): try: user = slack(inverse[issue['user']['login']]) + ':' update = issue['updated_at'][:10] url = Open.get_url(str(issue['number'])) lab = labels_to_names(labels[issue['number']]) print(' %s (%s): %s (%s)' % (url, update, user, lab)) except Exception as e: print('ERROR:', e) raise print()
def get_context(user=None): return { 'branch': Git.branch(), 'dev_branch': DEV_BRANCHES.get(Settings.PROJECT, 'master'), 'user': user or Settings.USER, 'project_user': Settings.PROJECT_USER, 'project': Settings.PROJECT, }
def start(branch, directory=""): branches = Git.branches() if branch in branches: raise ValueError(_ERROR % (branch, " ".join(branches))) directory = clone(directory) Call.call_raw("git checkout -b " + branch, cwd=directory) banner("Checked out new branch", branch)
def update_pulls(self, base_commit): pulls = [p for p in Git.pulls().values() if self.accept(p)] pull_dict = dict((p.number, p.commit_id) for p in pulls) pull_dict['base_commit'] = base_commit if self.pull_dict != pull_dict: self.pull_dict = pull_dict _release(pulls, self.branch('working'), self.branch('next'), self.name) return True
def swap(a, b): missing = set((a, b)) - set(Git.branches()) if missing: raise Exception("Non-existent branch%s: %s" % ("" if len(missing) == 1 else "es", " ".join(missing))) temp = a + "-" + b rename(a, temp) rename(b, a) rename(temp, b)
def _check_vcxproj(): # Now run scons vcxproj and see if anything changes. if not CHECK_VCXPROJ: return Call.runlines('scons vcxproj') status = Git.git('status') if not MATCH in status: # TODO: Check to see if src/soci/src/core/version.h is the only # difference. raise VcxprojException()
def version_commit(version_number=None, success=None, failure=None): root = GitRoot.root() files = Project.settings('version')['files'] old_version = get_version() if version_number == old_version: raise Exception('Version number is already %s' % old_version) if not version_number: version_number = semver.increment_string(old_version) if not CommandList.confirm('update version %s to %s' % (old_version, version_number)): return for f in files: File.subn(os.path.join(root, f), VERSION, version_number) if success or failure: ChangeLog.add_status_line(version_number, success, failure) Git.git('commit', '-am', 'Set version to %s' % version_number)
def do_delete(branches, print=print): pulls = set(branches) & set(Git.pull_branches()) if pulls: raise Exception("Can't delete pull branches: " + ' '.join(pulls)) success = set() for b in branches: try: Git.remove_local_branch(b, print=print) success.add(b) except: print and print('No local branch %s.' % b) try: Git.remove_origin_branch(b, print=print) success.add(b) except: print and print('No origin branch %s.' % b) return success, set(branches) - success
def rotate(count='1'): count = int(count) if not count: raise ValueError('Rotate by 0!') if count < 0: count = -count ARGS.reverse = not ARGS.reverse for c in range(count): branch = Git.rotate_local_branch(ARGS.reverse) print('Branch is now %s.' % branch)
def run_import(branch, **kwds): user, branch = parse_branch(branch) if branch not in Git.branch1es(user): raise ValueError(_BRANCH_ERROR.format(**locals())) if user == Settings.USER: Git.git('checkout', branch) else: Remote.remote(user, **kwds) Git.git('fetch', user, branch) Git.git('checkout', '-b', '/'.join([user, branch]))
def clone(directory): settings = Project.settings("clone") branch = settings.get("base_branch", "develop") root = GitRoot.root(os.getcwd()) if root: directory = directory or os.path.basename(root) root = os.path.dirname(root) else: directory = directory or Settings.PROJECT root = os.getcwd() directory = File.next_version(os.path.join(root, directory)) settings.update(branch=branch, directory=directory, project=Settings.PROJECT, user=Settings.USER) # Call git clone. if Git.git(*_CLONE.format(**settings).split(), cwd=root): raise ValueError("Failed to start new directory") Remote.remote("all", cwd=directory) Remote.remote("upstream", Settings.PROJECT, directory) Git.git("pull", "upstream", branch) banner("Created", branch + ", directory", directory) return directory
def parse_branch(branch): try: pull_number = int(branch) except: pass else: pulls = Git.pulls() if pull_number not in pulls: raise ValueError(_ERROR % (pull, ' '.join(sorted(pulls)))) pull = pulls[pull_number] branch = pull.branch if ':' in branch: return branch.split(':', 1) else: return Settings.USER, branch
def get_url(name='', user=''): if not platform.system() in _OPEN_COMMANDS: raise ValueError("Can't open a URL for platform.system() = " + plat) remotes = get_remotes() origin = remotes.get('origin') or remotes.get('upstream') upstream = remotes.get('upstream') or remotes.get('origin') context = { 'branch': Git.branch(), 'dev_branch': DEV_BRANCHES.get(origin[1], 'master'), 'user': origin[0], 'project_user': upstream[0], 'project': origin[1], } fmt = get_format_string(name, user, context) return fmt.format(**context)
def release(): previous_pulls = {} while True: base_commit = Git.commit_id(upstream=True, branch=base_branch()) success = False for selector in SELECTORS: success = selector.update_pulls(base_commit) or success if success: Slack.slack() else: print(String.timestamp(short=True) + ': no change.') if ARGS.period: time.sleep(ARGS.period) Cache.clear() else: break
def branches(prefix='', *args): root = GitRoot.root_container() pulls = Git.pull_branches() if not ARGS.expanded: fname = [''] def before(f): fname[0] = os.path.basename(f) def callback(data): parts = filter(None, data.splitlines()) for i, p in enumerate(parts): branch = p.split()[-1] if branch in pulls: branch += '(%s)' % pulls[branch] if p.startswith('*'): branch = '*' + branch parts[i] = branch print('%-12s %s' % (fname[0] + ':', ' '.join(parts))) Call.for_each_directory( BRANCH_COMMAND, path=root, select=GitRoot.select(prefix), before=before, callback=callback) else: def before(f): print('\n%s:' % os.path.basename(f)) Call.for_each_directory( BRANCH_COMMAND, path=root, select=GitRoot.select(prefix), before=before) if args: print('ERROR: arguments %s ignored' % ', '.join(args))
def SAFE(): print('Current branch is %s.' % Git.branch())
def fresh(branch, base_branch=None): base_branch = base_branch or Git.branch() Git.copy_from_remote(base_branch, branch, 'origin')
def pulls(): for number, p in reversed(sorted(Git.pulls().items())): print(_to_string(number, p.branch, p.title))
def _release(pulls, working_branch, next_branch, selector_name): Git.complete_reset() Delete.do_delete([working_branch], print=None) Git.copy_from_remote(base_branch(), working_branch, push=False) pulls.sort(key=operator.attrgetter('number')) if pulls: print('%s: Building release branch for %s:' % ( String.timestamp(), selector_name)) print(' ' + '\n '.join(str(p) for p in pulls)) print() success = [] failure = [] exceptions = [] for pull in pulls: try: print(pull.number, '...', sep='', end='') _pull_request(pull, working_branch) except VcxprojException: failure.append(pull.number) print('VCXPROJ...', end='') except Exception as e: failure.append(pull.number) print('ERROR...', end='') else: success.append(pull.number) if pulls: print() print() Version.version_commit( version_number=None, success=success, failure=failure) commit_id = Git.commit_id() Git.force_checkout(next_branch) Git.git('reset', '--hard', commit_id) Git.git('push', '-f') commits = Open.get_commits() plural = '' if len(commits) == 1 else 's' _print_pulls('Proposed new develop branch %s for pull%s' % (commits, plural), success) _print_pulls('FAILED:', failure) if success or failure: print('---------------------------------------------') print() else: print(String.timestamp(), ': no pulls ready.')