def bump_repos_version(module_name, new_version, local_only):
    """
    Changes the pinned version number in the requirements files of all repos
    which have the specified Python module as a dependency.

    This script assumes that GITHUB_TOKEN is set for GitHub authentication.
    """
    # Make the cloning directory and change directories into it.
    tmp_dir = tempfile.mkdtemp(dir=os.getcwd())

    # Iterate through each repository.
    for owner, repo_name in REPOS_TO_CHANGE:
        repo_url = REPO_URL_FORMAT.format(owner, repo_name)

        gh = GitHubApiUtils(owner, repo_name)

        os.chdir(tmp_dir)

        # Clone the repo.
        ret_code = subprocess.call(['git', 'clone', '{}.git'.format(repo_url)])
        if ret_code:
            logging.error('Failed to clone repo {}'.format(repo_url))
            continue

        # Change into the cloned repo dir.
        os.chdir(repo_name)

        # Create a branch, using the version number.
        branch_name = '{}/{}'.format(module_name, new_version)
        ret_code = subprocess.call(['git', 'checkout', '-b', branch_name])
        if ret_code:
            logging.error('Failed to create branch in repo {}'.format(repo_url))
            continue

        # Search through all TXT files to find all lines with the module name, changing the pinned version.
        files_changed = False
        for root, _dirs, files in os.walk('.'):
            for file in files:
                if file.endswith('.txt') and (('requirements' in file) or ('requirements' in root)):
                    found = False
                    filepath = os.path.join(root, file)
                    with open(filepath) as f:
                        if '{}=='.format(module_name) in f.read():
                            found = True
                    if found:
                        files_changed = True
                        # Change the file in-place.
                        for line in fileinput.input(filepath, inplace=True):
                            if '{}=='.format(module_name) in line:
                                print '{}=={}'.format(module_name, new_version)
                            else:
                                print line,

        if not files_changed:
            # Module name wasn't found in the requirements files.
            logging.info("Module name '{}' not found in repo {} - skipping.".format(module_name, repo_url))
            continue

        # Add/commit the files.
        ret_code = subprocess.call(['git', 'commit', '-am', 'Updating {} requirement to version {}'.format(module_name, new_version)])
        if ret_code:
            logging.error("Failed to add and commit changed files to repo {}".format(repo_url))
            continue

        if local_only:
            # For local_only, don't push the branch to the remote and create the PR - leave all changes local for review.
            continue

        # Push the branch.
        ret_code = subprocess.call(['git', 'push', '--set-upstream', 'origin', branch_name])
        if ret_code:
            logging.error("Failed to push branch {} upstream for repo {}".format(branch_name, repo_url))
            continue

        # Create a PR with an automated message.
        rollback_branch_push = False
        try:
            # The GitHub "mention" below does not work via the API - unfortunately...
            response = gh.create_pull(
                title='Change {} version.'.format(module_name),
                body='Change the required version of {} to {}.\n\n@edx-ops/pipeline-team Please review and tag appropriate parties.'.format(module_name, new_version),
                head=branch_name,
                base='master'
            )
        except:
            logging.error('Failed to create PR for repo {} - did you set GITHUB_TOKEN?'.format(repo_url))
            rollback_branch_push = True
        else:
            logging.info('Created PR #{} for repo {}: {}'.format(response.number, repo_url, response.html_url))

        if rollback_branch_push:
            # Since the PR creation failed, delete the branch in the remote repo as well.
            ret_code = subprocess.call(['git', 'push', 'origin', '--delete', branch_name])
            if ret_code:
                logging.error("ROLLBACK: Failed to delete upstream branch {} for repo {}".format(branch_name, repo_url))

    if not local_only:
        # Remove the temp directory containing all the cloned repos.
        shutil.rmtree(tmp_dir)