Example #1
0
def build_pex(fetch: bool) -> None:
    if fetch:
        extra_pex_args = [
            f"--platform={plat}-{abi}"
            for plat in ("linux_x86_64", "macosx_10.15_x86_64")
            for abi in ("cp-37-m", "cp-38-cp38", "cp-39-cp39")
        ]
        pex_name = f"pants.{CONSTANTS.pants_unstable_version}.pex"
        banner(f"Building {pex_name} by fetching wheels.")
    else:
        extra_pex_args = [f"--python={sys.executable}"]
        plat = os.uname()[0].lower()
        py = f"cp{''.join(map(str, sys.version_info[:2]))}"
        pex_name = f"pants.{CONSTANTS.pants_unstable_version}.{plat}-{py}.pex"
        banner(f"Building {pex_name} by building wheels.")

    if CONSTANTS.deploy_dir.exists():
        shutil.rmtree(CONSTANTS.deploy_dir)
    CONSTANTS.deploy_dir.mkdir(parents=True)

    if fetch:
        fetch_prebuilt_wheels(CONSTANTS.deploy_dir)
        check_prebuilt_wheels_present(CONSTANTS.deploy_dir)
    else:
        build_pants_wheels()
        build_3rdparty_wheels()

    dest = Path("dist") / pex_name
    with download_pex_bin() as pex_bin:
        subprocess.run(
            [
                sys.executable,
                str(pex_bin),
                "-o",
                str(dest),
                "--no-build",
                "--no-pypi",
                "--disable-cache",
                "-f",
                str(CONSTANTS.deploy_pants_wheel_dir / CONSTANTS.pants_unstable_version),
                "-f",
                str(CONSTANTS.deploy_3rdparty_wheel_dir / CONSTANTS.pants_unstable_version),
                "--no-strip-pex-env",
                "--console-script=pants",
                "--unzip",
                *extra_pex_args,
                f"pantsbuild.pants=={CONSTANTS.pants_unstable_version}",
            ],
            check=True,
        )

    if os.environ.get("PANTS_PEX_RELEASE", "") == "STABLE":
        stable_dest = CONSTANTS.deploy_dir / "pex" / f"pants.{CONSTANTS.pants_stable_version}.pex"
        stable_dest.parent.mkdir(parents=True, exist_ok=True)
        dest.rename(stable_dest)
        dest = stable_dest
    green(f"Built {dest}")

    subprocess.run([sys.executable, str(dest), "--version"], check=True)
    green(f"Validated {dest}")
Example #2
0
def check_prebuilt_wheels(check_dir: str) -> None:
    banner(f"Checking prebuilt wheels for {CONSTANTS.pants_unstable_version}")
    missing_packages = []
    for package in sorted(all_packages()):
        local_files = package.find_locally(
            version=CONSTANTS.pants_unstable_version, search_dir=check_dir
        )
        if not local_files:
            missing_packages.append(package.name)
            continue

        # If the package is cross platform, confirm that we have whls for two platforms.
        is_cross_platform = not all(
            local_file.name.endswith("-none-any.whl") for local_file in local_files
        )
        if is_cross_platform and len(local_files) != 2:
            formatted_local_files = ", ".join(f.name for f in local_files)
            missing_packages.append(
                f"{package.name} (expected a macOS wheel and a linux wheel, but found "
                f"{formatted_local_files})"
            )

    if missing_packages:
        formatted_missing = "\n  ".join(missing_packages)
        die(f"Failed to find prebuilt wheels:\n  {formatted_missing}")
    green(f"All {len(all_packages())} pantsbuild.pants packages were fetched and are valid.")
Example #3
0
def run_python_tests_v2() -> None:
    known_v2_failures_file = "build-support/unit_test_v2_blacklist.txt"
    with open(known_v2_failures_file, "r") as f:
        blacklisted_targets = {line.strip() for line in f.readlines()}
    with travis_section("PythonTestsV1",
                        "Running Python unit tests with V2 test runner"):
        check_pants_pex_exists()
        try:
            all_targets = subprocess.run([
                "./pants.pex",
                "--tag=-integration",
                "--filter-type=python_tests",
                "filter",
                "src/python::",
                "tests/python::",
            ],
                                         stdout=subprocess.PIPE,
                                         encoding="utf-8",
                                         check=True).stdout.strip().split("\n")
            v2_targets = set(all_targets) - blacklisted_targets
            subprocess.run(["./pants.pex", "--no-v1", "--v2", "test.pytest"] +
                           sorted(v2_targets) + PYTEST_PASSTHRU_ARGS,
                           check=True)
        except subprocess.CalledProcessError:
            die("Python unit tests failure (V2 test runner)")
        else:
            green("V2 unit tests passed.")
