Пример #1
0
def open_new_tab_in_browser_if_possible(url):
    """Opens the given URL in a new browser tab, if possible."""
    if USER_PREFERENCES['open_new_tab_in_browser'] is None:
        python_utils.PRINT(
            '\nDo you want the url to be opened in the browser? '
            'Confirm by entering y/ye/yes.')
        USER_PREFERENCES['open_new_tab_in_browser'] = python_utils.INPUT()
    if USER_PREFERENCES['open_new_tab_in_browser'] not in ['y', 'ye', 'yes']:
        python_utils.PRINT('Please open the following link in browser: %s' %
                           url)
        return
    browser_cmds = ['chromium-browser', 'google-chrome', 'firefox']
    for cmd in browser_cmds:
        if subprocess.call(['which', cmd]) == 0:
            subprocess.check_call([cmd, url])
            return
    python_utils.PRINT(
        '******************************************************************')
    python_utils.PRINT(
        'WARNING: Unable to open browser. Please manually open the following')
    python_utils.PRINT('URL in a browser window, then press Enter to confirm.')
    python_utils.PRINT('')
    python_utils.PRINT('    %s' % url)
    python_utils.PRINT('')
    python_utils.PRINT(
        'NOTE: To get rid of this message, open scripts/common.py and fix')
    python_utils.PRINT(
        'the function open_new_tab_in_browser_if_possible() to work on your')
    python_utils.PRINT('system.')
    python_utils.INPUT()
Пример #2
0
def check_travis_and_circleci_tests(current_branch_name):
    """Checks if all travis and circleci tests are passing on release branch.

    Args:
        current_branch_name: str. The name of current branch.

    Raises:
        Exception: The latest commit on release branch locally does not match
            the latest commit on local fork or upstream.
        Exception: The travis or circleci tests are failing.
    """
    local_sha = subprocess.check_output(
        ['git', 'rev-parse', current_branch_name])
    origin_sha = subprocess.check_output(
        ['git', 'rev-parse',
         'origin/%s' % current_branch_name])
    upstream_sha = subprocess.check_output([
        'git', 'rev-parse',
        '%s/%s' % (common.get_remote_alias(
            release_constants.REMOTE_URL), current_branch_name)
    ])
    if local_sha != origin_sha:
        raise Exception('The latest commit on release branch locally does '
                        'not match the latest commit on your local fork.')
    if local_sha != upstream_sha:
        raise Exception('The latest commit on release branch locally does '
                        'not match the latest commit on Oppia repo.')

    python_utils.PRINT('\nEnter your GitHub username.\n')
    github_username = python_utils.INPUT().lower()

    travis_url = 'https://travis-ci.org/%s/oppia/branches' % github_username
    circleci_url = 'https://circleci.com/gh/%s/workflows/oppia' % (
        github_username)

    try:
        python_utils.url_open(travis_url)
    except Exception:
        travis_url = 'https://travis-ci.org/oppia/oppia/branches'

    try:
        python_utils.url_open(circleci_url)
    except Exception:
        circleci_url = 'https://circleci.com/gh/oppia/workflows/oppia'

    common.open_new_tab_in_browser_if_possible(travis_url)
    python_utils.PRINT('Are all travis tests passing on branch %s?\n' %
                       current_branch_name)
    travis_tests_passing = python_utils.INPUT().lower()
    if travis_tests_passing not in release_constants.AFFIRMATIVE_CONFIRMATIONS:
        raise Exception('Please fix the travis tests before deploying.')

    common.open_new_tab_in_browser_if_possible(circleci_url)
    python_utils.PRINT('Are all circleci tests passing on branch %s?\n' %
                       current_branch_name)
    circleci_tests_passing = python_utils.INPUT().lower()
    if circleci_tests_passing not in (
            release_constants.AFFIRMATIVE_CONFIRMATIONS):
        raise Exception('Please fix the circleci tests before deploying.')
Пример #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 switch_version(app_name, current_release_version):
    """Switches version if library page loads correctly.

    Args:
        app_name: str. The name of the app to deploy.
        current_release_version: str. The version of the current release.

    Raises:
        Exception. The library page does not load correctly.
    """
    release_version_library_url = (
        'https://%s-dot-%s.appspot.com/community-library' %
        (current_release_version, app_name))
    library_page_loads_correctly = check_errors_in_a_page(
        release_version_library_url, 'Library page is loading correctly?')

    if not library_page_loads_correctly:
        raise Exception(
            'Aborting version switch due to issues in library page '
            'loading.')

    version_switch = release_constants.AFFIRMATIVE_CONFIRMATIONS[0]
    if common.is_current_branch_a_hotfix_branch():
        python_utils.PRINT('Do you want to switch version?')
        version_switch = python_utils.INPUT()

    if version_switch in release_constants.AFFIRMATIVE_CONFIRMATIONS:
        gcloud_adapter.switch_version(app_name, current_release_version)
        python_utils.PRINT('Successfully migrated traffic to release version!')
