예제 #1
0
def main(args=None):
    """Performs task to restore backup or check the status of
    backup restoration.
    """
    common.require_cwd_to_be_oppia()
    if not os.path.exists(os.path.dirname(GAE_DIR)):
        raise Exception('Directory %s does not exist.' % GAE_DIR)
    sys.path.insert(0, GAE_DIR)

    options = _PARSER.parse_args(args=args)

    if options.check_status or options.cancel_operation:
        if options.check_status:
            check_backup_restoration_status()
        if options.cancel_operation:
            cancel_operation()
    else:
        if options.project_name is None:
            raise Exception(
                'Please provide project name for backup restoration.')
        set_project(options.project_name)
        initiate_backup_restoration_process()
        python_utils.PRINT('Backup restoration process initiated!\n'
                           'To check the status of the project please run: '
                           'python -m scripts.restore_backup --check_status')
예제 #2
0
def main(personal_access_token):
    """Updates the files corresponding to LOCAL_FECONF_PATH and
    LOCAL_CONSTANTS_PATH after doing the prerequisite checks.

    Args:
        personal_access_token: str. The personal access token for the
            GitHub id of user.
    """
    # Do prerequisite checks.
    common.require_cwd_to_be_oppia()
    assert common.is_current_branch_a_release_branch()
    common.ensure_release_scripts_folder_exists_and_is_up_to_date()
    try:
        python_utils.url_open(TERMS_PAGE_URL)
    except Exception:
        raise Exception('Terms mainpage does not exist on Github.')

    try:
        check_updates_to_terms_of_service(personal_access_token)
        add_mailgun_api_key()

        apply_changes_based_on_config(LOCAL_FECONF_PATH, FECONF_CONFIG_PATH,
                                      FECONF_REGEX)
        apply_changes_based_on_config(LOCAL_CONSTANTS_PATH,
                                      CONSTANTS_CONFIG_PATH, CONSTANTS_REGEX)
    except Exception as e:
        common.run_cmd(
            ['git', 'checkout', '--', LOCAL_FECONF_PATH, LOCAL_CONSTANTS_PATH])
        raise Exception(e)

    common.ask_user_to_confirm(
        'Done! Please check manually to ensure all the changes are correct.')
예제 #3
0
def main():
    """Performs task to initiate the release."""
    common.require_cwd_to_be_oppia()
    common.verify_current_branch_name('develop')
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_NOTES_URL)
    common.ask_user_to_confirm(
        'Please check if anything extra is required for the release. '
        'If so, keep track of this and do it at the appropriate point.')

    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_DRIVE_URL)
    python_utils.PRINT(
        'Has the QA lead created a document for the current release?\n'
        'Confirm by entering y/ye/yes.\n')
    doc_for_release_created = python_utils.INPUT().lower()
    if doc_for_release_created not in (
            release_constants.AFFIRMATIVE_CONFIRMATIONS):
        raise Exception('Please ensure a new doc is created for the '
                        'release before starting with the release process.')

    remote_alias = common.get_remote_alias(release_constants.REMOTE_URL)
    python_utils.PRINT('Enter version of previous release.')
    previous_release_version = python_utils.INPUT()
    assert re.match(r'^\d+\.\d+\.\d+$', previous_release_version)

    extra_jobs_to_run = get_extra_jobs_due_to_schema_changes(
        remote_alias, previous_release_version)
    if did_supported_audio_languages_change(remote_alias,
                                            previous_release_version):
        # This job is run so that an opportunity is created for
        # contributors to translate and voiceover an exploration
        # whenever a new audio language is added.
        # Refer: https://github.com/oppia/oppia/issues/8027.
        extra_jobs_to_run.append(
            'ExplorationOpportunitySummaryModelRegenerationJob')
    if extra_jobs_to_run:
        common.ask_user_to_confirm(
            'Please add the following jobs to release journal and '
            'run them after deployment:\n%s' % '\n'.join(extra_jobs_to_run))

    common.open_new_tab_in_browser_if_possible(
        release_constants.REPEATABLE_JOBS_SPREADSHEETS_URL)
    common.open_new_tab_in_browser_if_possible(
        release_constants.ONE_TIME_JOBS_SPREADSHEET_URL)
    common.ask_user_to_confirm(
        'Please copy the names of the jobs to be run for this release along '
        'with author names, author mail ids & instruction docs.\n'
        'Note: Copy only those jobs that have been successfully run '
        'on backup server.')
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_DRIVE_URL)
    common.ask_user_to_confirm(
        'Please enter the above job names to release journal.')

    cut_release_branch()