Example #4
0
def run_python_tests_v1() -> None:
    check_pants_pex_exists()

    blacklisted_v2_targets = get_blacklisted_targets(
        "unit_test_v2_blacklist.txt")
    blacklisted_chroot_targets = get_blacklisted_targets(
        "unit_test_chroot_blacklist.txt")
    chrooted_targets = blacklisted_v2_targets - blacklisted_chroot_targets

    with travis_section("PythonTestsV1",
                        "Running Python unit tests with V1 test runner"):

        try:
            subprocess.run(
                ["./pants.pex", "--test-pytest-chroot", "test.pytest"] +
                sorted(chrooted_targets) + PYTEST_PASSTHRU_ARGS,
                check=True)
            subprocess.run(["./pants.pex", "test.pytest"] +
                           sorted(blacklisted_chroot_targets) +
                           PYTEST_PASSTHRU_ARGS,
                           check=True)
        except subprocess.CalledProcessError:
            die("Python unit test failure (V1 test runner")
        else:
            green("V1 unit tests passed.")
Example #5
0
def build_fs_util() -> None:
    # See https://www.pantsbuild.org/docs/contributions-rust for a description of fs_util. We include
    # it in our releases because it can be a useful standalone tool.
    with travis_section("fs_util", "Building fs_util"):
        subprocess.run(
            [
                "build-support/bin/native/cargo",
                "build",
                "--release",
                "--manifest-path=src/rust/engine/Cargo.toml",
                "-p",
                "fs_util",
            ],
            check=True,
            env={
                **os.environ, "RUST_BACKTRACE": "1"
            },
        )
        current_os = (subprocess.run(["build-support/bin/get_os.sh"],
                                     stdout=subprocess.PIPE,
                                     check=True).stdout.decode().strip())
        dest_dir = (Path(CONSTANTS.deploy_dir) / "bin" / "fs_util" /
                    current_os / CONSTANTS.pants_unstable_version)
        dest_dir.mkdir(parents=True, exist_ok=True)
        shutil.copy("src/rust/engine/target/release/fs_util", dest_dir)
        green(f"Built fs_util at {dest_dir / 'fs_util'}.")
Example #6
0
def build_pants_wheels() -> None:
    banner(f"Building Pants wheels with Python {CONSTANTS.python_version}")
    version = CONSTANTS.pants_unstable_version

    dest = CONSTANTS.deploy_pants_wheel_dir / version
    dest.mkdir(parents=True, exist_ok=True)

    args = (
        "./pants",
        # TODO(#9924).
        "--no-dynamic-ui",
        # TODO(#7654): It's not safe to use Pantsd because we're already using Pants to run
        #  this script.
        "--concurrent",
        "package",
        *(package.target for package in PACKAGES),
    )

    with set_pants_version(CONSTANTS.pants_unstable_version):
        try:
            subprocess.run(args, check=True)
        except subprocess.CalledProcessError as e:
            failed_packages = ",".join(package.name for package in PACKAGES)
            failed_targets = " ".join(package.target for package in PACKAGES)
            die(
                softwrap(f"""
                    Failed to build packages {failed_packages} for {version} with targets
                    {failed_targets}.

                    {e!r}
                    """))

        # TODO(#10718): Allow for sdist releases. We can build an sdist for
        #  `pantsbuild.pants.testutil`, but need to wire it up to the rest of our release process.
        for package in PACKAGES:
            found_wheels = sorted(
                Path("dist").glob(f"{package}-{version}-*.whl"))
            # NB: For any platform-specific wheels, like pantsbuild.pants, we assume that the
            # top-level `dist` will only have wheels built for the current platform. This
            # should be safe because it is not possible to build native wheels for another
            # platform.
            if not is_cross_platform(found_wheels) and len(found_wheels) > 1:
                die(
                    softwrap(f"""
                        Found multiple wheels for {package} in the `dist/` folder, but was
                        expecting only one wheel: {sorted(wheel.name for wheel in found_wheels)}.
                        """))
            for wheel in found_wheels:
                if not (dest / wheel.name).exists():
                    # We use `copy2` to preserve metadata.
                    shutil.copy2(wheel, dest)

    green(f"Wrote Pants wheels to {dest}.")

    banner(f"Validating Pants wheels for {CONSTANTS.python_version}.")
    create_twine_venv()
    subprocess.run(
        [CONSTANTS.twine_venv_dir / "bin/twine", "check", dest / "*.whl"],
        check=True)
    green(f"Validated Pants wheels for {CONSTANTS.python_version}.")
