Ejemplo n.º 1
0
def check_release_doc():
    """Asks the co-ordinator to create a doc for the current release.
    or update the doc for the hotfix.
    """
    message = ('Please create a dedicated section for this release in the '
               'release tracking document created by the QA Lead.\n'
               'The three tabs in your browser point to: '
               'Release drive url, template for the release notes, example of '
               'release notes from previous release.')
    if common.is_current_branch_a_hotfix_branch():
        message = (
            'Please ensure you note down the notes for the hotfix in the '
            'release tracking document created by the QA Lead for the release '
            'corresponding to the hotfix.\n'
            'The three tabs in your browser point to: '
            'Release drive url, template for the release notes, example of '
            'release notes from previous release.')

    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_DRIVE_URL)
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_NOTES_TEMPLATE_URL)
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_NOTES_EXAMPLE_URL)
    common.ask_user_to_confirm(message)
def validate_release_message():
    """Checks the message after the mail template is updated by the
    user.
    """
    # Validation will work fine for cases where no new contributors are
    # found since in that case the release co-ordinator will completely
    # remove the new contributors section from the announcement mail.
    message_is_invalid = True
    while message_is_invalid:
        mail_message_file = python_utils.open_file(
            RELEASE_MAIL_MESSAGE_FILEPATH, 'r')
        release_mail_message = mail_message_file.read()
        extra_sections = [
            section for section in SECTIONS_TO_ADD
            if (section in release_mail_message)
        ]
        if extra_sections:
            common.ask_user_to_confirm(
                'Template not formatted correctly. '
                'Following sections still not updated: %s.\n'
                'Please update the sections correctly.' %
                (', '.join(extra_sections)))
            common.ask_user_to_confirm('Please save the file.')
        else:
            message_is_invalid = False
Ejemplo n.º 3
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.')
Ejemplo n.º 4
0
def flush_memcache(app_name):
    """Flushes the memcache.

    Args:
        app_name: str. The name of the app to deploy.
    """
    memcache_url = ('https://console.cloud.google.com/appengine/memcache?'
                    'src=ac&project=%s') % app_name
    common.open_new_tab_in_browser_if_possible(memcache_url)
    common.ask_user_to_confirm('Please flush the memcache.')
Ejemplo n.º 5
0
def ask_user_to_update_jobs_tracker():
    """Asks the release co-ordinator to update the status of jobs run
    in the release.
    """
    common.open_new_tab_in_browser_if_possible(
        release_constants.JOBS_SPREADSHEETS_URL)
    common.ask_user_to_confirm(
        'Move all the jobs which are run (both successful & failed ones) to '
        'the past jobs tab in the jobs tracker.\n')
    common.ask_user_to_confirm(
        'Send updates regarding each job to the job author '
        '(just the success/failure status, don\'t include any data or '
        'job output).\n')
Ejemplo n.º 6
0
def ask_user_to_remove_protection_rule():
    """Asks the release co-ordinator to perform the steps for deletion of
    github protection rule for release branch.
    """
    common.ask_user_to_confirm(
        'Ask Sean to delete '
        'the github protection rule by:\n'
        '1. Going to this page: '
        'https://github.com/oppia/oppia/settings/branches. '
        '(Note, this link will give a 404 since access is limited to Sean.)\n'
        '2. Delete the github protection rule for %s branch but leave the '
        'existing release-* rule as-is. This will cause the branch to fall '
        'under the general protection rule for release branches\n' %
        (common.get_current_branch_name()))
Ejemplo n.º 7
0
def create_release_doc():
    """Asks the co-ordinator to create a doc for the current release."""
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_DRIVE_URL)
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_NOTES_TEMPLATE_URL)
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_NOTES_EXAMPLE_URL)
    common.ask_user_to_confirm(
        'Please create a dedicated section for this release in the '
        'release tracking document created by the QA Lead.\n'
        'The three tabs in your browser point to: '
        'Release drive url, template for the release notes, example of release '
        'notes from previous release.')