예제 #4
0
def update_indexes():
    """Updates production indexes after doing the prerequisite checks."""
    parsed_args = _PARSER.parse_args()
    if parsed_args.app_name:
        app_name = parsed_args.app_name
    else:
        raise Exception('No app name specified.')

    # Do prerequisite checks.
    common.require_cwd_to_be_oppia()
    gcloud_adapter.require_gcloud_to_be_available()
    if not common.is_current_branch_a_release_branch():
        raise Exception(
            'Indexes should only be updated from a release branch.')

    # Update the indexes.
    gcloud_adapter.update_indexes(INDEX_YAML_PATH, app_name)
예제 #5
0
def main(personal_access_token):
    """Updates the files corresponding to LOCAL_FECONF_PATH and
    LOCAL_CONSTANTS_PATH after doing the prerequisite checks.

    Args:
        personal_access_token: str. The personal access token for the
            GitHub id of user.
    """
    # Do prerequisite checks.
    common.require_cwd_to_be_oppia()
    assert common.is_current_branch_a_release_branch(), (
        'Current branch is not a release branch_name')
    common.ensure_release_scripts_folder_exists_and_is_up_to_date()
    try:
        python_utils.url_open(TERMS_PAGE_URL)
    except Exception:
        raise Exception('Terms mainpage does not exist on Github.')

    try:
        check_updates_to_terms_of_service(personal_access_token)
        add_mailgun_api_key()

        apply_changes_based_on_config(
            LOCAL_FECONF_PATH, FECONF_CONFIG_PATH, FECONF_REGEX)
        apply_changes_based_on_config(
            LOCAL_CONSTANTS_PATH, CONSTANTS_CONFIG_PATH, CONSTANTS_REGEX)
    except Exception as e:
        common.run_cmd([
            'git', 'checkout', '--', LOCAL_FECONF_PATH, LOCAL_CONSTANTS_PATH])
        raise Exception(e)

    common.ask_user_to_confirm(
        'Done! Please check feconf.py and assets/constants.ts to ensure that '
        'the changes made are correct. Specifically verify that the '
        'MAILGUN_API_KEY and REDISHOST are updated correctly and '
        'other config changes are corresponding to %s and %s.\n' % (
            FECONF_CONFIG_PATH, CONSTANTS_CONFIG_PATH))