Example #7
0
def run_python_tests_v1() -> None:
    known_v2_failures_file = "build-support/unit_test_v2_blacklist.txt"
    with travis_section("PythonTestsV1",
                        "Running Python unit tests with V1 test runner"):
        check_pants_pex_exists()
        try:
            subprocess.run([
                "./pants.pex",
                f"--target-spec-file={known_v2_failures_file}",
                "test.pytest",
                "--chroot",
            ] + PYTEST_PASSTHRU_ARGS,
                           check=True)
        except subprocess.CalledProcessError:
            die("Python unit test failure (V1 test runner")
        else:
            green("V1 unit tests passed.")

        try:
            subprocess.run([
                "./pants.pex",
                "--tag=-integration",
                "--exclude-target-regexp=./*testprojects/.*",
                "test.pytest",
                "contrib::",
            ] + PYTEST_PASSTHRU_ARGS,
                           check=True)
        except subprocess.CalledProcessError:
            die("Contrib Python test failure")
        else:
            green("Contrib unit tests passed.")
Example #8
0
def install_and_test_packages(version: str, *, extra_pip_args: list[str] | None = None) -> None:
    with create_tmp_venv() as venv_tmpdir:
        for pkg in PACKAGES:
            pip_req = f"{pkg.name}=={version}"
            banner(f"Installing and testing {pip_req}")
            pkg.validate(version, venv_tmpdir, extra_pip_args or [])
            green(f"Tests succeeded for {pip_req}")
Example #9
0
def build_fs_util() -> None:
    # See https://www.pantsbuild.org/docs/contributions-rust for a description of fs_util. We
    # include it in our releases because it can be a useful standalone tool.
    with travis_section("fs_util", "Building fs_util"):
        command = ["./cargo", "build", "-p", "fs_util"]
        release_mode = os.environ.get("MODE", "") != "debug"
        if release_mode:
            command.append("--release")
        subprocess.run(command, check=True, env={**os.environ, "RUST_BACKTRACE": "1"})
        current_os = (
            subprocess.run(["build-support/bin/get_os.sh"], stdout=subprocess.PIPE, check=True)
            .stdout.decode()
            .strip()
        )
        dest_dir = (
            Path(CONSTANTS.deploy_dir)
            / "bin"
            / "fs_util"
            / current_os
            / CONSTANTS.pants_unstable_version
        )
        dest_dir.mkdir(parents=True, exist_ok=True)
        shutil.copy(
            f"src/rust/engine/target/{'release' if release_mode else 'debug'}/fs_util",
            dest_dir,
        )
        green(f"Built fs_util at {dest_dir / 'fs_util'}.")
Example #10
0
def run_unit_tests(*, remote_execution_enabled: bool) -> None:
    check_pants_pex_exists()

    all_targets = get_all_python_tests(tag="-integration")
    blacklisted_chroot_targets = get_blacklisted_targets(
        "unit_test_chroot_blacklist.txt")
    blacklisted_v2_targets = get_blacklisted_targets(
        "unit_test_v2_blacklist.txt")
    blacklisted_remote_targets = get_blacklisted_targets(
        "unit_test_remote_blacklist.txt")

    v1_no_chroot_targets = blacklisted_chroot_targets
    v1_chroot_targets = blacklisted_v2_targets
    v2_local_targets = blacklisted_remote_targets
    v2_remote_targets = all_targets - v2_local_targets - v1_chroot_targets - v1_no_chroot_targets

    basic_command = ["./pants.pex", "test.pytest"]
    v2_command = ["./pants.pex", "--no-v1", "--v2", "test.pytest"]
    v1_no_chroot_command = basic_command + sorted(
        v1_no_chroot_targets) + PYTEST_PASSTHRU_ARGS
    v1_chroot_command = basic_command + [
        "--test-pytest-chroot"
    ] + sorted(v1_chroot_targets) + PYTEST_PASSTHRU_ARGS
    v2_local_command = v2_command + sorted(v2_local_targets)

    if not remote_execution_enabled:
        v2_local_targets = v2_local_targets | v2_remote_targets
        v2_local_command = v2_command + sorted(v2_local_targets)
    else:
        with travis_section(
                "UnitTestsRemote", "Running unit tests via remote execution"
        ), get_remote_execution_oauth_token_path() as oauth_token_path:
            v2_remote_command = v2_command[:-1] + [
                "--pants-config-files=pants.remote.ini",
                # We turn off speculation to reduce the risk of flakiness, where a test passes locally but
                # fails remoting and we have a race condition for which environment executes first.
                "--process-execution-speculation-strategy=none",
                f"--remote-oauth-bearer-token-path={oauth_token_path}",
                "test.pytest",
            ] + sorted(v2_remote_targets)
            try:
                subprocess.run(v2_remote_command, check=True)
            except subprocess.CalledProcessError:
                die("Unit test failure (remote execution)")
            else:
                green("Unit tests passed (remote execution)")

    with travis_section("UnitTestsLocal",
                        "Running unit tests via local execution"):
        try:
            subprocess.run(v2_local_command, check=True)
            subprocess.run(v1_chroot_command, check=True)
            subprocess.run(v1_no_chroot_command, check=True)
        except subprocess.CalledProcessError:
            die("Unit test failure (local execution)")
        else:
            green("Unit tests passed (local execution)")
