Example #1
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 #2
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 #3
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 #4
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 #5
0
def publish() -> None:
    banner("Releasing packages to PyPI and GitHub")
    # Check prereqs.
    check_clean_git_branch()
    check_pgp()
    check_roles()

    # Fetch and validate prebuilt wheels.
    if CONSTANTS.deploy_pants_wheel_dir.exists():
        shutil.rmtree(CONSTANTS.deploy_pants_wheel_dir)
    fetch_prebuilt_wheels(CONSTANTS.deploy_dir)
    check_prebuilt_wheels_present(CONSTANTS.deploy_dir)
    reversion_prebuilt_wheels()

    # Release.
    create_twine_venv()
    subprocess.run(
        [
            str(CONSTANTS.twine_venv_dir / "bin/twine"),
            "upload",
            "--sign",
            f"--sign-with={get_pgp_program_name()}",
            f"--identity={get_pgp_key_id()}",
            "--skip-existing",  # Makes the upload idempotent.
            str(CONSTANTS.deploy_pants_wheel_dir / CONSTANTS.pants_stable_version / "*.whl"),
        ],
        check=True,
    )
    tag_release()
    banner("Successfully released packages to PyPI and GitHub")
Example #6
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 venv_tmpdir:
        deps = (
            subprocess.run(
                [
                    "./pants",
                    "--concurrent",
                    "--no-dynamic-ui",
                    "dependencies",
                    "--transitive",
                    "--type=3rdparty",
                    *pkg_tgts,
                ],
                stdout=subprocess.PIPE,
                check=True,
            )
            .stdout.decode()
            .strip()
            .splitlines()
        )
        if not deps:
            die(
                f"No 3rd-party dependencies detected for {pkg_tgts}. Is `./pants dependencies` "
                "broken?"
            )
        subprocess.run(
            [Path(venv_tmpdir, "bin/pip"), "wheel", f"--wheel-dir={dest}", *deps],
            check=True,
        )
Example #7
0
File: ci.py Project: tushar19/pants
def setup_python_interpreter(version: PythonVersion) -> None:
    if "PY" not in os.environ:
        os.environ["PY"] = f"python{version}"
    constraints_env_var = "PANTS_PYTHON_SETUP_INTERPRETER_CONSTRAINTS"
    if constraints_env_var not in os.environ:
        os.environ[constraints_env_var] = f"['CPython=={version}.*']"
    banner(f"Setting interpreter constraints to {os.environ[constraints_env_var]}")