예제 #6
0
파일: deploy.py 프로젝트: KapoorAyush/oppia
def execute_deployment():
    """Executes the deployment process after doing the prerequisite checks.

    Raises:
        Exception. App name is invalid.
        Exception. Custom version is used with production app.
        Exception. App name is not specified.
        Exception. The deployment script is not run from a release or test
            branch.
        Exception. The deployment script is run for prod server from a test
            branch.
        Exception. Current release version has '.' character.
        Exception. Last commit message is invalid.
        Exception. The mailgun API key is not added before deployment.
        Exception. Could not find third party directory.
        Exception. Invalid directory accessed during deployment.
    """
    parsed_args = _PARSER.parse_args()
    custom_version = None
    if parsed_args.app_name:
        app_name = parsed_args.app_name
        if app_name not in [APP_NAME_OPPIASERVER, APP_NAME_OPPIATESTSERVER
                            ] and ('migration' not in app_name):
            raise Exception('Invalid app name: %s' % app_name)
        if parsed_args.version and app_name == APP_NAME_OPPIASERVER:
            raise Exception('Cannot use custom version with production app.')
        # Note that custom_version may be None.
        custom_version = parsed_args.version
    else:
        raise Exception('No app name specified.')

    current_branch_name = common.get_current_branch_name()

    release_dir_name = 'deploy-%s-%s-%s' % (
        '-'.join('-'.join(app_name.split('.')).split(':')),
        current_branch_name, CURRENT_DATETIME.strftime('%Y%m%d-%H%M%S'))
    release_dir_path = os.path.join(os.getcwd(), '..', release_dir_name)

    deploy_data_path = os.path.join(os.getcwd(), os.pardir, 'release-scripts',
                                    'deploy_data', app_name)

    install_third_party_libs.main()

    if not (common.is_current_branch_a_release_branch() or
            (common.is_current_branch_a_test_branch())):
        raise Exception(
            'The deployment script must be run from a release or test branch.')
    if common.is_current_branch_a_test_branch() and (app_name in [
            APP_NAME_OPPIASERVER, APP_NAME_OPPIATESTSERVER
    ]):
        raise Exception('Test branch can only be deployed to backup server.')
    if custom_version is not None:
        current_release_version = custom_version.replace(DOT_CHAR, HYPHEN_CHAR)
    else:
        current_release_version = current_branch_name[
            len(common.RELEASE_BRANCH_NAME_PREFIX):].replace(
                DOT_CHAR, HYPHEN_CHAR)

    # This is required to compose the release_version_library_url
    # (defined in switch_version function) correctly.
    if '.' in current_release_version:
        raise Exception('Current release version has \'.\' character.')

    assert len(current_release_version) <= 25, (
        'The length of the "version" arg should be less than or '
        'equal to 25 characters.')

    # Do prerequisite checks.
    common.require_cwd_to_be_oppia()
    common.ensure_release_scripts_folder_exists_and_is_up_to_date()
    gcloud_adapter.require_gcloud_to_be_available()
    try:
        if app_name == APP_NAME_OPPIASERVER:
            check_release_doc()
            release_version_number = common.get_current_release_version_number(
                current_branch_name)
            last_commit_message = subprocess.check_output(
                'git log -1 --pretty=%B'.split())
            personal_access_token = common.get_personal_access_token()
            if not common.is_current_branch_a_hotfix_branch():
                if not last_commit_message.startswith(
                        'Update authors and changelog for v%s' %
                    (release_version_number)):
                    raise Exception('Invalid last commit message: %s.' %
                                    (last_commit_message))
                g = github.Github(personal_access_token)
                repo = g.get_organization('oppia').get_repo('oppia')
                common.check_blocking_bug_issue_count(repo)
                common.check_prs_for_current_release_are_released(repo)

            check_travis_and_circleci_tests(current_branch_name)
            update_configs.main(personal_access_token)
            with python_utils.open_file(common.FECONF_PATH, 'r') as f:
                feconf_contents = f.read()
                if ('MAILGUN_API_KEY' not in feconf_contents
                        or 'MAILGUN_API_KEY = None' in feconf_contents):
                    raise Exception(
                        'The mailgun API key must be added before deployment.')

        update_configs.add_redishost()

        if not os.path.exists(THIRD_PARTY_DIR):
            raise Exception(
                'Could not find third_party directory at %s. Please run '
                'install_third_party_libs.py prior to running this script.' %
                THIRD_PARTY_DIR)

        current_git_revision = subprocess.check_output(
            ['git', 'rev-parse', 'HEAD']).strip()

        # Create a folder in which to save the release candidate.
        python_utils.PRINT('Ensuring that the release directory parent exists')
        common.ensure_directory_exists(os.path.dirname(release_dir_path))

        # Copy files to the release directory. Omits the .git subfolder.
        python_utils.PRINT('Copying files to the release directory')
        shutil.copytree(os.getcwd(),
                        release_dir_path,
                        ignore=shutil.ignore_patterns('.git'))

        # Change the current directory to the release candidate folder.
        with common.CD(release_dir_path):
            if not os.getcwd().endswith(release_dir_name):
                raise Exception(
                    'Invalid directory accessed during deployment: %s' %
                    os.getcwd())

            python_utils.PRINT('Changing directory to %s' % os.getcwd())

            python_utils.PRINT('Preprocessing release...')
            preprocess_release(app_name, deploy_data_path)

            update_and_check_indexes(app_name)
            build_scripts(parsed_args.maintenance_mode)
            deploy_application_and_write_log_entry(app_name,
                                                   current_release_version,
                                                   current_git_revision)

            python_utils.PRINT('Returning to oppia/ root directory.')

        switch_version(app_name, current_release_version)
        flush_memcache(app_name)
        check_breakage(app_name, current_release_version)

        python_utils.PRINT('Done!')
    finally:
        subprocess.check_output([
            'git', 'checkout', '--', update_configs.LOCAL_FECONF_PATH,
            update_configs.LOCAL_CONSTANTS_PATH, APP_DEV_YAML_PATH
        ])