Example #11
0
def run_shellcheck() -> None:
  targets = glob("./**/*.sh", recursive=True) + ["./pants"]
  command = ["shellcheck", "--shell=bash"] + targets
  try:
    subprocess.run(command, check=True)
  except subprocess.CalledProcessError:
    die("Please fix the above errors and run again.")
  else:
    green("./pants passed the shellcheck!")
Example #12
0
def build_pants_wheels() -> None:
    banner("Building Pants wheels")
    version = CONSTANTS.pants_unstable_version

    destination = CONSTANTS.deploy_pants_wheel_dir / version
    destination.mkdir(parents=True, exist_ok=True)

    def build(packages: Iterable[Package],
              bdist_wheel_flags: Iterable[str]) -> None:
        args = (
            "./pants",
            # TODO(#9924).
            "--no-dynamic-ui",
            # TODO(#7654): It's not safe to use Pantsd because we're already using Pants to run
            #  this script.
            "--concurrent",
            "setup-py",
            *(package.target for package in packages),
            "--",
            "bdist_wheel",
            *bdist_wheel_flags,
        )
        try:
            subprocess.run(args, check=True)
            for package in packages:
                found_wheels = sorted(
                    Path("dist").glob(f"{package}-{version}-*.whl"))
                # NB: For any platform-specific wheels, like pantsbuild.pants, we assume that the
                # top-level `dist` will only have wheels built for the current platform. This
                # should be safe because it is not possible to build native wheels for another
                # platform.
                if not is_cross_platform(
                        found_wheels) and len(found_wheels) > 1:
                    raise ValueError(
                        f"Found multiple wheels for {package} in the `dist/` folder, but was "
                        f"expecting only one wheel: {sorted(wheel.name for wheel in found_wheels)}."
                    )
                for wheel in found_wheels:
                    if not (destination / wheel.name).exists():
                        # We use `copy2` to preserve metadata.
                        shutil.copy2(wheel, destination)
        except subprocess.CalledProcessError as e:
            failed_packages = ",".join(package.name for package in packages)
            failed_targets = " ".join(package.target for package in packages)
            die(
                f"Failed to build packages {failed_packages} for {version} with targets "
                f"{failed_targets}.\n\n{e!r}", )

    packages_by_flags = defaultdict(list)
    for package in PACKAGES:
        packages_by_flags[package.bdist_wheel_flags].append(package)

    with set_pants_version(CONSTANTS.pants_unstable_version):
        for flags, packages in packages_by_flags.items():
            build(packages, flags)
    green(f"Wrote Pants wheels to {destination}.")