Пример #5
0
def check_updates_to_terms_of_service(
        release_feconf_path, personal_access_token):
    """Checks if updates are made to terms of service and updates
    REGISTRATION_PAGE_LAST_UPDATED_UTC in feconf.py if there are updates.

    Args:
        release_feconf_path: str. The path to feconf file in release
            directory.
        personal_access_token: str. The personal access token for the
            GitHub id of user.
    """
    g = github.Github(personal_access_token)
    repo = g.get_organization('oppia').get_repo('oppia')

    common.open_new_tab_in_browser_if_possible(TERMS_PAGE_URL)
    python_utils.PRINT(
        'Are the terms of service changed? Check commits/changes made '
        'to the file: terms-page.mainpage.html. Enter y/ye/yes if they '
        'are changed else enter n/no.')
    terms_of_service_are_changed = python_utils.INPUT().lower()
    while terms_of_service_are_changed not in ['y', 'ye', 'yes', 'n', 'no']:
        python_utils.PRINT(
            'Invalid Input: %s. Please enter yes or no.' % (
                terms_of_service_are_changed))
        terms_of_service_are_changed = python_utils.INPUT().lower()

    if terms_of_service_are_changed in (
            release_constants.AFFIRMATIVE_CONFIRMATIONS):
        python_utils.PRINT(
            'Enter sha of the commit which changed the terms of service.')
        commit_sha = python_utils.INPUT().lstrip().rstrip()
        commit_time = repo.get_commit(commit_sha).commit.committer.date
        time_tuple = (
            commit_time.year, commit_time.month, commit_time.day,
            commit_time.hour, commit_time.minute, commit_time.second)
        feconf_lines = []
        with python_utils.open_file(release_feconf_path, 'r') as f:
            feconf_lines = f.readlines()
        with python_utils.open_file(release_feconf_path, 'w') as f:
            for line in feconf_lines:
                if line.startswith('REGISTRATION_PAGE_LAST_UPDATED_UTC'):
                    line = (
                        'REGISTRATION_PAGE_LAST_UPDATED_UTC = '
                        'datetime.datetime(%s, %s, %s, %s, %s, %s)\n' % (
                            time_tuple))
                f.write(line)
Пример #6
0
def cancel_operation():
    """Cancels a datastore operation."""
    python_utils.PRINT('Cancellation of operation may corrupt the datastore. '
                       'Refer: https://cloud.google.com/datastore/docs/'
                       'export-import-entities#cancel_an_operation\n'
                       'Do you want to continue?\n')
    execute_cancellation = python_utils.INPUT().lower()
    if execute_cancellation not in release_constants.AFFIRMATIVE_CONFIRMATIONS:
        python_utils.PRINT('Aborting Cancellation.')
        return

    python_utils.PRINT('List of operations in progress:\n')
    check_backup_restoration_status()
    python_utils.PRINT(
        'Enter the name of the operation to cancel from the above list. '
        'The name of an operation is listed in the field called "name". '
        'Check the example here: https://stackoverflow.com/a/53630367 for '
        'details.\n')
    operation_name = python_utils.INPUT()
    common.run_cmd(
        [GCLOUD_PATH, 'datastore', 'operations', 'cancel', operation_name])
Пример #7
0
def ask_user_to_confirm(message):
    """Asks user to perform a task and confirm once they are done.

    Args:
        message: str. The message which specifies the task user has
            to do.
    """
    while True:
        python_utils.PRINT(
            '******************************************************')
        python_utils.PRINT(message)
        python_utils.PRINT('Confirm once you are done by entering y/ye/yes.\n')
        answer = python_utils.INPUT().lower()
        if answer in release_constants.AFFIRMATIVE_CONFIRMATIONS:
            return
Пример #8
0
def initiate_backup_restoration_process():
    """Initiate the backup restoration process on backup migration server."""
    common.open_new_tab_in_browser_if_possible(LIST_OF_BUCKETS_URL)
    python_utils.PRINT(
        'Navigate into the newest backup folder. \n'
        'There should be a file here of the form '
        '<date_time>.overall_export_metadata. \n'
        'For example, "20181122-090002.overall_export_metadata". '
        'This is the file you want to import.\n'
        'Please copy and enter the name of this file\n')
    export_metadata_filepath = python_utils.INPUT()
    common.run_cmd([
        GCLOUD_PATH, 'datastore', 'import',
        'gs://%s' % export_metadata_filepath, '--async'
    ])
Пример #9
0
def _execute_branch_cut():
    """Pushes the new release branch to Github."""

    # 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('[email protected]:oppia/oppia.git')
    subprocess.call(['git', 'pull', remote_alias])

    _verify_target_branch_does_not_already_exist(remote_alias)
    _verify_target_version_is_consistent_with_latest_released_version()

    # 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:
        python_utils.PRINT(
            'Please confirm: are Travis checks passing on develop? (y/n) ')
        answer = python_utils.INPUT().lower()
        if answer in release_constants.AFFIRMATIVE_CONFIRMATIONS:
            break
        elif answer:
            python_utils.PRINT(
                'Tests should pass on develop before this script is run. '
                'Exiting.')
            sys.exit()

    # Cut a new release branch.
    python_utils.PRINT('Cutting a new release branch: %s' % NEW_BRANCH_NAME)
    subprocess.call(['git', 'checkout', '-b', NEW_BRANCH_NAME])

    # Push the new release branch to GitHub.
    python_utils.PRINT('Pushing new release branch to GitHub.')
    subprocess.call(['git', 'push', remote_alias, NEW_BRANCH_NAME])

    python_utils.PRINT('')
    python_utils.PRINT(
        'New release branch successfully cut. You are now on branch %s' %
        NEW_BRANCH_NAME)
    python_utils.PRINT('Done!')
