Esempio n. 1
0
def main(argv):
    """The release_push script is mainly responsible for copying the artifacts
    (for the AFU and the Checker Framework) from the
    development web site to Maven Central and to
    the live site. It also performs link checking on the live site, pushes
    the release to GitHub repositories, and guides the user to
    perform manual steps such as sending the
    release announcement e-mail."""
    # MANUAL Indicates a manual step
    # AUTO Indicates the step is fully automated.

    set_umask()

    validate_args(argv)
    test_mode = not read_command_line_option(argv, "release")

    m2_settings = expanduser("~") + "/.m2/settings.xml"
    if not os.path.exists(m2_settings):
        raise Exception("File does not exist: " + m2_settings)

    if test_mode:
        msg = (
            "You have chosen test_mode.\n" +
            "This means that this script will execute all build steps that " +
            "do not have side effects.  That is, this is a test run of the script.  All checks and user prompts "
            +
            "will be shown but no steps will be executed that will cause the release to be deployed or partially "
            + "deployed.\n" +
            'If you meant to do an actual release, re-run this script with one argument, "release".'
        )
    else:
        msg = "You have chosen release_mode.  Please follow the prompts to run a full Checker Framework release."

    continue_or_exit(msg + "\n")
    if test_mode:
        print("Continuing in test mode.")
    else:
        print("Continuing in release mode.")

    if not os.path.exists(RELEASE_BUILD_COMPLETED_FLAG_FILE):
        continue_or_exit(
            "It appears that release_build.py has not been run since the last push to "
            +
            "the AFU or Checker Framework repositories.  Please ensure it has "
            + "been run.")

    # The release script checks that the new release version is greater than the previous release version.

    print_step("Push Step 1: Checking release versions")  # SEMIAUTO
    dev_afu_website = os.path.join(DEV_SITE_URL, "annotation-file-utilities")
    live_afu_website = os.path.join(LIVE_SITE_URL, "annotation-file-utilities")

    dev_checker_website = DEV_SITE_URL
    live_checker_website = LIVE_SITE_URL
    current_cf_version = current_distribution_by_website(live_checker_website)
    new_cf_version = CF_VERSION
    check_release_version(current_cf_version, new_cf_version)

    print("Checker Framework and AFU:  current-version=%s    new-version=%s" %
          (current_cf_version, new_cf_version))

    # Runs the link the checker on all websites at:
    # https://checkerframework.org/dev/
    # The output of the link checker is written to files in the /scratch/$USER/cf-release directory
    # whose locations will be output at the command prompt if the link checker reported errors.

    # In rare instances (such as when a link is correct but the link checker is
    # unable to check it), you may add a suppression to the checklink-args.txt file.
    # In extremely rare instances (such as when a website happens to be down at the
    # time you ran the link checker), you may ignore an error.

    print_step("Push Step 2: Check links on development site")  # SEMIAUTO

    if prompt_yes_no("Run link checker on DEV site?", True):
        check_all_links(dev_afu_website, dev_checker_website, "dev", test_mode,
                        new_cf_version)

    # Runs sanity tests on the development release. Later, we will run a smaller set of sanity
    # tests on the live release to ensure no errors occurred when promoting the release.

    print_step("Push Step 3: Run development sanity tests")  # SEMIAUTO
    if prompt_yes_no("Perform this step?", True):

        print_step("3a: Run javac sanity test on development release.")
        if prompt_yes_no("Run javac sanity test on development release?",
                         True):
            javac_sanity_check(dev_checker_website, new_cf_version)

        print_step("3b: Run Maven sanity test on development release.")
        if prompt_yes_no("Run Maven sanity test on development repo?", True):
            maven_sanity_check("maven-dev", "", new_cf_version)

    # The Central repository is a repository of build artifacts for build programs like Maven and Ivy.
    # This step stages (but doesn't release) the Checker Framework's Maven artifacts in the Sonatypes
    # Central Repository.

    # Once staging is complete, there are manual steps to log into Sonatypes Central and "close" the
    # staging repository. Closing allows us to test the artifacts.

    # This step deploys the artifacts to the Central repository and prompts the user to close the
    # artifacts. Later, you will be prompted to release the staged artifacts after we push the
    # release to our GitHub repositories.

    # For more information on deploying to the Central Repository see:
    # https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide

    print_step("Push Step 4: Stage Maven artifacts in Central")  # SEMIAUTO

    print_step("4a: Stage the artifacts at Maven central.")
    if (not test_mode) or prompt_yes_no(
            "Stage Maven artifacts in Maven Central?", not test_mode):
        stage_maven_artifacts_in_maven_central(new_cf_version)

        print_step("4b: Close staged artifacts at Maven central.")
        continue_or_exit(
            "Maven artifacts have been staged!  Please 'close' (but don't release) the artifacts.\n"
            + " * Browse to https://oss.sonatype.org/#stagingRepositories\n" +
            " * Log in using your Sonatype credentials\n" +
            ' * In the search box at upper right, type "checker"\n' +
            " * In the top pane, click on orgcheckerframework-XXXX\n" +
            ' * Click "close" at the top\n' +
            " * For the close message, enter:  Checker Framework release " +
            new_cf_version + "\n" +
            " * Click the Refresh button near the top of the page until the bottom pane has:\n"
            + '   "Activity   Last operation completed successfully".\n' +
            " * Copy the URL of the closed artifacts (in the bottom pane) for use in the next step\n"
            "(You can also see the instructions at: http://central.sonatype.org/pages/releasing-the-deployment.html)\n"
        )

        print_step("4c: Run Maven sanity test on Maven central artifacts.")
        if prompt_yes_no("Run Maven sanity test on Maven central artifacts?",
                         True):
            repo_url = input(
                "Please enter the repo URL of the closed artifacts:\n")

            maven_sanity_check("maven-staging", repo_url, new_cf_version)

    # This step copies the development release directories to the live release directories.
    # It then adds the appropriate permissions to the release. Symlinks need to be updated to point
    # to the live website rather than the development website. A straight copy of the directory
    # will NOT update the symlinks.

    print_step("Push Step 5. Copy dev current release website to live website"
               )  # SEMIAUTO
    if not test_mode:
        if prompt_yes_no("Copy release to the live website?"):
            print("Copying to live site")
            copy_releases_to_live_site(new_cf_version)
            copy_htaccess()
            ensure_group_access_to_releases()
    else:
        print("Test mode: Skipping copy to live site!")

    # This step downloads the checker-framework-X.Y.Z.zip file of the newly live release and ensures we
    # can run the Nullness Checker. If this step fails, you should backout the release.

    print_step(
        "Push Step 6: Run javac sanity tests on the live release.")  # SEMIAUTO
    if not test_mode:
        if prompt_yes_no("Run javac sanity test on live release?", True):
            javac_sanity_check(live_checker_website, new_cf_version)
            SANITY_TEST_CHECKER_FRAMEWORK_DIR = SANITY_DIR + "/test-checker-framework"
            if not os.path.isdir(SANITY_TEST_CHECKER_FRAMEWORK_DIR):
                execute("mkdir -p " + SANITY_TEST_CHECKER_FRAMEWORK_DIR)
            sanity_test_script = os.path.join(SCRIPTS_DIR,
                                              "test-checker-framework.sh")
            execute(
                "sh " + sanity_test_script + " " + new_cf_version,
                True,
                False,
                SANITY_TEST_CHECKER_FRAMEWORK_DIR,
            )
    else:
        print("Test mode: Skipping javac sanity tests on the live release.")

    # Runs the link the checker on all websites at:
    # https://checkerframework.org/
    # The output of the link checker is written to files in the /scratch/$USER/cf-release directory whose locations
    # will be output at the command prompt. Review the link checker output.

    # The set of broken links that is displayed by this check will differ from those in push
    # step 2 because the Checker Framework manual and website uses a mix of absolute and
    # relative links. Therefore, some links from the development site actually point to the
    # live site (the previous release). After step 5, these links point to the current
    # release and may be broken.

    print_step("Push Step 7. Check live site links")  # SEMIAUTO
    if not test_mode:
        if prompt_yes_no("Run link checker on LIVE site?", True):
            check_all_links(live_afu_website, live_checker_website, "live",
                            test_mode)
    else:
        print("Test mode: Skipping checking of live site links.")

    # This step pushes the changes committed to the interm repositories to the GitHub
    # repositories. This is the first irreversible change. After this point, you can no longer
    # backout changes and should do another release in case of critical errors.

    print_step("Push Step 8. Push changes to repositories")  # SEMIAUTO
    # This step could be performed without asking for user input but I think we should err on the side of caution.
    if not test_mode:
        if prompt_yes_no(
                "Push the release to GitHub repositories?  This is irreversible.",
                True):
            push_interm_to_release_repos()
            print("Pushed to repos")
    else:
        print("Test mode: Skipping push to GitHub!")

    # This is a manual step that releases the staged Maven artifacts to the actual Central repository.
    # This is also an irreversible step. Once you have released these artifacts they will be forever
    # available to the Java community through the Central repository. Follow the prompts. The Maven
    # artifacts (such as checker-qual.jar) are still needed, but the Maven plug-in is no longer maintained.

    print_step("Push Step 9. Release staged artifacts in Central repository."
               )  # MANUAL
    if test_mode:
        msg = (
            "Test Mode: You are in test_mode.  Please 'DROP' the artifacts. " +
            "To drop, log into https://oss.sonatype.org using your " +
            "Sonatype credentials and follow the 'DROP' instructions at: " +
            "http://central.sonatype.org/pages/releasing-the-deployment.html")
    else:
        msg = (
            "Please 'release' the artifacts.\n" +
            "First log into https://oss.sonatype.org using your Sonatype credentials. Go to Staging Repositories and "
            + "locate the orgcheckerframework repository and click on it.\n" +
            "If you have a permissions problem, try logging out and back in.\n"
            +
            "Finally, click on the Release button at the top of the page. In the dialog box that pops up, "
            +
            'leave the "Automatically drop" box checked. For the description, write '
            + "Checker Framework release " + new_cf_version + "\n\n")

    print(msg)
    prompt_to_continue()

    if test_mode:
        print("Test complete")
    else:
        # A prompt describes the email you should send to all relevant mailing lists.
        # Please fill out the email and announce the release.

        print_step(
            "Push Step 10. Post the Checker Framework and Annotation File Utilities releases on GitHub."
        )  # MANUAL

        msg = (
            "\n" + "* Download the following files to your local machine." +
            "\n" + "https://checkerframework.org/checker-framework-" +
            new_cf_version + ".zip\n" +
            "https://checkerframework.org/annotation-file-utilities/annotation-tools-"
            + new_cf_version + ".zip\n" + "\n" +
            "To post the Checker Framework release on GitHub:\n" + "\n" +
            "* Go to https://github.com/typetools/checker-framework/releases/new?tag=checker-framework-"
            + new_cf_version + "\n" +
            "* For the release title, enter: Checker Framework " +
            new_cf_version + "\n" +
            "* For the description, insert the latest Checker Framework changelog entry (available at https://checkerframework.org/CHANGELOG.md). Please include the first line with the release version and date.\n"
            +
            '* Find the link below "Attach binaries by dropping them here or selecting them." Click on "selecting them" and upload checker-framework-'
            + new_cf_version + ".zip from your machine.\n" +
            '* Click on the green "Publish release" button.\n' + "\n" +
            "To post the Annotation File Utilities release on GitHub:\n" +
            "\n" +
            "* Go to https://github.com/typetools/annotation-tools/releases/new?tag="
            + new_cf_version + "\n" +
            "* For the release title, enter: Annotation File Utilities " +
            new_cf_version + "\n" +
            "* For the description, insert the latest Annotation File Utilities changelog entry (available at https://checkerframework.org/annotation-file-utilities/changelog.html). Please include the first line with the release version and date. For bullet points, use the * Markdown character.\n"
            +
            '* Find the link below "Attach binaries by dropping them here or selecting them." Click on "selecting them" and upload annotation-tools-'
            + new_cf_version + ".zip from your machine.\n" +
            '* Click on the green "Publish release" button.\n')

        print(msg)

        print_step("Push Step 11. Announce the release.")  # MANUAL
        continue_or_exit(
            "Please announce the release using the email structure below.\n" +
            get_announcement_email(new_cf_version))

        print_step("Push Step 12. Update the Checker Framework Gradle plugin."
                   )  # MANUAL
        continue_or_exit(
            "Please update the Checker Framework Gradle plugin:\n" +
            "https://github.com/kelloggm/checkerframework-gradle-plugin/blob/master/RELEASE.md#updating-the-checker-framework-version\n"
        )

        print_step(
            "Push Step 13. Prep for next Checker Framework release.")  # MANUAL
        continue_or_exit(
            "Change the patch level (last number) of the Checker Framework version\nin build.gradle:  increment it and add -SNAPSHOT\n"
        )

    delete_if_exists(RELEASE_BUILD_COMPLETED_FLAG_FILE)

    print("Done with release_push.py")