Ejemplo n.º 8
0
def create_new_file_with_release_message_template():
    """Adds the template message to release mail filepath."""
    with python_utils.open_file(RELEASE_MAIL_MESSAGE_FILEPATH, 'w') as f:
        f.write(RELEASE_MAIL_MESSAGE_TEMPLATE)

    common.ask_user_to_confirm(
        'Please make updates to following file %s for generating the '
        'release announcement mail by adding:\n'
        '   1. Main changes for release\n'
        '   2. Editorials/announcements if required\n'
        '   3. Author details from release_summary.md\n'
        '   4. Names of release testers\n'
        '   5. Name of QA Team lead\n'
        '   6. Your name\n' % RELEASE_MAIL_MESSAGE_FILEPATH)
Ejemplo n.º 9
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()
Ejemplo n.º 10
0
def main(release_dir_path, deploy_data_path, personal_access_token,
         prompt_for_mailgun_and_terms_update):
    """Updates the files corresponding to LOCAL_FECONF_PATH and
    LOCAL_CONSTANTS_PATH after doing the prerequisite checks.

    Args:
        release_dir_path: str. Path of directory where all files are copied
            for release.
        deploy_data_path: str. Path for deploy data directory.
        personal_access_token: str. The personal access token for the
            GitHub id of user.
        prompt_for_mailgun_and_terms_update: bool. Whether to update mailgun api
            and last updated time for terms page.
    """
    # Do prerequisite checks.
    feconf_config_path = os.path.join(deploy_data_path,
                                      'feconf_updates.config')
    constants_config_path = os.path.join(deploy_data_path,
                                         'constants_updates.config')

    release_feconf_path = os.path.join(release_dir_path, common.FECONF_PATH)
    release_constants_path = os.path.join(release_dir_path,
                                          common.CONSTANTS_FILE_PATH)

    if prompt_for_mailgun_and_terms_update:
        try:
            python_utils.url_open(TERMS_PAGE_URL)
        except Exception:
            raise Exception('Terms mainpage does not exist on Github.')
        add_mailgun_api_key(release_feconf_path)
        check_updates_to_terms_of_service(release_feconf_path,
                                          personal_access_token)

    apply_changes_based_on_config(release_feconf_path, feconf_config_path,
                                  FECONF_REGEX)
    apply_changes_based_on_config(release_constants_path,
                                  constants_config_path, CONSTANTS_REGEX)

    common.ask_user_to_confirm(
        'Done! Please check %s and %s 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' %
        (release_feconf_path, release_constants_path, feconf_config_path,
         constants_config_path))
Ejemplo n.º 11
0
def draft_new_release():
    """Drafts a new release tag on github."""
    release_version = common.get_current_release_version_number(
        common.get_current_branch_name())
    remote_alias = common.get_remote_alias(release_constants.REMOTE_URL)
    subprocess.check_call([
        'git', 'tag', '-a', 'v%s' % release_version,
        '-m', 'Version %s' % release_version])
    subprocess.check_call([
        'git', 'push', remote_alias, 'v%s' % release_version])
    common.open_new_tab_in_browser_if_possible(
        release_constants.NEW_RELEASE_URL)
    common.open_new_tab_in_browser_if_possible(
        release_constants.GITHUB_RELEASE_TAB_URL)
    common.ask_user_to_confirm(
        'Please draft a new release on GitHub pointing to the '
        'new tag and including relevant changelog information.\n'
        'The two tabs in your browser point to: '
        'Page to draft a new release, examples of previous releases.')
Ejemplo n.º 12
0
def flush_memcache(app_name):
    """Flushes the memcache.

    Args:
        app_name: str. The name of the app to deploy.
    """
    memcache_url = ('https://console.cloud.google.com/appengine/memcache?'
                    'src=ac&project=%s') % app_name
    common.open_new_tab_in_browser_if_possible(memcache_url)
    common.ask_user_to_confirm('Please flush the memcache.')

    admin_misc_tab_url = None
    if app_name == APP_NAME_OPPIASERVER:
        admin_misc_tab_url = 'https://www.oppia.org/admin#/misc'
    else:
        admin_misc_tab_url = 'https://%s.appspot.com/admin#/misc' % app_name

    if admin_misc_tab_url:
        common.open_new_tab_in_browser_if_possible(admin_misc_tab_url)
        common.ask_user_to_confirm('Please flush the cache on Oppia website.')