def execute_branch_cut(target_version, hotfix_number):
    """Creates & pushes the new release branch to Github.

    Args:
        target_version: str. The release version.
        hotfix_number: int. The number for the hotfix branch.

    Raises:
        Exception: Travis tests are failing on the branch from which
            the new branch is cut.
    """

    # Construct the new branch name.
    if not hotfix_number:
        new_branch_type, new_branch_name = _get_release_branch_type_and_name(
            target_version)
    else:
        new_branch_type, new_branch_name = _get_hotfix_branch_type_and_name(
            target_version, hotfix_number)

    # Do prerequisite checks.
    common.require_cwd_to_be_oppia()
    common.verify_local_repo_is_clean()
    common.verify_current_branch_name('develop')

    # Update the local repo.
    remote_alias = common.get_remote_alias(release_constants.REMOTE_URL)
    subprocess.check_call(['git', 'pull', remote_alias, 'develop'])

    verify_target_branch_does_not_already_exist(remote_alias, new_branch_name)

    # The release coordinator should verify that tests are passing on the parent
    # branch before checking out the new branch.
    common.open_new_tab_in_browser_if_possible(
        'https://travis-ci.org/oppia/oppia/branches')
    while True:
        if not hotfix_number:
            branch_to_check = 'develop'
        elif hotfix_number == 1:
            branch_to_check = 'release-%s' % target_version
        else:
            branch_to_check = 'release-%s-hotfix-%s' % (target_version,
                                                        hotfix_number - 1)
        python_utils.PRINT(
            'Please confirm: are Travis checks passing on %s? (y/n) ' %
            (branch_to_check))
        answer = python_utils.INPUT().lower()
        if answer in release_constants.AFFIRMATIVE_CONFIRMATIONS:
            break
        elif answer:
            raise Exception(
                'Tests should pass on %s before this script is run.' %
                (branch_to_check))

    # Cut a new release or hotfix branch.
    if new_branch_type == release_constants.BRANCH_TYPE_HOTFIX:
        verify_hotfix_number_is_one_ahead_of_previous_hotfix_number(
            remote_alias, target_version, hotfix_number)
        if hotfix_number == 1:
            branch_to_cut_from = 'release-%s' % target_version
        else:
            branch_to_cut_from = 'release-%s-hotfix-%s' % (target_version,
                                                           hotfix_number - 1)
        python_utils.PRINT('Cutting a new hotfix branch: %s' % new_branch_name)
        subprocess.check_call(
            ['git', 'checkout', '-b', new_branch_name, branch_to_cut_from])
    else:
        verify_target_version_compatible_with_latest_release(target_version)
        python_utils.PRINT('Cutting a new release branch: %s' %
                           new_branch_name)
        subprocess.check_call(['git', 'checkout', '-b', new_branch_name])

    # Push the new release branch to GitHub.
    python_utils.PRINT('Pushing new %s branch to GitHub.' % new_branch_type)
    subprocess.check_call(['git', 'push', remote_alias, new_branch_name])

    python_utils.PRINT('')
    python_utils.PRINT(
        'New %s branch successfully cut. You are now on branch %s' %
        (new_branch_type, new_branch_name))
    python_utils.PRINT('Done!')

    common.ask_user_to_confirm(
        'Ask Sean (or Ben, if Sean isn\'t available) to create '
        'a new branch protection rule by:\n'
        '1. Going to this page: https://github.com/oppia/oppia/'
        'settings/branch_protection_rules/new.\n'
        '2. Typing in the full branch name %s.\n'
        '3. Checking the box: Restrict who can push to matching '
        'branches (then add the oppia/release-coordinators team)\n' %
        (new_branch_name))