Esempio n. 2
0
def build_checker_framework_release(version, old_cf_version, afu_release_date,
                                    checker_framework_interm_dir):
    """Build the release files for the Checker Framework project, including the
    manual and the zip file, and run tests on the build."""
    checker_dir = os.path.join(CHECKER_FRAMEWORK, "checker")

    afu_build_properties = os.path.join(ANNO_FILE_UTILITIES,
                                        "build.properties")

    # build stubparser
    execute("mvn package -Dmaven.test.skip=true", True, False, STUBPARSER)

    # build annotation-tools
    execute("./gradlew assemble -Prelease=true", True, False,
            ANNO_FILE_UTILITIES)

    # update versions
    ant_props = (
        '-Dchecker=%s -Drelease.ver=%s -Dafu.version=%s -Dafu.properties=%s -Dafu.release.date="%s"'
        % (checker_dir, version, version, afu_build_properties,
           afu_release_date))
    # IMPORTANT: The release.xml in the directory where the Checker Framework is being built is used. Not the release.xml in the directory you ran release_build.py from.
    ant_cmd = "ant %s -f release.xml %s update-checker-framework-versions " % (
        ant_debug,
        ant_props,
    )
    execute(ant_cmd, True, False, CHECKER_FRAMEWORK_RELEASE)

    # Check that updating versions didn't overlook anything.
    print("Here are occurrences of the old version number, " + old_cf_version)
    grep_cmd = "grep -n -r --exclude-dir=build --exclude-dir=.git -F %s" % old_cf_version
    execute(grep_cmd, False, False, CHECKER_FRAMEWORK)
    continue_or_exit(
        'If any occurrence is not acceptable, then stop the release, update target "update-checker-framework-versions" in file release.xml, and start over.'
    )

    # build the checker framework binaries and documents.  Tests are run by release_push.py
    gradle_cmd = "./gradlew releaseBuild"
    execute(gradle_cmd, True, False, CHECKER_FRAMEWORK)

    # make the Checker Framework Manual
    checker_manual_dir = os.path.join(CHECKER_FRAMEWORK, "docs", "manual")
    execute("make manual.pdf manual.html", True, False, checker_manual_dir)

    # make the dataflow manual
    dataflow_manual_dir = os.path.join(CHECKER_FRAMEWORK, "dataflow", "manual")
    execute("make", True, False, dataflow_manual_dir)

    # make the checker framework tutorial
    checker_tutorial_dir = os.path.join(CHECKER_FRAMEWORK, "docs", "tutorial")
    execute("make", True, False, checker_tutorial_dir)

    cfZipName = "checker-framework-%s.zip" % version

    # Create checker-framework-X.Y.Z.zip and put it in checker_framework_interm_dir
    ant_props = "-Dchecker=%s -Ddest.dir=%s -Dfile.name=%s -Dversion=%s" % (
        checker_dir,
        checker_framework_interm_dir,
        cfZipName,
        version,
    )
    # IMPORTANT: The release.xml in the directory where the Checker Framework is being built is used. Not the release.xml in the directory you ran release_build.py from.
    ant_cmd = "ant %s -f release.xml %s zip-checker-framework " % (ant_debug,
                                                                   ant_props)
    execute(ant_cmd, True, False, CHECKER_FRAMEWORK_RELEASE)

    ant_props = "-Dchecker=%s -Ddest.dir=%s -Dfile.name=%s -Dversion=%s" % (
        checker_dir,
        checker_framework_interm_dir,
        "mvn-examples.zip",
        version,
    )
    # IMPORTANT: The release.xml in the directory where the Checker Framework is being built is used. Not the release.xml in the directory you ran release_build.py from.
    ant_cmd = "ant %s -f release.xml %s zip-maven-examples " % (ant_debug,
                                                                ant_props)
    execute(ant_cmd, True, False, CHECKER_FRAMEWORK_RELEASE)

    # copy the remaining checker-framework website files to checker_framework_interm_dir
    ant_props = "-Dchecker=%s -Ddest.dir=%s -Dmanual.name=%s -Ddataflow.manual.name=%s -Dchecker.webpage=%s" % (
        checker_dir,
        checker_framework_interm_dir,
        "checker-framework-manual",
        "checker-framework-dataflow-manual",
        "checker-framework-webpage.html",
    )

    # IMPORTANT: The release.xml in the directory where the Checker Framework is being built is used. Not the release.xml in the directory you ran release_build.py from.
    ant_cmd = "ant %s -f release.xml %s checker-framework-website-docs " % (
        ant_debug,
        ant_props,
    )
    execute(ant_cmd, True, False, CHECKER_FRAMEWORK_RELEASE)

    # clean no longer necessary files left over from building the checker framework tutorial
    checker_tutorial_dir = os.path.join(CHECKER_FRAMEWORK, "docs", "tutorial")
    execute("make clean", True, False, checker_tutorial_dir)

    build_and_locally_deploy_maven(version)

    update_project_dev_website("checker-framework", version)

    return