Ejemplo n.º 13
0
def create_group_for_next_release():
    """Asks the release co-ordinator to create a new chat group for
    the next release.
    """
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_ROTA_URL)
    common.ask_user_to_confirm(
        'Please do the following two things:\n\n'
        '1. Create a new chat group for the next release, '
        'and add the release coordinator, QA lead, Ankita '
        'and Nithesh to that group. You can find the release schedule '
        'and coordinators here: %s\n\n'
        '2. Please send the following message to the newly created group:\n\n'
        'Hi all, This is the group chat for the next release. '
        '[Release co-ordinator\'s name] and [QA Lead\'s name] will be '
        'the release co-ordinator & QA Lead for next release. '
        'Please follow the release process doc: '
        '[Add link to release process doc] to ensure the release '
        'follows the schedule. Thanks!\n' %
        (release_constants.RELEASE_ROTA_URL))
Ejemplo n.º 14
0
def prompt_user_to_send_announcement_email():
    """Asks the user to send release announcement mail and check if
    it is in announcement category.
    """
    new_contributors_mail_ids = (', ').join(
        get_new_authors_and_contributors_mail_ids())
    common.open_new_tab_in_browser_if_possible('https://www.gmail.com')
    common.ask_user_to_confirm(
        'Please copy the mail message from %s and send the email to:\n'
        '   TO: [email protected]\n'
        '   BCC: [email protected], '
        '[email protected], %s\n'
        'Please make sure to check that the mail ids of new authors '
        'and contributors are correct.\n' %
        (RELEASE_MAIL_MESSAGE_FILEPATH, new_contributors_mail_ids))

    common.open_new_tab_in_browser_if_possible(
        'https://groups.google.com/forum/#!categories/oppia/announcements')
    common.ask_user_to_confirm(
        'Ensure the email sent to oppia@ is in the Announcements category')
Ejemplo n.º 15
0
def inform_server_errors_team(release_rota_url, server_error_playbook_url):
    """Asks the release coordinator to inform the server errors team
    that the release will be deployed to production.

    Args:
        release_rota_url: str. URL pointing to the page which lists the rota
            to be followed for release coordinators.
        server_error_playbook_url: str. URL pointing to the server error team
            playbook.
    """
    common.open_new_tab_in_browser_if_possible(release_rota_url)
    common.open_new_tab_in_browser_if_possible(server_error_playbook_url)
    common.ask_user_to_confirm(
        'Ping the Server errors team coordinator (you can find them here: %s) '
        'that the release will be deployed on the production server and '
        'send them the Playbook for the Server Errors Team: %s.'
        'Wait for them to confirm they have done all the stuff that was needed '
        'before doing the deployment. If there is no response in 24 hours '
        'then go ahead with the deployment.' %
        (release_rota_url, server_error_playbook_url))
Ejemplo n.º 16
0
def create_new_file_with_release_message_template():
    """Adds the template message to release mail filepath."""
    release_version = common.get_current_release_version_number(
        common.get_current_branch_name())
    with python_utils.open_file(RELEASE_MAIL_MESSAGE_FILEPATH, 'w') as f:
        f.write(RELEASE_MAIL_MESSAGE_TEMPLATE % (
            tuple([release_version] + SECTIONS_TO_ADD)))

    common.ask_user_to_confirm(
        'Please make updates to following file %s for generating the '
        'release announcement mail by adding:\n'
        '   1. Main changes for release\n'
        '   2. Screenshots/celebration text for major changes. You can '
        'collect these from project leads\n'
        '   3. Editorials/announcements if required\n'
        '   4. Author details from release_summary.md\n'
        '   5. Names of release testers\n'
        '   6. Name of QA Team lead\n'
        '   7. Your name\n' % RELEASE_MAIL_MESSAGE_FILEPATH)
    common.ask_user_to_confirm('Please save the file.')
