def tagRepo(config, repo, reponame, revision, tags, bumpFiles, relbranch, pushAttempts): remote = make_hg_url(HG, repo) mercurial(remote, reponame) def bump_and_tag(repo, attempt, config, relbranch, revision, tags): # set relbranchChangesets=1 because tag() generates exactly 1 commit relbranchChangesets = 1 if relbranch in get_branches(reponame): update(reponame, revision=relbranch) else: update(reponame, revision=revision) run_cmd(['hg', 'branch', relbranch], cwd=reponame) if len(bumpFiles) > 0: # Bump files on the relbranch, if necessary bump(reponame, bumpFiles, 'version') run_cmd(['hg', 'diff'], cwd=repo) try: get_output([ 'hg', 'commit', '-u', config['hgUsername'], '-m', getBumpCommitMessage(config['productName'], config['version']) ], cwd=reponame) relbranchChangesets += 1 except subprocess.CalledProcessError, e: # We only want to ignore exceptions caused by having nothing to # commit, which are OK. We still want to raise exceptions caused # by any other thing. if e.returncode != 1 or "nothing changed" not in e.output: raise # We always want our tags pointing at the tip of the relbranch # so we need to grab the current revision after we've switched # branches and bumped versions. revision = get_revision(reponame) # Create the desired tags on the relbranch tag(repo, revision, tags, config['hgUsername']) # Validate that the repository is only different from the remote in # ways we expect. outgoingRevs = out(src=reponame, remote=remote, ssh_username=config['hgUsername'], ssh_key=config['hgSshKey']) if len([r for r in outgoingRevs if r[BRANCH] == relbranch ]) != relbranchChangesets: raise Exception("Incorrect number of revisions on %s" % relbranch) if len(outgoingRevs) != relbranchChangesets: raise Exception("Wrong number of outgoing revisions")
def tagRepo(config, repo, reponame, revision, tags, bumpFiles, relbranch, pushAttempts): remote = make_hg_url(HG, repo) mercurial(remote, reponame) def bump_and_tag(repo, attempt, config, relbranch, revision, tags): # set relbranchChangesets=1 because tag() generates exactly 1 commit relbranchChangesets = 1 if relbranch in get_branches(reponame): update(reponame, revision=relbranch) else: update(reponame, revision=revision) run_cmd(['hg', 'branch', relbranch], cwd=reponame) if len(bumpFiles) > 0: # Bump files on the relbranch, if necessary bump(reponame, bumpFiles, 'version') run_cmd(['hg', 'diff'], cwd=repo) try: get_output(['hg', 'commit', '-u', config['hgUsername'], '-m', getBumpCommitMessage(config['productName'], config['version'])], cwd=reponame) relbranchChangesets += 1 except subprocess.CalledProcessError, e: # We only want to ignore exceptions caused by having nothing to # commit, which are OK. We still want to raise exceptions caused # by any other thing. if e.returncode != 1 or "nothing changed" not in e.output: raise # We always want our tags pointing at the tip of the relbranch # so we need to grab the current revision after we've switched # branches and bumped versions. revision = get_revision(reponame) # Create the desired tags on the relbranch tag(repo, revision, tags, config['hgUsername']) # Validate that the repository is only different from the remote in # ways we expect. outgoingRevs = out(src=reponame, remote=remote, ssh_username=config['hgUsername'], ssh_key=config['hgSshKey']) if len([r for r in outgoingRevs if r[BRANCH] == relbranch]) != relbranchChangesets: raise Exception("Incorrect number of revisions on %s" % relbranch) if len(outgoingRevs) != relbranchChangesets: raise Exception("Wrong number of outgoing revisions")
else: dest = os.path.basename(repo) # Parse propsfile if options.propsfile: try: import json except ImportError: import simplejson as json js = json.load(open(options.propsfile)) if options.revision is None: options.revision = js['sourcestamp']['revision'] if options.branch is None: options.branch = js['sourcestamp']['branch'] # look for and clobber outgoing changesets if options.outgoing: if out(dest, repo): remove_path(dest) if options.shared_dir and out(options.shared_dir, repo): remove_path(options.shared_dir) got_revision = mercurial(repo, dest, options.branch, options.revision, shareBase=options.shared_dir, clone_by_rev=options.clone_by_rev, mirrors=options.mirrors, bundles=options.bundles, autoPurge=options.auto_purge) print "Got revision %s" % got_revision
# Parse propsfile if options.propsfile: try: import json except ImportError: import simplejson as json js = json.load(open(options.propsfile)) if options.revision is None: options.revision = js['sourcestamp']['revision'] if options.branch is None: options.branch = js['sourcestamp']['branch'] # look for and clobber outgoing changesets if options.outgoing: if out(dest, repo): remove_path(dest) if options.shared_dir and out(options.shared_dir, repo): remove_path(options.shared_dir) got_revision = mercurial(repo, dest, options.branch, options.revision, shareBase=options.shared_dir, clone_by_rev=options.clone_by_rev, mirrors=options.mirrors, bundles=options.bundles, autoPurge=options.auto_purge) print "Got revision %s" % got_revision
update(reponame, revision=defaultBranch) bump(reponame, bumpFiles, 'nextVersion') run_cmd(['hg', 'diff'], cwd=repo) try: get_output(['hg', 'commit', '-u', config['hgUsername'], '-m', getBumpCommitMessage(config['productName'], config['version'])], cwd=reponame) defaultBranchChangesets += 1 except subprocess.CalledProcessError, e: if e.returncode != 1 or "nothing changed" not in e.output: raise # Validate that the repository is only different from the remote in # ways we expect. outgoingRevs = out(src=reponame, remote=remote, ssh_username=config['hgUsername'], ssh_key=config['hgSshKey']) if len([r for r in outgoingRevs if r[BRANCH] == "default"]) != defaultBranchChangesets: raise Exception("Incorrect number of revisions on 'default' branch") if len([r for r in outgoingRevs if r[BRANCH] == relbranch]) != relbranchChangesets: raise Exception("Incorrect number of revisions on %s" % relbranch) if len(outgoingRevs) != (relbranchChangesets + defaultBranchChangesets): raise Exception("Wrong number of outgoing revisions") pushRepo = make_hg_url(HG, repo, protocol='ssh') def bump_and_tag_wrapper(r, n): bump_and_tag(r, n, config, relbranch, revision, tags, defaultBranch) def cleanup_wrapper(): cleanOutgoingRevs(reponame, pushRepo, config['hgUsername'], config['hgSshKey'])
def main(): import argparse import logging parser = argparse.ArgumentParser(description='Tool to do safe operations with hg.') parser.add_argument( "-v", "--verbose", dest="loglevel", action="store_const", const=logging.DEBUG, help="verbose logging", default=logging.INFO) parser.add_argument( "-r", "--rev", dest="revision", help="which revision to update to", default=os.environ.get('HG_REV')) parser.add_argument( "-b", "--branch", dest="branch", help="which branch to update to", default=os.environ.get('HG_BRANCH', None)) parser.add_argument( "-p", "--props-file", dest="propsfile", help="build json file containing revision information", default=os.environ.get('PROPERTIES_FILE')) parser.add_argument( "-s", "--shared-dir", dest="shared_dir", help="clone to a shared directory", default=os.environ.get('HG_SHARE_BASE_DIR')) parser.add_argument( "--check-outgoing", dest="outgoing", action="store_true", help="check for and clobber outgoing changesets", default=False) parser.add_argument( "--clone-by-revision", dest="clone_by_rev", action="store_true", help="do initial clone with -r <rev> instead of cloning the entire repo. " "This is slower but is useful when cloning repositories with many " "heads which may timeout otherwise.", default=False) parser.add_argument( "--mirror", dest="mirrors", action="append", help="add a mirror to try cloning/pulling from before repo", default=None) parser.add_argument( "--bundle", dest="bundles", action="append", help="add a bundle to try downloading/unbundling from before doing a full clone", default=None) parser.add_argument( "--purge", dest="auto_purge", action="store_true", help="Purge the destination directory (if it exists).", default=False) parser.add_argument( "--dest", dest="dest", action="store", help="Destination path.", default=None) parser.add_argument( "--repo", dest="repo", action="store", help="Repo path.", required=True, default=None) options = parser.parse_args() if options.repo is None: parser.error("No repo argument specified.") if options.dest is None: options.dest = os.path.basename(options.repo) logging.basicConfig(level=options.loglevel, format="%(message)s") # Parse propsfile if options.propsfile: try: import json except ImportError: import simplejson as json js = json.load(open(options.propsfile)) if options.revision is None: options.revision = js['sourcestamp']['revision'] if options.branch is None: options.branch = js['sourcestamp']['branch'] # look for and clobber outgoing changesets if options.outgoing: if out(options.dest, options.repo): remove_path(options.dest) if options.shared_dir and out(options.shared_dir, options.repo): remove_path(options.shared_dir) got_revision = mercurial(options.repo, options.dest, options.branch, options.revision, shareBase=options.shared_dir, clone_by_rev=options.clone_by_rev, mirrors=options.mirrors, bundles=options.bundles, autoPurge=options.auto_purge) print "Got revision %s" % got_revision