Example #13
0
def main() -> None:
    banner("CI BEGINS")

    args = create_parser().parse_args()
    setup_environment(python_version=args.python_version)

    with maybe_get_remote_execution_oauth_token_path(
            remote_execution_enabled=args.remote_execution_enabled
    ) as remote_execution_oauth_token_path:

        if args.bootstrap:
            bootstrap(
                clean=args.bootstrap_clean,
                try_to_skip_rust_compilation=args.
                bootstrap_try_to_skip_rust_compilation,
                python_version=args.python_version,
            )
        set_run_from_pex()

        if args.githooks:
            run_githooks()
        if args.sanity_checks:
            run_sanity_checks()
        if args.lint:
            run_lint(oauth_token_path=remote_execution_oauth_token_path)
        if args.doc_gen:
            run_doc_gen_tests()
        if args.clippy:
            run_clippy()
        if args.cargo_audit:
            run_cargo_audit()
        if args.unit_tests:
            run_unit_tests(oauth_token_path=remote_execution_oauth_token_path)
        if args.rust_tests:
            run_rust_tests()
        if args.jvm_tests:
            run_jvm_tests()
        if args.integration_tests_v1:
            run_integration_tests_v1(shard=args.integration_shard)
        if args.integration_tests_v2:
            run_integration_tests_v2(
                oauth_token_path=remote_execution_oauth_token_path)
        if args.plugin_tests:
            run_plugin_tests(
                oauth_token_path=remote_execution_oauth_token_path)
        if args.platform_specific_tests:
            run_platform_specific_tests()

    banner("CI ENDS")
    print()
    green("SUCCESS")
Example #14
0
def build_3rdparty_wheels() -> None:
    banner(f"Building 3rdparty wheels with Python {CONSTANTS.python_version}")
    dest = CONSTANTS.deploy_3rdparty_wheel_dir / CONSTANTS.pants_unstable_version
    pkg_tgts = [pkg.target for pkg in PACKAGES]
    with create_tmp_venv() as bin_dir:
        deps = (subprocess.run(
            [
                "./pants",
                "--concurrent",
                "dependencies",
                "--transitive",
                *pkg_tgts,
            ],
            stdout=subprocess.PIPE,
            check=True,
        ).stdout.decode().strip().splitlines())
        python_requirements = (subprocess.run(
            [
                "./pants",
                "--concurrent",
                "filter",
                "--target-type=python_requirement",
                *deps,
            ],
            stdout=subprocess.PIPE,
            check=True,
        ).stdout.decode().strip().splitlines())
        if not python_requirements:
            die(
                softwrap(f"""
                    No 3rd-party dependencies detected for {pkg_tgts}. Is `./pants dependencies`
                    broken?
                    """))
        reqs = itertools.chain.from_iterable(obj["requirements"]
                                             for obj in json.loads(
                                                 subprocess.run(
                                                     [
                                                         "./pants",
                                                         "--concurrent",
                                                         "peek",
                                                         *python_requirements,
                                                     ],
                                                     stdout=subprocess.PIPE,
                                                     check=True,
                                                 ).stdout))
        subprocess.run(
            [bin_dir / "pip", "wheel", f"--wheel-dir={dest}", *reqs],
            check=True,
        )
        green(f"Wrote 3rdparty wheels to {dest}")
Example #15
0
def run_shellcheck() -> None:
  targets = set(glob("./**/*.sh", recursive=True)) | {
    "./pants",
    "./pants2",
    "./build-support/pants_venv",
    "./build-support/virtualenv",
    "./build-support/githooks/pre-commit",
    "./build-support/githooks/prepare-commit-msg",
  }
  targets -= set(glob("./build-support/bin/native/src/**/*.sh", recursive=True))
  targets -= set(glob("./build-support/virtualenv.dist/**/*.sh", recursive=True))
  command = ["shellcheck", "--shell=bash", "--external-sources"] + sorted(targets)
  try:
    subprocess.run(command, check=True)
  except subprocess.CalledProcessError:
    die("Please fix the above errors and run again.")
  else:
    green("./pants passed the shellcheck!")
Example #16
0
def main() -> None:
  if not Path("pants.pex").is_file:
    die("pants.pex not found! Ensure you are in the repository root, then run " \
        "'./build-support/bin/ci.sh -b' to bootstrap pants.pex with Python 3 or " \
        "'./build-support/bin/ci.sh -2b' to bootstrap pants.pex with Python 2.")
  expected_abis = frozenset(create_parser().parse_args().abis)
  with zipfile.ZipFile("pants.pex", "r") as pex:
    with pex.open("PEX-INFO", "r") as pex_info:
      pex_info_content = pex_info.readline().decode()
  parsed_abis = frozenset(
    parse_abi_from_filename(filename)
    for filename in json.loads(pex_info_content)["distributions"].keys()
    if parse_abi_from_filename(filename) != "none"
  )
  if not parsed_abis.issubset(expected_abis):
    die("pants.pex was built with the incorrect ABI. Expected wheels with: {}, found: {}."
        .format(' or '.join(sorted(expected_abis)), ', '.join(sorted(parsed_abis))))
  green("Success. The pants.pex was built with wheels carrying the expected ABIs: {}."
          .format(', '.join(sorted(parsed_abis))))