Ejemplo n.º 17
0
def prompt_user_to_send_announcement_email():
    """Asks the user to send release announcement mail and check if
    it is in announcement category.
    """
    new_contributors_mail_ids = (', ').join(
        get_new_authors_and_contributors_mail_ids())
    release_version = common.get_current_release_version_number(
        common.get_current_branch_name())
    common.open_new_tab_in_browser_if_possible(
        'https://www.gmail.com')
    common.ask_user_to_confirm(
        'Please copy the mail message from %s and send the email to:\n'
        '   TO: [email protected]\n'
        '   BCC: [email protected], '
        '[email protected], %s\n'
        'with the following subject: "Announcing release v%s of Oppia!"'
        'Please make sure to check that the mail ids of new authors '
        'and contributors are correct.\n' % (
            RELEASE_MAIL_MESSAGE_FILEPATH, new_contributors_mail_ids,
            release_version))
    common.open_new_tab_in_browser_if_possible(
        'https://groups.google.com/forum/#!categories/oppia')
    common.ask_user_to_confirm('Add announcements label to the email sent.\n')
    common.ask_user_to_confirm(
        'Ensure the email sent to oppia@ is in the Announcements category')
Ejemplo n.º 18
0
def get_release_summary_lines():
    """Returns the lines from release summary file. It checks whether
    incorrect email is present or ordering of sections is invalid.
    In either case, the user will be asked to update the release
    summary file and the lines will be re-read.

    Returns:
        list(str). List of lines in ../release_summary.md.
    """
    invalid_email_is_present = True
    ordering_is_invalid = True
    while invalid_email_is_present or ordering_is_invalid:
        release_summary_file = python_utils.open_file(
            constants.release_constants.RELEASE_SUMMARY_FILEPATH, 'r')
        release_summary_lines = release_summary_file.readlines()
        invalid_email_is_present = is_invalid_email_present(
            release_summary_lines)
        if invalid_email_is_present:
            common.ask_user_to_confirm(
                'The release summary file contains emails of the form: %s '
                'Please replace them with the correct emails. '
                '(See error messages above.)' %
                (constants.release_constants.INVALID_EMAIL_SUFFIX))
        ordering_is_invalid = not (
            is_order_of_sections_valid(release_summary_lines))
        if ordering_is_invalid:
            common.ask_user_to_confirm(
                'Please fix the ordering in release summary file. '
                '(See error messages above.)')
        if invalid_email_is_present or ordering_is_invalid:
            common.ask_user_to_confirm(
                'Please save the file: %s with all the changes that '
                'you have made.' %
                (constants.release_constants.RELEASE_SUMMARY_FILEPATH))
    return release_summary_lines
Ejemplo n.º 19
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))
Ejemplo n.º 20
0
def prepare_for_next_release():
    """Asks the release co-ordinator:
        1. To create a new chat group for the next release and send a message
        to make the release & QA co-ordinators aware.
        2. Send message to oppia-dev to inform about next release cut.
        3. Send message to oppia-dev as a reminder for job submissions.
    """
    common.open_new_tab_in_browser_if_possible(
        release_constants.RELEASE_ROTA_URL)
    common.ask_user_to_confirm(
        'Create a new chat group for the next release, '
        'and add the release coordinator, QA lead, Ankita '
        'and Nithesh to that group. You can find the release schedule '
        'and coordinators here: %s\n' % release_constants.RELEASE_ROTA_URL)
    common.ask_user_to_confirm(
        'Please send the following message to the newly created group:\n\n'
        'Hi all, This is the group chat for the next release. '
        '[Release co-ordinator\'s name] and [QA Lead\'s name] will be '
        'the release co-ordinator & QA Lead for next release. '
        'Please follow the release process doc: '
        '[Add link to release process doc] to ensure the release '
        'follows the schedule. Thanks!\n')
    common.open_new_tab_in_browser_if_possible(
        release_constants.OPPIA_DEV_GROUP_URL)
    common.ask_user_to_confirm(
        'Send the following message to oppia-dev:\n\n'
        'Hi all, This is an update for the next month\'s release. '
        'The next month release cut is [Add release cut date for next month]. '
        'Make sure you plan your tasks accordingly. Thanks!\n'
        'The subject for the message: Updates for next release\n')
    common.ask_user_to_confirm(
        'Send the following message to oppia-dev:\n\n'
        'Hi all, This is a reminder to fill in the job requests '
        'here: %s if you are planning to run your job in the next release. '
        'Please fill in the requests by [Add a deadline which is at least 7 '
        'days before the next release cut]. Thanks!\n'
        'The subject for the message: Deadline for job requests for '
        'the next release\n' % release_constants.JOBS_FORM_URL)