Example #8
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.
    banner("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 #9
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 #10
0
def main() -> None:
    if not Path("src/python/pants").is_dir():
        raise ValueError(
            "This script assumes that you are in the Pants build root. Instead, you are at "
            f"{Path.cwd()}.")
    args = create_parser().parse_args()
    pex_url = f"s3://{args.aws_bucket}/{args.pex_key}"
    native_engine_so_local_path = "./src/python/pants/engine/internals/native_engine.so"

    # NB: we must set `$PY` before calling `bootstrap()` to ensure that we use the exact same
    # Python interpreter when calculating the hash of `native_engine.so` as the one we use when
    # calling `ci.py --bootstrap`.
    python_version = create_parser().parse_args().python_version
    if "PY" not in os.environ:
        os.environ["PY"] = f"python{python_version}"

    native_engine_so_hash = calculate_native_engine_so_hash()
    native_engine_so_aws_key = (
        f"{args.native_engine_so_key_prefix}/{native_engine_so_hash}/native_engine.so"
    )
    native_engine_so_aws_url = f"s3://{args.aws_bucket}/{native_engine_so_aws_key}"

    if native_engine_so_in_s3_cache(
            aws_bucket=args.aws_bucket,
            native_engine_so_aws_key=native_engine_so_aws_key):
        banner(
            f"`native_engine.so` found in the AWS S3 cache at {native_engine_so_aws_url}. "
            f"Downloading to avoid unnecessary Rust compilation.")
        get_native_engine_so(
            native_engine_so_aws_url=native_engine_so_aws_url,
            native_engine_so_local_path=native_engine_so_local_path,
        )
    else:
        banner(
            f"`native_engine.so` not found in the AWS S3 cache at {native_engine_so_aws_url}. "
            f"Recompiling Rust...")

    bootstrap_pants_pex(python_version)

    if native_engine_so_in_s3_cache(
            aws_bucket=args.aws_bucket,
            native_engine_so_aws_key=native_engine_so_aws_key):
        banner(
            f"`native_engine.so` already cached at {native_engine_so_aws_url}. Skipping deploy."
        )
    else:
        banner(f"Deploying `native_engine.so` to {native_engine_so_aws_url}.")
        deploy_native_engine_so(
            native_engine_so_aws_url=native_engine_so_aws_url,
            native_engine_so_local_path=native_engine_so_local_path,
        )

    banner(f"Deploying `pants.pex` to {pex_url}.")
    deploy_pants_pex(pex_url=pex_url)
Example #11
0
def check_pgp() -> None:
    banner("Checking PGP setup")
    key = get_pgp_key_id()
    if not key:
        die("You must set up a PGP key. See https://www.pantsbuild.org/docs/release-process."
            )
    print("Found the following key for release signing:\n")
    subprocess.run([get_pgp_program_name(), "-k", key], check=True)
    key_confirmation = input("\nIs this the correct key? [Y/n]: ")
    if key_confirmation and key_confirmation.lower() != "y":
        die("Please configure the key you intend to use. See "
            "https://www.pantsbuild.org/docs/release-process.")
Example #12
0
def check_roles() -> None:
    # Check that the packages we plan to publish are correctly owned.
    banner("Checking current user.")
    username = get_pypi_config("server-login", "username")
    if username not in _expected_owners and username not in _expected_maintainers:
        die(f"User {username} not authorized to publish.")
    banner("Checking package roles.")
    validator = PackageAccessValidator()
    for pkg in PACKAGES:
        if pkg.name not in _known_packages:
            die(f"Unknown package {pkg}")
        validator.validate_package_access(pkg.name)
Example #13
0
def fetch_prebuilt_wheels(destination_dir: str) -> None:
    banner(f"Fetching pre-built wheels for {CONSTANTS.pants_unstable_version}")
    print(f"Saving to {destination_dir}.\n", file=sys.stderr)
    for wheel in determine_prebuilt_wheels():
        full_url = f"{CONSTANTS.binary_base_url}/{wheel.url}"
        print(f"Fetching {full_url}", file=sys.stderr)
        response = requests.get(full_url)
        response.raise_for_status()
        print(file=sys.stderr)

        dest = Path(destination_dir, wheel.path)
        dest.parent.mkdir(parents=True, exist_ok=True)
        dest.write_bytes(response.content)
Example #14
0
def check_clean_git_branch() -> None:
    banner("Checking for a clean Git branch")
    git_status = (subprocess.run(["git", "status", "--porcelain"],
                                 stdout=subprocess.PIPE,
                                 check=True).stdout.decode().strip())
    if git_status:
        die("Uncommitted changes detected when running `git status`. You must be on a clean branch "
            "to release.")
    valid_branch_pattern = r"^(main)|([0-9]+\.[0-9]+\.x)$"
    git_branch = get_git_branch()
    if not re.match(valid_branch_pattern, git_branch):
        die("On an invalid branch. You must either be on `main` or a release branch like "
            f"`2.4.x`. Detected: {git_branch}")
Example #15
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 #16
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 #17
0
def dry_run_install() -> None:
    banner(f"Performing a dry run release with {CONSTANTS.python_version}")
    build_pants_wheels()
    build_3rdparty_wheels()
    install_and_test_packages(
        CONSTANTS.pants_unstable_version,
        extra_pip_args=[
            "--only-binary=:all:",
            "-f",
            str(CONSTANTS.deploy_3rdparty_wheel_dir / CONSTANTS.pants_unstable_version),
            "-f",
            str(CONSTANTS.deploy_pants_wheel_dir / CONSTANTS.pants_unstable_version),
        ],
    )
    banner(f"Dry run release succeeded with {CONSTANTS.python_version}")
Example #18
0
def fetch_prebuilt_wheels(destination_dir: str | Path, *, include_3rdparty: bool) -> None:
    banner(f"Fetching pre-built wheels for {CONSTANTS.pants_unstable_version}")
    print(f"Saving to {destination_dir}.\n", file=sys.stderr)
    session = requests.Session()
    session.mount(CONSTANTS.binary_base_url, requests.adapters.HTTPAdapter(max_retries=4))
    for wheel in determine_prebuilt_wheels(include_3rdparty=include_3rdparty):
        full_url = f"{CONSTANTS.binary_base_url}/{wheel.url}"
        print(f"Fetching {full_url}", file=sys.stderr)
        response = session.get(full_url)
        response.raise_for_status()
        print(file=sys.stderr)

        dest = Path(destination_dir, wheel.path)
        dest.parent.mkdir(parents=True, exist_ok=True)
        dest.write_bytes(response.content)
Example #19
0
    def check_ownership(i: int, package: Package) -> None:
        banner(
            f"[{i}/{len(PACKAGES)}] checking ownership for {package}: > {minimum_owner_count} "
            f"releasers including {', '.join(users)}")
        if not package.exists_on_pypi():
            print(
                f"The {package.name} package is new! There are no owners yet.")
            return

        owners = package.owners()
        if len(owners) <= minimum_owner_count:
            insufficient.add(package)

        difference = users.difference(owners)
        for d in difference:
            unowned.setdefault(d, set()).add(package)
Example #20
0
def main():
    """Process command line args."""
    clrm.init()

    args = sys.argv[1:]
    if args:
        args_set = set(args)

        max_args = 2  # -q and one other
        doc_arg_set = set(['-d', '--doc'])
        help_arg_set = set(['-h', '--help'])
        license_arg_set = set(['-l', '--license'])
        quiet_arg_set = set(['-q', '--quiet'])
        reference_arg_set = set(['-r', '--reference'])
        version_arg_set = set(['-V', '--version'])
        legal_args_set = (doc_arg_set | help_arg_set | license_arg_set |
                          quiet_arg_set | reference_arg_set | version_arg_set)

        # if any wrong arg, too many args or (max args and -q not among them)
        if (args_set - legal_args_set or len(args) > max_args or
           (len(args) == max_args and not (quiet_arg_set & args_set))):
            print(common.banner())
            print(clrm.Fore.RED + lcl.WRONG_ARG + '\n')
            print(clrm.Fore.RESET + common.usage())
        else:
            if not (quiet_arg_set & args_set):
                print(common.banner())

            if doc_arg_set & args_set:
                get_app_info()
                update_doc()
            elif license_arg_set & args_set:
                print(common.license_())
            elif help_arg_set & args_set:
                print(common.usage())
            elif reference_arg_set & args_set:
                get_app_info()
                update_ref()
            elif version_arg_set & args_set:
                print(lcl.VERSION, common.version())
            else:  # only -q
                create_setup()
    else:
        print(common.banner())
        create_setup()
Example #21
0
def check_ownership(users, minimum_owner_count: int = 3) -> None:
    minimum_owner_count = max(len(users), minimum_owner_count)
    packages = sorted(all_packages())
    banner(f"Checking package ownership for {len(packages)} packages")
    users = {user.lower() for user in users}
    insufficient = set()
    unowned: Dict[str, Set[Package]] = dict()

    def check_ownership(i: int, package: Package) -> None:
        banner(
            f"[{i}/{len(packages)}] checking ownership for {package}: > {minimum_owner_count} "
            f"releasers including {', '.join(users)}")
        if not package.exists_on_pypi():
            print(
                f"The {package.name} package is new! There are no owners yet.")
            return

        owners = package.owners()
        if len(owners) <= minimum_owner_count:
            insufficient.add(package)

        difference = users.difference(owners)
        for d in difference:
            unowned.setdefault(d, set()).add(package)

    for i, package in enumerate(packages):
        check_ownership(i, package)

    if unowned:
        for user, unowned_packages in sorted(unowned.items()):
            formatted_unowned = "\n".join(package.name
                                          for package in sorted(packages))
            print(
                f"PyPI account {user} needs to be added as an owner for the following "
                f"packages:\n{formatted_unowned}",
                file=sys.stderr,
            )
        raise SystemExit()

    if insufficient:
        insufficient_packages = "\n".join(package.name
                                          for package in insufficient)
        die(
            f"The following packages have fewer than {minimum_owner_count} owners but should be "
            f"setup for all releasers:\n{insufficient_packages}", )
Example #22
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 #23
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")
Example #24
0
def publish_apple_silicon() -> None:
    banner("Building and publishing an Apple Silicon wheel")
    if os.environ.get("USE_PY39") != "true":
        die("Must set `USE_PY39=true` when building for Apple Silicon.")
    if os.environ.get("MODE") == "debug":
        die("Must build Rust in release mode, not debug. Please run `unset MODE`."
            )
    check_clean_git_branch()
    check_pgp()
    check_roles()

    dest_dir = CONSTANTS.deploy_pants_wheel_dir / CONSTANTS.pants_stable_version
    if dest_dir.exists():
        shutil.rmtree(dest_dir)
    subprocess.run(
        [
            "./pants",
            "--concurrent",
            f"--pants-distdir={dest_dir}",
            "package",
            PANTS_PKG.target,
        ],
        check=True,
    )
    expected_whl = (
        dest_dir /
        f"pantsbuild.pants-{CONSTANTS.pants_stable_version}-cp39-cp39-macosx_11_0_arm64.whl"
    )
    if not expected_whl.exists():
        die(
            softwrap(f"""
                Failed to find {expected_whl}. Are you running from the correct platform and
                macOS version?
                """))

    create_twine_venv()
    subprocess.run(
        [CONSTANTS.twine_venv_dir / "bin/twine", "check", expected_whl],
        check=True)
    upload_wheels_via_twine()
    banner("Successfully released Apple Silicon wheel to PyPI")
Example #25
0
def publish() -> None:
    banner("Releasing to PyPI and GitHub")
    # Check prereqs.
    check_clean_git_branch()
    prompt_artifact_freshness()
    check_pgp()
    check_roles()

    # Fetch and validate prebuilt wheels.
    if CONSTANTS.deploy_pants_wheel_dir.exists():
        shutil.rmtree(CONSTANTS.deploy_pants_wheel_dir)
    fetch_prebuilt_wheels(CONSTANTS.deploy_dir, include_3rdparty=False)
    check_pants_wheels_present(CONSTANTS.deploy_dir)
    reversion_prebuilt_wheels()

    # Release.
    create_twine_venv()
    upload_wheels_via_twine()
    tag_release()
    banner("Successfully released to PyPI and GitHub")
    prompt_apple_silicon()
    prompt_to_generate_docs()
Example #26
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 #27
0
def main():

    # 这里还要在check 基本环境
    argpa = argparse.ArgumentParser(description="A Scan For Network")
    argpa.add_argument("--banner")
    argpa.add_argument("--debug")
    argpa.add_argument("-u", help="Web Url")
    argpa.add_argument("-p", help="Server Port")
    argpa.add_argument("-H", help="Server Host")
    args = argpa.parse_args()
    # arg_dict= arg.__dict__
    # # print arg_dict

    if Os_win:
        print "a"

    banner()

    try:
        initoptions(args)
    except Exception, msg:
        pass
Example #28
0
def start(argv):
    """Print banner, read/create data & log file and process args."""
    clrm.init()

    print(common.banner())
    childs, last_upd = shrd.open_create_datafile()

    arg0 = argv[0]
    if arg0 in ['-a', '--auto']:
        auto_upd(childs, last_upd)
    elif arg0 in ['-h', '--help']:
        print(common.usage())
    elif arg0 in ['-l', '--license']:
        print(common.license_())
    elif arg0 in ['-V', '--version']:
        print(lcl.VERSION, common.version())
    else:
        man_upd(argv, childs, last_upd)

    sys.exit(0)  # ToDo: other return codes
Example #29
0
def setup_python_version(test_python_version: PythonVersion):
    """Modify pants.ini to allow the Python version to be unspecified or change to what was requested."""
    updated_config = read_config()
    config_entry = "pants_runtime_python_version"
    if test_python_version == PythonVersion.unspecified:
        updated_config.remove_option(CONFIG_GLOBAL_SECTION, config_entry)
        banner(f"Temporarily removing `{config_entry}` from pants.ini.")
    else:
        updated_config[CONFIG_GLOBAL_SECTION][
            config_entry] = test_python_version.value
        banner(
            f"Temporarily rewriting `{config_entry}` to `{test_python_version}`."
        )
    with temporarily_rewrite_config(updated_config):
        yield
    banner(f"Restoring original `{config_entry}` value in pants.ini.")
Example #30
0
def start(argv):
    """Print banner and process args."""
    ansi.init()

    print(common.banner())

    if not argv:
        print_ips()
    else:
        arg0 = argv[0]
        if arg0 in ['-h', '--help']:
            print(common.usage())
        elif arg0 in ['-l', '--license']:
            print(common.license_())
        elif arg0 in ['-p', '--pause']:
            print_ips()
            input(lcl.PRESS_ANY_KEY)
        elif arg0 in ['-V', '--version']:
            print(lcl.VERSION, common.version())
        else:
            print(ansi.Fore.RED + lcl.WRONG_ARG + arg0 + '\n')
            print(ansi.Fore.RESET + common.usage())

    sys.exit(0)  # ToDo: other return codes
Example #31
0
def start(argv):
    """Print banner and process args."""
    ansi.init()

    print(common.banner())

    if not argv:
        print_ips()
    else:
        arg0 = argv[0]
        if arg0 in ['-h', '--help']:
            print(common.usage())
        elif arg0 in ['-l', '--license']:
            print(common.license_())
        elif arg0 in ['-p', '--pause']:
            print_ips()
            input(lcl.PRESS_ANY_KEY)
        elif arg0 in ['-V', '--version']:
            print(lcl.VERSION, common.version())
        else:
            print(ansi.Fore.RED + lcl.WRONG_ARG + arg0 + '\n')
            print(ansi.Fore.RESET + common.usage())

    sys.exit(0)  # ToDo: other return codes
Example #32
0
def start():
    """Print banner, read/create data & log file and start GUI."""
    global prev_child, child, childs, last_upd

    def plus_btn(*args):
        """Plus button was pressed. Update days_var."""
        if int(days_var.get()) < 0:
            days_var.set(0)
        else:
            days_var.set(min(shrd.MAX_DAYS, int(days_var.get()) + 1))

    def minus_btn(*args):
        """Minus button was pressed. Update days_var."""
        if int(days_var.get()) > shrd.MAX_DAYS:
            days_var.set(shrd.MAX_DAYS)
        else:
            days_var.set(max(0, int(days_var.get()) - 1))

    def days_scale_chg(*args):
        """Days scale changed. Update. Update days_var."""
        days_var.set(int(float(days_var.get())))  # fix increment to integer

    def childs_combo_chg(*args):
        """
        Child selection changed.
        Save current child's grounded days and update all fields with new
        child's.
        """
        global child, prev_child

        try:
            int(days_var.get())
        except ValueError:  # as error:
            days_var.set(0)

        if 0 <= int(days_var.get()) <= shrd.MAX_DAYS:
            childs[prev_child] = int(days_var.get())
            child = prev_child = childs_combo.get()
            days_var.set(childs[child])
        else:
            childs_combo.set(prev_child)
            tk_msg_box.showwarning(lcl.WARNING, lcl.DAYS_RANGE +
                                   shrd.MAX_DAYS_STR)

    def set_upd_btn(upd):
        """Set or update selected child's grounded days."""
        global last_upd

        try:
            int(days_var.get())
        except ValueError:  # as error:
            days_var.set(0)

        if 0 <= int(days_var.get()) <= shrd.MAX_DAYS:
            childs[childs_combo.get()] = int(days_var.get())
            if upd:
                last_upd = shrd.auto_upd_datafile(childs, last_upd)
            else:
                last_upd = dt.date.today()
                shrd.update_file(childs, last_upd)
            last_upd_var.set(value=str(last_upd))
        else:
            tk_msg_box.showwarning(lcl.WARNING, lcl.DAYS_RANGE +
                                   shrd.MAX_DAYS_STR)

    def confirm_exit():
        """Confirm exit from program."""
        if tk_msg_box.askokcancel(lcl.EXIT, lcl.CONFIRM_EXIT):
            root.destroy()
            sys.exit(0)  # ToDo: other return codes

    def digits_only(up_down, idx, value, prev_val, char, val_type, source,
                    widget):
        """Only allow digits in source field."""
        return char in '0123456789' and len(value) <= len(shrd.MAX_DAYS_STR)

    def center(window):
        """Center window."""
        window.update_idletasks()
        width = window.winfo_width()
        frm_width = window.winfo_rootx() - window.winfo_x()
        win_width = width + 2 * frm_width
        height = window.winfo_height()
        titlebar_height = window.winfo_rooty() - window.winfo_y()
        win_height = height + titlebar_height + frm_width
        x = window.winfo_screenwidth() // 2 - win_width // 2
        y = window.winfo_screenheight() // 2 - win_height // 2
        window.geometry('{}x{}+{}+{}'.format(width, height, x, y))
        if window.attributes('-alpha') == 0:
            window.attributes('-alpha', 1.0)
        window.deiconify()

    def show_help(*args):
        """Show help message."""
        tk_msg_box.showinfo(lcl.HELP, common.usage())

    print(common.banner())
    childs, last_upd = shrd.open_create_datafile()

    root = tk.Tk()
    root.withdraw()
    win = tk.Toplevel(root)

    # for exit confirmation
    win.protocol('WM_DELETE_WINDOW', confirm_exit)

    win.title(lcl.WIN_TITLE)

    # not resizable
    win.resizable(False, False)

    # resizable (limits)
    # win.minsize(250, 125)
    # win.maxsize(500, 250)

    # needed by center function?
    # win.attributes('-alpha', 0.0)

    win.bind('<F1>', show_help)
    win.bind('+', plus_btn)
    win.bind('-', minus_btn)

    # menu
    win.option_add('*tearOff', False)
    menubar = tk.Menu(win)
    win.config(menu=menubar)
    filemenu = tk.Menu(menubar)
    helpmenu = tk.Menu(menubar)

    menubar.add_cascade(label=lcl.FILE, menu=filemenu, underline=0)
    menubar.add_cascade(label=lcl.HELP, menu=helpmenu, underline=0)

    filemenu.add_command(label=lcl.EXIT, underline=0, command=confirm_exit)

    helpmenu.add_command(label=lcl.HELP, underline=0, command=show_help,
                         accelerator='F1')
    helpmenu.add_separator()
    helpmenu.add_command(label=lcl.ABOUT, underline=0, state='disabled')

    # ToDo: log menu item
    # filemenu.add_separator()
    # check = StringVar(value=1)
    # filemenu.add_checkbutton(label='Log', variable=check, onvalue=1,
    #                          offvalue=0)

    frame = tk_ttk.Frame(win, padding='3 3 3 3')
    frame.grid(column=0, row=0, sticky='WNES')

    # if the main window is resized, the frame should expand
    # frame.columnconfigure(0, weight=1)
    # frame.rowconfigure(0, weight=1)

    # must convert to list for Python 3 compatibility
    prev_child = child = list(childs.keys())[0]

    child_lbl = tk.StringVar(value=lcl.CHILD)
    last_upd_lbl = tk.StringVar(value=lcl.LAST_UPDATE)

    days_var = tk.StringVar(value=childs[child])
    last_upd_var = tk.StringVar(value=str(last_upd))

    # 1st row
    tk_ttk.Button(frame, text='+', command=plus_btn).grid(column=3, row=1)
    days_scale = tk_ttk.Scale(frame, orient=tk.VERTICAL, length=100,
                              from_=shrd.MAX_DAYS, to=0,
                              command=days_scale_chg, variable=days_var)
    days_scale.grid(column=4, row=1, rowspan=3)

    # 2nd row
    tk_ttk.Label(frame, textvariable=child_lbl).grid(column=1, row=2)
    childs_combo = tk_ttk.Combobox(frame, state='readonly',  # width=10,
                                   values=list(childs.keys()))
    childs_combo.grid(column=2, row=2)
    childs_combo.set(child)
    childs_combo.bind('<<ComboboxSelected>>', childs_combo_chg)

    # validate command, used below by some widgets
    vcmd = (win.register(digits_only),
            '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')

    days_entry = tk_ttk.Entry(frame, width=len(shrd.MAX_DAYS_STR) + 1,
                              justify=tk.RIGHT, textvariable=days_var,
                              validate='key', validatecommand=vcmd)
    days_entry.grid(column=3, row=2)  # , sticky='WE')  # for expanding
    tk.Spinbox(frame, from_=0, to=shrd.MAX_DAYS,
               width=len(shrd.MAX_DAYS_STR) + 1, justify=tk.RIGHT,
               textvariable=days_var, validate='key',
               validatecommand=vcmd).grid(column=5, row=2)

    # 3rd row
    tk_ttk.Button(frame, text='-', command=minus_btn).grid(column=3, row=3)

    # 4th row
    # lambda is necessary so that the function is called on button creation
    tk_ttk.Button(frame, text=lcl.UPDATE,
                  command=lambda: set_upd_btn(upd=True)).grid(column=1, row=4)
    tk_ttk.Label(frame, textvariable=last_upd_lbl).grid(column=2, row=4,
                                                        sticky='E')
    tk_ttk.Label(frame, textvariable=last_upd_var).grid(column=3, row=4,
                                                        sticky='W')
    tk_ttk.Button(frame, text=lcl.SET,
                  command=lambda: set_upd_btn(upd=False)).grid(column=4, row=4,
                                                               columnspan=2)
    # remove if windows is non resizable
    # tk_ttk.Sizegrip(frame).grid(column=999, row=999, sticky=(E,S))

    # padding around all widgets
    for widget in frame.winfo_children():
        widget.grid_configure(padx=5, pady=5)

    days_entry.focus()

    # center window
    center(win)

    root.mainloop()
Example #33
0
def start():
    """Print banner and start GUI."""

    def exit_gui():
        """Exit program."""
        root.destroy()
        sys.exit(0)  # ToDo: other return codes

    def center(window):
        """Center window."""
        window.update_idletasks()
        width = window.winfo_width()
        frm_width = window.winfo_rootx() - window.winfo_x()
        win_width = width + 2 * frm_width
        height = window.winfo_height()
        titlebar_height = window.winfo_rooty() - window.winfo_y()
        win_height = height + titlebar_height + frm_width
        x = window.winfo_screenwidth() // 2 - win_width // 2
        y = window.winfo_screenheight() // 2 - win_height // 2
        window.geometry('{}x{}+{}+{}'.format(width, height, x, y))
        if window.attributes('-alpha') == 0:
            window.attributes('-alpha', 1.0)
        window.deiconify()

    def show_help(*args):
        """Show help message."""
        tk_msg_box.showinfo(lcl.HELP, common.usage())

    print(common.banner())

    root = tk.Tk()
    root.withdraw()
    win = tk.Toplevel(root)

    # for exit confirmation
    win.protocol('WM_DELETE_WINDOW', exit_gui)

    win.title(lcl.WIN_TITLE)

    # not resizable
    win.resizable(False, False)

    # resizable (limits)
    # win.minsize(250, 125)
    # win.maxsize(500, 250)

    # needed by center function?
    # win.attributes('-alpha', 0.0)

    win.bind('<F1>', show_help)

    # menu
    win.option_add('*tearOff', False)
    menubar = tk.Menu(win)
    win.config(menu=menubar)
    filemenu = tk.Menu(menubar)
    helpmenu = tk.Menu(menubar)

    menubar.add_cascade(label=lcl.FILE, menu=filemenu, underline=0)
    menubar.add_cascade(label=lcl.HELP, menu=helpmenu, underline=0)

    filemenu.add_command(label=lcl.EXIT, underline=0, command=exit_gui)

    helpmenu.add_command(label=lcl.HELP, underline=0, command=show_help,
                         accelerator='F1')
    helpmenu.add_separator()
    helpmenu.add_command(label=lcl.ABOUT, underline=0, state='disabled')

    # ToDo: log menu item
    # filemenu.add_separator()
    # check = StringVar(value=1)
    # filemenu.add_checkbutton(label='Log', variable=check, onvalue=1,
    #                          offvalue=0)

    frame = tk_ttk.Frame(win, padding='3 3 3 3')
    frame.grid(column=0, row=0, sticky='WNES')

    # if the main window is resized, the frame should expand
    # frame.columnconfigure(0, weight=1)
    # frame.rowconfigure(0, weight=1)

    private_lbl = tk.StringVar(value=lcl.PRIVATE_IP + shrd.get_private_ip())
    public_lbl = tk.StringVar(value=lcl.PUBLIC_IP + shrd.get_public_ip())

    # 1st row
    tk_ttk.Label(frame, textvariable=private_lbl).grid(column=1, row=1)

    # 2nd row
    tk_ttk.Label(frame, textvariable=public_lbl).grid(column=1, row=2)

    # remove if windows is non resizable
    # tk_ttk.Sizegrip(frame).grid(column=999, row=999, sticky=(E,S))

    # padding around all widgets
    for widget in frame.winfo_children():
        widget.grid_configure(padx=5, pady=5)

    # center window
    center(win)

    root.mainloop()