def run_release(args): assert args.version assert args.environ pivotal.check_version_format(args.version) gitflow = GitFlow() # Fetch remote refs. if not args.no_fetch: sys.stderr.write('Fetching origin ... ') gitflow.origin().fetch() print('OK') # Check the environ argument. branch = GitFlow().managers['release'].full_name(args.version) if args.environ not in ('qa', 'client'): raise DeploymentRequestError(branch, args.environ) if args.environ == 'client' and not args.no_check: #+++ Check if all stories were accepted by the client pt_release = pivotal.Release(args.version) print('Checking Pivotal Tracker stories ... ') pt_release.try_stage() print('OK') #+++ Check all relevant review requests in Review Board, to be sure rb_release = review.Release(pt_release) print('Checking if all relevant stories have been reviewed ... ') rb_release.try_stage(args.ignore_missing_reviews) print('OK') DeployCommand._run_deploy(args)
def test_gitflow_is_merged_into_remote(self): gitflow = GitFlow(self.repo).init() # devel is behind feat/even self.assertTrue( gitflow.is_merged_into('devel', 'remotes/my-remote/feat/even')) self.assertTrue( gitflow.is_merged_into('devel', gitflow.origin().refs['devel'])) self.assertTrue( gitflow.is_merged_into(gitflow.origin().refs['devel'], 'remotes/my-remote/feat/even')) self.assertTrue( gitflow.is_merged_into(gitflow.origin().refs['devel'], gitflow.origin().refs['devel'])) # feat/even is ahead of devel self.assertFalse(gitflow.is_merged_into('feat/recursion', 'devel')) self.assertFalse( gitflow.is_merged_into('remotes/my-remote/feat/recursion', 'devel')) self.assertFalse( gitflow.is_merged_into('feat/recursion', gitflow.origin().refs['devel'])) self.assertFalse( gitflow.is_merged_into('remotes/my-remote/feat/recursion', gitflow.origin().refs['devel']))
def test_gitflow_is_merged_into_remote(self): gitflow = GitFlow(self.repo).init() # devel is behind feat/even self.assertTrue(gitflow.is_merged_into( 'devel', 'remotes/my-remote/feat/even')) self.assertTrue(gitflow.is_merged_into( 'devel', gitflow.origin().refs['devel'])) self.assertTrue(gitflow.is_merged_into( gitflow.origin().refs['devel'], 'remotes/my-remote/feat/even')) self.assertTrue(gitflow.is_merged_into( gitflow.origin().refs['devel'], gitflow.origin().refs['devel'])) # feat/even is ahead of devel self.assertFalse(gitflow.is_merged_into( 'feat/recursion', 'devel')) self.assertFalse(gitflow.is_merged_into( 'remotes/my-remote/feat/recursion', 'devel')) self.assertFalse(gitflow.is_merged_into( 'feat/recursion', gitflow.origin().refs['devel'])) self.assertFalse(gitflow.is_merged_into( 'remotes/my-remote/feat/recursion', gitflow.origin().refs['devel']))
def run_append(args): # Print info and ask for confirmation. pivotal.prompt_user_to_confirm_release(args.version) # Merge, push and insert PT labels. gitflow = GitFlow() git = gitflow.git current_branch = gitflow.repo.active_branch develop = gitflow.develop_name() gitflow.name_or_current('release', args.version) release = gitflow.get_prefix('release') + str(args.version) print('') sys.stdout.write('Merging develop into ' + release + ' ... ') gitflow.checkout('release', str(args.version)) git.merge(gitflow.develop_name()) print('OK') sys.stdout.write('Pushing ' + release + ' ... ') gitflow.origin().push([release]) print('OK') sys.stdout.write('Moving back to ' + str(current_branch) + ' ... ') current_branch.checkout() print('OK') sys.stdout.write('Marking Pivotal Tracker stories ... ') pivotal.start_release(args.version) print('OK')
def test_gitflow_track_creates_tracking_branch(self): gitflow = GitFlow(self.repo).init() gitflow.track('feature', 'even') self.assertEqual(self.repo.active_branch.name, 'feat/even') self.assertTrue(self.repo.active_branch.tracking_branch()) self.assertEqual(self.repo.refs['feat/even'].tracking_branch(), gitflow.origin().refs['feat/even'])
def run_finish(args): gitflow = GitFlow() git = gitflow.git origin = gitflow.origin() version = gitflow.name_or_current('release', args.version) #+++ Check if all stories were QA'd pt_release = pivotal.Release(args.version) print('Checking Pivotal Tracker stories ... ') pt_release.try_finish() print('OK') #+++ Check all relevant review requests in Review Board, to be sure rb_release = review.Release(pt_release) print('Checking Review Board review requests ... ') rb_release.try_finish(args.ignore_missing_reviews) print('OK') #+++ Merge release branch into develop and master sys.stdout.write('Merging release branch %s ... ' % version) tagging_info = None if not args.notag: tagging_info = dict( sign=args.sign or args.signingkey, signingkey=args.signingkey, message=args.message) gitflow.finish('release', version, fetch=(not args.no_fetch), rebase=False, keep=True, force_delete=False, tagging_info=tagging_info, push=False) print('OK') #+++ Close all relevant review requests sys.stdout.write('Submitting all relevant review requests ... ') rb_release.finish() print('OK') #+++ Collect local and remote branches to be deleted sys.stdout.write('Collecting branches to be deleted ... ') local_branches = list() remote_branches = list() #+ Collect features to be deleted. origin_prefix = str(origin) + '/' feature_prefix = gitflow.get_prefix('feature') # refs = [<type>/<id>/...] refs = [str(ref)[len(origin_prefix):] for ref in origin.refs] for story in pt_release: if story.is_rejected(): continue # prefix = <feature-prefix>/<id> prefix = feature_prefix + str(story.get_id()) base_marker = gitflow.managers['feature'].base_marker_name(prefix) try: name = gitflow.nameprefix_or_current('feature', prefix) local_branches.append(feature_prefix + name) if base_marker in gitflow.repo.refs: local_branches.append(base_marker) except NoSuchBranchError: pass for ref in refs: # if <feature-prefix>/... startswith <feature-prefix>/<id> if ref.startswith(prefix) or ref == base_marker: remote_branches.append(ref) #+ Collect releases to be deleted. if not args.keep: release_branch = gitflow.get_prefix('release') + version try: gitflow.name_or_current('release', version) local_branches.append(release_branch) except NoSuchBranchError: pass if release_branch in refs: remote_branches.append(release_branch) print 'OK' #+++ Delete local and remote branches that are a part of this release sys.stdout.write('Checking out %s ... ' % gitflow.develop_name()) git.checkout(gitflow.develop_name()) print 'OK' #+ Delete local branches. print 'Deleting local branches ...' for branch in local_branches: git.branch('-D', branch) print ' ' + branch print ' OK' #+ Delete remote branches. print 'Deleting remote branches and pushing the rest ...' for branch in remote_branches: print ' ' + branch refspecs = [(':' + b) for b in remote_branches] refspecs.append(gitflow.develop_name()) refspecs.append(gitflow.master_name()) git.push(str(origin), '--tags', *refspecs) print ' OK'
def run_start(args): if args.for_release: pivotal.check_version_format(args.for_release) gitflow = GitFlow() git = gitflow.git base = None if args.for_release is not None: # Make sure --for-release matches the requirements. pivotal.check_version_format(args.for_release) base = gitflow.get_prefix('release') + args.for_release else: base = gitflow.managers['feature'].default_base() if not args.no_fetch: sys.stderr.write('Fetching origin ... ') gitflow.origin().fetch() print 'OK' # Check if the base exists and is in sync as soon as possible. sys.stdout.write('Checking the base branch ({0}) ... '.format(base)) origin_base = gitflow.require_origin_branch(base) try: gitflow.must_be_uptodate(base) except NoSuchBranchError: sys.stdout.write('found remote counterpart ... ') git.branch(base, origin_base.name) print('OK') [story, name] = pivotal.prompt_user_to_select_story(match=args.match) sys.stdout.write('Setting myself as the story owner ... ') try: story.set_me_as_owner() except: print('FAIL') print('OK') if args.for_release is not None: sys.stdout.write('Assigning the chosen story to release {0} ... '.format(args.for_release)) story.assign_to_release(args.for_release) print('OK') if story.is_rejected(): sid = str(story.get_id()) gitflow.start_transaction('restart story {0}'.format(sid)) sys.stdout.write('Checking out the feature branch ... ') try: gitflow.checkout('feature', sid) print('OK') except NoSuchBranchError as e: print('FAIL') raise InconsistencyDetected( 'The branch is missing for story {0}.'.format(sid)) sys.stdout.write('Updating Pivotal Tracker ... ') story.start() print('OK') return # :fixme: Why does the sh-version not require a clean working dir? gitflow.start_transaction('start feature branch %s (from %s)' % \ (name, base)) try: # fetch=False because we are already fetching at the beginning. branch = gitflow.create('feature', name, base, fetch=False) except (NotInitialized, BaseNotOnBranch): # printed in main() raise except Exception, e: die("Could not create feature branch %r" % name, e)
def run_finish(args): gitflow = GitFlow() git = gitflow.git origin = gitflow.origin() version = gitflow.name_or_current('release', args.version) #+++ Check if all stories were QA'd pt_release = pivotal.Release(args.version) print('Checking Pivotal Tracker stories ... ') pt_release.try_finish() print('OK') #+++ Check all relevant review requests in Review Board, to be sure rb_release = review.Release(pt_release) print('Checking Review Board review requests ... ') rb_release.try_finish(args.ignore_missing_reviews) print('OK') #+++ Merge release branch into develop and master sys.stdout.write('Merging release branch %s ... ' % version) tagging_info = None if not args.notag: tagging_info = dict(sign=args.sign or args.signingkey, signingkey=args.signingkey, message=args.message) gitflow.finish('release', version, fetch=(not args.no_fetch), rebase=False, keep=True, force_delete=False, tagging_info=tagging_info, push=False) print('OK') #+++ Close all relevant review requests sys.stdout.write('Submitting all relevant review requests ... ') rb_release.finish() print('OK') #+++ Collect local and remote branches to be deleted sys.stdout.write('Collecting branches to be deleted ... ') local_branches = list() remote_branches = list() #+ Collect features to be deleted. origin_prefix = str(origin) + '/' feature_prefix = gitflow.get_prefix('feature') # refs = [<type>/<id>/...] refs = [str(ref)[len(origin_prefix):] for ref in origin.refs] for story in pt_release: if story.is_rejected(): continue # prefix = <feature-prefix>/<id> prefix = feature_prefix + str(story.get_id()) base_marker = gitflow.managers['feature'].base_marker_name(prefix) try: name = gitflow.nameprefix_or_current('feature', prefix) local_branches.append(feature_prefix + name) if base_marker in gitflow.repo.refs: local_branches.append(base_marker) except NoSuchBranchError: pass for ref in refs: # if <feature-prefix>/... startswith <feature-prefix>/<id> if ref.startswith(prefix) or ref == base_marker: remote_branches.append(ref) #+ Collect releases to be deleted. if not args.keep: release_branch = gitflow.get_prefix('release') + version try: gitflow.name_or_current('release', version) local_branches.append(release_branch) except NoSuchBranchError: pass if release_branch in refs: remote_branches.append(release_branch) print 'OK' #+++ Delete local and remote branches that are a part of this release sys.stdout.write('Checking out %s ... ' % gitflow.develop_name()) git.checkout(gitflow.develop_name()) print 'OK' #+ Delete local branches. print 'Deleting local branches ...' for branch in local_branches: git.branch('-D', branch) print ' ' + branch print ' OK' #+ Delete remote branches. print 'Deleting remote branches and pushing the rest ...' for branch in remote_branches: print ' ' + branch refspecs = [(':' + b) for b in remote_branches] refspecs.append(gitflow.develop_name()) refspecs.append(gitflow.master_name()) git.push(str(origin), '--tags', *refspecs) print ' OK'
def run_start(args): if args.for_release: pivotal.check_version_format(args.for_release) gitflow = GitFlow() git = gitflow.git base = None if args.for_release is not None: # Make sure --for-release matches the requirements. pivotal.check_version_format(args.for_release) base = gitflow.get_prefix('release') + args.for_release else: base = gitflow.managers['feature'].default_base() if not args.no_fetch: sys.stderr.write('Fetching origin ... ') gitflow.origin().fetch() print 'OK' # Check if the base exists and is in sync as soon as possible. sys.stdout.write('Checking the base branch ({0}) ... '.format(base)) origin_base = gitflow.require_origin_branch(base) try: gitflow.must_be_uptodate(base) except NoSuchBranchError: sys.stdout.write('found remote counterpart ... ') git.branch(base, origin_base.name) print('OK') [story, name] = pivotal.prompt_user_to_select_story(match=args.match) sys.stdout.write('Setting myself as the story owner ... ') try: story.set_me_as_owner() except: print('FAIL') print('OK') if args.for_release is not None: sys.stdout.write( 'Assigning the chosen story to release {0} ... '.format( args.for_release)) story.assign_to_release(args.for_release) print('OK') if story.is_rejected(): sid = str(story.get_id()) gitflow.start_transaction('restart story {0}'.format(sid)) sys.stdout.write('Checking out the feature branch ... ') try: gitflow.checkout('feature', sid) print('OK') except NoSuchBranchError as e: print('FAIL') raise InconsistencyDetected( 'The branch is missing for story {0}.'.format(sid)) sys.stdout.write('Updating Pivotal Tracker ... ') story.start() print('OK') return # :fixme: Why does the sh-version not require a clean working dir? gitflow.start_transaction('start feature branch %s (from %s)' % \ (name, base)) try: # fetch=False because we are already fetching at the beginning. branch = gitflow.create('feature', name, base, fetch=False) except (NotInitialized, BaseNotOnBranch): # printed in main() raise except Exception, e: die("Could not create feature branch %r" % name, e)