def main():
    """Collects necessary info and dumps it to disk."""
    branch_name = common.get_current_branch_name()
    if not common.is_current_branch_a_release_branch():
        raise Exception(
            'This script should only be run from the latest release branch.')

    parsed_args = _PARSER.parse_args()
    if parsed_args.github_username is None:
        raise Exception(
            'No GitHub username provided. Please re-run the '
            'script specifying a username using '
            '--github_username=<Your username>')
    github_username = parsed_args.github_username

    personal_access_token = common.get_personal_access_token()

    python_utils.PRINT('Generating release summary...')
    generate_release_info.main(personal_access_token)

    if not os.path.exists(release_constants.RELEASE_SUMMARY_FILEPATH):
        raise Exception(
            'Release summary file %s is missing. Please re-run '
            'this script.' % release_constants.RELEASE_SUMMARY_FILEPATH)

    g = github.Github(personal_access_token)
    repo_fork = g.get_repo('%s/oppia' % github_username)

    current_release_version_number = common.get_current_release_version_number(
        branch_name)
    target_branch = 'update-changelog-for-releasev%s' % (
        current_release_version_number)

    remove_updates_and_delete_branch(repo_fork, target_branch)

    # Opens Credit Form.
    python_utils.PRINT(
        'Note: Make following changes directly to %s and make sure to '
        'save the file after making these changes.' % (
            release_constants.RELEASE_SUMMARY_FILEPATH))

    common.ask_user_to_confirm(
        'Check emails and names for authors and contributors in the release '
        'summary file and verify that the emails are '
        'correct through welcome emails sent from [email protected] '
        '(confirm with Sean in case of doubt).')
    common.open_new_tab_in_browser_if_possible(
        release_constants.CREDITS_FORM_URL)
    common.ask_user_to_confirm(
        'Check the credits form and add any additional contributors '
        'to the contributor list in the release summary file.')
    common.ask_user_to_confirm(
        'Categorize the PR titles in the Uncategorized section of the '
        'changelog in the release summary file, and arrange the changelog '
        'to have user-facing categories on top.')
    common.ask_user_to_confirm(
        'Verify each item is in the correct section in the release summary '
        'file and remove trivial changes like "Fix lint errors" '
        'from the changelog.')
    common.ask_user_to_confirm(
        'Ensure that all items in changelog in the release summary file '
        'start with a verb in simple present tense.')
    common.ask_user_to_confirm(
        'Please save the release summary file with all the changes that '
        'you have made.')

    release_summary_lines = []
    with python_utils.open_file(
        release_constants.RELEASE_SUMMARY_FILEPATH, 'r'
        ) as release_summary_file:
        release_summary_lines = release_summary_file.readlines()

    check_ordering_of_sections(release_summary_lines)

    update_changelog(
        branch_name, release_summary_lines, current_release_version_number)
    update_authors(release_summary_lines)
    update_contributors(release_summary_lines)
    update_developer_names(release_summary_lines)

    message = (
        'Please check the changes and make updates if required in the '
        'following files:\n1. %s\n2. %s\n3. %s\n4. %s\n' % (
            CHANGELOG_FILEPATH, AUTHORS_FILEPATH, CONTRIBUTORS_FILEPATH,
            ABOUT_PAGE_FILEPATH))
    common.ask_user_to_confirm(message)

    create_branch(
        repo_fork, target_branch, github_username,
        current_release_version_number)
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))
Ejemplo n.º 23
0
def main():
    """Collects necessary info and dumps it to disk."""
    branch_name = common.get_current_branch_name()
    if not common.is_current_branch_a_release_branch():
        raise Exception(
            'This script should only be run from the latest release branch.')

    parsed_args = _PARSER.parse_args()
    if parsed_args.github_username is None:
        raise Exception('No GitHub username provided. Please re-run the '
                        'script specifying a username using '
                        '--github_username=<Your username>')
    github_username = parsed_args.github_username

    personal_access_token = common.get_personal_access_token()

    g = github.Github(personal_access_token)
    repo = g.get_organization('oppia').get_repo('oppia')
    repo_fork = g.get_repo('%s/oppia' % github_username)

    common.check_blocking_bug_issue_count(repo)
    common.check_prs_for_current_release_are_released(repo)

    if not os.path.exists(
            constants.release_constants.RELEASE_SUMMARY_FILEPATH):
        raise Exception('Release summary file %s is missing. Please re-run '
                        'this script.' %
                        (constants.release_constants.RELEASE_SUMMARY_FILEPATH))

    current_release_version_number = common.get_current_release_version_number(
        branch_name)
    target_branch = 'update-changelog-for-releasev%s' % (
        current_release_version_number)

    remove_updates_and_delete_branch(repo_fork, target_branch)

    # Opens Credit Form.
    python_utils.PRINT(
        'Note: Make following changes directly to %s and make sure to '
        'save the file after making these changes.' %
        (constants.release_constants.RELEASE_SUMMARY_FILEPATH))

    common.ask_user_to_confirm(
        'Check emails and names for new authors and new contributors in the '
        'file: %s and verify that the emails are '
        'correct through welcome emails sent from [email protected] '
        '(confirm with Sean in case of doubt). Please ensure that you correct '
        'the emails of the form: %s.' %
        (constants.release_constants.RELEASE_SUMMARY_FILEPATH,
         constants.release_constants.INVALID_EMAIL_SUFFIX))
    common.open_new_tab_in_browser_if_possible(
        constants.release_constants.CREDITS_FORM_URL)
    common.ask_user_to_confirm(
        'Check the credits form and add any additional contributors '
        'to the contributor list in the file: %s.' %
        (constants.release_constants.RELEASE_SUMMARY_FILEPATH))
    common.ask_user_to_confirm(
        'Categorize the PR titles in the Uncategorized section of the '
        'changelog in the file: %s, and arrange the changelog '
        'to have user-facing categories on top.' %
        (constants.release_constants.RELEASE_SUMMARY_FILEPATH))
    common.ask_user_to_confirm(
        'Verify each item is in the correct section in the '
        'file: %s and remove trivial changes like "Fix lint errors" '
        'from the changelog.' %
        (constants.release_constants.RELEASE_SUMMARY_FILEPATH))
    common.ask_user_to_confirm(
        'Ensure that all items in changelog in the file: %s '
        'start with a verb in simple present tense.' %
        (constants.release_constants.RELEASE_SUMMARY_FILEPATH))
    common.ask_user_to_confirm(
        'Please save the file: %s with all the changes that '
        'you have made.' %
        (constants.release_constants.RELEASE_SUMMARY_FILEPATH))

    release_summary_lines = get_release_summary_lines()

    update_changelog(branch_name, release_summary_lines,
                     current_release_version_number)
    update_authors(release_summary_lines)
    update_contributors(release_summary_lines)
    update_developer_names(release_summary_lines)
    update_version_in_config_files()

    list_of_numbered_files = []
    for i, filepath in enumerate(LIST_OF_FILEPATHS_TO_MODIFY, start=1):
        list_of_numbered_files.append('%s. %s' % (i, filepath))

    message = ('Please check the changes and make updates if required in the '
               'following files:\n%s\n' % '\n'.join(list_of_numbered_files))
    common.ask_user_to_confirm(message)

    create_branch(repo, repo_fork, target_branch, github_username,
                  current_release_version_number)
Ejemplo n.º 24
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)