Example #17
0
def check_pants_wheels_present(check_dir: str | Path) -> None:
    banner(f"Checking prebuilt wheels for {CONSTANTS.pants_unstable_version}")
    missing_packages = []
    for package in PACKAGES:
        local_files = package.find_locally(
            version=CONSTANTS.pants_unstable_version, search_dir=check_dir)
        if not local_files:
            missing_packages.append(package.name)
            continue
        if is_cross_platform(local_files) and len(local_files) != 6:
            formatted_local_files = ", ".join(f.name for f in local_files)
            missing_packages.append(
                f"{package.name} (expected 6 wheels, {{macosx, linux}} x {{cp37m, cp38, cp39}}, "
                f"but found {formatted_local_files})")
    if missing_packages:
        formatted_missing = "\n  ".join(missing_packages)
        die(f"Failed to find prebuilt wheels:\n  {formatted_missing}")
    green(
        f"All {len(PACKAGES)} pantsbuild.pants packages were fetched and are valid."
    )
Example #18
0
def main() -> None:
  if not Path("pants.pex").is_file:
    die("pants.pex not found! Ensure you are in the repository root, then run "
        "`./build-support/bin/ci.py --bootstrap` to bootstrap pants.pex with Python 3.6 or "
        "`./build-support/bin/ci.py --bootstrap --python-version 2.7` to bootstrap pants.pex with "
        "Python 2.7.")
  expected_abis = frozenset(create_parser().parse_args().abis)
  with zipfile.ZipFile("pants.pex", "r") as pex:
    with pex.open("PEX-INFO", "r") as pex_info:
      pex_info_content = pex_info.readline().decode()
  parsed_abis = frozenset(
    parse_abi_from_filename(filename)
    for filename in json.loads(pex_info_content)["distributions"].keys()
    if parse_abi_from_filename(filename) != "none"
  )
  if not parsed_abis.issubset(expected_abis):
    die("pants.pex was built with the incorrect ABI. Expected wheels with: {}, found: {}."
        .format(' or '.join(sorted(expected_abis)), ', '.join(sorted(parsed_abis))))
  green("Success. The pants.pex was built with wheels carrying the expected ABIs: {}."
          .format(', '.join(sorted(parsed_abis))))
Example #19
0
def main() -> None:
    banner("CI BEGINS")

    args = create_parser().parse_args()
    setup_environment(python_version=args.python_version)

    if args.bootstrap:
        bootstrap(clean=args.bootstrap_clean,
                  python_version=args.python_version)
    set_run_from_pex()

    if args.githooks:
        run_githooks()
    if args.sanity_checks:
        run_sanity_checks()
    if args.lint:
        run_lint()
    if args.doc_gen:
        run_doc_gen_tests()
    if args.clippy:
        run_clippy()
    if args.cargo_audit:
        run_cargo_audit()
    if args.python_tests_v1:
        run_python_tests_v1()
    if args.python_tests_v2:
        run_python_tests_v2()
    if args.rust_tests:
        run_rust_tests()
    if args.jvm_tests:
        run_jvm_tests()
    if args.integration_tests:
        run_integration_tests(shard=args.integration_shard)
    if args.plugin_tests:
        run_plugin_tests()
    if args.platform_specific_tests:
        run_platform_specific_tests()

    banner("CI ENDS")
    print()
    green("SUCCESS")
def run_shellcheck() -> None:
    targets = set(glob("./**/*.sh", recursive=True)) | {
        "./pants",
        "./pants2",
        "./build-support/pants_venv",
        "./build-support/virtualenv",
        "./build-support/githooks/pre-commit",
        "./build-support/githooks/prepare-commit-msg",
    }
    targets -= set(
        glob("./build-support/bin/native/src/**/*.sh", recursive=True))
    targets -= set(
        glob("./build-support/virtualenv.dist/**/*.sh", recursive=True))
    command = ["shellcheck", "--shell=bash", "--external-sources"
               ] + sorted(targets)
    try:
        subprocess.run(command, check=True)
    except subprocess.CalledProcessError:
        die("Please fix the above errors and run again.")
    else:
        green("./pants passed the shellcheck!")