예제 #8
0
def execute_branch_cut(target_version, hotfix_number):
    """Creates & pushes the new release branch to Github.

    Args:
        target_version: str. The release version.
        hotfix_number: int. The number for the hotfix branch.

    Raises:
        Exception. Actions tests are failing on the branch from which
            the new branch is cut.
    """

    # Construct the new branch name.
    if not hotfix_number:
        new_branch_type, new_branch_name = _get_release_branch_type_and_name(
            target_version)
    else:
        new_branch_type, new_branch_name = _get_hotfix_branch_type_and_name(
            target_version, hotfix_number)

    # Do prerequisite checks.
    common.require_cwd_to_be_oppia()
    common.verify_local_repo_is_clean()
    common.verify_current_branch_name('develop')

    # Update the local repo.
    remote_alias = common.get_remote_alias(
        constants.release_constants.REMOTE_URLS)
    subprocess.check_call(['git', 'pull', remote_alias, 'develop'])

    verify_target_branch_does_not_already_exist(remote_alias, new_branch_name)

    if not hotfix_number:
        branch_to_check = 'develop'
    elif hotfix_number == 1:
        branch_to_check = 'release-%s' % target_version
    else:
        branch_to_check = 'release-%s-hotfix-%s' % (target_version,
                                                    hotfix_number - 1)
    # The release coordinator should verify that tests are passing on
    # the parent branch before checking out the new branch.
    common.open_new_tab_in_browser_if_possible(
        'https://github.com/oppia/oppia/actions?query=branch:%s' %
        branch_to_check)
    print('Please confirm: are Actions checks passing on %s? (y/n) ' %
          (branch_to_check))
    answer = input().lower()
    if answer not in common.AFFIRMATIVE_CONFIRMATIONS:
        raise Exception('Tests should pass on %s before this script is run.' %
                        (branch_to_check))

    # Cut a new release or hotfix branch.
    if new_branch_type == constants.release_constants.BRANCH_TYPE_HOTFIX:
        verify_hotfix_number_is_one_ahead_of_previous_hotfix_number(
            remote_alias, target_version, hotfix_number)
        if hotfix_number == 1:
            branch_to_cut_from = 'release-%s' % target_version
        else:
            branch_to_cut_from = 'release-%s-hotfix-%s' % (target_version,
                                                           hotfix_number - 1)
        print('Cutting a new hotfix branch: %s' % new_branch_name)
        subprocess.check_call(['git', 'checkout', branch_to_cut_from])
        common.update_branch_with_upstream()
        subprocess.check_call(
            ['git', 'checkout', '-b', new_branch_name, branch_to_cut_from])
    else:
        verify_target_version_compatible_with_latest_release(target_version)
        print('Cutting a new release branch: %s' % new_branch_name)
        subprocess.check_call(['git', 'checkout', '-b', new_branch_name])

    # Push the new release branch to GitHub.
    if new_branch_type == constants.release_constants.BRANCH_TYPE_RELEASE:
        print('Pushing new %s branch to GitHub.' % new_branch_type)
        subprocess.check_call(['git', 'push', remote_alias, new_branch_name])
    else:
        print('Please cherrypick the required PRs and push the branch '
              'to Github once this script is done.\n'
              'Note: It is fine to push the branch only after creating the '
              'branch protection rule and doing all the cherrypicks.')

    print('')
    print('New %s branch successfully cut. You are now on branch %s' %
          (new_branch_type, new_branch_name))
    print('Done!')