Пример #10
0
def cut_release_branch():
    """Calls the cut_release_or_hotfix_branch script to cut a release branch.

    Raises:
        AssertionError. The version entered is invalid.
    """
    common.open_new_tab_in_browser_if_possible(
        'https://github.com/oppia/oppia/releases')
    python_utils.PRINT(
        'Enter the new version for the release.\n'
        'If major changes occurred since the last release, or if '
        'the third version is a 9, increment the minor version '
        '(e.g. 2.5.3 -> 2.6.0 or 2.5.9 -> 2.6.0)\n'
        'Otherwise, increment the third version number '
        '(e.g. 2.5.3 -> 2.5.4)\n')
    release_version = python_utils.INPUT()
    assert re.match(r'\d+\.\d+\.\d+$', release_version)
    cut_release_or_hotfix_branch.main(
        args=['--release_version=%s' % release_version])
Пример #11
0
def initiate_backup_restoration_process():
    """Initiate the backup restoration process on backup migration server."""
    common.open_new_tab_in_browser_if_possible(LIST_OF_BUCKETS_URL)
    python_utils.PRINT('Navigate into the newest backup folder. \n'
                       'There should be a file here of the form '
                       '<date_time>.overall_export_metadata. \n'
                       'For example, "<folder-name>/20200213-090001/'
                       '20200213-090001.overall_export_metadata". '
                       'This is the file you want to import.\n'
                       'Please copy and enter the full path of this file\n')
    export_metadata_filepath = python_utils.INPUT()
    if not re.match(
            r'^oppia-export-backups/(\d{8}-\d{6})/\1\.overall_export_metadata$',
            export_metadata_filepath):
        raise Exception('Invalid export metadata filepath: %s' %
                        (export_metadata_filepath))
    common.run_cmd([
        GCLOUD_PATH, 'datastore', 'import',
        'gs://%s' % export_metadata_filepath, '--async'
    ])
Пример #12
0
def open_new_tab_in_browser_if_possible(url):
    """Opens the given URL in a new browser tab, if possible."""
    browser_cmds = ['chromium-browser', 'google-chrome', 'firefox']
    for cmd in browser_cmds:
        if subprocess.call(['which', cmd]) == 0:
            subprocess.check_call([cmd, url])
            return
    python_utils.PRINT(
        '******************************************************************')
    python_utils.PRINT(
        'WARNING: Unable to open browser. Please manually open the following')
    python_utils.PRINT('URL in a browser window, then press Enter to confirm.')
    python_utils.PRINT('')
    python_utils.PRINT('    %s' % url)
    python_utils.PRINT('')
    python_utils.PRINT(
        'NOTE: To get rid of this message, open scripts/common.py and fix')
    python_utils.PRINT(
        'the function open_new_tab_in_browser_if_possible() to work on your')
    python_utils.PRINT('system.')
    python_utils.INPUT()
Пример #13
0
def check_errors_in_a_page(url_to_check, msg_to_confirm):
    """Prompts user to check errors in a page.

    Args:
        url_to_check: str. The url of the page to be tested.
        msg_to_confirm: str. The message displayed asking user for confirmation.

    Returns:
        bool. Whether the page has errors or not.
    """
    common.open_new_tab_in_browser_if_possible(url_to_check)
    while True:
        python_utils.PRINT(
            '******************************************************')
        python_utils.PRINT('PLEASE CONFIRM: %s See %s '
                           '(y/n)' % (msg_to_confirm, url_to_check))
        answer = python_utils.INPUT().lower()
        if answer in release_constants.AFFIRMATIVE_CONFIRMATIONS:
            return True
        elif answer:
            return False
Пример #14
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!')
Пример #15
0
def _execute_branch_cut():
    """Pushes the new release branch to Github."""

    # 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('[email protected]:oppia/oppia.git')
    subprocess.call(['git', 'pull', remote_alias])

    _verify_target_branch_does_not_already_exist(remote_alias)
    _verify_target_version_is_consistent_with_latest_released_version()

    # 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 == 'hotfix':
        _verify_hotfix_number_is_one_ahead_of_previous_hotfix_number(
            remote_alias)
        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.call(
            ['git', 'checkout', '-b', NEW_BRANCH_NAME, branch_to_cut_from])
    else:
        python_utils.PRINT('Cutting a new release branch: %s' %
                           NEW_BRANCH_NAME)
        subprocess.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.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!')
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))
Пример #17
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)