Example #21
0
File: ci.py Project: valeraz/pants
def main() -> None:
    banner("CI BEGINS")

    args = create_parser().parse_args()
    setup_environment(python_version=args.python_version)

    if args.bootstrap:
        bootstrap(
            clean=args.bootstrap_clean,
            try_to_skip_rust_compilation=args.
            bootstrap_try_to_skip_rust_compilation,
            python_version=args.python_version,
        )
    set_run_from_pex()

    if args.githooks:
        run_githooks()
    if args.smoke_tests:
        run_smoke_tests()
    if args.lint:
        run_lint(remote_cache_enabled=args.remote_cache_enabled)
    if args.clippy:
        run_clippy()
    if args.cargo_audit:
        run_cargo_audit()
    if args.unit_tests or args.integration_tests:
        run_python_tests(
            include_unit=args.unit_tests,
            include_integration=args.integration_tests,
            remote_cache_enabled=args.remote_cache_enabled,
        )
    if args.rust_tests:
        run_rust_tests()
    if args.platform_specific_tests:
        run_platform_specific_tests()

    banner("CI ENDS")
    print()
    green("SUCCESS")
Example #22
0
 def run_v2_tests(*,
                  targets: Set[str],
                  execution_strategy: str,
                  oauth_token_path: Optional[str] = None) -> None:
     try:
         command = (["./pants.pex", "--no-v1", "--v2", "test.pytest"] +
                    sorted(targets) + PYTEST_PASSTHRU_ARGS)
         if oauth_token_path is not None:
             command[3:3] = [
                 "--pants-config-files=pants.remote.ini",
                 # We turn off speculation to reduce the risk of flakiness, where a test passes locally but
                 # fails remoting and we have a race condition for which environment executes first.
                 "--process-execution-speculation-strategy=none",
                 f"--remote-oauth-bearer-token-path={oauth_token_path}"
             ]
         subprocess.run(command, check=True)
     except subprocess.CalledProcessError:
         die(f"V2 unit tests failure ({execution_strategy} build execution)."
             )
     else:
         green(
             f"V2 unit tests passed ({execution_strategy} build execution)."
         )
Example #23
0
def build_pex(fetch: bool) -> None:
    if fetch:
        extra_pex_args = [
            f"--platform={plat}-{abi}"
            for plat in ("linux_x86_64", "macosx_10.15_x86_64")
            for abi in ("cp-37-m", "cp-38-cp38", "cp-39-cp39")
        ]
        pex_name = f"pants.{CONSTANTS.pants_unstable_version}.pex"
        banner(f"Building {pex_name} by fetching wheels.")
    else:
        extra_pex_args = [f"--python={sys.executable}"]
        plat = os.uname()[0].lower()
        py = f"cp{''.join(map(str, sys.version_info[:2]))}"
        pex_name = f"pants.{CONSTANTS.pants_unstable_version}.{plat}-{py}.pex"
        banner(f"Building {pex_name} by building wheels.")

    if CONSTANTS.deploy_dir.exists():
        shutil.rmtree(CONSTANTS.deploy_dir)
    CONSTANTS.deploy_dir.mkdir(parents=True)

    if fetch:
        fetch_prebuilt_wheels(CONSTANTS.deploy_dir, include_3rdparty=True)
        check_pants_wheels_present(CONSTANTS.deploy_dir)
    else:
        build_pants_wheels()
        build_3rdparty_wheels()

    # We need to both run Pex and the Pants PEX we build with it with clean environments since we
    # ourselves may be running via `./pants run ...` which injects confounding environment variables
    # like PEX_EXTRA_SYS_PATH, PEX_PATH and PEX_ROOT that need not or should not apply to these
    # sub-processes.
    env = {k: v for k, v in os.environ.items() if not k.startswith("PEX_")}

    dest = Path("dist") / pex_name
    with download_pex_bin() as pex_bin:
        subprocess.run(
            [
                sys.executable,
                str(pex_bin),
                "-o",
                str(dest),
                "--no-build",
                "--no-pypi",
                "--disable-cache",
                "-f",
                str(CONSTANTS.deploy_pants_wheel_dir / CONSTANTS.pants_unstable_version),
                "-f",
                str(CONSTANTS.deploy_3rdparty_wheel_dir / CONSTANTS.pants_unstable_version),
                "--no-strip-pex-env",
                "--console-script=pants",
                *extra_pex_args,
                f"pantsbuild.pants=={CONSTANTS.pants_unstable_version}",
            ],
            env=env,
            check=True,
        )

    if os.environ.get("PANTS_PEX_RELEASE", "") == "STABLE":
        stable_dest = CONSTANTS.deploy_dir / "pex" / f"pants.{CONSTANTS.pants_stable_version}.pex"
        stable_dest.parent.mkdir(parents=True, exist_ok=True)
        dest.rename(stable_dest)
        dest = stable_dest
    green(f"Built {dest}")

    subprocess.run([sys.executable, str(dest), "--no-pantsd", "--version"], env=env, check=True)
    green(f"Validated {dest}")