예제 #9
0
def main():
    """Performs task to initiate the release."""
    common.require_cwd_to_be_oppia()
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_NOTES_URL)
    common.ask_user_to_confirm(
        'Please check if anything extra is required for the release. '
        'If so, keep track of this and do it at the appropriate point.')

    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_DRIVE_URL)
    python_utils.PRINT(
        'Has the QA lead created a document for the current release?\n'
        'Confirm by entering y/ye/yes.\n')
    doc_for_release_created = python_utils.INPUT().lower()
    if doc_for_release_created not in (
            release_constants.AFFIRMATIVE_CONFIRMATIONS):
        raise Exception('Please ensure a new doc is created for the '
                        'release before starting with the release process.')

    remote_alias = common.get_remote_alias(release_constants.REMOTE_URL)
    python_utils.PRINT('Enter version of previous release.')
    previous_release_version = python_utils.INPUT()
    assert re.match(r'^\d+\.\d+\.\d+$', previous_release_version)

    extra_jobs_to_run = get_extra_jobs_due_to_schema_changes(
        remote_alias, previous_release_version)
    if did_supported_audio_languages_change(remote_alias,
                                            previous_release_version):
        # This job is run so that an opportunity is created for
        # contributors to translate and voiceover an exploration
        # whenever a new audio language is added.
        # Refer: https://github.com/oppia/oppia/issues/8027.
        extra_jobs_to_run.append(
            'ExplorationOpportunitySummaryModelRegenerationJob')
    if extra_jobs_to_run:
        common.ask_user_to_confirm(
            'Please add the following jobs to release journal and '
            'run them after deployment:\n%s' % '\n'.join(extra_jobs_to_run))
    try:
        # The file here is opened and closed just to create an empty
        # file where the release co-ordinator can enter the credentials.
        f = python_utils.open_file(RELEASE_CREDENTIALS_FILEPATH, 'w')
        f.close()
        common.ask_user_to_confirm(
            'Copy the release json credentials from the release '
            'doc and paste them in the file %s. Make sure to save the '
            'file once you are done.' % (RELEASE_CREDENTIALS_FILEPATH))
        client = pygsheets.authorize(
            client_secret=RELEASE_CREDENTIALS_FILEPATH)

        repeatable_jobs_sheet = client.open(
            'Oppia release team: Submitting an existing job for '
            'testing on the Oppia test server (Responses)').sheet1
        repeatable_job_details = get_job_details_for_current_release(
            repeatable_jobs_sheet.get_all_records(),
            'Select the job you want to test',
            'Which upcoming release are you targeting this job for? ',
            'Email Address', 'What is your name? ',
            'Please give a clear description of why you want to '
            'run this job on the test server')
        repeatable_job_names = [
            job_detail['job_name'] for job_detail in repeatable_job_details
        ]

        one_time_jobs_sheet = client.open(
            'Oppia release team: Submitting a job for testing (Responses)'
        ).sheet1
        one_time_job_details = get_job_details_for_current_release(
            one_time_jobs_sheet.get_all_records(),
            'What is the name of the job to be run?',
            'Which upcoming release are you targeting this job for?',
            'Email Address', 'What is your name?',
            'URL of a Google Doc with clear instructions on what the tester '
            'needs to do:')
        one_time_job_names = [
            job_detail['job_name'] for job_detail in one_time_job_details
        ]

        if repeatable_job_names:
            python_utils.PRINT('Repeatable jobs to run:\n%s\n' %
                               ('\n').join(repeatable_job_names))
        if one_time_job_names:
            python_utils.PRINT('One time jobs to run:\n%s\n' %
                               ('\n').join(one_time_job_names))
        if repeatable_job_names or one_time_job_names:
            common.open_new_tab_in_browser_if_possible(
                release_constants.RELEASE_DRIVE_URL)
            common.ask_user_to_confirm(
                'Please enter the above job names to release journal.')
            common.open_new_tab_in_browser_if_possible(
                release_constants.REPEATABLE_JOBS_SPREADSHEETS_URL)
            common.open_new_tab_in_browser_if_possible(
                release_constants.ONE_TIME_JOBS_SPREADSHEET_URL)
            python_utils.PRINT(
                get_mail_message_template(repeatable_job_details +
                                          one_time_job_details))
            author_mail_ids = [
                job_details['author_email']
                for job_details in (repeatable_job_details +
                                    one_time_job_details)
            ]
            common.ask_user_to_confirm(
                'Note: Send the mail only after deploying to backup server.\n\n'
                'Note: Add author email ids: %s to the cc list when you send '
                'the mail.\n\n'
                'Note: Please check manually if the details in the above mail '
                'are correct and add anything extra if required.\n\n'
                'Copy and save the above template for sending a mail to Sean '
                'to run these jobs on backup server.\n\n'
                'If the jobs are successful on backup server, run them on test '
                'and prod server.' % list(set(author_mail_ids)))
        else:
            python_utils.PRINT('No jobs to run for the release.')
            common.open_new_tab_in_browser_if_possible(
                release_constants.REPEATABLE_JOBS_SPREADSHEETS_URL)
            common.open_new_tab_in_browser_if_possible(
                release_constants.ONE_TIME_JOBS_SPREADSHEET_URL)
            common.ask_user_to_confirm(
                'Please check manually if there are no jobs to run.')
    finally:
        if os.path.isfile(RELEASE_CREDENTIALS_FILEPATH):
            os.remove(RELEASE_CREDENTIALS_FILEPATH)
        if os.path.isfile(AUTH_FILEPATH):
            os.remove(AUTH_FILEPATH)