Example #24
0
def build_pex(fetch: bool) -> None:
    stable = os.environ.get("PANTS_PEX_RELEASE", "") == "STABLE"
    if fetch:
        # TODO: Support macOS on ARM64.
        extra_pex_args = [
            "--python-shebang",
            "/usr/bin/env python",
            "--interpreter-constraint",
            "CPython>=3.7,<3.10",
            *(f"--platform={plat}-{abi}"
              for plat in ("linux_x86_64", "macosx_10.15_x86_64")
              for abi in ("cp-37-m", "cp-38-cp38", "cp-39-cp39")),
        ]
        pex_name = f"pants.{CONSTANTS.pants_unstable_version}.pex"
        banner(f"Building {pex_name} by fetching wheels.")
    else:
        # TODO: Support macOS on ARM64. Will require qualifying the pex name with the arch.
        major, minor = sys.version_info[:2]
        extra_pex_args = [
            f"--interpreter-constraint=CPython=={major}.{minor}.*",
            f"--python={sys.executable}",
        ]
        plat = os.uname()[0].lower()
        py = f"cp{major}{minor}"
        pex_name = f"pants.{CONSTANTS.pants_unstable_version}.{plat}-{py}.pex"
        banner(f"Building {pex_name} by building wheels.")

    if CONSTANTS.deploy_dir.exists():
        shutil.rmtree(CONSTANTS.deploy_dir)
    CONSTANTS.deploy_dir.mkdir(parents=True)

    if fetch:
        fetch_prebuilt_wheels(CONSTANTS.deploy_dir, include_3rdparty=True)
        check_pants_wheels_present(CONSTANTS.deploy_dir)
        if stable:
            reversion_prebuilt_wheels()
    else:
        build_pants_wheels()
        build_3rdparty_wheels()

    # We need to both run Pex and the Pants PEX we build with it with clean environments since we
    # ourselves may be running via `./pants run ...` which injects confounding environment variables
    # like PEX_EXTRA_SYS_PATH, PEX_PATH and PEX_ROOT that need not or should not apply to these
    # sub-processes.
    env = {k: v for k, v in os.environ.items() if not k.startswith("PEX_")}

    dest = Path("dist") / pex_name
    with download_pex_bin() as pex_bin:
        subprocess.run(
            [
                sys.executable,
                str(pex_bin),
                "-o",
                str(dest),
                "--no-build",
                "--no-pypi",
                "--disable-cache",
                "-f",
                str(CONSTANTS.deploy_pants_wheel_dir /
                    CONSTANTS.pants_unstable_version),
                "-f",
                str(CONSTANTS.deploy_3rdparty_wheel_dir /
                    CONSTANTS.pants_unstable_version),
                "--no-strip-pex-env",
                "--console-script=pants",
                *extra_pex_args,
                f"pantsbuild.pants=={CONSTANTS.pants_unstable_version}",
                "--venv",
            ],
            env=env,
            check=True,
        )

    if stable:
        stable_dest = CONSTANTS.deploy_dir / "pex" / f"pants.{CONSTANTS.pants_stable_version}.pex"
        stable_dest.parent.mkdir(parents=True, exist_ok=True)
        dest.rename(stable_dest)
        dest = stable_dest
    green(f"Built {dest}")

    with TemporaryDirectory() as tmpdir:
        validated_pex_path = Path(tmpdir, "pants.pex")
        shutil.copyfile(dest, validated_pex_path)
        validated_pex_path.chmod(0o777)
        Path(tmpdir, "BUILD_ROOT").touch()
        # We also need to filter out Pants options like `PANTS_CONFIG_FILES` and disable certain internal backends.
        env = {k: v for k, v in env.items() if not k.startswith("PANTS_")}
        env.update(DISABLED_BACKENDS_CONFIG)
        subprocess.run([validated_pex_path, "--version"],
                       env=env,
                       check=True,
                       cwd=dest.parent)
    green(f"Validated {dest}")