예제 #10
0
def execute_branch_cut():
    """Pushes the new release branch to Github."""

    parsed_args = _PARSER.parse_args()
    if parsed_args.new_version:
        target_version = parsed_args.new_version
    else:
        raise Exception('ERROR: A "new_version" arg must be specified.')

    # Construct the new branch name.
    hotfix_number = int(parsed_args.hotfix_number)
    if not hotfix_number:
        new_branch_type, new_branch_name = _get_release_branch_type_and_name(
            target_version)
    else:
        new_branch_type, new_branch_name = _get_hotfix_branch_type_and_name(
            target_version, hotfix_number)

    # Do prerequisite checks.
    common.require_cwd_to_be_oppia()
    common.verify_local_repo_is_clean()
    common.verify_current_branch_name('develop')

    # Update the local repo.
    remote_alias = common.get_remote_alias(release_constants.REMOTE_URL)
    subprocess.check_call(['git', 'pull', remote_alias, 'develop'])

    verify_target_branch_does_not_already_exist(remote_alias, new_branch_name)

    # The release coordinator should verify that tests are passing on develop
    # before checking out the release branch.
    common.open_new_tab_in_browser_if_possible(
        'https://github.com/oppia/oppia#oppia---')
    while True:
        if not hotfix_number:
            branch_to_check = 'develop'
        elif hotfix_number == 1:
            branch_to_check = 'release-%s' % target_version
        else:
            branch_to_check = 'release-%s-hotfix-%s' % (
                target_version, hotfix_number - 1)
        python_utils.PRINT(
            'Please confirm: are Travis checks passing on %s? (y/n) ' % (
                branch_to_check))
        answer = python_utils.INPUT().lower()
        if answer in release_constants.AFFIRMATIVE_CONFIRMATIONS:
            break
        elif answer:
            python_utils.PRINT(
                'Tests should pass on %s before this script is run. '
                'Exiting.' % branch_to_check)
            sys.exit()

    # Cut a new release or hotfix branch.
    if new_branch_type == release_constants.BRANCH_TYPE_HOTFIX:
        verify_hotfix_number_is_one_ahead_of_previous_hotfix_number(
            remote_alias, target_version, hotfix_number)
        if hotfix_number == 1:
            branch_to_cut_from = 'release-%s' % target_version
        else:
            branch_to_cut_from = 'release-%s-hotfix-%s' % (
                target_version, hotfix_number - 1)
        python_utils.PRINT('Cutting a new hotfix branch: %s' % new_branch_name)
        subprocess.check_call([
            'git', 'checkout', '-b', new_branch_name, branch_to_cut_from])
    else:
        verify_target_version_compatible_with_latest_release(
            target_version)
        python_utils.PRINT('Cutting a new release branch: %s' % new_branch_name)
        subprocess.check_call(['git', 'checkout', '-b', new_branch_name])

    # Push the new release branch to GitHub.
    python_utils.PRINT('Pushing new %s branch to GitHub.' % new_branch_type)
    subprocess.check_call(['git', 'push', remote_alias, new_branch_name])

    python_utils.PRINT('')
    python_utils.PRINT(
        'New %s branch successfully cut. You are now on branch %s' % (
            new_branch_type, new_branch_name))
    python_utils.PRINT('Done!')